Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6
authorLinus Torvalds <torvalds@woody.linux-foundation.org>
Mon, 15 Oct 2007 16:57:54 +0000 (09:57 -0700)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Mon, 15 Oct 2007 16:57:54 +0000 (09:57 -0700)
* 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6:
  [IA64] update sn2_defconfig
  [IA64] Fix kernel hangup in kdump on INIT
  [IA64] Fix kernel panic in kdump on INIT
  [IA64] Remove vector from ia64_machine_kexec()
  [IA64] Fix race when multiple cpus go through MCA
  [IA64] Remove needless delay in MCA rendezvous
  [IA64] add driver for ACPI methods to call native firmware
  [IA64] abstract SAL_CALL wrapper to allow other firmware entry points
  [IA64] perfmon: Remove exit_pfm_fs()
  [IA64] tree-wide: Misc __cpu{initdata, init, exit} annotations

1470 files changed:
Documentation/DMA-API.txt
Documentation/DocBook/Makefile
Documentation/DocBook/deviceiobook.tmpl
Documentation/DocBook/kernel-api.tmpl
Documentation/DocBook/kernel-hacking.tmpl
Documentation/DocBook/mcabook.tmpl
Documentation/DocBook/mtdnand.tmpl
Documentation/DocBook/s390-drivers.tmpl [new file with mode: 0644]
Documentation/MSI-HOWTO.txt
Documentation/filesystems/ntfs.txt
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/ja_JP/HOWTO
Documentation/kernel-parameters.txt
Documentation/kobject.txt
Documentation/s390/00-INDEX [new file with mode: 0644]
Documentation/s390/CommonIO
Documentation/s390/cds.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
Documentation/usb/authorization.txt [new file with mode: 0644]
Documentation/usb/power-management.txt [new file with mode: 0644]
Documentation/usb/usb-serial.txt
Documentation/usb/usbmon.txt
MAINTAINERS
arch/arm/mach-imx/cpufreq.c
arch/arm/mach-omap1/board-h2.c
arch/arm/mach-omap1/board-h3.c
arch/arm/mach-omap1/board-osk.c
arch/arm/mach-sa1100/cpu-sa1110.c
arch/arm/plat-omap/cpu-omap.c
arch/blackfin/mach-bf533/cpu.c
arch/blackfin/mach-bf537/boards/generic_board.c
arch/blackfin/mach-bf537/boards/pnav10.c
arch/blackfin/mach-bf537/boards/stamp.c
arch/i386/Kconfig
arch/ia64/hp/sim/simscsi.c
arch/ia64/kernel/cpufreq/acpi-cpufreq.c
arch/ia64/sn/kernel/tiocx.c
arch/m68k/atari/atakeyb.c
arch/mips/kernel/smp.c
arch/mips/mm/tlbex.c
arch/powerpc/kernel/of_device.c
arch/powerpc/kernel/vio.c
arch/powerpc/platforms/52xx/lite5200.c
arch/powerpc/platforms/cell/cbe_cpufreq.c
arch/powerpc/platforms/pasemi/cpufreq.c
arch/powerpc/platforms/powermac/cpufreq_32.c
arch/powerpc/platforms/powermac/cpufreq_64.c
arch/powerpc/platforms/ps3/system-bus.c
arch/s390/appldata/appldata_base.c
arch/s390/kernel/audit.c
arch/s390/kernel/audit.h [new file with mode: 0644]
arch/s390/kernel/compat_audit.c
arch/s390/kernel/cpcmd.c
arch/s390/kernel/dis.c
arch/s390/kernel/ipl.c
arch/s390/kernel/vmlinux.lds.S
arch/s390/mm/fault.c
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 [new file with mode: 0644]
arch/sh/configs/rts7751r2d_defconfig [deleted file]
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/pci-dma.c [deleted file]
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 [new file with mode: 0644]
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/us2e_cpufreq.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/Makefile_32
arch/x86/kernel/Makefile_64
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/cpu/cpufreq/acpi-cpufreq.c
arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c
arch/x86/kernel/cpu/cpufreq/e_powersaver.c
arch/x86/kernel/cpu/cpufreq/elanfreq.c
arch/x86/kernel/cpu/cpufreq/gx-suspmod.c
arch/x86/kernel/cpu/cpufreq/longhaul.c
arch/x86/kernel/cpu/cpufreq/p4-clockmod.c
arch/x86/kernel/cpu/cpufreq/powernow-k6.c
arch/x86/kernel/cpu/cpufreq/powernow-k7.c
arch/x86/kernel/cpu/cpufreq/powernow-k8.c
arch/x86/kernel/cpu/cpufreq/sc520_freq.c
arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c
arch/x86/kernel/cpu/cpufreq/speedstep-ich.c
arch/x86/kernel/cpu/cpufreq/speedstep-smi.c
arch/x86/kernel/cpuid.c
arch/x86/kernel/crash_dump_32.c
arch/x86/kernel/crash_dump_64.c
arch/x86/kernel/geode_32.c
arch/x86/kernel/head64.c
arch/x86/kernel/hpet.c [new file with mode: 0644]
arch/x86/kernel/hpet_32.c [deleted file]
arch/x86/kernel/hpet_64.c [deleted file]
arch/x86/kernel/i387_32.c
arch/x86/kernel/i387_64.c
arch/x86/kernel/i8237.c
arch/x86/kernel/i8253.c [new file with mode: 0644]
arch/x86/kernel/i8253_32.c [deleted file]
arch/x86/kernel/i8259_32.c
arch/x86/kernel/i8259_64.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/mfgpt_32.c [new file with mode: 0644]
arch/x86/kernel/msr.c
arch/x86/kernel/nmi_32.c
arch/x86/kernel/nmi_64.c
arch/x86/kernel/pci-dma_32.c
arch/x86/kernel/pci-dma_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/quirks.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_64.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/pci/acpi.c
arch/x86/pci/common.c
arch/x86/pci/fixup.c
arch/x86/pci/i386.c
arch/x86/pci/irq.c
arch/x86/pci/pci.h
arch/x86_64/Kconfig
block/Kconfig
block/Makefile
block/bsg.c
block/elevator.c
block/genhd.c
block/ll_rw_blk.c
drivers/acpi/bus.c
drivers/acpi/processor_idle.c
drivers/acpi/scan.c
drivers/acpi/toshiba_acpi.c
drivers/acpi/video.c
drivers/amba/bus.c
drivers/ata/Kconfig
drivers/ata/Makefile
drivers/ata/ahci.c
drivers/ata/ata_generic.c
drivers/ata/ata_piix.c
drivers/ata/libata-acpi.c
drivers/ata/libata-core.c
drivers/ata/libata-eh.c
drivers/ata/libata-pmp.c [new file with mode: 0644]
drivers/ata/libata-scsi.c
drivers/ata/libata-sff.c
drivers/ata/libata.h
drivers/ata/pata_acpi.c [new file with mode: 0644]
drivers/ata/pata_ali.c
drivers/ata/pata_amd.c
drivers/ata/pata_artop.c
drivers/ata/pata_at32.c [new file with mode: 0644]
drivers/ata/pata_atiixp.c
drivers/ata/pata_bf54x.c [new file with mode: 0644]
drivers/ata/pata_cmd640.c
drivers/ata/pata_cmd64x.c
drivers/ata/pata_cs5520.c
drivers/ata/pata_cs5530.c
drivers/ata/pata_cs5535.c
drivers/ata/pata_cypress.c
drivers/ata/pata_efar.c
drivers/ata/pata_hpt366.c
drivers/ata/pata_hpt37x.c
drivers/ata/pata_hpt3x2n.c
drivers/ata/pata_hpt3x3.c
drivers/ata/pata_icside.c
drivers/ata/pata_isapnp.c
drivers/ata/pata_it8213.c
drivers/ata/pata_it821x.c
drivers/ata/pata_ixp4xx_cf.c
drivers/ata/pata_jmicron.c
drivers/ata/pata_legacy.c
drivers/ata/pata_marvell.c
drivers/ata/pata_mpc52xx.c
drivers/ata/pata_mpiix.c
drivers/ata/pata_netcell.c
drivers/ata/pata_ns87410.c
drivers/ata/pata_ns87415.c [new file with mode: 0644]
drivers/ata/pata_oldpiix.c
drivers/ata/pata_opti.c
drivers/ata/pata_optidma.c
drivers/ata/pata_pcmcia.c
drivers/ata/pata_pdc2027x.c
drivers/ata/pata_pdc202xx_old.c
drivers/ata/pata_platform.c
drivers/ata/pata_qdi.c
drivers/ata/pata_radisys.c
drivers/ata/pata_rz1000.c
drivers/ata/pata_sc1200.c
drivers/ata/pata_scc.c
drivers/ata/pata_serverworks.c
drivers/ata/pata_sil680.c
drivers/ata/pata_sis.c
drivers/ata/pata_sl82c105.c
drivers/ata/pata_triflex.c
drivers/ata/pata_via.c
drivers/ata/pata_winbond.c
drivers/ata/pdc_adma.c
drivers/ata/sata_inic162x.c
drivers/ata/sata_mv.c
drivers/ata/sata_nv.c
drivers/ata/sata_promise.c
drivers/ata/sata_qstor.c
drivers/ata/sata_sil.c
drivers/ata/sata_sil24.c
drivers/ata/sata_sis.c
drivers/ata/sata_svw.c
drivers/ata/sata_sx4.c
drivers/ata/sata_uli.c
drivers/ata/sata_via.c
drivers/ata/sata_vsc.c
drivers/atm/ambassador.h
drivers/atm/firestream.c
drivers/atm/horizon.h
drivers/base/Kconfig
drivers/base/base.h
drivers/base/bus.c
drivers/base/class.c
drivers/base/core.c
drivers/base/firmware_class.c
drivers/base/memory.c
drivers/base/platform.c
drivers/base/power/Makefile
drivers/base/power/main.c
drivers/base/power/power.h
drivers/base/power/resume.c [deleted file]
drivers/base/power/suspend.c [deleted file]
drivers/base/sys.c
drivers/block/Kconfig
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/ip2/ip2main.c
drivers/char/ipmi/ipmi_devintf.c
drivers/char/ipmi/ipmi_si_intf.c
drivers/char/istallion.c
drivers/char/lp.c
drivers/char/pcmcia/cm4000_cs.c
drivers/char/pcmcia/cm4040_cs.c
drivers/char/pty.c
drivers/char/raw.c
drivers/char/rio/host.h
drivers/char/riscom8.h
drivers/char/snsc.c
drivers/char/stallion.c
drivers/char/sx.h
drivers/char/synclink_gt.c
drivers/char/tipar.c
drivers/char/viotape.c
drivers/char/watchdog/mpc5200_wdt.c
drivers/cpufreq/Kconfig
drivers/cpufreq/cpufreq.c
drivers/cpufreq/cpufreq_conservative.c
drivers/cpufreq/cpufreq_ondemand.c
drivers/cpufreq/cpufreq_stats.c
drivers/edac/edac_mc_sysfs.c
drivers/eisa/eisa-bus.c
drivers/fc4/fc.c
drivers/fc4/fcp_impl.h
drivers/firewire/fw-cdev.c
drivers/firewire/fw-device.c
drivers/firmware/dmi-id.c
drivers/firmware/edd.c
drivers/firmware/efivars.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/ieee1394/nodemgr.c
drivers/infiniband/core/sysfs.c
drivers/infiniband/ulp/srp/Kconfig
drivers/infiniband/ulp/srp/ib_srp.c
drivers/input/input.c
drivers/input/keyboard/atakbd.c
drivers/input/misc/pcspkr.c
drivers/input/mouse/atarimouse.c
drivers/input/serio/serio.c
drivers/input/touchscreen/ads7846.c
drivers/isdn/hisax/avm_pci.c
drivers/isdn/hisax/bkm_a8.c
drivers/isdn/hisax/diva.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/isdn/hisax/sedlbauer.c
drivers/isdn/hisax/telespci.c
drivers/isdn/hisax/w6692.c
drivers/isdn/hysdn/hysdn_init.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/md/md.c
drivers/media/dvb/dvb-core/dvbdev.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/pvrusb2/pvrusb2-sysfs.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/misc/tifm_core.c
drivers/mmc/core/bus.c
drivers/mmc/core/host.c
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/atarilance.c
drivers/net/bnx2.c
drivers/net/hamradio/6pack.c
drivers/net/hamradio/mkiss.c
drivers/net/ibm_newemac/core.c
drivers/net/ibm_newemac/rgmii.c
drivers/net/ibm_newemac/tah.c
drivers/net/ibm_newemac/zmii.c
drivers/net/ibmveth.c
drivers/net/ipg.c
drivers/net/ipg.h
drivers/net/macmace.c
drivers/net/macvlan.c
drivers/net/mlx4/main.c
drivers/net/mv643xx_eth.c
drivers/net/mvme147.c
drivers/net/ni65.c
drivers/net/sky2.c
drivers/net/tg3.c
drivers/net/tulip/de4x5.h
drivers/net/tulip/tulip_core.c
drivers/net/wan/cosa.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/pci/hotplug.c
drivers/pci/hotplug/cpqphp_core.c
drivers/pci/hotplug/cpqphp_ctrl.c
drivers/pci/hotplug/ibmphp_hpc.c
drivers/pci/hotplug/pci_hotplug_core.c
drivers/pci/hotplug/pciehp_core.c
drivers/pci/hotplug/pciehp_ctrl.c
drivers/pci/hotplug/pciehp_hpc.c
drivers/pci/hotplug/pciehp_pci.c
drivers/pci/hotplug/rpadlpar_sysfs.c
drivers/pci/msi.c
drivers/pci/pci-driver.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/pcie/Kconfig
drivers/pci/pcie/aer/aerdrv.c
drivers/pci/probe.c
drivers/pci/proc.c
drivers/pci/quirks.c
drivers/pci/setup-bus.c
drivers/pci/setup-irq.c
drivers/pcmcia/cs.c
drivers/pcmcia/ds.c
drivers/pcmcia/i82365.c
drivers/pcmcia/pd6729.c
drivers/pcmcia/pxa2xx_mainstone.c
drivers/pcmcia/pxa2xx_sharpsl.c
drivers/pcmcia/tcic.c
drivers/power/power_supply.h
drivers/power/power_supply_sysfs.c
drivers/rtc/rtc-sh.c
drivers/s390/block/dasd_int.h
drivers/s390/block/xpram.c
drivers/s390/char/con3215.c
drivers/s390/char/con3270.c
drivers/s390/char/sclp.c
drivers/s390/char/tape_3590.c
drivers/s390/char/tty3270.c
drivers/s390/char/tty3270.h [new file with mode: 0644]
drivers/s390/char/vmwatchdog.c
drivers/s390/char/zcore.c
drivers/s390/cio/ccwgroup.c
drivers/s390/cio/chp.c
drivers/s390/cio/cio.c
drivers/s390/cio/cmf.c
drivers/s390/cio/css.c
drivers/s390/cio/css.h
drivers/s390/cio/device.c
drivers/s390/cio/device.h
drivers/s390/cio/device_fsm.c
drivers/s390/cio/device_ops.c
drivers/s390/cio/qdio.c
drivers/s390/crypto/ap_bus.c
drivers/s390/crypto/zcrypt_mono.c
drivers/s390/crypto/zcrypt_pcixcc.c
drivers/s390/crypto/zcrypt_pcixcc.h
drivers/s390/scsi/zfcp_aux.c
drivers/s390/scsi/zfcp_ccw.c
drivers/s390/scsi/zfcp_dbf.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/ipr.c
drivers/scsi/ips.c
drivers/scsi/ips.h
drivers/scsi/libsas/sas_ata.c
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/spi/spi.c
drivers/ssb/main.c
drivers/ssb/pcmcia.c
drivers/usb/Makefile
drivers/usb/atm/cxacru.c
drivers/usb/atm/speedtch.c
drivers/usb/atm/ueagle-atm.c
drivers/usb/atm/xusbatm.c
drivers/usb/class/usblp.c
drivers/usb/core/config.c
drivers/usb/core/devio.c
drivers/usb/core/driver.c
drivers/usb/core/endpoint.c
drivers/usb/core/generic.c
drivers/usb/core/hcd.c
drivers/usb/core/hcd.h
drivers/usb/core/hub.c
drivers/usb/core/message.c
drivers/usb/core/quirks.c
drivers/usb/core/sysfs.c
drivers/usb/core/urb.c
drivers/usb/core/usb.c
drivers/usb/core/usb.h
drivers/usb/gadget/Kconfig
drivers/usb/gadget/Makefile
drivers/usb/gadget/amd5536udc.c
drivers/usb/gadget/at91_udc.c
drivers/usb/gadget/atmel_usba_udc.c [new file with mode: 0644]
drivers/usb/gadget/atmel_usba_udc.h [new file with mode: 0644]
drivers/usb/gadget/config.c
drivers/usb/gadget/dummy_hcd.c
drivers/usb/gadget/epautoconf.c
drivers/usb/gadget/ether.c
drivers/usb/gadget/file_storage.c
drivers/usb/gadget/fsl_usb2_udc.c
drivers/usb/gadget/gmidi.c
drivers/usb/gadget/goku_udc.c
drivers/usb/gadget/inode.c
drivers/usb/gadget/lh7a40x_udc.h
drivers/usb/gadget/m66592-udc.c
drivers/usb/gadget/net2280.c
drivers/usb/gadget/omap_udc.c
drivers/usb/gadget/pxa2xx_udc.c
drivers/usb/gadget/s3c2410_udc.c
drivers/usb/gadget/serial.c
drivers/usb/gadget/usbstring.c
drivers/usb/gadget/zero.c
drivers/usb/host/Kconfig
drivers/usb/host/ehci-au1xxx.c
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-pci.c
drivers/usb/host/ehci-ppc-soc.c
drivers/usb/host/ehci-ps3.c
drivers/usb/host/ehci-q.c
drivers/usb/host/ehci-sched.c
drivers/usb/host/isp116x-hcd.c
drivers/usb/host/ohci-dbg.c
drivers/usb/host/ohci-hcd.c
drivers/usb/host/ohci-mem.c
drivers/usb/host/ohci-pci.c
drivers/usb/host/ohci-ppc-of.c
drivers/usb/host/ohci-ppc-soc.c
drivers/usb/host/ohci-q.c
drivers/usb/host/ohci-ssb.c [new file with mode: 0644]
drivers/usb/host/ohci.h
drivers/usb/host/r8a66597-hcd.c
drivers/usb/host/sl811-hcd.c
drivers/usb/host/u132-hcd.c
drivers/usb/host/uhci-debug.c
drivers/usb/host/uhci-hcd.h
drivers/usb/host/uhci-q.c
drivers/usb/image/microtek.c
drivers/usb/misc/adutux.c
drivers/usb/misc/berry_charge.c
drivers/usb/misc/ftdi-elan.c
drivers/usb/misc/sisusbvga/sisusb.c
drivers/usb/misc/sisusbvga/sisusb.h
drivers/usb/misc/sisusbvga/sisusb_con.c
drivers/usb/misc/sisusbvga/sisusb_init.c
drivers/usb/misc/sisusbvga/sisusb_init.h
drivers/usb/misc/sisusbvga/sisusb_struct.h
drivers/usb/mon/mon_bin.c
drivers/usb/mon/mon_main.c
drivers/usb/mon/mon_text.c
drivers/usb/mon/usb_mon.h
drivers/usb/serial/Kconfig
drivers/usb/serial/Makefile
drivers/usb/serial/ark3116.c
drivers/usb/serial/bus.c
drivers/usb/serial/ch341.c [new file with mode: 0644]
drivers/usb/serial/cp2101.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/funsoft.c
drivers/usb/serial/ipaq.c
drivers/usb/serial/kl5kusb105.c
drivers/usb/serial/kobil_sct.c
drivers/usb/serial/mct_u232.c
drivers/usb/serial/oti6858.c
drivers/usb/serial/pl2303.c
drivers/usb/serial/pl2303.h
drivers/usb/serial/safe_serial.c
drivers/usb/serial/ti_usb_3410_5052.c
drivers/usb/serial/usb-serial.c
drivers/usb/serial/visor.c
drivers/usb/storage/initializers.c
drivers/usb/storage/initializers.h
drivers/usb/storage/shuttle_usbat.c
drivers/usb/storage/transport.c
drivers/usb/storage/unusual_devs.h
drivers/usb/storage/usb.c
drivers/usb/usb-skeleton.c
drivers/video/backlight/hp680_bl.c
drivers/video/cg6.c
drivers/video/ffb.c
drivers/video/output.c
drivers/video/pvr2fb.c
drivers/video/xilinxfb.c
drivers/w1/w1.c
fs/Kconfig
fs/debugfs/file.c
fs/dlm/dlm_internal.h
fs/dlm/lock.c
fs/dlm/lock.h
fs/dlm/lockspace.c
fs/dlm/lowcomms.c
fs/dlm/member.c
fs/dlm/midcomms.c
fs/dlm/rcom.c
fs/dlm/rcom.h
fs/dlm/recoverd.c
fs/dlm/requestqueue.c
fs/dlm/requestqueue.h
fs/gfs2/bmap.c
fs/gfs2/daemon.c
fs/gfs2/daemon.h
fs/gfs2/dir.c
fs/gfs2/eaops.c
fs/gfs2/eaops.h
fs/gfs2/glock.c
fs/gfs2/glock.h
fs/gfs2/glops.c
fs/gfs2/incore.h
fs/gfs2/inode.c
fs/gfs2/inode.h
fs/gfs2/locking/dlm/lock_dlm.h
fs/gfs2/locking/dlm/plock.c
fs/gfs2/locking/dlm/sysfs.c
fs/gfs2/locking/dlm/thread.c
fs/gfs2/locking/nolock/main.c
fs/gfs2/log.c
fs/gfs2/log.h
fs/gfs2/lops.c
fs/gfs2/main.c
fs/gfs2/meta_io.c
fs/gfs2/meta_io.h
fs/gfs2/mount.c
fs/gfs2/ops_address.c
fs/gfs2/ops_export.c
fs/gfs2/ops_file.c
fs/gfs2/ops_fstype.c
fs/gfs2/ops_inode.c
fs/gfs2/ops_super.c
fs/gfs2/quota.c
fs/gfs2/recovery.c
fs/gfs2/rgrp.c
fs/gfs2/super.c
fs/gfs2/sys.c
fs/gfs2/trans.c
fs/gfs2/trans.h
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/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/ntfs/ChangeLog
fs/ntfs/Makefile
fs/ntfs/aops.c
fs/ntfs/attrib.c
fs/ntfs/file.c
fs/ntfs/inode.c
fs/ntfs/logfile.c
fs/ntfs/runlist.c
fs/ocfs2/alloc.c
fs/ocfs2/alloc.h
fs/ocfs2/aops.c
fs/ocfs2/aops.h
fs/ocfs2/cluster/masklog.c
fs/ocfs2/dir.c
fs/ocfs2/dir.h
fs/ocfs2/dlmglue.c
fs/ocfs2/dlmglue.h
fs/ocfs2/export.c
fs/ocfs2/extent_map.c
fs/ocfs2/file.c
fs/ocfs2/file.h
fs/ocfs2/inode.c
fs/ocfs2/inode.h
fs/ocfs2/journal.c
fs/ocfs2/journal.h
fs/ocfs2/namei.c
fs/ocfs2/namei.h
fs/ocfs2/ocfs2.h
fs/ocfs2/ocfs2_fs.h
fs/ocfs2/super.c
fs/ocfs2/sysfile.c
fs/partitions/check.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
fs/sysfs/bin.c
fs/sysfs/dir.c
fs/sysfs/file.c
fs/sysfs/group.c
fs/sysfs/inode.c
fs/sysfs/mount.c
fs/sysfs/symlink.c
fs/sysfs/sysfs.h
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/libata-portmap.h
include/asm-generic/vmlinux.lds.h
include/asm-m68k/Kbuild
include/asm-m68k/unistd.h
include/asm-mips/fw/cfe/cfe_api.h
include/asm-powerpc/io.h
include/asm-powerpc/of_device.h
include/asm-s390/cache.h
include/asm-s390/ccwdev.h
include/asm-s390/ccwgroup.h
include/asm-s390/cio.h
include/asm-s390/cmb.h
include/asm-s390/page.h
include/asm-s390/pgtable.h
include/asm-s390/s390_ext.h
include/asm-s390/system.h
include/asm-s390/zcrypt.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/8253pit.h [deleted file]
include/asm-x86/8253pit_32.h [deleted file]
include/asm-x86/8253pit_64.h [deleted file]
include/asm-x86/apic_64.h
include/asm-x86/cpufeature_64.h
include/asm-x86/geode.h
include/asm-x86/hardirq_32.h
include/asm-x86/hpet.h
include/asm-x86/hpet_32.h [deleted file]
include/asm-x86/hpet_64.h [deleted file]
include/asm-x86/i8253.h
include/asm-x86/i8253_32.h [deleted file]
include/asm-x86/i8253_64.h [deleted file]
include/asm-x86/io_apic_32.h
include/asm-x86/pci.h
include/asm-x86/pci_32.h
include/asm-x86/pci_64.h
include/asm-x86/pda.h
include/asm-x86/processor-flags.h
include/asm-x86/proto.h
include/asm-x86/system_32.h
include/asm-x86/system_64.h
include/asm-x86/timex.h
include/asm-x86/timex_32.h [deleted file]
include/asm-x86/timex_64.h [deleted file]
include/asm-x86/tsc.h
include/asm-x86/vsyscall.h
include/linux/agpgart.h
include/linux/ata.h
include/linux/blkdev.h
include/linux/blktrace_api.h
include/linux/clockchips.h
include/linux/cpufreq.h
include/linux/debugfs.h
include/linux/device.h
include/linux/gfs2_ondisk.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/jffs2.h
include/linux/jiffies.h
include/linux/kernel.h
include/linux/kernel_stat.h
include/linux/kobject.h
include/linux/kvm.h
include/linux/libata.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/netdevice.h
include/linux/nfsd/nfsd.h
include/linux/nfsd/nfsfh.h
include/linux/nfsd/xdr4.h
include/linux/pci.h
include/linux/pci_ids.h
include/linux/pci_regs.h
include/linux/platform_device.h
include/linux/reiserfs_fs_sb.h
include/linux/sched.h
include/linux/scx200_gpio.h
include/linux/stallion.h
include/linux/sunrpc/cache.h
include/linux/sysfs.h
include/linux/topology.h
include/linux/tty.h
include/linux/usb.h
include/linux/usb/gadget.h [new file with mode: 0644]
include/linux/usb/quirks.h
include/linux/usb/serial.h
include/linux/usb_gadget.h [deleted file]
include/linux/usb_sl811.h [deleted file]
include/linux/video_output.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/delayacct.c
kernel/exit.c
kernel/fork.c
kernel/ksysfs.c
kernel/posix-timers.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/Kconfig
kernel/time/Makefile
kernel/time/clockevents.c
kernel/time/tick-broadcast.c
kernel/time/tick-common.c
kernel/user.c
lib/Makefile
lib/idr.c
lib/kobject.c
lib/kobject_uevent.c
lib/swiotlb.c
mm/migrate.c
net/atm/atm_sysfs.c
net/bridge/br_sysfs_br.c
net/core/dev.c
net/core/net-sysfs.c
net/core/sock.c
net/ipv4/inet_lro.c
net/sctp/socket.c
net/sunrpc/auth_gss/svcauth_gss.c
net/sunrpc/svc.c
net/unix/af_unix.c
net/wireless/sysfs.c
scripts/mod/file2alias.c
sound/aoa/soundbus/core.c
sound/pci/bt87x.c
sound/usb/usbaudio.c

index cc7a8c39fb6fbf224483355cd169a2cee0d6a30a..b939ebb62871ec6b743b02cd78be1ca6d230baae 100644 (file)
@@ -68,6 +68,9 @@ size and dma_handle must all be the same as those passed into the
 consistent allocate.  cpu_addr must be the virtual address returned by
 the consistent allocate.
 
+Note that unlike their sibling allocation calls, these routines
+may only be called with IRQs enabled.
+
 
 Part Ib - Using small dma-coherent buffers
 ------------------------------------------
index 08687e45e19dcf7f68f84a70901a1abc4a95d829..1a7f53068ec2a01f0881be61c22d707b40381a67 100644 (file)
@@ -11,7 +11,7 @@ DOCBOOKS := wanbook.xml z8530book.xml mcabook.xml videobook.xml \
            procfs-guide.xml writing_usb_driver.xml \
            kernel-api.xml filesystems.xml lsm.xml usb.xml \
            gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \
-           genericirq.xml
+           genericirq.xml s390-drivers.xml
 
 ###
 # The build process is as follows (targets):
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){
diff --git a/Documentation/DocBook/s390-drivers.tmpl b/Documentation/DocBook/s390-drivers.tmpl
new file mode 100644 (file)
index 0000000..254e769
--- /dev/null
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+       "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+
+<book id="s390drivers">
+ <bookinfo>
+  <title>Writing s390 channel device drivers</title>
+
+  <authorgroup>
+   <author>
+    <firstname>Cornelia</firstname>
+    <surname>Huck</surname>
+    <affiliation>
+     <address>
+       <email>cornelia.huck@de.ibm.com</email>
+     </address>
+    </affiliation>
+   </author>
+  </authorgroup>
+
+  <copyright>
+   <year>2007</year>
+   <holder>IBM Corp.</holder>
+  </copyright>
+
+  <legalnotice>
+   <para>
+     This documentation 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.
+   </para>
+
+   <para>
+     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.
+   </para>
+
+   <para>
+     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
+   </para>
+
+   <para>
+     For more details see the file COPYING in the source
+     distribution of Linux.
+   </para>
+  </legalnotice>
+ </bookinfo>
+
+<toc></toc>
+
+  <chapter id="intro">
+   <title>Introduction</title>
+  <para>
+    This document describes the interfaces available for device drivers that
+    drive s390 based channel attached devices. This includes interfaces for
+    interaction with the hardware and interfaces for interacting with the
+    common driver core. Those interfaces are provided by the s390 common I/O
+    layer.
+  </para>
+  <para>
+    The document assumes a familarity with the technical terms associated
+    with the s390 channel I/O architecture. For a description of this
+    architecture, please refer to the "z/Architecture: Principles of
+    Operation", IBM publication no. SA22-7832.
+  </para>
+  <para>
+    While most I/O devices on a s390 system are typically driven through the
+    channel I/O mechanism described here, there are various other methods
+    (like the diag interface). These are out of the scope of this document.
+  </para>
+  <para>
+    Some additional information can also be found in the kernel source
+    under Documentation/s390/driver-model.txt.
+  </para>
+  </chapter>
+  <chapter id="ccw">
+   <title>The ccw bus</title>
+  <para>
+       The ccw bus typically contains the majority of devices available to
+       a s390 system. Named after the channel command word (ccw), the basic
+       command structure used to address its devices, the ccw bus contains
+       so-called channel attached devices. They are addressed via subchannels,
+       visible on the css bus. A device driver, however, will never interact
+       with the subchannel directly, but only via the device on the ccw bus,
+       the ccw device.
+  </para>
+    <sect1 id="channelIO">
+     <title>I/O functions for channel-attached devices</title>
+    <para>
+      Some hardware structures have been translated into C structures for use
+      by the common I/O layer and device drivers. For more information on
+      the hardware structures represented here, please consult the Principles
+      of Operation.
+    </para>
+!Iinclude/asm-s390/cio.h
+    </sect1>
+    <sect1 id="ccwdev">
+     <title>ccw devices</title>
+    <para>
+      Devices that want to initiate channel I/O need to attach to the ccw bus.
+      Interaction with the driver core is done via the common I/O layer, which
+      provides the abstractions of ccw devices and ccw device drivers.
+    </para>
+    <para>
+      The functions that initiate or terminate channel I/O all act upon a
+      ccw device structure. Device drivers must not bypass those functions
+      or strange side effects may happen.
+    </para>
+!Iinclude/asm-s390/ccwdev.h
+!Edrivers/s390/cio/device.c
+!Edrivers/s390/cio/device_ops.c
+    </sect1>
+    <sect1 id="cmf">
+     <title>The channel-measurement facility</title>
+  <para>
+       The channel-measurement facility provides a means to collect
+       measurement data which is made available by the channel subsystem
+       for each channel attached device.
+  </para>
+!Iinclude/asm-s390/cmb.h
+!Edrivers/s390/cio/cmf.c
+    </sect1>
+  </chapter>
+
+  <chapter id="ccwgroup">
+   <title>The ccwgroup bus</title>
+  <para>
+       The ccwgroup bus only contains artificial devices, created by the user.
+       Many networking devices (e.g. qeth) are in fact composed of several
+       ccw devices (like read, write and data channel for qeth). The
+       ccwgroup bus provides a mechanism to create a meta-device which
+       contains those ccw devices as slave devices and can be associated
+       with the netdevice.
+  </para>
+   <sect1 id="ccwgroupdevices">
+    <title>ccw group devices</title>
+!Iinclude/asm-s390/ccwgroup.h
+!Edrivers/s390/cio/ccwgroup.c
+   </sect1>
+  </chapter>
+
+</book>
index 0d8240774fca2d3bc00454ce5bc65ec20fe09e2e..a51f693c15419e9b2da87df025b69d898f648b51 100644 (file)
@@ -241,68 +241,7 @@ address space of the MSI-X table/MSI-X PBA. Otherwise, the PCI subsystem
 will fail enabling MSI-X on its hardware device when it calls the function
 pci_enable_msix().
 
-5.3.2 Handling MSI-X allocation
-
-Determining the number of MSI-X vectors allocated to a function is
-dependent on the number of MSI capable devices and MSI-X capable
-devices populated in the system. The policy of allocating MSI-X
-vectors to a function is defined as the following:
-
-#of MSI-X vectors allocated to a function = (x - y)/z where
-
-x =    The number of available PCI vector resources by the time
-       the device driver calls pci_enable_msix(). The PCI vector
-       resources is the sum of the number of unassigned vectors
-       (new) and the number of released vectors when any MSI/MSI-X
-       device driver switches its hardware device back to a legacy
-       mode or is hot-removed. The number of unassigned vectors
-       may exclude some vectors reserved, as defined in parameter
-       NR_HP_RESERVED_VECTORS, for the case where the system is
-       capable of supporting hot-add/hot-remove operations. Users
-       may change the value defined in NR_HR_RESERVED_VECTORS to
-       meet their specific needs.
-
-y =    The number of MSI capable devices populated in the system.
-       This policy ensures that each MSI capable device has its
-       vector reserved to avoid the case where some MSI-X capable
-       drivers may attempt to claim all available vector resources.
-
-z =    The number of MSI-X capable devices populated in the system.
-       This policy ensures that maximum (x - y) is distributed
-       evenly among MSI-X capable devices.
-
-Note that the PCI subsystem scans y and z during a bus enumeration.
-When the PCI subsystem completes configuring MSI/MSI-X capability
-structure of a device as requested by its device driver, y/z is
-decremented accordingly.
-
-5.3.3 Handling MSI-X shortages
-
-For the case where fewer MSI-X vectors are allocated to a function
-than requested, the function pci_enable_msix() will return the
-maximum number of MSI-X vectors available to the caller. A device
-driver may re-send its request with fewer or equal vectors indicated
-in the return. For example, if a device driver requests 5 vectors, but
-the number of available vectors is 3 vectors, a value of 3 will be
-returned as a result of pci_enable_msix() call. A function could be
-designed for its driver to use only 3 MSI-X table entries as
-different combinations as ABC--, A-B-C, A--CB, etc. Note that this
-patch does not support multiple entries with the same vector. Such
-attempt by a device driver to use 5 MSI-X table entries with 3 vectors
-as ABBCC, AABCC, BCCBA, etc will result as a failure by the function
-pci_enable_msix(). Below are the reasons why supporting multiple
-entries with the same vector is an undesirable solution.
-
-       - The PCI subsystem cannot determine the entry that
-         generated the message to mask/unmask MSI while handling
-         software driver ISR. Attempting to walk through all MSI-X
-         table entries (2048 max) to mask/unmask any match vector
-         is an undesirable solution.
-
-       - Walking through all MSI-X table entries (2048 max) to handle
-         SMP affinity of any match vector is an undesirable solution.
-
-5.3.4 API pci_enable_msix
+5.3.2 API pci_enable_msix
 
 int pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, int nvec)
 
@@ -339,7 +278,7 @@ a failure. This failure may be a result of duplicate entries
 specified in second argument, or a result of no available vector,
 or a result of failing to initialize MSI-X table entries.
 
-5.3.5 API pci_disable_msix
+5.3.3 API pci_disable_msix
 
 void pci_disable_msix(struct pci_dev *dev)
 
@@ -349,7 +288,7 @@ always call free_irq() on all MSI-X vectors it has done request_irq()
 on before calling this API. Failure to do so results in a BUG_ON() and
 a device will be left with MSI-X enabled and leaks its vectors.
 
-5.3.6 MSI-X mode vs. legacy mode diagram
+5.3.4 MSI-X mode vs. legacy mode diagram
 
 The below diagram shows the events which switch the interrupt
 mode on the MSI-X capable device function between MSI-X mode and
@@ -407,7 +346,7 @@ between MSI mod MSI-X mode during a run-time.
 MSI/MSI-X support requires support from both system hardware and
 individual hardware device functions.
 
-5.5.1 System hardware support
+5.5.1 Required x86 hardware support
 
 Since the target of MSI address is the local APIC CPU, enabling
 MSI/MSI-X support in the Linux kernel is dependent on whether existing
index 8ee10ec882936d1725e948554da052b3c7d09426..e79ee2db183a0a19f09bccb810a29794ab72031e 100644 (file)
@@ -407,7 +407,7 @@ raiddev /dev/md0
        device          /dev/hda5
        raid-disk       0
        device          /dev/hdb1
-       raid-disl       1
+       raid-disk       1
 
 For linear raid, just change the raid-level above to "raid-level linear", for
 mirrors, change it to "raid-level 1", and for stripe sets with parity, change
@@ -457,6 +457,8 @@ ChangeLog
 
 Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
 
+2.1.29:
+       - Fix a deadlock when mounting read-write.
 2.1.28:
        - Fix a deadlock.
 2.1.27:
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 9f08dab1e75be0d2ea0b39315c82fdc7023e60d5..d9d832c010ef4fb21ce5a768bb4ed87df40f816b 100644 (file)
@@ -1,4 +1,4 @@
-NOTE:
+NOTE:
 This is a version of Documentation/HOWTO translated into Japanese.
 This document is maintained by Tsugikazu Shibata <tshibata@ab.jp.nec.com>
 and the JF Project team <www.linux.or.jp/JF>.
@@ -11,14 +11,14 @@ for non English (read: Japanese) speakers and is not intended as a
 fork. So if you have any comments or updates for this file, please try
 to update the original English file first.
 
-Last Updated: 2007/07/18
+Last Updated: 2007/09/23
 ==================================
 これは、
-linux-2.6.22/Documentation/HOWTO
+linux-2.6.23/Documentation/HOWTO
 の和訳です。
 
 翻訳団体: JF プロジェクト < http://www.linux.or.jp/JF/ >
-翻訳日: 2007/07/16
+翻訳日: 2007/09/19
 翻訳者: Tsugikazu Shibata <tshibata at ab dot jp dot nec dot com>
 校正者: 松倉さん <nbh--mats at nifty dot com>
          小林 雅典さん (Masanori Kobayasi) <zap03216 at nifty dot ne dot jp>
@@ -27,6 +27,7 @@ linux-2.6.22/Documentation/HOWTO
          野口さん (Kenji Noguchi) <tokyo246 at gmail dot com>
          河内さん (Takayoshi Kochi) <t-kochi at bq dot jp dot nec dot com>
          岩本さん (iwamoto) <iwamoto.kn at ncos dot nec dot co dot jp>
+         内田さん (Satoshi Uchida) <s-uchida at ap dot jp dot nec dot com>
 ==================================
 
 Linux カーネル開発のやり方
@@ -40,7 +41,7 @@ Linux カーネル開発コミュニティと共に活動するやり方を学
 手助けになります。
 
 もし、このドキュメントのどこかが古くなっていた場合には、このドキュメン
\83\88ã\81®æ\9c\80å¾\8cã\81«ã\83ªã\82¹ã\83\88ã\81\97ã\81\9fã\83¡ã\83³ã\83\86ã\83\8aã\83¼ã\81«ã\83\91ã\83\83ã\83\81ã\82\92é\80\81ã\81£ã\81¦ã\81\8fã\81 ã\81\95ã\81\84ã\80\82
+トの最後にリストしたメンテナにパッチを送ってください。
 
 はじめに
 ---------
@@ -59,7 +60,7 @@ Linux カーネル開発コミュニティと共に活動するやり方を学
 ネル開発者には必要です。アーキテクチャ向けの低レベル部分の開発をするの
 でなければ、(どんなアーキテクチャでも)アセンブリ(訳注: 言語)は必要あり
 ません。以下の本は、C 言語の十分な知識や何年もの経験に取って代わるもの
-ではありませんが、少なくともリファレンスとしてはい本です。
+ではありませんが、少なくともリファレンスとしてはい本です。
  - "The C Programming Language" by Kernighan and Ritchie [Prentice Hall]
  -『プログラミング言語C第2版』(B.W. カーニハン/D.M. リッチー著 石田晴久訳) [共立出版]
  - "Practical C Programming" by Steve Oualline [O'Reilly]
@@ -76,7 +77,7 @@ Linux カーネル開発コミュニティと共に活動するやり方を学
 ときどき、カーネルがツールチェインや C 言語拡張に置いている前提がどう
 なっているのかわかりにくいことがあり、また、残念なことに決定的なリファ
 レンスは存在しません。情報を得るには、gcc の info ページ( info gcc )を
-てください。
+てください。
 
 あなたは既存の開発コミュニティと一緒に作業する方法を学ぼうとしているこ
 とに留意してください。そのコミュニティは、コーディング、スタイル、
@@ -92,7 +93,7 @@ Linux カーネル開発コミュニティと共に活動するやり方を学
 
 Linux カーネルのソースコードは GPL ライセンスの下でリリースされていま
 す。ライセンスの詳細については、ソースツリーのメインディレクトリに存在
-する、COPYING のファイルをてください。もしライセンスについてさらに質
+する、COPYING のファイルをてください。もしライセンスについてさらに質
 問があれば、Linux Kernel メーリングリストに質問するのではなく、どうぞ
 法律家に相談してください。メーリングリストの人達は法律家ではなく、法的
 問題については彼らの声明はあてにするべきではありません。
@@ -109,7 +110,8 @@ Linux カーネルソースツリーは幅広い範囲のドキュメントを
 新しいドキュメントファイルも追加することを勧めます。
 カーネルの変更が、カーネルがユーザ空間に公開しているインターフェイスの
 変更を引き起こす場合、その変更を説明するマニュアルページのパッチや情報
-をマニュアルページのメンテナ mtk-manpages@gmx.net に送ることを勧めます。
+をマニュアルページのメンテナ mtk-manpages@gmx.net に送ることを勧めま
+す。
 
 以下はカーネルソースツリーに含まれている読んでおくべきファイルの一覧で
 す-
@@ -117,7 +119,7 @@ Linux カーネルソースツリーは幅広い範囲のドキュメントを
   README
     このファイルは Linuxカーネルの簡単な背景とカーネルを設定(訳注
     configure )し、生成(訳注 build )するために必要なことは何かが書かれ
-    ています。カーネルに関して初めての人はここからスタートするといで
+    ています。カーネルに関して初めての人はここからスタートするといで
     しょう。
 
   Documentation/Changes
@@ -128,7 +130,7 @@ Linux カーネルソースツリーは幅広い範囲のドキュメントを
   Documentation/CodingStyle
     これは Linux カーネルのコーディングスタイルと背景にある理由を記述
     しています。全ての新しいコードはこのドキュメントにあるガイドライン
-    ã\81«å¾\93ã\81£ã\81¦ã\81\84ã\82\8bã\81\93ã\81¨ã\82\92æ\9c\9få¾\85ã\81\95ã\82\8cã\81¦ã\81\84ã\81¾ã\81\99ã\80\82大é\83¨å\88\86ã\81®ã\83¡ã\83³ã\83\86ã\83\8aã\83¼ã\81¯ã\81\93ã\82\8cã\82\89ã\81®ã\83«ã\83¼
+    に従っていることを期待されています。大部分のメンテナはこれらのルー
     ルに従っているものだけを受け付け、多くの人は正しいスタイルのコード
     だけをレビューします。
 
@@ -168,16 +170,16 @@ Linux カーネルソースツリーは幅広い範囲のドキュメントを
     支援してください。
 
   Documentation/ManagementStyle
-    このドキュメントは Linux カーネルのメンテナ達がどう行動するか、
+    このドキュメントは Linux カーネルのメンテナ達がどう行動するか、
     彼らの手法の背景にある共有されている精神について記述しています。こ
     れはカーネル開発の初心者なら(もしくは、単に興味があるだけの人でも)
-    重要です。なぜならこのドキュメントは、カーネルメンテナ達の独特な
+    重要です。なぜならこのドキュメントは、カーネルメンテナ達の独特な
     行動についての多くの誤解や混乱を解消するからです。
 
   Documentation/stable_kernel_rules.txt
     このファイルはどのように stable カーネルのリリースが行われるかのルー
     ルが記述されています。そしてこれらのリリースの中のどこかで変更を取
-    り入れてもらいたい場合に何をすればいかが示されています。
+    り入れてもらいたい場合に何をすればいかが示されています。
 
   Documentation/kernel-docs.txt
   カーネル開発に付随する外部ドキュメントのリストです。もしあなたが
@@ -218,9 +220,9 @@ web サイトには、コードの構成、サブシステム、現在存在す
 ここには、また、カーネルのコンパイルのやり方やパッチの当て方などの間接
 的な基本情報も記述されています。
 
-あなたがどこからスタートしていかわからないが、Linux カーネル開発コミュ
+あなたがどこからスタートしていかわからないが、Linux カーネル開発コミュ
 ニティに参加して何かすることをさがしている場合には、Linux kernel
-Janitor's プロジェクトにいけばいでしょう -
+Janitor's プロジェクトにいけばいでしょう -
        http://janitor.kernelnewbies.org/
 ここはそのようなスタートをするのにうってつけの場所です。ここには、
 Linux カーネルソースツリーの中に含まれる、きれいにし、修正しなければな
@@ -243,7 +245,7 @@ Linux カーネルソースツリーの中に含まれる、きれいにし、
 自己参照方式で、索引がついた web 形式で、ソースコードを参照することが
 できます。この最新の素晴しいカーネルコードのリポジトリは以下で見つかり
 ます-
-       http://sosdg.org/~coywolf/lxr/
+       http://sosdg.org/~qiyong/lxr/
 
 開発プロセス
 -----------------------
@@ -265,9 +267,9 @@ Linux カーネルの開発プロセスは現在幾つかの異なるメイン
 以下のとおり-
 
   - 新しいカーネルがリリースされた直後に、2週間の特別期間が設けられ、
-    この期間中に、メンテナー達は Linus に大きな差分を送ることができま
-    ã\81\99ã\80\82ã\81\93ã\81®ã\82\88ã\81\86ã\81ªå·®å\88\86ã\81¯é\80\9a常 -mm ã\82«ã\83¼ã\83\8dã\83«ã\81«æ\95°é\80±é\96\93å\90«ã\81¾ã\82\8cã\81¦ã\81\8dã\81\9fã\83\91ã\83\83ã\83\81ã\81§
-    す。 大きな変更は git(カーネルのソース管理ツール、詳細は
+    この期間中に、メンテナ達は Linus に大きな差分を送ることができます。
+    ã\81\93ã\81®ã\82\88ã\81\86ã\81ªå·®å\88\86ã\81¯é\80\9a常 -mm ã\82«ã\83¼ã\83\8dã\83«ã\81«æ\95°é\80±é\96\93å\90«ã\81¾ã\82\8cã\81¦ã\81\8dã\81\9fã\83\91ã\83\83ã\83\81ã\81§ã\81\99ã\80\82
+    大きな変更は git(カーネルのソース管理ツール、詳細は
     http://git.or.cz/  参照) を使って送るのが好ましいやり方ですが、パッ
     チファイルの形式のまま送るのでも十分です。
 
@@ -285,6 +287,10 @@ Linux カーネルの開発プロセスは現在幾つかの異なるメイン
     に安定した状態にあると判断したときにリリースされます。目標は毎週新
     しい -rc カーネルをリリースすることです。
 
+   - 以下の URL で各 -rc リリースに存在する既知の後戻り問題のリスト
+     が追跡されます-
+     http://kernelnewbies.org/known_regressions
+
   - このプロセスはカーネルが 「準備ができた」と考えられるまで継続しま
     す。このプロセスはだいたい 6週間継続します。
 
@@ -331,8 +337,8 @@ Andrew は個別のサブシステムカーネルツリーとパッチを全て
 linux-kernel メーリングリストで収集された多数のパッチと同時に一つにま
 とめます。
 このツリーは新機能とパッチが検証される場となります。ある期間の間パッチ
-が -mm に入って価値を証明されたら、Andrew やサブシステムメンテナが、
-インラインへ入れるように Linus にプッシュします。
+が -mm に入って価値を証明されたら、Andrew やサブシステムメンテナが、
\83¡ã\82¤ã\83³ã\83©ã\82¤ã\83³ã\81¸å\85¥ã\82\8cã\82\8bã\82\88ã\81\86ã\81« Linus ã\81«ã\83\97ã\83\83ã\82·ã\83¥ã\81\97ã\81¾ã\81\99ã\80\82
 
 メインカーネルツリーに含めるために Linus に送る前に、すべての新しいパッ
 チが -mm ツリーでテストされることが強く推奨されます。
@@ -460,7 +466,7 @@ MAINTAINERS ファイルにリストがありますので参照してくださ
 せん-
 彼らはあなたのパッチの行毎にコメントを入れたいので、そのためにはそうす
 るしかありません。あなたのメールプログラムが空白やタブを圧縮しないよう
-に確認した方がいです。最初の良いテストとしては、自分にメールを送って
+に確認した方がいです。最初の良いテストとしては、自分にメールを送って
 みて、そのパッチを自分で当ててみることです。もしそれがうまく行かないな
 ら、あなたのメールプログラムを直してもらうか、正しく動くように変えるべ
 きです。
@@ -507,14 +513,14 @@ MAINTAINERS ファイルにリストがありますので参照してくださ
 とも普通のことです。これはあなたのパッチが受け入れられないということで
 は *ありません*、そしてあなた自身に反対することを意味するのでも *ありま
 せん*。単に自分のパッチに対して指摘された問題を全て修正して再送すれば
-いのです。
+いのです。
 
 
 カーネルコミュニティと企業組織のちがい
 -----------------------------------------------------------------
 
 カーネルコミュニティは大部分の伝統的な会社の開発環境とは異ったやり方で
-動いています。以下は問題を避けるためにできるとよいことののリストです-
+動いています。以下は問題を避けるためにできると良いことのリストです-
 
   あなたの提案する変更について言うときのうまい言い方:
 
@@ -525,7 +531,7 @@ MAINTAINERS ファイルにリストがありますので参照してくださ
     - "以下は一連の小さなパッチ群ですが..."
     - "これは典型的なマシンでの性能を向上させます.."
 
-  やめた方がい悪い言い方:
+  やめた方がい悪い言い方:
 
     - このやり方で AIX/ptx/Solaris ではできたので、できるはずだ
     - 私はこれを20年もの間やってきた、だから
@@ -575,10 +581,10 @@ Linux カーネルコミュニティは、一度に大量のコードの塊を
 
 1) 小さいパッチはあなたのパッチが適用される見込みを大きくします、カー
    ネルの人達はパッチが正しいかどうかを確認する時間や労力をかけないか
-   らです。5行のパッチはメンテナがたった1秒見るだけで適用できます。
-   ã\81\8bã\81\97ã\80\81500è¡\8cã\81®ã\83\91ã\83\83ã\83\81ã\81¯ã\80\81æ­£ã\81\97ã\81\84ã\81\93ã\81¨ã\82\92ã\83¬ã\83\93ã\83¥ã\83¼ã\81\99ã\82\8bã\81®ã\81«æ\95°æ\99\82é\96\93ã\81\8bã\81\8bã\82\8bã\81\8bã\82\82
-   ã\81\97ã\82\8cã\81¾ã\81\9bã\82\93\99\82é\96\93ã\81¯ã\83\91ã\83\83ã\83\81ã\81®ã\82µã\82¤ã\82ºã\81ªã\81©ã\81«ã\82\88ã\82\8aæ\8c\87æ\95°é\96¢æ\95°ã\81«æ¯\94ä¾\8bã\81\97ã\81¦ã\81\8bã\81\8bã\82\8aã\81¾
-   す)
+   らです。5行のパッチはメンテナがたった1秒見るだけで適用できます。
+   ã\81\97ã\81\8bã\81\97ã\80\81500è¡\8cã\81®ã\83\91ã\83\83ã\83\81ã\81¯ã\80\81æ­£ã\81\97ã\81\84ã\81\93ã\81¨ã\82\92ã\83¬ã\83\93ã\83¥ã\83¼ã\81\99ã\82\8bã\81®ã\81«æ\95°æ\99\82é\96\93ã\81\8bã\81\8bã\82\8bã\81\8b
+   ã\82\82ã\81\97ã\82\8cã\81¾ã\81\9bã\82\93\99\82é\96\93ã\81¯ã\83\91ã\83\83ã\83\81ã\81®ã\82µã\82¤ã\82ºã\81ªã\81©ã\81«ã\82\88ã\82\8aæ\8c\87æ\95°é\96¢æ\95°ã\81«æ¯\94ä¾\8bã\81\97ã\81¦ã\81\8bã\81\8bã\82\8a
+   ã\81¾ã\81\99)
 
    小さいパッチは何かあったときにデバッグもとても簡単になります。パッ
    チを1個1個取り除くのは、とても大きなパッチを当てた後に(かつ、何かお
@@ -587,23 +593,23 @@ Linux カーネルコミュニティは、一度に大量のコードの塊を
 2) 小さいパッチを送るだけでなく、送るまえに、書き直して、シンプルにす
    る(もしくは、単に順番を変えるだけでも)ことも、とても重要です。
 
-以ä¸\8bã\81¯ã\82«ã\83¼ã\83\8dã\83«é\96\8bç\99ºè\80\85ã\81® Al Viro ã\81®ã\81\9fã\81¨ã\81\88話ã\81\97ã\81§ã\81\99ï¼\9a
+以下はカーネル開発者の Al Viro のたとえ話です:
 
         "生徒の数学の宿題を採点する先生のことを考えてみてください、先
-        生は生徒が解に到達するまでの試行錯誤をたいとは思わないでしょ
-        う。先生は簡潔な最高の解をたいのです。良い生徒はこれを知って
+        生は生徒が解に到達するまでの試行錯誤をたいとは思わないでしょ
+        う。先生は簡潔な最高の解をたいのです。良い生徒はこれを知って
         おり、そして最終解の前の中間作業を提出することは決してないので
         す"
 
-        カーネル開発でもこれは同じです。メンテナ達とレビューア達は、
-        問題を解決する解の背後になる思考プロセスをたいとは思いません。
-        彼らは単純であざやかな解決方法をたいのです。
+        カーネル開発でもこれは同じです。メンテナ達とレビューア達は、
+        問題を解決する解の背後になる思考プロセスをたいとは思いません。
+        彼らは単純であざやかな解決方法をたいのです。
 
 あざやかな解を説明するのと、コミュニティと共に仕事をし、未解決の仕事を
 議論することのバランスをキープするのは難しいかもしれません。
 ですから、開発プロセスの早期段階で改善のためのフィードバックをもらうよ
-うにするのもいですが、変更点を小さい部分に分割して全体ではまだ完成し
-ていない仕事を(部分的に)取り込んでもらえるようにすることもいことです。
+うにするのもいですが、変更点を小さい部分に分割して全体ではまだ完成し
+ていない仕事を(部分的に)取り込んでもらえるようにすることもいことです。
 
 また、でき上がっていないものや、"将来直す" ようなパッチを、本流に含め
 てもらうように送っても、それは受け付けられないことを理解してください。
@@ -629,7 +635,7 @@ Linux カーネルコミュニティは、一度に大量のコードの塊を
   - テスト結果
 
 これについて全てがどのようにあるべきかについての詳細は、以下のドキュメ
-ントの ChangeLog セクションをてください-
+ントの ChangeLog セクションをてください-
   "The Perfect Patch"
       http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt
 
index a57c1f216b2154d352b6b3fc9b94a1f47d2cf0b1..c323778270ff5f3f955e5c12e905f5b7d68dc9ff 100644 (file)
@@ -68,6 +68,7 @@ parameter is applicable:
        PARIDE  The ParIDE (parallel port IDE) subsystem is enabled.
        PARISC  The PA-RISC architecture is enabled.
        PCI     PCI bus support is enabled.
+       PCIE    PCI Express support is enabled.
        PCMCIA  The PCMCIA subsystem is enabled.
        PNP     Plug & Play support is enabled.
        PPC     PowerPC architecture is enabled.
@@ -864,6 +865,10 @@ and is between 256 and 4096 characters. It is defined in the file
        lasi=           [HW,SCSI] PARISC LASI driver for the 53c700 chip
                        Format: addr:<io>,irq:<irq>
 
+       libata.noacpi   [LIBATA] Disables use of ACPI in libata suspend/resume
+                       when set.
+                       Format: <int>
+
        load_ramdisk=   [RAM] List of ramdisks to load from floppy
                        See Documentation/ramdisk.txt.
 
@@ -1009,6 +1014,10 @@ and is between 256 and 4096 characters. It is defined in the file
        meye.*=         [HW] Set MotionEye Camera parameters
                        See Documentation/video4linux/meye.txt.
 
+       mfgpt_irq=      [IA-32] Specify the IRQ to use for the
+                       Multi-Function General Purpose Timers on AMD Geode
+                       platforms.
+
        mga=            [HW,DRM]
 
        mousedev.tap_time=
@@ -1080,10 +1089,6 @@ and is between 256 and 4096 characters. It is defined in the file
                        emulation library even if a 387 maths coprocessor
                        is present.
 
-       noacpi          [LIBATA] Disables use of ACPI in libata suspend/resume
-                       when set.
-                       Format: <int>
-
        noaliencache    [MM, NUMA, SLAB] Disables the allocation of alien
                        caches in the slab allocator.  Saves per-node memory,
                        but will impact performance.
@@ -1160,6 +1165,9 @@ and is between 256 and 4096 characters. It is defined in the file
 
        nomce           [X86-32] Machine Check Exception
 
+       nomfgpt         [X86-32] Disable Multi-Function General Purpose
+                       Timer usage (for AMD Geode machines).
+
        noreplace-paravirt      [X86-32,PV_OPS] Don't patch paravirt_ops
 
        noreplace-smp   [X86-32,SMP] Don't replace SMP instructions
@@ -1270,6 +1278,11 @@ and is between 256 and 4096 characters. It is defined in the file
                                Mechanism 1.
                conf2           [X86-32] Force use of PCI Configuration
                                Mechanism 2.
+               noaer           [PCIE] If the PCIEAER kernel config parameter is
+                               enabled, this kernel boot option can be used to
+                               disable the use of PCIE advanced error reporting.
+               nodomains       [PCI] Disable support for multiple PCI
+                               root domains (aka PCI segments, in ACPI-speak).
                nommconf        [X86-32,X86_64] Disable use of MMCONFIG for PCI
                                Configuration
                nomsi           [MSI] If the PCI_MSI kernel config parameter is
@@ -1314,6 +1327,8 @@ and is between 256 and 4096 characters. It is defined in the file
                                IRQ routing is enabled.
                noacpi          [X86-32] Do not use ACPI for IRQ routing
                                or for PCI scanning.
+               use_crs         [X86-32] Use _CRS for PCI resource
+                               allocation.
                routeirq        Do IRQ routing for all PCI devices.
                                This is normally done in pci_enable_device(),
                                so this option is a temporary workaround
@@ -1430,6 +1445,10 @@ and is between 256 and 4096 characters. It is defined in the file
        pt.             [PARIDE]
                        See Documentation/paride.txt.
 
+       pty.legacy_count=
+                       [KNL] Number of legacy pty's. Overwrites compiled-in
+                       default number.
+
        quiet           [KNL] Disable most log messages
 
        r128=           [HW,DRM]
index 8ee49ee7c9636ad6b16cd0ecf3e98539ff818fee..ca86a885ad8f71c6f98647debd50bf293b33de47 100644 (file)
@@ -54,7 +54,6 @@ embedded in larger data structures and replace fields they duplicate.
 
 struct kobject {
        const char              * k_name;
-       char                    name[KOBJ_NAME_LEN];
        struct kref             kref;
        struct list_head        entry;
        struct kobject          * parent;
@@ -223,18 +222,15 @@ decl_subsys(devices, &ktype_device, &device_uevent_ops);
 is equivalent to doing:
 
 struct kset devices_subsys = {
-     .kobj = {
-          .name = "devices",
-     },
      .ktype = &ktype_devices,
      .uevent_ops = &device_uevent_ops,
 };
-
+kobject_set_name(&devices_subsys, name);
 
 The objects that are registered with a subsystem that use the
 subsystem's default list must have their kset ptr set properly. These
 objects may have embedded kobjects or ksets. The
-following helpers make setting the kset easier:
+following helper makes setting the kset easier:
 
 
 kobj_set_kset_s(obj,subsys)
@@ -242,22 +238,8 @@ kobj_set_kset_s(obj,subsys)
 - Assumes that obj->kobj exists, and is a struct kobject.
 - Sets the kset of that kobject to the kset <subsys>.
 
-
-kset_set_kset_s(obj,subsys)
-
-- Assumes that obj->kset exists, and is a struct kset.
-- Sets the kset of the embedded kobject to the kset <subsys>.
-
-subsys_set_kset(obj,subsys)
-
-- Assumes obj->subsys exists, and is a struct subsystem.
-- Sets obj->subsys.kset.kobj.kset to the subsystem's embedded kset.
-
-void subsystem_init(struct kset *s);
 int subsystem_register(struct kset *s);
 void subsystem_unregister(struct kset *s);
-struct kset *subsys_get(struct kset *s);
-void kset_put(struct kset *s);
 
 These are just wrappers around the respective kset_* functions.
 
diff --git a/Documentation/s390/00-INDEX b/Documentation/s390/00-INDEX
new file mode 100644 (file)
index 0000000..3a2b963
--- /dev/null
@@ -0,0 +1,26 @@
+00-INDEX
+       - this file.
+3270.ChangeLog
+       - ChangeLog for the UTS Global 3270-support patch (outdated).
+3270.txt
+       - how to use the IBM 3270 display system support.
+cds.txt
+       - s390 common device support (common I/O layer).
+CommonIO
+       - common I/O layer command line parameters, procfs and debugfs  entries
+config3270.sh
+       - example configuration for 3270 devices.
+DASD
+       - information on the DASD disk device driver.
+Debugging390.txt
+       - hints for debugging on s390 systems.
+driver-model.txt
+       - information on s390 devices and the driver model.
+monreader.txt
+       - information on accessing the z/VM monitor stream from Linux.
+s390dbf.txt
+       - information on using the s390 debug feature.
+TAPE
+       - information on the driver for channel-attached tapes.
+zfcpdump
+       - information on the s390 SCSI dump tool.
index 22f82f21bc605395b4fa34d7a85cc8ad63bd2e07..86320aa3fb0b4728c2e6f581c2e346f3d018088d 100644 (file)
@@ -1,5 +1,5 @@
-S/390 common I/O-Layer - command line parameters and /proc entries
-==================================================================
+S/390 common I/O-Layer - command line parameters, procfs and debugfs entries
+============================================================================
 
 Command line parameters
 -----------------------
@@ -7,9 +7,9 @@ Command line parameters
 * cio_msg = yes | no
   
   Determines whether information on found devices and sensed device 
-  characteristics should be shown during startup, i. e. messages of the types 
-  "Detected device 0.0.4711 on subchannel 0.0.0042" and "SenseID: Device
-  0.0.4711 reports: ...".
+  characteristics should be shown during startup or when new devices are
+  found, i. e. messages of the types "Detected device 0.0.4711 on subchannel
+  0.0.0042" and "SenseID: Device 0.0.4711 reports: ...".
 
   Default is off.
 
@@ -26,8 +26,10 @@ Command line parameters
   An ignored device can be un-ignored later; see the "/proc entries"-section for
   details.
 
-  The devices must be given either as bus ids (0.0.abcd) or as hexadecimal
-  device numbers (0xabcd or abcd, for 2.4 backward compatibility).
+  The devices must be given either as bus ids (0.x.abcd) or as hexadecimal
+  device numbers (0xabcd or abcd, for 2.4 backward compatibility). If you
+  give a device number 0xabcd, it will be interpreted as 0.0.abcd.
+
   You can use the 'all' keyword to ignore all devices.
   The '!' operator will cause the I/O-layer to _not_ ignore a device.
   The command line is parsed from left to right.
@@ -81,31 +83,36 @@ Command line parameters
   will add 0.0.a000-0.0.accc and 0.0.af00-0.0.afff to the list of ignored
   devices.
 
-  The devices can be specified either by bus id (0.0.abcd) or, for 2.4 backward
-  compatibility, by the device number in hexadecimal (0xabcd or abcd).
+  The devices can be specified either by bus id (0.x.abcd) or, for 2.4 backward
+  compatibility, by the device number in hexadecimal (0xabcd or abcd). Device
+  numbers given as 0xabcd will be interpreted as 0.0.abcd.
+
+* For some of the information present in the /proc filesystem in 2.4 (namely,
+  /proc/subchannels and /proc/chpids), see driver-model.txt.
+  Information formerly in /proc/irq_count is now in /proc/interrupts.
+
 
+debugfs entries
+---------------
 
-* /proc/s390dbf/cio_*/ (S/390 debug feature)
+* /sys/kernel/debug/s390dbf/cio_*/ (S/390 debug feature)
 
   Some views generated by the debug feature to hold various debug outputs.
 
-  - /proc/s390dbf/cio_crw/sprintf
+  - /sys/kernel/debug/s390dbf/cio_crw/sprintf
     Messages from the processing of pending channel report words (machine check
-    handling), which will also show when CONFIG_DEBUG_CRW is defined.
+    handling).
 
-  - /proc/s390dbf/cio_msg/sprintf
-    Various debug messages from the common I/O-layer; generally, messages which 
-    will also show when CONFIG_DEBUG_IO is defined.
+  - /sys/kernel/debug/s390dbf/cio_msg/sprintf
+    Various debug messages from the common I/O-layer, including messages
+    printed when cio_msg=yes.
 
-  - /proc/s390dbf/cio_trace/hex_ascii
+  - /sys/kernel/debug/s390dbf/cio_trace/hex_ascii
     Logs the calling of functions in the common I/O-layer and, if applicable, 
     which subchannel they were called for, as well as dumps of some data
     structures (like irb in an error case).
 
   The level of logging can be changed to be more or less verbose by piping to 
-  /proc/s390dbf/cio_*/level a number between 0 and 6; see the documentation on
-  the S/390 debug feature (Documentation/s390/s390dbf.txt) for details.
-
-* For some of the information present in the /proc filesystem in 2.4 (namely,
-  /proc/subchannels and /proc/chpids), see driver-model.txt.
-  Information formerly in /proc/irq_count is now in /proc/interrupts.
+  /sys/kernel/debug/s390dbf/cio_*/level a number between 0 and 6; see the
+  documentation on the S/390 debug feature (Documentation/s390/s390dbf.txt)
+  for details.
index 58919d6a593ae0b0f91badb0e1e66d424f735738..3081927cc2d64048c1bc02ddf0e33f737082f993 100644 (file)
@@ -286,10 +286,10 @@ first:
             timeout value
 -EIO:       the common I/O layer terminated the request due to an error state
 
-If the concurrent sense flag in the extended status word in the irb is set, the
-field irb->scsw.count describes the number of device specific sense bytes
-available in the extended control word irb->scsw.ecw[0]. No device sensing by
-the device driver itself is required.
+If the concurrent sense flag in the extended status word (esw) in the irb is
+set, the field erw.scnt in the esw describes the number of device specific
+sense bytes available in the extended control word irb->scsw.ecw[]. No device
+sensing by the device driver itself is required.
 
 The device interrupt handler can use the following definitions to investigate
 the primary unit check source coded in sense byte 0 :
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)
diff --git a/Documentation/usb/authorization.txt b/Documentation/usb/authorization.txt
new file mode 100644 (file)
index 0000000..2af4006
--- /dev/null
@@ -0,0 +1,92 @@
+
+Authorizing (or not) your USB devices to connect to the system
+
+(C) 2007 Inaky Perez-Gonzalez <inaky@linux.intel.com> Intel Corporation
+
+This feature allows you to control if a USB device can be used (or
+not) in a system. This feature will allow you to implement a lock-down
+of USB devices, fully controlled by user space.
+
+As of now, when a USB device is connected it is configured and
+it's interfaces inmediately made available to the users. With this
+modification, only if root authorizes the device to be configured will
+then it be possible to use it.
+
+Usage:
+
+Authorize a device to connect:
+
+$ echo 1 > /sys/usb/devices/DEVICE/authorized
+
+Deauthorize a device:
+
+$ echo 0 > /sys/usb/devices/DEVICE/authorized
+
+Set new devices connected to hostX to be deauthorized by default (ie:
+lock down):
+
+$ echo 0 > /sys/bus/devices/usbX/authorized_default
+
+Remove the lock down:
+
+$ echo 1 > /sys/bus/devices/usbX/authorized_default
+
+By default, Wired USB devices are authorized by default to
+connect. Wireless USB hosts deauthorize by default all new connected
+devices (this is so because we need to do an authentication phase
+before authorizing).
+
+
+Example system lockdown (lame)
+-----------------------
+
+Imagine you want to implement a lockdown so only devices of type XYZ
+can be connected (for example, it is a kiosk machine with a visible
+USB port):
+
+boot up
+rc.local ->
+
+ for host in /sys/bus/devices/usb*
+ do
+    echo 0 > $host/authorized_default
+ done
+
+Hookup an script to udev, for new USB devices
+
+ if device_is_my_type $DEV
+ then
+   echo 1 > $device_path/authorized
+ done
+
+
+Now, device_is_my_type() is where the juice for a lockdown is. Just
+checking if the class, type and protocol match something is the worse
+security verification you can make (or the best, for someone willing
+to break it). If you need something secure, use crypto and Certificate
+Authentication or stuff like that. Something simple for an storage key
+could be:
+
+function device_is_my_type()
+{
+   echo 1 > authorized         # temporarily authorize it
+                                # FIXME: make sure none can mount it
+   mount DEVICENODE /mntpoint
+   sum=$(md5sum /mntpoint/.signature)
+   if [ $sum = $(cat /etc/lockdown/keysum) ]
+   then
+        echo "We are good, connected"
+        umount /mntpoint
+        # Other stuff so others can use it
+   else
+        echo 0 > authorized
+   fi
+}
+
+
+Of course, this is lame, you'd want to do a real certificate
+verification stuff with PKI, so you don't depend on a shared secret,
+etc, but you get the idea. Anybody with access to a device gadget kit
+can fake descriptors and device info. Don't trust that. You are
+welcome.
+
diff --git a/Documentation/usb/power-management.txt b/Documentation/usb/power-management.txt
new file mode 100644 (file)
index 0000000..97842de
--- /dev/null
@@ -0,0 +1,517 @@
+                       Power Management for USB
+
+                Alan Stern <stern@rowland.harvard.edu>
+
+                           October 5, 2007
+
+
+
+       What is Power Management?
+       -------------------------
+
+Power Management (PM) is the practice of saving energy by suspending
+parts of a computer system when they aren't being used.  While a
+component is "suspended" it is in a nonfunctional low-power state; it
+might even be turned off completely.  A suspended component can be
+"resumed" (returned to a functional full-power state) when the kernel
+needs to use it.  (There also are forms of PM in which components are
+placed in a less functional but still usable state instead of being
+suspended; an example would be reducing the CPU's clock rate.  This
+document will not discuss those other forms.)
+
+When the parts being suspended include the CPU and most of the rest of
+the system, we speak of it as a "system suspend".  When a particular
+device is turned off while the system as a whole remains running, we
+call it a "dynamic suspend" (also known as a "runtime suspend" or
+"selective suspend").  This document concentrates mostly on how
+dynamic PM is implemented in the USB subsystem, although system PM is
+covered to some extent (see Documentation/power/*.txt for more
+information about system PM).
+
+Note: Dynamic PM support for USB is present only if the kernel was
+built with CONFIG_USB_SUSPEND enabled.  System PM support is present
+only if the kernel was built with CONFIG_SUSPEND or CONFIG_HIBERNATION
+enabled.
+
+
+       What is Remote Wakeup?
+       ----------------------
+
+When a device has been suspended, it generally doesn't resume until
+the computer tells it to.  Likewise, if the entire computer has been
+suspended, it generally doesn't resume until the user tells it to, say
+by pressing a power button or opening the cover.
+
+However some devices have the capability of resuming by themselves, or
+asking the kernel to resume them, or even telling the entire computer
+to resume.  This capability goes by several names such as "Wake On
+LAN"; we will refer to it generically as "remote wakeup".  When a
+device is enabled for remote wakeup and it is suspended, it may resume
+itself (or send a request to be resumed) in response to some external
+event.  Examples include a suspended keyboard resuming when a key is
+pressed, or a suspended USB hub resuming when a device is plugged in.
+
+
+       When is a USB device idle?
+       --------------------------
+
+A device is idle whenever the kernel thinks it's not busy doing
+anything important and thus is a candidate for being suspended.  The
+exact definition depends on the device's driver; drivers are allowed
+to declare that a device isn't idle even when there's no actual
+communication taking place.  (For example, a hub isn't considered idle
+unless all the devices plugged into that hub are already suspended.)
+In addition, a device isn't considered idle so long as a program keeps
+its usbfs file open, whether or not any I/O is going on.
+
+If a USB device has no driver, its usbfs file isn't open, and it isn't
+being accessed through sysfs, then it definitely is idle.
+
+
+       Forms of dynamic PM
+       -------------------
+
+Dynamic suspends can occur in two ways: manual and automatic.
+"Manual" means that the user has told the kernel to suspend a device,
+whereas "automatic" means that the kernel has decided all by itself to
+suspend a device.  Automatic suspend is called "autosuspend" for
+short.  In general, a device won't be autosuspended unless it has been
+idle for some minimum period of time, the so-called idle-delay time.
+
+Of course, nothing the kernel does on its own initiative should
+prevent the computer or its devices from working properly.  If a
+device has been autosuspended and a program tries to use it, the
+kernel will automatically resume the device (autoresume).  For the
+same reason, an autosuspended device will usually have remote wakeup
+enabled, if the device supports remote wakeup.
+
+It is worth mentioning that many USB drivers don't support
+autosuspend.  In fact, at the time of this writing (Linux 2.6.23) the
+only drivers which do support it are the hub driver, kaweth, asix,
+usblp, usblcd, and usb-skeleton (which doesn't count).  If a
+non-supporting driver is bound to a device, the device won't be
+autosuspended.  In effect, the kernel pretends the device is never
+idle.
+
+We can categorize power management events in two broad classes:
+external and internal.  External events are those triggered by some
+agent outside the USB stack: system suspend/resume (triggered by
+userspace), manual dynamic suspend/resume (also triggered by
+userspace), and remote wakeup (triggered by the device).  Internal
+events are those triggered within the USB stack: autosuspend and
+autoresume.
+
+
+       The user interface for dynamic PM
+       ---------------------------------
+
+The user interface for controlling dynamic PM is located in the power/
+subdirectory of each USB device's sysfs directory, that is, in
+/sys/bus/usb/devices/.../power/ where "..." is the device's ID.  The
+relevant attribute files are: wakeup, level, and autosuspend.
+
+       power/wakeup
+
+               This file is empty if the device does not support
+               remote wakeup.  Otherwise the file contains either the
+               word "enabled" or the word "disabled", and you can
+               write those words to the file.  The setting determines
+               whether or not remote wakeup will be enabled when the
+               device is next suspended.  (If the setting is changed
+               while the device is suspended, the change won't take
+               effect until the following suspend.)
+
+       power/level
+
+               This file contains one of three words: "on", "auto",
+               or "suspend".  You can write those words to the file
+               to change the device's setting.
+
+               "on" means that the device should be resumed and
+               autosuspend is not allowed.  (Of course, system
+               suspends are still allowed.)
+
+               "auto" is the normal state in which the kernel is
+               allowed to autosuspend and autoresume the device.
+
+               "suspend" means that the device should remain
+               suspended, and autoresume is not allowed.  (But remote
+               wakeup may still be allowed, since it is controlled
+               separately by the power/wakeup attribute.)
+
+       power/autosuspend
+
+               This file contains an integer value, which is the
+               number of seconds the device should remain idle before
+               the kernel will autosuspend it (the idle-delay time).
+               The default is 2.  0 means to autosuspend as soon as
+               the device becomes idle, and -1 means never to
+               autosuspend.  You can write a number to the file to
+               change the autosuspend idle-delay time.
+
+Writing "-1" to power/autosuspend and writing "on" to power/level do
+essentially the same thing -- they both prevent the device from being
+autosuspended.  Yes, this is a redundancy in the API.
+
+(In 2.6.21 writing "0" to power/autosuspend would prevent the device
+from being autosuspended; the behavior was changed in 2.6.22.  The
+power/autosuspend attribute did not exist prior to 2.6.21, and the
+power/level attribute did not exist prior to 2.6.22.)
+
+
+       Changing the default idle-delay time
+       ------------------------------------
+
+The default autosuspend idle-delay time is controlled by a module
+parameter in usbcore.  You can specify the value when usbcore is
+loaded.  For example, to set it to 5 seconds instead of 2 you would
+do:
+
+       modprobe usbcore autosuspend=5
+
+Equivalently, you could add to /etc/modprobe.conf a line saying:
+
+       options usbcore autosuspend=5
+
+Some distributions load the usbcore module very early during the boot
+process, by means of a program or script running from an initramfs
+image.  To alter the parameter value you would have to rebuild that
+image.
+
+If usbcore is compiled into the kernel rather than built as a loadable
+module, you can add
+
+       usbcore.autosuspend=5
+
+to the kernel's boot command line.
+
+Finally, the parameter value can be changed while the system is
+running.  If you do:
+
+       echo 5 >/sys/module/usbcore/parameters/autosuspend
+
+then each new USB device will have its autosuspend idle-delay
+initialized to 5.  (The idle-delay values for already existing devices
+will not be affected.)
+
+Setting the initial default idle-delay to -1 will prevent any
+autosuspend of any USB device.  This is a simple alternative to
+disabling CONFIG_USB_SUSPEND and rebuilding the kernel, and it has the
+added benefit of allowing you to enable autosuspend for selected
+devices.
+
+
+       Warnings
+       --------
+
+The USB specification states that all USB devices must support power
+management.  Nevertheless, the sad fact is that many devices do not
+support it very well.  You can suspend them all right, but when you
+try to resume them they disconnect themselves from the USB bus or
+they stop working entirely.  This seems to be especially prevalent
+among printers and scanners, but plenty of other types of device have
+the same deficiency.
+
+For this reason, by default the kernel disables autosuspend (the
+power/level attribute is initialized to "on") for all devices other
+than hubs.  Hubs, at least, appear to be reasonably well-behaved in
+this regard.
+
+(In 2.6.21 and 2.6.22 this wasn't the case.  Autosuspend was enabled
+by default for almost all USB devices.  A number of people experienced
+problems as a result.)
+
+This means that non-hub devices won't be autosuspended unless the user
+or a program explicitly enables it.  As of this writing there aren't
+any widespread programs which will do this; we hope that in the near
+future device managers such as HAL will take on this added
+responsibility.  In the meantime you can always carry out the
+necessary operations by hand or add them to a udev script.  You can
+also change the idle-delay time; 2 seconds is not the best choice for
+every device.
+
+Sometimes it turns out that even when a device does work okay with
+autosuspend there are still problems.  For example, there are
+experimental patches adding autosuspend support to the usbhid driver,
+which manages keyboards and mice, among other things.  Tests with a
+number of keyboards showed that typing on a suspended keyboard, while
+causing the keyboard to do a remote wakeup all right, would
+nonetheless frequently result in lost keystrokes.  Tests with mice
+showed that some of them would issue a remote-wakeup request in
+response to button presses but not to motion, and some in response to
+neither.
+
+The kernel will not prevent you from enabling autosuspend on devices
+that can't handle it.  It is even possible in theory to damage a
+device by suspending it at the wrong time -- for example, suspending a
+USB hard disk might cause it to spin down without parking the heads.
+(Highly unlikely, but possible.)  Take care.
+
+
+       The driver interface for Power Management
+       -----------------------------------------
+
+The requirements for a USB driver to support external power management
+are pretty modest; the driver need only define
+
+       .suspend
+       .resume
+       .reset_resume
+
+methods in its usb_driver structure, and the reset_resume method is
+optional.  The methods' jobs are quite simple:
+
+       The suspend method is called to warn the driver that the
+       device is going to be suspended.  If the driver returns a
+       negative error code, the suspend will be aborted.  Normally
+       the driver will return 0, in which case it must cancel all
+       outstanding URBs (usb_kill_urb()) and not submit any more.
+
+       The resume method is called to tell the driver that the
+       device has been resumed and the driver can return to normal
+       operation.  URBs may once more be submitted.
+
+       The reset_resume method is called to tell the driver that
+       the device has been resumed and it also has been reset.
+       The driver should redo any necessary device initialization,
+       since the device has probably lost most or all of its state
+       (although the interfaces will be in the same altsettings as
+       before the suspend).
+
+The reset_resume method is used by the USB Persist facility (see
+Documentation/usb/persist.txt) and it can also be used under certain
+circumstances when CONFIG_USB_PERSIST is not enabled.  Currently, if a
+device is reset during a resume and the driver does not have a
+reset_resume method, the driver won't receive any notification about
+the resume.  Later kernels will call the driver's disconnect method;
+2.6.23 doesn't do this.
+
+USB drivers are bound to interfaces, so their suspend and resume
+methods get called when the interfaces are suspended or resumed.  In
+principle one might want to suspend some interfaces on a device (i.e.,
+force the drivers for those interface to stop all activity) without
+suspending the other interfaces.  The USB core doesn't allow this; all
+interfaces are suspended when the device itself is suspended and all
+interfaces are resumed when the device is resumed.  It isn't possible
+to suspend or resume some but not all of a device's interfaces.  The
+closest you can come is to unbind the interfaces' drivers.
+
+
+       The driver interface for autosuspend and autoresume
+       ---------------------------------------------------
+
+To support autosuspend and autoresume, a driver should implement all
+three of the methods listed above.  In addition, a driver indicates
+that it supports autosuspend by setting the .supports_autosuspend flag
+in its usb_driver structure.  It is then responsible for informing the
+USB core whenever one of its interfaces becomes busy or idle.  The
+driver does so by calling these three functions:
+
+       int  usb_autopm_get_interface(struct usb_interface *intf);
+       void usb_autopm_put_interface(struct usb_interface *intf);
+       int  usb_autopm_set_interface(struct usb_interface *intf);
+
+The functions work by maintaining a counter in the usb_interface
+structure.  When intf->pm_usage_count is > 0 then the interface is
+deemed to be busy, and the kernel will not autosuspend the interface's
+device.  When intf->pm_usage_count is <= 0 then the interface is
+considered to be idle, and the kernel may autosuspend the device.
+
+(There is a similar pm_usage_count field in struct usb_device,
+associated with the device itself rather than any of its interfaces.
+This field is used only by the USB core.)
+
+The driver owns intf->pm_usage_count; it can modify the value however
+and whenever it likes.  A nice aspect of the usb_autopm_* routines is
+that the changes they make are protected by the usb_device structure's
+PM mutex (udev->pm_mutex); however drivers may change pm_usage_count
+without holding the mutex.
+
+       usb_autopm_get_interface() increments pm_usage_count and
+       attempts an autoresume if the new value is > 0 and the
+       device is suspended.
+
+       usb_autopm_put_interface() decrements pm_usage_count and
+       attempts an autosuspend if the new value is <= 0 and the
+       device isn't suspended.
+
+       usb_autopm_set_interface() leaves pm_usage_count alone.
+       It attempts an autoresume if the value is > 0 and the device
+       is suspended, and it attempts an autosuspend if the value is
+       <= 0 and the device isn't suspended.
+
+There also are a couple of utility routines drivers can use:
+
+       usb_autopm_enable() sets pm_usage_cnt to 1 and then calls
+       usb_autopm_set_interface(), which will attempt an autoresume.
+
+       usb_autopm_disable() sets pm_usage_cnt to 0 and then calls
+       usb_autopm_set_interface(), which will attempt an autosuspend.
+
+The conventional usage pattern is that a driver calls
+usb_autopm_get_interface() in its open routine and
+usb_autopm_put_interface() in its close or release routine.  But
+other patterns are possible.
+
+The autosuspend attempts mentioned above will often fail for one
+reason or another.  For example, the power/level attribute might be
+set to "on", or another interface in the same device might not be
+idle.  This is perfectly normal.  If the reason for failure was that
+the device hasn't been idle for long enough, a delayed workqueue
+routine is automatically set up to carry out the operation when the
+autosuspend idle-delay has expired.
+
+Autoresume attempts also can fail.  This will happen if power/level is
+set to "suspend" or if the device doesn't manage to resume properly.
+Unlike autosuspend, there's no delay for an autoresume.
+
+
+       Other parts of the driver interface
+       -----------------------------------
+
+Sometimes a driver needs to make sure that remote wakeup is enabled
+during autosuspend.  For example, there's not much point
+autosuspending a keyboard if the user can't cause the keyboard to do a
+remote wakeup by typing on it.  If the driver sets
+intf->needs_remote_wakeup to 1, the kernel won't autosuspend the
+device if remote wakeup isn't available or has been disabled through
+the power/wakeup attribute.  (If the device is already autosuspended,
+though, setting this flag won't cause the kernel to autoresume it.
+Normally a driver would set this flag in its probe method, at which
+time the device is guaranteed not to be autosuspended.)
+
+The usb_autopm_* routines have to run in a sleepable process context;
+they must not be called from an interrupt handler or while holding a
+spinlock.  In fact, the entire autosuspend mechanism is not well geared
+toward interrupt-driven operation.  However there is one thing a
+driver can do in an interrupt handler:
+
+       usb_mark_last_busy(struct usb_device *udev);
+
+This sets udev->last_busy to the current time.  udev->last_busy is the
+field used for idle-delay calculations; updating it will cause any
+pending autosuspend to be moved back.  The usb_autopm_* routines will
+also set the last_busy field to the current time.
+
+Calling urb_mark_last_busy() from within an URB completion handler is
+subject to races: The kernel may have just finished deciding the
+device has been idle for long enough but not yet gotten around to
+calling the driver's suspend method.  The driver would have to be
+responsible for synchronizing its suspend method with its URB
+completion handler and causing the autosuspend to fail with -EBUSY if
+an URB had completed too recently.
+
+External suspend calls should never be allowed to fail in this way,
+only autosuspend calls.  The driver can tell them apart by checking
+udev->auto_pm; this flag will be set to 1 for internal PM events
+(autosuspend or autoresume) and 0 for external PM events.
+
+Many of the ingredients in the autosuspend framework are oriented
+towards interfaces: The usb_interface structure contains the
+pm_usage_cnt field, and the usb_autopm_* routines take an interface
+pointer as their argument.  But somewhat confusingly, a few of the
+pieces (usb_mark_last_busy() and udev->auto_pm) use the usb_device
+structure instead.  Drivers need to keep this straight; they can call
+interface_to_usbdev() to find the device structure for a given
+interface.
+
+
+       Locking requirements
+       --------------------
+
+All three suspend/resume methods are always called while holding the
+usb_device's PM mutex.  For external events -- but not necessarily for
+autosuspend or autoresume -- the device semaphore (udev->dev.sem) will
+also be held.  This implies that external suspend/resume events are
+mutually exclusive with calls to probe, disconnect, pre_reset, and
+post_reset; the USB core guarantees that this is true of internal
+suspend/resume events as well.
+
+If a driver wants to block all suspend/resume calls during some
+critical section, it can simply acquire udev->pm_mutex.
+Alternatively, if the critical section might call some of the
+usb_autopm_* routines, the driver can avoid deadlock by doing:
+
+       down(&udev->dev.sem);
+       rc = usb_autopm_get_interface(intf);
+
+and at the end of the critical section:
+
+       if (!rc)
+               usb_autopm_put_interface(intf);
+       up(&udev->dev.sem);
+
+Holding the device semaphore will block all external PM calls, and the
+usb_autopm_get_interface() will prevent any internal PM calls, even if
+it fails.  (Exercise: Why?)
+
+The rules for locking order are:
+
+       Never acquire any device semaphore while holding any PM mutex.
+
+       Never acquire udev->pm_mutex while holding the PM mutex for
+       a device that isn't a descendant of udev.
+
+In other words, PM mutexes should only be acquired going up the device
+tree, and they should be acquired only after locking all the device
+semaphores you need to hold.  These rules don't matter to drivers very
+much; they usually affect just the USB core.
+
+Still, drivers do need to be careful.  For example, many drivers use a
+private mutex to synchronize their normal I/O activities with their
+disconnect method.  Now if the driver supports autosuspend then it
+must call usb_autopm_put_interface() from somewhere -- maybe from its
+close method.  It should make the call while holding the private mutex,
+since a driver shouldn't call any of the usb_autopm_* functions for an
+interface from which it has been unbound.
+
+But the usb_autpm_* routines always acquire the device's PM mutex, and
+consequently the locking order has to be: private mutex first, PM
+mutex second.  Since the suspend method is always called with the PM
+mutex held, it mustn't try to acquire the private mutex.  It has to
+synchronize with the driver's I/O activities in some other way.
+
+
+       Interaction between dynamic PM and system PM
+       --------------------------------------------
+
+Dynamic power management and system power management can interact in
+a couple of ways.
+
+Firstly, a device may already be manually suspended or autosuspended
+when a system suspend occurs.  Since system suspends are supposed to
+be as transparent as possible, the device should remain suspended
+following the system resume.  The 2.6.23 kernel obeys this principle
+for manually suspended devices but not for autosuspended devices; they
+do get resumed when the system wakes up.  (Presumably they will be
+autosuspended again after their idle-delay time expires.)  In later
+kernels this behavior will be fixed.
+
+(There is an exception.  If a device would undergo a reset-resume
+instead of a normal resume, and the device is enabled for remote
+wakeup, then the reset-resume takes place even if the device was
+already suspended when the system suspend began.  The justification is
+that a reset-resume is a kind of remote-wakeup event.  Or to put it
+another way, a device which needs a reset won't be able to generate
+normal remote-wakeup signals, so it ought to be resumed immediately.)
+
+Secondly, a dynamic power-management event may occur as a system
+suspend is underway.  The window for this is short, since system
+suspends don't take long (a few seconds usually), but it can happen.
+For example, a suspended device may send a remote-wakeup signal while
+the system is suspending.  The remote wakeup may succeed, which would
+cause the system suspend to abort.  If the remote wakeup doesn't
+succeed, it may still remain active and thus cause the system to
+resume as soon as the system suspend is complete.  Or the remote
+wakeup may fail and get lost.  Which outcome occurs depends on timing
+and on the hardware and firmware design.
+
+More interestingly, a device might undergo a manual resume or
+autoresume during system suspend.  With current kernels this shouldn't
+happen, because manual resumes must be initiated by userspace and
+autoresumes happen in response to I/O requests, but all user processes
+and I/O should be quiescent during a system suspend -- thanks to the
+freezer.  However there are plans to do away with the freezer, which
+would mean these things would become possible.  If and when this comes
+about, the USB core will carefully arrange matters so that either type
+of resume will block until the entire system has resumed.
index 5b635ae849443a1deae12b9f0c0019cc06bcc4e5..4e0b62b8566ff266d3242e55efea5977e9d8bbbb 100644 (file)
@@ -428,6 +428,17 @@ Options supported:
   See http://www.uuhaus.de/linux/palmconnect.html for up-to-date
   information on this driver.
 
+Winchiphead CH341 Driver
+
+  This driver is for the Winchiphead CH341 USB-RS232 Converter. This chip
+  also implements an IEEE 1284 parallel port, I2C and SPI, but that is not
+  supported by the driver. The protocol was analyzed from the behaviour
+  of the Windows driver, no datasheet is available at present.
+  The manufacturer's website: http://www.winchiphead.com/.
+  For any questions or problems with this driver, please contact
+  frank@kingswood-consulting.co.uk.
+
+
 Generic Serial driver
 
   If your device is not one of the above listed devices, compatible with
index 53ae866ae37b7e238c8d132783e63102a24ef331..2917ce4ffdc4f5df267bdc9b5f239a9679c2e6d4 100644 (file)
@@ -34,9 +34,12 @@ if usbmon is built into the kernel.
 Verify that bus sockets are present.
 
 # ls /sys/kernel/debug/usbmon
-1s  1t  1u  2s  2t  2u  3s  3t  3u  4s  4t  4u
+0s  0t  0u  1s  1t  1u  2s  2t  2u  3s  3t  3u  4s  4t  4u
 #
 
+Now you can choose to either use the sockets numbered '0' (to capture packets on
+all buses), and skip to step #3, or find the bus used by your device with step #2.
+
 2. Find which bus connects to the desired device
 
 Run "cat /proc/bus/usb/devices", and find the T-line which corresponds to
@@ -56,6 +59,10 @@ Bus=03 means it's bus 3.
 
 # cat /sys/kernel/debug/usbmon/3u > /tmp/1.mon.out
 
+to listen on a single bus, otherwise, to listen on all buses, type:
+
+# cat /sys/kernel/debug/usbmon/0u > /tmp/1.mon.out
+
 This process will be reading until killed. Naturally, the output can be
 redirected to a desirable location. This is preferred, because it is going
 to be quite long.
index c4eca56ed5bf75d7ca1626adc247853a75bf6a22..12cee3da2625f48ad5564892026c7873c9123184 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
@@ -677,6 +683,13 @@ P: Haavard Skinnemoen
 M:     hskinnemoen@atmel.com
 S:     Supported
 
+ATMEL USBA UDC DRIVER
+P:     Haavard Skinnemoen
+M:     hskinnemoen@atmel.com
+L:     kernel@avr32linux.org
+W:     http://avr32linux.org/twiki/bin/view/Main/AtmelUsbDeviceDriver
+S:     Supported
+
 ATMEL WIRELESS DRIVER
 P:     Simon Kelley
 M:     simon@thekelleys.org.uk
@@ -1653,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
@@ -1769,8 +1783,8 @@ M:        venkatesh.pallipadi@intel.com
 S:     Maintained
 
 HPET:  x86_64
-P:     Andi Kleen and Vojtech Pavlik
-M:     andi@firstfloor.org and vojtech@suse.cz
+P:     Vojtech Pavlik
+M:     vojtech@suse.cz
 S:     Maintained
 
 HPET:  ACPI hpet.c
@@ -1881,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
@@ -2396,7 +2415,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
@@ -4170,7 +4189,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
@@ -4258,14 +4277,6 @@ P:       Ingo Molnar
 M:     mingo@redhat.com
 S:     Maintained
 
-X86-64 port
-P:     Andi Kleen
-M:     ak@suse.de
-L:     discuss@x86-64.org
-W:     http://www.x86-64.org
-T:     quilt ftp://ftp.firstfloor.org/pub/ak/x86_64/quilt-current
-S:     Maintained
-
 YAM DRIVER FOR AX.25
 P:     Jean-Paul Roubelat
 M:     jpr@f6fbb.org
index 467d899fbe755eab9e2dc1860d4dff3dfa423762..e548ba74a4d2a17bf4537748f92edc807e859df1 100644 (file)
@@ -269,7 +269,6 @@ static int __init imx_cpufreq_driver_init(struct cpufreq_policy *policy)
                return -EINVAL;
 
        policy->cur = policy->min = policy->max = imx_get_speed(0);
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cpuinfo.min_freq = 8000;
        policy->cpuinfo.max_freq = 200000;
         /* Manual states, that PLL stabilizes in two CLK32 periods */
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 78f4c1346044f64a1282294332e13d6e78d3e9cd..36b47ff5af11ddf5dccadba8170baee881a2d133 100644 (file)
@@ -331,7 +331,6 @@ static int __init sa1110_cpu_init(struct cpufreq_policy *policy)
        if (policy->cpu != 0)
                return -EINVAL;
        policy->cur = policy->min = policy->max = sa11x0_getspeed(0);
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cpuinfo.min_freq = 59000;
        policy->cpuinfo.max_freq = 287000;
        policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
index a0c71dca237330aac55e15bf24221b39e1962128..c0d63b0c61c9c5a54a11a298ea0f8d7334444e58 100644 (file)
@@ -108,7 +108,6 @@ static int __init omap_cpu_init(struct cpufreq_policy *policy)
        if (policy->cpu != 0)
                return -EINVAL;
        policy->cur = policy->min = policy->max = omap_getspeed(0);
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cpuinfo.min_freq = clk_round_rate(mpu_clk, 0) / 1000;
        policy->cpuinfo.max_freq = clk_round_rate(mpu_clk, VERY_HI_RATE) / 1000;
        policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
index 6fd9cfd0a31bd1a330f89a1c803ca749abffa67b..b7a0e0fbd9af9f32bf618c3b98b6a46eb9608ec1 100644 (file)
@@ -118,8 +118,6 @@ static int __init __bf533_cpu_init(struct cpufreq_policy *policy)
        if (policy->cpu != 0)
                return -EINVAL;
 
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
-
        policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
        /*Now ,only support one cpu */
        policy->cur = bf533_getfreq(0);
index 5e9d09eb857944fb553e6de1c23c9f9d9780c59f..6668c8e4a3fc953fb95f7f1a899a5e1212945985 100644 (file)
@@ -40,7 +40,7 @@
 #include <linux/pata_platform.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
-#include <linux/usb_sl811.h>
+#include <linux/usb/sl811.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
 #include <asm/reboot.h>
index 20507e92a3a4bfbd334d06eb324492c0bbd665cd..f83a2544004d4260ca574d57d54cccabd55b3c37 100644 (file)
@@ -40,7 +40,7 @@
 #include <linux/irq.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
-#include <linux/usb_sl811.h>
+#include <linux/usb/sl811.h>
 
 #include <linux/spi/ad7877.h>
 
index 47d7d4a0e73dd1e2e3e2cf25264ed5ff9840ee49..f42ba3aa86d786407f6cb0d67c0cd046304889a7 100644 (file)
@@ -40,7 +40,7 @@
 #include <linux/pata_platform.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
-#include <linux/usb_sl811.h>
+#include <linux/usb/sl811.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
 #include <asm/reboot.h>
index 2d85e4b87307a1e87b7999a068f8620304758c15..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
@@ -1137,6 +1148,11 @@ config PCI_MMCONFIG
        depends on PCI && ACPI && (PCI_GOMMCONFIG || PCI_GOANY)
        default y
 
+config PCI_DOMAINS
+       bool
+       depends on PCI
+       default y
+
 source "drivers/pci/pcie/Kconfig"
 
 source "drivers/pci/Kconfig"
@@ -1206,6 +1222,16 @@ config SCx200HR_TIMER
          processor goes idle (as is done by the scheduler).  The
          other workaround is idle=poll boot option.
 
+config GEODE_MFGPT_TIMER
+       bool "Geode Multi-Function General Purpose Timer (MFGPT) events"
+       depends on MGEODE_LX && GENERIC_TIME && GENERIC_CLOCKEVENTS
+       default y
+       help
+         This driver provides a clock event source based on the MFGPT
+         timer(s) in the CS5535 and CS5536 companion chip for the geode.
+         MFGPTs have a better resolution and max interval than the
+         generic PIT, and are suitable for use as high-res timers.
+
 config K8_NB
        def_bool y
        depends on AGP_AMD64
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 8c6ec7070844d7a7826881ccf15b4ca5079d5654..b8498ea6206800b613f753cc75db7c84e71b9e93 100644 (file)
@@ -321,8 +321,6 @@ acpi_cpufreq_cpu_init (
                            data->acpi_data.states[i].transition_latency * 1000;
                }
        }
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
-
        policy->cur = processor_get_freq(data, policy->cpu);
 
        /* table init */
index 5a289e4de8383eb7f286ed99fe7d0d1c80c36df5..a88eba3314d7fb02b812c7b8cf5055788da90fa4 100644 (file)
@@ -66,8 +66,7 @@ static int tiocx_match(struct device *dev, struct device_driver *drv)
 
 }
 
-static int tiocx_uevent(struct device *dev, char **envp, int num_envp,
-                        char *buffer, int buffer_size)
+static int tiocx_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        return -ENODEV;
 }
index 2b5f64726a2e88ff851c4c02119f5729e7947d80..fbbccb5e75117a22967bbbeadc62e3e3c8a3c6dc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/atari/atakeyb.c
+ * linux/arch/m68k/atari/atakeyb.c
  *
  * Atari Keyboard driver for 680x0 Linux
  *
@@ -11,6 +11,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 +35,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 +106,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 +120,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 +157,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 +226,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 +247,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 +572,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 +634,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 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 89b911e83c0453cfe3824db2ac514faa62e39cea..8f3db32fac8bbe040b9a2a638ccbecd744ef1766 100644 (file)
@@ -57,26 +57,21 @@ ssize_t of_device_get_modalias(struct of_device *ofdev,
        return tsize;
 }
 
-int of_device_uevent(struct device *dev,
-               char **envp, int num_envp, char *buffer, int buffer_size)
+int of_device_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        struct of_device *ofdev;
        const char *compat;
-       int i = 0, length = 0, seen = 0, cplen, sl;
+       int seen = 0, cplen, sl;
 
        if (!dev)
                return -ENODEV;
 
        ofdev = to_of_device(dev);
 
-       if (add_uevent_var(envp, num_envp, &i,
-                          buffer, buffer_size, &length,
-                          "OF_NAME=%s", ofdev->node->name))
+       if (add_uevent_var(env, "OF_NAME=%s", ofdev->node->name))
                return -ENOMEM;
 
-       if (add_uevent_var(envp, num_envp, &i,
-                          buffer, buffer_size, &length,
-                          "OF_TYPE=%s", ofdev->node->type))
+       if (add_uevent_var(env, "OF_TYPE=%s", ofdev->node->type))
                return -ENOMEM;
 
         /* Since the compatible field can contain pretty much anything
@@ -85,9 +80,7 @@ int of_device_uevent(struct device *dev,
 
        compat = of_get_property(ofdev->node, "compatible", &cplen);
        while (compat && *compat && cplen > 0) {
-               if (add_uevent_var(envp, num_envp, &i,
-                                  buffer, buffer_size, &length,
-                                  "OF_COMPATIBLE_%d=%s", seen, compat))
+               if (add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat))
                        return -ENOMEM;
 
                sl = strlen (compat) + 1;
@@ -96,25 +89,17 @@ int of_device_uevent(struct device *dev,
                seen++;
        }
 
-       if (add_uevent_var(envp, num_envp, &i,
-                          buffer, buffer_size, &length,
-                          "OF_COMPATIBLE_N=%d", seen))
+       if (add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen))
                return -ENOMEM;
 
        /* modalias is trickier, we add it in 2 steps */
-       if (add_uevent_var(envp, num_envp, &i,
-                          buffer, buffer_size, &length,
-                          "MODALIAS="))
+       if (add_uevent_var(env, "MODALIAS="))
                return -ENOMEM;
-
-       sl = of_device_get_modalias(ofdev, &buffer[length-1],
-                                       buffer_size-length);
-       if (sl >= (buffer_size-length))
+       sl = of_device_get_modalias(ofdev, &env->buf[env->buflen-1],
+                                   sizeof(env->buf) - env->buflen);
+       if (sl >= (sizeof(env->buf) - env->buflen))
                return -ENOMEM;
-
-       length += sl;
-
-       envp[i] = NULL;
+       env->buflen += sl;
 
        return 0;
 }
index cb22a3557c4e88303535336d8859eb2f0da69a7c..19a5656001c080f8da3f3f5a9050c03a80fb1746 100644 (file)
@@ -317,30 +317,20 @@ static int vio_bus_match(struct device *dev, struct device_driver *drv)
        return (ids != NULL) && (vio_match_device(ids, vio_dev) != NULL);
 }
 
-static int vio_hotplug(struct device *dev, char **envp, int num_envp,
-                       char *buffer, int buffer_size)
+static int vio_hotplug(struct device *dev, struct kobj_uevent_env *env)
 {
        const struct vio_dev *vio_dev = to_vio_dev(dev);
        struct device_node *dn;
        const char *cp;
-       int length;
-
-       if (!num_envp)
-               return -ENOMEM;
 
        dn = dev->archdata.of_node;
        if (!dn)
                return -ENODEV;
-       cp = of_get_property(dn, "compatible", &length);
+       cp = of_get_property(dn, "compatible", NULL);
        if (!cp)
                return -ENODEV;
 
-       envp[0] = buffer;
-       length = scnprintf(buffer, buffer_size, "MODALIAS=vio:T%sS%s",
-                               vio_dev->type, cp);
-       if ((buffer_size - length) <= 0)
-               return -ENOMEM;
-       envp[1] = NULL;
+       add_uevent_var(env, "MODALIAS=vio:T%sS%s", vio_dev->type, cp);
        return 0;
 }
 
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 901236fa0f07bed62c1e63c191a4b5debd90fcd4..5123e9d4164b7c1c6c65898ed20dfb0b23f0cddd 100644 (file)
@@ -107,8 +107,6 @@ static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
                pr_debug("%d: %d\n", i, cbe_freqs[i].frequency);
        }
 
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
-
        /* if DEBUG is enabled set_pmode() measures the latency
         * of a transition */
        policy->cpuinfo.transition_latency = 25000;
index 3ae083851b01043383bda66a1518e737c8144c56..1cfb8b0c8fecd512f6b26564138a9df52b148c17 100644 (file)
@@ -195,8 +195,6 @@ static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy)
                pr_debug("%d: %d\n", i, pas_freqs[i].frequency);
        }
 
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
-
        policy->cpuinfo.transition_latency = get_gizmo_latency();
 
        cur_astate = get_cur_astate(policy->cpu);
index 1fe35dab0e9eb7d519569ef37265956d0b85613d..c04abcc28a7a88060a9cb6be50922c9ef41bd4a9 100644 (file)
@@ -410,7 +410,6 @@ static int pmac_cpufreq_cpu_init(struct cpufreq_policy *policy)
        if (policy->cpu != 0)
                return -ENODEV;
 
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cpuinfo.transition_latency      = CPUFREQ_ETERNAL;
        policy->cur = cur_freq;
 
index 00f50298c342aad55c982687e03bddbde0d731cb..4dfb4bc242b5cc2c360530085a36681506a41d10 100644 (file)
@@ -357,7 +357,6 @@ static unsigned int g5_cpufreq_get_speed(unsigned int cpu)
 
 static int g5_cpufreq_cpu_init(struct cpufreq_policy *policy)
 {
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
        policy->cur = g5_cpu_freqs[g5_query_freq()].frequency;
        /* secondary CPUs are tied to the primary one by the
index 4bb634a17e433fa3e2f675a10c7ac0c59da1f098..190ff4b59a557bd5be11d34d3e069b0425bb7572 100644 (file)
@@ -437,18 +437,12 @@ static void ps3_system_bus_shutdown(struct device *_dev)
        dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);
 }
 
-static int ps3_system_bus_uevent(struct device *_dev, char **envp,
-                                int num_envp, char *buffer, int buffer_size)
+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(envp, num_envp, &i, buffer, buffer_size,
-                          &length, "MODALIAS=ps3:%d",
-                          dev->match_id))
+       if (add_uevent_var(env, "MODALIAS=ps3:%d", dev->match_id))
                return -ENOMEM;
-
-       envp[i] = NULL;
        return 0;
 }
 
index 62391fb1f61f0ed158c304bd0c939e77595d5191..ac61cf43a7d950b36cf1316165ea499c63c6283d 100644 (file)
@@ -547,8 +547,7 @@ static void __cpuinit appldata_online_cpu(int cpu)
        spin_unlock(&appldata_timer_lock);
 }
 
-static void
-appldata_offline_cpu(int cpu)
+static void __cpuinit appldata_offline_cpu(int cpu)
 {
        del_virt_timer(&per_cpu(appldata_timer, cpu));
        if (atomic_dec_and_test(&appldata_expire_count)) {
@@ -560,9 +559,9 @@ appldata_offline_cpu(int cpu)
        spin_unlock(&appldata_timer_lock);
 }
 
-static int __cpuinit
-appldata_cpu_notify(struct notifier_block *self,
-                   unsigned long action, void *hcpu)
+static int __cpuinit appldata_cpu_notify(struct notifier_block *self,
+                                        unsigned long action,
+                                        void *hcpu)
 {
        switch (action) {
        case CPU_ONLINE:
@@ -608,63 +607,15 @@ static int __init appldata_init(void)
        register_hotcpu_notifier(&appldata_nb);
 
        appldata_sysctl_header = register_sysctl_table(appldata_dir_table);
-#ifdef MODULE
-       appldata_dir_table[0].de->owner = THIS_MODULE;
-       appldata_table[0].de->owner = THIS_MODULE;
-       appldata_table[1].de->owner = THIS_MODULE;
-#endif
 
        P_DEBUG("Base interface initialized.\n");
        return 0;
 }
 
-/*
- * appldata_exit()
- *
- * stop timer, unregister /proc entries
- */
-static void __exit appldata_exit(void)
-{
-       struct list_head *lh;
-       struct appldata_ops *ops;
-       int rc, i;
+__initcall(appldata_init);
 
-       P_DEBUG("Unloading module ...\n");
-       /*
-        * ops list should be empty, but just in case something went wrong...
-        */
-       spin_lock(&appldata_ops_lock);
-       list_for_each(lh, &appldata_ops_list) {
-               ops = list_entry(lh, struct appldata_ops, list);
-               rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC,
-                               (unsigned long) ops->data, ops->size,
-                               ops->mod_lvl);
-               if (rc != 0) {
-                       P_ERROR("STOP DIAG 0xDC for %s failed, "
-                               "return code: %d\n", ops->name, rc);
-               }
-       }
-       spin_unlock(&appldata_ops_lock);
-
-       for_each_online_cpu(i)
-               appldata_offline_cpu(i);
-
-       appldata_timer_active = 0;
-
-       unregister_sysctl_table(appldata_sysctl_header);
-
-       destroy_workqueue(appldata_wq);
-       P_DEBUG("... module unloaded!\n");
-}
 /**************************** init / exit <END> ******************************/
 
-
-module_init(appldata_init);
-module_exit(appldata_exit);
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Gerald Schaefer");
-MODULE_DESCRIPTION("Linux-VM Monitor Stream, base infrastructure");
-
 EXPORT_SYMBOL_GPL(appldata_register_ops);
 EXPORT_SYMBOL_GPL(appldata_unregister_ops);
 EXPORT_SYMBOL_GPL(appldata_diag);
index d1c76fe10f29e0d8630979abc973a54f4e230472..f4932c22ebe4f86d6bf13c02c099e81f58a4569d 100644 (file)
@@ -2,6 +2,7 @@
 #include <linux/types.h>
 #include <linux/audit.h>
 #include <asm/unistd.h>
+#include "audit.h"
 
 static unsigned dir_class[] = {
 #include <asm-generic/audit_dir_write.h>
@@ -40,7 +41,6 @@ int audit_classify_arch(int arch)
 int audit_classify_syscall(int abi, unsigned syscall)
 {
 #ifdef CONFIG_COMPAT
-       extern int s390_classify_syscall(unsigned);
        if (abi == AUDIT_ARCH_S390)
                return s390_classify_syscall(syscall);
 #endif
@@ -61,11 +61,6 @@ int audit_classify_syscall(int abi, unsigned syscall)
 static int __init audit_classes_init(void)
 {
 #ifdef CONFIG_COMPAT
-       extern __u32 s390_dir_class[];
-       extern __u32 s390_write_class[];
-       extern __u32 s390_read_class[];
-       extern __u32 s390_chattr_class[];
-       extern __u32 s390_signal_class[];
        audit_register_class(AUDIT_CLASS_WRITE_32, s390_write_class);
        audit_register_class(AUDIT_CLASS_READ_32, s390_read_class);
        audit_register_class(AUDIT_CLASS_DIR_WRITE_32, s390_dir_class);
diff --git a/arch/s390/kernel/audit.h b/arch/s390/kernel/audit.h
new file mode 100644 (file)
index 0000000..12b56f4
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef __ARCH_S390_KERNEL_AUDIT_H
+#define __ARCH_S390_KERNEL_AUDIT_H
+
+#include <linux/types.h>
+
+#ifdef CONFIG_COMPAT
+extern int s390_classify_syscall(unsigned);
+extern __u32 s390_dir_class[];
+extern __u32 s390_write_class[];
+extern __u32 s390_read_class[];
+extern __u32 s390_chattr_class[];
+extern __u32 s390_signal_class[];
+#endif /* CONFIG_COMPAT */
+
+#endif /* __ARCH_S390_KERNEL_AUDIT_H */
index 0569f5126e499ea4bdd477301eeb8e5cc35f42df..d6487bf879e5bc098d67339764ee1d03fa43d1ef 100644 (file)
@@ -1,5 +1,6 @@
 #undef __s390x__
 #include <asm/unistd.h>
+#include "audit.h"
 
 unsigned s390_dir_class[] = {
 #include <asm-generic/audit_dir_write.h>
index 6c89f30c8e31ea39f181fe610dffada543254129..d8c1131e081568927e7f4460aa4febd912c869bf 100644 (file)
@@ -2,7 +2,7 @@
  *  arch/s390/kernel/cpcmd.c
  *
  *  S390 version
- *    Copyright (C) 1999,2005 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Copyright IBM Corp. 1999,2007
  *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
  *               Christian Borntraeger (cborntra@de.ibm.com),
  */
 static DEFINE_SPINLOCK(cpcmd_lock);
 static char cpcmd_buf[241];
 
+static int diag8_noresponse(int cmdlen)
+{
+       register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf;
+       register unsigned long reg3 asm ("3") = cmdlen;
+
+       asm volatile(
+#ifndef CONFIG_64BIT
+               "       diag    %1,%0,0x8\n"
+#else /* CONFIG_64BIT */
+               "       sam31\n"
+               "       diag    %1,%0,0x8\n"
+               "       sam64\n"
+#endif /* CONFIG_64BIT */
+               : "+d" (reg3) : "d" (reg2) : "cc");
+       return reg3;
+}
+
+static int diag8_response(int cmdlen, char *response, int *rlen)
+{
+       register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf;
+       register unsigned long reg3 asm ("3") = (addr_t) response;
+       register unsigned long reg4 asm ("4") = cmdlen | 0x40000000L;
+       register unsigned long reg5 asm ("5") = *rlen;
+
+       asm volatile(
+#ifndef CONFIG_64BIT
+               "       diag    %2,%0,0x8\n"
+               "       brc     8,1f\n"
+               "       ar      %1,%4\n"
+#else /* CONFIG_64BIT */
+               "       sam31\n"
+               "       diag    %2,%0,0x8\n"
+               "       sam64\n"
+               "       brc     8,1f\n"
+               "       agr     %1,%4\n"
+#endif /* CONFIG_64BIT */
+               "1:\n"
+               : "+d" (reg4), "+d" (reg5)
+               : "d" (reg2), "d" (reg3), "d" (*rlen) : "cc");
+       *rlen = reg5;
+       return reg4;
+}
+
 /*
  * __cpcmd has some restrictions over cpcmd
  *  - the response buffer must reside below 2GB (if any)
@@ -28,59 +71,27 @@ static char cpcmd_buf[241];
  */
 int  __cpcmd(const char *cmd, char *response, int rlen, int *response_code)
 {
-       unsigned cmdlen;
-       int return_code, return_len;
+       int cmdlen;
+       int rc;
+       int response_len;
 
        cmdlen = strlen(cmd);
        BUG_ON(cmdlen > 240);
        memcpy(cpcmd_buf, cmd, cmdlen);
        ASCEBC(cpcmd_buf, cmdlen);
 
-       if (response != NULL && rlen > 0) {
-               register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf;
-               register unsigned long reg3 asm ("3") = (addr_t) response;
-               register unsigned long reg4 asm ("4") = cmdlen | 0x40000000L;
-               register unsigned long reg5 asm ("5") = rlen;
-
+       if (response) {
                memset(response, 0, rlen);
-               asm volatile(
-#ifndef CONFIG_64BIT
-                       "       diag    %2,%0,0x8\n"
-                       "       brc     8,1f\n"
-                       "       ar      %1,%4\n"
-#else /* CONFIG_64BIT */
-                       "       sam31\n"
-                       "       diag    %2,%0,0x8\n"
-                       "       sam64\n"
-                       "       brc     8,1f\n"
-                       "       agr     %1,%4\n"
-#endif /* CONFIG_64BIT */
-                       "1:\n"
-                       : "+d" (reg4), "+d" (reg5)
-                       : "d" (reg2), "d" (reg3), "d" (rlen) : "cc");
-               return_code = (int) reg4;
-               return_len = (int) reg5;
-                EBCASC(response, rlen);
+               response_len = rlen;
+               rc = diag8_response(cmdlen, response, &rlen);
+               EBCASC(response, response_len);
         } else {
-               register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf;
-               register unsigned long reg3 asm ("3") = cmdlen;
-               return_len = 0;
-               asm volatile(
-#ifndef CONFIG_64BIT
-                       "       diag    %1,%0,0x8\n"
-#else /* CONFIG_64BIT */
-                       "       sam31\n"
-                       "       diag    %1,%0,0x8\n"
-                       "       sam64\n"
-#endif /* CONFIG_64BIT */
-                       : "+d" (reg3) : "d" (reg2) : "cc");
-               return_code = (int) reg3;
+               rc = diag8_noresponse(cmdlen);
         }
-       if (response_code != NULL)
-               *response_code = return_code;
-       return return_len;
+       if (response_code)
+               *response_code = rc;
+       return rlen;
 }
-
 EXPORT_SYMBOL(__cpcmd);
 
 int cpcmd(const char *cmd, char *response, int rlen, int *response_code)
@@ -109,5 +120,4 @@ int cpcmd(const char *cmd, char *response, int rlen, int *response_code)
        }
        return len;
 }
-
 EXPORT_SYMBOL(cpcmd);
index 50d2235df732456482201077904cddad27e99970..c14a336f63002c2d166ab86731a4c876a6a51d62 100644 (file)
@@ -1162,6 +1162,7 @@ static int print_insn(char *buffer, unsigned char *code, unsigned long addr)
        unsigned int value;
        char separator;
        char *ptr;
+       int i;
 
        ptr = buffer;
        insn = find_insn(code);
@@ -1169,7 +1170,8 @@ static int print_insn(char *buffer, unsigned char *code, unsigned long addr)
                ptr += sprintf(ptr, "%.5s\t", insn->name);
                /* Extract the operands. */
                separator = 0;
-               for (ops = formats[insn->format] + 1; *ops != 0; ops++) {
+               for (ops = formats[insn->format] + 1, i = 0;
+                    *ops != 0 && i < 6; ops++, i++) {
                        operand = operands + *ops;
                        value = extract_operand(code, operand);
                        if ((operand->flags & OPERAND_INDEX)  && value == 0)
@@ -1241,7 +1243,6 @@ void show_code(struct pt_regs *regs)
        }
        /* Find a starting point for the disassembly. */
        while (start < 32) {
-               hops = 0;
                for (i = 0, hops = 0; start + i < 32 && hops < 3; hops++) {
                        if (!find_insn(code + start + i))
                                break;
index 8b8f136d9cc76b582a96699bdb76a9c3a491760e..66b51901c87d29be81d8c25cc0b8546ae1e970b1 100644 (file)
@@ -735,10 +735,10 @@ void do_reipl(void)
        case REIPL_METHOD_CCW_VM:
                reipl_get_ascii_loadparm(loadparm);
                if (strlen(loadparm) == 0)
-                       sprintf(buf, "IPL %X",
+                       sprintf(buf, "IPL %X CLEAR",
                                reipl_block_ccw->ipl_info.ccw.devno);
                else
-                       sprintf(buf, "IPL %X LOADPARM '%s'",
+                       sprintf(buf, "IPL %X CLEAR LOADPARM '%s'",
                                reipl_block_ccw->ipl_info.ccw.devno, loadparm);
                __cpcmd(buf, NULL, 0, NULL);
                break;
index b4622a3889b0575f86dea86ccf6ffa96bd25ec2d..849120e3e28a0b6e7c2dddaa16c82e09dc086bc9 100644 (file)
@@ -2,6 +2,7 @@
  * Written by Martin Schwidefsky (schwidefsky@de.ibm.com)
  */
 
+#include <asm/page.h>
 #include <asm-generic/vmlinux.lds.h>
 
 #ifndef CONFIG_64BIT
@@ -18,121 +19,142 @@ jiffies = jiffies_64;
 
 SECTIONS
 {
-  . = 0x00000000;
-  _text = .;                   /* Text and read-only data */
-  .text : {
-       *(.text.head)
+       . = 0x00000000;
+       .text : {
+       _text = .;              /* Text and read-only data */
+               *(.text.head)
        TEXT_TEXT
-       SCHED_TEXT
-       LOCK_TEXT
-       KPROBES_TEXT
-       *(.fixup)
-       *(.gnu.warning)
+               SCHED_TEXT
+               LOCK_TEXT
+               KPROBES_TEXT
+               *(.fixup)
+               *(.gnu.warning)
        } = 0x0700
 
-  _etext = .;                  /* End of text section */
+       _etext = .;             /* End of text section */
 
-  RODATA
+       RODATA
 
 #ifdef CONFIG_SHARED_KERNEL
-  . = ALIGN(1048576);          /* VM shared segments are 1MB aligned */
+       . = ALIGN(0x100000);    /* VM shared segments are 1MB aligned */
 #endif
 
-  . = ALIGN(4096);
-  _eshared = .;                        /* End of shareable data */
-
-  . = ALIGN(16);               /* Exception table */
-  __start___ex_table = .;
-  __ex_table : { *(__ex_table) }
-  __stop___ex_table = .;
-
-  NOTES
-
-  BUG_TABLE
-
-  .data : {                    /* Data */
-       DATA_DATA
-       CONSTRUCTORS
-       }
-
-  . = ALIGN(4096);
-  __nosave_begin = .;
-  .data_nosave : { *(.data.nosave) }
-  . = ALIGN(4096);
-  __nosave_end = .;
-
-  . = ALIGN(4096);
-  .data.page_aligned : { *(.data.idt) }
-
-  . = ALIGN(256);
-  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
-
-  . = ALIGN(256);
-  .data.read_mostly : { *(.data.read_mostly) }
-  _edata = .;                  /* End of data section */
-
-  . = ALIGN(8192);             /* init_task */
-  .data.init_task : { *(.data.init_task) }
-
-  /* will be freed after init */
-  . = ALIGN(4096);             /* Init code and data */
-  __init_begin = .;
-  .init.text : { 
-       _sinittext = .;
-       *(.init.text)
-       _einittext = .;
-  }
-  /*
-   * .exit.text is discarded at runtime, not link time,
-   * to deal with references from __bug_table
-   */
-  .exit.text :  { *(.exit.text) }
-
-  .init.data : { *(.init.data) }
-  . = ALIGN(256);
-  __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(PAGE_SIZE);
+       _eshared = .;           /* End of shareable data */
+
+       . = ALIGN(16);          /* Exception table */
+       __ex_table : {
+               __start___ex_table = .;
+               *(__ex_table)
+               __stop___ex_table = .;
+       }
+
+       NOTES
+       BUG_TABLE
+
+       .data : {               /* Data */
+               DATA_DATA
+               CONSTRUCTORS
+       }
+
+       . = ALIGN(PAGE_SIZE);
+       .data_nosave : {
+       __nosave_begin = .;
+               *(.data.nosave)
+       }
+       . = ALIGN(PAGE_SIZE);
+       __nosave_end = .;
+
+       . = ALIGN(PAGE_SIZE);
+       .data.page_aligned : {
+               *(.data.idt)
+       }
+
+       . = ALIGN(0x100);
+       .data.cacheline_aligned : {
+               *(.data.cacheline_aligned)
+       }
+
+       . = ALIGN(0x100);
+       .data.read_mostly : {
+               *(.data.read_mostly)
+       }
+       _edata = .;             /* End of data section */
+
+       . = ALIGN(2 * PAGE_SIZE);       /* init_task */
+       .data.init_task : {
+               *(.data.init_task)
+       }
+
+       /* will be freed after init */
+       . = ALIGN(PAGE_SIZE);   /* Init code and data */
+       __init_begin = .;
+       .init.text : {
+               _sinittext = .;
+               *(.init.text)
+               _einittext = .;
+       }
+       /*
+        * .exit.text is discarded at runtime, not link time,
+        * to deal with references from __bug_table
+       */
+       .exit.text : {
+               *(.exit.text)
+       }
+
+       .init.data : {
+               *(.init.data)
+       }
+       . = ALIGN(0x100);
+       .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(256);
-  __initramfs_start = .;
-  .init.ramfs : { *(.init.initramfs) }
-  . = ALIGN(2);
-  __initramfs_end = .;
+       . = ALIGN(0x100);
+       .init.ramfs : {
+               __initramfs_start = .;
+               *(.init.ramfs)
+               . = ALIGN(2);
+               __initramfs_end = .;
+       }
 #endif
-  PERCPU(4096)
-  . = ALIGN(4096);
-  __init_end = .;
-  /* freed after init ends here */
-
-  __bss_start = .;             /* BSS */
-  .bss : { *(.bss) }
-  . = ALIGN(2);
-  __bss_stop = .;
-
-  _end = . ;
-
-  /* Sections to be discarded */
-  /DISCARD/ : {
-       *(.exit.data) *(.exitcall.exit)
-       }
-
-  /* Stabs debugging sections.  */
-  .stab 0 : { *(.stab) }
-  .stabstr 0 : { *(.stabstr) }
-  .stab.excl 0 : { *(.stab.excl) }
-  .stab.exclstr 0 : { *(.stab.exclstr) }
-  .stab.index 0 : { *(.stab.index) }
-  .stab.indexstr 0 : { *(.stab.indexstr) }
-  .comment 0 : { *(.comment) }
+
+       PERCPU(PAGE_SIZE)
+       . = ALIGN(PAGE_SIZE);
+       __init_end = .;         /* freed after init ends here */
+
+       /* BSS */
+       .bss : {
+               __bss_start = .;
+               *(.bss)
+               . = ALIGN(2);
+               __bss_stop = .;
+       }
+
+       _end = . ;
+
+       /* Sections to be discarded */
+       /DISCARD/ : {
+               *(.exit.data)
+               *(.exitcall.exit)
+       }
+
+       /* Debugging sections.  */
+       STABS_DEBUG
+       DWARF_DEBUG
 }
index 54055194e9af320e3b9e675bdebaab77014419c2..4c1ac341ec80633c95194f3c83ab7f358b36189a 100644 (file)
@@ -468,7 +468,7 @@ typedef struct {
        __u64 refselmk;
        __u64 refcmpmk;
        __u64 reserved;
-} __attribute__ ((packed)) pfault_refbk_t;
+} __attribute__ ((packed, aligned(8))) pfault_refbk_t;
 
 int pfault_init(void)
 {
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
diff --git a/arch/sh/configs/rts7751r2d1_defconfig b/arch/sh/configs/rts7751r2d1_defconfig
new file mode 100644 (file)
index 0000000..2dc754e
--- /dev/null
@@ -0,0 +1,1167 @@
+#
+# Automatically generated make config: don't edit
+# 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=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 is not set
+CONFIG_RTS7751R2D_1=y
+
+#
+# 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
diff --git a/arch/sh/configs/rts7751r2d_defconfig b/arch/sh/configs/rts7751r2d_defconfig
deleted file mode 100644 (file)
index b64f73b..0000000
+++ /dev/null
@@ -1,1353 +0,0 @@
-#
-# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.21-rc1
-# Thu Mar  1 16:42:40 2007
-#
-CONFIG_SUPERH=y
-CONFIG_RWSEM_GENERIC_SPINLOCK=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_STACKTRACE_SUPPORT=y
-CONFIG_LOCKDEP_SUPPORT=y
-# CONFIG_ARCH_HAS_ILOG2_U32 is not set
-# CONFIG_ARCH_HAS_ILOG2_U64 is not set
-CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
-
-#
-# Code maturity level options
-#
-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_AUDIT is not set
-# CONFIG_IKCONFIG is not set
-CONFIG_SYSFS_DEPRECATED=y
-# CONFIG_RELAY 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_EPOLL=y
-CONFIG_SHMEM=y
-CONFIG_SLAB=y
-CONFIG_VM_EVENT_COUNTERS=y
-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
-
-#
-# 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_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_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
-
-#
-# 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_SH7343 is not set
-# CONFIG_CPU_SUBTYPE_SH7722 is not set
-
-#
-# Memory management options
-#
-CONFIG_MMU=y
-CONFIG_PAGE_OFFSET=0x80000000
-CONFIG_MEMORY_START=0x0c000000
-CONFIG_MEMORY_SIZE=0x04000000
-CONFIG_VSYSCALL=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_SPLIT_PTLOCK_CPUS=4
-# CONFIG_RESOURCES_64BIT is not set
-CONFIG_ZONE_DMA_FLAG=0
-
-#
-# Cache configuration
-#
-# CONFIG_SH_DIRECT_MAPPED is not set
-# CONFIG_SH_WRITETHROUGH is not set
-# CONFIG_SH_OCRAM is not set
-
-#
-# Processor features
-#
-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
-CONFIG_CPU_HAS_SR_RB=y
-CONFIG_CPU_HAS_PTEA=y
-
-#
-# Timer support
-#
-CONFIG_SH_TMU=y
-
-#
-# RTS7751R2D options
-#
-CONFIG_RTS7751R2D_REV11=y
-CONFIG_SH_TIMER_IRQ=16
-# CONFIG_NO_IDLE_HZ is not set
-CONFIG_SH_PCLK_FREQ=60000000
-
-#
-# CPU Frequency scaling
-#
-# CONFIG_CPU_FREQ is not set
-
-#
-# 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_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_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
-
-#
-# 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
-# CONFIG_HOTPLUG_PCI_SHPC is not set
-
-#
-# 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
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-# CONFIG_NETDEBUG is not set
-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
-
-#
-# 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
-# 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_IEEE80211 is not set
-CONFIG_WIRELESS_EXT=y
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
-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_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_BLK_DEV_INITRD is not set
-# CONFIG_CDROM_PKTCDVD is not set
-# CONFIG_ATA_OVER_ETH is not set
-
-#
-# Misc devices
-#
-# CONFIG_SGI_IOC4 is not set
-# CONFIG_TIFM_CORE is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-# CONFIG_RAID_ATTRS is not set
-CONFIG_SCSI=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
-
-#
-# 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_ATTRS is not set
-# CONFIG_SCSI_SAS_LIBSAS is not set
-
-#
-# SCSI low-level drivers
-#
-# 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_DPT_I2O 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
-
-#
-# Serial ATA (prod) and Parallel ATA (experimental) drivers
-#
-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_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
-
-#
-# Multi-device support (RAID and LVM)
-#
-# 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_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
-# Network device support
-#
-CONFIG_NETDEVICES=y
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING 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
-# 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
-
-#
-# Tulip family network device support
-#
-# 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
-
-#
-# Ethernet (1000 Mbit)
-#
-# 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_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_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_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
-#
-# 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
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
-# CONFIG_PHONE is not set
-
-#
-# Input device support
-#
-CONFIG_INPUT=y
-# CONFIG_INPUT_FF_MEMLESS 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_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
-
-#
-# 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_I2C is not set
-
-#
-# SPI support
-#
-# 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_HWMON=y
-# CONFIG_HWMON_VID is not set
-# CONFIG_SENSORS_ABITUGURU is not set
-# CONFIG_SENSORS_F71805F is not set
-# CONFIG_SENSORS_PC87427 is not set
-# CONFIG_SENSORS_VT1211 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
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# Graphics support
-#
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
-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_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
-
-#
-# 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
-# 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_TRIDENT 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_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
-# 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_AC97_POWER_SAVE is not set
-
-#
-# SoC audio support
-#
-# CONFIG_SND_SOC is not set
-
-#
-# 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=y
-# CONFIG_HID_DEBUG is not set
-
-#
-# USB support
-#
-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
-
-#
-# 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
-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
-
-#
-# 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_SH=y
-# CONFIG_RTC_DRV_TEST is not set
-# CONFIG_RTC_DRV_V3020 is not set
-
-#
-# DMA Engine support
-#
-# CONFIG_DMA_ENGINE is not set
-
-#
-# DMA Clients
-#
-
-#
-# DMA Devices
-#
-
-#
-# Auxiliary Display support
-#
-
-#
-# Virtualization
-#
-
-#
-# 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
-# CONFIG_9P_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_LOG_BUF_SHIFT=14
-# 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
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
-
-#
-# Library routines
-#
-CONFIG_BITREVERSE=y
-# CONFIG_CRC_CCITT is not set
-# CONFIG_CRC16 is not set
-CONFIG_CRC32=y
-# CONFIG_LIBCRC32C is not set
-CONFIG_PLIST=y
-CONFIG_HAS_IOMEM=y
-CONFIG_HAS_IOPORT=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 e61890217c5012b006fa8437975d4fe55a0fe108..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;
 
@@ -93,7 +91,6 @@ static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy)
        policy->cpuinfo.max_freq = (clk_round_rate(cpuclk, ~0UL) + 500) / 1000;
        policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
 
-       policy->governor        = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cur             = sh_cpufreq_get(policy->cpu);
        policy->min             = policy->cpuinfo.min_freq;
        policy->max             = policy->cpuinfo.max_freq;
@@ -144,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)
 {
diff --git a/arch/sh64/kernel/pci-dma.c b/arch/sh64/kernel/pci-dma.c
deleted file mode 100644 (file)
index a9328f8..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
- * Copyright (C) 2003 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.
- *
- * Dynamic DMA mapping support.
- */
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-
-void *consistent_alloc(struct pci_dev *hwdev, size_t size,
-                          dma_addr_t *dma_handle)
-{
-       void *ret;
-       int gfp = GFP_ATOMIC;
-        void *vp;
-
-       if (hwdev == NULL || hwdev->dma_mask != 0xffffffff)
-               gfp |= GFP_DMA;
-
-       ret = (void *)__get_free_pages(gfp, get_order(size));
-
-       /* now call our friend ioremap_nocache to give us an uncached area */
-        vp = ioremap_nocache(virt_to_phys(ret), size);
-
-       if (vp != NULL) {
-               memset(vp, 0, size);
-               *dma_handle = virt_to_phys(ret);
-               dma_cache_wback_inv((unsigned long)ret, size);
-       }
-
-       return vp;
-}
-
-void consistent_free(struct pci_dev *hwdev, size_t size,
-                        void *vaddr, dma_addr_t dma_handle)
-{
-       void *alloc;
-
-       alloc = phys_to_virt((unsigned long)dma_handle);
-       free_pages((unsigned long)alloc, get_order(size));
-
-       iounmap(vaddr);
-}
-
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
-
diff --git a/arch/sh64/mm/consistent.c b/arch/sh64/mm/consistent.c
new file mode 100644 (file)
index 0000000..8875a2a
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
+ * Copyright (C) 2003 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.
+ *
+ * Dynamic DMA mapping support.
+ */
+#include <linux/types.h>
+#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,
+                          dma_addr_t *dma_handle)
+{
+       void *ret;
+       int gfp = GFP_ATOMIC;
+        void *vp;
+
+       if (hwdev == NULL || hwdev->dma_mask != 0xffffffff)
+               gfp |= GFP_DMA;
+
+       ret = (void *)__get_free_pages(gfp, get_order(size));
+
+       /* now call our friend ioremap_nocache to give us an uncached area */
+        vp = ioremap_nocache(virt_to_phys(ret), size);
+
+       if (vp != NULL) {
+               memset(vp, 0, size);
+               *dma_handle = virt_to_phys(ret);
+               dma_cache_wback_inv((unsigned long)ret, size);
+       }
+
+       return vp;
+}
+EXPORT_SYMBOL(consistent_alloc);
+
+void consistent_free(struct pci_dev *hwdev, size_t size,
+                        void *vaddr, dma_addr_t dma_handle)
+{
+       void *alloc;
+
+       alloc = phys_to_virt((unsigned long)dma_handle);
+       free_pages((unsigned long)alloc, get_order(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 1f83fe6a82d628bfbacf63795799b401d4812903..791c15138f3a4abf3cb368e12041fcd7f304842c 100644 (file)
@@ -326,7 +326,6 @@ static int __init us2e_freq_cpu_init(struct cpufreq_policy *policy)
        table[2].index = 5;
        table[3].frequency = CPUFREQ_TABLE_END;
 
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cpuinfo.transition_latency = 0;
        policy->cur = clock_tick;
 
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 c624193740fde274a00f59e123b7667cdda71111..7ff02063b858c7855c0d4dd0ce27dbdd3160cbcd 100644 (file)
@@ -7,7 +7,7 @@ extra-y := head_32.o init_task_32.o vmlinux.lds
 obj-y  := process_32.o signal_32.o entry_32.o traps_32.o irq_32.o \
                ptrace_32.o time_32.o ioport_32.o ldt_32.o setup_32.o i8259_32.o sys_i386_32.o \
                pci-dma_32.o i386_ksyms_32.o i387_32.o bootflag.o e820_32.o\
-               quirks.o i8237.o topology.o alternative.o i8253_32.o tsc_32.o
+               quirks.o i8237.o topology.o alternative.o i8253.o tsc_32.o
 
 obj-$(CONFIG_STACKTRACE)       += stacktrace.o
 obj-y                          += cpu/
@@ -37,9 +37,9 @@ obj-$(CONFIG_EFI)             += efi_32.o efi_stub_32.o
 obj-$(CONFIG_DOUBLEFAULT)      += doublefault_32.o
 obj-$(CONFIG_VM86)             += vm86_32.o
 obj-$(CONFIG_EARLY_PRINTK)     += early_printk.o
-obj-$(CONFIG_HPET_TIMER)       += hpet_32.o
+obj-$(CONFIG_HPET_TIMER)       += hpet.o
 obj-$(CONFIG_K8_NB)            += k8.o
-obj-$(CONFIG_MGEODE_LX)                += geode_32.o
+obj-$(CONFIG_MGEODE_LX)                += geode_32.o mfgpt_32.o
 
 obj-$(CONFIG_VMI)              += vmi_32.o vmiclock_32.o
 obj-$(CONFIG_PARAVIRT)         += paravirt_32.o
index 3ab017a0a3b94dc436e1ca26e992591d2a7af7ab..43da66213a479117a91c05f62e4b67447d412205 100644 (file)
@@ -8,8 +8,8 @@ obj-y   := process_64.o signal_64.o entry_64.o traps_64.o irq_64.o \
                ptrace_64.o time_64.o ioport_64.o ldt_64.o setup_64.o i8259_64.o sys_x86_64.o \
                x8664_ksyms_64.o i387_64.o syscall_64.o vsyscall_64.o \
                setup64.o bootflag.o e820_64.o reboot_64.o quirks.o i8237.o \
-               pci-dma_64.o pci-nommu_64.o alternative.o hpet_64.o tsc_64.o bugs_64.o \
-               perfctr-watchdog.o
+               pci-dma_64.o pci-nommu_64.o alternative.o hpet.o tsc_64.o bugs_64.o \
+               perfctr-watchdog.o i8253.o
 
 obj-$(CONFIG_STACKTRACE)       += stacktrace.o
 obj-$(CONFIG_X86_MCE)          += mce_64.o therm_throt.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 925758dbca0c6016b52e91ab90e7503c90ea08c0..09b82093bc759e5aa9eb1f9003bf7d4c822d0679 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/sysdev.h>
 #include <linux/module.h>
 #include <linux/ioport.h>
+#include <linux/clockchips.h>
 
 #include <asm/atomic.h>
 #include <asm/smp.h>
 #include <asm/hpet.h>
 #include <asm/apic.h>
 
-int apic_mapped;
 int apic_verbosity;
-int apic_runs_main_timer;
-int apic_calibrate_pmtmr __initdata;
-
-int disable_apic_timer __initdata;
+int disable_apic_timer __cpuinitdata;
+static int apic_calibrate_pmtmr __initdata;
 
 /* Local APIC timer works in C2? */
 int local_apic_timer_c2_ok;
@@ -56,14 +54,78 @@ static struct resource lapic_resource = {
        .flags = IORESOURCE_MEM | IORESOURCE_BUSY,
 };
 
+static unsigned int calibration_result;
+
+static int lapic_next_event(unsigned long delta,
+                           struct clock_event_device *evt);
+static void lapic_timer_setup(enum clock_event_mode mode,
+                             struct clock_event_device *evt);
+
+static void lapic_timer_broadcast(cpumask_t mask);
+
+static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen);
+
+static struct clock_event_device lapic_clockevent = {
+       .name           = "lapic",
+       .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT
+                       | CLOCK_EVT_FEAT_C3STOP | CLOCK_EVT_FEAT_DUMMY,
+       .shift          = 32,
+       .set_mode       = lapic_timer_setup,
+       .set_next_event = lapic_next_event,
+       .broadcast      = lapic_timer_broadcast,
+       .rating         = 100,
+       .irq            = -1,
+};
+static DEFINE_PER_CPU(struct clock_event_device, lapic_events);
+
+static int lapic_next_event(unsigned long delta,
+                           struct clock_event_device *evt)
+{
+       apic_write(APIC_TMICT, delta);
+       return 0;
+}
+
+static void lapic_timer_setup(enum clock_event_mode mode,
+                             struct clock_event_device *evt)
+{
+       unsigned long flags;
+       unsigned int v;
+
+       /* Lapic used as dummy for broadcast ? */
+       if (evt->features & CLOCK_EVT_FEAT_DUMMY)
+               return;
+
+       local_irq_save(flags);
+
+       switch (mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+       case CLOCK_EVT_MODE_ONESHOT:
+               __setup_APIC_LVTT(calibration_result,
+                                 mode != CLOCK_EVT_MODE_PERIODIC, 1);
+               break;
+       case CLOCK_EVT_MODE_UNUSED:
+       case CLOCK_EVT_MODE_SHUTDOWN:
+               v = apic_read(APIC_LVTT);
+               v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
+               apic_write(APIC_LVTT, v);
+               break;
+       case CLOCK_EVT_MODE_RESUME:
+               /* Nothing to do here */
+               break;
+       }
+
+       local_irq_restore(flags);
+}
+
 /*
- * cpu_mask that denotes the CPUs that needs timer interrupt coming in as
- * IPIs in place of local APIC timers
+ * Local APIC timer broadcast function
  */
-static cpumask_t timer_interrupt_broadcast_ipi_mask;
-
-/* Using APIC to generate smp_local_timer_interrupt? */
-int using_apic_timer __read_mostly = 0;
+static void lapic_timer_broadcast(cpumask_t mask)
+{
+#ifdef CONFIG_SMP
+       send_IPI_mask(mask, LOCAL_TIMER_VECTOR);
+#endif
+}
 
 static void apic_pm_activate(void);
 
@@ -184,7 +246,10 @@ void disconnect_bsp_APIC(int virt_wire_setup)
        apic_write(APIC_SPIV, value);
 
        if (!virt_wire_setup) {
-               /* For LVT0 make it edge triggered, active high, external and enabled */
+               /*
+                * For LVT0 make it edge triggered, active high,
+                * external and enabled
+                */
                value = apic_read(APIC_LVT0);
                value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING |
                        APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR |
@@ -420,10 +485,12 @@ void __cpuinit setup_local_APIC (void)
        value = apic_read(APIC_LVT0) & APIC_LVT_MASKED;
        if (!smp_processor_id() && !value) {
                value = APIC_DM_EXTINT;
-               apic_printk(APIC_VERBOSE, "enabled ExtINT on CPU#%d\n", smp_processor_id());
+               apic_printk(APIC_VERBOSE, "enabled ExtINT on CPU#%d\n",
+                           smp_processor_id());
        } else {
                value = APIC_DM_EXTINT | APIC_LVT_MASKED;
-               apic_printk(APIC_VERBOSE, "masked ExtINT on CPU#%d\n", smp_processor_id());
+               apic_printk(APIC_VERBOSE, "masked ExtINT on CPU#%d\n",
+                           smp_processor_id());
        }
        apic_write(APIC_LVT0, value);
 
@@ -706,8 +773,8 @@ void __init init_apic_mappings(void)
                apic_phys = mp_lapic_addr;
 
        set_fixmap_nocache(FIX_APIC_BASE, apic_phys);
-       apic_mapped = 1;
-       apic_printk(APIC_VERBOSE,"mapped APIC to %16lx (%16lx)\n", APIC_BASE, apic_phys);
+       apic_printk(APIC_VERBOSE, "mapped APIC to %16lx (%16lx)\n",
+                               APIC_BASE, apic_phys);
 
        /* Put local APIC into the resource map. */
        lapic_resource.start = apic_phys;
@@ -730,12 +797,14 @@ void __init init_apic_mappings(void)
                        if (smp_found_config) {
                                ioapic_phys = mp_ioapics[i].mpc_apicaddr;
                        } else {
-                               ioapic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE);
+                               ioapic_phys = (unsigned long)
+                                       alloc_bootmem_pages(PAGE_SIZE);
                                ioapic_phys = __pa(ioapic_phys);
                        }
                        set_fixmap_nocache(idx, ioapic_phys);
-                       apic_printk(APIC_VERBOSE,"mapped IOAPIC to %016lx (%016lx)\n",
-                                       __fix_to_virt(idx), ioapic_phys);
+                       apic_printk(APIC_VERBOSE,
+                                   "mapped IOAPIC to %016lx (%016lx)\n",
+                                   __fix_to_virt(idx), ioapic_phys);
                        idx++;
 
                        if (ioapic_res != NULL) {
@@ -758,16 +827,14 @@ void __init init_apic_mappings(void)
  * P5 APIC double write bug.
  */
 
-#define APIC_DIVISOR 16
-
-static void __setup_APIC_LVTT(unsigned int clocks)
+static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen)
 {
        unsigned int lvtt_value, tmp_value;
-       int cpu = smp_processor_id();
 
-       lvtt_value = APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR;
-
-       if (cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask))
+       lvtt_value = LOCAL_TIMER_VECTOR;
+       if (!oneshot)
+               lvtt_value |= APIC_LVT_TIMER_PERIODIC;
+       if (!irqen)
                lvtt_value |= APIC_LVT_MASKED;
 
        apic_write(APIC_LVTT, lvtt_value);
@@ -780,44 +847,18 @@ static void __setup_APIC_LVTT(unsigned int clocks)
                                & ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE))
                                | APIC_TDR_DIV_16);
 
-       apic_write(APIC_TMICT, clocks/APIC_DIVISOR);
+       if (!oneshot)
+               apic_write(APIC_TMICT, clocks);
 }
 
-static void setup_APIC_timer(unsigned int clocks)
+static void setup_APIC_timer(void)
 {
-       unsigned long flags;
+       struct clock_event_device *levt = &__get_cpu_var(lapic_events);
 
-       local_irq_save(flags);
+       memcpy(levt, &lapic_clockevent, sizeof(*levt));
+       levt->cpumask = cpumask_of_cpu(smp_processor_id());
 
-       /* wait for irq slice */
-       if (hpet_address && hpet_use_timer) {
-               u32 trigger = hpet_readl(HPET_T0_CMP);
-               while (hpet_readl(HPET_T0_CMP) == trigger)
-                       /* do nothing */ ;
-       } else {
-               int c1, c2;
-               outb_p(0x00, 0x43);
-               c2 = inb_p(0x40);
-               c2 |= inb_p(0x40) << 8;
-               do {
-                       c1 = c2;
-                       outb_p(0x00, 0x43);
-                       c2 = inb_p(0x40);
-                       c2 |= inb_p(0x40) << 8;
-               } while (c2 - c1 < 300);
-       }
-       __setup_APIC_LVTT(clocks);
-       /* Turn off PIT interrupt if we use APIC timer as main timer.
-          Only works with the PM timer right now
-          TBD fix it for HPET too. */
-       if ((pmtmr_ioport != 0) &&
-               smp_processor_id() == boot_cpu_id &&
-               apic_runs_main_timer == 1 &&
-               !cpu_isset(boot_cpu_id, timer_interrupt_broadcast_ipi_mask)) {
-               stop_timer_interrupt();
-               apic_runs_main_timer++;
-       }
-       local_irq_restore(flags);
+       clockevents_register_device(levt);
 }
 
 /*
@@ -835,17 +876,22 @@ static void setup_APIC_timer(unsigned int clocks)
 
 #define TICK_COUNT 100000000
 
-static int __init calibrate_APIC_clock(void)
+static void __init calibrate_APIC_clock(void)
 {
        unsigned apic, apic_start;
        unsigned long tsc, tsc_start;
        int result;
+
+       local_irq_disable();
+
        /*
         * Put whatever arbitrary (but long enough) timeout
         * value into the APIC clock, we just want to get the
         * counter running for calibration.
+        *
+        * No interrupt enable !
         */
-       __setup_APIC_LVTT(4000000000);
+       __setup_APIC_LVTT(250000000, 0, 0);
 
        apic_start = apic_read(APIC_TMCCT);
 #ifdef CONFIG_X86_PM_TIMER
@@ -867,123 +913,88 @@ static int __init calibrate_APIC_clock(void)
                result = (apic_start - apic) * 1000L * tsc_khz /
                                        (tsc - tsc_start);
        }
-       printk("result %d\n", result);
 
+       local_irq_enable();
+
+       printk(KERN_DEBUG "APIC timer calibration result %d\n", result);
 
        printk(KERN_INFO "Detected %d.%03d MHz APIC timer.\n",
                result / 1000 / 1000, result / 1000 % 1000);
 
-       return result * APIC_DIVISOR / HZ;
-}
+       /* Calculate the scaled math multiplication factor */
+       lapic_clockevent.mult = div_sc(result, NSEC_PER_SEC, 32);
+       lapic_clockevent.max_delta_ns =
+               clockevent_delta2ns(0x7FFFFF, &lapic_clockevent);
+       lapic_clockevent.min_delta_ns =
+               clockevent_delta2ns(0xF, &lapic_clockevent);
 
-static unsigned int calibration_result;
+       calibration_result = result / HZ;
+}
 
 void __init setup_boot_APIC_clock (void)
 {
+       /*
+        * The local apic timer can be disabled via the kernel commandline.
+        * Register the lapic timer as a dummy clock event source on SMP
+        * systems, so the broadcast mechanism is used. On UP systems simply
+        * ignore it.
+        */
        if (disable_apic_timer) {
                printk(KERN_INFO "Disabling APIC timer\n");
+               /* No broadcast on UP ! */
+               if (num_possible_cpus() > 1)
+                       setup_APIC_timer();
                return;
        }
 
        printk(KERN_INFO "Using local APIC timer interrupts.\n");
-       using_apic_timer = 1;
-
-       local_irq_disable();
+       calibrate_APIC_clock();
 
-       calibration_result = calibrate_APIC_clock();
        /*
-        * Now set up the timer for real.
+        * If nmi_watchdog is set to IO_APIC, we need the
+        * PIT/HPET going.  Otherwise register lapic as a dummy
+        * device.
         */
-       setup_APIC_timer(calibration_result);
-
-       local_irq_enable();
-}
-
-void __cpuinit setup_secondary_APIC_clock(void)
-{
-       local_irq_disable(); /* FIXME: Do we need this? --RR */
-       setup_APIC_timer(calibration_result);
-       local_irq_enable();
-}
-
-void disable_APIC_timer(void)
-{
-       if (using_apic_timer) {
-               unsigned long v;
+       if (nmi_watchdog != NMI_IO_APIC)
+               lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY;
+       else
+               printk(KERN_WARNING "APIC timer registered as dummy,"
+                      " due to nmi_watchdog=1!\n");
 
-               v = apic_read(APIC_LVTT);
-               /*
-                * When an illegal vector value (0-15) is written to an LVT
-                * entry and delivery mode is Fixed, the APIC may signal an
-                * illegal vector error, with out regard to whether the mask
-                * bit is set or whether an interrupt is actually seen on input.
-                *
-                * Boot sequence might call this function when the LVTT has
-                * '0' vector value. So make sure vector field is set to
-                * valid value.
-                */
-               v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
-               apic_write(APIC_LVTT, v);
-       }
+       setup_APIC_timer();
 }
 
-void enable_APIC_timer(void)
+/*
+ * 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)
 {
-       int cpu = smp_processor_id();
+       struct clock_event_device *levt = &per_cpu(lapic_events, boot_cpu_id);
 
-       if (using_apic_timer &&
-           !cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) {
-               unsigned long v;
+       if (!disable_apic_timer ||
+           (lapic_clockevent.features & CLOCK_EVT_FEAT_DUMMY))
+               return;
 
-               v = apic_read(APIC_LVTT);
-               apic_write(APIC_LVTT, v & ~APIC_LVT_MASKED);
-       }
-}
+       printk(KERN_INFO "AMD C1E detected late. Force timer broadcast.\n");
+       lapic_clockevent.features |= CLOCK_EVT_FEAT_DUMMY;
+       levt->features |= CLOCK_EVT_FEAT_DUMMY;
 
-void switch_APIC_timer_to_ipi(void *cpumask)
-{
-       cpumask_t mask = *(cpumask_t *)cpumask;
-       int cpu = smp_processor_id();
-
-       if (cpu_isset(cpu, mask) &&
-           !cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) {
-               disable_APIC_timer();
-               cpu_set(cpu, timer_interrupt_broadcast_ipi_mask);
-       }
+       local_irq_enable();
+       clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_FORCE, &boot_cpu_id);
+       local_irq_disable();
 }
-EXPORT_SYMBOL(switch_APIC_timer_to_ipi);
 
-void smp_send_timer_broadcast_ipi(void)
+void __cpuinit setup_secondary_APIC_clock(void)
 {
-       int cpu = smp_processor_id();
-       cpumask_t mask;
-
-       cpus_and(mask, cpu_online_map, timer_interrupt_broadcast_ipi_mask);
-
-       if (cpu_isset(cpu, mask)) {
-               cpu_clear(cpu, mask);
-               add_pda(apic_timer_irqs, 1);
-               smp_local_timer_interrupt();
-       }
-
-       if (!cpus_empty(mask)) {
-               send_IPI_mask(mask, LOCAL_TIMER_VECTOR);
-       }
+       check_boot_apic_timer_broadcast();
+       setup_APIC_timer();
 }
 
-void switch_ipi_to_APIC_timer(void *cpumask)
-{
-       cpumask_t mask = *(cpumask_t *)cpumask;
-       int cpu = smp_processor_id();
-
-       if (cpu_isset(cpu, mask) &&
-           cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) {
-               cpu_clear(cpu, timer_interrupt_broadcast_ipi_mask);
-               enable_APIC_timer();
-       }
-}
-EXPORT_SYMBOL(switch_ipi_to_APIC_timer);
-
 int setup_profiling_timer(unsigned int multiplier)
 {
        return -EINVAL;
@@ -997,8 +1008,6 @@ void setup_APIC_extended_lvt(unsigned char lvt_off, unsigned char vector,
        apic_write(reg, v);
 }
 
-#undef APIC_DIVISOR
-
 /*
  * Local timer interrupt handler. It does both profiling and
  * process statistics/rescheduling.
@@ -1011,22 +1020,34 @@ void setup_APIC_extended_lvt(unsigned char lvt_off, unsigned char vector,
 
 void smp_local_timer_interrupt(void)
 {
-       profile_tick(CPU_PROFILING);
-#ifdef CONFIG_SMP
-       update_process_times(user_mode(get_irq_regs()));
-#endif
-       if (apic_runs_main_timer > 1 && smp_processor_id() == boot_cpu_id)
-               main_timer_handler();
+       int cpu = smp_processor_id();
+       struct clock_event_device *evt = &per_cpu(lapic_events, cpu);
+
        /*
-        * We take the 'long' return path, and there every subsystem
-        * grabs the appropriate locks (kernel lock/ irq lock).
+        * Normally we should not be here till LAPIC has been initialized but
+        * in some cases like kdump, its possible that there is a pending LAPIC
+        * timer interrupt from previous kernel's context and is delivered in
+        * new kernel the moment interrupts are enabled.
         *
-        * We might want to decouple profiling from the 'long path',
-        * and do the profiling totally in assembly.
-        *
-        * Currently this isn't too much of an issue (performance wise),
-        * we can take more than 100K local irqs per second on a 100 MHz P5.
+        * Interrupts are enabled early and LAPIC is setup much later, hence
+        * its possible that when we get here evt->event_handler is NULL.
+        * Check for event_handler being NULL and discard the interrupt as
+        * spurious.
+        */
+       if (!evt->event_handler) {
+               printk(KERN_WARNING
+                      "Spurious LAPIC timer interrupt on cpu %d\n", cpu);
+               /* Switch it off */
+               lapic_timer_setup(CLOCK_EVT_MODE_SHUTDOWN, evt);
+               return;
+       }
+
+       /*
+        * the NMI deadlock-detector uses this.
         */
+       add_pda(apic_timer_irqs, 1);
+
+       evt->event_handler(evt);
 }
 
 /*
@@ -1041,11 +1062,6 @@ void smp_apic_timer_interrupt(struct pt_regs *regs)
 {
        struct pt_regs *old_regs = set_irq_regs(regs);
 
-       /*
-        * the NMI deadlock-detector uses this.
-        */
-       add_pda(apic_timer_irqs, 1);
-
        /*
         * NOTE! We'd better ACK the irq immediately,
         * because timer handling can be slow.
@@ -1225,29 +1241,13 @@ static __init int setup_noapictimer(char *str)
        disable_apic_timer = 1;
        return 1;
 }
-
-static __init int setup_apicmaintimer(char *str)
-{
-       apic_runs_main_timer = 1;
-       nohpet = 1;
-       return 1;
-}
-__setup("apicmaintimer", setup_apicmaintimer);
-
-static __init int setup_noapicmaintimer(char *str)
-{
-       apic_runs_main_timer = -1;
-       return 1;
-}
-__setup("noapicmaintimer", setup_noapicmaintimer);
+__setup("noapictimer", setup_noapictimer);
 
 static __init int setup_apicpmtimer(char *s)
 {
        apic_calibrate_pmtmr = 1;
        notsc_setup(NULL);
-       return setup_apicmaintimer(NULL);
+       return 0;
 }
 __setup("apicpmtimer", setup_apicpmtimer);
 
-__setup("noapictimer", setup_noapictimer);
-
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 b6434a7ef8b2b311f76aad4307f642e64746dd8b..ffd01e5dcb52c2cacf61f8dee9cf2f450543b8a7 100644 (file)
@@ -646,7 +646,6 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
                        policy->cpuinfo.transition_latency =
                            perf->states[i].transition_latency * 1000;
        }
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 
        data->max_freq = perf->states[0].core_frequency * 1000;
        /* table init */
index 66acd5039918350d16819cbf41457053f021fe56..32f0bda3fc953a4568c194b13773f5a70ba22c69 100644 (file)
@@ -363,7 +363,6 @@ static int nforce2_cpu_init(struct cpufreq_policy *policy)
        policy->cur = nforce2_get(policy->cpu);
        policy->min = policy->cpuinfo.min_freq;
        policy->max = policy->cpuinfo.max_freq;
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 
        return 0;
 }
index f43d98e11cc72bbe72bc66a5b9cbcaac0704e2d7..c11baaf9f2b403f6624e1fa0d4fd5756491d8383 100644 (file)
@@ -253,7 +253,6 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
                f_table[k].frequency = CPUFREQ_TABLE_END;
        }
 
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cpuinfo.transition_latency = 140000; /* 844mV -> 700mV in ns */
        policy->cur = fsb * current_multiplier;
 
index f317276afa7af179906f2035705bcf66a91d1824..1e7ae7dafcf6a50921d1271347e2f522ad13ad2b 100644 (file)
@@ -219,7 +219,6 @@ static int elanfreq_cpu_init(struct cpufreq_policy *policy)
        }
 
        /* cpuinfo and default policy values */
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
        policy->cur = elanfreq_get_cpu_frequency(0);
 
index 461dabc4e4959d23a7b5411d109b1a239a8c3872..ed2bda127c44b8734fbc88af3bc394ed95290ff9 100644 (file)
@@ -420,7 +420,6 @@ static int cpufreq_gx_cpu_init(struct cpufreq_policy *policy)
                policy->min = maxfreq / POLICY_MIN_DIV;
        policy->max = maxfreq;
        policy->cur = curfreq;
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cpuinfo.min_freq = maxfreq / max_duration;
        policy->cpuinfo.max_freq = maxfreq;
        policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
index f0cce3c2dc3a4fe33916f2c1ff5c34bae77237e6..5045f5d583c81954fa7123df8697188a39012583 100644 (file)
@@ -710,6 +710,10 @@ static int enable_arbiter_disable(void)
        reg = 0x78;
        dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8601_0,
                             NULL);
+       /* Find PM133/VT8605 host bridge */
+       if (dev == NULL)
+               dev = pci_get_device(PCI_VENDOR_ID_VIA,
+                                    PCI_DEVICE_ID_VIA_8605_0, NULL);
        /* Find CLE266 host bridge */
        if (dev == NULL) {
                reg = 0x76;
@@ -918,7 +922,6 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
        if ((longhaul_version != TYPE_LONGHAUL_V1) && (scale_voltage != 0))
                longhaul_setup_voltagescaling();
 
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cpuinfo.transition_latency = 200000;    /* nsec */
        policy->cur = calc_speed(longhaul_get_cpu_mult());
 
index 4c76b511e1944d16ed420343cb57db0dafb1f943..8eb414b906d29f7e20f93fdc5d0e6e0edfe21da1 100644 (file)
@@ -229,7 +229,6 @@ static int cpufreq_p4_cpu_init(struct cpufreq_policy *policy)
        cpufreq_frequency_table_get_attr(p4clockmod_table, policy->cpu);
 
        /* cpuinfo and default policy values */
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cpuinfo.transition_latency = 1000000; /* assumed */
        policy->cur = stock_freq;
 
index f89524051e4a3aa78012fd16a4179976764dc7ec..6d02853393175305e8f749b99a8500379d1353d2 100644 (file)
@@ -160,7 +160,6 @@ static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
        }
 
        /* cpuinfo and default policy values */
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
        policy->cur = busfreq * max_multiplier;
 
index ca3e1d341889dfc00964fd2d052e13d9108d8562..7decd6a50ffa6f44a83e36dfe443522a923ad15b 100644 (file)
@@ -637,8 +637,6 @@ static int __init powernow_cpu_init (struct cpufreq_policy *policy)
        printk (KERN_INFO PFX "Minimum speed %d MHz. Maximum speed %d MHz.\n",
                                minimum_speed/1000, maximum_speed/1000);
 
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
-
        policy->cpuinfo.transition_latency = cpufreq_scale(2000000UL, fsb, latency);
 
        policy->cur = powernow_get(0);
index 34ed53a067307d78166019961f5e431c26f83c1f..b273b69cfddf0532d18b4db6646fafd077cdc31e 100644 (file)
@@ -76,7 +76,10 @@ static u32 find_khz_freq_from_fid(u32 fid)
 /* Return a frequency in MHz, given an input fid and did */
 static u32 find_freq_from_fiddid(u32 fid, u32 did)
 {
-       return 100 * (fid + 0x10) >> did;
+       if (current_cpu_data.x86 == 0x10)
+               return 100 * (fid + 0x10) >> did;
+       else
+               return 100 * (fid + 0x8) >> did;
 }
 
 static u32 find_khz_freq_from_fiddid(u32 fid, u32 did)
@@ -1208,7 +1211,6 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
        /* run on any CPU again */
        set_cpus_allowed(current, oldmask);
 
-       pol->governor = CPUFREQ_DEFAULT_GOVERNOR;
        if (cpu_family == CPU_HW_PSTATE)
                pol->cpus = cpumask_of_cpu(pol->cpu);
        else
@@ -1325,21 +1327,16 @@ static struct cpufreq_driver cpufreq_amd64_driver = {
 static int __cpuinit powernowk8_init(void)
 {
        unsigned int i, supported_cpus = 0;
-       unsigned int booted_cores = 1;
 
        for_each_online_cpu(i) {
                if (check_supported_cpu(i))
                        supported_cpus++;
        }
 
-#ifdef CONFIG_SMP
-       booted_cores = cpu_data[0].booted_cores;
-#endif
-
        if (supported_cpus == num_online_cpus()) {
                printk(KERN_INFO PFX "Found %d %s "
                        "processors (%d cpu cores) (" VERSION ")\n",
-                       supported_cpus/booted_cores,
+                       num_online_nodes(),
                        boot_cpu_data.x86_model_id, supported_cpus);
                return cpufreq_register_driver(&cpufreq_amd64_driver);
        }
index b8fb4b521c62806a2ec8e3134a281590e0dc8b7a..d9f3e90a7ae080c9ba1e316c56ccb3afe6022231 100644 (file)
@@ -111,7 +111,6 @@ static int sc520_freq_cpu_init(struct cpufreq_policy *policy)
                return -ENODEV;
 
        /* cpuinfo and default policy values */
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cpuinfo.transition_latency = 1000000; /* 1ms */
        policy->cur = sc520_freq_get_cpu_frequency(0);
 
index 6c5dc2c85aeb99241ef85fac0cd20bfcc1e522a2..811d47438546974e41651794cecf380a26e53c33 100644 (file)
@@ -393,7 +393,6 @@ static int centrino_cpu_init(struct cpufreq_policy *policy)
 
        freq = get_cur_freq(policy->cpu);
 
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cpuinfo.transition_latency = 10000; /* 10uS transition latency */
        policy->cur = freq;
 
index a5b2346faf1fd2bba8d01bcbedb2253f4d3529cb..36685e8f7be1171cf260d75646be0dff7f00a472 100644 (file)
@@ -348,7 +348,6 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
                (speed / 1000));
 
        /* cpuinfo and default policy values */
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cur = speed;
 
        result = cpufreq_frequency_table_cpuinfo(policy, speedstep_freqs);
index e1c509aa3054ef5dc7f453c3f665b5dcf1cdfa8e..f2b5a621d27b39e4ece42418719655406b220e17 100644 (file)
@@ -290,7 +290,6 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
                (speed / 1000));
 
        /* cpuinfo and default policy values */
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
        policy->cur = speed;
 
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 41e8aec4c61d4c940d1d0e9258109733ed3c35a2..f12d8c5d98093b2abbe5231cb7304455622d027d 100644 (file)
@@ -145,10 +145,14 @@ EXPORT_SYMBOL_GPL(geode_gpio_setup_event);
 
 static int __init geode_southbridge_init(void)
 {
+       int timers;
+
        if (!is_geode())
                return -ENODEV;
 
        init_lbars();
+       timers = geode_mfgpt_detect();
+       printk(KERN_INFO "geode:  %d MFGPT timers available.\n", timers);
        return 0;
 }
 
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
  */
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c
new file mode 100644 (file)
index 0000000..f836707
--- /dev/null
@@ -0,0 +1,655 @@
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/hpet.h>
+#include <linux/init.h>
+#include <linux/sysdev.h>
+#include <linux/pm.h>
+#include <linux/delay.h>
+
+#include <asm/fixmap.h>
+#include <asm/hpet.h>
+#include <asm/i8253.h>
+#include <asm/io.h>
+
+#define HPET_MASK      CLOCKSOURCE_MASK(32)
+#define HPET_SHIFT     22
+
+/* FSEC = 10^-15 NSEC = 10^-9 */
+#define FSEC_PER_NSEC  1000000
+
+/*
+ * HPET address is set in acpi/boot.c, when an ACPI entry exists
+ */
+unsigned long hpet_address;
+static void __iomem *hpet_virt_address;
+
+unsigned long hpet_readl(unsigned long a)
+{
+       return readl(hpet_virt_address + a);
+}
+
+static inline void hpet_writel(unsigned long d, unsigned long a)
+{
+       writel(d, hpet_virt_address + a);
+}
+
+#ifdef CONFIG_X86_64
+
+#include <asm/pgtable.h>
+
+static inline void hpet_set_mapping(void)
+{
+       set_fixmap_nocache(FIX_HPET_BASE, hpet_address);
+       __set_fixmap(VSYSCALL_HPET, hpet_address, PAGE_KERNEL_VSYSCALL_NOCACHE);
+       hpet_virt_address = (void __iomem *)fix_to_virt(FIX_HPET_BASE);
+}
+
+static inline void hpet_clear_mapping(void)
+{
+       hpet_virt_address = NULL;
+}
+
+#else
+
+static inline void hpet_set_mapping(void)
+{
+       hpet_virt_address = ioremap_nocache(hpet_address, HPET_MMAP_SIZE);
+}
+
+static inline void hpet_clear_mapping(void)
+{
+       iounmap(hpet_virt_address);
+       hpet_virt_address = NULL;
+}
+#endif
+
+/*
+ * HPET command line enable / disable
+ */
+static int boot_hpet_disable;
+
+static int __init hpet_setup(char* str)
+{
+       if (str) {
+               if (!strncmp("disable", str, 7))
+                       boot_hpet_disable = 1;
+       }
+       return 1;
+}
+__setup("hpet=", hpet_setup);
+
+static int __init disable_hpet(char *str)
+{
+       boot_hpet_disable = 1;
+       return 1;
+}
+__setup("nohpet", disable_hpet);
+
+static inline int is_hpet_capable(void)
+{
+       return (!boot_hpet_disable && hpet_address);
+}
+
+/*
+ * HPET timer interrupt enable / disable
+ */
+static int hpet_legacy_int_enabled;
+
+/**
+ * is_hpet_enabled - check whether the hpet timer interrupt is enabled
+ */
+int is_hpet_enabled(void)
+{
+       return is_hpet_capable() && hpet_legacy_int_enabled;
+}
+
+/*
+ * When the hpet driver (/dev/hpet) is enabled, we need to reserve
+ * timer 0 and timer 1 in case of RTC emulation.
+ */
+#ifdef CONFIG_HPET
+static void hpet_reserve_platform_timers(unsigned long id)
+{
+       struct hpet __iomem *hpet = hpet_virt_address;
+       struct hpet_timer __iomem *timer = &hpet->hpet_timers[2];
+       unsigned int nrtimers, i;
+       struct hpet_data hd;
+
+       nrtimers = ((id & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT) + 1;
+
+       memset(&hd, 0, sizeof (hd));
+       hd.hd_phys_address = hpet_address;
+       hd.hd_address = hpet;
+       hd.hd_nirqs = nrtimers;
+       hd.hd_flags = HPET_DATA_PLATFORM;
+       hpet_reserve_timer(&hd, 0);
+
+#ifdef CONFIG_HPET_EMULATE_RTC
+       hpet_reserve_timer(&hd, 1);
+#endif
+
+       hd.hd_irq[0] = HPET_LEGACY_8254;
+       hd.hd_irq[1] = HPET_LEGACY_RTC;
+
+       for (i = 2; i < nrtimers; timer++, i++)
+               hd.hd_irq[i] = (timer->hpet_config & Tn_INT_ROUTE_CNF_MASK) >>
+                       Tn_INT_ROUTE_CNF_SHIFT;
+
+       hpet_alloc(&hd);
+
+}
+#else
+static void hpet_reserve_platform_timers(unsigned long id) { }
+#endif
+
+/*
+ * Common hpet info
+ */
+static unsigned long hpet_period;
+
+static void hpet_legacy_set_mode(enum clock_event_mode mode,
+                         struct clock_event_device *evt);
+static int hpet_legacy_next_event(unsigned long delta,
+                          struct clock_event_device *evt);
+
+/*
+ * The hpet clock event device
+ */
+static struct clock_event_device hpet_clockevent = {
+       .name           = "hpet",
+       .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+       .set_mode       = hpet_legacy_set_mode,
+       .set_next_event = hpet_legacy_next_event,
+       .shift          = 32,
+       .irq            = 0,
+       .rating         = 50,
+};
+
+static void hpet_start_counter(void)
+{
+       unsigned long cfg = hpet_readl(HPET_CFG);
+
+       cfg &= ~HPET_CFG_ENABLE;
+       hpet_writel(cfg, HPET_CFG);
+       hpet_writel(0, HPET_COUNTER);
+       hpet_writel(0, HPET_COUNTER + 4);
+       cfg |= HPET_CFG_ENABLE;
+       hpet_writel(cfg, HPET_CFG);
+}
+
+static void hpet_resume_device(void)
+{
+       force_hpet_resume();
+}
+
+static void hpet_restart_counter(void)
+{
+       hpet_resume_device();
+       hpet_start_counter();
+}
+
+static void hpet_enable_legacy_int(void)
+{
+       unsigned long cfg = hpet_readl(HPET_CFG);
+
+       cfg |= HPET_CFG_LEGACY;
+       hpet_writel(cfg, HPET_CFG);
+       hpet_legacy_int_enabled = 1;
+}
+
+static void hpet_legacy_clockevent_register(void)
+{
+       uint64_t hpet_freq;
+
+       /* Start HPET legacy interrupts */
+       hpet_enable_legacy_int();
+
+       /*
+        * The period is a femto seconds value. We need to calculate the
+        * scaled math multiplication factor for nanosecond to hpet tick
+        * conversion.
+        */
+       hpet_freq = 1000000000000000ULL;
+       do_div(hpet_freq, hpet_period);
+       hpet_clockevent.mult = div_sc((unsigned long) hpet_freq,
+                                     NSEC_PER_SEC, 32);
+       /* Calculate the min / max delta */
+       hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF,
+                                                          &hpet_clockevent);
+       hpet_clockevent.min_delta_ns = clockevent_delta2ns(0x30,
+                                                          &hpet_clockevent);
+
+       /*
+        * Start hpet with the boot cpu mask and make it
+        * global after the IO_APIC has been initialized.
+        */
+       hpet_clockevent.cpumask = cpumask_of_cpu(smp_processor_id());
+       clockevents_register_device(&hpet_clockevent);
+       global_clock_event = &hpet_clockevent;
+       printk(KERN_DEBUG "hpet clockevent registered\n");
+}
+
+static void hpet_legacy_set_mode(enum clock_event_mode mode,
+                         struct clock_event_device *evt)
+{
+       unsigned long cfg, cmp, now;
+       uint64_t delta;
+
+       switch(mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+               delta = ((uint64_t)(NSEC_PER_SEC/HZ)) * hpet_clockevent.mult;
+               delta >>= hpet_clockevent.shift;
+               now = hpet_readl(HPET_COUNTER);
+               cmp = now + (unsigned long) delta;
+               cfg = hpet_readl(HPET_T0_CFG);
+               cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC |
+                      HPET_TN_SETVAL | HPET_TN_32BIT;
+               hpet_writel(cfg, HPET_T0_CFG);
+               /*
+                * The first write after writing TN_SETVAL to the
+                * config register sets the counter value, the second
+                * write sets the period.
+                */
+               hpet_writel(cmp, HPET_T0_CMP);
+               udelay(1);
+               hpet_writel((unsigned long) delta, HPET_T0_CMP);
+               break;
+
+       case CLOCK_EVT_MODE_ONESHOT:
+               cfg = hpet_readl(HPET_T0_CFG);
+               cfg &= ~HPET_TN_PERIODIC;
+               cfg |= HPET_TN_ENABLE | HPET_TN_32BIT;
+               hpet_writel(cfg, HPET_T0_CFG);
+               break;
+
+       case CLOCK_EVT_MODE_UNUSED:
+       case CLOCK_EVT_MODE_SHUTDOWN:
+               cfg = hpet_readl(HPET_T0_CFG);
+               cfg &= ~HPET_TN_ENABLE;
+               hpet_writel(cfg, HPET_T0_CFG);
+               break;
+
+       case CLOCK_EVT_MODE_RESUME:
+               hpet_enable_legacy_int();
+               break;
+       }
+}
+
+static int hpet_legacy_next_event(unsigned long delta,
+                          struct clock_event_device *evt)
+{
+       unsigned long cnt;
+
+       cnt = hpet_readl(HPET_COUNTER);
+       cnt += delta;
+       hpet_writel(cnt, HPET_T0_CMP);
+
+       return ((long)(hpet_readl(HPET_COUNTER) - cnt ) > 0) ? -ETIME : 0;
+}
+
+/*
+ * Clock source related code
+ */
+static cycle_t read_hpet(void)
+{
+       return (cycle_t)hpet_readl(HPET_COUNTER);
+}
+
+#ifdef CONFIG_X86_64
+static cycle_t __vsyscall_fn vread_hpet(void)
+{
+       return readl((const void __iomem *)fix_to_virt(VSYSCALL_HPET) + 0xf0);
+}
+#endif
+
+static struct clocksource clocksource_hpet = {
+       .name           = "hpet",
+       .rating         = 250,
+       .read           = read_hpet,
+       .mask           = HPET_MASK,
+       .shift          = HPET_SHIFT,
+       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+       .resume         = hpet_restart_counter,
+#ifdef CONFIG_X86_64
+       .vread          = vread_hpet,
+#endif
+};
+
+static int hpet_clocksource_register(void)
+{
+       u64 tmp, start, now;
+       cycle_t t1;
+
+       /* Start the counter */
+       hpet_start_counter();
+
+       /* Verify whether hpet counter works */
+       t1 = read_hpet();
+       rdtscll(start);
+
+       /*
+        * We don't know the TSC frequency yet, but waiting for
+        * 200000 TSC cycles is safe:
+        * 4 GHz == 50us
+        * 1 GHz == 200us
+        */
+       do {
+               rep_nop();
+               rdtscll(now);
+       } while ((now - start) < 200000UL);
+
+       if (t1 == read_hpet()) {
+               printk(KERN_WARNING
+                      "HPET counter not counting. HPET disabled\n");
+               return -ENODEV;
+       }
+
+       /* Initialize and register HPET clocksource
+        *
+        * hpet period is in femto seconds per cycle
+        * so we need to convert this to ns/cyc units
+        * aproximated by mult/2^shift
+        *
+        *  fsec/cyc * 1nsec/1000000fsec = nsec/cyc = mult/2^shift
+        *  fsec/cyc * 1ns/1000000fsec * 2^shift = mult
+        *  fsec/cyc * 2^shift * 1nsec/1000000fsec = mult
+        *  (fsec/cyc << shift)/1000000 = mult
+        *  (hpet_period << shift)/FSEC_PER_NSEC = mult
+        */
+       tmp = (u64)hpet_period << HPET_SHIFT;
+       do_div(tmp, FSEC_PER_NSEC);
+       clocksource_hpet.mult = (u32)tmp;
+
+       clocksource_register(&clocksource_hpet);
+
+       return 0;
+}
+
+/*
+ * Try to setup the HPET timer
+ */
+int __init hpet_enable(void)
+{
+       unsigned long id;
+
+       if (!is_hpet_capable())
+               return 0;
+
+       hpet_set_mapping();
+
+       /*
+        * Read the period and check for a sane value:
+        */
+       hpet_period = hpet_readl(HPET_PERIOD);
+       if (hpet_period < HPET_MIN_PERIOD || hpet_period > HPET_MAX_PERIOD)
+               goto out_nohpet;
+
+       /*
+        * Read the HPET ID register to retrieve the IRQ routing
+        * information and the number of channels
+        */
+       id = hpet_readl(HPET_ID);
+
+#ifdef CONFIG_HPET_EMULATE_RTC
+       /*
+        * The legacy routing mode needs at least two channels, tick timer
+        * and the rtc emulation channel.
+        */
+       if (!(id & HPET_ID_NUMBER))
+               goto out_nohpet;
+#endif
+
+       if (hpet_clocksource_register())
+               goto out_nohpet;
+
+       if (id & HPET_ID_LEGSUP) {
+               hpet_legacy_clockevent_register();
+               return 1;
+       }
+       return 0;
+
+out_nohpet:
+       hpet_clear_mapping();
+       boot_hpet_disable = 1;
+       return 0;
+}
+
+/*
+ * Needs to be late, as the reserve_timer code calls kalloc !
+ *
+ * Not a problem on i386 as hpet_enable is called from late_time_init,
+ * but on x86_64 it is necessary !
+ */
+static __init int hpet_late_init(void)
+{
+       if (boot_hpet_disable)
+               return -ENODEV;
+
+       if (!hpet_address) {
+               if (!force_hpet_address)
+                       return -ENODEV;
+
+               hpet_address = force_hpet_address;
+               hpet_enable();
+               if (!hpet_virt_address)
+                       return -ENODEV;
+       }
+
+       hpet_reserve_platform_timers(hpet_readl(HPET_ID));
+
+       return 0;
+}
+fs_initcall(hpet_late_init);
+
+#ifdef CONFIG_HPET_EMULATE_RTC
+
+/* HPET in LegacyReplacement Mode eats up RTC interrupt line. When, HPET
+ * is enabled, we support RTC interrupt functionality in software.
+ * RTC has 3 kinds of interrupts:
+ * 1) Update Interrupt - generate an interrupt, every sec, when RTC clock
+ *    is updated
+ * 2) Alarm Interrupt - generate an interrupt at a specific time of day
+ * 3) Periodic Interrupt - generate periodic interrupt, with frequencies
+ *    2Hz-8192Hz (2Hz-64Hz for non-root user) (all freqs in powers of 2)
+ * (1) and (2) above are implemented using polling at a frequency of
+ * 64 Hz. The exact frequency is a tradeoff between accuracy and interrupt
+ * overhead. (DEFAULT_RTC_INT_FREQ)
+ * For (3), we use interrupts at 64Hz or user specified periodic
+ * frequency, whichever is higher.
+ */
+#include <linux/mc146818rtc.h>
+#include <linux/rtc.h>
+
+#define DEFAULT_RTC_INT_FREQ   64
+#define DEFAULT_RTC_SHIFT      6
+#define RTC_NUM_INTS           1
+
+static unsigned long hpet_rtc_flags;
+static unsigned long hpet_prev_update_sec;
+static struct rtc_time hpet_alarm_time;
+static unsigned long hpet_pie_count;
+static unsigned long hpet_t1_cmp;
+static unsigned long hpet_default_delta;
+static unsigned long hpet_pie_delta;
+static unsigned long hpet_pie_limit;
+
+/*
+ * Timer 1 for RTC emulation. We use one shot mode, as periodic mode
+ * is not supported by all HPET implementations for timer 1.
+ *
+ * hpet_rtc_timer_init() is called when the rtc is initialized.
+ */
+int hpet_rtc_timer_init(void)
+{
+       unsigned long cfg, cnt, delta, flags;
+
+       if (!is_hpet_enabled())
+               return 0;
+
+       if (!hpet_default_delta) {
+               uint64_t clc;
+
+               clc = (uint64_t) hpet_clockevent.mult * NSEC_PER_SEC;
+               clc >>= hpet_clockevent.shift + DEFAULT_RTC_SHIFT;
+               hpet_default_delta = (unsigned long) clc;
+       }
+
+       if (!(hpet_rtc_flags & RTC_PIE) || hpet_pie_limit)
+               delta = hpet_default_delta;
+       else
+               delta = hpet_pie_delta;
+
+       local_irq_save(flags);
+
+       cnt = delta + hpet_readl(HPET_COUNTER);
+       hpet_writel(cnt, HPET_T1_CMP);
+       hpet_t1_cmp = cnt;
+
+       cfg = hpet_readl(HPET_T1_CFG);
+       cfg &= ~HPET_TN_PERIODIC;
+       cfg |= HPET_TN_ENABLE | HPET_TN_32BIT;
+       hpet_writel(cfg, HPET_T1_CFG);
+
+       local_irq_restore(flags);
+
+       return 1;
+}
+
+/*
+ * The functions below are called from rtc driver.
+ * Return 0 if HPET is not being used.
+ * Otherwise do the necessary changes and return 1.
+ */
+int hpet_mask_rtc_irq_bit(unsigned long bit_mask)
+{
+       if (!is_hpet_enabled())
+               return 0;
+
+       hpet_rtc_flags &= ~bit_mask;
+       return 1;
+}
+
+int hpet_set_rtc_irq_bit(unsigned long bit_mask)
+{
+       unsigned long oldbits = hpet_rtc_flags;
+
+       if (!is_hpet_enabled())
+               return 0;
+
+       hpet_rtc_flags |= bit_mask;
+
+       if (!oldbits)
+               hpet_rtc_timer_init();
+
+       return 1;
+}
+
+int hpet_set_alarm_time(unsigned char hrs, unsigned char min,
+                       unsigned char sec)
+{
+       if (!is_hpet_enabled())
+               return 0;
+
+       hpet_alarm_time.tm_hour = hrs;
+       hpet_alarm_time.tm_min = min;
+       hpet_alarm_time.tm_sec = sec;
+
+       return 1;
+}
+
+int hpet_set_periodic_freq(unsigned long freq)
+{
+       uint64_t clc;
+
+       if (!is_hpet_enabled())
+               return 0;
+
+       if (freq <= DEFAULT_RTC_INT_FREQ)
+               hpet_pie_limit = DEFAULT_RTC_INT_FREQ / freq;
+       else {
+               clc = (uint64_t) hpet_clockevent.mult * NSEC_PER_SEC;
+               do_div(clc, freq);
+               clc >>= hpet_clockevent.shift;
+               hpet_pie_delta = (unsigned long) clc;
+       }
+       return 1;
+}
+
+int hpet_rtc_dropped_irq(void)
+{
+       return is_hpet_enabled();
+}
+
+static void hpet_rtc_timer_reinit(void)
+{
+       unsigned long cfg, delta;
+       int lost_ints = -1;
+
+       if (unlikely(!hpet_rtc_flags)) {
+               cfg = hpet_readl(HPET_T1_CFG);
+               cfg &= ~HPET_TN_ENABLE;
+               hpet_writel(cfg, HPET_T1_CFG);
+               return;
+       }
+
+       if (!(hpet_rtc_flags & RTC_PIE) || hpet_pie_limit)
+               delta = hpet_default_delta;
+       else
+               delta = hpet_pie_delta;
+
+       /*
+        * Increment the comparator value until we are ahead of the
+        * current count.
+        */
+       do {
+               hpet_t1_cmp += delta;
+               hpet_writel(hpet_t1_cmp, HPET_T1_CMP);
+               lost_ints++;
+       } while ((long)(hpet_readl(HPET_COUNTER) - hpet_t1_cmp) > 0);
+
+       if (lost_ints) {
+               if (hpet_rtc_flags & RTC_PIE)
+                       hpet_pie_count += lost_ints;
+               if (printk_ratelimit())
+                       printk(KERN_WARNING "rtc: lost %d interrupts\n",
+                               lost_ints);
+       }
+}
+
+irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id)
+{
+       struct rtc_time curr_time;
+       unsigned long rtc_int_flag = 0;
+
+       hpet_rtc_timer_reinit();
+
+       if (hpet_rtc_flags & (RTC_UIE | RTC_AIE))
+               rtc_get_rtc_time(&curr_time);
+
+       if (hpet_rtc_flags & RTC_UIE &&
+           curr_time.tm_sec != hpet_prev_update_sec) {
+               rtc_int_flag = RTC_UF;
+               hpet_prev_update_sec = curr_time.tm_sec;
+       }
+
+       if (hpet_rtc_flags & RTC_PIE &&
+           ++hpet_pie_count >= hpet_pie_limit) {
+               rtc_int_flag |= RTC_PF;
+               hpet_pie_count = 0;
+       }
+
+       if (hpet_rtc_flags & RTC_PIE &&
+           (curr_time.tm_sec == hpet_alarm_time.tm_sec) &&
+           (curr_time.tm_min == hpet_alarm_time.tm_min) &&
+           (curr_time.tm_hour == hpet_alarm_time.tm_hour))
+                       rtc_int_flag |= RTC_AF;
+
+       if (rtc_int_flag) {
+               rtc_int_flag |= (RTC_IRQF | (RTC_NUM_INTS << 8));
+               rtc_interrupt(rtc_int_flag, dev_id);
+       }
+       return IRQ_HANDLED;
+}
+#endif
diff --git a/arch/x86/kernel/hpet_32.c b/arch/x86/kernel/hpet_32.c
deleted file mode 100644 (file)
index 533d493..0000000
+++ /dev/null
@@ -1,553 +0,0 @@
-#include <linux/clocksource.h>
-#include <linux/clockchips.h>
-#include <linux/errno.h>
-#include <linux/hpet.h>
-#include <linux/init.h>
-#include <linux/sysdev.h>
-#include <linux/pm.h>
-#include <linux/delay.h>
-
-#include <asm/hpet.h>
-#include <asm/io.h>
-
-extern struct clock_event_device *global_clock_event;
-
-#define HPET_MASK      CLOCKSOURCE_MASK(32)
-#define HPET_SHIFT     22
-
-/* FSEC = 10^-15 NSEC = 10^-9 */
-#define FSEC_PER_NSEC  1000000
-
-/*
- * HPET address is set in acpi/boot.c, when an ACPI entry exists
- */
-unsigned long hpet_address;
-static void __iomem * hpet_virt_address;
-
-static inline unsigned long hpet_readl(unsigned long a)
-{
-       return readl(hpet_virt_address + a);
-}
-
-static inline void hpet_writel(unsigned long d, unsigned long a)
-{
-       writel(d, hpet_virt_address + a);
-}
-
-/*
- * HPET command line enable / disable
- */
-static int boot_hpet_disable;
-
-static int __init hpet_setup(char* str)
-{
-       if (str) {
-               if (!strncmp("disable", str, 7))
-                       boot_hpet_disable = 1;
-       }
-       return 1;
-}
-__setup("hpet=", hpet_setup);
-
-static inline int is_hpet_capable(void)
-{
-       return (!boot_hpet_disable && hpet_address);
-}
-
-/*
- * HPET timer interrupt enable / disable
- */
-static int hpet_legacy_int_enabled;
-
-/**
- * is_hpet_enabled - check whether the hpet timer interrupt is enabled
- */
-int is_hpet_enabled(void)
-{
-       return is_hpet_capable() && hpet_legacy_int_enabled;
-}
-
-/*
- * When the hpet driver (/dev/hpet) is enabled, we need to reserve
- * timer 0 and timer 1 in case of RTC emulation.
- */
-#ifdef CONFIG_HPET
-static void hpet_reserve_platform_timers(unsigned long id)
-{
-       struct hpet __iomem *hpet = hpet_virt_address;
-       struct hpet_timer __iomem *timer = &hpet->hpet_timers[2];
-       unsigned int nrtimers, i;
-       struct hpet_data hd;
-
-       nrtimers = ((id & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT) + 1;
-
-       memset(&hd, 0, sizeof (hd));
-       hd.hd_phys_address = hpet_address;
-       hd.hd_address = hpet_virt_address;
-       hd.hd_nirqs = nrtimers;
-       hd.hd_flags = HPET_DATA_PLATFORM;
-       hpet_reserve_timer(&hd, 0);
-
-#ifdef CONFIG_HPET_EMULATE_RTC
-       hpet_reserve_timer(&hd, 1);
-#endif
-
-       hd.hd_irq[0] = HPET_LEGACY_8254;
-       hd.hd_irq[1] = HPET_LEGACY_RTC;
-
-       for (i = 2; i < nrtimers; timer++, i++)
-               hd.hd_irq[i] = (timer->hpet_config & Tn_INT_ROUTE_CNF_MASK) >>
-                       Tn_INT_ROUTE_CNF_SHIFT;
-
-       hpet_alloc(&hd);
-
-}
-#else
-static void hpet_reserve_platform_timers(unsigned long id) { }
-#endif
-
-/*
- * Common hpet info
- */
-static unsigned long hpet_period;
-
-static void hpet_set_mode(enum clock_event_mode mode,
-                         struct clock_event_device *evt);
-static int hpet_next_event(unsigned long delta,
-                          struct clock_event_device *evt);
-
-/*
- * The hpet clock event device
- */
-static struct clock_event_device hpet_clockevent = {
-       .name           = "hpet",
-       .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
-       .set_mode       = hpet_set_mode,
-       .set_next_event = hpet_next_event,
-       .shift          = 32,
-       .irq            = 0,
-};
-
-static void hpet_start_counter(void)
-{
-       unsigned long cfg = hpet_readl(HPET_CFG);
-
-       cfg &= ~HPET_CFG_ENABLE;
-       hpet_writel(cfg, HPET_CFG);
-       hpet_writel(0, HPET_COUNTER);
-       hpet_writel(0, HPET_COUNTER + 4);
-       cfg |= HPET_CFG_ENABLE;
-       hpet_writel(cfg, HPET_CFG);
-}
-
-static void hpet_enable_int(void)
-{
-       unsigned long cfg = hpet_readl(HPET_CFG);
-
-       cfg |= HPET_CFG_LEGACY;
-       hpet_writel(cfg, HPET_CFG);
-       hpet_legacy_int_enabled = 1;
-}
-
-static void hpet_set_mode(enum clock_event_mode mode,
-                         struct clock_event_device *evt)
-{
-       unsigned long cfg, cmp, now;
-       uint64_t delta;
-
-       switch(mode) {
-       case CLOCK_EVT_MODE_PERIODIC:
-               delta = ((uint64_t)(NSEC_PER_SEC/HZ)) * hpet_clockevent.mult;
-               delta >>= hpet_clockevent.shift;
-               now = hpet_readl(HPET_COUNTER);
-               cmp = now + (unsigned long) delta;
-               cfg = hpet_readl(HPET_T0_CFG);
-               cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC |
-                      HPET_TN_SETVAL | HPET_TN_32BIT;
-               hpet_writel(cfg, HPET_T0_CFG);
-               /*
-                * The first write after writing TN_SETVAL to the
-                * config register sets the counter value, the second
-                * write sets the period.
-                */
-               hpet_writel(cmp, HPET_T0_CMP);
-               udelay(1);
-               hpet_writel((unsigned long) delta, HPET_T0_CMP);
-               break;
-
-       case CLOCK_EVT_MODE_ONESHOT:
-               cfg = hpet_readl(HPET_T0_CFG);
-               cfg &= ~HPET_TN_PERIODIC;
-               cfg |= HPET_TN_ENABLE | HPET_TN_32BIT;
-               hpet_writel(cfg, HPET_T0_CFG);
-               break;
-
-       case CLOCK_EVT_MODE_UNUSED:
-       case CLOCK_EVT_MODE_SHUTDOWN:
-               cfg = hpet_readl(HPET_T0_CFG);
-               cfg &= ~HPET_TN_ENABLE;
-               hpet_writel(cfg, HPET_T0_CFG);
-               break;
-
-       case CLOCK_EVT_MODE_RESUME:
-               hpet_enable_int();
-               break;
-       }
-}
-
-static int hpet_next_event(unsigned long delta,
-                          struct clock_event_device *evt)
-{
-       unsigned long cnt;
-
-       cnt = hpet_readl(HPET_COUNTER);
-       cnt += delta;
-       hpet_writel(cnt, HPET_T0_CMP);
-
-       return ((long)(hpet_readl(HPET_COUNTER) - cnt ) > 0) ? -ETIME : 0;
-}
-
-/*
- * Clock source related code
- */
-static cycle_t read_hpet(void)
-{
-       return (cycle_t)hpet_readl(HPET_COUNTER);
-}
-
-static struct clocksource clocksource_hpet = {
-       .name           = "hpet",
-       .rating         = 250,
-       .read           = read_hpet,
-       .mask           = HPET_MASK,
-       .shift          = HPET_SHIFT,
-       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
-       .resume         = hpet_start_counter,
-};
-
-/*
- * Try to setup the HPET timer
- */
-int __init hpet_enable(void)
-{
-       unsigned long id;
-       uint64_t hpet_freq;
-       u64 tmp, start, now;
-       cycle_t t1;
-
-       if (!is_hpet_capable())
-               return 0;
-
-       hpet_virt_address = ioremap_nocache(hpet_address, HPET_MMAP_SIZE);
-
-       /*
-        * Read the period and check for a sane value:
-        */
-       hpet_period = hpet_readl(HPET_PERIOD);
-       if (hpet_period < HPET_MIN_PERIOD || hpet_period > HPET_MAX_PERIOD)
-               goto out_nohpet;
-
-       /*
-        * The period is a femto seconds value. We need to calculate the
-        * scaled math multiplication factor for nanosecond to hpet tick
-        * conversion.
-        */
-       hpet_freq = 1000000000000000ULL;
-       do_div(hpet_freq, hpet_period);
-       hpet_clockevent.mult = div_sc((unsigned long) hpet_freq,
-                                     NSEC_PER_SEC, 32);
-       /* Calculate the min / max delta */
-       hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF,
-                                                          &hpet_clockevent);
-       hpet_clockevent.min_delta_ns = clockevent_delta2ns(0x30,
-                                                          &hpet_clockevent);
-
-       /*
-        * Read the HPET ID register to retrieve the IRQ routing
-        * information and the number of channels
-        */
-       id = hpet_readl(HPET_ID);
-
-#ifdef CONFIG_HPET_EMULATE_RTC
-       /*
-        * The legacy routing mode needs at least two channels, tick timer
-        * and the rtc emulation channel.
-        */
-       if (!(id & HPET_ID_NUMBER))
-               goto out_nohpet;
-#endif
-
-       /* Start the counter */
-       hpet_start_counter();
-
-       /* Verify whether hpet counter works */
-       t1 = read_hpet();
-       rdtscll(start);
-
-       /*
-        * We don't know the TSC frequency yet, but waiting for
-        * 200000 TSC cycles is safe:
-        * 4 GHz == 50us
-        * 1 GHz == 200us
-        */
-       do {
-               rep_nop();
-               rdtscll(now);
-       } while ((now - start) < 200000UL);
-
-       if (t1 == read_hpet()) {
-               printk(KERN_WARNING
-                      "HPET counter not counting. HPET disabled\n");
-               goto out_nohpet;
-       }
-
-       /* Initialize and register HPET clocksource
-        *
-        * hpet period is in femto seconds per cycle
-        * so we need to convert this to ns/cyc units
-        * aproximated by mult/2^shift
-        *
-        *  fsec/cyc * 1nsec/1000000fsec = nsec/cyc = mult/2^shift
-        *  fsec/cyc * 1ns/1000000fsec * 2^shift = mult
-        *  fsec/cyc * 2^shift * 1nsec/1000000fsec = mult
-        *  (fsec/cyc << shift)/1000000 = mult
-        *  (hpet_period << shift)/FSEC_PER_NSEC = mult
-        */
-       tmp = (u64)hpet_period << HPET_SHIFT;
-       do_div(tmp, FSEC_PER_NSEC);
-       clocksource_hpet.mult = (u32)tmp;
-
-       clocksource_register(&clocksource_hpet);
-
-       if (id & HPET_ID_LEGSUP) {
-               hpet_enable_int();
-               hpet_reserve_platform_timers(id);
-               /*
-                * Start hpet with the boot cpu mask and make it
-                * global after the IO_APIC has been initialized.
-                */
-               hpet_clockevent.cpumask = cpumask_of_cpu(smp_processor_id());
-               clockevents_register_device(&hpet_clockevent);
-               global_clock_event = &hpet_clockevent;
-               return 1;
-       }
-       return 0;
-
-out_nohpet:
-       iounmap(hpet_virt_address);
-       hpet_virt_address = NULL;
-       boot_hpet_disable = 1;
-       return 0;
-}
-
-
-#ifdef CONFIG_HPET_EMULATE_RTC
-
-/* HPET in LegacyReplacement Mode eats up RTC interrupt line. When, HPET
- * is enabled, we support RTC interrupt functionality in software.
- * RTC has 3 kinds of interrupts:
- * 1) Update Interrupt - generate an interrupt, every sec, when RTC clock
- *    is updated
- * 2) Alarm Interrupt - generate an interrupt at a specific time of day
- * 3) Periodic Interrupt - generate periodic interrupt, with frequencies
- *    2Hz-8192Hz (2Hz-64Hz for non-root user) (all freqs in powers of 2)
- * (1) and (2) above are implemented using polling at a frequency of
- * 64 Hz. The exact frequency is a tradeoff between accuracy and interrupt
- * overhead. (DEFAULT_RTC_INT_FREQ)
- * For (3), we use interrupts at 64Hz or user specified periodic
- * frequency, whichever is higher.
- */
-#include <linux/mc146818rtc.h>
-#include <linux/rtc.h>
-
-#define DEFAULT_RTC_INT_FREQ   64
-#define DEFAULT_RTC_SHIFT      6
-#define RTC_NUM_INTS           1
-
-static unsigned long hpet_rtc_flags;
-static unsigned long hpet_prev_update_sec;
-static struct rtc_time hpet_alarm_time;
-static unsigned long hpet_pie_count;
-static unsigned long hpet_t1_cmp;
-static unsigned long hpet_default_delta;
-static unsigned long hpet_pie_delta;
-static unsigned long hpet_pie_limit;
-
-/*
- * Timer 1 for RTC emulation. We use one shot mode, as periodic mode
- * is not supported by all HPET implementations for timer 1.
- *
- * hpet_rtc_timer_init() is called when the rtc is initialized.
- */
-int hpet_rtc_timer_init(void)
-{
-       unsigned long cfg, cnt, delta, flags;
-
-       if (!is_hpet_enabled())
-               return 0;
-
-       if (!hpet_default_delta) {
-               uint64_t clc;
-
-               clc = (uint64_t) hpet_clockevent.mult * NSEC_PER_SEC;
-               clc >>= hpet_clockevent.shift + DEFAULT_RTC_SHIFT;
-               hpet_default_delta = (unsigned long) clc;
-       }
-
-       if (!(hpet_rtc_flags & RTC_PIE) || hpet_pie_limit)
-               delta = hpet_default_delta;
-       else
-               delta = hpet_pie_delta;
-
-       local_irq_save(flags);
-
-       cnt = delta + hpet_readl(HPET_COUNTER);
-       hpet_writel(cnt, HPET_T1_CMP);
-       hpet_t1_cmp = cnt;
-
-       cfg = hpet_readl(HPET_T1_CFG);
-       cfg &= ~HPET_TN_PERIODIC;
-       cfg |= HPET_TN_ENABLE | HPET_TN_32BIT;
-       hpet_writel(cfg, HPET_T1_CFG);
-
-       local_irq_restore(flags);
-
-       return 1;
-}
-
-/*
- * The functions below are called from rtc driver.
- * Return 0 if HPET is not being used.
- * Otherwise do the necessary changes and return 1.
- */
-int hpet_mask_rtc_irq_bit(unsigned long bit_mask)
-{
-       if (!is_hpet_enabled())
-               return 0;
-
-       hpet_rtc_flags &= ~bit_mask;
-       return 1;
-}
-
-int hpet_set_rtc_irq_bit(unsigned long bit_mask)
-{
-       unsigned long oldbits = hpet_rtc_flags;
-
-       if (!is_hpet_enabled())
-               return 0;
-
-       hpet_rtc_flags |= bit_mask;
-
-       if (!oldbits)
-               hpet_rtc_timer_init();
-
-       return 1;
-}
-
-int hpet_set_alarm_time(unsigned char hrs, unsigned char min,
-                       unsigned char sec)
-{
-       if (!is_hpet_enabled())
-               return 0;
-
-       hpet_alarm_time.tm_hour = hrs;
-       hpet_alarm_time.tm_min = min;
-       hpet_alarm_time.tm_sec = sec;
-
-       return 1;
-}
-
-int hpet_set_periodic_freq(unsigned long freq)
-{
-       uint64_t clc;
-
-       if (!is_hpet_enabled())
-               return 0;
-
-       if (freq <= DEFAULT_RTC_INT_FREQ)
-               hpet_pie_limit = DEFAULT_RTC_INT_FREQ / freq;
-       else {
-               clc = (uint64_t) hpet_clockevent.mult * NSEC_PER_SEC;
-               do_div(clc, freq);
-               clc >>= hpet_clockevent.shift;
-               hpet_pie_delta = (unsigned long) clc;
-       }
-       return 1;
-}
-
-int hpet_rtc_dropped_irq(void)
-{
-       return is_hpet_enabled();
-}
-
-static void hpet_rtc_timer_reinit(void)
-{
-       unsigned long cfg, delta;
-       int lost_ints = -1;
-
-       if (unlikely(!hpet_rtc_flags)) {
-               cfg = hpet_readl(HPET_T1_CFG);
-               cfg &= ~HPET_TN_ENABLE;
-               hpet_writel(cfg, HPET_T1_CFG);
-               return;
-       }
-
-       if (!(hpet_rtc_flags & RTC_PIE) || hpet_pie_limit)
-               delta = hpet_default_delta;
-       else
-               delta = hpet_pie_delta;
-
-       /*
-        * Increment the comparator value until we are ahead of the
-        * current count.
-        */
-       do {
-               hpet_t1_cmp += delta;
-               hpet_writel(hpet_t1_cmp, HPET_T1_CMP);
-               lost_ints++;
-       } while ((long)(hpet_readl(HPET_COUNTER) - hpet_t1_cmp) > 0);
-
-       if (lost_ints) {
-               if (hpet_rtc_flags & RTC_PIE)
-                       hpet_pie_count += lost_ints;
-               if (printk_ratelimit())
-                       printk(KERN_WARNING "rtc: lost %d interrupts\n",
-                               lost_ints);
-       }
-}
-
-irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id)
-{
-       struct rtc_time curr_time;
-       unsigned long rtc_int_flag = 0;
-
-       hpet_rtc_timer_reinit();
-
-       if (hpet_rtc_flags & (RTC_UIE | RTC_AIE))
-               rtc_get_rtc_time(&curr_time);
-
-       if (hpet_rtc_flags & RTC_UIE &&
-           curr_time.tm_sec != hpet_prev_update_sec) {
-               rtc_int_flag = RTC_UF;
-               hpet_prev_update_sec = curr_time.tm_sec;
-       }
-
-       if (hpet_rtc_flags & RTC_PIE &&
-           ++hpet_pie_count >= hpet_pie_limit) {
-               rtc_int_flag |= RTC_PF;
-               hpet_pie_count = 0;
-       }
-
-       if (hpet_rtc_flags & RTC_PIE &&
-           (curr_time.tm_sec == hpet_alarm_time.tm_sec) &&
-           (curr_time.tm_min == hpet_alarm_time.tm_min) &&
-           (curr_time.tm_hour == hpet_alarm_time.tm_hour))
-                       rtc_int_flag |= RTC_AF;
-
-       if (rtc_int_flag) {
-               rtc_int_flag |= (RTC_IRQF | (RTC_NUM_INTS << 8));
-               rtc_interrupt(rtc_int_flag, dev_id);
-       }
-       return IRQ_HANDLED;
-}
-#endif
diff --git a/arch/x86/kernel/hpet_64.c b/arch/x86/kernel/hpet_64.c
deleted file mode 100644 (file)
index e2d1b91..0000000
+++ /dev/null
@@ -1,493 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/mc146818rtc.h>
-#include <linux/time.h>
-#include <linux/clocksource.h>
-#include <linux/ioport.h>
-#include <linux/acpi.h>
-#include <linux/hpet.h>
-#include <asm/pgtable.h>
-#include <asm/vsyscall.h>
-#include <asm/timex.h>
-#include <asm/hpet.h>
-
-#define HPET_MASK      0xFFFFFFFF
-#define HPET_SHIFT     22
-
-/* FSEC = 10^-15 NSEC = 10^-9 */
-#define FSEC_PER_NSEC  1000000
-
-int nohpet __initdata;
-
-unsigned long hpet_address;
-unsigned long hpet_period;     /* fsecs / HPET clock */
-unsigned long hpet_tick;       /* HPET clocks / interrupt */
-
-int hpet_use_timer;            /* Use counter of hpet for time keeping,
-                                * otherwise PIT
-                                */
-
-#ifdef CONFIG_HPET
-static __init int late_hpet_init(void)
-{
-       struct hpet_data        hd;
-       unsigned int            ntimer;
-
-       if (!hpet_address)
-               return 0;
-
-       memset(&hd, 0, sizeof(hd));
-
-       ntimer = hpet_readl(HPET_ID);
-       ntimer = (ntimer & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT;
-       ntimer++;
-
-       /*
-        * Register with driver.
-        * Timer0 and Timer1 is used by platform.
-        */
-       hd.hd_phys_address = hpet_address;
-       hd.hd_address = (void __iomem *)fix_to_virt(FIX_HPET_BASE);
-       hd.hd_nirqs = ntimer;
-       hd.hd_flags = HPET_DATA_PLATFORM;
-       hpet_reserve_timer(&hd, 0);
-#ifdef CONFIG_HPET_EMULATE_RTC
-       hpet_reserve_timer(&hd, 1);
-#endif
-       hd.hd_irq[0] = HPET_LEGACY_8254;
-       hd.hd_irq[1] = HPET_LEGACY_RTC;
-       if (ntimer > 2) {
-               struct hpet             *hpet;
-               struct hpet_timer       *timer;
-               int                     i;
-
-               hpet = (struct hpet *) fix_to_virt(FIX_HPET_BASE);
-               timer = &hpet->hpet_timers[2];
-               for (i = 2; i < ntimer; timer++, i++)
-                       hd.hd_irq[i] = (timer->hpet_config &
-                                       Tn_INT_ROUTE_CNF_MASK) >>
-                               Tn_INT_ROUTE_CNF_SHIFT;
-
-       }
-
-       hpet_alloc(&hd);
-       return 0;
-}
-fs_initcall(late_hpet_init);
-#endif
-
-int hpet_timer_stop_set_go(unsigned long tick)
-{
-       unsigned int cfg;
-
-/*
- * Stop the timers and reset the main counter.
- */
-
-       cfg = hpet_readl(HPET_CFG);
-       cfg &= ~(HPET_CFG_ENABLE | HPET_CFG_LEGACY);
-       hpet_writel(cfg, HPET_CFG);
-       hpet_writel(0, HPET_COUNTER);
-       hpet_writel(0, HPET_COUNTER + 4);
-
-/*
- * Set up timer 0, as periodic with first interrupt to happen at hpet_tick,
- * and period also hpet_tick.
- */
-       if (hpet_use_timer) {
-               hpet_writel(HPET_TN_ENABLE | HPET_TN_PERIODIC | HPET_TN_SETVAL |
-                   HPET_TN_32BIT, HPET_T0_CFG);
-               hpet_writel(hpet_tick, HPET_T0_CMP); /* next interrupt */
-               hpet_writel(hpet_tick, HPET_T0_CMP); /* period */
-               cfg |= HPET_CFG_LEGACY;
-       }
-/*
- * Go!
- */
-
-       cfg |= HPET_CFG_ENABLE;
-       hpet_writel(cfg, HPET_CFG);
-
-       return 0;
-}
-
-static cycle_t read_hpet(void)
-{
-       return (cycle_t)hpet_readl(HPET_COUNTER);
-}
-
-static cycle_t __vsyscall_fn vread_hpet(void)
-{
-       return readl((void __iomem *)fix_to_virt(VSYSCALL_HPET) + 0xf0);
-}
-
-struct clocksource clocksource_hpet = {
-       .name           = "hpet",
-       .rating         = 250,
-       .read           = read_hpet,
-       .mask           = (cycle_t)HPET_MASK,
-       .mult           = 0, /* set below */
-       .shift          = HPET_SHIFT,
-       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
-       .vread          = vread_hpet,
-};
-
-int __init hpet_arch_init(void)
-{
-       unsigned int id;
-       u64 tmp;
-
-       if (!hpet_address)
-               return -1;
-       set_fixmap_nocache(FIX_HPET_BASE, hpet_address);
-       __set_fixmap(VSYSCALL_HPET, hpet_address, PAGE_KERNEL_VSYSCALL_NOCACHE);
-
-/*
- * Read the period, compute tick and quotient.
- */
-
-       id = hpet_readl(HPET_ID);
-
-       if (!(id & HPET_ID_VENDOR) || !(id & HPET_ID_NUMBER))
-               return -1;
-
-       hpet_period = hpet_readl(HPET_PERIOD);
-       if (hpet_period < 100000 || hpet_period > 100000000)
-               return -1;
-
-       hpet_tick = (FSEC_PER_TICK + hpet_period / 2) / hpet_period;
-
-       hpet_use_timer = (id & HPET_ID_LEGSUP);
-
-       /*
-        * hpet period is in femto seconds per cycle
-        * so we need to convert this to ns/cyc units
-        * aproximated by mult/2^shift
-        *
-        *  fsec/cyc * 1nsec/1000000fsec = nsec/cyc = mult/2^shift
-        *  fsec/cyc * 1ns/1000000fsec * 2^shift = mult
-        *  fsec/cyc * 2^shift * 1nsec/1000000fsec = mult
-        *  (fsec/cyc << shift)/1000000 = mult
-        *  (hpet_period << shift)/FSEC_PER_NSEC = mult
-        */
-       tmp = (u64)hpet_period << HPET_SHIFT;
-       do_div(tmp, FSEC_PER_NSEC);
-       clocksource_hpet.mult = (u32)tmp;
-       clocksource_register(&clocksource_hpet);
-
-       return hpet_timer_stop_set_go(hpet_tick);
-}
-
-int hpet_reenable(void)
-{
-       return hpet_timer_stop_set_go(hpet_tick);
-}
-
-/*
- * calibrate_tsc() calibrates the processor TSC in a very simple way, comparing
- * it to the HPET timer of known frequency.
- */
-
-#define TICK_COUNT 100000000
-#define SMI_THRESHOLD 50000
-#define MAX_TRIES  5
-
-/*
- * Some platforms take periodic SMI interrupts with 5ms duration. Make sure none
- * occurs between the reads of the hpet & TSC.
- */
-static void __init read_hpet_tsc(int *hpet, int *tsc)
-{
-       int tsc1, tsc2, hpet1, i;
-
-       for (i = 0; i < MAX_TRIES; i++) {
-               tsc1 = get_cycles_sync();
-               hpet1 = hpet_readl(HPET_COUNTER);
-               tsc2 = get_cycles_sync();
-               if ((tsc2 - tsc1) < SMI_THRESHOLD)
-                       break;
-       }
-       *hpet = hpet1;
-       *tsc = tsc2;
-}
-
-unsigned int __init hpet_calibrate_tsc(void)
-{
-       int tsc_start, hpet_start;
-       int tsc_now, hpet_now;
-       unsigned long flags;
-
-       local_irq_save(flags);
-
-       read_hpet_tsc(&hpet_start, &tsc_start);
-
-       do {
-               local_irq_disable();
-               read_hpet_tsc(&hpet_now, &tsc_now);
-               local_irq_restore(flags);
-       } while ((tsc_now - tsc_start) < TICK_COUNT &&
-               (hpet_now - hpet_start) < TICK_COUNT);
-
-       return (tsc_now - tsc_start) * 1000000000L
-               / ((hpet_now - hpet_start) * hpet_period / 1000);
-}
-
-#ifdef CONFIG_HPET_EMULATE_RTC
-/* HPET in LegacyReplacement Mode eats up RTC interrupt line. When, HPET
- * is enabled, we support RTC interrupt functionality in software.
- * RTC has 3 kinds of interrupts:
- * 1) Update Interrupt - generate an interrupt, every sec, when RTC clock
- *    is updated
- * 2) Alarm Interrupt - generate an interrupt at a specific time of day
- * 3) Periodic Interrupt - generate periodic interrupt, with frequencies
- *    2Hz-8192Hz (2Hz-64Hz for non-root user) (all freqs in powers of 2)
- * (1) and (2) above are implemented using polling at a frequency of
- * 64 Hz. The exact frequency is a tradeoff between accuracy and interrupt
- * overhead. (DEFAULT_RTC_INT_FREQ)
- * For (3), we use interrupts at 64Hz or user specified periodic
- * frequency, whichever is higher.
- */
-#include <linux/rtc.h>
-
-#define DEFAULT_RTC_INT_FREQ   64
-#define RTC_NUM_INTS           1
-
-static unsigned long UIE_on;
-static unsigned long prev_update_sec;
-
-static unsigned long AIE_on;
-static struct rtc_time alarm_time;
-
-static unsigned long PIE_on;
-static unsigned long PIE_freq = DEFAULT_RTC_INT_FREQ;
-static unsigned long PIE_count;
-
-static unsigned long hpet_rtc_int_freq; /* RTC interrupt frequency */
-static unsigned int hpet_t1_cmp; /* cached comparator register */
-
-int is_hpet_enabled(void)
-{
-       return hpet_address != 0;
-}
-
-/*
- * Timer 1 for RTC, we do not use periodic interrupt feature,
- * even if HPET supports periodic interrupts on Timer 1.
- * The reason being, to set up a periodic interrupt in HPET, we need to
- * stop the main counter. And if we do that everytime someone diables/enables
- * RTC, we will have adverse effect on main kernel timer running on Timer 0.
- * So, for the time being, simulate the periodic interrupt in software.
- *
- * hpet_rtc_timer_init() is called for the first time and during subsequent
- * interuppts reinit happens through hpet_rtc_timer_reinit().
- */
-int hpet_rtc_timer_init(void)
-{
-       unsigned int cfg, cnt;
-       unsigned long flags;
-
-       if (!is_hpet_enabled())
-               return 0;
-       /*
-        * Set the counter 1 and enable the interrupts.
-        */
-       if (PIE_on && (PIE_freq > DEFAULT_RTC_INT_FREQ))
-               hpet_rtc_int_freq = PIE_freq;
-       else
-               hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ;
-
-       local_irq_save(flags);
-
-       cnt = hpet_readl(HPET_COUNTER);
-       cnt += ((hpet_tick*HZ)/hpet_rtc_int_freq);
-       hpet_writel(cnt, HPET_T1_CMP);
-       hpet_t1_cmp = cnt;
-
-       cfg = hpet_readl(HPET_T1_CFG);
-       cfg &= ~HPET_TN_PERIODIC;
-       cfg |= HPET_TN_ENABLE | HPET_TN_32BIT;
-       hpet_writel(cfg, HPET_T1_CFG);
-
-       local_irq_restore(flags);
-
-       return 1;
-}
-
-static void hpet_rtc_timer_reinit(void)
-{
-       unsigned int cfg, cnt, ticks_per_int, lost_ints;
-
-       if (unlikely(!(PIE_on | AIE_on | UIE_on))) {
-               cfg = hpet_readl(HPET_T1_CFG);
-               cfg &= ~HPET_TN_ENABLE;
-               hpet_writel(cfg, HPET_T1_CFG);
-               return;
-       }
-
-       if (PIE_on && (PIE_freq > DEFAULT_RTC_INT_FREQ))
-               hpet_rtc_int_freq = PIE_freq;
-       else
-               hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ;
-
-       /* It is more accurate to use the comparator value than current count.*/
-       ticks_per_int = hpet_tick * HZ / hpet_rtc_int_freq;
-       hpet_t1_cmp += ticks_per_int;
-       hpet_writel(hpet_t1_cmp, HPET_T1_CMP);
-
-       /*
-        * If the interrupt handler was delayed too long, the write above tries
-        * to schedule the next interrupt in the past and the hardware would
-        * not interrupt until the counter had wrapped around.
-        * So we have to check that the comparator wasn't set to a past time.
-        */
-       cnt = hpet_readl(HPET_COUNTER);
-       if (unlikely((int)(cnt - hpet_t1_cmp) > 0)) {
-               lost_ints = (cnt - hpet_t1_cmp) / ticks_per_int + 1;
-               /* Make sure that, even with the time needed to execute
-                * this code, the next scheduled interrupt has been moved
-                * back to the future: */
-               lost_ints++;
-
-               hpet_t1_cmp += lost_ints * ticks_per_int;
-               hpet_writel(hpet_t1_cmp, HPET_T1_CMP);
-
-               if (PIE_on)
-                       PIE_count += lost_ints;
-
-               if (printk_ratelimit())
-                       printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n",
-                              hpet_rtc_int_freq);
-       }
-}
-
-/*
- * The functions below are called from rtc driver.
- * Return 0 if HPET is not being used.
- * Otherwise do the necessary changes and return 1.
- */
-int hpet_mask_rtc_irq_bit(unsigned long bit_mask)
-{
-       if (!is_hpet_enabled())
-               return 0;
-
-       if (bit_mask & RTC_UIE)
-               UIE_on = 0;
-       if (bit_mask & RTC_PIE)
-               PIE_on = 0;
-       if (bit_mask & RTC_AIE)
-               AIE_on = 0;
-
-       return 1;
-}
-
-int hpet_set_rtc_irq_bit(unsigned long bit_mask)
-{
-       int timer_init_reqd = 0;
-
-       if (!is_hpet_enabled())
-               return 0;
-
-       if (!(PIE_on | AIE_on | UIE_on))
-               timer_init_reqd = 1;
-
-       if (bit_mask & RTC_UIE) {
-               UIE_on = 1;
-       }
-       if (bit_mask & RTC_PIE) {
-               PIE_on = 1;
-               PIE_count = 0;
-       }
-       if (bit_mask & RTC_AIE) {
-               AIE_on = 1;
-       }
-
-       if (timer_init_reqd)
-               hpet_rtc_timer_init();
-
-       return 1;
-}
-
-int hpet_set_alarm_time(unsigned char hrs, unsigned char min, unsigned char sec)
-{
-       if (!is_hpet_enabled())
-               return 0;
-
-       alarm_time.tm_hour = hrs;
-       alarm_time.tm_min = min;
-       alarm_time.tm_sec = sec;
-
-       return 1;
-}
-
-int hpet_set_periodic_freq(unsigned long freq)
-{
-       if (!is_hpet_enabled())
-               return 0;
-
-       PIE_freq = freq;
-       PIE_count = 0;
-
-       return 1;
-}
-
-int hpet_rtc_dropped_irq(void)
-{
-       if (!is_hpet_enabled())
-               return 0;
-
-       return 1;
-}
-
-irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id)
-{
-       struct rtc_time curr_time;
-       unsigned long rtc_int_flag = 0;
-       int call_rtc_interrupt = 0;
-
-       hpet_rtc_timer_reinit();
-
-       if (UIE_on | AIE_on) {
-               rtc_get_rtc_time(&curr_time);
-       }
-       if (UIE_on) {
-               if (curr_time.tm_sec != prev_update_sec) {
-                       /* Set update int info, call real rtc int routine */
-                       call_rtc_interrupt = 1;
-                       rtc_int_flag = RTC_UF;
-                       prev_update_sec = curr_time.tm_sec;
-               }
-       }
-       if (PIE_on) {
-               PIE_count++;
-               if (PIE_count >= hpet_rtc_int_freq/PIE_freq) {
-                       /* Set periodic int info, call real rtc int routine */
-                       call_rtc_interrupt = 1;
-                       rtc_int_flag |= RTC_PF;
-                       PIE_count = 0;
-               }
-       }
-       if (AIE_on) {
-               if ((curr_time.tm_sec == alarm_time.tm_sec) &&
-                   (curr_time.tm_min == alarm_time.tm_min) &&
-                   (curr_time.tm_hour == alarm_time.tm_hour)) {
-                       /* Set alarm int info, call real rtc int routine */
-                       call_rtc_interrupt = 1;
-                       rtc_int_flag |= RTC_AF;
-               }
-       }
-       if (call_rtc_interrupt) {
-               rtc_int_flag |= (RTC_IRQF | (RTC_NUM_INTS << 8));
-               rtc_interrupt(rtc_int_flag, dev_id);
-       }
-       return IRQ_HANDLED;
-}
-#endif
-
-static int __init nohpet_setup(char *s)
-{
-       nohpet = 1;
-       return 1;
-}
-
-__setup("nohpet", nohpet_setup);
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.
  *
diff --git a/arch/x86/kernel/i8253.c b/arch/x86/kernel/i8253.c
new file mode 100644 (file)
index 0000000..5cc8841
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * 8253/PIT functions
+ *
+ */
+#include <linux/clockchips.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+#include <asm/smp.h>
+#include <asm/delay.h>
+#include <asm/i8253.h>
+#include <asm/io.h>
+
+DEFINE_SPINLOCK(i8253_lock);
+EXPORT_SYMBOL(i8253_lock);
+
+/*
+ * HPET replaces the PIT, when enabled. So we need to know, which of
+ * the two timers is used
+ */
+struct clock_event_device *global_clock_event;
+
+/*
+ * Initialize the PIT timer.
+ *
+ * This is also called after resume to bring the PIT into operation again.
+ */
+static void init_pit_timer(enum clock_event_mode mode,
+                          struct clock_event_device *evt)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&i8253_lock, flags);
+
+       switch(mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+               /* binary, mode 2, LSB/MSB, ch 0 */
+               outb_p(0x34, PIT_MODE);
+               outb_p(LATCH & 0xff , PIT_CH0); /* LSB */
+               outb(LATCH >> 8 , PIT_CH0);     /* MSB */
+               break;
+
+       case CLOCK_EVT_MODE_SHUTDOWN:
+       case CLOCK_EVT_MODE_UNUSED:
+               if (evt->mode == CLOCK_EVT_MODE_PERIODIC ||
+                   evt->mode == CLOCK_EVT_MODE_ONESHOT) {
+                       outb_p(0x30, PIT_MODE);
+                       outb_p(0, PIT_CH0);
+                       outb_p(0, PIT_CH0);
+               }
+               break;
+
+       case CLOCK_EVT_MODE_ONESHOT:
+               /* One shot setup */
+               outb_p(0x38, PIT_MODE);
+               break;
+
+       case CLOCK_EVT_MODE_RESUME:
+               /* Nothing to do here */
+               break;
+       }
+       spin_unlock_irqrestore(&i8253_lock, flags);
+}
+
+/*
+ * Program the next event in oneshot mode
+ *
+ * Delta is given in PIT ticks
+ */
+static int pit_next_event(unsigned long delta, struct clock_event_device *evt)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&i8253_lock, flags);
+       outb_p(delta & 0xff , PIT_CH0); /* LSB */
+       outb(delta >> 8 , PIT_CH0);     /* MSB */
+       spin_unlock_irqrestore(&i8253_lock, flags);
+
+       return 0;
+}
+
+/*
+ * On UP the PIT can serve all of the possible timer functions. On SMP systems
+ * it can be solely used for the global tick.
+ *
+ * The profiling and update capabilites are switched off once the local apic is
+ * registered. This mechanism replaces the previous #ifdef LOCAL_APIC -
+ * !using_apic_timer decisions in do_timer_interrupt_hook()
+ */
+struct clock_event_device pit_clockevent = {
+       .name           = "pit",
+       .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+       .set_mode       = init_pit_timer,
+       .set_next_event = pit_next_event,
+       .shift          = 32,
+       .irq            = 0,
+};
+
+/*
+ * Initialize the conversion factor and the min/max deltas of the clock event
+ * structure and register the clock event source with the framework.
+ */
+void __init setup_pit_timer(void)
+{
+       /*
+        * Start pit with the boot cpu mask and make it global after the
+        * IO_APIC has been initialized.
+        */
+       pit_clockevent.cpumask = cpumask_of_cpu(smp_processor_id());
+       pit_clockevent.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, 32);
+       pit_clockevent.max_delta_ns =
+               clockevent_delta2ns(0x7FFF, &pit_clockevent);
+       pit_clockevent.min_delta_ns =
+               clockevent_delta2ns(0xF, &pit_clockevent);
+       clockevents_register_device(&pit_clockevent);
+       global_clock_event = &pit_clockevent;
+}
+
+#ifndef CONFIG_X86_64
+/*
+ * Since the PIT overflows every tick, its not very useful
+ * to just read by itself. So use jiffies to emulate a free
+ * running counter:
+ */
+static cycle_t pit_read(void)
+{
+       unsigned long flags;
+       int count;
+       u32 jifs;
+       static int old_count;
+       static u32 old_jifs;
+
+       spin_lock_irqsave(&i8253_lock, flags);
+       /*
+        * Although our caller may have the read side of xtime_lock,
+        * this is now a seqlock, and we are cheating in this routine
+        * by having side effects on state that we cannot undo if
+        * there is a collision on the seqlock and our caller has to
+        * retry.  (Namely, old_jifs and old_count.)  So we must treat
+        * jiffies as volatile despite the lock.  We read jiffies
+        * before latching the timer count to guarantee that although
+        * the jiffies value might be older than the count (that is,
+        * the counter may underflow between the last point where
+        * jiffies was incremented and the point where we latch the
+        * count), it cannot be newer.
+        */
+       jifs = jiffies;
+       outb_p(0x00, PIT_MODE); /* latch the count ASAP */
+       count = inb_p(PIT_CH0); /* read the latched count */
+       count |= inb_p(PIT_CH0) << 8;
+
+       /* VIA686a test code... reset the latch if count > max + 1 */
+       if (count > LATCH) {
+               outb_p(0x34, PIT_MODE);
+               outb_p(LATCH & 0xff, PIT_CH0);
+               outb(LATCH >> 8, PIT_CH0);
+               count = LATCH - 1;
+       }
+
+       /*
+        * It's possible for count to appear to go the wrong way for a
+        * couple of reasons:
+        *
+        *  1. The timer counter underflows, but we haven't handled the
+        *     resulting interrupt and incremented jiffies yet.
+        *  2. Hardware problem with the timer, not giving us continuous time,
+        *     the counter does small "jumps" upwards on some Pentium systems,
+        *     (see c't 95/10 page 335 for Neptun bug.)
+        *
+        * Previous attempts to handle these cases intelligently were
+        * buggy, so we just do the simple thing now.
+        */
+       if (count > old_count && jifs == old_jifs) {
+               count = old_count;
+       }
+       old_count = count;
+       old_jifs = jifs;
+
+       spin_unlock_irqrestore(&i8253_lock, flags);
+
+       count = (LATCH - 1) - count;
+
+       return (cycle_t)(jifs * LATCH) + count;
+}
+
+static struct clocksource clocksource_pit = {
+       .name   = "pit",
+       .rating = 110,
+       .read   = pit_read,
+       .mask   = CLOCKSOURCE_MASK(32),
+       .mult   = 0,
+       .shift  = 20,
+};
+
+static int __init init_pit_clocksource(void)
+{
+       if (num_possible_cpus() > 1) /* PIT does not scale! */
+               return 0;
+
+       clocksource_pit.mult = clocksource_hz2mult(CLOCK_TICK_RATE, 20);
+       return clocksource_register(&clocksource_pit);
+}
+arch_initcall(init_pit_clocksource);
+
+#endif
diff --git a/arch/x86/kernel/i8253_32.c b/arch/x86/kernel/i8253_32.c
deleted file mode 100644 (file)
index 6d839f2..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * i8253.c  8253/PIT functions
- *
- */
-#include <linux/clockchips.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/jiffies.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-
-#include <asm/smp.h>
-#include <asm/delay.h>
-#include <asm/i8253.h>
-#include <asm/io.h>
-#include <asm/timer.h>
-
-DEFINE_SPINLOCK(i8253_lock);
-EXPORT_SYMBOL(i8253_lock);
-
-/*
- * HPET replaces the PIT, when enabled. So we need to know, which of
- * the two timers is used
- */
-struct clock_event_device *global_clock_event;
-
-/*
- * Initialize the PIT timer.
- *
- * This is also called after resume to bring the PIT into operation again.
- */
-static void init_pit_timer(enum clock_event_mode mode,
-                          struct clock_event_device *evt)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&i8253_lock, flags);
-
-       switch(mode) {
-       case CLOCK_EVT_MODE_PERIODIC:
-               /* binary, mode 2, LSB/MSB, ch 0 */
-               outb_p(0x34, PIT_MODE);
-               outb_p(LATCH & 0xff , PIT_CH0); /* LSB */
-               outb(LATCH >> 8 , PIT_CH0);     /* MSB */
-               break;
-
-       case CLOCK_EVT_MODE_SHUTDOWN:
-       case CLOCK_EVT_MODE_UNUSED:
-               if (evt->mode == CLOCK_EVT_MODE_PERIODIC ||
-                   evt->mode == CLOCK_EVT_MODE_ONESHOT) {
-                       outb_p(0x30, PIT_MODE);
-                       outb_p(0, PIT_CH0);
-                       outb_p(0, PIT_CH0);
-               }
-               break;
-
-       case CLOCK_EVT_MODE_ONESHOT:
-               /* One shot setup */
-               outb_p(0x38, PIT_MODE);
-               break;
-
-       case CLOCK_EVT_MODE_RESUME:
-               /* Nothing to do here */
-               break;
-       }
-       spin_unlock_irqrestore(&i8253_lock, flags);
-}
-
-/*
- * Program the next event in oneshot mode
- *
- * Delta is given in PIT ticks
- */
-static int pit_next_event(unsigned long delta, struct clock_event_device *evt)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&i8253_lock, flags);
-       outb_p(delta & 0xff , PIT_CH0); /* LSB */
-       outb(delta >> 8 , PIT_CH0);     /* MSB */
-       spin_unlock_irqrestore(&i8253_lock, flags);
-
-       return 0;
-}
-
-/*
- * On UP the PIT can serve all of the possible timer functions. On SMP systems
- * it can be solely used for the global tick.
- *
- * The profiling and update capabilites are switched off once the local apic is
- * registered. This mechanism replaces the previous #ifdef LOCAL_APIC -
- * !using_apic_timer decisions in do_timer_interrupt_hook()
- */
-struct clock_event_device pit_clockevent = {
-       .name           = "pit",
-       .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
-       .set_mode       = init_pit_timer,
-       .set_next_event = pit_next_event,
-       .shift          = 32,
-       .irq            = 0,
-};
-
-/*
- * Initialize the conversion factor and the min/max deltas of the clock event
- * structure and register the clock event source with the framework.
- */
-void __init setup_pit_timer(void)
-{
-       /*
-        * Start pit with the boot cpu mask and make it global after the
-        * IO_APIC has been initialized.
-        */
-       pit_clockevent.cpumask = cpumask_of_cpu(smp_processor_id());
-       pit_clockevent.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, 32);
-       pit_clockevent.max_delta_ns =
-               clockevent_delta2ns(0x7FFF, &pit_clockevent);
-       pit_clockevent.min_delta_ns =
-               clockevent_delta2ns(0xF, &pit_clockevent);
-       clockevents_register_device(&pit_clockevent);
-       global_clock_event = &pit_clockevent;
-}
-
-/*
- * Since the PIT overflows every tick, its not very useful
- * to just read by itself. So use jiffies to emulate a free
- * running counter:
- */
-static cycle_t pit_read(void)
-{
-       unsigned long flags;
-       int count;
-       u32 jifs;
-       static int old_count;
-       static u32 old_jifs;
-
-       spin_lock_irqsave(&i8253_lock, flags);
-       /*
-        * Although our caller may have the read side of xtime_lock,
-        * this is now a seqlock, and we are cheating in this routine
-        * by having side effects on state that we cannot undo if
-        * there is a collision on the seqlock and our caller has to
-        * retry.  (Namely, old_jifs and old_count.)  So we must treat
-        * jiffies as volatile despite the lock.  We read jiffies
-        * before latching the timer count to guarantee that although
-        * the jiffies value might be older than the count (that is,
-        * the counter may underflow between the last point where
-        * jiffies was incremented and the point where we latch the
-        * count), it cannot be newer.
-        */
-       jifs = jiffies;
-       outb_p(0x00, PIT_MODE); /* latch the count ASAP */
-       count = inb_p(PIT_CH0); /* read the latched count */
-       count |= inb_p(PIT_CH0) << 8;
-
-       /* VIA686a test code... reset the latch if count > max + 1 */
-       if (count > LATCH) {
-               outb_p(0x34, PIT_MODE);
-               outb_p(LATCH & 0xff, PIT_CH0);
-               outb(LATCH >> 8, PIT_CH0);
-               count = LATCH - 1;
-       }
-
-       /*
-        * It's possible for count to appear to go the wrong way for a
-        * couple of reasons:
-        *
-        *  1. The timer counter underflows, but we haven't handled the
-        *     resulting interrupt and incremented jiffies yet.
-        *  2. Hardware problem with the timer, not giving us continuous time,
-        *     the counter does small "jumps" upwards on some Pentium systems,
-        *     (see c't 95/10 page 335 for Neptun bug.)
-        *
-        * Previous attempts to handle these cases intelligently were
-        * buggy, so we just do the simple thing now.
-        */
-       if (count > old_count && jifs == old_jifs) {
-               count = old_count;
-       }
-       old_count = count;
-       old_jifs = jifs;
-
-       spin_unlock_irqrestore(&i8253_lock, flags);
-
-       count = (LATCH - 1) - count;
-
-       return (cycle_t)(jifs * LATCH) + count;
-}
-
-static struct clocksource clocksource_pit = {
-       .name   = "pit",
-       .rating = 110,
-       .read   = pit_read,
-       .mask   = CLOCKSOURCE_MASK(32),
-       .mult   = 0,
-       .shift  = 20,
-};
-
-static int __init init_pit_clocksource(void)
-{
-       if (num_possible_cpus() > 1) /* PIT does not scale! */
-               return 0;
-
-       clocksource_pit.mult = clocksource_hz2mult(CLOCK_TICK_RATE, 20);
-       return clocksource_register(&clocksource_pit);
-}
-arch_initcall(init_pit_clocksource);
index 0499cbe9871a4bb410c762f89bec6756685280fe..679bb33acbf1ce30e216a7a05e4e1d9cd61e5d2b 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/sysdev.h>
 #include <linux/bitops.h>
 
-#include <asm/8253pit.h>
 #include <asm/atomic.h>
 #include <asm/system.h>
 #include <asm/io.h>
index 948cae646099cc451a834e53c9a8b0ab5da037b7..eb72976cc13c177f38a178bb093b5cc721ce3d1e 100644 (file)
@@ -444,46 +444,6 @@ void __init init_ISA_irqs (void)
        }
 }
 
-static void setup_timer_hardware(void)
-{
-       outb_p(0x34,0x43);              /* binary, mode 2, LSB/MSB, ch 0 */
-       udelay(10);
-       outb_p(LATCH & 0xff , 0x40);    /* LSB */
-       udelay(10);
-       outb(LATCH >> 8 , 0x40);        /* MSB */
-}
-
-static int timer_resume(struct sys_device *dev)
-{
-       setup_timer_hardware();
-       return 0;
-}
-
-void i8254_timer_resume(void)
-{
-       setup_timer_hardware();
-}
-
-static struct sysdev_class timer_sysclass = {
-       set_kset_name("timer_pit"),
-       .resume         = timer_resume,
-};
-
-static struct sys_device device_timer = {
-       .id             = 0,
-       .cls            = &timer_sysclass,
-};
-
-static int __init init_timer_sysfs(void)
-{
-       int error = sysdev_class_register(&timer_sysclass);
-       if (!error)
-               error = sysdev_register(&device_timer);
-       return error;
-}
-
-device_initcall(init_timer_sysfs);
-
 void __init init_IRQ(void)
 {
        int i;
@@ -533,12 +493,6 @@ void __init init_IRQ(void)
        set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
        set_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
 
-       /*
-        * Set the clock to HZ Hz, we already have a valid
-        * vector now:
-        */
-       setup_timer_hardware();
-
        if (!acpi_ioapic)
                setup_irq(2, &irq2);
 }
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..c2d03e96ae9f9a38b8f26225dd05f7a15e3c5194 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
index a30e004682e2dc60fe81a7e1caf007fbbcf314a7..1df17a0ec0c9d7ddca19df029d6fca8818b68090 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
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:
diff --git a/arch/x86/kernel/mfgpt_32.c b/arch/x86/kernel/mfgpt_32.c
new file mode 100644 (file)
index 0000000..0ab680f
--- /dev/null
@@ -0,0 +1,362 @@
+/*
+ * Driver/API for AMD Geode Multi-Function General Purpose Timers (MFGPT)
+ *
+ * Copyright (C) 2006, Advanced Micro Devices, Inc.
+ * Copyright (C) 2007, Andres Salomon <dilinger@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * The MFGPTs are documented in AMD Geode CS5536 Companion Device Data Book.
+ */
+
+/*
+ * We are using the 32Khz input clock - its the only one that has the
+ * ranges we find desirable.  The following table lists the suitable
+ * divisors and the associated hz, minimum interval
+ * and the maximum interval:
+ *
+ *  Divisor   Hz      Min Delta (S) Max Delta (S)
+ *   1        32000     .0005          2.048
+ *   2        16000      .001          4.096
+ *   4         8000      .002          8.192
+ *   8         4000      .004         16.384
+ *   16        2000      .008         32.768
+ *   32        1000      .016         65.536
+ *   64         500      .032        131.072
+ *  128         250      .064        262.144
+ *  256         125      .128        524.288
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <asm/geode.h>
+
+#define F_AVAIL    0x01
+
+static struct mfgpt_timer_t {
+       int flags;
+       struct module *owner;
+} mfgpt_timers[MFGPT_MAX_TIMERS];
+
+/* Selected from the table above */
+
+#define MFGPT_DIVISOR 16
+#define MFGPT_SCALE  4     /* divisor = 2^(scale) */
+#define MFGPT_HZ  (32000 / MFGPT_DIVISOR)
+#define MFGPT_PERIODIC (MFGPT_HZ / HZ)
+
+#ifdef CONFIG_GEODE_MFGPT_TIMER
+static int __init mfgpt_timer_setup(void);
+#else
+#define mfgpt_timer_setup() (0)
+#endif
+
+/* Allow for disabling of MFGPTs */
+static int disable;
+static int __init mfgpt_disable(char *s)
+{
+       disable = 1;
+       return 1;
+}
+__setup("nomfgpt", mfgpt_disable);
+
+/*
+ * Check whether any MFGPTs are available for the kernel to use.  In most
+ * cases, firmware that uses AMD's VSA code will claim all timers during
+ * bootup; we certainly don't want to take them if they're already in use.
+ * In other cases (such as with VSAless OpenFirmware), the system firmware
+ * leaves timers available for us to use.
+ */
+int __init geode_mfgpt_detect(void)
+{
+       int count = 0, i;
+       u16 val;
+
+       if (disable) {
+               printk(KERN_INFO "geode-mfgpt:  Skipping MFGPT setup\n");
+               return 0;
+       }
+
+       for (i = 0; i < MFGPT_MAX_TIMERS; i++) {
+               val = geode_mfgpt_read(i, MFGPT_REG_SETUP);
+               if (!(val & MFGPT_SETUP_SETUP)) {
+                       mfgpt_timers[i].flags = F_AVAIL;
+                       count++;
+               }
+       }
+
+       /* set up clock event device, if desired */
+       i = mfgpt_timer_setup();
+
+       return count;
+}
+
+int geode_mfgpt_toggle_event(int timer, int cmp, int event, int enable)
+{
+       u32 msr, mask, value, dummy;
+       int shift = (cmp == MFGPT_CMP1) ? 0 : 8;
+
+       if (timer < 0 || timer >= MFGPT_MAX_TIMERS)
+               return -EIO;
+
+       /*
+        * The register maps for these are described in sections 6.17.1.x of
+        * the AMD Geode CS5536 Companion Device Data Book.
+        */
+       switch (event) {
+       case MFGPT_EVENT_RESET:
+               /*
+                * XXX: According to the docs, we cannot reset timers above
+                * 6; that is, resets for 7 and 8 will be ignored.  Is this
+                * a problem?   -dilinger
+                */
+               msr = MFGPT_NR_MSR;
+               mask = 1 << (timer + 24);
+               break;
+
+       case MFGPT_EVENT_NMI:
+               msr = MFGPT_NR_MSR;
+               mask = 1 << (timer + shift);
+               break;
+
+       case MFGPT_EVENT_IRQ:
+               msr = MFGPT_IRQ_MSR;
+               mask = 1 << (timer + shift);
+               break;
+
+       default:
+               return -EIO;
+       }
+
+       rdmsr(msr, value, dummy);
+
+       if (enable)
+               value |= mask;
+       else
+               value &= ~mask;
+
+       wrmsr(msr, value, dummy);
+       return 0;
+}
+
+int geode_mfgpt_set_irq(int timer, int cmp, int irq, int enable)
+{
+       u32 val, dummy;
+       int offset;
+
+       if (timer < 0 || timer >= MFGPT_MAX_TIMERS)
+               return -EIO;
+
+       if (geode_mfgpt_toggle_event(timer, cmp, MFGPT_EVENT_IRQ, enable))
+               return -EIO;
+
+       rdmsr(MSR_PIC_ZSEL_LOW, val, dummy);
+
+       offset = (timer % 4) * 4;
+
+       val &= ~((0xF << offset) | (0xF << (offset + 16)));
+
+       if (enable) {
+               val |= (irq & 0x0F) << (offset);
+               val |= (irq & 0x0F) << (offset + 16);
+       }
+
+       wrmsr(MSR_PIC_ZSEL_LOW, val, dummy);
+       return 0;
+}
+
+static int mfgpt_get(int timer, struct module *owner)
+{
+       mfgpt_timers[timer].flags &= ~F_AVAIL;
+       mfgpt_timers[timer].owner = owner;
+       printk(KERN_INFO "geode-mfgpt:  Registered timer %d\n", timer);
+       return timer;
+}
+
+int geode_mfgpt_alloc_timer(int timer, int domain, struct module *owner)
+{
+       int i;
+
+       if (!geode_get_dev_base(GEODE_DEV_MFGPT))
+               return -ENODEV;
+       if (timer >= MFGPT_MAX_TIMERS)
+               return -EIO;
+
+       if (timer < 0) {
+               /* Try to find an available timer */
+               for (i = 0; i < MFGPT_MAX_TIMERS; i++) {
+                       if (mfgpt_timers[i].flags & F_AVAIL)
+                               return mfgpt_get(i, owner);
+
+                       if (i == 5 && domain == MFGPT_DOMAIN_WORKING)
+                               break;
+               }
+       } else {
+               /* If they requested a specific timer, try to honor that */
+               if (mfgpt_timers[timer].flags & F_AVAIL)
+                       return mfgpt_get(timer, owner);
+       }
+
+       /* No timers available - too bad */
+       return -1;
+}
+
+
+#ifdef CONFIG_GEODE_MFGPT_TIMER
+
+/*
+ * The MFPGT timers on the CS5536 provide us with suitable timers to use
+ * as clock event sources - not as good as a HPET or APIC, but certainly
+ * better then the PIT.  This isn't a general purpose MFGPT driver, but
+ * a simplified one designed specifically to act as a clock event source.
+ * For full details about the MFGPT, please consult the CS5536 data sheet.
+ */
+
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+
+static unsigned int mfgpt_tick_mode = CLOCK_EVT_MODE_SHUTDOWN;
+static u16 mfgpt_event_clock;
+
+static int irq = 7;
+static int __init mfgpt_setup(char *str)
+{
+       get_option(&str, &irq);
+       return 1;
+}
+__setup("mfgpt_irq=", mfgpt_setup);
+
+static inline void mfgpt_disable_timer(u16 clock)
+{
+       u16 val = geode_mfgpt_read(clock, MFGPT_REG_SETUP);
+       geode_mfgpt_write(clock, MFGPT_REG_SETUP, val & ~MFGPT_SETUP_CNTEN);
+}
+
+static int mfgpt_next_event(unsigned long, struct clock_event_device *);
+static void mfgpt_set_mode(enum clock_event_mode, struct clock_event_device *);
+
+static struct clock_event_device mfgpt_clockevent = {
+       .name = "mfgpt-timer",
+       .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+       .set_mode = mfgpt_set_mode,
+       .set_next_event = mfgpt_next_event,
+       .rating = 250,
+       .cpumask = CPU_MASK_ALL,
+       .shift = 32
+};
+
+static inline void mfgpt_start_timer(u16 clock, u16 delta)
+{
+       geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_CMP2, (u16) delta);
+       geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_COUNTER, 0);
+
+       geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_SETUP,
+                         MFGPT_SETUP_CNTEN | MFGPT_SETUP_CMP2);
+}
+
+static void mfgpt_set_mode(enum clock_event_mode mode,
+                          struct clock_event_device *evt)
+{
+       mfgpt_disable_timer(mfgpt_event_clock);
+
+       if (mode == CLOCK_EVT_MODE_PERIODIC)
+               mfgpt_start_timer(mfgpt_event_clock, MFGPT_PERIODIC);
+
+       mfgpt_tick_mode = mode;
+}
+
+static int mfgpt_next_event(unsigned long delta, struct clock_event_device *evt)
+{
+       mfgpt_start_timer(mfgpt_event_clock, delta);
+       return 0;
+}
+
+/* Assume (foolishly?), that this interrupt was due to our tick */
+
+static irqreturn_t mfgpt_tick(int irq, void *dev_id)
+{
+       if (mfgpt_tick_mode == CLOCK_EVT_MODE_SHUTDOWN)
+               return IRQ_HANDLED;
+
+       /* Turn off the clock */
+       mfgpt_disable_timer(mfgpt_event_clock);
+
+       /* Clear the counter */
+       geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_COUNTER, 0);
+
+       /* Restart the clock in periodic mode */
+
+       if (mfgpt_tick_mode == CLOCK_EVT_MODE_PERIODIC) {
+               geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_SETUP,
+                                 MFGPT_SETUP_CNTEN | MFGPT_SETUP_CMP2);
+       }
+
+       mfgpt_clockevent.event_handler(&mfgpt_clockevent);
+       return IRQ_HANDLED;
+}
+
+static struct irqaction mfgptirq  = {
+       .handler = mfgpt_tick,
+       .flags = IRQF_DISABLED | IRQF_NOBALANCING,
+       .mask = CPU_MASK_NONE,
+       .name = "mfgpt-timer"
+};
+
+static int __init mfgpt_timer_setup(void)
+{
+       int timer, ret;
+       u16 val;
+
+       timer = geode_mfgpt_alloc_timer(MFGPT_TIMER_ANY, MFGPT_DOMAIN_WORKING,
+                       THIS_MODULE);
+       if (timer < 0) {
+               printk(KERN_ERR
+                      "mfgpt-timer:  Could not allocate a MFPGT timer\n");
+               return -ENODEV;
+       }
+
+       mfgpt_event_clock = timer;
+       /* Set the clock scale and enable the event mode for CMP2 */
+       val = MFGPT_SCALE | (3 << 8);
+
+       geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_SETUP, val);
+
+       /* Set up the IRQ on the MFGPT side */
+       if (geode_mfgpt_setup_irq(mfgpt_event_clock, MFGPT_CMP2, irq)) {
+               printk(KERN_ERR "mfgpt-timer:  Could not set up IRQ %d\n", irq);
+               return -EIO;
+       }
+
+       /* And register it with the kernel */
+       ret = setup_irq(irq, &mfgptirq);
+
+       if (ret) {
+               printk(KERN_ERR
+                      "mfgpt-timer:  Unable to set up the interrupt.\n");
+               goto err;
+       }
+
+       /* Set up the clock event */
+       mfgpt_clockevent.mult = div_sc(MFGPT_HZ, NSEC_PER_SEC, 32);
+       mfgpt_clockevent.min_delta_ns = clockevent_delta2ns(0xF,
+                       &mfgpt_clockevent);
+       mfgpt_clockevent.max_delta_ns = clockevent_delta2ns(0xFFFE,
+                       &mfgpt_clockevent);
+
+       printk(KERN_INFO
+              "mfgpt-timer:  registering the MFGT timer as a clock event.\n");
+       clockevents_register_device(&mfgpt_clockevent);
+
+       return 0;
+
+err:
+       geode_mfgpt_release_irq(mfgpt_event_clock, MFGPT_CMP2, irq);
+       printk(KERN_ERR
+              "mfgpt-timer:  Unable to set up the MFGPT clock source\n");
+       return -EIO;
+}
+
+#endif
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 c7227e2180f850bde4a04de8a0e4417045bd6be2..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>
@@ -353,7 +351,8 @@ __kprobes int nmi_watchdog_tick(struct pt_regs * regs, unsigned reason)
         * Take the local apic timer and PIT/HPET into account. We don't
         * know which one is active, when we have highres/dyntick on
         */
-       sum = per_cpu(irq_stat, cpu).apic_timer_irqs + kstat_cpu(cpu).irqs[0];
+       sum = per_cpu(irq_stat, cpu).apic_timer_irqs +
+               per_cpu(irq_stat, cpu).irq0_irqs;
 
        /* if the none of the timers isn't firing, this cpu isn't doing much */
        if (!touched && last_irq_sums[cpu] == sum) {
index 0ec6d2ddb931f48a2cbeef6daf09503907328638..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>
@@ -329,7 +327,7 @@ int __kprobes nmi_watchdog_tick(struct pt_regs * regs, unsigned reason)
                touched = 1;
        }
 
-       sum = read_pda(apic_timer_irqs);
+       sum = read_pda(apic_timer_irqs) + read_pda(irq0_irqs);
        if (__get_cpu_var(nmi_touch)) {
                __get_cpu_var(nmi_touch) = 0;
                touched = 1;
index 048f09b62553e638ecb6c0ba89528a4f9665b014..0aae2f3847a5486fe657ce3403179c6359aabeca 100644 (file)
@@ -63,7 +63,8 @@ void dma_free_coherent(struct device *dev, size_t size,
 {
        struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
        int order = get_order(size);
-       
+
+       WARN_ON(irqs_disabled());       /* for portability */
        if (mem && vaddr >= mem->virt_base && vaddr < (mem->virt_base + (mem->size << PAGE_SHIFT))) {
                int page = (vaddr - mem->virt_base) >> PAGE_SHIFT;
 
index 29711445c8187464c6c00b14938451c23732df3e..9576a2eb375ed81f5aee52e657676cd74dbad4f9 100644 (file)
@@ -167,6 +167,7 @@ EXPORT_SYMBOL(dma_alloc_coherent);
 void dma_free_coherent(struct device *dev, size_t size,
                         void *vaddr, dma_addr_t bus)
 {
+       WARN_ON(irqs_disabled());       /* for portability */
        if (dma_ops->unmap_single)
                dma_ops->unmap_single(dev, bus, size, 0);
        free_pages((unsigned long)vaddr, get_order(size));
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 98956555450beff2c49d22eed79a63aecff87175..7352d4b377e6d0f411bf1a6cf9d26e9266afacaa 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  linux/arch/x86-64/kernel/process.c
- *
  *  Copyright (C) 1995  Linus Torvalds
  *
  *  Pentium III FXSR, SSE support
@@ -38,6 +36,7 @@
 #include <linux/notifier.h>
 #include <linux/kprobes.h>
 #include <linux/kdebug.h>
+#include <linux/tick.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -208,6 +207,8 @@ void cpu_idle (void)
                        if (__get_cpu_var(cpu_idle_state))
                                __get_cpu_var(cpu_idle_state) = 0;
 
+                       tick_nohz_stop_sched_tick();
+
                        rmb();
                        idle = pm_idle;
                        if (!idle)
@@ -228,6 +229,7 @@ void cpu_idle (void)
                        __exit_idle();
                }
 
+               tick_nohz_restart_sched_tick();
                preempt_enable_no_resched();
                schedule();
                preempt_disable();
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 6722469c2633841c7ad8f29fb5355e9b7df02b42..d769e204f942904b389daba44417cd9c97f61dc1 100644 (file)
@@ -4,6 +4,8 @@
 #include <linux/pci.h>
 #include <linux/irq.h>
 
+#include <asm/hpet.h>
+
 #if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_SMP) && defined(CONFIG_PCI)
 
 static void __devinit quirk_intel_irqbalance(struct pci_dev *dev)
@@ -47,3 +49,206 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,        PCI_DEVICE_ID_INTEL_E7320_MCH,  quir
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_E7525_MCH,  quirk_intel_irqbalance);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_E7520_MCH,  quirk_intel_irqbalance);
 #endif
+
+#if defined(CONFIG_HPET_TIMER)
+unsigned long force_hpet_address;
+
+static enum {
+       NONE_FORCE_HPET_RESUME,
+       OLD_ICH_FORCE_HPET_RESUME,
+       ICH_FORCE_HPET_RESUME
+} force_hpet_resume_type;
+
+static void __iomem *rcba_base;
+
+static void ich_force_hpet_resume(void)
+{
+       u32 val;
+
+       if (!force_hpet_address)
+               return;
+
+       if (rcba_base == NULL)
+               BUG();
+
+       /* read the Function Disable register, dword mode only */
+       val = readl(rcba_base + 0x3404);
+       if (!(val & 0x80)) {
+               /* HPET disabled in HPTC. Trying to enable */
+               writel(val | 0x80, rcba_base + 0x3404);
+       }
+
+       val = readl(rcba_base + 0x3404);
+       if (!(val & 0x80))
+               BUG();
+       else
+               printk(KERN_DEBUG "Force enabled HPET at resume\n");
+
+       return;
+}
+
+static void ich_force_enable_hpet(struct pci_dev *dev)
+{
+       u32 val;
+       u32 uninitialized_var(rcba);
+       int err = 0;
+
+       if (hpet_address || force_hpet_address)
+               return;
+
+       pci_read_config_dword(dev, 0xF0, &rcba);
+       rcba &= 0xFFFFC000;
+       if (rcba == 0) {
+               printk(KERN_DEBUG "RCBA disabled. Cannot force enable HPET\n");
+               return;
+       }
+
+       /* use bits 31:14, 16 kB aligned */
+       rcba_base = ioremap_nocache(rcba, 0x4000);
+       if (rcba_base == NULL) {
+               printk(KERN_DEBUG "ioremap failed. Cannot force enable HPET\n");
+               return;
+       }
+
+       /* read the Function Disable register, dword mode only */
+       val = readl(rcba_base + 0x3404);
+
+       if (val & 0x80) {
+               /* HPET is enabled in HPTC. Just not reported by BIOS */
+               val = val & 0x3;
+               force_hpet_address = 0xFED00000 | (val << 12);
+               printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n",
+                              force_hpet_address);
+               iounmap(rcba_base);
+               return;
+       }
+
+       /* HPET disabled in HPTC. Trying to enable */
+       writel(val | 0x80, rcba_base + 0x3404);
+
+       val = readl(rcba_base + 0x3404);
+       if (!(val & 0x80)) {
+               err = 1;
+       } else {
+               val = val & 0x3;
+               force_hpet_address = 0xFED00000 | (val << 12);
+       }
+
+       if (err) {
+               force_hpet_address = 0;
+               iounmap(rcba_base);
+               printk(KERN_DEBUG "Failed to force enable HPET\n");
+       } else {
+               force_hpet_resume_type = ICH_FORCE_HPET_RESUME;
+               printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n",
+                              force_hpet_address);
+       }
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_0,
+                         ich_force_enable_hpet);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1,
+                         ich_force_enable_hpet);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0,
+                         ich_force_enable_hpet);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1,
+                         ich_force_enable_hpet);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31,
+                         ich_force_enable_hpet);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_1,
+                         ich_force_enable_hpet);
+
+
+static struct pci_dev *cached_dev;
+
+static void old_ich_force_hpet_resume(void)
+{
+       u32 val;
+       u32 uninitialized_var(gen_cntl);
+
+       if (!force_hpet_address || !cached_dev)
+               return;
+
+       pci_read_config_dword(cached_dev, 0xD0, &gen_cntl);
+       gen_cntl &= (~(0x7 << 15));
+       gen_cntl |= (0x4 << 15);
+
+       pci_write_config_dword(cached_dev, 0xD0, gen_cntl);
+       pci_read_config_dword(cached_dev, 0xD0, &gen_cntl);
+       val = gen_cntl >> 15;
+       val &= 0x7;
+       if (val == 0x4)
+               printk(KERN_DEBUG "Force enabled HPET at resume\n");
+       else
+               BUG();
+}
+
+static void old_ich_force_enable_hpet(struct pci_dev *dev)
+{
+       u32 val;
+       u32 uninitialized_var(gen_cntl);
+
+       if (hpet_address || force_hpet_address)
+               return;
+
+       pci_read_config_dword(dev, 0xD0, &gen_cntl);
+       /*
+        * Bit 17 is HPET enable bit.
+        * Bit 16:15 control the HPET base address.
+        */
+       val = gen_cntl >> 15;
+       val &= 0x7;
+       if (val & 0x4) {
+               val &= 0x3;
+               force_hpet_address = 0xFED00000 | (val << 12);
+               printk(KERN_DEBUG "HPET at base address 0x%lx\n",
+                              force_hpet_address);
+               return;
+       }
+
+       /*
+        * HPET is disabled. Trying enabling at FED00000 and check
+        * whether it sticks
+        */
+       gen_cntl &= (~(0x7 << 15));
+       gen_cntl |= (0x4 << 15);
+       pci_write_config_dword(dev, 0xD0, gen_cntl);
+
+       pci_read_config_dword(dev, 0xD0, &gen_cntl);
+
+       val = gen_cntl >> 15;
+       val &= 0x7;
+       if (val & 0x4) {
+               /* HPET is enabled in HPTC. Just not reported by BIOS */
+               val &= 0x3;
+               force_hpet_address = 0xFED00000 | (val << 12);
+               printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n",
+                              force_hpet_address);
+               cached_dev = dev;
+               force_hpet_resume_type = OLD_ICH_FORCE_HPET_RESUME;
+               return;
+       }
+
+       printk(KERN_DEBUG "Failed to force enable HPET\n");
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0,
+                         old_ich_force_enable_hpet);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_12,
+                         old_ich_force_enable_hpet);
+
+void force_hpet_resume(void)
+{
+       switch (force_hpet_resume_type) {
+           case ICH_FORCE_HPET_RESUME:
+               return ich_force_hpet_resume();
+
+           case OLD_ICH_FORCE_HPET_RESUME:
+               return old_ich_force_hpet_resume();
+
+           default:
+               break;
+       }
+}
+
+#endif
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 03e1cce58f499a3712e2e9957a3ef1781d490f2f..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:
@@ -11,6 +9,7 @@
 
 #include <asm/delay.h>
 #include <linux/pci.h>
+#include <linux/interrupt.h>
 #include <asm/reboot_fixups.h>
 #include <asm/msr.h>
 
@@ -56,6 +55,11 @@ void mach_reboot_fixups(void)
        struct pci_dev *dev;
        int i;
 
+       /* we can be called from sysrq-B code. In such a case it is
+        * prohibited to dig PCI */
+       if (in_interrupt())
+               return;
+
        for (i=0; i < ARRAY_SIZE(fixups_table); i++) {
                cur = &(fixups_table[i]);
                dev = pci_get_device(cur->vendor, cur->device, NULL);
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 af838f6b0b7fc9b7e3ed4de0ab12992e48cf9f18..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.
  */
 
 /*
@@ -546,6 +541,37 @@ static void __init amd_detect_cmp(struct cpuinfo_x86 *c)
 #endif
 }
 
+#define ENABLE_C1E_MASK                0x18000000
+#define CPUID_PROCESSOR_SIGNATURE      1
+#define CPUID_XFAM             0x0ff00000
+#define CPUID_XFAM_K8          0x00000000
+#define CPUID_XFAM_10H         0x00100000
+#define CPUID_XFAM_11H         0x00200000
+#define CPUID_XMOD             0x000f0000
+#define CPUID_XMOD_REV_F       0x00040000
+
+/* AMD systems with C1E don't have a working lAPIC timer. Check for that. */
+static __cpuinit int amd_apic_timer_broken(void)
+{
+       u32 lo, hi;
+       u32 eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
+       switch (eax & CPUID_XFAM) {
+       case CPUID_XFAM_K8:
+               if ((eax & CPUID_XMOD) < CPUID_XMOD_REV_F)
+                       break;
+       case CPUID_XFAM_10H:
+       case CPUID_XFAM_11H:
+               rdmsr(MSR_K8_ENABLE_C1E, lo, hi);
+               if (lo & ENABLE_C1E_MASK)
+                       return 1;
+               break;
+       default:
+               /* err on the side of caution */
+               return 1;
+       }
+       return 0;
+}
+
 static void __cpuinit init_amd(struct cpuinfo_x86 *c)
 {
        unsigned level;
@@ -617,6 +643,9 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
        /* Family 10 doesn't support C states in MWAIT so don't use it */
        if (c->x86 == 0x10 && !force_mwait)
                clear_bit(X86_FEATURE_MWAIT, &c->x86_capability);
+
+       if (amd_apic_timer_broken())
+               disable_apic_timer = 1;
 }
 
 static void __cpuinit detect_ht(struct cpuinfo_x86 *c)
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 32f50783edc812e4d5d6618bb754d2051d3cea38..720a7d1f8862be153b8e356e582c57727cbdaaef 100644 (file)
@@ -223,8 +223,6 @@ void __cpuinit smp_callin(void)
        local_irq_disable();
        Dprintk("Stack at about %p\n",&cpuid);
 
-       disable_APIC_timer();
-
        /*
         * Save our processor parameters
         */
@@ -337,19 +335,12 @@ 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);
                enable_8259A_irq(0);
        }
 
-       enable_APIC_timer();
-
        /*
         * The sibling maps must be set before turing the online map on for
         * this cpu
@@ -378,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 19a6c678d02ecc1448cff0bf0b6f03b997d478c0..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:
@@ -157,6 +155,9 @@ EXPORT_SYMBOL(profile_pc);
  */
 irqreturn_t timer_interrupt(int irq, void *dev_id)
 {
+       /* Keep nmi watchdog up to date */
+       per_cpu(irq_stat, smp_processor_id()).irq0_irqs++;
+
 #ifdef CONFIG_X86_IO_APIC
        if (timer_ack) {
                /*
index 6d48a4e826d9d1f27dc0cf6a76b0d98b8ba3ffbb..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
 #include <linux/cpu.h>
 #include <linux/kallsyms.h>
 #include <linux/acpi.h>
+#include <linux/clockchips.h>
+
 #ifdef CONFIG_ACPI
 #include <acpi/achware.h>      /* for PM timer frequency */
 #include <acpi/acpi_bus.h>
 #endif
-#include <asm/8253pit.h>
 #include <asm/i8253.h>
 #include <asm/pgtable.h>
 #include <asm/vsyscall.h>
 #include <asm/nmi.h>
 #include <asm/vgtod.h>
 
-static char *timename = NULL;
-
 DEFINE_SPINLOCK(rtc_lock);
 EXPORT_SYMBOL(rtc_lock);
-DEFINE_SPINLOCK(i8253_lock);
-EXPORT_SYMBOL(i8253_lock);
 
 volatile unsigned long __jiffies __section_jiffies = INITIAL_JIFFIES;
 
@@ -153,45 +148,12 @@ int update_persistent_clock(struct timespec now)
        return set_rtc_mmss(now.tv_sec);
 }
 
-void main_timer_handler(void)
+static irqreturn_t timer_event_interrupt(int irq, void *dev_id)
 {
-/*
- * Here we are in the timer irq handler. We have irqs locally disabled (so we
- * don't need spin_lock_irqsave()) but we don't know if the timer_bh is running
- * on the other CPU, so we need a lock. We also need to lock the vsyscall
- * variables, because both do_timer() and us change them -arca+vojtech
- */
-
-       write_seqlock(&xtime_lock);
-
-/*
- * Do the timer stuff.
- */
+       add_pda(irq0_irqs, 1);
 
-       do_timer(1);
-#ifndef CONFIG_SMP
-       update_process_times(user_mode(get_irq_regs()));
-#endif
-
-/*
- * In the SMP case we use the local APIC timer interrupt to do the profiling,
- * except when we simulate SMP mode on a uniprocessor system, in that case we
- * have to call the local interrupt handler.
- */
-
-       if (!using_apic_timer)
-               smp_local_timer_interrupt();
+       global_clock_event->event_handler(global_clock_event);
 
-       write_sequnlock(&xtime_lock);
-}
-
-static irqreturn_t timer_interrupt(int irq, void *dev_id)
-{
-       if (apic_runs_main_timer > 1)
-               return IRQ_HANDLED;
-       main_timer_handler();
-       if (using_apic_timer)
-               smp_send_timer_broadcast_ipi();
        return IRQ_HANDLED;
 }
 
@@ -292,97 +254,21 @@ static unsigned int __init tsc_calibrate_cpu_khz(void)
        return pmc_now * tsc_khz / (tsc_now - tsc_start);
 }
 
-/*
- * pit_calibrate_tsc() uses the speaker output (channel 2) of
- * the PIT. This is better than using the timer interrupt output,
- * because we can read the value of the speaker with just one inb(),
- * where we need three i/o operations for the interrupt channel.
- * We count how many ticks the TSC does in 50 ms.
- */
-
-static unsigned int __init pit_calibrate_tsc(void)
-{
-       unsigned long start, end;
-       unsigned long flags;
-
-       spin_lock_irqsave(&i8253_lock, flags);
-
-       outb((inb(0x61) & ~0x02) | 0x01, 0x61);
-
-       outb(0xb0, 0x43);
-       outb((PIT_TICK_RATE / (1000 / 50)) & 0xff, 0x42);
-       outb((PIT_TICK_RATE / (1000 / 50)) >> 8, 0x42);
-       start = get_cycles_sync();
-       while ((inb(0x61) & 0x20) == 0);
-       end = get_cycles_sync();
-
-       spin_unlock_irqrestore(&i8253_lock, flags);
-
-       return (end - start) / 50;
-}
-
-#define PIT_MODE 0x43
-#define PIT_CH0  0x40
-
-static void __pit_init(int val, u8 mode)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&i8253_lock, flags);
-       outb_p(mode, PIT_MODE);
-       outb_p(val & 0xff, PIT_CH0);    /* LSB */
-       outb_p(val >> 8, PIT_CH0);      /* MSB */
-       spin_unlock_irqrestore(&i8253_lock, flags);
-}
-
-void __init pit_init(void)
-{
-       __pit_init(LATCH, 0x34); /* binary, mode 2, LSB/MSB, ch 0 */
-}
-
-void pit_stop_interrupt(void)
-{
-       __pit_init(0, 0x30); /* mode 0 */
-}
-
-void stop_timer_interrupt(void)
-{
-       char *name;
-       if (hpet_address) {
-               name = "HPET";
-               hpet_timer_stop_set_go(0);
-       } else {
-               name = "PIT";
-               pit_stop_interrupt();
-       }
-       printk(KERN_INFO "timer: %s interrupt stopped.\n", name);
-}
-
 static struct irqaction irq0 = {
-       .handler        = timer_interrupt,
-       .flags          = IRQF_DISABLED | IRQF_IRQPOLL,
+       .handler        = timer_event_interrupt,
+       .flags          = IRQF_DISABLED | IRQF_IRQPOLL | IRQF_NOBALANCING,
        .mask           = CPU_MASK_NONE,
        .name           = "timer"
 };
 
 void __init time_init(void)
 {
-       if (nohpet)
-               hpet_address = 0;
+       if (!hpet_enable())
+               setup_pit_timer();
 
-       if (hpet_arch_init())
-               hpet_address = 0;
+       setup_irq(0, &irq0);
 
-       if (hpet_use_timer) {
-               /* set tick_nsec to use the proper rate for HPET */
-               tick_nsec = TICK_NSEC_HPET;
-               tsc_khz = hpet_calibrate_tsc();
-               timename = "HPET";
-       } else {
-               pit_init();
-               tsc_khz = pit_calibrate_tsc();
-               timename = "PIT";
-       }
+       tsc_calibrate();
 
        cpu_khz = tsc_khz;
        if (cpu_has(&boot_cpu_data, X86_FEATURE_CONSTANT_TSC) &&
@@ -398,50 +284,7 @@ void __init time_init(void)
        else
                vgetcpu_mode = VGETCPU_LSL;
 
-       set_cyc2ns_scale(tsc_khz);
        printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n",
                cpu_khz / 1000, cpu_khz % 1000);
        init_tsc_clocksource();
-
-       setup_irq(0, &irq0);
-}
-
-/*
- * sysfs support for the timer.
- */
-
-static int timer_suspend(struct sys_device *dev, pm_message_t state)
-{
-       return 0;
-}
-
-static int timer_resume(struct sys_device *dev)
-{
-       if (hpet_address)
-               hpet_reenable();
-       else
-               i8254_timer_resume();
-       return 0;
 }
-
-static struct sysdev_class timer_sysclass = {
-       .resume = timer_resume,
-       .suspend = timer_suspend,
-       set_kset_name("timer"),
-};
-
-/* XXX this sysfs stuff should probably go elsewhere later -john */
-static struct sys_device device_timer = {
-       .id     = 0,
-       .cls    = &timer_sysclass,
-};
-
-static int time_init_device(void)
-{
-       int error = sysdev_class_register(&timer_sysclass);
-       if (!error)
-               error = sysdev_register(&device_timer);
-       return error;
-}
-
-device_initcall(time_init_device);
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 2a59bde663f2f1c2b32028f141603bfdab1f38ca..9f22e542c37409e84967b4903f4a24bb7db56dfd 100644 (file)
@@ -6,7 +6,9 @@
 #include <linux/time.h>
 #include <linux/acpi.h>
 #include <linux/cpufreq.h>
+#include <linux/acpi_pmtmr.h>
 
+#include <asm/hpet.h>
 #include <asm/timex.h>
 
 static int notsc __initdata = 0;
@@ -18,7 +20,7 @@ EXPORT_SYMBOL(tsc_khz);
 
 static unsigned int cyc2ns_scale __read_mostly;
 
-void set_cyc2ns_scale(unsigned long khz)
+static inline void set_cyc2ns_scale(unsigned long khz)
 {
        cyc2ns_scale = (NSEC_PER_MSEC << NS_SCALE) / khz;
 }
@@ -118,6 +120,95 @@ core_initcall(cpufreq_tsc);
 
 #endif
 
+#define MAX_RETRIES    5
+#define SMI_TRESHOLD   50000
+
+/*
+ * Read TSC and the reference counters. Take care of SMI disturbance
+ */
+static unsigned long __init tsc_read_refs(unsigned long *pm,
+                                         unsigned long *hpet)
+{
+       unsigned long t1, t2;
+       int i;
+
+       for (i = 0; i < MAX_RETRIES; i++) {
+               t1 = get_cycles_sync();
+               if (hpet)
+                       *hpet = hpet_readl(HPET_COUNTER) & 0xFFFFFFFF;
+               else
+                       *pm = acpi_pm_read_early();
+               t2 = get_cycles_sync();
+               if ((t2 - t1) < SMI_TRESHOLD)
+                       return t2;
+       }
+       return ULONG_MAX;
+}
+
+/**
+ * tsc_calibrate - calibrate the tsc on boot
+ */
+void __init tsc_calibrate(void)
+{
+       unsigned long flags, tsc1, tsc2, tr1, tr2, pm1, pm2, hpet1, hpet2;
+       int hpet = is_hpet_enabled();
+
+       local_irq_save(flags);
+
+       tsc1 = tsc_read_refs(&pm1, hpet ? &hpet1 : NULL);
+
+       outb((inb(0x61) & ~0x02) | 0x01, 0x61);
+
+       outb(0xb0, 0x43);
+       outb((CLOCK_TICK_RATE / (1000 / 50)) & 0xff, 0x42);
+       outb((CLOCK_TICK_RATE / (1000 / 50)) >> 8, 0x42);
+       tr1 = get_cycles_sync();
+       while ((inb(0x61) & 0x20) == 0);
+       tr2 = get_cycles_sync();
+
+       tsc2 = tsc_read_refs(&pm2, hpet ? &hpet2 : NULL);
+
+       local_irq_restore(flags);
+
+       /*
+        * Preset the result with the raw and inaccurate PIT
+        * calibration value
+        */
+       tsc_khz = (tr2 - tr1) / 50;
+
+       /* hpet or pmtimer available ? */
+       if (!hpet && !pm1 && !pm2) {
+               printk(KERN_INFO "TSC calibrated against PIT\n");
+               return;
+       }
+
+       /* Check, whether the sampling was disturbed by an SMI */
+       if (tsc1 == ULONG_MAX || tsc2 == ULONG_MAX) {
+               printk(KERN_WARNING "TSC calibration disturbed by SMI, "
+                      "using PIT calibration result\n");
+               return;
+       }
+
+       tsc2 = (tsc2 - tsc1) * 1000000L;
+
+       if (hpet) {
+               printk(KERN_INFO "TSC calibrated against HPET\n");
+               if (hpet2 < hpet1)
+                       hpet2 += 0x100000000;
+               hpet2 -= hpet1;
+               tsc1 = (hpet2 * hpet_readl(HPET_PERIOD)) / 1000000;
+       } else {
+               printk(KERN_INFO "TSC calibrated against PM_TIMER\n");
+               if (pm2 < pm1)
+                       pm2 += ACPI_PM_OVRRUN;
+               pm2 -= pm1;
+               tsc1 = (pm2 * 1000000000) / PMTMR_TICKS_PER_SEC;
+       }
+
+       tsc_khz = tsc2 / tsc1;
+       set_cyc2ns_scale(tsc_khz);
+}
+
 /*
  * Make an educated guess if the TSC is trustworthy and synchronized
  * over all CPUs.
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 bc8a44bddaa7b7f8ab83638fbfa38231d631349b..2d88f7c6d6ac901a3f2f2ffe2f64f680706b435a 100644 (file)
 #include <linux/acpi.h>
 #include <linux/init.h>
 #include <linux/irq.h>
+#include <linux/dmi.h>
 #include <asm/numa.h>
 #include "pci.h"
 
+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);
+       return 0;
+}
+
+static struct dmi_system_id acpi_pciprobe_dmi_table[] = {
+/*
+ * Systems where PCI IO resource ISA alignment can be skipped
+ * when the ISA enable bit in the bridge control is not set
+ */
+       {
+               .callback = can_skip_ioresource_align,
+               .ident = "IBM System x3800",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "IBM"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "x3800"),
+               },
+       },
+       {
+               .callback = can_skip_ioresource_align,
+               .ident = "IBM System x3850",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "IBM"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "x3850"),
+               },
+       },
+       {
+               .callback = can_skip_ioresource_align,
+               .ident = "IBM System x3950",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "IBM"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "x3950"),
+               },
+       },
+       {}
+};
+
+struct pci_root_info {
+       char *name;
+       unsigned int res_num;
+       struct resource *res;
+       struct pci_bus *bus;
+       int busnum;
+};
+
+static acpi_status
+resource_to_addr(struct acpi_resource *resource,
+                       struct acpi_resource_address64 *addr)
+{
+       acpi_status status;
+
+       status = acpi_resource_to_address64(resource, addr);
+       if (ACPI_SUCCESS(status) &&
+           (addr->resource_type == ACPI_MEMORY_RANGE ||
+           addr->resource_type == ACPI_IO_RANGE) &&
+           addr->address_length > 0 &&
+           addr->producer_consumer == ACPI_PRODUCER) {
+               return AE_OK;
+       }
+       return AE_ERROR;
+}
+
+static acpi_status
+count_resource(struct acpi_resource *acpi_res, void *data)
+{
+       struct pci_root_info *info = data;
+       struct acpi_resource_address64 addr;
+       acpi_status status;
+
+       status = resource_to_addr(acpi_res, &addr);
+       if (ACPI_SUCCESS(status))
+               info->res_num++;
+       return AE_OK;
+}
+
+static acpi_status
+setup_resource(struct acpi_resource *acpi_res, void *data)
+{
+       struct pci_root_info *info = data;
+       struct resource *res;
+       struct acpi_resource_address64 addr;
+       acpi_status status;
+       unsigned long flags;
+       struct resource *root;
+
+       status = resource_to_addr(acpi_res, &addr);
+       if (!ACPI_SUCCESS(status))
+               return AE_OK;
+
+       if (addr.resource_type == ACPI_MEMORY_RANGE) {
+               root = &iomem_resource;
+               flags = IORESOURCE_MEM;
+               if (addr.info.mem.caching == ACPI_PREFETCHABLE_MEMORY)
+                       flags |= IORESOURCE_PREFETCH;
+       } else if (addr.resource_type == ACPI_IO_RANGE) {
+               root = &ioport_resource;
+               flags = IORESOURCE_IO;
+       } else
+               return AE_OK;
+
+       res = &info->res[info->res_num];
+       res->name = info->name;
+       res->flags = flags;
+       res->start = addr.minimum + addr.translation_offset;
+       res->end = res->start + addr.address_length - 1;
+       res->child = NULL;
+
+       if (insert_resource(root, res)) {
+               printk(KERN_ERR "PCI: Failed to allocate 0x%lx-0x%lx "
+                       "from %s for %s\n", (unsigned long) res->start,
+                       (unsigned long) res->end, root->name, info->name);
+       } else {
+               info->bus->resource[info->res_num] = res;
+               info->res_num++;
+       }
+       return AE_OK;
+}
+
+static void
+adjust_transparent_bridge_resources(struct pci_bus *bus)
+{
+       struct pci_dev *dev;
+
+       list_for_each_entry(dev, &bus->devices, bus_list) {
+               int i;
+               u16 class = dev->class >> 8;
+
+               if (class == PCI_CLASS_BRIDGE_PCI && dev->transparent) {
+                       for(i = 3; i < PCI_BUS_NUM_RESOURCES; i++)
+                               dev->subordinate->resource[i] =
+                                               dev->bus->resource[i - 3];
+               }
+       }
+}
+
+static void
+get_current_resources(struct acpi_device *device, int busnum,
+                       struct pci_bus *bus)
+{
+       struct pci_root_info info;
+       size_t size;
+
+       info.bus = bus;
+       info.res_num = 0;
+       acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_resource,
+                               &info);
+       if (!info.res_num)
+               return;
+
+       size = sizeof(*info.res) * info.res_num;
+       info.res = kmalloc(size, GFP_KERNEL);
+       if (!info.res)
+               goto res_alloc_fail;
+
+       info.name = kmalloc(12, GFP_KERNEL);
+       if (!info.name)
+               goto name_alloc_fail;
+       sprintf(info.name, "PCI Bus #%02x", busnum);
+
+       info.res_num = 0;
+       acpi_walk_resources(device->handle, METHOD_NAME__CRS, setup_resource,
+                               &info);
+       if (info.res_num)
+               adjust_transparent_bridge_resources(bus);
+
+       return;
+
+name_alloc_fail:
+       kfree(info.res);
+res_alloc_fail:
+       return;
+}
+
 struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int domain, int busnum)
 {
        struct pci_bus *bus;
        struct pci_sysdata *sd;
        int pxm;
 
+       dmi_check_system(acpi_pciprobe_dmi_table);
+
+       if (domain && !pci_domains_supported) {
+               printk(KERN_WARNING "PCI: Multiple domains not supported "
+                      "(dom %d, bus %d)\n", domain, busnum);
+               return NULL;
+       }
+
        /* Allocate per-root-bus (not per bus) arch-specific data.
         * TODO: leak; this memory is never freed.
         * It's arguable whether it's worth the trouble to care.
@@ -21,12 +205,7 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do
                return NULL;
        }
 
-       if (domain != 0) {
-               printk(KERN_WARNING "PCI: Multiple domains not supported\n");
-               kfree(sd);
-               return NULL;
-       }
-
+       sd->domain = domain;
        sd->node = -1;
 
        pxm = acpi_get_pxm(device->handle);
@@ -47,6 +226,9 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do
                }
        }
 #endif
+
+       if (bus && (pci_probe & PCI_USE__CRS))
+               get_current_resources(device, busnum, bus);
        
        return bus;
 }
index 07d5223442bf2ca09073fd7b4e84312a239f37ef..2d71bbc411d2f049b824cc275948ddea5e61754f 100644 (file)
@@ -29,12 +29,14 @@ struct pci_raw_ops *raw_pci_ops;
 
 static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value)
 {
-       return raw_pci_ops->read(0, bus->number, devfn, where, size, value);
+       return raw_pci_ops->read(pci_domain_nr(bus), bus->number,
+                                devfn, where, size, value);
 }
 
 static int pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value)
 {
-       return raw_pci_ops->write(0, bus->number, devfn, where, size, value);
+       return raw_pci_ops->write(pci_domain_nr(bus), bus->number,
+                                 devfn, where, size, value);
 }
 
 struct pci_ops pci_root_ops = {
@@ -287,6 +289,16 @@ static struct dmi_system_id __devinitdata pciprobe_dmi_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL685c G1"),
                },
        },
+#ifdef __i386__
+       {
+               .callback = assign_all_busses,
+               .ident = "Compaq EVO N800c",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Compaq"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "EVO N800c"),
+               },
+       },
+#endif
        {}
 };
 
@@ -426,6 +438,9 @@ char * __devinit  pcibios_setup(char *str)
        } else if (!strcmp(str, "assign-busses")) {
                pci_probe |= PCI_ASSIGN_ALL_BUSSES;
                return NULL;
+       } else if (!strcmp(str, "use_crs")) {
+               pci_probe |= PCI_USE__CRS;
+               return NULL;
        } else if (!strcmp(str, "routeirq")) {
                pci_routeirq = 1;
                return NULL;
index c82cbf4c7226ec65a4acd21c68669279dc761c33..6cff66dd0c91ac6d071701dd3f92e95a59d62da7 100644 (file)
@@ -353,6 +353,53 @@ static void __devinit pci_fixup_video(struct pci_dev *pdev)
 }
 DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_video);
 
+
+static struct dmi_system_id __devinitdata msi_k8t_dmi_table[] = {
+       {
+               .ident = "MSI-K8T-Neo2Fir",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "MSI"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MS-6702E"),
+               },
+       },
+       {}
+};
+
+/*
+ * The AMD-Athlon64 board MSI "K8T Neo2-FIR" disables the onboard sound
+ * card if a PCI-soundcard is added.
+ *
+ * The BIOS only gives options "DISABLED" and "AUTO". This code sets
+ * the corresponding register-value to enable the soundcard.
+ *
+ * The soundcard is only enabled, if the mainborad is identified
+ * via DMI-tables and the soundcard is detected to be off.
+ */
+static void __devinit pci_fixup_msi_k8t_onboard_sound(struct pci_dev *dev)
+{
+       unsigned char val;
+       if (!dmi_check_system(msi_k8t_dmi_table))
+               return; /* only applies to MSI K8T Neo2-FIR */
+
+       pci_read_config_byte(dev, 0x50, &val);
+       if (val & 0x40) {
+               pci_write_config_byte(dev, 0x50, val & (~0x40));
+
+               /* verify the change for status output */
+               pci_read_config_byte(dev, 0x50, &val);
+               if (val & 0x40)
+                       printk(KERN_INFO "PCI: Detected MSI K8T Neo2-FIR, "
+                                       "can't enable onboard soundcard!\n");
+               else
+                       printk(KERN_INFO "PCI: Detected MSI K8T Neo2-FIR, "
+                                       "enabled onboard soundcard.\n");
+       }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237,
+               pci_fixup_msi_k8t_onboard_sound);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237,
+               pci_fixup_msi_k8t_onboard_sound);
+
 /*
  * Some Toshiba laptops need extra code to enable their TI TSB43AB22/A.
  *
index bcd2f94b732c59ebd998cad10dd64225d8283303..42ba0e2da1a05235f4cade3b9c12315f4eca5134 100644 (file)
 
 #include "pci.h"
 
+static int
+skip_isa_ioresource_align(struct pci_dev *dev) {
+
+       if ((pci_probe & PCI_CAN_SKIP_ISA_ALIGN) &&
+           !(dev->bus->bridge_ctl & PCI_BRIDGE_CTL_ISA))
+               return 1;
+       return 0;
+}
+
 /*
  * We need to avoid collisions with `mirrored' VGA ports
  * and other strange ISA hardware, so we always want the
@@ -50,9 +59,13 @@ void
 pcibios_align_resource(void *data, struct resource *res,
                        resource_size_t size, resource_size_t align)
 {
+       struct pci_dev *dev = data;
+
        if (res->flags & IORESOURCE_IO) {
                resource_size_t start = res->start;
 
+               if (skip_isa_ioresource_align(dev))
+                       return;
                if (start & 0x300) {
                        start = (start + 0x3ff) & ~0x3ff;
                        res->start = start;
index d98c6b096f8e34e7c4877521bf69fa5b9dff400d..c52150fdf82b51015515c1a7bb3716be515a7ef7 100644 (file)
@@ -492,6 +492,26 @@ static int pirq_amd756_set(struct pci_dev *router, struct pci_dev *dev, int pirq
        return 1;
 }
 
+/*
+ * PicoPower PT86C523
+ */
+static int pirq_pico_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+       outb(0x10 + ((pirq - 1) >> 1), 0x24);
+       return ((pirq - 1) & 1) ? (inb(0x26) >> 4) : (inb(0x26) & 0xf);
+}
+
+static int pirq_pico_set(struct pci_dev *router, struct pci_dev *dev, int pirq,
+                       int irq)
+{
+       unsigned int x;
+       outb(0x10 + ((pirq - 1) >> 1), 0x24);
+       x = inb(0x26);
+       x = ((pirq - 1) & 1) ? ((x & 0x0f) | (irq << 4)) : ((x & 0xf0) | (irq));
+       outb(x, 0x26);
+       return 1;
+}
+
 #ifdef CONFIG_PCI_BIOS
 
 static int pirq_bios_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
@@ -721,6 +741,24 @@ static __init int amd_router_probe(struct irq_router *r, struct pci_dev *router,
        return 1;
 }
                
+static __init int pico_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
+{
+       switch (device) {
+       case PCI_DEVICE_ID_PICOPOWER_PT86C523:
+               r->name = "PicoPower PT86C523";
+               r->get = pirq_pico_get;
+               r->set = pirq_pico_set;
+               return 1;
+
+       case PCI_DEVICE_ID_PICOPOWER_PT86C523BBP:
+               r->name = "PicoPower PT86C523 rev. BB+";
+               r->get = pirq_pico_get;
+               r->set = pirq_pico_set;
+               return 1;
+       }
+       return 0;
+}
+
 static __initdata struct irq_router_handler pirq_routers[] = {
        { PCI_VENDOR_ID_INTEL, intel_router_probe },
        { PCI_VENDOR_ID_AL, ali_router_probe },
@@ -732,6 +770,7 @@ static __initdata struct irq_router_handler pirq_routers[] = {
        { PCI_VENDOR_ID_VLSI, vlsi_router_probe },
        { PCI_VENDOR_ID_SERVERWORKS, serverworks_router_probe },
        { PCI_VENDOR_ID_AMD, amd_router_probe },
+       { PCI_VENDOR_ID_PICOPOWER, pico_router_probe },
        /* Someone with docs needs to add the ATI Radeon IGP */
        { 0, NULL }
 };
index 8c66f275756f9f9ac4dc0d1177b396307fb3a7fc..ac56d3916c50e3491ff6ca0421950a3f3a3efc39 100644 (file)
@@ -26,6 +26,8 @@
 #define PCI_ASSIGN_ROMS                0x1000
 #define PCI_BIOS_IRQ_SCAN      0x2000
 #define PCI_ASSIGN_ALL_BUSSES  0x4000
+#define PCI_CAN_SKIP_ISA_ALIGN 0x8000
+#define PCI_USE__CRS           0x10000
 
 extern unsigned int pci_probe;
 extern unsigned long pirq_table_addr;
index b1b98e614f7cd2982ae9646c2b6188d234d233d4..cf013cb85ea4c86dfcd65da4418d8f7a0e910978 100644 (file)
@@ -36,6 +36,18 @@ config GENERIC_CMOS_UPDATE
        bool
        default y
 
+config CLOCKSOURCE_WATCHDOG
+       bool
+       default y
+
+config GENERIC_CLOCKEVENTS
+       bool
+       default y
+
+config GENERIC_CLOCKEVENTS_BROADCAST
+       bool
+       default y
+
 config ZONE_DMA32
        bool
        default y
@@ -130,6 +142,8 @@ source "init/Kconfig"
 
 menu "Processor type and features"
 
+source "kernel/time/Kconfig"
+
 choice
        prompt "Subarchitecture Type"
        default X86_PC
@@ -724,6 +738,11 @@ config PCI_MMCONFIG
        bool "Support mmconfig PCI config space access"
        depends on PCI && ACPI
 
+config PCI_DOMAINS
+       bool
+       depends on PCI
+       default y
+
 source "drivers/pci/pcie/Kconfig"
 
 source "drivers/pci/Kconfig"
index 2484e0e9d89c9127c0678052b18bfa879b8a827d..9bda7bc80307f2a69c06a0c46819c0a10d5321e2 100644 (file)
@@ -64,4 +64,9 @@ config BLK_DEV_BSG
 
 endif # BLOCK
 
+config BLOCK_COMPAT
+       bool
+       depends on BLOCK && COMPAT
+       default y
+
 source block/Kconfig.iosched
index 3cfe7cebaa6ad3222eb3161367101b755dccd79d..826108190f00d3ed9afc1cba7869424584cd6dd4 100644 (file)
@@ -11,4 +11,4 @@ obj-$(CONFIG_IOSCHED_DEADLINE)        += deadline-iosched.o
 obj-$(CONFIG_IOSCHED_CFQ)      += cfq-iosched.o
 
 obj-$(CONFIG_BLK_DEV_IO_TRACE) += blktrace.o
-obj-$(CONFIG_COMPAT)           += compat_ioctl.o
+obj-$(CONFIG_BLOCK_COMPAT)     += compat_ioctl.o
index ed264682723465793f0c947143e4a9fcd7ed5c93..b8ddfc66f210aac023479291a95ea1627f396950 100644 (file)
@@ -1010,10 +1010,7 @@ unlock:
 }
 EXPORT_SYMBOL_GPL(bsg_register_queue);
 
-static struct cdev bsg_cdev = {
-       .kobj   = {.name = "bsg", },
-       .owner  = THIS_MODULE,
-};
+static struct cdev bsg_cdev;
 
 static int __init bsg_init(void)
 {
index c6d153de9fd68ba33fcfb9cc65c00deb35623e8b..b9c518afe1f8bf61907999f56844c5583a9d0a43 100644 (file)
@@ -186,7 +186,7 @@ static elevator_t *elevator_alloc(struct request_queue *q,
        eq->ops = &e->ops;
        eq->elevator_type = e;
        kobject_init(&eq->kobj);
-       snprintf(eq->kobj.name, KOBJ_NAME_LEN, "%s", "iosched");
+       kobject_set_name(&eq->kobj, "%s", "iosched");
        eq->kobj.ktype = &elv_ktype;
        mutex_init(&eq->sysfs_lock);
 
index 3af1e7a378d4162bad38f46825bf055d3e56b38b..e609996f2e766d7009d5984aa8b4fbc29c813bbf 100644 (file)
@@ -540,61 +540,42 @@ static int block_uevent_filter(struct kset *kset, struct kobject *kobj)
        return ((ktype == &ktype_block) || (ktype == &ktype_part));
 }
 
-static int block_uevent(struct kset *kset, struct kobject *kobj, char **envp,
-                        int num_envp, char *buffer, int buffer_size)
+static int block_uevent(struct kset *kset, struct kobject *kobj,
+                       struct kobj_uevent_env *env)
 {
        struct kobj_type *ktype = get_ktype(kobj);
        struct device *physdev;
        struct gendisk *disk;
        struct hd_struct *part;
-       int length = 0;
-       int i = 0;
 
        if (ktype == &ktype_block) {
                disk = container_of(kobj, struct gendisk, kobj);
-               add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
-                              &length, "MINOR=%u", disk->first_minor);
+               add_uevent_var(env, "MINOR=%u", disk->first_minor);
        } else if (ktype == &ktype_part) {
                disk = container_of(kobj->parent, struct gendisk, kobj);
                part = container_of(kobj, struct hd_struct, kobj);
-               add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
-                              &length, "MINOR=%u",
+               add_uevent_var(env, "MINOR=%u",
                               disk->first_minor + part->partno);
        } else
                return 0;
 
-       add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
-                      "MAJOR=%u", disk->major);
+       add_uevent_var(env, "MAJOR=%u", disk->major);
 
        /* add physical device, backing this device  */
        physdev = disk->driverfs_dev;
        if (physdev) {
                char *path = kobject_get_path(&physdev->kobj, GFP_KERNEL);
 
-               add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
-                              &length, "PHYSDEVPATH=%s", path);
+               add_uevent_var(env, "PHYSDEVPATH=%s", path);
                kfree(path);
 
                if (physdev->bus)
-                       add_uevent_var(envp, num_envp, &i,
-                                      buffer, buffer_size, &length,
-                                      "PHYSDEVBUS=%s",
-                                      physdev->bus->name);
+                       add_uevent_var(env, "PHYSDEVBUS=%s", physdev->bus->name);
 
                if (physdev->driver)
-                       add_uevent_var(envp, num_envp, &i,
-                                      buffer, buffer_size, &length,
-                                      "PHYSDEVDRIVER=%s",
-                                      physdev->driver->name);
+                       add_uevent_var(env, physdev->driver->name);
        }
 
-       /* terminate, set to next free slot, shrink available space */
-       envp[i] = NULL;
-       envp = &envp[i];
-       num_envp -= i;
-       buffer = &buffer[length];
-       buffer_size -= length;
-
        return 0;
 }
 
index cd9d2c5d91ae22664081e83136f9da4f3a9aae4c..d875673e76cda569f008a6828e7d52b50d87e3d8 100644 (file)
@@ -1854,7 +1854,7 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
 
        init_timer(&q->unplug_timer);
 
-       snprintf(q->kobj.name, KOBJ_NAME_LEN, "%s", "queue");
+       kobject_set_name(&q->kobj, "%s", "queue");
        q->kobj.ktype = &queue_ktype;
        kobject_init(&q->kobj);
 
index feab124d8e05fd6b356e0e6bd6d5fe508f7355aa..cbfc81579c9af5ddf5760e6ac410174cff203e38 100644 (file)
@@ -194,7 +194,7 @@ int acpi_bus_set_power(acpi_handle handle, int state)
 
        if (!device->flags.power_manageable) {
                ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable\n",
-                               device->dev.kobj.name));
+                               kobject_name(&device->dev.kobj)));
                return -ENODEV;
        }
        /*
index 1e8287b4f40c5ff0ad16d54d27e926319a52132d..1f6fb38de017fc2c16dcd067b96efec802b1e155 100644 (file)
@@ -276,21 +276,12 @@ static void acpi_timer_check_state(int state, struct acpi_processor *pr,
 
 static void acpi_propagate_timer_broadcast(struct acpi_processor *pr)
 {
-#ifdef CONFIG_GENERIC_CLOCKEVENTS
        unsigned long reason;
 
        reason = pr->power.timer_broadcast_on_state < INT_MAX ?
                CLOCK_EVT_NOTIFY_BROADCAST_ON : CLOCK_EVT_NOTIFY_BROADCAST_OFF;
 
        clockevents_notify(reason, &pr->id);
-#else
-       cpumask_t mask = cpumask_of_cpu(pr->id);
-
-       if (pr->power.timer_broadcast_on_state < INT_MAX)
-               on_each_cpu(switch_APIC_timer_to_ipi, &mask, 1, 1);
-       else
-               on_each_cpu(switch_ipi_to_APIC_timer, &mask, 1, 1);
-#endif
 }
 
 /* Power(C) State timer broadcast control */
@@ -298,8 +289,6 @@ static void acpi_state_timer_broadcast(struct acpi_processor *pr,
                                       struct acpi_processor_cx *cx,
                                       int broadcast)
 {
-#ifdef CONFIG_GENERIC_CLOCKEVENTS
-
        int state = cx - pr->power.states;
 
        if (state >= pr->power.timer_broadcast_on_state) {
@@ -309,7 +298,6 @@ static void acpi_state_timer_broadcast(struct acpi_processor *pr,
                        CLOCK_EVT_NOTIFY_BROADCAST_EXIT;
                clockevents_notify(reason, &pr->id);
        }
-#endif
 }
 
 #else
index 64620d668742ea8cb3345c0a07d415e96268a3bf..5b4d462117cf915c6e1f2a89d7604ec9ddaa712b 100644 (file)
@@ -319,16 +319,18 @@ static int acpi_bus_match(struct device *dev, struct device_driver *drv)
        return !acpi_match_device_ids(acpi_dev, acpi_drv->ids);
 }
 
-static int acpi_device_uevent(struct device *dev, char **envp, int num_envp,
-                             char *buffer, int buffer_size)
+static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        struct acpi_device *acpi_dev = to_acpi_device(dev);
+       int len;
 
-       strcpy(buffer, "MODALIAS=");
-       if (create_modalias(acpi_dev, buffer + 9, buffer_size - 9) > 0) {
-               envp[0] = buffer;
-               envp[1] = NULL;
-       }
+       if (add_uevent_var(env, "MODALIAS="))
+               return -ENOMEM;
+       len = create_modalias(acpi_dev, &env->buf[env->buflen - 1],
+                             sizeof(env->buf) - env->buflen);
+       if (len >= (sizeof(env->buf) - env->buflen))
+               return -ENOMEM;
+       env->buflen += len;
        return 0;
 }
 
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 d05891f16282338d96d5cf5a5f3f22d30d6cd5c0..b8a2095cb5ee44f3ceea40ccdf7d11c9c9c58ca0 100644 (file)
@@ -316,7 +316,7 @@ static int acpi_video_output_get(struct output_device *od)
 {
        unsigned long state;
        struct acpi_video_device *vd =
-               (struct acpi_video_device *)class_get_devdata(&od->class_dev);
+               (struct acpi_video_device *)dev_get_drvdata(&od->dev);
        acpi_video_device_get_state(vd, &state);
        return (int)state;
 }
@@ -325,7 +325,7 @@ static int acpi_video_output_set(struct output_device *od)
 {
        unsigned long state = od->request_state;
        struct acpi_video_device *vd=
-               (struct acpi_video_device *)class_get_devdata(&od->class_dev);
+               (struct acpi_video_device *)dev_get_drvdata(&od->dev);
        return acpi_video_device_set_state(vd, state);
 }
 
index 268e301775fc69c76c132f89e4a67d220f1fb056..6b94fb7be5f280bbe2a8e5c0ddace6355cae0185 100644 (file)
@@ -44,15 +44,12 @@ static int amba_match(struct device *dev, struct device_driver *drv)
 }
 
 #ifdef CONFIG_HOTPLUG
-static int amba_uevent(struct device *dev, char **envp, int nr_env, char *buf, int bufsz)
+static int amba_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        struct amba_device *pcdev = to_amba_device(dev);
-       int retval = 0, i = 0, len = 0;
+       int retval = 0;
 
-       retval = add_uevent_var(envp, nr_env, &i,
-                               buf, bufsz, &len,
-                               "AMBA_ID=%08x", pcdev->periphid);
-       envp[i] = NULL;
+       retval = add_uevent_var(env, "AMBA_ID=%08x", pcdev->periphid);
        return retval;
 }
 #else
index d8046a113c371ce0dc820f113fbbbb51261fbfcb..4672066167e35ab8e66065f9fdc1450f8e306c9c 100644 (file)
@@ -173,6 +173,15 @@ config SATA_INIC162X
        help
          This option enables support for Initio 162x Serial ATA.
 
+config PATA_ACPI
+       tristate "ACPI firmware driver for PATA"
+       depends on ATA_ACPI
+       help
+         This option enables an ACPI method driver which drives
+         motherboard PATA controller interfaces through the ACPI
+         firmware in the BIOS. This driver can sometimes handle
+         otherwise unsupported hardware.
+
 config PATA_ALI
        tristate "ALi PATA support (Experimental)"
        depends on PCI && EXPERIMENTAL
@@ -192,16 +201,25 @@ config PATA_AMD
          If unsure, say N.
 
 config PATA_ARTOP
-       tristate "ARTOP 6210/6260 PATA support (Experimental)"
-       depends on PCI && EXPERIMENTAL
+       tristate "ARTOP 6210/6260 PATA support"
+       depends on PCI
        help
          This option enables support for ARTOP PATA controllers.
 
          If unsure, say N.
 
+config PATA_AT32
+       tristate "Atmel AVR32 PATA support (Experimental)"
+       depends on AVR32 && PLATFORM_AT32AP && EXPERIMENTAL
+       help
+         This option enables support for the IDE devices on the
+         Atmel AT32AP platform.
+
+         If unsure, say N.
+
 config PATA_ATIIXP
-       tristate "ATI PATA support (Experimental)"
-       depends on PCI && EXPERIMENTAL
+       tristate "ATI PATA support"
+       depends on PCI
        help
          This option enables support for the ATI ATA interfaces
          found on the many ATI chipsets.
@@ -219,8 +237,8 @@ config PATA_CMD640_PCI
          If unsure, say N.
 
 config PATA_CMD64X
-       tristate "CMD64x PATA support (Very Experimental)"
-       depends on PCI&& EXPERIMENTAL
+       tristate "CMD64x PATA support"
+       depends on PCI
        help
          This option enables support for the CMD64x series chips
          except for the CMD640.
@@ -282,8 +300,8 @@ config ATA_GENERIC
          If unsure, say N.
 
 config PATA_HPT366
-       tristate "HPT 366/368 PATA support (Experimental)"
-       depends on PCI && EXPERIMENTAL
+       tristate "HPT 366/368 PATA support"
+       depends on PCI
        help
          This option enables support for the HPT 366 and 368
          PATA controllers via the new ATA layer.
@@ -432,6 +450,15 @@ config PATA_NS87410
 
          If unsure, say N.
 
+config PATA_NS87415
+       tristate "Nat Semi NS87415 PATA support (Experimental)"
+       depends on PCI && EXPERIMENTAL
+       help
+         This option enables support for the National Semiconductor
+         NS87415 PCI-IDE controller.
+
+         If unsure, say N.
+
 config PATA_OPTI
        tristate "OPTI621/6215 PATA support (Very Experimental)"
        depends on PCI && EXPERIMENTAL
@@ -596,4 +623,20 @@ config PATA_SCC
 
          If unsure, say N.
 
+config PATA_BF54X
+       tristate "Blackfin 54x ATAPI support"
+       depends on BF542 || BF548 || BF549
+       help
+         This option enables support for the built-in ATAPI controller on
+         Blackfin 54x family chips.
+
+         If unsure, say N.
+
+config PATA_BF54X_DMA
+       bool "DMA mode"
+       depends on PATA_BF54X
+       default y
+       help
+         Enable DMA mode for Blackfin ATAPI controller.
+
 endif # ATA
index 8149c68ac2c71475d9e88d0fc41c0b63ef38323e..2a63645003eb7eb7242c843fa05b72390413e8fa 100644 (file)
@@ -21,6 +21,7 @@ obj-$(CONFIG_PDC_ADMA)                += pdc_adma.o
 obj-$(CONFIG_PATA_ALI)         += pata_ali.o
 obj-$(CONFIG_PATA_AMD)         += pata_amd.o
 obj-$(CONFIG_PATA_ARTOP)       += pata_artop.o
+obj-$(CONFIG_PATA_AT32)                += pata_at32.o
 obj-$(CONFIG_PATA_ATIIXP)      += pata_atiixp.o
 obj-$(CONFIG_PATA_CMD640_PCI)  += pata_cmd640.o
 obj-$(CONFIG_PATA_CMD64X)      += pata_cmd64x.o
@@ -39,6 +40,7 @@ obj-$(CONFIG_PATA_IT8213)     += pata_it8213.o
 obj-$(CONFIG_PATA_JMICRON)     += pata_jmicron.o
 obj-$(CONFIG_PATA_NETCELL)     += pata_netcell.o
 obj-$(CONFIG_PATA_NS87410)     += pata_ns87410.o
+obj-$(CONFIG_PATA_NS87415)     += pata_ns87415.o
 obj-$(CONFIG_PATA_OPTI)                += pata_opti.o
 obj-$(CONFIG_PATA_OPTIDMA)     += pata_optidma.o
 obj-$(CONFIG_PATA_MPC52xx)     += pata_mpc52xx.o
@@ -61,12 +63,16 @@ obj-$(CONFIG_PATA_SIS)              += pata_sis.o
 obj-$(CONFIG_PATA_TRIFLEX)     += pata_triflex.o
 obj-$(CONFIG_PATA_IXP4XX_CF)   += pata_ixp4xx_cf.o
 obj-$(CONFIG_PATA_SCC)         += pata_scc.o
+obj-$(CONFIG_PATA_BF54X)       += pata_bf54x.o
 obj-$(CONFIG_PATA_PLATFORM)    += pata_platform.o
 obj-$(CONFIG_PATA_ICSIDE)      += pata_icside.o
+# Should be last but two libata driver
+obj-$(CONFIG_PATA_ACPI)                += pata_acpi.o
 # Should be last but one libata driver
 obj-$(CONFIG_ATA_GENERIC)      += ata_generic.o
 # Should be last libata driver
 obj-$(CONFIG_PATA_LEGACY)      += pata_legacy.o
 
-libata-objs    := libata-core.o libata-scsi.o libata-sff.o libata-eh.o
+libata-objs    := libata-core.o libata-scsi.o libata-sff.o libata-eh.o \
+                  libata-pmp.o
 libata-$(CONFIG_ATA_ACPI)      += libata-acpi.o
index c16820325d7bf127fc1989e3dede84665cc3fed6..10bc3f64c453d50896be9178d20879aef65abb1a 100644 (file)
@@ -46,7 +46,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME       "ahci"
-#define DRV_VERSION    "2.3"
+#define DRV_VERSION    "3.0"
 
 
 enum {
@@ -77,11 +77,10 @@ enum {
        RX_FIS_UNK              = 0x60, /* offset of Unknown FIS data */
 
        board_ahci              = 0,
-       board_ahci_pi           = 1,
-       board_ahci_vt8251       = 2,
-       board_ahci_ign_iferr    = 3,
-       board_ahci_sb600        = 4,
-       board_ahci_mv           = 5,
+       board_ahci_vt8251       = 1,
+       board_ahci_ign_iferr    = 2,
+       board_ahci_sb600        = 3,
+       board_ahci_mv           = 4,
 
        /* global controller registers */
        HOST_CAP                = 0x00, /* host capabilities */
@@ -97,6 +96,7 @@ enum {
 
        /* HOST_CAP bits */
        HOST_CAP_SSC            = (1 << 14), /* Slumber capable */
+       HOST_CAP_PMP            = (1 << 17), /* Port Multiplier support */
        HOST_CAP_CLO            = (1 << 24), /* Command List Override support */
        HOST_CAP_SSS            = (1 << 27), /* Staggered Spin-up */
        HOST_CAP_SNTF           = (1 << 29), /* SNotification register */
@@ -144,7 +144,8 @@ enum {
                                  PORT_IRQ_IF_ERR |
                                  PORT_IRQ_CONNECT |
                                  PORT_IRQ_PHYRDY |
-                                 PORT_IRQ_UNK_FIS,
+                                 PORT_IRQ_UNK_FIS |
+                                 PORT_IRQ_BAD_PMP,
        PORT_IRQ_ERROR          = PORT_IRQ_FREEZE |
                                  PORT_IRQ_TF_ERR |
                                  PORT_IRQ_HBUS_DATA_ERR,
@@ -154,6 +155,7 @@ enum {
 
        /* PORT_CMD bits */
        PORT_CMD_ATAPI          = (1 << 24), /* Device is ATAPI */
+       PORT_CMD_PMP            = (1 << 17), /* PMP attached */
        PORT_CMD_LIST_ON        = (1 << 15), /* cmd list DMA engine running */
        PORT_CMD_FIS_ON         = (1 << 14), /* FIS DMA engine running */
        PORT_CMD_FIS_RX         = (1 << 4), /* Enable FIS receive DMA engine */
@@ -167,19 +169,22 @@ enum {
        PORT_CMD_ICC_PARTIAL    = (0x2 << 28), /* Put i/f in partial state */
        PORT_CMD_ICC_SLUMBER    = (0x6 << 28), /* Put i/f in slumber state */
 
+       /* hpriv->flags bits */
+       AHCI_HFLAG_NO_NCQ               = (1 << 0),
+       AHCI_HFLAG_IGN_IRQ_IF_ERR       = (1 << 1), /* ignore IRQ_IF_ERR */
+       AHCI_HFLAG_IGN_SERR_INTERNAL    = (1 << 2), /* ignore SERR_INTERNAL */
+       AHCI_HFLAG_32BIT_ONLY           = (1 << 3), /* force 32bit */
+       AHCI_HFLAG_MV_PATA              = (1 << 4), /* PATA port */
+       AHCI_HFLAG_NO_MSI               = (1 << 5), /* no PCI MSI */
+       AHCI_HFLAG_NO_PMP               = (1 << 6), /* no PMP */
+
        /* ap->flags bits */
-       AHCI_FLAG_NO_NCQ                = (1 << 24),
-       AHCI_FLAG_IGN_IRQ_IF_ERR        = (1 << 25), /* ignore IRQ_IF_ERR */
-       AHCI_FLAG_HONOR_PI              = (1 << 26), /* honor PORTS_IMPL */
-       AHCI_FLAG_IGN_SERR_INTERNAL     = (1 << 27), /* ignore SERR_INTERNAL */
-       AHCI_FLAG_32BIT_ONLY            = (1 << 28), /* force 32bit */
-       AHCI_FLAG_MV_PATA               = (1 << 29), /* PATA port */
-       AHCI_FLAG_NO_MSI                = (1 << 30), /* no PCI MSI */
+       AHCI_FLAG_NO_HOTPLUG            = (1 << 24), /* ignore PxSERR.DIAG.N */
 
        AHCI_FLAG_COMMON                = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
                                          ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
-                                         ATA_FLAG_SKIP_D2H_BSY |
-                                         ATA_FLAG_ACPI_SATA,
+                                         ATA_FLAG_ACPI_SATA | ATA_FLAG_AN,
+       AHCI_LFLAG_COMMON               = ATA_LFLAG_SKIP_D2H_BSY,
 };
 
 struct ahci_cmd_hdr {
@@ -198,6 +203,7 @@ struct ahci_sg {
 };
 
 struct ahci_host_priv {
+       unsigned int            flags;          /* AHCI_HFLAG_* */
        u32                     cap;            /* cap to use */
        u32                     port_map;       /* port map to use */
        u32                     saved_cap;      /* saved initial cap */
@@ -205,6 +211,7 @@ struct ahci_host_priv {
 };
 
 struct ahci_port_priv {
+       struct ata_link         *active_link;
        struct ahci_cmd_hdr     *cmd_slot;
        dma_addr_t              cmd_slot_dma;
        void                    *cmd_tbl;
@@ -215,6 +222,7 @@ struct ahci_port_priv {
        unsigned int            ncq_saw_d2h:1;
        unsigned int            ncq_saw_dmas:1;
        unsigned int            ncq_saw_sdb:1;
+       u32                     intr_mask;      /* interrupts to enable */
 };
 
 static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
@@ -229,6 +237,8 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc);
 static u8 ahci_check_status(struct ata_port *ap);
 static void ahci_freeze(struct ata_port *ap);
 static void ahci_thaw(struct ata_port *ap);
+static void ahci_pmp_attach(struct ata_port *ap);
+static void ahci_pmp_detach(struct ata_port *ap);
 static void ahci_error_handler(struct ata_port *ap);
 static void ahci_vt8251_error_handler(struct ata_port *ap);
 static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
@@ -262,20 +272,17 @@ static struct scsi_host_template ahci_sht = {
 };
 
 static const struct ata_port_operations ahci_ops = {
-       .port_disable           = ata_port_disable,
-
        .check_status           = ahci_check_status,
        .check_altstatus        = ahci_check_status,
        .dev_select             = ata_noop_dev_select,
 
        .tf_read                = ahci_tf_read,
 
+       .qc_defer               = sata_pmp_qc_defer_cmd_switch,
        .qc_prep                = ahci_qc_prep,
        .qc_issue               = ahci_qc_issue,
 
        .irq_clear              = ahci_irq_clear,
-       .irq_on                 = ata_dummy_irq_on,
-       .irq_ack                = ata_dummy_irq_ack,
 
        .scr_read               = ahci_scr_read,
        .scr_write              = ahci_scr_write,
@@ -286,6 +293,9 @@ static const struct ata_port_operations ahci_ops = {
        .error_handler          = ahci_error_handler,
        .post_internal_cmd      = ahci_post_internal_cmd,
 
+       .pmp_attach             = ahci_pmp_attach,
+       .pmp_detach             = ahci_pmp_detach,
+
 #ifdef CONFIG_PM
        .port_suspend           = ahci_port_suspend,
        .port_resume            = ahci_port_resume,
@@ -296,20 +306,17 @@ static const struct ata_port_operations ahci_ops = {
 };
 
 static const struct ata_port_operations ahci_vt8251_ops = {
-       .port_disable           = ata_port_disable,
-
        .check_status           = ahci_check_status,
        .check_altstatus        = ahci_check_status,
        .dev_select             = ata_noop_dev_select,
 
        .tf_read                = ahci_tf_read,
 
+       .qc_defer               = sata_pmp_qc_defer_cmd_switch,
        .qc_prep                = ahci_qc_prep,
        .qc_issue               = ahci_qc_issue,
 
        .irq_clear              = ahci_irq_clear,
-       .irq_on                 = ata_dummy_irq_on,
-       .irq_ack                = ata_dummy_irq_ack,
 
        .scr_read               = ahci_scr_read,
        .scr_write              = ahci_scr_write,
@@ -320,6 +327,9 @@ static const struct ata_port_operations ahci_vt8251_ops = {
        .error_handler          = ahci_vt8251_error_handler,
        .post_internal_cmd      = ahci_post_internal_cmd,
 
+       .pmp_attach             = ahci_pmp_attach,
+       .pmp_detach             = ahci_pmp_detach,
+
 #ifdef CONFIG_PM
        .port_suspend           = ahci_port_suspend,
        .port_resume            = ahci_port_resume,
@@ -329,53 +339,52 @@ static const struct ata_port_operations ahci_vt8251_ops = {
        .port_stop              = ahci_port_stop,
 };
 
+#define AHCI_HFLAGS(flags)     .private_data   = (void *)(flags)
+
 static const struct ata_port_info ahci_port_info[] = {
        /* board_ahci */
        {
                .flags          = AHCI_FLAG_COMMON,
-               .pio_mask       = 0x1f, /* pio0-4 */
-               .udma_mask      = ATA_UDMA6,
-               .port_ops       = &ahci_ops,
-       },
-       /* board_ahci_pi */
-       {
-               .flags          = AHCI_FLAG_COMMON | AHCI_FLAG_HONOR_PI,
+               .link_flags     = AHCI_LFLAG_COMMON,
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &ahci_ops,
        },
        /* board_ahci_vt8251 */
        {
-               .flags          = AHCI_FLAG_COMMON | ATA_FLAG_HRST_TO_RESUME |
-                                 AHCI_FLAG_NO_NCQ,
+               AHCI_HFLAGS     (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP),
+               .flags          = AHCI_FLAG_COMMON,
+               .link_flags     = AHCI_LFLAG_COMMON | ATA_LFLAG_HRST_TO_RESUME,
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &ahci_vt8251_ops,
        },
        /* board_ahci_ign_iferr */
        {
-               .flags          = AHCI_FLAG_COMMON | AHCI_FLAG_IGN_IRQ_IF_ERR,
+               AHCI_HFLAGS     (AHCI_HFLAG_IGN_IRQ_IF_ERR),
+               .flags          = AHCI_FLAG_COMMON,
+               .link_flags     = AHCI_LFLAG_COMMON,
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &ahci_ops,
        },
        /* board_ahci_sb600 */
        {
-               .flags          = AHCI_FLAG_COMMON |
-                                 AHCI_FLAG_IGN_SERR_INTERNAL |
-                                 AHCI_FLAG_32BIT_ONLY,
+               AHCI_HFLAGS     (AHCI_HFLAG_IGN_SERR_INTERNAL |
+                                AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_PMP),
+               .flags          = AHCI_FLAG_COMMON,
+               .link_flags     = AHCI_LFLAG_COMMON,
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &ahci_ops,
        },
        /* board_ahci_mv */
        {
-               .sht            = &ahci_sht,
+               AHCI_HFLAGS     (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI |
+                                AHCI_HFLAG_MV_PATA),
                .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-                                 ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
-                                 ATA_FLAG_SKIP_D2H_BSY | AHCI_FLAG_HONOR_PI |
-                                 AHCI_FLAG_NO_NCQ | AHCI_FLAG_NO_MSI |
-                                 AHCI_FLAG_MV_PATA,
+                                 ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA,
+               .link_flags     = AHCI_LFLAG_COMMON,
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &ahci_ops,
@@ -394,23 +403,25 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */
        { PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */
        { PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */
-       { PCI_VDEVICE(INTEL, 0x2821), board_ahci_pi }, /* ICH8 */
-       { PCI_VDEVICE(INTEL, 0x2822), board_ahci_pi }, /* ICH8 */
-       { PCI_VDEVICE(INTEL, 0x2824), board_ahci_pi }, /* ICH8 */
-       { PCI_VDEVICE(INTEL, 0x2829), board_ahci_pi }, /* ICH8M */
-       { PCI_VDEVICE(INTEL, 0x282a), board_ahci_pi }, /* ICH8M */
-       { PCI_VDEVICE(INTEL, 0x2922), board_ahci_pi }, /* ICH9 */
-       { PCI_VDEVICE(INTEL, 0x2923), board_ahci_pi }, /* ICH9 */
-       { PCI_VDEVICE(INTEL, 0x2924), board_ahci_pi }, /* ICH9 */
-       { PCI_VDEVICE(INTEL, 0x2925), board_ahci_pi }, /* ICH9 */
-       { PCI_VDEVICE(INTEL, 0x2927), board_ahci_pi }, /* ICH9 */
-       { PCI_VDEVICE(INTEL, 0x2929), board_ahci_pi }, /* ICH9M */
-       { PCI_VDEVICE(INTEL, 0x292a), board_ahci_pi }, /* ICH9M */
-       { PCI_VDEVICE(INTEL, 0x292b), board_ahci_pi }, /* ICH9M */
-       { PCI_VDEVICE(INTEL, 0x292c), board_ahci_pi }, /* ICH9M */
-       { PCI_VDEVICE(INTEL, 0x292f), board_ahci_pi }, /* ICH9M */
-       { PCI_VDEVICE(INTEL, 0x294d), board_ahci_pi }, /* ICH9 */
-       { PCI_VDEVICE(INTEL, 0x294e), board_ahci_pi }, /* ICH9M */
+       { PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */
+       { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */
+       { PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */
+       { PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */
+       { PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */
+       { PCI_VDEVICE(INTEL, 0x2922), board_ahci }, /* ICH9 */
+       { PCI_VDEVICE(INTEL, 0x2923), board_ahci }, /* ICH9 */
+       { PCI_VDEVICE(INTEL, 0x2924), board_ahci }, /* ICH9 */
+       { PCI_VDEVICE(INTEL, 0x2925), board_ahci }, /* ICH9 */
+       { PCI_VDEVICE(INTEL, 0x2927), board_ahci }, /* ICH9 */
+       { PCI_VDEVICE(INTEL, 0x2929), board_ahci }, /* ICH9M */
+       { PCI_VDEVICE(INTEL, 0x292a), board_ahci }, /* ICH9M */
+       { PCI_VDEVICE(INTEL, 0x292b), board_ahci }, /* ICH9M */
+       { PCI_VDEVICE(INTEL, 0x292c), board_ahci }, /* ICH9M */
+       { PCI_VDEVICE(INTEL, 0x292f), board_ahci }, /* ICH9M */
+       { PCI_VDEVICE(INTEL, 0x294d), board_ahci }, /* ICH9 */
+       { PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */
+       { PCI_VDEVICE(INTEL, 0x502a), board_ahci }, /* Tolapai */
+       { PCI_VDEVICE(INTEL, 0x502b), board_ahci }, /* Tolapai */
 
        /* JMicron 360/1/3/5/6, match class to avoid IDE function */
        { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
@@ -474,6 +485,14 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(NVIDIA, 0x0ad9), board_ahci },            /* MCP77 */
        { PCI_VDEVICE(NVIDIA, 0x0ada), board_ahci },            /* MCP77 */
        { PCI_VDEVICE(NVIDIA, 0x0adb), board_ahci },            /* MCP77 */
+       { PCI_VDEVICE(NVIDIA, 0x0ab8), board_ahci },            /* MCP79 */
+       { PCI_VDEVICE(NVIDIA, 0x0ab9), board_ahci },            /* MCP79 */
+       { PCI_VDEVICE(NVIDIA, 0x0aba), board_ahci },            /* MCP79 */
+       { PCI_VDEVICE(NVIDIA, 0x0abb), board_ahci },            /* MCP79 */
+       { PCI_VDEVICE(NVIDIA, 0x0abc), board_ahci },            /* MCP79 */
+       { PCI_VDEVICE(NVIDIA, 0x0abd), board_ahci },            /* MCP79 */
+       { PCI_VDEVICE(NVIDIA, 0x0abe), board_ahci },            /* MCP79 */
+       { PCI_VDEVICE(NVIDIA, 0x0abf), board_ahci },            /* MCP79 */
 
        /* SiS */
        { PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */
@@ -524,7 +543,6 @@ static inline void __iomem *ahci_port_base(struct ata_port *ap)
 /**
  *     ahci_save_initial_config - Save and fixup initial config values
  *     @pdev: target PCI device
- *     @pi: associated ATA port info
  *     @hpriv: host private area to store config values
  *
  *     Some registers containing configuration info might be setup by
@@ -538,7 +556,6 @@ static inline void __iomem *ahci_port_base(struct ata_port *ap)
  *     None.
  */
 static void ahci_save_initial_config(struct pci_dev *pdev,
-                                    const struct ata_port_info *pi,
                                     struct ahci_host_priv *hpriv)
 {
        void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
@@ -552,26 +569,22 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
        hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
 
        /* some chips have errata preventing 64bit use */
-       if ((cap & HOST_CAP_64) && (pi->flags & AHCI_FLAG_32BIT_ONLY)) {
+       if ((cap & HOST_CAP_64) && (hpriv->flags & AHCI_HFLAG_32BIT_ONLY)) {
                dev_printk(KERN_INFO, &pdev->dev,
                           "controller can't do 64bit DMA, forcing 32bit\n");
                cap &= ~HOST_CAP_64;
        }
 
-       if ((cap & HOST_CAP_NCQ) && (pi->flags & AHCI_FLAG_NO_NCQ)) {
+       if ((cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_NO_NCQ)) {
                dev_printk(KERN_INFO, &pdev->dev,
                           "controller can't do NCQ, turning off CAP_NCQ\n");
                cap &= ~HOST_CAP_NCQ;
        }
 
-       /* fixup zero port_map */
-       if (!port_map) {
-               port_map = (1 << ahci_nr_ports(cap)) - 1;
-               dev_printk(KERN_WARNING, &pdev->dev,
-                          "PORTS_IMPL is zero, forcing 0x%x\n", port_map);
-
-               /* write the fixed up value to the PI register */
-               hpriv->saved_port_map = port_map;
+       if ((cap && HOST_CAP_PMP) && (hpriv->flags & AHCI_HFLAG_NO_PMP)) {
+               dev_printk(KERN_INFO, &pdev->dev,
+                          "controller can't do PMP, turning off CAP_PMP\n");
+               cap &= ~HOST_CAP_PMP;
        }
 
        /*
@@ -579,7 +592,7 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
         * is asserted through the standard AHCI port
         * presence register, as bit 4 (counting from 0)
         */
-       if (pi->flags & AHCI_FLAG_MV_PATA) {
+       if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
                dev_printk(KERN_ERR, &pdev->dev,
                           "MV_AHCI HACK: port_map %x -> %x\n",
                           hpriv->port_map,
@@ -589,7 +602,7 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
        }
 
        /* cross check port_map and cap.n_ports */
-       if (pi->flags & AHCI_FLAG_HONOR_PI) {
+       if (port_map) {
                u32 tmp_port_map = port_map;
                int n_ports = ahci_nr_ports(cap);
 
@@ -600,17 +613,26 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
                        }
                }
 
-               /* Whine if inconsistent.  No need to update cap.
-                * port_map is used to determine number of ports.
+               /* If n_ports and port_map are inconsistent, whine and
+                * clear port_map and let it be generated from n_ports.
                 */
-               if (n_ports || tmp_port_map)
+               if (n_ports || tmp_port_map) {
                        dev_printk(KERN_WARNING, &pdev->dev,
                                   "nr_ports (%u) and implemented port map "
-                                  "(0x%x) don't match\n",
+                                  "(0x%x) don't match, using nr_ports\n",
                                   ahci_nr_ports(cap), port_map);
-       } else {
-               /* fabricate port_map from cap.nr_ports */
+                       port_map = 0;
+               }
+       }
+
+       /* fabricate port_map from cap.nr_ports */
+       if (!port_map) {
                port_map = (1 << ahci_nr_ports(cap)) - 1;
+               dev_printk(KERN_WARNING, &pdev->dev,
+                          "forcing PORTS_IMPL to 0x%x\n", port_map);
+
+               /* write the fixed up value to the PI register */
+               hpriv->saved_port_map = port_map;
        }
 
        /* record values to use during operation */
@@ -836,8 +858,14 @@ static int ahci_reset_controller(struct ata_host *host)
        void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
        u32 tmp;
 
-       /* global controller reset */
+       /* we must be in AHCI mode, before using anything
+        * AHCI-specific, such as HOST_RESET.
+        */
        tmp = readl(mmio + HOST_CTL);
+       if (!(tmp & HOST_AHCI_EN))
+               writel(tmp | HOST_AHCI_EN, mmio + HOST_CTL);
+
+       /* global controller reset */
        if ((tmp & HOST_RESET) == 0) {
                writel(tmp | HOST_RESET, mmio + HOST_CTL);
                readl(mmio + HOST_CTL); /* flush */
@@ -904,13 +932,14 @@ static void ahci_port_init(struct pci_dev *pdev, struct ata_port *ap,
 
 static void ahci_init_controller(struct ata_host *host)
 {
+       struct ahci_host_priv *hpriv = host->private_data;
        struct pci_dev *pdev = to_pci_dev(host->dev);
        void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
        int i;
        void __iomem *port_mmio;
        u32 tmp;
 
-       if (host->ports[0]->flags & AHCI_FLAG_MV_PATA) {
+       if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
                port_mmio = __ahci_port_base(host, 4);
 
                writel(0, port_mmio + PORT_IRQ_MASK);
@@ -1042,9 +1071,10 @@ static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
        return 0;
 }
 
-static int ahci_do_softreset(struct ata_port *ap, unsigned int *class,
+static int ahci_do_softreset(struct ata_link *link, unsigned int *class,
                             int pmp, unsigned long deadline)
 {
+       struct ata_port *ap = link->ap;
        const char *reason = NULL;
        unsigned long now, msecs;
        struct ata_taskfile tf;
@@ -1052,7 +1082,7 @@ static int ahci_do_softreset(struct ata_port *ap, unsigned int *class,
 
        DPRINTK("ENTER\n");
 
-       if (ata_port_offline(ap)) {
+       if (ata_link_offline(link)) {
                DPRINTK("PHY reports no device\n");
                *class = ATA_DEV_NONE;
                return 0;
@@ -1061,10 +1091,10 @@ static int ahci_do_softreset(struct ata_port *ap, unsigned int *class,
        /* prepare for SRST (AHCI-1.1 10.4.1) */
        rc = ahci_kick_engine(ap, 1);
        if (rc)
-               ata_port_printk(ap, KERN_WARNING,
+               ata_link_printk(link, KERN_WARNING,
                                "failed to reset engine (errno=%d)", rc);
 
-       ata_tf_init(ap->device, &tf);
+       ata_tf_init(link->device, &tf);
 
        /* issue the first D2H Register FIS */
        msecs = 0;
@@ -1109,19 +1139,25 @@ static int ahci_do_softreset(struct ata_port *ap, unsigned int *class,
        return 0;
 
  fail:
-       ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
+       ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason);
        return rc;
 }
 
-static int ahci_softreset(struct ata_port *ap, unsigned int *class,
+static int ahci_softreset(struct ata_link *link, unsigned int *class,
                          unsigned long deadline)
 {
-       return ahci_do_softreset(ap, class, 0, deadline);
+       int pmp = 0;
+
+       if (link->ap->flags & ATA_FLAG_PMP)
+               pmp = SATA_PMP_CTRL_PORT;
+
+       return ahci_do_softreset(link, class, pmp, deadline);
 }
 
-static int ahci_hardreset(struct ata_port *ap, unsigned int *class,
+static int ahci_hardreset(struct ata_link *link, unsigned int *class,
                          unsigned long deadline)
 {
+       struct ata_port *ap = link->ap;
        struct ahci_port_priv *pp = ap->private_data;
        u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
        struct ata_taskfile tf;
@@ -1132,26 +1168,27 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class,
        ahci_stop_engine(ap);
 
        /* clear D2H reception area to properly wait for D2H FIS */
-       ata_tf_init(ap->device, &tf);
+       ata_tf_init(link->device, &tf);
        tf.command = 0x80;
        ata_tf_to_fis(&tf, 0, 0, d2h_fis);
 
-       rc = sata_std_hardreset(ap, class, deadline);
+       rc = sata_std_hardreset(link, class, deadline);
 
        ahci_start_engine(ap);
 
-       if (rc == 0 && ata_port_online(ap))
+       if (rc == 0 && ata_link_online(link))
                *class = ahci_dev_classify(ap);
-       if (*class == ATA_DEV_UNKNOWN)
+       if (rc != -EAGAIN && *class == ATA_DEV_UNKNOWN)
                *class = ATA_DEV_NONE;
 
        DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
        return rc;
 }
 
-static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class,
+static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
                                 unsigned long deadline)
 {
+       struct ata_port *ap = link->ap;
        u32 serror;
        int rc;
 
@@ -1159,7 +1196,7 @@ static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class,
 
        ahci_stop_engine(ap);
 
-       rc = sata_port_hardreset(ap, sata_ehc_deb_timing(&ap->eh_context),
+       rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
                                 deadline);
 
        /* vt8251 needs SError cleared for the port to operate */
@@ -1176,12 +1213,13 @@ static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class,
        return rc ?: -EAGAIN;
 }
 
-static void ahci_postreset(struct ata_port *ap, unsigned int *class)
+static void ahci_postreset(struct ata_link *link, unsigned int *class)
 {
+       struct ata_port *ap = link->ap;
        void __iomem *port_mmio = ahci_port_base(ap);
        u32 new_tmp, tmp;
 
-       ata_std_postreset(ap, class);
+       ata_std_postreset(link, class);
 
        /* Make sure port's ATAPI bit is set appropriately */
        new_tmp = tmp = readl(port_mmio + PORT_CMD);
@@ -1195,6 +1233,12 @@ static void ahci_postreset(struct ata_port *ap, unsigned int *class)
        }
 }
 
+static int ahci_pmp_softreset(struct ata_link *link, unsigned int *class,
+                             unsigned long deadline)
+{
+       return ahci_do_softreset(link, class, link->pmp, deadline);
+}
+
 static u8 ahci_check_status(struct ata_port *ap)
 {
        void __iomem *mmio = ap->ioaddr.cmd_addr;
@@ -1253,7 +1297,7 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc)
         */
        cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
 
-       ata_tf_to_fis(&qc->tf, 0, 1, cmd_tbl);
+       ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, cmd_tbl);
        if (is_atapi) {
                memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
                memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
@@ -1266,7 +1310,7 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc)
        /*
         * Fill in command slot information.
         */
-       opts = cmd_fis_len | n_elem << 16;
+       opts = cmd_fis_len | n_elem << 16 | (qc->dev->link->pmp << 12);
        if (qc->tf.flags & ATA_TFLAG_WRITE)
                opts |= AHCI_CMD_WRITE;
        if (is_atapi)
@@ -1277,66 +1321,87 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc)
 
 static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
 {
+       struct ahci_host_priv *hpriv = ap->host->private_data;
        struct ahci_port_priv *pp = ap->private_data;
-       struct ata_eh_info *ehi = &ap->eh_info;
-       unsigned int err_mask = 0, action = 0;
-       struct ata_queued_cmd *qc;
+       struct ata_eh_info *host_ehi = &ap->link.eh_info;
+       struct ata_link *link = NULL;
+       struct ata_queued_cmd *active_qc;
+       struct ata_eh_info *active_ehi;
        u32 serror;
 
-       ata_ehi_clear_desc(ehi);
+       /* determine active link */
+       ata_port_for_each_link(link, ap)
+               if (ata_link_active(link))
+                       break;
+       if (!link)
+               link = &ap->link;
+
+       active_qc = ata_qc_from_tag(ap, link->active_tag);
+       active_ehi = &link->eh_info;
+
+       /* record irq stat */
+       ata_ehi_clear_desc(host_ehi);
+       ata_ehi_push_desc(host_ehi, "irq_stat 0x%08x", irq_stat);
 
        /* AHCI needs SError cleared; otherwise, it might lock up */
        ahci_scr_read(ap, SCR_ERROR, &serror);
        ahci_scr_write(ap, SCR_ERROR, serror);
-
-       /* analyze @irq_stat */
-       ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat);
+       host_ehi->serror |= serror;
 
        /* some controllers set IRQ_IF_ERR on device errors, ignore it */
-       if (ap->flags & AHCI_FLAG_IGN_IRQ_IF_ERR)
+       if (hpriv->flags & AHCI_HFLAG_IGN_IRQ_IF_ERR)
                irq_stat &= ~PORT_IRQ_IF_ERR;
 
        if (irq_stat & PORT_IRQ_TF_ERR) {
-               err_mask |= AC_ERR_DEV;
-               if (ap->flags & AHCI_FLAG_IGN_SERR_INTERNAL)
-                       serror &= ~SERR_INTERNAL;
+               /* If qc is active, charge it; otherwise, the active
+                * link.  There's no active qc on NCQ errors.  It will
+                * be determined by EH by reading log page 10h.
+                */
+               if (active_qc)
+                       active_qc->err_mask |= AC_ERR_DEV;
+               else
+                       active_ehi->err_mask |= AC_ERR_DEV;
+
+               if (hpriv->flags & AHCI_HFLAG_IGN_SERR_INTERNAL)
+                       host_ehi->serror &= ~SERR_INTERNAL;
+       }
+
+       if (irq_stat & PORT_IRQ_UNK_FIS) {
+               u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK);
+
+               active_ehi->err_mask |= AC_ERR_HSM;
+               active_ehi->action |= ATA_EH_SOFTRESET;
+               ata_ehi_push_desc(active_ehi,
+                                 "unknown FIS %08x %08x %08x %08x" ,
+                                 unk[0], unk[1], unk[2], unk[3]);
+       }
+
+       if (ap->nr_pmp_links && (irq_stat & PORT_IRQ_BAD_PMP)) {
+               active_ehi->err_mask |= AC_ERR_HSM;
+               active_ehi->action |= ATA_EH_SOFTRESET;
+               ata_ehi_push_desc(active_ehi, "incorrect PMP");
        }
 
        if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) {
-               err_mask |= AC_ERR_HOST_BUS;
-               action |= ATA_EH_SOFTRESET;
+               host_ehi->err_mask |= AC_ERR_HOST_BUS;
+               host_ehi->action |= ATA_EH_SOFTRESET;
+               ata_ehi_push_desc(host_ehi, "host bus error");
        }
 
        if (irq_stat & PORT_IRQ_IF_ERR) {
-               err_mask |= AC_ERR_ATA_BUS;
-               action |= ATA_EH_SOFTRESET;
-               ata_ehi_push_desc(ehi, "interface fatal error");
+               host_ehi->err_mask |= AC_ERR_ATA_BUS;
+               host_ehi->action |= ATA_EH_SOFTRESET;
+               ata_ehi_push_desc(host_ehi, "interface fatal error");
        }
 
        if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
-               ata_ehi_hotplugged(ehi);
-               ata_ehi_push_desc(ehi, "%s", irq_stat & PORT_IRQ_CONNECT ?
+               ata_ehi_hotplugged(host_ehi);
+               ata_ehi_push_desc(host_ehi, "%s",
+                       irq_stat & PORT_IRQ_CONNECT ?
                        "connection status changed" : "PHY RDY changed");
        }
 
-       if (irq_stat & PORT_IRQ_UNK_FIS) {
-               u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK);
-
-               err_mask |= AC_ERR_HSM;
-               action |= ATA_EH_SOFTRESET;
-               ata_ehi_push_desc(ehi, "unknown FIS %08x %08x %08x %08x",
-                                 unk[0], unk[1], unk[2], unk[3]);
-       }
-
        /* okay, let's hand over to EH */
-       ehi->serror |= serror;
-       ehi->action |= action;
-
-       qc = ata_qc_from_tag(ap, ap->active_tag);
-       if (qc)
-               qc->err_mask |= err_mask;
-       else
-               ehi->err_mask |= err_mask;
 
        if (irq_stat & PORT_IRQ_FREEZE)
                ata_port_freeze(ap);
@@ -1347,25 +1412,64 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
 static void ahci_port_intr(struct ata_port *ap)
 {
        void __iomem *port_mmio = ap->ioaddr.cmd_addr;
-       struct ata_eh_info *ehi = &ap->eh_info;
+       struct ata_eh_info *ehi = &ap->link.eh_info;
        struct ahci_port_priv *pp = ap->private_data;
+       struct ahci_host_priv *hpriv = ap->host->private_data;
+       int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING);
        u32 status, qc_active;
        int rc, known_irq = 0;
 
        status = readl(port_mmio + PORT_IRQ_STAT);
        writel(status, port_mmio + PORT_IRQ_STAT);
 
+       /* ignore BAD_PMP while resetting */
+       if (unlikely(resetting))
+               status &= ~PORT_IRQ_BAD_PMP;
+
        if (unlikely(status & PORT_IRQ_ERROR)) {
                ahci_error_intr(ap, status);
                return;
        }
 
-       if (ap->sactive)
+       if (status & PORT_IRQ_SDB_FIS) {
+               /* If SNotification is available, leave notification
+                * handling to sata_async_notification().  If not,
+                * emulate it by snooping SDB FIS RX area.
+                *
+                * Snooping FIS RX area is probably cheaper than
+                * poking SNotification but some constrollers which
+                * implement SNotification, ICH9 for example, don't
+                * store AN SDB FIS into receive area.
+                */
+               if (hpriv->cap & HOST_CAP_SNTF)
+                       sata_async_notification(ap);
+               else {
+                       /* If the 'N' bit in word 0 of the FIS is set,
+                        * we just received asynchronous notification.
+                        * Tell libata about it.
+                        */
+                       const __le32 *f = pp->rx_fis + RX_FIS_SDB;
+                       u32 f0 = le32_to_cpu(f[0]);
+
+                       if (f0 & (1 << 15))
+                               sata_async_notification(ap);
+               }
+       }
+
+       /* pp->active_link is valid iff any command is in flight */
+       if (ap->qc_active && pp->active_link->sactive)
                qc_active = readl(port_mmio + PORT_SCR_ACT);
        else
                qc_active = readl(port_mmio + PORT_CMD_ISSUE);
 
        rc = ata_qc_complete_multiple(ap, qc_active, NULL);
+
+       /* If resetting, spurious or invalid completions are expected,
+        * return unconditionally.
+        */
+       if (resetting)
+               return;
+
        if (rc > 0)
                return;
        if (rc < 0) {
@@ -1380,7 +1484,7 @@ static void ahci_port_intr(struct ata_port *ap)
        /* if !NCQ, ignore.  No modern ATA device has broken HSM
         * implementation for non-NCQ commands.
         */
-       if (!ap->sactive)
+       if (!ap->link.sactive)
                return;
 
        if (status & PORT_IRQ_D2H_REG_FIS) {
@@ -1433,7 +1537,7 @@ static void ahci_port_intr(struct ata_port *ap)
        if (!known_irq)
                ata_port_printk(ap, KERN_INFO, "spurious interrupt "
                                "(irq_stat 0x%x active_tag 0x%x sactive 0x%x)\n",
-                               status, ap->active_tag, ap->sactive);
+                               status, ap->link.active_tag, ap->link.sactive);
 }
 
 static void ahci_irq_clear(struct ata_port *ap)
@@ -1498,6 +1602,13 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
        void __iomem *port_mmio = ahci_port_base(ap);
+       struct ahci_port_priv *pp = ap->private_data;
+
+       /* Keep track of the currently active link.  It will be used
+        * in completion path to determine whether NCQ phase is in
+        * progress.
+        */
+       pp->active_link = qc->dev->link;
 
        if (qc->tf.protocol == ATA_PROT_NCQ)
                writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
@@ -1520,6 +1631,7 @@ static void ahci_thaw(struct ata_port *ap)
        void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
        void __iomem *port_mmio = ahci_port_base(ap);
        u32 tmp;
+       struct ahci_port_priv *pp = ap->private_data;
 
        /* clear IRQ */
        tmp = readl(port_mmio + PORT_IRQ_STAT);
@@ -1527,7 +1639,7 @@ static void ahci_thaw(struct ata_port *ap)
        writel(1 << ap->port_no, mmio + HOST_IRQ_STAT);
 
        /* turn IRQ back on */
-       writel(DEF_PORT_IRQ, port_mmio + PORT_IRQ_MASK);
+       writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
 }
 
 static void ahci_error_handler(struct ata_port *ap)
@@ -1539,8 +1651,10 @@ static void ahci_error_handler(struct ata_port *ap)
        }
 
        /* perform recovery */
-       ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_hardreset,
-                 ahci_postreset);
+       sata_pmp_do_eh(ap, ata_std_prereset, ahci_softreset,
+                      ahci_hardreset, ahci_postreset,
+                      sata_pmp_std_prereset, ahci_pmp_softreset,
+                      sata_pmp_std_hardreset, sata_pmp_std_postreset);
 }
 
 static void ahci_vt8251_error_handler(struct ata_port *ap)
@@ -1565,11 +1679,44 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
                ahci_kick_engine(ap, 1);
 }
 
+static void ahci_pmp_attach(struct ata_port *ap)
+{
+       void __iomem *port_mmio = ahci_port_base(ap);
+       struct ahci_port_priv *pp = ap->private_data;
+       u32 cmd;
+
+       cmd = readl(port_mmio + PORT_CMD);
+       cmd |= PORT_CMD_PMP;
+       writel(cmd, port_mmio + PORT_CMD);
+
+       pp->intr_mask |= PORT_IRQ_BAD_PMP;
+       writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
+}
+
+static void ahci_pmp_detach(struct ata_port *ap)
+{
+       void __iomem *port_mmio = ahci_port_base(ap);
+       struct ahci_port_priv *pp = ap->private_data;
+       u32 cmd;
+
+       cmd = readl(port_mmio + PORT_CMD);
+       cmd &= ~PORT_CMD_PMP;
+       writel(cmd, port_mmio + PORT_CMD);
+
+       pp->intr_mask &= ~PORT_IRQ_BAD_PMP;
+       writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
+}
+
 static int ahci_port_resume(struct ata_port *ap)
 {
        ahci_power_up(ap);
        ahci_start_port(ap);
 
+       if (ap->nr_pmp_links)
+               ahci_pmp_attach(ap);
+       else
+               ahci_pmp_detach(ap);
+
        return 0;
 }
 
@@ -1681,6 +1828,12 @@ static int ahci_port_start(struct ata_port *ap)
        pp->cmd_tbl = mem;
        pp->cmd_tbl_dma = mem_dma;
 
+       /*
+        * Save off initial list of interrupts to be enabled.
+        * This could be changed later
+        */
+       pp->intr_mask = DEF_PORT_IRQ;
+
        ap->private_data = pp;
 
        /* engage engines, captain */
@@ -1830,20 +1983,24 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (rc)
                return rc;
 
-       if ((pi.flags & AHCI_FLAG_NO_MSI) || pci_enable_msi(pdev))
-               pci_intx(pdev, 1);
-
        hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
        if (!hpriv)
                return -ENOMEM;
+       hpriv->flags |= (unsigned long)pi.private_data;
+
+       if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev))
+               pci_intx(pdev, 1);
 
        /* save initial config */
-       ahci_save_initial_config(pdev, &pi, hpriv);
+       ahci_save_initial_config(pdev, hpriv);
 
        /* prepare host */
        if (hpriv->cap & HOST_CAP_NCQ)
                pi.flags |= ATA_FLAG_NCQ;
 
+       if (hpriv->cap & HOST_CAP_PMP)
+               pi.flags |= ATA_FLAG_PMP;
+
        host = ata_host_alloc_pinfo(&pdev->dev, ppi, fls(hpriv->port_map));
        if (!host)
                return -ENOMEM;
@@ -1854,6 +2011,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                struct ata_port *ap = host->ports[i];
                void __iomem *port_mmio = ahci_port_base(ap);
 
+               ata_port_pbar_desc(ap, AHCI_PCI_BAR, -1, "abar");
+               ata_port_pbar_desc(ap, AHCI_PCI_BAR,
+                                  0x100 + ap->port_no * 0x80, "port");
+
                /* standard SATA port setup */
                if (hpriv->port_map & (1 << i))
                        ap->ioaddr.cmd_addr = port_mmio;
index 9454669547244e5960e05c5bd9741d6a3efc90fb..90329982bef760fe6a4cadead1f1d526943f4958 100644 (file)
@@ -34,7 +34,7 @@
 
 /**
  *     generic_set_mode        -       mode setting
- *     @ap: interface to set up
+ *     @link: link to set up
  *     @unused: returned device on error
  *
  *     Use a non standard set_mode function. We don't want to be tuned.
  *     and respect them.
  */
 
-static int generic_set_mode(struct ata_port *ap, struct ata_device **unused)
+static int generic_set_mode(struct ata_link *link, struct ata_device **unused)
 {
+       struct ata_port *ap = link->ap;
        int dma_enabled = 0;
-       int i;
+       struct ata_device *dev;
 
        /* Bits 5 and 6 indicate if DMA is active on master/slave */
        if (ap->ioaddr.bmdma_addr)
                dma_enabled = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
 
-       for (i = 0; i < ATA_MAX_DEVICES; i++) {
-               struct ata_device *dev = &ap->device[i];
+       ata_link_for_each_dev(dev, link) {
                if (ata_dev_enabled(dev)) {
                        /* We don't really care */
                        dev->pio_mode = XFER_PIO_0;
                        dev->dma_mode = XFER_MW_DMA_0;
                        /* We do need the right mode information for DMA or PIO
                           and this comes from the current configuration flags */
-                       if (dma_enabled & (1 << (5 + i))) {
+                       if (dma_enabled & (1 << (5 + dev->devno))) {
                                ata_id_to_dma_mode(dev, XFER_MW_DMA_0);
                                dev->flags &= ~ATA_DFLAG_PIO;
                        } else {
@@ -95,7 +95,6 @@ static struct scsi_host_template generic_sht = {
 static struct ata_port_operations generic_port_ops = {
        .set_mode       = generic_set_mode,
 
-       .port_disable   = ata_port_disable,
        .tf_load        = ata_tf_load,
        .tf_read        = ata_tf_read,
        .check_status   = ata_check_status,
@@ -121,9 +120,8 @@ static struct ata_port_operations generic_port_ops = {
        .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,
+       .port_start     = ata_sff_port_start,
 };
 
 static int all_generic_ide;            /* Set to claim all devices */
index 92c2d5082bef45e97030b22c0e8d1b1a2f926b05..9ce4aa9c2f255c5686298ffbb399360cb12958c4 100644 (file)
@@ -123,7 +123,6 @@ enum {
        ich_pata_33             = 1,    /* ICH up to UDMA 33 only */
        ich_pata_66             = 2,    /* ICH up to 66 Mhz */
        ich_pata_100            = 3,    /* ICH up to UDMA 100 */
-       ich_pata_133            = 4,    /* ICH up to UDMA 133 */
        ich5_sata               = 5,
        ich6_sata               = 6,
        ich6_sata_ahci          = 7,
@@ -199,7 +198,7 @@ static const struct pci_device_id piix_pci_tbl[] = {
        { 0x8086, 0x24CA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
        { 0x8086, 0x24CB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
        /* Intel ICH5 */
-       { 0x8086, 0x24DB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_133 },
+       { 0x8086, 0x24DB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
        /* C-ICH (i810E2) */
        { 0x8086, 0x245B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
        /* ESB (855GME/875P + 6300ESB) UDMA 100  */
@@ -207,7 +206,7 @@ static const struct pci_device_id piix_pci_tbl[] = {
        /* ICH6 (and 6) (i915) UDMA 100 */
        { 0x8086, 0x266F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
        /* ICH7/7-R (i945, i975) UDMA 100*/
-       { 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_133 },
+       { 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
        { 0x8086, 0x269E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
        /* ICH8 Mobile PATA Controller */
        { 0x8086, 0x2850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
@@ -290,7 +289,6 @@ static struct scsi_host_template piix_sht = {
 };
 
 static const struct ata_port_operations piix_pata_ops = {
-       .port_disable           = ata_port_disable,
        .set_piomode            = piix_set_piomode,
        .set_dmamode            = piix_set_dmamode,
        .mode_filter            = ata_pci_default_filter,
@@ -318,13 +316,11 @@ static const struct ata_port_operations piix_pata_ops = {
        .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,
 };
 
 static const struct ata_port_operations ich_pata_ops = {
-       .port_disable           = ata_port_disable,
        .set_piomode            = piix_set_piomode,
        .set_dmamode            = ich_set_dmamode,
        .mode_filter            = ata_pci_default_filter,
@@ -352,14 +348,11 @@ static const struct ata_port_operations ich_pata_ops = {
        .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,
 };
 
 static const struct ata_port_operations piix_sata_ops = {
-       .port_disable           = ata_port_disable,
-
        .tf_load                = ata_tf_load,
        .tf_read                = ata_tf_read,
        .check_status           = ata_check_status,
@@ -382,7 +375,6 @@ static const struct ata_port_operations piix_sata_ops = {
        .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,
 };
@@ -445,15 +437,15 @@ static const struct piix_map_db ich8_map_db = {
 };
 
 static const struct piix_map_db tolapai_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 },
-        },
+       .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[] = {
@@ -466,7 +458,7 @@ static const struct piix_map_db *piix_map_db_table[] = {
 };
 
 static struct ata_port_info piix_port_info[] = {
-       /* piix_pata_33: 0:  PIIX4 at 33MHz */
+       [piix_pata_33] =        /* PIIX4 at 33MHz */
        {
                .sht            = &piix_sht,
                .flags          = PIIX_PATA_FLAGS,
@@ -476,7 +468,7 @@ static struct ata_port_info piix_port_info[] = {
                .port_ops       = &piix_pata_ops,
        },
 
-       /* ich_pata_33: 1       ICH0 - ICH at 33Mhz*/
+       [ich_pata_33] =         /* ICH0 - ICH at 33Mhz*/
        {
                .sht            = &piix_sht,
                .flags          = PIIX_PATA_FLAGS,
@@ -485,7 +477,8 @@ static struct ata_port_info piix_port_info[] = {
                .udma_mask      = ATA_UDMA2, /* UDMA33 */
                .port_ops       = &ich_pata_ops,
        },
-       /* ich_pata_66: 2       ICH controllers up to 66MHz */
+
+       [ich_pata_66] =         /* ICH controllers up to 66MHz */
        {
                .sht            = &piix_sht,
                .flags          = PIIX_PATA_FLAGS,
@@ -495,7 +488,7 @@ static struct ata_port_info piix_port_info[] = {
                .port_ops       = &ich_pata_ops,
        },
 
-       /* ich_pata_100: 3 */
+       [ich_pata_100] =
        {
                .sht            = &piix_sht,
                .flags          = PIIX_PATA_FLAGS | PIIX_FLAG_CHECKINTR,
@@ -505,17 +498,7 @@ static struct ata_port_info piix_port_info[] = {
                .port_ops       = &ich_pata_ops,
        },
 
-       /* ich_pata_133: 4      ICH with full UDMA6 */
-       {
-               .sht            = &piix_sht,
-               .flags          = PIIX_PATA_FLAGS | PIIX_FLAG_CHECKINTR,
-               .pio_mask       = 0x1f, /* pio 0-4 */
-               .mwdma_mask     = 0x06, /* Check: maybe 0x07  */
-               .udma_mask      = ATA_UDMA6, /* UDMA133 */
-               .port_ops       = &ich_pata_ops,
-       },
-
-       /* ich5_sata: 5 */
+       [ich5_sata] =
        {
                .sht            = &piix_sht,
                .flags          = PIIX_SATA_FLAGS,
@@ -525,7 +508,7 @@ static struct ata_port_info piix_port_info[] = {
                .port_ops       = &piix_sata_ops,
        },
 
-       /* ich6_sata: 6 */
+       [ich6_sata] =
        {
                .sht            = &piix_sht,
                .flags          = PIIX_SATA_FLAGS | PIIX_FLAG_SCR,
@@ -535,7 +518,7 @@ static struct ata_port_info piix_port_info[] = {
                .port_ops       = &piix_sata_ops,
        },
 
-       /* ich6_sata_ahci: 7 */
+       [ich6_sata_ahci] =
        {
                .sht            = &piix_sht,
                .flags          = PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
@@ -546,7 +529,7 @@ static struct ata_port_info piix_port_info[] = {
                .port_ops       = &piix_sata_ops,
        },
 
-       /* ich6m_sata_ahci: 8 */
+       [ich6m_sata_ahci] =
        {
                .sht            = &piix_sht,
                .flags          = PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
@@ -557,7 +540,7 @@ static struct ata_port_info piix_port_info[] = {
                .port_ops       = &piix_sata_ops,
        },
 
-       /* ich8_sata_ahci: 9 */
+       [ich8_sata_ahci] =
        {
                .sht            = &piix_sht,
                .flags          = PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
@@ -568,7 +551,7 @@ static struct ata_port_info piix_port_info[] = {
                .port_ops       = &piix_sata_ops,
        },
 
-       /* piix_pata_mwdma: 10:  PIIX3 MWDMA only */
+       [piix_pata_mwdma] =     /* PIIX3 MWDMA only */
        {
                .sht            = &piix_sht,
                .flags          = PIIX_PATA_FLAGS,
@@ -577,7 +560,7 @@ static struct ata_port_info piix_port_info[] = {
                .port_ops       = &piix_pata_ops,
        },
 
-       /* tolapai_sata_ahci: 11: */
+       [tolapai_sata_ahci] =
        {
                .sht            = &piix_sht,
                .flags          = PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
@@ -615,6 +598,7 @@ static const struct ich_laptop ich_laptop[] = {
        { 0x27DF, 0x0005, 0x0280 },     /* ICH7 on Acer 5602WLMi */
        { 0x27DF, 0x1025, 0x0110 },     /* ICH7 on Acer 3682WLMi */
        { 0x27DF, 0x1043, 0x1267 },     /* ICH7 on Asus W5F */
+       { 0x27DF, 0x103C, 0x30A1 },     /* ICH7 on HP Compaq nc2400 */
        { 0x24CA, 0x1025, 0x0061 },     /* ICH4 on ACER Aspire 2023WLMi */
        /* end marker */
        { 0, }
@@ -657,19 +641,20 @@ static int ich_pata_cable_detect(struct ata_port *ap)
 
 /**
  *     piix_pata_prereset - prereset for PATA host controller
- *     @ap: Target port
+ *     @link: Target link
  *     @deadline: deadline jiffies for the operation
  *
  *     LOCKING:
  *     None (inherited from caller).
  */
-static int piix_pata_prereset(struct ata_port *ap, unsigned long deadline)
+static int piix_pata_prereset(struct ata_link *link, unsigned long deadline)
 {
+       struct ata_port *ap = link->ap;
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 
        if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no]))
                return -ENOENT;
-       return ata_std_prereset(ap, deadline);
+       return ata_std_prereset(link, deadline);
 }
 
 static void piix_pata_error_handler(struct ata_port *ap)
@@ -1137,7 +1122,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 c059f78ad944dc18a3372f63a49a14b4b0179441..3f7533589041b7bd9f11b77cb6d875d864f50add 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/acpi.h>
 #include <linux/libata.h>
 #include <linux/pci.h>
+#include <scsi/scsi_device.h>
 #include "libata.h"
 
 #include <acpi/acpi_bus.h>
@@ -40,11 +41,40 @@ static int is_pci_dev(struct device *dev)
        return (dev->bus == &pci_bus_type);
 }
 
-static void ata_acpi_associate_sata_port(struct ata_port *ap)
+/**
+ * ata_acpi_associate_sata_port - associate SATA port with ACPI objects
+ * @ap: target SATA port
+ *
+ * Look up ACPI objects associated with @ap and initialize acpi_handle
+ * fields of @ap, the port and devices accordingly.
+ *
+ * LOCKING:
+ * EH context.
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+void ata_acpi_associate_sata_port(struct ata_port *ap)
 {
-       acpi_integer adr = SATA_ADR(ap->port_no, NO_PORT_MULT);
+       WARN_ON(!(ap->flags & ATA_FLAG_ACPI_SATA));
+
+       if (!ap->nr_pmp_links) {
+               acpi_integer adr = SATA_ADR(ap->port_no, NO_PORT_MULT);
+
+               ap->link.device->acpi_handle =
+                       acpi_get_child(ap->host->acpi_handle, adr);
+       } else {
+               struct ata_link *link;
+
+               ap->link.device->acpi_handle = NULL;
 
-       ap->device->acpi_handle = acpi_get_child(ap->host->acpi_handle, adr);
+               ata_port_for_each_link(link, ap) {
+                       acpi_integer adr = SATA_ADR(ap->port_no, link->pmp);
+
+                       link->device->acpi_handle =
+                               acpi_get_child(ap->host->acpi_handle, adr);
+               }
+       }
 }
 
 static void ata_acpi_associate_ide_port(struct ata_port *ap)
@@ -60,12 +90,53 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap)
                max_devices++;
 
        for (i = 0; i < max_devices; i++) {
-               struct ata_device *dev = &ap->device[i];
+               struct ata_device *dev = &ap->link.device[i];
 
                dev->acpi_handle = acpi_get_child(ap->acpi_handle, i);
        }
 }
 
+static void ata_acpi_handle_hotplug (struct ata_port *ap, struct kobject *kobj,
+                                    u32 event)
+{
+       char event_string[12];
+       char *envp[] = { event_string, NULL };
+       struct ata_eh_info *ehi = &ap->link.eh_info;
+
+       if (event == 0 || event == 1) {
+              unsigned long flags;
+              spin_lock_irqsave(ap->lock, flags);
+              ata_ehi_clear_desc(ehi);
+              ata_ehi_push_desc(ehi, "ACPI event");
+              ata_ehi_hotplugged(ehi);
+              ata_port_freeze(ap);
+              spin_unlock_irqrestore(ap->lock, flags);
+       }
+
+       if (kobj) {
+               sprintf(event_string, "BAY_EVENT=%d", event);
+               kobject_uevent_env(kobj, KOBJ_CHANGE, envp);
+       }
+}
+
+static void ata_acpi_dev_notify(acpi_handle handle, u32 event, void *data)
+{
+       struct ata_device *dev = data;
+       struct kobject *kobj = NULL;
+
+       if (dev->sdev)
+               kobj = &dev->sdev->sdev_gendev.kobj;
+
+       ata_acpi_handle_hotplug (dev->link->ap, kobj, event);
+}
+
+static void ata_acpi_ap_notify(acpi_handle handle, u32 event, void *data)
+{
+       struct ata_port *ap = data;
+
+       ata_acpi_handle_hotplug (ap, &ap->dev->kobj, event);
+}
+
 /**
  * ata_acpi_associate - associate ATA host with ACPI objects
  * @host: target ATA host
@@ -81,7 +152,7 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap)
  */
 void ata_acpi_associate(struct ata_host *host)
 {
-       int i;
+       int i, j;
 
        if (!is_pci_dev(host->dev) || libata_noacpi)
                return;
@@ -97,6 +168,22 @@ void ata_acpi_associate(struct ata_host *host)
                        ata_acpi_associate_sata_port(ap);
                else
                        ata_acpi_associate_ide_port(ap);
+
+               if (ap->acpi_handle)
+                       acpi_install_notify_handler (ap->acpi_handle,
+                                                    ACPI_SYSTEM_NOTIFY,
+                                                    ata_acpi_ap_notify,
+                                                    ap);
+
+               for (j = 0; j < ata_link_max_devices(&ap->link); j++) {
+                       struct ata_device *dev = &ap->link.device[j];
+
+                       if (dev->acpi_handle)
+                               acpi_install_notify_handler (dev->acpi_handle,
+                                                            ACPI_SYSTEM_NOTIFY,
+                                                            ata_acpi_dev_notify,
+                                                            dev);
+               }
        }
 }
 
@@ -113,7 +200,7 @@ void ata_acpi_associate(struct ata_host *host)
  * RETURNS:
  * 0 on success, -ENOENT if _GTM doesn't exist, -errno on failure.
  */
-static int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *gtm)
+int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *gtm)
 {
        struct acpi_buffer output = { .length = ACPI_ALLOCATE_BUFFER };
        union acpi_object *out_obj;
@@ -157,6 +244,8 @@ static int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *gtm)
        return rc;
 }
 
+EXPORT_SYMBOL_GPL(ata_acpi_gtm);
+
 /**
  * ata_acpi_stm - execute _STM
  * @ap: target ATA port
@@ -170,7 +259,7 @@ static int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *gtm)
  * RETURNS:
  * 0 on success, -ENOENT if _STM doesn't exist, -errno on failure.
  */
-static int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm)
+int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm)
 {
        acpi_status status;
        struct acpi_object_list         input;
@@ -182,10 +271,10 @@ static int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm)
        /* Buffers for id may need byteswapping ? */
        in_params[1].type = ACPI_TYPE_BUFFER;
        in_params[1].buffer.length = 512;
-       in_params[1].buffer.pointer = (u8 *)ap->device[0].id;
+       in_params[1].buffer.pointer = (u8 *)ap->link.device[0].id;
        in_params[2].type = ACPI_TYPE_BUFFER;
        in_params[2].buffer.length = 512;
-       in_params[2].buffer.pointer = (u8 *)ap->device[1].id;
+       in_params[2].buffer.pointer = (u8 *)ap->link.device[1].id;
 
        input.count = 3;
        input.pointer = in_params;
@@ -202,6 +291,8 @@ static int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm)
        return 0;
 }
 
+EXPORT_SYMBOL_GPL(ata_acpi_stm);
+
 /**
  * ata_dev_get_GTF - get the drive bootup default taskfile settings
  * @dev: target ATA device
@@ -226,7 +317,7 @@ static int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm)
 static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf,
                           void **ptr_to_free)
 {
-       struct ata_port *ap = dev->ap;
+       struct ata_port *ap = dev->link->ap;
        acpi_status status;
        struct acpi_buffer output;
        union acpi_object *out_obj;
@@ -295,6 +386,44 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf,
        return rc;
 }
 
+/**
+ * ata_acpi_cbl_80wire         -       Check for 80 wire cable
+ * @ap: Port to check
+ *
+ * Return 1 if the ACPI mode data for this port indicates the BIOS selected
+ * an 80wire mode.
+ */
+
+int ata_acpi_cbl_80wire(struct ata_port *ap)
+{
+       struct ata_acpi_gtm gtm;
+       int valid = 0;
+       
+       /* No _GTM data, no information */
+       if (ata_acpi_gtm(ap, &gtm) < 0)
+               return 0;
+               
+       /* Split timing, DMA enabled */
+       if ((gtm.flags & 0x11) == 0x11 && gtm.drive[0].dma < 55)
+               valid |= 1;
+       if ((gtm.flags & 0x14) == 0x14 && gtm.drive[1].dma < 55)
+               valid |= 2;
+       /* Shared timing, DMA enabled */
+       if ((gtm.flags & 0x11) == 0x01 && gtm.drive[0].dma < 55)
+               valid |= 1;
+       if ((gtm.flags & 0x14) == 0x04 && gtm.drive[0].dma < 55)
+               valid |= 2;
+
+       /* Drive check */
+       if ((valid & 1) && ata_dev_enabled(&ap->link.device[0]))
+               return 1;
+       if ((valid & 2) && ata_dev_enabled(&ap->link.device[1]))
+               return 1;
+       return 0;
+}
+
+EXPORT_SYMBOL_GPL(ata_acpi_cbl_80wire);
+
 /**
  * taskfile_load_raw - send taskfile registers to host controller
  * @dev: target ATA device
@@ -320,7 +449,7 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf,
 static int taskfile_load_raw(struct ata_device *dev,
                              const struct ata_acpi_gtf *gtf)
 {
-       struct ata_port *ap = dev->ap;
+       struct ata_port *ap = dev->link->ap;
        struct ata_taskfile tf, rtf;
        unsigned int err_mask;
 
@@ -349,7 +478,7 @@ static int taskfile_load_raw(struct ata_device *dev,
                               tf.lbal, tf.lbam, tf.lbah, tf.device);
 
        rtf = tf;
-       err_mask = ata_exec_internal(dev, &rtf, NULL, DMA_NONE, NULL, 0);
+       err_mask = ata_exec_internal(dev, &rtf, NULL, DMA_NONE, NULL, 0, 0);
        if (err_mask) {
                ata_dev_printk(dev, KERN_ERR,
                        "ACPI cmd %02x/%02x:%02x:%02x:%02x:%02x:%02x failed "
@@ -424,7 +553,7 @@ static int ata_acpi_exec_tfs(struct ata_device *dev)
  */
 static int ata_acpi_push_id(struct ata_device *dev)
 {
-       struct ata_port *ap = dev->ap;
+       struct ata_port *ap = dev->link->ap;
        int err;
        acpi_status status;
        struct acpi_object_list input;
@@ -508,7 +637,7 @@ int ata_acpi_on_suspend(struct ata_port *ap)
  */
 void ata_acpi_on_resume(struct ata_port *ap)
 {
-       int i;
+       struct ata_device *dev;
 
        if (ap->acpi_handle && (ap->pflags & ATA_PFLAG_GTM_VALID)) {
                BUG_ON(ap->flags & ATA_FLAG_ACPI_SATA);
@@ -518,8 +647,8 @@ void ata_acpi_on_resume(struct ata_port *ap)
        }
 
        /* schedule _GTF */
-       for (i = 0; i < ATA_MAX_DEVICES; i++)
-               ap->device[i].flags |= ATA_DFLAG_ACPI_PENDING;
+       ata_link_for_each_dev(dev, &ap->link)
+               dev->flags |= ATA_DFLAG_ACPI_PENDING;
 }
 
 /**
@@ -538,8 +667,8 @@ void ata_acpi_on_resume(struct ata_port *ap)
  */
 int ata_acpi_on_devcfg(struct ata_device *dev)
 {
-       struct ata_port *ap = dev->ap;
-       struct ata_eh_context *ehc = &ap->eh_context;
+       struct ata_port *ap = dev->link->ap;
+       struct ata_eh_context *ehc = &ap->link.eh_context;
        int acpi_sata = ap->flags & ATA_FLAG_ACPI_SATA;
        int rc;
 
index 772be09b468966277c7d1a41960d52b758cd7480..b05384a8c3261d1eb2b3e9c9108f82cf0763dd25 100644 (file)
@@ -59,8 +59,6 @@
 
 #include "libata.h"
 
-#define DRV_VERSION    "2.21"  /* must be exactly four chars */
-
 
 /* debounce timing parameters in msecs { interval, duration, timeout } */
 const unsigned long sata_deb_timing_normal[]           = {   5,  100, 2000 };
@@ -70,6 +68,7 @@ const unsigned long sata_deb_timing_long[]            = { 100, 2000, 5000 };
 static unsigned int ata_dev_init_params(struct ata_device *dev,
                                        u16 heads, u16 sectors);
 static unsigned int ata_dev_set_xfermode(struct ata_device *dev);
+static unsigned int ata_dev_set_AN(struct ata_device *dev, u8 enable);
 static void ata_dev_xfermask(struct ata_device *dev);
 static unsigned long ata_dev_blacklisted(const struct ata_device *dev);
 
@@ -86,6 +85,10 @@ int atapi_dmadir = 0;
 module_param(atapi_dmadir, int, 0444);
 MODULE_PARM_DESC(atapi_dmadir, "Enable ATAPI DMADIR bridge support (0=off, 1=on)");
 
+int atapi_passthru16 = 1;
+module_param(atapi_passthru16, int, 0444);
+MODULE_PARM_DESC(atapi_passthru16, "Enable ATA_16 passthru for ATAPI devices; on by default (0=off, 1=on)");
+
 int libata_fua = 0;
 module_param_named(fua, libata_fua, int, 0444);
 MODULE_PARM_DESC(fua, "FUA support (0=off, 1=on)");
@@ -94,13 +97,17 @@ static int ata_ignore_hpa = 0;
 module_param_named(ignore_hpa, ata_ignore_hpa, int, 0644);
 MODULE_PARM_DESC(ignore_hpa, "Ignore HPA limit (0=keep BIOS limits, 1=ignore limits, using full disk)");
 
+static int libata_dma_mask = ATA_DMA_MASK_ATA|ATA_DMA_MASK_ATAPI|ATA_DMA_MASK_CFA;
+module_param_named(dma, libata_dma_mask, int, 0444);
+MODULE_PARM_DESC(dma, "DMA enable/disable (0x1==ATA, 0x2==ATAPI, 0x4==CF)");
+
 static int ata_probe_timeout = ATA_TMOUT_INTERNAL / HZ;
 module_param(ata_probe_timeout, int, 0444);
 MODULE_PARM_DESC(ata_probe_timeout, "Set ATA probing timeout (seconds)");
 
-int libata_noacpi = 1;
+int libata_noacpi = 0;
 module_param_named(noacpi, libata_noacpi, int, 0444);
-MODULE_PARM_DESC(noacpi, "Disables the use of ACPI in suspend/resume when set");
+MODULE_PARM_DESC(noacpi, "Disables the use of ACPI in probe/suspend/resume when set");
 
 MODULE_AUTHOR("Jeff Garzik");
 MODULE_DESCRIPTION("Library module for ATA devices");
@@ -235,7 +242,7 @@ static int ata_rwcmd_protocol(struct ata_taskfile *tf, struct ata_device *dev)
        if (dev->flags & ATA_DFLAG_PIO) {
                tf->protocol = ATA_PROT_PIO;
                index = dev->multi_count ? 0 : 8;
-       } else if (lba48 && (dev->ap->flags & ATA_FLAG_PIO_LBA48)) {
+       } else if (lba48 && (dev->link->ap->flags & ATA_FLAG_PIO_LBA48)) {
                /* Unable to use DMA due to host limitation */
                tf->protocol = ATA_PROT_PIO;
                index = dev->multi_count ? 0 : 8;
@@ -604,7 +611,7 @@ static const char *sata_spd_string(unsigned int spd)
 void ata_dev_disable(struct ata_device *dev)
 {
        if (ata_dev_enabled(dev)) {
-               if (ata_msg_drv(dev->ap))
+               if (ata_msg_drv(dev->link->ap))
                        ata_dev_printk(dev, KERN_WARNING, "disabled\n");
                ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO0 |
                                             ATA_DNXFER_QUIET);
@@ -667,37 +674,57 @@ static unsigned int ata_devchk(struct ata_port *ap, unsigned int device)
  *     None.
  *
  *     RETURNS:
- *     Device type, %ATA_DEV_ATA, %ATA_DEV_ATAPI, or %ATA_DEV_UNKNOWN
- *     the event of failure.
+ *     Device type, %ATA_DEV_ATA, %ATA_DEV_ATAPI, %ATA_DEV_PMP or
+ *     %ATA_DEV_UNKNOWN the event of failure.
  */
-
 unsigned int ata_dev_classify(const struct ata_taskfile *tf)
 {
        /* Apple's open source Darwin code hints that some devices only
         * put a proper signature into the LBA mid/high registers,
         * So, we only check those.  It's sufficient for uniqueness.
+        *
+        * ATA/ATAPI-7 (d1532v1r1: Feb. 19, 2003) specified separate
+        * signatures for ATA and ATAPI devices attached on SerialATA,
+        * 0x3c/0xc3 and 0x69/0x96 respectively.  However, SerialATA
+        * spec has never mentioned about using different signatures
+        * for ATA/ATAPI devices.  Then, Serial ATA II: Port
+        * Multiplier specification began to use 0x69/0x96 to identify
+        * port multpliers and 0x3c/0xc3 to identify SEMB device.
+        * ATA/ATAPI-7 dropped descriptions about 0x3c/0xc3 and
+        * 0x69/0x96 shortly and described them as reserved for
+        * SerialATA.
+        *
+        * We follow the current spec and consider that 0x69/0x96
+        * identifies a port multiplier and 0x3c/0xc3 a SEMB device.
         */
-
-       if (((tf->lbam == 0) && (tf->lbah == 0)) ||
-           ((tf->lbam == 0x3c) && (tf->lbah == 0xc3))) {
+       if ((tf->lbam == 0) && (tf->lbah == 0)) {
                DPRINTK("found ATA device by sig\n");
                return ATA_DEV_ATA;
        }
 
-       if (((tf->lbam == 0x14) && (tf->lbah == 0xeb)) ||
-           ((tf->lbam == 0x69) && (tf->lbah == 0x96))) {
+       if ((tf->lbam == 0x14) && (tf->lbah == 0xeb)) {
                DPRINTK("found ATAPI device by sig\n");
                return ATA_DEV_ATAPI;
        }
 
+       if ((tf->lbam == 0x69) && (tf->lbah == 0x96)) {
+               DPRINTK("found PMP device by sig\n");
+               return ATA_DEV_PMP;
+       }
+
+       if ((tf->lbam == 0x3c) && (tf->lbah == 0xc3)) {
+               printk("ata: SEMB device ignored\n");
+               return ATA_DEV_SEMB_UNSUP; /* not yet */
+       }
+
        DPRINTK("unknown device\n");
        return ATA_DEV_UNKNOWN;
 }
 
 /**
  *     ata_dev_try_classify - Parse returned ATA device signature
- *     @ap: ATA channel to examine
- *     @device: Device to examine (starting at zero)
+ *     @dev: ATA device to classify (starting at zero)
+ *     @present: device seems present
  *     @r_err: Value of error register on completion
  *
  *     After an event -- SRST, E.D.D., or SATA COMRESET -- occurs,
@@ -715,15 +742,15 @@ unsigned int ata_dev_classify(const struct ata_taskfile *tf)
  *     RETURNS:
  *     Device type - %ATA_DEV_ATA, %ATA_DEV_ATAPI or %ATA_DEV_NONE.
  */
-
-unsigned int
-ata_dev_try_classify(struct ata_port *ap, unsigned int device, u8 *r_err)
+unsigned int ata_dev_try_classify(struct ata_device *dev, int present,
+                                 u8 *r_err)
 {
+       struct ata_port *ap = dev->link->ap;
        struct ata_taskfile tf;
        unsigned int class;
        u8 err;
 
-       ap->ops->dev_select(ap, device);
+       ap->ops->dev_select(ap, dev->devno);
 
        memset(&tf, 0, sizeof(tf));
 
@@ -733,12 +760,12 @@ ata_dev_try_classify(struct ata_port *ap, unsigned int device, u8 *r_err)
                *r_err = err;
 
        /* see if device passed diags: if master then continue and warn later */
-       if (err == 0 && device == 0)
+       if (err == 0 && dev->devno == 0)
                /* diagnostic fail : do nothing _YET_ */
-               ap->device[device].horkage |= ATA_HORKAGE_DIAGNOSTIC;
+               dev->horkage |= ATA_HORKAGE_DIAGNOSTIC;
        else if (err == 1)
                /* do nothing */ ;
-       else if ((device == 0) && (err == 0x81))
+       else if ((dev->devno == 0) && (err == 0x81))
                /* do nothing */ ;
        else
                return ATA_DEV_NONE;
@@ -746,10 +773,20 @@ ata_dev_try_classify(struct ata_port *ap, unsigned int device, u8 *r_err)
        /* determine if device is ATA or ATAPI */
        class = ata_dev_classify(&tf);
 
-       if (class == ATA_DEV_UNKNOWN)
-               return ATA_DEV_NONE;
-       if ((class == ATA_DEV_ATA) && (ata_chk_status(ap) == 0))
-               return ATA_DEV_NONE;
+       if (class == ATA_DEV_UNKNOWN) {
+               /* If the device failed diagnostic, it's likely to
+                * have reported incorrect device signature too.
+                * Assume ATA device if the device seems present but
+                * device signature is invalid with diagnostic
+                * failure.
+                */
+               if (present && (dev->horkage & ATA_HORKAGE_DIAGNOSTIC))
+                       class = ATA_DEV_ATA;
+               else
+                       class = ATA_DEV_NONE;
+       } else if ((class == ATA_DEV_ATA) && (ata_chk_status(ap) == 0))
+               class = ATA_DEV_NONE;
+
        return class;
 }
 
@@ -816,6 +853,21 @@ void ata_id_c_string(const u16 *id, unsigned char *s,
        *p = '\0';
 }
 
+static u64 ata_id_n_sectors(const u16 *id)
+{
+       if (ata_id_has_lba(id)) {
+               if (ata_id_has_lba48(id))
+                       return ata_id_u64(id, 100);
+               else
+                       return ata_id_u32(id, 60);
+       } else {
+               if (ata_id_current_chs_valid(id))
+                       return ata_id_u32(id, 57);
+               else
+                       return id[1] * id[3] * id[6];
+       }
+}
+
 static u64 ata_tf_to_lba48(struct ata_taskfile *tf)
 {
        u64 sectors = 0;
@@ -843,129 +895,110 @@ static u64 ata_tf_to_lba(struct ata_taskfile *tf)
 }
 
 /**
- *     ata_read_native_max_address_ext -       LBA48 native max query
- *     @dev: Device to query
+ *     ata_read_native_max_address - Read native max address
+ *     @dev: target device
+ *     @max_sectors: out parameter for the result native max address
  *
- *     Perform an LBA48 size query upon the device in question. Return the
- *     actual LBA48 size or zero if the command fails.
- */
-
-static u64 ata_read_native_max_address_ext(struct ata_device *dev)
-{
-       unsigned int err;
-       struct ata_taskfile tf;
-
-       ata_tf_init(dev, &tf);
-
-       tf.command = ATA_CMD_READ_NATIVE_MAX_EXT;
-       tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 | ATA_TFLAG_ISADDR;
-       tf.protocol |= ATA_PROT_NODATA;
-       tf.device |= 0x40;
-
-       err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
-       if (err)
-               return 0;
-
-       return ata_tf_to_lba48(&tf);
-}
-
-/**
- *     ata_read_native_max_address     -       LBA28 native max query
- *     @dev: Device to query
+ *     Perform an LBA48 or LBA28 native size query upon the device in
+ *     question.
  *
- *     Performa an LBA28 size query upon the device in question. Return the
- *     actual LBA28 size or zero if the command fails.
+ *     RETURNS:
+ *     0 on success, -EACCES if command is aborted by the drive.
+ *     -EIO on other errors.
  */
-
-static u64 ata_read_native_max_address(struct ata_device *dev)
+static int ata_read_native_max_address(struct ata_device *dev, u64 *max_sectors)
 {
-       unsigned int err;
+       unsigned int err_mask;
        struct ata_taskfile tf;
+       int lba48 = ata_id_has_lba48(dev->id);
 
        ata_tf_init(dev, &tf);
 
-       tf.command = ATA_CMD_READ_NATIVE_MAX;
+       /* always clear all address registers */
        tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
+
+       if (lba48) {
+               tf.command = ATA_CMD_READ_NATIVE_MAX_EXT;
+               tf.flags |= ATA_TFLAG_LBA48;
+       } else
+               tf.command = ATA_CMD_READ_NATIVE_MAX;
+
        tf.protocol |= ATA_PROT_NODATA;
-       tf.device |= 0x40;
+       tf.device |= ATA_LBA;
 
-       err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
-       if (err)
-               return 0;
+       err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
+       if (err_mask) {
+               ata_dev_printk(dev, KERN_WARNING, "failed to read native "
+                              "max address (err_mask=0x%x)\n", err_mask);
+               if (err_mask == AC_ERR_DEV && (tf.feature & ATA_ABORTED))
+                       return -EACCES;
+               return -EIO;
+       }
 
-       return ata_tf_to_lba(&tf);
+       if (lba48)
+               *max_sectors = ata_tf_to_lba48(&tf);
+       else
+               *max_sectors = ata_tf_to_lba(&tf);
+        if (dev->horkage & ATA_HORKAGE_HPA_SIZE)
+               (*max_sectors)--;
+       return 0;
 }
 
 /**
- *     ata_set_native_max_address_ext  -       LBA48 native max set
- *     @dev: Device to query
+ *     ata_set_max_sectors - Set max sectors
+ *     @dev: target device
  *     @new_sectors: new max sectors value to set for the device
  *
- *     Perform an LBA48 size set max upon the device in question. Return the
- *     actual LBA48 size or zero if the command fails.
+ *     Set max sectors of @dev to @new_sectors.
+ *
+ *     RETURNS:
+ *     0 on success, -EACCES if command is aborted or denied (due to
+ *     previous non-volatile SET_MAX) by the drive.  -EIO on other
+ *     errors.
  */
-
-static u64 ata_set_native_max_address_ext(struct ata_device *dev, u64 new_sectors)
+static int ata_set_max_sectors(struct ata_device *dev, u64 new_sectors)
 {
-       unsigned int err;
+       unsigned int err_mask;
        struct ata_taskfile tf;
+       int lba48 = ata_id_has_lba48(dev->id);
 
        new_sectors--;
 
        ata_tf_init(dev, &tf);
 
-       tf.command = ATA_CMD_SET_MAX_EXT;
-       tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 | ATA_TFLAG_ISADDR;
-       tf.protocol |= ATA_PROT_NODATA;
-       tf.device |= 0x40;
-
-       tf.lbal = (new_sectors >> 0) & 0xff;
-       tf.lbam = (new_sectors >> 8) & 0xff;
-       tf.lbah = (new_sectors >> 16) & 0xff;
-
-       tf.hob_lbal = (new_sectors >> 24) & 0xff;
-       tf.hob_lbam = (new_sectors >> 32) & 0xff;
-       tf.hob_lbah = (new_sectors >> 40) & 0xff;
-
-       err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
-       if (err)
-               return 0;
-
-       return ata_tf_to_lba48(&tf);
-}
-
-/**
- *     ata_set_native_max_address      -       LBA28 native max set
- *     @dev: Device to query
- *     @new_sectors: new max sectors value to set for the device
- *
- *     Perform an LBA28 size set max upon the device in question. Return the
- *     actual LBA28 size or zero if the command fails.
- */
+       tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
 
-static u64 ata_set_native_max_address(struct ata_device *dev, u64 new_sectors)
-{
-       unsigned int err;
-       struct ata_taskfile tf;
+       if (lba48) {
+               tf.command = ATA_CMD_SET_MAX_EXT;
+               tf.flags |= ATA_TFLAG_LBA48;
 
-       new_sectors--;
+               tf.hob_lbal = (new_sectors >> 24) & 0xff;
+               tf.hob_lbam = (new_sectors >> 32) & 0xff;
+               tf.hob_lbah = (new_sectors >> 40) & 0xff;
+       } else {
+               tf.command = ATA_CMD_SET_MAX;
 
-       ata_tf_init(dev, &tf);
+               tf.device |= (new_sectors >> 24) & 0xf;
+       }
 
-       tf.command = ATA_CMD_SET_MAX;
-       tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
        tf.protocol |= ATA_PROT_NODATA;
+       tf.device |= ATA_LBA;
 
        tf.lbal = (new_sectors >> 0) & 0xff;
        tf.lbam = (new_sectors >> 8) & 0xff;
        tf.lbah = (new_sectors >> 16) & 0xff;
-       tf.device |= ((new_sectors >> 24) & 0x0f) | 0x40;
 
-       err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
-       if (err)
-               return 0;
+       err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
+       if (err_mask) {
+               ata_dev_printk(dev, KERN_WARNING, "failed to set "
+                              "max address (err_mask=0x%x)\n", err_mask);
+               if (err_mask == AC_ERR_DEV &&
+                   (tf.feature & (ATA_ABORTED | ATA_IDNF)))
+                       return -EACCES;
+               return -EIO;
+       }
 
-       return ata_tf_to_lba(&tf);
+       return 0;
 }
 
 /**
@@ -975,60 +1008,93 @@ static u64 ata_set_native_max_address(struct ata_device *dev, u64 new_sectors)
  *     Read the size of an LBA28 or LBA48 disk with HPA features and resize
  *     it if required to the full size of the media. The caller must check
  *     the drive has the HPA feature set enabled.
+ *
+ *     RETURNS:
+ *     0 on success, -errno on failure.
  */
-
-static u64 ata_hpa_resize(struct ata_device *dev)
+static int ata_hpa_resize(struct ata_device *dev)
 {
-       u64 sectors = dev->n_sectors;
-       u64 hpa_sectors;
+       struct ata_eh_context *ehc = &dev->link->eh_context;
+       int print_info = ehc->i.flags & ATA_EHI_PRINTINFO;
+       u64 sectors = ata_id_n_sectors(dev->id);
+       u64 native_sectors;
+       int rc;
 
-       if (ata_id_has_lba48(dev->id))
-               hpa_sectors = ata_read_native_max_address_ext(dev);
-       else
-               hpa_sectors = ata_read_native_max_address(dev);
+       /* do we need to do it? */
+       if (dev->class != ATA_DEV_ATA ||
+           !ata_id_has_lba(dev->id) || !ata_id_hpa_enabled(dev->id) ||
+           (dev->horkage & ATA_HORKAGE_BROKEN_HPA))
+               return 0;
 
-       if (hpa_sectors > sectors) {
-               ata_dev_printk(dev, KERN_INFO,
-                       "Host Protected Area detected:\n"
-                       "\tcurrent size: %lld sectors\n"
-                       "\tnative size: %lld sectors\n",
-                       (long long)sectors, (long long)hpa_sectors);
-
-               if (ata_ignore_hpa) {
-                       if (ata_id_has_lba48(dev->id))
-                               hpa_sectors = ata_set_native_max_address_ext(dev, hpa_sectors);
-                       else
-                               hpa_sectors = ata_set_native_max_address(dev,
-                                                               hpa_sectors);
-
-                       if (hpa_sectors) {
-                               ata_dev_printk(dev, KERN_INFO, "native size "
-                                       "increased to %lld sectors\n",
-                                       (long long)hpa_sectors);
-                               return hpa_sectors;
-                       }
+       /* read native max address */
+       rc = ata_read_native_max_address(dev, &native_sectors);
+       if (rc) {
+               /* If HPA isn't going to be unlocked, skip HPA
+                * resizing from the next try.
+                */
+               if (!ata_ignore_hpa) {
+                       ata_dev_printk(dev, KERN_WARNING, "HPA support seems "
+                                      "broken, will skip HPA handling\n");
+                       dev->horkage |= ATA_HORKAGE_BROKEN_HPA;
+
+                       /* we can continue if device aborted the command */
+                       if (rc == -EACCES)
+                               rc = 0;
                }
-       } else if (hpa_sectors < sectors)
-               ata_dev_printk(dev, KERN_WARNING, "%s 1: hpa sectors (%lld) "
-                              "is smaller than sectors (%lld)\n", __FUNCTION__,
-                              (long long)hpa_sectors, (long long)sectors);
 
-       return sectors;
-}
+               return rc;
+       }
 
-static u64 ata_id_n_sectors(const u16 *id)
-{
-       if (ata_id_has_lba(id)) {
-               if (ata_id_has_lba48(id))
-                       return ata_id_u64(id, 100);
-               else
-                       return ata_id_u32(id, 60);
-       } else {
-               if (ata_id_current_chs_valid(id))
-                       return ata_id_u32(id, 57);
-               else
-                       return id[1] * id[3] * id[6];
+       /* nothing to do? */
+       if (native_sectors <= sectors || !ata_ignore_hpa) {
+               if (!print_info || native_sectors == sectors)
+                       return 0;
+
+               if (native_sectors > sectors)
+                       ata_dev_printk(dev, KERN_INFO,
+                               "HPA detected: current %llu, native %llu\n",
+                               (unsigned long long)sectors,
+                               (unsigned long long)native_sectors);
+               else if (native_sectors < sectors)
+                       ata_dev_printk(dev, KERN_WARNING,
+                               "native sectors (%llu) is smaller than "
+                               "sectors (%llu)\n",
+                               (unsigned long long)native_sectors,
+                               (unsigned long long)sectors);
+               return 0;
        }
+
+       /* let's unlock HPA */
+       rc = ata_set_max_sectors(dev, native_sectors);
+       if (rc == -EACCES) {
+               /* if device aborted the command, skip HPA resizing */
+               ata_dev_printk(dev, KERN_WARNING, "device aborted resize "
+                              "(%llu -> %llu), skipping HPA handling\n",
+                              (unsigned long long)sectors,
+                              (unsigned long long)native_sectors);
+               dev->horkage |= ATA_HORKAGE_BROKEN_HPA;
+               return 0;
+       } else if (rc)
+               return rc;
+
+       /* re-read IDENTIFY data */
+       rc = ata_dev_reread_id(dev, 0);
+       if (rc) {
+               ata_dev_printk(dev, KERN_ERR, "failed to re-read IDENTIFY "
+                              "data after HPA resizing\n");
+               return rc;
+       }
+
+       if (print_info) {
+               u64 new_sectors = ata_id_n_sectors(dev->id);
+               ata_dev_printk(dev, KERN_INFO,
+                       "HPA unlocked: %llu -> %llu, native %llu\n",
+                       (unsigned long long)sectors,
+                       (unsigned long long)new_sectors,
+                       (unsigned long long)native_sectors);
+       }
+
+       return 0;
 }
 
 /**
@@ -1150,7 +1216,7 @@ void ata_dev_select(struct ata_port *ap, unsigned int device,
        ap->ops->dev_select(ap, device);
 
        if (wait) {
-               if (can_sleep && ap->device[device].class == ATA_DEV_ATAPI)
+               if (can_sleep && ap->link.device[device].class == ATA_DEV_ATAPI)
                        msleep(150);
                ata_wait_idle(ap);
        }
@@ -1328,6 +1394,7 @@ static void ata_qc_complete_internal(struct ata_queued_cmd *qc)
  *     @dma_dir: Data tranfer direction of the command
  *     @sg: sg list for the data buffer of the command
  *     @n_elem: Number of sg entries
+ *     @timeout: Timeout in msecs (0 for default)
  *
  *     Executes libata internal command with timeout.  @tf contains
  *     command on entry and result on return.  Timeout and error
@@ -1344,13 +1411,15 @@ static void ata_qc_complete_internal(struct ata_queued_cmd *qc)
 unsigned ata_exec_internal_sg(struct ata_device *dev,
                              struct ata_taskfile *tf, const u8 *cdb,
                              int dma_dir, struct scatterlist *sg,
-                             unsigned int n_elem)
+                             unsigned int n_elem, unsigned long timeout)
 {
-       struct ata_port *ap = dev->ap;
+       struct ata_link *link = dev->link;
+       struct ata_port *ap = link->ap;
        u8 command = tf->command;
        struct ata_queued_cmd *qc;
        unsigned int tag, preempted_tag;
        u32 preempted_sactive, preempted_qc_active;
+       int preempted_nr_active_links;
        DECLARE_COMPLETION_ONSTACK(wait);
        unsigned long flags;
        unsigned int err_mask;
@@ -1386,12 +1455,14 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
        qc->dev = dev;
        ata_qc_reinit(qc);
 
-       preempted_tag = ap->active_tag;
-       preempted_sactive = ap->sactive;
+       preempted_tag = link->active_tag;
+       preempted_sactive = link->sactive;
        preempted_qc_active = ap->qc_active;
-       ap->active_tag = ATA_TAG_POISON;
-       ap->sactive = 0;
+       preempted_nr_active_links = ap->nr_active_links;
+       link->active_tag = ATA_TAG_POISON;
+       link->sactive = 0;
        ap->qc_active = 0;
+       ap->nr_active_links = 0;
 
        /* prepare & issue qc */
        qc->tf = *tf;
@@ -1416,7 +1487,10 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
 
        spin_unlock_irqrestore(ap->lock, flags);
 
-       rc = wait_for_completion_timeout(&wait, ata_probe_timeout);
+       if (!timeout)
+               timeout = ata_probe_timeout * 1000 / HZ;
+
+       rc = wait_for_completion_timeout(&wait, msecs_to_jiffies(timeout));
 
        ata_port_flush_task(ap);
 
@@ -1467,9 +1541,10 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
        err_mask = qc->err_mask;
 
        ata_qc_free(qc);
-       ap->active_tag = preempted_tag;
-       ap->sactive = preempted_sactive;
+       link->active_tag = preempted_tag;
+       link->sactive = preempted_sactive;
        ap->qc_active = preempted_qc_active;
+       ap->nr_active_links = preempted_nr_active_links;
 
        /* XXX - Some LLDDs (sata_mv) disable port on command failure.
         * Until those drivers are fixed, we detect the condition
@@ -1500,6 +1575,7 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
  *     @dma_dir: Data tranfer direction of the command
  *     @buf: Data buffer of the command
  *     @buflen: Length of data buffer
+ *     @timeout: Timeout in msecs (0 for default)
  *
  *     Wrapper around ata_exec_internal_sg() which takes simple
  *     buffer instead of sg list.
@@ -1512,7 +1588,8 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
  */
 unsigned ata_exec_internal(struct ata_device *dev,
                           struct ata_taskfile *tf, const u8 *cdb,
-                          int dma_dir, void *buf, unsigned int buflen)
+                          int dma_dir, void *buf, unsigned int buflen,
+                          unsigned long timeout)
 {
        struct scatterlist *psg = NULL, sg;
        unsigned int n_elem = 0;
@@ -1524,7 +1601,8 @@ unsigned ata_exec_internal(struct ata_device *dev,
                n_elem++;
        }
 
-       return ata_exec_internal_sg(dev, tf, cdb, dma_dir, psg, n_elem);
+       return ata_exec_internal_sg(dev, tf, cdb, dma_dir, psg, n_elem,
+                                   timeout);
 }
 
 /**
@@ -1551,7 +1629,7 @@ unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd)
        tf.flags |= ATA_TFLAG_DEVICE;
        tf.protocol = ATA_PROT_NODATA;
 
-       return ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+       return ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
 }
 
 /**
@@ -1566,7 +1644,7 @@ unsigned int ata_pio_need_iordy(const struct ata_device *adev)
 {
        /* Controller doesn't support  IORDY. Probably a pointless check
           as the caller should know this */
-       if (adev->ap->flags & ATA_FLAG_NO_IORDY)
+       if (adev->link->ap->flags & ATA_FLAG_NO_IORDY)
                return 0;
        /* PIO3 and higher it is mandatory */
        if (adev->pio_mode > XFER_PIO_2)
@@ -1613,6 +1691,9 @@ static u32 ata_pio_mask_no_iordy(const struct ata_device *adev)
  *     devices.  This function also issues ATA_CMD_INIT_DEV_PARAMS
  *     for pre-ATA4 drives.
  *
+ *     FIXME: ATA_CMD_ID_ATA is optional for early drives and right
+ *     now we abort if we hit that case. 
+ *
  *     LOCKING:
  *     Kernel thread context (may sleep)
  *
@@ -1622,7 +1703,7 @@ static u32 ata_pio_mask_no_iordy(const struct ata_device *adev)
 int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
                    unsigned int flags, u16 *id)
 {
-       struct ata_port *ap = dev->ap;
+       struct ata_port *ap = dev->link->ap;
        unsigned int class = *p_class;
        struct ata_taskfile tf;
        unsigned int err_mask = 0;
@@ -1663,7 +1744,7 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
        tf.flags |= ATA_TFLAG_POLLING;
 
        err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,
-                                    id, sizeof(id[0]) * ATA_ID_WORDS);
+                                    id, sizeof(id[0]) * ATA_ID_WORDS, 0);
        if (err_mask) {
                if (err_mask & AC_ERR_NODEV_HINT) {
                        DPRINTK("ata%u.%d: NODEV after polling detection\n",
@@ -1722,7 +1803,8 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
                tf.feature = SETFEATURES_SPINUP;
                tf.protocol = ATA_PROT_NODATA;
                tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
-               err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+               err_mask = ata_exec_internal(dev, &tf, NULL,
+                                            DMA_NONE, NULL, 0, 0);
                if (err_mask && id[2] != 0x738c) {
                        rc = -EIO;
                        reason = "SPINUP failed";
@@ -1740,10 +1822,13 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
                /*
                 * The exact sequence expected by certain pre-ATA4 drives is:
                 * SRST RESET
-                * IDENTIFY
-                * INITIALIZE DEVICE PARAMETERS
+                * IDENTIFY (optional in early ATA)
+                * INITIALIZE DEVICE PARAMETERS (later IDE and ATA)
                 * anything else..
                 * Some drives were very specific about that exact sequence.
+                *
+                * Note that ATA4 says lba is mandatory so the second check
+                * shoud never trigger.
                 */
                if (ata_id_major_version(id) < 4 || !ata_id_has_lba(id)) {
                        err_mask = ata_dev_init_params(dev, id[3], id[6]);
@@ -1774,13 +1859,14 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
 
 static inline u8 ata_dev_knobble(struct ata_device *dev)
 {
-       return ((dev->ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id)));
+       struct ata_port *ap = dev->link->ap;
+       return ((ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id)));
 }
 
 static void ata_dev_config_ncq(struct ata_device *dev,
                               char *desc, size_t desc_sz)
 {
-       struct ata_port *ap = dev->ap;
+       struct ata_port *ap = dev->link->ap;
        int hdepth = 0, ddepth = ata_id_queue_depth(dev->id);
 
        if (!ata_id_has_ncq(dev->id)) {
@@ -1817,8 +1903,8 @@ static void ata_dev_config_ncq(struct ata_device *dev,
  */
 int ata_dev_configure(struct ata_device *dev)
 {
-       struct ata_port *ap = dev->ap;
-       struct ata_eh_context *ehc = &ap->eh_context;
+       struct ata_port *ap = dev->link->ap;
+       struct ata_eh_context *ehc = &dev->link->eh_context;
        int print_info = ehc->i.flags & ATA_EHI_PRINTINFO;
        const u16 *id = dev->id;
        unsigned int xfer_mask;
@@ -1844,6 +1930,11 @@ int ata_dev_configure(struct ata_device *dev)
        if (rc)
                return rc;
 
+       /* massage HPA, do it early as it might change IDENTIFY data */
+       rc = ata_hpa_resize(dev);
+       if (rc)
+               return rc;
+
        /* print device capabilities */
        if (ata_msg_probe(ap))
                ata_dev_printk(dev, KERN_DEBUG,
@@ -1911,10 +2002,6 @@ int ata_dev_configure(struct ata_device *dev)
                                        dev->flags |= ATA_DFLAG_FLUSH_EXT;
                        }
 
-                       if (!(dev->horkage & ATA_HORKAGE_BROKEN_HPA) &&
-                           ata_id_hpa_enabled(dev->id))
-                               dev->n_sectors = ata_hpa_resize(dev);
-
                        /* config NCQ */
                        ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc));
 
@@ -1963,7 +2050,9 @@ int ata_dev_configure(struct ata_device *dev)
 
        /* ATAPI-specific feature tests */
        else if (dev->class == ATA_DEV_ATAPI) {
-               char *cdb_intr_string = "";
+               const char *cdb_intr_string = "";
+               const char *atapi_an_string = "";
+               u32 sntf;
 
                rc = atapi_cdb_len(id);
                if ((rc < 12) || (rc > ATAPI_CDB_LEN)) {
@@ -1975,6 +2064,28 @@ int ata_dev_configure(struct ata_device *dev)
                }
                dev->cdb_len = (unsigned int) rc;
 
+               /* Enable ATAPI AN if both the host and device have
+                * the support.  If PMP is attached, SNTF is required
+                * to enable ATAPI AN to discern between PHY status
+                * changed notifications and ATAPI ANs.
+                */
+               if ((ap->flags & ATA_FLAG_AN) && ata_id_has_atapi_AN(id) &&
+                   (!ap->nr_pmp_links ||
+                    sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf) == 0)) {
+                       unsigned int err_mask;
+
+                       /* issue SET feature command to turn this on */
+                       err_mask = ata_dev_set_AN(dev, SETFEATURES_SATA_ENABLE);
+                       if (err_mask)
+                               ata_dev_printk(dev, KERN_ERR,
+                                       "failed to enable ATAPI AN "
+                                       "(err_mask=0x%x)\n", err_mask);
+                       else {
+                               dev->flags |= ATA_DFLAG_AN;
+                               atapi_an_string = ", ATAPI AN";
+                       }
+               }
+
                if (ata_id_cdb_intr(dev->id)) {
                        dev->flags |= ATA_DFLAG_CDB_INTR;
                        cdb_intr_string = ", CDB intr";
@@ -1983,10 +2094,10 @@ int ata_dev_configure(struct ata_device *dev)
                /* print device info to dmesg */
                if (ata_msg_drv(ap) && print_info)
                        ata_dev_printk(dev, KERN_INFO,
-                                      "ATAPI: %s, %s, max %s%s\n",
+                                      "ATAPI: %s, %s, max %s%s%s\n",
                                       modelbuf, fwrevbuf,
                                       ata_mode_string(xfer_mask),
-                                      cdb_intr_string);
+                                      cdb_intr_string, atapi_an_string);
        }
 
        /* determine max_sectors */
@@ -2103,21 +2214,19 @@ int ata_bus_probe(struct ata_port *ap)
 {
        unsigned int classes[ATA_MAX_DEVICES];
        int tries[ATA_MAX_DEVICES];
-       int i, rc;
+       int rc;
        struct ata_device *dev;
 
        ata_port_probe(ap);
 
-       for (i = 0; i < ATA_MAX_DEVICES; i++)
-               tries[i] = ATA_PROBE_MAX_TRIES;
+       ata_link_for_each_dev(dev, &ap->link)
+               tries[dev->devno] = ATA_PROBE_MAX_TRIES;
 
  retry:
        /* reset and determine device classes */
        ap->ops->phy_reset(ap);
 
-       for (i = 0; i < ATA_MAX_DEVICES; i++) {
-               dev = &ap->device[i];
-
+       ata_link_for_each_dev(dev, &ap->link) {
                if (!(ap->flags & ATA_FLAG_DISABLED) &&
                    dev->class != ATA_DEV_UNKNOWN)
                        classes[dev->devno] = dev->class;
@@ -2132,18 +2241,16 @@ int ata_bus_probe(struct ata_port *ap)
        /* after the reset the device state is PIO 0 and the controller
           state is undefined. Record the mode */
 
-       for (i = 0; i < ATA_MAX_DEVICES; i++)
-               ap->device[i].pio_mode = XFER_PIO_0;
+       ata_link_for_each_dev(dev, &ap->link)
+               dev->pio_mode = XFER_PIO_0;
 
        /* read IDENTIFY page and configure devices. We have to do the identify
           specific sequence bass-ackwards so that PDIAG- is released by
           the slave device */
 
-       for (i = ATA_MAX_DEVICES - 1; i >=  0; i--) {
-               dev = &ap->device[i];
-
-               if (tries[i])
-                       dev->class = classes[i];
+       ata_link_for_each_dev(dev, &ap->link) {
+               if (tries[dev->devno])
+                       dev->class = classes[dev->devno];
 
                if (!ata_dev_enabled(dev))
                        continue;
@@ -2158,33 +2265,42 @@ int ata_bus_probe(struct ata_port *ap)
        if (ap->ops->cable_detect)
                ap->cbl = ap->ops->cable_detect(ap);
 
+       /* We may have SATA bridge glue hiding here irrespective of the
+          reported cable types and sensed types */
+       ata_link_for_each_dev(dev, &ap->link) {
+               if (!ata_dev_enabled(dev))
+                       continue;
+               /* SATA drives indicate we have a bridge. We don't know which
+                  end of the link the bridge is which is a problem */
+               if (ata_id_is_sata(dev->id))
+                       ap->cbl = ATA_CBL_SATA;
+       }
+
        /* After the identify sequence we can now set up the devices. We do
           this in the normal order so that the user doesn't get confused */
 
-       for(i = 0; i < ATA_MAX_DEVICES; i++) {
-               dev = &ap->device[i];
+       ata_link_for_each_dev(dev, &ap->link) {
                if (!ata_dev_enabled(dev))
                        continue;
 
-               ap->eh_context.i.flags |= ATA_EHI_PRINTINFO;
+               ap->link.eh_context.i.flags |= ATA_EHI_PRINTINFO;
                rc = ata_dev_configure(dev);
-               ap->eh_context.i.flags &= ~ATA_EHI_PRINTINFO;
+               ap->link.eh_context.i.flags &= ~ATA_EHI_PRINTINFO;
                if (rc)
                        goto fail;
        }
 
        /* configure transfer mode */
-       rc = ata_set_mode(ap, &dev);
+       rc = ata_set_mode(&ap->link, &dev);
        if (rc)
                goto fail;
 
-       for (i = 0; i < ATA_MAX_DEVICES; i++)
-               if (ata_dev_enabled(&ap->device[i]))
+       ata_link_for_each_dev(dev, &ap->link)
+               if (ata_dev_enabled(dev))
                        return 0;
 
        /* no device present, disable port */
        ata_port_disable(ap);
-       ap->ops->port_disable(ap);
        return -ENODEV;
 
  fail:
@@ -2204,7 +2320,7 @@ int ata_bus_probe(struct ata_port *ap)
                        /* This is the last chance, better to slow
                         * down than lose it.
                         */
-                       sata_down_spd_limit(ap);
+                       sata_down_spd_limit(&ap->link);
                        ata_down_xfermask_limit(dev, ATA_DNXFER_PIO);
                }
        }
@@ -2233,28 +2349,28 @@ void ata_port_probe(struct ata_port *ap)
 
 /**
  *     sata_print_link_status - Print SATA link status
- *     @ap: SATA port to printk link status about
+ *     @link: SATA link to printk link status about
  *
  *     This function prints link speed and status of a SATA link.
  *
  *     LOCKING:
  *     None.
  */
-void sata_print_link_status(struct ata_port *ap)
+void sata_print_link_status(struct ata_link *link)
 {
        u32 sstatus, scontrol, tmp;
 
-       if (sata_scr_read(ap, SCR_STATUS, &sstatus))
+       if (sata_scr_read(link, SCR_STATUS, &sstatus))
                return;
-       sata_scr_read(ap, SCR_CONTROL, &scontrol);
+       sata_scr_read(link, SCR_CONTROL, &scontrol);
 
-       if (ata_port_online(ap)) {
+       if (ata_link_online(link)) {
                tmp = (sstatus >> 4) & 0xf;
-               ata_port_printk(ap, KERN_INFO,
+               ata_link_printk(link, KERN_INFO,
                                "SATA link up %s (SStatus %X SControl %X)\n",
                                sata_spd_string(tmp), sstatus, scontrol);
        } else {
-               ata_port_printk(ap, KERN_INFO,
+               ata_link_printk(link, KERN_INFO,
                                "SATA link down (SStatus %X SControl %X)\n",
                                sstatus, scontrol);
        }
@@ -2274,32 +2390,33 @@ void sata_print_link_status(struct ata_port *ap)
  */
 void __sata_phy_reset(struct ata_port *ap)
 {
-       u32 sstatus;
+       struct ata_link *link = &ap->link;
        unsigned long timeout = jiffies + (HZ * 5);
+       u32 sstatus;
 
        if (ap->flags & ATA_FLAG_SATA_RESET) {
                /* issue phy wake/reset */
-               sata_scr_write_flush(ap, SCR_CONTROL, 0x301);
+               sata_scr_write_flush(link, SCR_CONTROL, 0x301);
                /* Couldn't find anything in SATA I/II specs, but
                 * AHCI-1.1 10.4.2 says at least 1 ms. */
                mdelay(1);
        }
        /* phy wake/clear reset */
-       sata_scr_write_flush(ap, SCR_CONTROL, 0x300);
+       sata_scr_write_flush(link, SCR_CONTROL, 0x300);
 
        /* wait for phy to become ready, if necessary */
        do {
                msleep(200);
-               sata_scr_read(ap, SCR_STATUS, &sstatus);
+               sata_scr_read(link, SCR_STATUS, &sstatus);
                if ((sstatus & 0xf) != 1)
                        break;
        } while (time_before(jiffies, timeout));
 
        /* print link status */
-       sata_print_link_status(ap);
+       sata_print_link_status(link);
 
        /* TODO: phy layer with polling, timeouts, etc. */
-       if (!ata_port_offline(ap))
+       if (!ata_link_offline(link))
                ata_port_probe(ap);
        else
                ata_port_disable(ap);
@@ -2344,8 +2461,8 @@ void sata_phy_reset(struct ata_port *ap)
 
 struct ata_device *ata_dev_pair(struct ata_device *adev)
 {
-       struct ata_port *ap = adev->ap;
-       struct ata_device *pair = &ap->device[1 - adev->devno];
+       struct ata_link *link = adev->link;
+       struct ata_device *pair = &link->device[1 - adev->devno];
        if (!ata_dev_enabled(pair))
                return NULL;
        return pair;
@@ -2366,16 +2483,16 @@ struct ata_device *ata_dev_pair(struct ata_device *adev)
 
 void ata_port_disable(struct ata_port *ap)
 {
-       ap->device[0].class = ATA_DEV_NONE;
-       ap->device[1].class = ATA_DEV_NONE;
+       ap->link.device[0].class = ATA_DEV_NONE;
+       ap->link.device[1].class = ATA_DEV_NONE;
        ap->flags |= ATA_FLAG_DISABLED;
 }
 
 /**
  *     sata_down_spd_limit - adjust SATA spd limit downward
- *     @ap: Port to adjust SATA spd limit for
+ *     @link: Link to adjust SATA spd limit for
  *
- *     Adjust SATA spd limit of @ap downward.  Note that this
+ *     Adjust SATA spd limit of @link downward.  Note that this
  *     function only adjusts the limit.  The change must be applied
  *     using sata_set_spd().
  *
@@ -2385,24 +2502,24 @@ void ata_port_disable(struct ata_port *ap)
  *     RETURNS:
  *     0 on success, negative errno on failure
  */
-int sata_down_spd_limit(struct ata_port *ap)
+int sata_down_spd_limit(struct ata_link *link)
 {
        u32 sstatus, spd, mask;
        int rc, highbit;
 
-       if (!sata_scr_valid(ap))
+       if (!sata_scr_valid(link))
                return -EOPNOTSUPP;
 
        /* If SCR can be read, use it to determine the current SPD.
-        * If not, use cached value in ap->sata_spd.
+        * If not, use cached value in link->sata_spd.
         */
-       rc = sata_scr_read(ap, SCR_STATUS, &sstatus);
+       rc = sata_scr_read(link, SCR_STATUS, &sstatus);
        if (rc == 0)
                spd = (sstatus >> 4) & 0xf;
        else
-               spd = ap->sata_spd;
+               spd = link->sata_spd;
 
-       mask = ap->sata_spd_limit;
+       mask = link->sata_spd_limit;
        if (mask <= 1)
                return -EINVAL;
 
@@ -2422,22 +2539,22 @@ int sata_down_spd_limit(struct ata_port *ap)
        if (!mask)
                return -EINVAL;
 
-       ap->sata_spd_limit = mask;
+       link->sata_spd_limit = mask;
 
-       ata_port_printk(ap, KERN_WARNING, "limiting SATA link speed to %s\n",
+       ata_link_printk(link, KERN_WARNING, "limiting SATA link speed to %s\n",
                        sata_spd_string(fls(mask)));
 
        return 0;
 }
 
-static int __sata_set_spd_needed(struct ata_port *ap, u32 *scontrol)
+static int __sata_set_spd_needed(struct ata_link *link, u32 *scontrol)
 {
        u32 spd, limit;
 
-       if (ap->sata_spd_limit == UINT_MAX)
+       if (link->sata_spd_limit == UINT_MAX)
                limit = 0;
        else
-               limit = fls(ap->sata_spd_limit);
+               limit = fls(link->sata_spd_limit);
 
        spd = (*scontrol >> 4) & 0xf;
        *scontrol = (*scontrol & ~0xf0) | ((limit & 0xf) << 4);
@@ -2447,10 +2564,10 @@ static int __sata_set_spd_needed(struct ata_port *ap, u32 *scontrol)
 
 /**
  *     sata_set_spd_needed - is SATA spd configuration needed
- *     @ap: Port in question
+ *     @link: Link in question
  *
  *     Test whether the spd limit in SControl matches
- *     @ap->sata_spd_limit.  This function is used to determine
+ *     @link->sata_spd_limit.  This function is used to determine
  *     whether hardreset is necessary to apply SATA spd
  *     configuration.
  *
@@ -2460,21 +2577,21 @@ static int __sata_set_spd_needed(struct ata_port *ap, u32 *scontrol)
  *     RETURNS:
  *     1 if SATA spd configuration is needed, 0 otherwise.
  */
-int sata_set_spd_needed(struct ata_port *ap)
+int sata_set_spd_needed(struct ata_link *link)
 {
        u32 scontrol;
 
-       if (sata_scr_read(ap, SCR_CONTROL, &scontrol))
+       if (sata_scr_read(link, SCR_CONTROL, &scontrol))
                return 0;
 
-       return __sata_set_spd_needed(ap, &scontrol);
+       return __sata_set_spd_needed(link, &scontrol);
 }
 
 /**
  *     sata_set_spd - set SATA spd according to spd limit
- *     @ap: Port to set SATA spd for
+ *     @link: Link to set SATA spd for
  *
- *     Set SATA spd of @ap according to sata_spd_limit.
+ *     Set SATA spd of @link according to sata_spd_limit.
  *
  *     LOCKING:
  *     Inherited from caller.
@@ -2483,18 +2600,18 @@ int sata_set_spd_needed(struct ata_port *ap)
  *     0 if spd doesn't need to be changed, 1 if spd has been
  *     changed.  Negative errno if SCR registers are inaccessible.
  */
-int sata_set_spd(struct ata_port *ap)
+int sata_set_spd(struct ata_link *link)
 {
        u32 scontrol;
        int rc;
 
-       if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
+       if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
                return rc;
 
-       if (!__sata_set_spd_needed(ap, &scontrol))
+       if (!__sata_set_spd_needed(link, &scontrol))
                return 0;
 
-       if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol)))
+       if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol)))
                return rc;
 
        return 1;
@@ -2749,7 +2866,7 @@ int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel)
 
 static int ata_dev_set_mode(struct ata_device *dev)
 {
-       struct ata_eh_context *ehc = &dev->ap->eh_context;
+       struct ata_eh_context *ehc = &dev->link->eh_context;
        unsigned int err_mask;
        int rc;
 
@@ -2761,7 +2878,11 @@ static int ata_dev_set_mode(struct ata_device *dev)
        /* Old CFA may refuse this command, which is just fine */
        if (dev->xfer_shift == ATA_SHIFT_PIO && ata_id_is_cfa(dev->id))
                err_mask &= ~AC_ERR_DEV;
-
+       /* Some very old devices and some bad newer ones fail any kind of
+          SET_XFERMODE request but support PIO0-2 timings and no IORDY */
+       if (dev->xfer_shift == ATA_SHIFT_PIO && !ata_id_has_iordy(dev->id) &&
+                       dev->pio_mode <= XFER_PIO_2)
+               err_mask &= ~AC_ERR_DEV;
        if (err_mask) {
                ata_dev_printk(dev, KERN_ERR, "failed to set xfermode "
                               "(err_mask=0x%x)\n", err_mask);
@@ -2769,7 +2890,7 @@ static int ata_dev_set_mode(struct ata_device *dev)
        }
 
        ehc->i.flags |= ATA_EHI_POST_SETMODE;
-       rc = ata_dev_revalidate(dev, 0);
+       rc = ata_dev_revalidate(dev, ATA_DEV_UNKNOWN, 0);
        ehc->i.flags &= ~ATA_EHI_POST_SETMODE;
        if (rc)
                return rc;
@@ -2784,7 +2905,7 @@ static int ata_dev_set_mode(struct ata_device *dev)
 
 /**
  *     ata_do_set_mode - Program timings and issue SET FEATURES - XFER
- *     @ap: port on which timings will be programmed
+ *     @link: link on which timings will be programmed
  *     @r_failed_dev: out paramter for failed device
  *
  *     Standard implementation of the function used to tune and set
@@ -2799,25 +2920,36 @@ static int ata_dev_set_mode(struct ata_device *dev)
  *     0 on success, negative errno otherwise
  */
 
-int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
+int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
 {
+       struct ata_port *ap = link->ap;
        struct ata_device *dev;
-       int i, rc = 0, used_dma = 0, found = 0;
-
+       int rc = 0, used_dma = 0, found = 0;
 
        /* step 1: calculate xfer_mask */
-       for (i = 0; i < ATA_MAX_DEVICES; i++) {
+       ata_link_for_each_dev(dev, link) {
                unsigned int pio_mask, dma_mask;
-
-               dev = &ap->device[i];
+               unsigned int mode_mask;
 
                if (!ata_dev_enabled(dev))
                        continue;
 
+               mode_mask = ATA_DMA_MASK_ATA;
+               if (dev->class == ATA_DEV_ATAPI)
+                       mode_mask = ATA_DMA_MASK_ATAPI;
+               else if (ata_id_is_cfa(dev->id))
+                       mode_mask = ATA_DMA_MASK_CFA;
+
                ata_dev_xfermask(dev);
 
                pio_mask = ata_pack_xfermask(dev->pio_mask, 0, 0);
                dma_mask = ata_pack_xfermask(0, dev->mwdma_mask, dev->udma_mask);
+
+               if (libata_dma_mask & mode_mask)
+                       dma_mask = ata_pack_xfermask(0, dev->mwdma_mask, dev->udma_mask);
+               else
+                       dma_mask = 0;
+
                dev->pio_mode = ata_xfer_mask2mode(pio_mask);
                dev->dma_mode = ata_xfer_mask2mode(dma_mask);
 
@@ -2829,8 +2961,7 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
                goto out;
 
        /* step 2: always set host PIO timings */
-       for (i = 0; i < ATA_MAX_DEVICES; i++) {
-               dev = &ap->device[i];
+       ata_link_for_each_dev(dev, link) {
                if (!ata_dev_enabled(dev))
                        continue;
 
@@ -2847,9 +2978,7 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
        }
 
        /* step 3: set host DMA timings */
-       for (i = 0; i < ATA_MAX_DEVICES; i++) {
-               dev = &ap->device[i];
-
+       ata_link_for_each_dev(dev, link) {
                if (!ata_dev_enabled(dev) || !dev->dma_mode)
                        continue;
 
@@ -2860,9 +2989,7 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
        }
 
        /* step 4: update devices' xfer mode */
-       for (i = 0; i < ATA_MAX_DEVICES; i++) {
-               dev = &ap->device[i];
-
+       ata_link_for_each_dev(dev, link) {
                /* don't update suspended devices' xfer mode */
                if (!ata_dev_enabled(dev))
                        continue;
@@ -2886,7 +3013,7 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
 
 /**
  *     ata_set_mode - Program timings and issue SET FEATURES - XFER
- *     @ap: port on which timings will be programmed
+ *     @link: link on which timings will be programmed
  *     @r_failed_dev: out paramter for failed device
  *
  *     Set ATA device disk transfer mode (PIO3, UDMA6, etc.).  If
@@ -2899,12 +3026,14 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
  *     RETURNS:
  *     0 on success, negative errno otherwise
  */
-int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
+int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
 {
+       struct ata_port *ap = link->ap;
+
        /* has private set_mode? */
        if (ap->ops->set_mode)
-               return ap->ops->set_mode(ap, r_failed_dev);
-       return ata_do_set_mode(ap, r_failed_dev);
+               return ap->ops->set_mode(link, r_failed_dev);
+       return ata_do_set_mode(link, r_failed_dev);
 }
 
 /**
@@ -3007,7 +3136,7 @@ int ata_wait_ready(struct ata_port *ap, unsigned long deadline)
 
                if (!(status & ATA_BUSY))
                        return 0;
-               if (!ata_port_online(ap) && status == 0xff)
+               if (!ata_link_online(&ap->link) && status == 0xff)
                        return -ENODEV;
                if (time_after(now, deadline))
                        return -EBUSY;
@@ -3088,6 +3217,8 @@ static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask,
                             unsigned long deadline)
 {
        struct ata_ioports *ioaddr = &ap->ioaddr;
+       struct ata_device *dev;
+       int i = 0;
 
        DPRINTK("ata%u: bus reset via SRST\n", ap->print_id);
 
@@ -3098,6 +3229,25 @@ static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask,
        udelay(20);     /* FIXME: flush */
        iowrite8(ap->ctl, ioaddr->ctl_addr);
 
+       /* If we issued an SRST then an ATA drive (not ATAPI)
+        * may have changed configuration and be in PIO0 timing. If
+        * we did a hard reset (or are coming from power on) this is
+        * true for ATA or ATAPI. Until we've set a suitable controller
+        * mode we should not touch the bus as we may be talking too fast.
+        */
+
+       ata_link_for_each_dev(dev, &ap->link)
+               dev->pio_mode = XFER_PIO_0;
+
+       /* If the controller has a pio mode setup function then use
+          it to set the chipset to rights. Don't touch the DMA setup
+          as that will be dealt with when revalidating */
+       if (ap->ops->set_piomode) {
+               ata_link_for_each_dev(dev, &ap->link)
+                       if (devmask & (1 << i++))
+                               ap->ops->set_piomode(ap, dev);
+       }
+
        /* spec mandates ">= 2ms" before checking status.
         * We wait 150ms, because that was the magic delay used for
         * ATAPI devices in Hale Landis's ATADRVR, for the period of time
@@ -3142,6 +3292,7 @@ static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask,
 
 void ata_bus_reset(struct ata_port *ap)
 {
+       struct ata_device *device = ap->link.device;
        struct ata_ioports *ioaddr = &ap->ioaddr;
        unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
        u8 err;
@@ -3177,19 +3328,19 @@ void ata_bus_reset(struct ata_port *ap)
        /*
         * determine by signature whether we have ATA or ATAPI devices
         */
-       ap->device[0].class = ata_dev_try_classify(ap, 0, &err);
+       device[0].class = ata_dev_try_classify(&device[0], dev0, &err);
        if ((slave_possible) && (err != 0x81))
-               ap->device[1].class = ata_dev_try_classify(ap, 1, &err);
+               device[1].class = ata_dev_try_classify(&device[1], dev1, &err);
 
        /* is double-select really necessary? */
-       if (ap->device[1].class != ATA_DEV_NONE)
+       if (device[1].class != ATA_DEV_NONE)
                ap->ops->dev_select(ap, 1);
-       if (ap->device[0].class != ATA_DEV_NONE)
+       if (device[0].class != ATA_DEV_NONE)
                ap->ops->dev_select(ap, 0);
 
        /* if no devices were detected, disable this port */
-       if ((ap->device[0].class == ATA_DEV_NONE) &&
-           (ap->device[1].class == ATA_DEV_NONE))
+       if ((device[0].class == ATA_DEV_NONE) &&
+           (device[1].class == ATA_DEV_NONE))
                goto err_out;
 
        if (ap->flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST)) {
@@ -3202,18 +3353,18 @@ void ata_bus_reset(struct ata_port *ap)
 
 err_out:
        ata_port_printk(ap, KERN_ERR, "disabling port\n");
-       ap->ops->port_disable(ap);
+       ata_port_disable(ap);
 
        DPRINTK("EXIT\n");
 }
 
 /**
- *     sata_phy_debounce - debounce SATA phy status
- *     @ap: ATA port to debounce SATA phy status for
+ *     sata_link_debounce - debounce SATA phy status
+ *     @link: ATA link to debounce SATA phy status for
  *     @params: timing parameters { interval, duratinon, timeout } in msec
  *     @deadline: deadline jiffies for the operation
  *
- *     Make sure SStatus of @ap reaches stable state, determined by
+*      Make sure SStatus of @link reaches stable state, determined by
  *     holding the same value where DET is not 1 for @duration polled
  *     every @interval, before @timeout.  Timeout constraints the
  *     beginning of the stable state.  Because DET gets stuck at 1 on
@@ -3229,8 +3380,8 @@ err_out:
  *     RETURNS:
  *     0 on success, -errno on failure.
  */
-int sata_phy_debounce(struct ata_port *ap, const unsigned long *params,
-                     unsigned long deadline)
+int sata_link_debounce(struct ata_link *link, const unsigned long *params,
+                      unsigned long deadline)
 {
        unsigned long interval_msec = params[0];
        unsigned long duration = msecs_to_jiffies(params[1]);
@@ -3242,7 +3393,7 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params,
        if (time_before(t, deadline))
                deadline = t;
 
-       if ((rc = sata_scr_read(ap, SCR_STATUS, &cur)))
+       if ((rc = sata_scr_read(link, SCR_STATUS, &cur)))
                return rc;
        cur &= 0xf;
 
@@ -3251,7 +3402,7 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params,
 
        while (1) {
                msleep(interval_msec);
-               if ((rc = sata_scr_read(ap, SCR_STATUS, &cur)))
+               if ((rc = sata_scr_read(link, SCR_STATUS, &cur)))
                        return rc;
                cur &= 0xf;
 
@@ -3277,12 +3428,12 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params,
 }
 
 /**
- *     sata_phy_resume - resume SATA phy
- *     @ap: ATA port to resume SATA phy for
+ *     sata_link_resume - resume SATA link
+ *     @link: ATA link to resume SATA
  *     @params: timing parameters { interval, duratinon, timeout } in msec
  *     @deadline: deadline jiffies for the operation
  *
- *     Resume SATA phy of @ap and debounce it.
+ *     Resume SATA phy @link and debounce it.
  *
  *     LOCKING:
  *     Kernel thread context (may sleep)
@@ -3290,18 +3441,18 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params,
  *     RETURNS:
  *     0 on success, -errno on failure.
  */
-int sata_phy_resume(struct ata_port *ap, const unsigned long *params,
-                   unsigned long deadline)
+int sata_link_resume(struct ata_link *link, const unsigned long *params,
+                    unsigned long deadline)
 {
        u32 scontrol;
        int rc;
 
-       if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
+       if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
                return rc;
 
        scontrol = (scontrol & 0x0f0) | 0x300;
 
-       if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol)))
+       if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol)))
                return rc;
 
        /* Some PHYs react badly if SStatus is pounded immediately
@@ -3309,15 +3460,15 @@ int sata_phy_resume(struct ata_port *ap, const unsigned long *params,
         */
        msleep(200);
 
-       return sata_phy_debounce(ap, params, deadline);
+       return sata_link_debounce(link, params, deadline);
 }
 
 /**
  *     ata_std_prereset - prepare for reset
- *     @ap: ATA port to be reset
+ *     @link: ATA link to be reset
  *     @deadline: deadline jiffies for the operation
  *
- *     @ap is about to be reset.  Initialize it.  Failure from
+ *     @link is about to be reset.  Initialize it.  Failure from
  *     prereset makes libata abort whole reset sequence and give up
  *     that port, so prereset should be best-effort.  It does its
  *     best to prepare for reset sequence but if things go wrong, it
@@ -3329,37 +3480,44 @@ int sata_phy_resume(struct ata_port *ap, const unsigned long *params,
  *     RETURNS:
  *     0 on success, -errno otherwise.
  */
-int ata_std_prereset(struct ata_port *ap, unsigned long deadline)
+int ata_std_prereset(struct ata_link *link, unsigned long deadline)
 {
-       struct ata_eh_context *ehc = &ap->eh_context;
+       struct ata_port *ap = link->ap;
+       struct ata_eh_context *ehc = &link->eh_context;
        const unsigned long *timing = sata_ehc_deb_timing(ehc);
        int rc;
 
        /* handle link resume */
        if ((ehc->i.flags & ATA_EHI_RESUME_LINK) &&
-           (ap->flags & ATA_FLAG_HRST_TO_RESUME))
+           (link->flags & ATA_LFLAG_HRST_TO_RESUME))
+               ehc->i.action |= ATA_EH_HARDRESET;
+
+       /* Some PMPs don't work with only SRST, force hardreset if PMP
+        * is supported.
+        */
+       if (ap->flags & ATA_FLAG_PMP)
                ehc->i.action |= ATA_EH_HARDRESET;
 
        /* if we're about to do hardreset, nothing more to do */
        if (ehc->i.action & ATA_EH_HARDRESET)
                return 0;
 
-       /* if SATA, resume phy */
+       /* if SATA, resume link */
        if (ap->flags & ATA_FLAG_SATA) {
-               rc = sata_phy_resume(ap, timing, deadline);
+               rc = sata_link_resume(link, timing, deadline);
                /* whine about phy resume failure but proceed */
                if (rc && rc != -EOPNOTSUPP)
-                       ata_port_printk(ap, KERN_WARNING, "failed to resume "
+                       ata_link_printk(link, KERN_WARNING, "failed to resume "
                                        "link for reset (errno=%d)\n", rc);
        }
 
        /* Wait for !BSY if the controller can wait for the first D2H
         * Reg FIS and we don't know that no device is attached.
         */
-       if (!(ap->flags & ATA_FLAG_SKIP_D2H_BSY) && !ata_port_offline(ap)) {
+       if (!(link->flags & ATA_LFLAG_SKIP_D2H_BSY) && !ata_link_offline(link)) {
                rc = ata_wait_ready(ap, deadline);
                if (rc && rc != -ENODEV) {
-                       ata_port_printk(ap, KERN_WARNING, "device not ready "
+                       ata_link_printk(link, KERN_WARNING, "device not ready "
                                        "(errno=%d), forcing hardreset\n", rc);
                        ehc->i.action |= ATA_EH_HARDRESET;
                }
@@ -3370,7 +3528,7 @@ int ata_std_prereset(struct ata_port *ap, unsigned long deadline)
 
 /**
  *     ata_std_softreset - reset host port via ATA SRST
- *     @ap: port to reset
+ *     @link: ATA link to reset
  *     @classes: resulting classes of attached devices
  *     @deadline: deadline jiffies for the operation
  *
@@ -3382,9 +3540,10 @@ int ata_std_prereset(struct ata_port *ap, unsigned long deadline)
  *     RETURNS:
  *     0 on success, -errno otherwise.
  */
-int ata_std_softreset(struct ata_port *ap, unsigned int *classes,
+int ata_std_softreset(struct ata_link *link, unsigned int *classes,
                      unsigned long deadline)
 {
+       struct ata_port *ap = link->ap;
        unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
        unsigned int devmask = 0;
        int rc;
@@ -3392,7 +3551,7 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes,
 
        DPRINTK("ENTER\n");
 
-       if (ata_port_offline(ap)) {
+       if (ata_link_offline(link)) {
                classes[0] = ATA_DEV_NONE;
                goto out;
        }
@@ -3410,15 +3569,17 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes,
        DPRINTK("about to softreset, devmask=%x\n", devmask);
        rc = ata_bus_softreset(ap, devmask, deadline);
        /* if link is occupied, -ENODEV too is an error */
-       if (rc && (rc != -ENODEV || sata_scr_valid(ap))) {
-               ata_port_printk(ap, KERN_ERR, "SRST failed (errno=%d)\n", rc);
+       if (rc && (rc != -ENODEV || sata_scr_valid(link))) {
+               ata_link_printk(link, KERN_ERR, "SRST failed (errno=%d)\n", rc);
                return rc;
        }
 
        /* determine by signature whether we have ATA or ATAPI devices */
-       classes[0] = ata_dev_try_classify(ap, 0, &err);
+       classes[0] = ata_dev_try_classify(&link->device[0],
+                                         devmask & (1 << 0), &err);
        if (slave_possible && err != 0x81)
-               classes[1] = ata_dev_try_classify(ap, 1, &err);
+               classes[1] = ata_dev_try_classify(&link->device[1],
+                                                 devmask & (1 << 1), &err);
 
  out:
        DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]);
@@ -3426,12 +3587,12 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes,
 }
 
 /**
- *     sata_port_hardreset - reset port via SATA phy reset
- *     @ap: port to reset
+ *     sata_link_hardreset - reset link via SATA phy reset
+ *     @link: link to reset
  *     @timing: timing parameters { interval, duratinon, timeout } in msec
  *     @deadline: deadline jiffies for the operation
  *
- *     SATA phy-reset host port using DET bits of SControl register.
+ *     SATA phy-reset @link using DET bits of SControl register.
  *
  *     LOCKING:
  *     Kernel thread context (may sleep)
@@ -3439,7 +3600,7 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes,
  *     RETURNS:
  *     0 on success, -errno otherwise.
  */
-int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing,
+int sata_link_hardreset(struct ata_link *link, const unsigned long *timing,
                        unsigned long deadline)
 {
        u32 scontrol;
@@ -3447,30 +3608,30 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing,
 
        DPRINTK("ENTER\n");
 
-       if (sata_set_spd_needed(ap)) {
+       if (sata_set_spd_needed(link)) {
                /* SATA spec says nothing about how to reconfigure
                 * spd.  To be on the safe side, turn off phy during
                 * reconfiguration.  This works for at least ICH7 AHCI
                 * and Sil3124.
                 */
-               if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
+               if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
                        goto out;
 
                scontrol = (scontrol & 0x0f0) | 0x304;
 
-               if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol)))
+               if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol)))
                        goto out;
 
-               sata_set_spd(ap);
+               sata_set_spd(link);
        }
 
        /* issue phy wake/reset */
-       if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
+       if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
                goto out;
 
        scontrol = (scontrol & 0x0f0) | 0x301;
 
-       if ((rc = sata_scr_write_flush(ap, SCR_CONTROL, scontrol)))
+       if ((rc = sata_scr_write_flush(link, SCR_CONTROL, scontrol)))
                goto out;
 
        /* Couldn't find anything in SATA I/II specs, but AHCI-1.1
@@ -3478,8 +3639,8 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing,
         */
        msleep(1);
 
-       /* bring phy back */
-       rc = sata_phy_resume(ap, timing, deadline);
+       /* bring link back */
+       rc = sata_link_resume(link, timing, deadline);
  out:
        DPRINTK("EXIT, rc=%d\n", rc);
        return rc;
@@ -3487,7 +3648,7 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing,
 
 /**
  *     sata_std_hardreset - reset host port via SATA phy reset
- *     @ap: port to reset
+ *     @link: link to reset
  *     @class: resulting class of attached device
  *     @deadline: deadline jiffies for the operation
  *
@@ -3500,24 +3661,25 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing,
  *     RETURNS:
  *     0 on success, -errno otherwise.
  */
-int sata_std_hardreset(struct ata_port *ap, unsigned int *class,
+int sata_std_hardreset(struct ata_link *link, unsigned int *class,
                       unsigned long deadline)
 {
-       const unsigned long *timing = sata_ehc_deb_timing(&ap->eh_context);
+       struct ata_port *ap = link->ap;
+       const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
        int rc;
 
        DPRINTK("ENTER\n");
 
        /* do hardreset */
-       rc = sata_port_hardreset(ap, timing, deadline);
+       rc = sata_link_hardreset(link, timing, deadline);
        if (rc) {
-               ata_port_printk(ap, KERN_ERR,
+               ata_link_printk(link, KERN_ERR,
                                "COMRESET failed (errno=%d)\n", rc);
                return rc;
        }
 
        /* TODO: phy layer with polling, timeouts, etc. */
-       if (ata_port_offline(ap)) {
+       if (ata_link_offline(link)) {
                *class = ATA_DEV_NONE;
                DPRINTK("EXIT, link offline\n");
                return 0;
@@ -3526,17 +3688,27 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class,
        /* wait a while before checking status, see SRST for more info */
        msleep(150);
 
+       /* If PMP is supported, we have to do follow-up SRST.  Note
+        * that some PMPs don't send D2H Reg FIS after hardreset at
+        * all if the first port is empty.  Wait for it just for a
+        * second and request follow-up SRST.
+        */
+       if (ap->flags & ATA_FLAG_PMP) {
+               ata_wait_ready(ap, jiffies + HZ);
+               return -EAGAIN;
+       }
+
        rc = ata_wait_ready(ap, deadline);
        /* link occupied, -ENODEV too is an error */
        if (rc) {
-               ata_port_printk(ap, KERN_ERR,
+               ata_link_printk(link, KERN_ERR,
                                "COMRESET failed (errno=%d)\n", rc);
                return rc;
        }
 
        ap->ops->dev_select(ap, 0);     /* probably unnecessary */
 
-       *class = ata_dev_try_classify(ap, 0, NULL);
+       *class = ata_dev_try_classify(link->device, 1, NULL);
 
        DPRINTK("EXIT, class=%u\n", *class);
        return 0;
@@ -3544,7 +3716,7 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class,
 
 /**
  *     ata_std_postreset - standard postreset callback
- *     @ap: the target ata_port
+ *     @link: the target ata_link
  *     @classes: classes of attached devices
  *
  *     This function is invoked after a successful reset.  Note that
@@ -3554,18 +3726,19 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class,
  *     LOCKING:
  *     Kernel thread context (may sleep)
  */
-void ata_std_postreset(struct ata_port *ap, unsigned int *classes)
+void ata_std_postreset(struct ata_link *link, unsigned int *classes)
 {
+       struct ata_port *ap = link->ap;
        u32 serror;
 
        DPRINTK("ENTER\n");
 
        /* print link status */
-       sata_print_link_status(ap);
+       sata_print_link_status(link);
 
        /* clear SError */
-       if (sata_scr_read(ap, SCR_ERROR, &serror) == 0)
-               sata_scr_write(ap, SCR_ERROR, serror);
+       if (sata_scr_read(link, SCR_ERROR, &serror) == 0)
+               sata_scr_write(link, SCR_ERROR, serror);
 
        /* is double-select really necessary? */
        if (classes[0] != ATA_DEV_NONE)
@@ -3652,7 +3825,7 @@ static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class,
 int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags)
 {
        unsigned int class = dev->class;
-       u16 *id = (void *)dev->ap->sector_buf;
+       u16 *id = (void *)dev->link->ap->sector_buf;
        int rc;
 
        /* read ID data */
@@ -3671,6 +3844,7 @@ int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags)
 /**
  *     ata_dev_revalidate - Revalidate ATA device
  *     @dev: device to revalidate
+ *     @new_class: new class code
  *     @readid_flags: read ID flags
  *
  *     Re-read IDENTIFY page, make sure @dev is still attached to the
@@ -3682,7 +3856,8 @@ int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags)
  *     RETURNS:
  *     0 on success, negative errno otherwise
  */
-int ata_dev_revalidate(struct ata_device *dev, unsigned int readid_flags)
+int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class,
+                      unsigned int readid_flags)
 {
        u64 n_sectors = dev->n_sectors;
        int rc;
@@ -3690,6 +3865,15 @@ int ata_dev_revalidate(struct ata_device *dev, unsigned int readid_flags)
        if (!ata_dev_enabled(dev))
                return -ENODEV;
 
+       /* fail early if !ATA && !ATAPI to avoid issuing [P]IDENTIFY to PMP */
+       if (ata_class_enabled(new_class) &&
+           new_class != ATA_DEV_ATA && new_class != ATA_DEV_ATAPI) {
+               ata_dev_printk(dev, KERN_INFO, "class mismatch %u != %u\n",
+                              dev->class, new_class);
+               rc = -ENODEV;
+               goto fail;
+       }
+
        /* re-read ID */
        rc = ata_dev_reread_id(dev, readid_flags);
        if (rc)
@@ -3763,6 +3947,9 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
        { "IOMEGA  ZIP 250       ATAPI", NULL,  ATA_HORKAGE_NODMA }, /* temporary fix */
        { "IOMEGA  ZIP 250       ATAPI       Floppy",
                                NULL,           ATA_HORKAGE_NODMA },
+       /* Odd clown on sil3726/4726 PMPs */
+       { "Config  Disk",       NULL,           ATA_HORKAGE_NODMA |
+                                               ATA_HORKAGE_SKIP_PM },
 
        /* Weird ATAPI devices */
        { "TORiSAN DVD-ROM DRD-N216", NULL,     ATA_HORKAGE_MAX_SEC_128 },
@@ -3775,16 +3962,12 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
        /* http://thread.gmane.org/gmane.linux.ide/14907 */
        { "FUJITSU MHT2060BH",  NULL,           ATA_HORKAGE_NONCQ },
        /* NCQ is broken */
-       { "Maxtor 6L250S0",     "BANC1G10",     ATA_HORKAGE_NONCQ },
-       { "Maxtor 6B200M0",     "BANC1BM0",     ATA_HORKAGE_NONCQ },
-       { "Maxtor 6B200M0",     "BANC1B10",     ATA_HORKAGE_NONCQ },
-       { "Maxtor 7B250S0",     "BANC1B70",     ATA_HORKAGE_NONCQ, },
-       { "Maxtor 7B300S0",     "BANC1B70",     ATA_HORKAGE_NONCQ },
+       { "Maxtor *",           "BANC*",        ATA_HORKAGE_NONCQ },
        { "Maxtor 7V300F0",     "VA111630",     ATA_HORKAGE_NONCQ },
-       { "HITACHI HDS7250SASUN500G 0621KTAWSD", "K2AOAJ0AHITACHI",
-        ATA_HORKAGE_NONCQ },
-       /* NCQ hard hangs device under heavier load, needs hard power cycle */
-       { "Maxtor 6B250S0",     "BANC1B70",     ATA_HORKAGE_NONCQ },
+       { "HITACHI HDS7250SASUN500G*", NULL,    ATA_HORKAGE_NONCQ },
+       { "HITACHI HDS7225SBSUN250G*", NULL,    ATA_HORKAGE_NONCQ },
+       { "ST380817AS",         "3.42",         ATA_HORKAGE_NONCQ },
+
        /* Blacklist entries taken from Silicon Image 3124/3132
           Windows driver .inf file - also several Linux problem reports */
        { "HTS541060G9SA00",    "MB3OC60D",     ATA_HORKAGE_NONCQ, },
@@ -3793,11 +3976,16 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
        /* Drives which do spurious command completion */
        { "HTS541680J9SA00",    "SB2IC7EP",     ATA_HORKAGE_NONCQ, },
        { "HTS541612J9SA00",    "SBDIC7JP",     ATA_HORKAGE_NONCQ, },
+       { "HDT722516DLA380",    "V43OA96A",     ATA_HORKAGE_NONCQ, },
        { "Hitachi HTS541616J9SA00", "SB4OC70P", ATA_HORKAGE_NONCQ, },
        { "WDC WD740ADFD-00NLR1", NULL,         ATA_HORKAGE_NONCQ, },
+       { "WDC WD3200AAJS-00RYA0", "12.01B01",  ATA_HORKAGE_NONCQ, },
        { "FUJITSU MHV2080BH",  "00840028",     ATA_HORKAGE_NONCQ, },
+       { "ST9120822AS",        "3.CLF",        ATA_HORKAGE_NONCQ, },
        { "ST9160821AS",        "3.CLF",        ATA_HORKAGE_NONCQ, },
-       { "ST3160812AS",        "3.AD",         ATA_HORKAGE_NONCQ, },
+       { "ST9160821AS",        "3.ALD",        ATA_HORKAGE_NONCQ, },
+       { "ST3160812AS",        "3.ADJ",        ATA_HORKAGE_NONCQ, },
+       { "ST980813AS",         "3.ADB",        ATA_HORKAGE_NONCQ, },
        { "SAMSUNG HD401LJ",    "ZZ100-15",     ATA_HORKAGE_NONCQ, },
 
        /* devices which puke on READ_NATIVE_MAX */
@@ -3806,10 +3994,31 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
        { "WDC WD2500JD-00HBB0", "WD-WMAL71490727", ATA_HORKAGE_BROKEN_HPA },
        { "MAXTOR 6L080L4",     "A93.0500",     ATA_HORKAGE_BROKEN_HPA },
 
+       /* Devices which report 1 sector over size HPA */
+       { "ST340823A",          NULL,           ATA_HORKAGE_HPA_SIZE, },
+       { "ST320413A",          NULL,           ATA_HORKAGE_HPA_SIZE, },
+
        /* End Marker */
        { }
 };
 
+int strn_pattern_cmp(const char *patt, const char *name, int wildchar)
+{
+       const char *p;
+       int len;
+
+       /*
+        * check for trailing wildcard: *\0
+        */
+       p = strchr(patt, wildchar);
+       if (p && ((*(p + 1)) == 0))
+               len = p - patt;
+       else
+               len = strlen(name);
+
+       return strncmp(patt, name, len);
+}
+
 static unsigned long ata_dev_blacklisted(const struct ata_device *dev)
 {
        unsigned char model_num[ATA_ID_PROD_LEN + 1];
@@ -3820,10 +4029,10 @@ static unsigned long ata_dev_blacklisted(const struct ata_device *dev)
        ata_id_c_string(dev->id, model_rev, ATA_ID_FW_REV, sizeof(model_rev));
 
        while (ad->model_num) {
-               if (!strcmp(ad->model_num, model_num)) {
+               if (!strn_pattern_cmp(ad->model_num, model_num, '*')) {
                        if (ad->model_rev == NULL)
                                return ad->horkage;
-                       if (!strcmp(ad->model_rev, model_rev))
+                       if (!strn_pattern_cmp(ad->model_rev, model_rev, '*'))
                                return ad->horkage;
                }
                ad++;
@@ -3837,7 +4046,7 @@ static int ata_dma_blacklisted(const struct ata_device *dev)
         * DMA blacklist those ATAPI devices with CDB-intr (and use PIO)
         * if the LLDD handles only interrupts in the HSM_ST_LAST state.
         */
-       if ((dev->ap->flags & ATA_FLAG_PIO_POLLING) &&
+       if ((dev->link->ap->flags & ATA_FLAG_PIO_POLLING) &&
            (dev->flags & ATA_DFLAG_CDB_INTR))
                return 1;
        return (dev->horkage & ATA_HORKAGE_NODMA) ? 1 : 0;
@@ -3857,7 +4066,8 @@ static int ata_dma_blacklisted(const struct ata_device *dev)
  */
 static void ata_dev_xfermask(struct ata_device *dev)
 {
-       struct ata_port *ap = dev->ap;
+       struct ata_link *link = dev->link;
+       struct ata_port *ap = link->ap;
        struct ata_host *host = ap->host;
        unsigned long xfer_mask;
 
@@ -3955,7 +4165,43 @@ static unsigned int ata_dev_set_xfermode(struct ata_device *dev)
        tf.protocol = ATA_PROT_NODATA;
        tf.nsect = dev->xfer_mode;
 
-       err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+       err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
+
+       DPRINTK("EXIT, err_mask=%x\n", err_mask);
+       return err_mask;
+}
+
+/**
+ *     ata_dev_set_AN - Issue SET FEATURES - SATA FEATURES
+ *     @dev: Device to which command will be sent
+ *     @enable: Whether to enable or disable the feature
+ *
+ *     Issue SET FEATURES - SATA FEATURES command to device @dev
+ *     on port @ap with sector count set to indicate Asynchronous
+ *     Notification feature
+ *
+ *     LOCKING:
+ *     PCI/etc. bus probe sem.
+ *
+ *     RETURNS:
+ *     0 on success, AC_ERR_* mask otherwise.
+ */
+static unsigned int ata_dev_set_AN(struct ata_device *dev, u8 enable)
+{
+       struct ata_taskfile tf;
+       unsigned int err_mask;
+
+       /* set up set-features taskfile */
+       DPRINTK("set features - SATA features\n");
+
+       ata_tf_init(dev, &tf);
+       tf.command = ATA_CMD_SET_FEATURES;
+       tf.feature = enable;
+       tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+       tf.protocol = ATA_PROT_NODATA;
+       tf.nsect = SATA_AN;
+
+       err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
 
        DPRINTK("EXIT, err_mask=%x\n", err_mask);
        return err_mask;
@@ -3993,7 +4239,7 @@ static unsigned int ata_dev_init_params(struct ata_device *dev,
        tf.nsect = sectors;
        tf.device |= (heads - 1) & 0x0f; /* max head = num. of heads - 1 */
 
-       err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+       err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
        /* A clean abort indicates an original or just out of spec drive
           and we should continue as we issue the setup based on the
           drive reported working geometry */
@@ -4206,6 +4452,36 @@ int ata_check_atapi_dma(struct ata_queued_cmd *qc)
        return 0;
 }
 
+/**
+ *     ata_std_qc_defer - Check whether a qc needs to be deferred
+ *     @qc: ATA command in question
+ *
+ *     Non-NCQ commands cannot run with any other command, NCQ or
+ *     not.  As upper layer only knows the queue depth, we are
+ *     responsible for maintaining exclusion.  This function checks
+ *     whether a new command @qc can be issued.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host lock)
+ *
+ *     RETURNS:
+ *     ATA_DEFER_* if deferring is needed, 0 otherwise.
+ */
+int ata_std_qc_defer(struct ata_queued_cmd *qc)
+{
+       struct ata_link *link = qc->dev->link;
+
+       if (qc->tf.protocol == ATA_PROT_NCQ) {
+               if (!ata_tag_valid(link->active_tag))
+                       return 0;
+       } else {
+               if (!ata_tag_valid(link->active_tag) && !link->sactive)
+                       return 0;
+       }
+
+       return ATA_DEFER_LINK;
+}
+
 /**
  *     ata_qc_prep - Prepare taskfile for submission
  *     @qc: Metadata associated with taskfile to be prepared
@@ -4482,7 +4758,7 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words)
 void ata_data_xfer(struct ata_device *adev, unsigned char *buf,
                   unsigned int buflen, int write_data)
 {
-       struct ata_port *ap = adev->ap;
+       struct ata_port *ap = adev->link->ap;
        unsigned int words = buflen >> 1;
 
        /* Transfer multiple of 2 bytes */
@@ -4611,6 +4887,8 @@ static void ata_pio_sectors(struct ata_queued_cmd *qc)
                        ata_pio_sector(qc);
        } else
                ata_pio_sector(qc);
+
+       ata_altstatus(qc->ap); /* flush */
 }
 
 /**
@@ -4785,6 +5063,7 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc)
        VPRINTK("ata%u: xfering %d bytes\n", ap->print_id, bytes);
 
        __atapi_pio_bytes(qc, bytes);
+       ata_altstatus(ap); /* flush */
 
        return;
 
@@ -4956,7 +5235,6 @@ fsm_start:
                         */
                        ap->hsm_task_state = HSM_ST;
                        ata_pio_sectors(qc);
-                       ata_altstatus(ap); /* flush */
                } else
                        /* send CDB */
                        atapi_send_cdb(ap, qc);
@@ -5037,7 +5315,6 @@ fsm_start:
 
                                if (!(qc->tf.flags & ATA_TFLAG_WRITE)) {
                                        ata_pio_sectors(qc);
-                                       ata_altstatus(ap);
                                        status = ata_wait_idle(ap);
                                }
 
@@ -5057,13 +5334,11 @@ fsm_start:
                        if (ap->hsm_task_state == HSM_ST_LAST &&
                            (!(qc->tf.flags & ATA_TFLAG_WRITE))) {
                                /* all data read */
-                               ata_altstatus(ap);
                                status = ata_wait_idle(ap);
                                goto fsm_start;
                        }
                }
 
-               ata_altstatus(ap); /* flush */
                poll_next = 1;
                break;
 
@@ -5188,7 +5463,7 @@ static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)
 
 struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev)
 {
-       struct ata_port *ap = dev->ap;
+       struct ata_port *ap = dev->link->ap;
        struct ata_queued_cmd *qc;
 
        qc = ata_qc_new(ap);
@@ -5231,6 +5506,7 @@ void ata_qc_free(struct ata_queued_cmd *qc)
 void __ata_qc_complete(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
+       struct ata_link *link = qc->dev->link;
 
        WARN_ON(qc == NULL);    /* ata_qc_from_tag _might_ return NULL */
        WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE));
@@ -5239,10 +5515,19 @@ void __ata_qc_complete(struct ata_queued_cmd *qc)
                ata_sg_clean(qc);
 
        /* command should be marked inactive atomically with qc completion */
-       if (qc->tf.protocol == ATA_PROT_NCQ)
-               ap->sactive &= ~(1 << qc->tag);
-       else
-               ap->active_tag = ATA_TAG_POISON;
+       if (qc->tf.protocol == ATA_PROT_NCQ) {
+               link->sactive &= ~(1 << qc->tag);
+               if (!link->sactive)
+                       ap->nr_active_links--;
+       } else {
+               link->active_tag = ATA_TAG_POISON;
+               ap->nr_active_links--;
+       }
+
+       /* clear exclusive status */
+       if (unlikely(qc->flags & ATA_QCFLAG_CLEAR_EXCL &&
+                    ap->excl_link == link))
+               ap->excl_link = NULL;
 
        /* atapi: mark qc as inactive to prevent the interrupt handler
         * from completing the command twice later, before the error handler
@@ -5411,19 +5696,25 @@ static inline int ata_should_dma_map(struct ata_queued_cmd *qc)
 void ata_qc_issue(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
+       struct ata_link *link = qc->dev->link;
 
        /* Make sure only one non-NCQ command is outstanding.  The
         * check is skipped for old EH because it reuses active qc to
         * request ATAPI sense.
         */
-       WARN_ON(ap->ops->error_handler && ata_tag_valid(ap->active_tag));
+       WARN_ON(ap->ops->error_handler && ata_tag_valid(link->active_tag));
 
        if (qc->tf.protocol == ATA_PROT_NCQ) {
-               WARN_ON(ap->sactive & (1 << qc->tag));
-               ap->sactive |= 1 << qc->tag;
+               WARN_ON(link->sactive & (1 << qc->tag));
+
+               if (!link->sactive)
+                       ap->nr_active_links++;
+               link->sactive |= 1 << qc->tag;
        } else {
-               WARN_ON(ap->sactive);
-               ap->active_tag = qc->tag;
+               WARN_ON(link->sactive);
+
+               ap->nr_active_links++;
+               link->active_tag = qc->tag;
        }
 
        qc->flags |= ATA_QCFLAG_ACTIVE;
@@ -5606,7 +5897,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc)
 inline unsigned int ata_host_intr (struct ata_port *ap,
                                   struct ata_queued_cmd *qc)
 {
-       struct ata_eh_info *ehi = &ap->eh_info;
+       struct ata_eh_info *ehi = &ap->link.eh_info;
        u8 status, host_stat = 0;
 
        VPRINTK("ata%u: protocol %d task_state %d\n",
@@ -5680,7 +5971,8 @@ idle_irq:
 
 #ifdef ATA_IRQ_TRAP
        if ((ap->stats.idle_irq % 1000) == 0) {
-               ap->ops->irq_ack(ap, 0); /* debug trap */
+               ata_chk_status(ap);
+               ap->ops->irq_clear(ap);
                ata_port_printk(ap, KERN_WARNING, "irq trap\n");
                return 1;
        }
@@ -5721,7 +6013,7 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance)
                    !(ap->flags & ATA_FLAG_DISABLED)) {
                        struct ata_queued_cmd *qc;
 
-                       qc = ata_qc_from_tag(ap, ap->active_tag);
+                       qc = ata_qc_from_tag(ap, ap->link.active_tag);
                        if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) &&
                            (qc->flags & ATA_QCFLAG_ACTIVE))
                                handled |= ata_host_intr(ap, qc);
@@ -5735,9 +6027,9 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance)
 
 /**
  *     sata_scr_valid - test whether SCRs are accessible
- *     @ap: ATA port to test SCR accessibility for
+ *     @link: ATA link to test SCR accessibility for
  *
- *     Test whether SCRs are accessible for @ap.
+ *     Test whether SCRs are accessible for @link.
  *
  *     LOCKING:
  *     None.
@@ -5745,60 +6037,74 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance)
  *     RETURNS:
  *     1 if SCRs are accessible, 0 otherwise.
  */
-int sata_scr_valid(struct ata_port *ap)
+int sata_scr_valid(struct ata_link *link)
 {
+       struct ata_port *ap = link->ap;
+
        return (ap->flags & ATA_FLAG_SATA) && ap->ops->scr_read;
 }
 
 /**
  *     sata_scr_read - read SCR register of the specified port
- *     @ap: ATA port to read SCR for
+ *     @link: ATA link to read SCR for
  *     @reg: SCR to read
  *     @val: Place to store read value
  *
- *     Read SCR register @reg of @ap into *@val.  This function is
- *     guaranteed to succeed if the cable type of the port is SATA
- *     and the port implements ->scr_read.
+ *     Read SCR register @reg of @link into *@val.  This function is
+ *     guaranteed to succeed if @link is ap->link, the cable type of
+ *     the port is SATA and the port implements ->scr_read.
  *
  *     LOCKING:
- *     None.
+ *     None if @link is ap->link.  Kernel thread context otherwise.
  *
  *     RETURNS:
  *     0 on success, negative errno on failure.
  */
-int sata_scr_read(struct ata_port *ap, int reg, u32 *val)
+int sata_scr_read(struct ata_link *link, int reg, u32 *val)
 {
-       if (sata_scr_valid(ap))
-               return ap->ops->scr_read(ap, reg, val);
-       return -EOPNOTSUPP;
+       if (ata_is_host_link(link)) {
+               struct ata_port *ap = link->ap;
+
+               if (sata_scr_valid(link))
+                       return ap->ops->scr_read(ap, reg, val);
+               return -EOPNOTSUPP;
+       }
+
+       return sata_pmp_scr_read(link, reg, val);
 }
 
 /**
  *     sata_scr_write - write SCR register of the specified port
- *     @ap: ATA port to write SCR for
+ *     @link: ATA link to write SCR for
  *     @reg: SCR to write
  *     @val: value to write
  *
- *     Write @val to SCR register @reg of @ap.  This function is
- *     guaranteed to succeed if the cable type of the port is SATA
- *     and the port implements ->scr_read.
+ *     Write @val to SCR register @reg of @link.  This function is
+ *     guaranteed to succeed if @link is ap->link, the cable type of
+ *     the port is SATA and the port implements ->scr_read.
  *
  *     LOCKING:
- *     None.
+ *     None if @link is ap->link.  Kernel thread context otherwise.
  *
  *     RETURNS:
  *     0 on success, negative errno on failure.
  */
-int sata_scr_write(struct ata_port *ap, int reg, u32 val)
+int sata_scr_write(struct ata_link *link, int reg, u32 val)
 {
-       if (sata_scr_valid(ap))
-               return ap->ops->scr_write(ap, reg, val);
-       return -EOPNOTSUPP;
+       if (ata_is_host_link(link)) {
+               struct ata_port *ap = link->ap;
+
+               if (sata_scr_valid(link))
+                       return ap->ops->scr_write(ap, reg, val);
+               return -EOPNOTSUPP;
+       }
+
+       return sata_pmp_scr_write(link, reg, val);
 }
 
 /**
  *     sata_scr_write_flush - write SCR register of the specified port and flush
- *     @ap: ATA port to write SCR for
+ *     @link: ATA link to write SCR for
  *     @reg: SCR to write
  *     @val: value to write
  *
@@ -5806,31 +6112,36 @@ int sata_scr_write(struct ata_port *ap, int reg, u32 val)
  *     function performs flush after writing to the register.
  *
  *     LOCKING:
- *     None.
+ *     None if @link is ap->link.  Kernel thread context otherwise.
  *
  *     RETURNS:
  *     0 on success, negative errno on failure.
  */
-int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val)
+int sata_scr_write_flush(struct ata_link *link, int reg, u32 val)
 {
-       int rc;
+       if (ata_is_host_link(link)) {
+               struct ata_port *ap = link->ap;
+               int rc;
 
-       if (sata_scr_valid(ap)) {
-               rc = ap->ops->scr_write(ap, reg, val);
-               if (rc == 0)
-                       rc = ap->ops->scr_read(ap, reg, &val);
-               return rc;
+               if (sata_scr_valid(link)) {
+                       rc = ap->ops->scr_write(ap, reg, val);
+                       if (rc == 0)
+                               rc = ap->ops->scr_read(ap, reg, &val);
+                       return rc;
+               }
+               return -EOPNOTSUPP;
        }
-       return -EOPNOTSUPP;
+
+       return sata_pmp_scr_write(link, reg, val);
 }
 
 /**
- *     ata_port_online - test whether the given port is online
- *     @ap: ATA port to test
+ *     ata_link_online - test whether the given link is online
+ *     @link: ATA link to test
  *
- *     Test whether @ap is online.  Note that this function returns 0
- *     if online status of @ap cannot be obtained, so
- *     ata_port_online(ap) != !ata_port_offline(ap).
+ *     Test whether @link is online.  Note that this function returns
+ *     0 if online status of @link cannot be obtained, so
+ *     ata_link_online(link) != !ata_link_offline(link).
  *
  *     LOCKING:
  *     None.
@@ -5838,22 +6149,23 @@ int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val)
  *     RETURNS:
  *     1 if the port online status is available and online.
  */
-int ata_port_online(struct ata_port *ap)
+int ata_link_online(struct ata_link *link)
 {
        u32 sstatus;
 
-       if (!sata_scr_read(ap, SCR_STATUS, &sstatus) && (sstatus & 0xf) == 0x3)
+       if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0 &&
+           (sstatus & 0xf) == 0x3)
                return 1;
        return 0;
 }
 
 /**
- *     ata_port_offline - test whether the given port is offline
- *     @ap: ATA port to test
+ *     ata_link_offline - test whether the given link is offline
+ *     @link: ATA link to test
  *
- *     Test whether @ap is offline.  Note that this function returns
- *     0 if offline status of @ap cannot be obtained, so
- *     ata_port_online(ap) != !ata_port_offline(ap).
+ *     Test whether @link is offline.  Note that this function
+ *     returns 0 if offline status of @link cannot be obtained, so
+ *     ata_link_online(link) != !ata_link_offline(link).
  *
  *     LOCKING:
  *     None.
@@ -5861,11 +6173,12 @@ int ata_port_online(struct ata_port *ap)
  *     RETURNS:
  *     1 if the port offline status is available and offline.
  */
-int ata_port_offline(struct ata_port *ap)
+int ata_link_offline(struct ata_link *link)
 {
        u32 sstatus;
 
-       if (!sata_scr_read(ap, SCR_STATUS, &sstatus) && (sstatus & 0xf) != 0x3)
+       if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0 &&
+           (sstatus & 0xf) != 0x3)
                return 1;
        return 0;
 }
@@ -5883,6 +6196,10 @@ int ata_flush_cache(struct ata_device *dev)
        else
                cmd = ATA_CMD_FLUSH;
 
+       /* This is wrong. On a failed flush we get back the LBA of the lost
+          sector and we should (assuming it wasn't aborted as unknown) issue
+          a further flush command to continue the writeback until it 
+          does not error */
        err_mask = ata_do_simple_cmd(dev, cmd);
        if (err_mask) {
                ata_dev_printk(dev, KERN_ERR, "failed to flush cache\n");
@@ -5902,6 +6219,7 @@ static int ata_host_request_pm(struct ata_host *host, pm_message_t mesg,
 
        for (i = 0; i < host->n_ports; i++) {
                struct ata_port *ap = host->ports[i];
+               struct ata_link *link;
 
                /* Previous resume operation might still be in
                 * progress.  Wait for PM_PENDING to clear.
@@ -5921,8 +6239,10 @@ static int ata_host_request_pm(struct ata_host *host, pm_message_t mesg,
                }
 
                ap->pflags |= ATA_PFLAG_PM_PENDING;
-               ap->eh_info.action |= action;
-               ap->eh_info.flags |= ehi_flags;
+               __ata_port_for_each_link(link, ap) {
+                       link->eh_info.action |= action;
+                       link->eh_info.flags |= ehi_flags;
+               }
 
                ata_port_schedule_eh(ap);
 
@@ -6026,12 +6346,13 @@ int ata_port_start(struct ata_port *ap)
  */
 void ata_dev_init(struct ata_device *dev)
 {
-       struct ata_port *ap = dev->ap;
+       struct ata_link *link = dev->link;
+       struct ata_port *ap = link->ap;
        unsigned long flags;
 
        /* SATA spd limit is bound to the first device */
-       ap->sata_spd_limit = ap->hw_sata_spd_limit;
-       ap->sata_spd = 0;
+       link->sata_spd_limit = link->hw_sata_spd_limit;
+       link->sata_spd = 0;
 
        /* High bits of dev->flags are used to record warm plug
         * requests which occur asynchronously.  Synchronize using
@@ -6049,6 +6370,70 @@ void ata_dev_init(struct ata_device *dev)
        dev->udma_mask = UINT_MAX;
 }
 
+/**
+ *     ata_link_init - Initialize an ata_link structure
+ *     @ap: ATA port link is attached to
+ *     @link: Link structure to initialize
+ *     @pmp: Port multiplier port number
+ *
+ *     Initialize @link.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep)
+ */
+void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp)
+{
+       int i;
+
+       /* clear everything except for devices */
+       memset(link, 0, offsetof(struct ata_link, device[0]));
+
+       link->ap = ap;
+       link->pmp = pmp;
+       link->active_tag = ATA_TAG_POISON;
+       link->hw_sata_spd_limit = UINT_MAX;
+
+       /* can't use iterator, ap isn't initialized yet */
+       for (i = 0; i < ATA_MAX_DEVICES; i++) {
+               struct ata_device *dev = &link->device[i];
+
+               dev->link = link;
+               dev->devno = dev - link->device;
+               ata_dev_init(dev);
+       }
+}
+
+/**
+ *     sata_link_init_spd - Initialize link->sata_spd_limit
+ *     @link: Link to configure sata_spd_limit for
+ *
+ *     Initialize @link->[hw_]sata_spd_limit to the currently
+ *     configured value.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep).
+ *
+ *     RETURNS:
+ *     0 on success, -errno on failure.
+ */
+int sata_link_init_spd(struct ata_link *link)
+{
+       u32 scontrol, spd;
+       int rc;
+
+       rc = sata_scr_read(link, SCR_CONTROL, &scontrol);
+       if (rc)
+               return rc;
+
+       spd = (scontrol >> 4) & 0xf;
+       if (spd)
+               link->hw_sata_spd_limit &= (1 << spd) - 1;
+
+       link->sata_spd_limit = link->hw_sata_spd_limit;
+
+       return 0;
+}
+
 /**
  *     ata_port_alloc - allocate and initialize basic ATA port resources
  *     @host: ATA host this allocated port belongs to
@@ -6064,7 +6449,6 @@ void ata_dev_init(struct ata_device *dev)
 struct ata_port *ata_port_alloc(struct ata_host *host)
 {
        struct ata_port *ap;
-       unsigned int i;
 
        DPRINTK("ENTER\n");
 
@@ -6079,9 +6463,6 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
        ap->ctl = ATA_DEVCTL_OBS;
        ap->host = host;
        ap->dev = host->dev;
-
-       ap->hw_sata_spd_limit = UINT_MAX;
-       ap->active_tag = ATA_TAG_POISON;
        ap->last_ctl = 0xFF;
 
 #if defined(ATA_VERBOSE_DEBUG)
@@ -6104,12 +6485,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
 
        ap->cbl = ATA_CBL_NONE;
 
-       for (i = 0; i < ATA_MAX_DEVICES; i++) {
-               struct ata_device *dev = &ap->device[i];
-               dev->ap = ap;
-               dev->devno = i;
-               ata_dev_init(dev);
-       }
+       ata_link_init(ap, &ap->link, 0);
 
 #ifdef ATA_IRQ_TRAP
        ap->stats.unhandled_irq = 1;
@@ -6145,6 +6521,7 @@ static void ata_host_release(struct device *gendev, void *res)
                if (ap->scsi_host)
                        scsi_host_put(ap->scsi_host);
 
+               kfree(ap->pmp_link);
                kfree(ap);
                host->ports[i] = NULL;
        }
@@ -6255,6 +6632,7 @@ struct ata_host *ata_host_alloc_pinfo(struct device *dev,
                ap->mwdma_mask = pi->mwdma_mask;
                ap->udma_mask = pi->udma_mask;
                ap->flags |= pi->flags;
+               ap->link.flags |= pi->link_flags;
                ap->ops = pi->port_ops;
 
                if (!host->ops && (pi->port_ops != &ata_dummy_port_ops))
@@ -6390,8 +6768,6 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
        /* set cable, sata_spd_limit and report */
        for (i = 0; i < host->n_ports; i++) {
                struct ata_port *ap = host->ports[i];
-               int irq_line;
-               u32 scontrol;
                unsigned long xfer_mask;
 
                /* set SATA cable type if still unset */
@@ -6399,32 +6775,20 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
                        ap->cbl = ATA_CBL_SATA;
 
                /* init sata_spd_limit to the current value */
-               if (sata_scr_read(ap, SCR_CONTROL, &scontrol) == 0) {
-                       int spd = (scontrol >> 4) & 0xf;
-                       if (spd)
-                               ap->hw_sata_spd_limit &= (1 << spd) - 1;
-               }
-               ap->sata_spd_limit = ap->hw_sata_spd_limit;
-
-               /* report the secondary IRQ for second channel legacy */
-               irq_line = host->irq;
-               if (i == 1 && host->irq2)
-                       irq_line = host->irq2;
+               sata_link_init_spd(&ap->link);
 
+               /* print per-port info to dmesg */
                xfer_mask = ata_pack_xfermask(ap->pio_mask, ap->mwdma_mask,
                                              ap->udma_mask);
 
-               /* print per-port info to dmesg */
-               if (!ata_port_is_dummy(ap))
-                       ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%p "
-                                       "ctl 0x%p bmdma 0x%p irq %d\n",
+               if (!ata_port_is_dummy(ap)) {
+                       ata_port_printk(ap, KERN_INFO,
+                                       "%cATA max %s %s\n",
                                        (ap->flags & ATA_FLAG_SATA) ? 'S' : 'P',
                                        ata_mode_string(xfer_mask),
-                                       ap->ioaddr.cmd_addr,
-                                       ap->ioaddr.ctl_addr,
-                                       ap->ioaddr.bmdma_addr,
-                                       irq_line);
-               else
+                                       ap->link.eh_info.desc);
+                       ata_ehi_clear_desc(&ap->link.eh_info);
+               } else
                        ata_port_printk(ap, KERN_INFO, "DUMMY\n");
        }
 
@@ -6436,7 +6800,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
 
                /* probe */
                if (ap->ops->error_handler) {
-                       struct ata_eh_info *ehi = &ap->eh_info;
+                       struct ata_eh_info *ehi = &ap->link.eh_info;
                        unsigned long flags;
 
                        ata_port_probe(ap);
@@ -6444,7 +6808,8 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
                        /* kick EH for boot probing */
                        spin_lock_irqsave(ap->lock, flags);
 
-                       ehi->probe_mask = (1 << ATA_MAX_DEVICES) - 1;
+                       ehi->probe_mask =
+                               (1 << ata_link_max_devices(&ap->link)) - 1;
                        ehi->action |= ATA_EH_SOFTRESET;
                        ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
 
@@ -6506,7 +6871,7 @@ int ata_host_activate(struct ata_host *host, int irq,
                      irq_handler_t irq_handler, unsigned long irq_flags,
                      struct scsi_host_template *sht)
 {
-       int rc;
+       int i, rc;
 
        rc = ata_host_start(host);
        if (rc)
@@ -6517,8 +6882,8 @@ int ata_host_activate(struct ata_host *host, int irq,
        if (rc)
                return rc;
 
-       /* Used to print device info at probe */
-       host->irq = irq;
+       for (i = 0; i < host->n_ports; i++)
+               ata_port_desc(host->ports[i], "irq %d", irq);
 
        rc = ata_host_register(host, sht);
        /* if failed, just free the IRQ and leave ports alone */
@@ -6542,7 +6907,8 @@ int ata_host_activate(struct ata_host *host, int irq,
 void ata_port_detach(struct ata_port *ap)
 {
        unsigned long flags;
-       int i;
+       struct ata_link *link;
+       struct ata_device *dev;
 
        if (!ap->ops->error_handler)
                goto skip_eh;
@@ -6559,8 +6925,10 @@ void ata_port_detach(struct ata_port *ap)
         */
        spin_lock_irqsave(ap->lock, flags);
 
-       for (i = 0; i < ATA_MAX_DEVICES; i++)
-               ata_dev_disable(&ap->device[i]);
+       ata_port_for_each_link(link, ap) {
+               ata_link_for_each_dev(dev, link)
+                       ata_dev_disable(dev);
+       }
 
        spin_unlock_irqrestore(ap->lock, flags);
 
@@ -6639,7 +7007,7 @@ void ata_std_ports(struct ata_ioports *ioaddr)
  */
 void ata_pci_remove_one(struct pci_dev *pdev)
 {
-       struct device *dev = pci_dev_to_dev(pdev);
+       struct device *dev = &pdev->dev;
        struct ata_host *host = dev_get_drvdata(dev);
 
        ata_host_detach(host);
@@ -6847,7 +7215,6 @@ static unsigned int ata_dummy_qc_issue(struct ata_queued_cmd *qc)
 }
 
 const struct ata_port_operations ata_dummy_port_ops = {
-       .port_disable           = ata_port_disable,
        .check_status           = ata_dummy_check_status,
        .check_altstatus        = ata_dummy_check_status,
        .dev_select             = ata_noop_dev_select,
@@ -6909,6 +7276,7 @@ EXPORT_SYMBOL_GPL(ata_interrupt);
 EXPORT_SYMBOL_GPL(ata_do_set_mode);
 EXPORT_SYMBOL_GPL(ata_data_xfer);
 EXPORT_SYMBOL_GPL(ata_data_xfer_noirq);
+EXPORT_SYMBOL_GPL(ata_std_qc_defer);
 EXPORT_SYMBOL_GPL(ata_qc_prep);
 EXPORT_SYMBOL_GPL(ata_dumb_qc_prep);
 EXPORT_SYMBOL_GPL(ata_noop_qc_prep);
@@ -6925,14 +7293,14 @@ EXPORT_SYMBOL_GPL(ata_bmdma_post_internal_cmd);
 EXPORT_SYMBOL_GPL(ata_port_probe);
 EXPORT_SYMBOL_GPL(ata_dev_disable);
 EXPORT_SYMBOL_GPL(sata_set_spd);
-EXPORT_SYMBOL_GPL(sata_phy_debounce);
-EXPORT_SYMBOL_GPL(sata_phy_resume);
+EXPORT_SYMBOL_GPL(sata_link_debounce);
+EXPORT_SYMBOL_GPL(sata_link_resume);
 EXPORT_SYMBOL_GPL(sata_phy_reset);
 EXPORT_SYMBOL_GPL(__sata_phy_reset);
 EXPORT_SYMBOL_GPL(ata_bus_reset);
 EXPORT_SYMBOL_GPL(ata_std_prereset);
 EXPORT_SYMBOL_GPL(ata_std_softreset);
-EXPORT_SYMBOL_GPL(sata_port_hardreset);
+EXPORT_SYMBOL_GPL(sata_link_hardreset);
 EXPORT_SYMBOL_GPL(sata_std_hardreset);
 EXPORT_SYMBOL_GPL(ata_std_postreset);
 EXPORT_SYMBOL_GPL(ata_dev_classify);
@@ -6953,8 +7321,8 @@ EXPORT_SYMBOL_GPL(sata_scr_valid);
 EXPORT_SYMBOL_GPL(sata_scr_read);
 EXPORT_SYMBOL_GPL(sata_scr_write);
 EXPORT_SYMBOL_GPL(sata_scr_write_flush);
-EXPORT_SYMBOL_GPL(ata_port_online);
-EXPORT_SYMBOL_GPL(ata_port_offline);
+EXPORT_SYMBOL_GPL(ata_link_online);
+EXPORT_SYMBOL_GPL(ata_link_offline);
 #ifdef CONFIG_PM
 EXPORT_SYMBOL_GPL(ata_host_suspend);
 EXPORT_SYMBOL_GPL(ata_host_resume);
@@ -6985,22 +7353,31 @@ EXPORT_SYMBOL_GPL(ata_pci_default_filter);
 EXPORT_SYMBOL_GPL(ata_pci_clear_simplex);
 #endif /* CONFIG_PCI */
 
+EXPORT_SYMBOL_GPL(sata_pmp_qc_defer_cmd_switch);
+EXPORT_SYMBOL_GPL(sata_pmp_std_prereset);
+EXPORT_SYMBOL_GPL(sata_pmp_std_hardreset);
+EXPORT_SYMBOL_GPL(sata_pmp_std_postreset);
+EXPORT_SYMBOL_GPL(sata_pmp_do_eh);
+
 EXPORT_SYMBOL_GPL(__ata_ehi_push_desc);
 EXPORT_SYMBOL_GPL(ata_ehi_push_desc);
 EXPORT_SYMBOL_GPL(ata_ehi_clear_desc);
+EXPORT_SYMBOL_GPL(ata_port_desc);
+#ifdef CONFIG_PCI
+EXPORT_SYMBOL_GPL(ata_port_pbar_desc);
+#endif /* CONFIG_PCI */
 EXPORT_SYMBOL_GPL(ata_eng_timeout);
 EXPORT_SYMBOL_GPL(ata_port_schedule_eh);
+EXPORT_SYMBOL_GPL(ata_link_abort);
 EXPORT_SYMBOL_GPL(ata_port_abort);
 EXPORT_SYMBOL_GPL(ata_port_freeze);
+EXPORT_SYMBOL_GPL(sata_async_notification);
 EXPORT_SYMBOL_GPL(ata_eh_freeze_port);
 EXPORT_SYMBOL_GPL(ata_eh_thaw_port);
 EXPORT_SYMBOL_GPL(ata_eh_qc_complete);
 EXPORT_SYMBOL_GPL(ata_eh_qc_retry);
 EXPORT_SYMBOL_GPL(ata_do_eh);
 EXPORT_SYMBOL_GPL(ata_irq_on);
-EXPORT_SYMBOL_GPL(ata_dummy_irq_on);
-EXPORT_SYMBOL_GPL(ata_irq_ack);
-EXPORT_SYMBOL_GPL(ata_dummy_irq_ack);
 EXPORT_SYMBOL_GPL(ata_dev_try_classify);
 
 EXPORT_SYMBOL_GPL(ata_cable_40wire);
index ac6ceed4bb602082037b3cc844eef9470a6b6adb..2eaa39fc65d031d5f44519e3ec43e9a80d3cb34b 100644 (file)
@@ -33,6 +33,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/pci.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_eh.h>
@@ -74,7 +75,6 @@ static const unsigned long ata_eh_reset_timeouts[] = {
 };
 
 static void __ata_port_freeze(struct ata_port *ap);
-static void ata_eh_finish(struct ata_port *ap);
 #ifdef CONFIG_PM
 static void ata_eh_handle_port_suspend(struct ata_port *ap);
 static void ata_eh_handle_port_resume(struct ata_port *ap);
@@ -151,6 +151,73 @@ void ata_ehi_clear_desc(struct ata_eh_info *ehi)
        ehi->desc_len = 0;
 }
 
+/**
+ *     ata_port_desc - append port description
+ *     @ap: target ATA port
+ *     @fmt: printf format string
+ *
+ *     Format string according to @fmt and append it to port
+ *     description.  If port description is not empty, " " is added
+ *     in-between.  This function is to be used while initializing
+ *     ata_host.  The description is printed on host registration.
+ *
+ *     LOCKING:
+ *     None.
+ */
+void ata_port_desc(struct ata_port *ap, const char *fmt, ...)
+{
+       va_list args;
+
+       WARN_ON(!(ap->pflags & ATA_PFLAG_INITIALIZING));
+
+       if (ap->link.eh_info.desc_len)
+               __ata_ehi_push_desc(&ap->link.eh_info, " ");
+
+       va_start(args, fmt);
+       __ata_ehi_pushv_desc(&ap->link.eh_info, fmt, args);
+       va_end(args);
+}
+
+#ifdef CONFIG_PCI
+
+/**
+ *     ata_port_pbar_desc - append PCI BAR description
+ *     @ap: target ATA port
+ *     @bar: target PCI BAR
+ *     @offset: offset into PCI BAR
+ *     @name: name of the area
+ *
+ *     If @offset is negative, this function formats a string which
+ *     contains the name, address, size and type of the BAR and
+ *     appends it to the port description.  If @offset is zero or
+ *     positive, only name and offsetted address is appended.
+ *
+ *     LOCKING:
+ *     None.
+ */
+void ata_port_pbar_desc(struct ata_port *ap, int bar, ssize_t offset,
+                       const char *name)
+{
+       struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+       char *type = "";
+       unsigned long long start, len;
+
+       if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM)
+               type = "m";
+       else if (pci_resource_flags(pdev, bar) & IORESOURCE_IO)
+               type = "i";
+
+       start = (unsigned long long)pci_resource_start(pdev, bar);
+       len = (unsigned long long)pci_resource_len(pdev, bar);
+
+       if (offset < 0)
+               ata_port_desc(ap, "%s %s%llu@0x%llx", name, type, len, start);
+       else
+               ata_port_desc(ap, "%s 0x%llx", name, start + offset);
+}
+
+#endif /* CONFIG_PCI */
+
 static void ata_ering_record(struct ata_ering *ering, int is_io,
                             unsigned int err_mask)
 {
@@ -195,28 +262,29 @@ static int ata_ering_map(struct ata_ering *ering,
 
 static unsigned int ata_eh_dev_action(struct ata_device *dev)
 {
-       struct ata_eh_context *ehc = &dev->ap->eh_context;
+       struct ata_eh_context *ehc = &dev->link->eh_context;
 
        return ehc->i.action | ehc->i.dev_action[dev->devno];
 }
 
-static void ata_eh_clear_action(struct ata_device *dev,
+static void ata_eh_clear_action(struct ata_link *link, struct ata_device *dev,
                                struct ata_eh_info *ehi, unsigned int action)
 {
-       int i;
+       struct ata_device *tdev;
 
        if (!dev) {
                ehi->action &= ~action;
-               for (i = 0; i < ATA_MAX_DEVICES; i++)
-                       ehi->dev_action[i] &= ~action;
+               ata_link_for_each_dev(tdev, link)
+                       ehi->dev_action[tdev->devno] &= ~action;
        } else {
                /* doesn't make sense for port-wide EH actions */
                WARN_ON(!(action & ATA_EH_PERDEV_MASK));
 
                /* break ehi->action into ehi->dev_action */
                if (ehi->action & action) {
-                       for (i = 0; i < ATA_MAX_DEVICES; i++)
-                               ehi->dev_action[i] |= ehi->action & action;
+                       ata_link_for_each_dev(tdev, link)
+                               ehi->dev_action[tdev->devno] |=
+                                       ehi->action & action;
                        ehi->action &= ~action;
                }
 
@@ -261,7 +329,7 @@ enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
 
        ret = EH_HANDLED;
        spin_lock_irqsave(ap->lock, flags);
-       qc = ata_qc_from_tag(ap, ap->active_tag);
+       qc = ata_qc_from_tag(ap, ap->link.active_tag);
        if (qc) {
                WARN_ON(qc->scsicmd != cmd);
                qc->flags |= ATA_QCFLAG_EH_SCHEDULED;
@@ -290,7 +358,7 @@ enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
 void ata_scsi_error(struct Scsi_Host *host)
 {
        struct ata_port *ap = ata_shost_to_port(host);
-       int i, repeat_cnt = ATA_EH_MAX_REPEAT;
+       int i;
        unsigned long flags;
 
        DPRINTK("ENTER\n");
@@ -356,12 +424,17 @@ void ata_scsi_error(struct Scsi_Host *host)
                        __ata_port_freeze(ap);
 
                spin_unlock_irqrestore(ap->lock, flags);
+
+               /* initialize eh_tries */
+               ap->eh_tries = ATA_EH_MAX_TRIES;
        } else
                spin_unlock_wait(ap->lock);
 
  repeat:
        /* invoke error handler */
        if (ap->ops->error_handler) {
+               struct ata_link *link;
+
                /* kill fast drain timer */
                del_timer_sync(&ap->fastdrain_timer);
 
@@ -371,12 +444,15 @@ void ata_scsi_error(struct Scsi_Host *host)
                /* fetch & clear EH info */
                spin_lock_irqsave(ap->lock, flags);
 
-               memset(&ap->eh_context, 0, sizeof(ap->eh_context));
-               ap->eh_context.i = ap->eh_info;
-               memset(&ap->eh_info, 0, sizeof(ap->eh_info));
+               __ata_port_for_each_link(link, ap) {
+                       memset(&link->eh_context, 0, sizeof(link->eh_context));
+                       link->eh_context.i = link->eh_info;
+                       memset(&link->eh_info, 0, sizeof(link->eh_info));
+               }
 
                ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS;
                ap->pflags &= ~ATA_PFLAG_EH_PENDING;
+               ap->excl_link = NULL;   /* don't maintain exclusion over EH */
 
                spin_unlock_irqrestore(ap->lock, flags);
 
@@ -396,20 +472,18 @@ void ata_scsi_error(struct Scsi_Host *host)
                spin_lock_irqsave(ap->lock, flags);
 
                if (ap->pflags & ATA_PFLAG_EH_PENDING) {
-                       if (--repeat_cnt) {
-                               ata_port_printk(ap, KERN_INFO,
-                                       "EH pending after completion, "
-                                       "repeating EH (cnt=%d)\n", repeat_cnt);
+                       if (--ap->eh_tries) {
                                spin_unlock_irqrestore(ap->lock, flags);
                                goto repeat;
                        }
                        ata_port_printk(ap, KERN_ERR, "EH pending after %d "
-                                       "tries, giving up\n", ATA_EH_MAX_REPEAT);
+                                       "tries, giving up\n", ATA_EH_MAX_TRIES);
                        ap->pflags &= ~ATA_PFLAG_EH_PENDING;
                }
 
                /* this run is complete, make sure EH info is clear */
-               memset(&ap->eh_info, 0, sizeof(ap->eh_info));
+               __ata_port_for_each_link(link, ap)
+                       memset(&link->eh_info, 0, sizeof(link->eh_info));
 
                /* Clear host_eh_scheduled while holding ap->lock such
                 * that if exception occurs after this point but
@@ -420,7 +494,7 @@ void ata_scsi_error(struct Scsi_Host *host)
 
                spin_unlock_irqrestore(ap->lock, flags);
        } else {
-               WARN_ON(ata_qc_from_tag(ap, ap->active_tag) == NULL);
+               WARN_ON(ata_qc_from_tag(ap, ap->link.active_tag) == NULL);
                ap->ops->eng_timeout(ap);
        }
 
@@ -575,7 +649,7 @@ void ata_eng_timeout(struct ata_port *ap)
 {
        DPRINTK("ENTER\n");
 
-       ata_qc_timeout(ata_qc_from_tag(ap, ap->active_tag));
+       ata_qc_timeout(ata_qc_from_tag(ap, ap->link.active_tag));
 
        DPRINTK("EXIT\n");
 }
@@ -718,19 +792,7 @@ void ata_port_schedule_eh(struct ata_port *ap)
        DPRINTK("port EH scheduled\n");
 }
 
-/**
- *     ata_port_abort - abort all qc's on the port
- *     @ap: ATA port to abort qc's for
- *
- *     Abort all active qc's of @ap and schedule EH.
- *
- *     LOCKING:
- *     spin_lock_irqsave(host lock)
- *
- *     RETURNS:
- *     Number of aborted qc's.
- */
-int ata_port_abort(struct ata_port *ap)
+static int ata_do_link_abort(struct ata_port *ap, struct ata_link *link)
 {
        int tag, nr_aborted = 0;
 
@@ -742,7 +804,7 @@ int ata_port_abort(struct ata_port *ap)
        for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
                struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag);
 
-               if (qc) {
+               if (qc && (!link || qc->dev->link == link)) {
                        qc->flags |= ATA_QCFLAG_FAILED;
                        ata_qc_complete(qc);
                        nr_aborted++;
@@ -755,6 +817,40 @@ int ata_port_abort(struct ata_port *ap)
        return nr_aborted;
 }
 
+/**
+ *     ata_link_abort - abort all qc's on the link
+ *     @link: ATA link to abort qc's for
+ *
+ *     Abort all active qc's active on @link and schedule EH.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host lock)
+ *
+ *     RETURNS:
+ *     Number of aborted qc's.
+ */
+int ata_link_abort(struct ata_link *link)
+{
+       return ata_do_link_abort(link->ap, link);
+}
+
+/**
+ *     ata_port_abort - abort all qc's on the port
+ *     @ap: ATA port to abort qc's for
+ *
+ *     Abort all active qc's of @ap and schedule EH.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host_set lock)
+ *
+ *     RETURNS:
+ *     Number of aborted qc's.
+ */
+int ata_port_abort(struct ata_port *ap)
+{
+       return ata_do_link_abort(ap, NULL);
+}
+
 /**
  *     __ata_port_freeze - freeze port
  *     @ap: ATA port to freeze
@@ -809,6 +905,79 @@ int ata_port_freeze(struct ata_port *ap)
        return nr_aborted;
 }
 
+/**
+ *     sata_async_notification - SATA async notification handler
+ *     @ap: ATA port where async notification is received
+ *
+ *     Handler to be called when async notification via SDB FIS is
+ *     received.  This function schedules EH if necessary.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host lock)
+ *
+ *     RETURNS:
+ *     1 if EH is scheduled, 0 otherwise.
+ */
+int sata_async_notification(struct ata_port *ap)
+{
+       u32 sntf;
+       int rc;
+
+       if (!(ap->flags & ATA_FLAG_AN))
+               return 0;
+
+       rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf);
+       if (rc == 0)
+               sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf);
+
+       if (!ap->nr_pmp_links || rc) {
+               /* PMP is not attached or SNTF is not available */
+               if (!ap->nr_pmp_links) {
+                       /* PMP is not attached.  Check whether ATAPI
+                        * AN is configured.  If so, notify media
+                        * change.
+                        */
+                       struct ata_device *dev = ap->link.device;
+
+                       if ((dev->class == ATA_DEV_ATAPI) &&
+                           (dev->flags & ATA_DFLAG_AN))
+                               ata_scsi_media_change_notify(dev);
+                       return 0;
+               } else {
+                       /* PMP is attached but SNTF is not available.
+                        * ATAPI async media change notification is
+                        * not used.  The PMP must be reporting PHY
+                        * status change, schedule EH.
+                        */
+                       ata_port_schedule_eh(ap);
+                       return 1;
+               }
+       } else {
+               /* PMP is attached and SNTF is available */
+               struct ata_link *link;
+
+               /* check and notify ATAPI AN */
+               ata_port_for_each_link(link, ap) {
+                       if (!(sntf & (1 << link->pmp)))
+                               continue;
+
+                       if ((link->device->class == ATA_DEV_ATAPI) &&
+                           (link->device->flags & ATA_DFLAG_AN))
+                               ata_scsi_media_change_notify(link->device);
+               }
+
+               /* If PMP is reporting that PHY status of some
+                * downstream ports has changed, schedule EH.
+                */
+               if (sntf & (1 << SATA_PMP_CTRL_PORT)) {
+                       ata_port_schedule_eh(ap);
+                       return 1;
+               }
+
+               return 0;
+       }
+}
+
 /**
  *     ata_eh_freeze_port - EH helper to freeze port
  *     @ap: ATA port to freeze
@@ -920,9 +1089,10 @@ void ata_eh_qc_retry(struct ata_queued_cmd *qc)
  *     LOCKING:
  *     None.
  */
-static void ata_eh_detach_dev(struct ata_device *dev)
+void ata_eh_detach_dev(struct ata_device *dev)
 {
-       struct ata_port *ap = dev->ap;
+       struct ata_link *link = dev->link;
+       struct ata_port *ap = link->ap;
        unsigned long flags;
 
        ata_dev_disable(dev);
@@ -937,31 +1107,32 @@ static void ata_eh_detach_dev(struct ata_device *dev)
        }
 
        /* clear per-dev EH actions */
-       ata_eh_clear_action(dev, &ap->eh_info, ATA_EH_PERDEV_MASK);
-       ata_eh_clear_action(dev, &ap->eh_context.i, ATA_EH_PERDEV_MASK);
+       ata_eh_clear_action(link, dev, &link->eh_info, ATA_EH_PERDEV_MASK);
+       ata_eh_clear_action(link, dev, &link->eh_context.i, ATA_EH_PERDEV_MASK);
 
        spin_unlock_irqrestore(ap->lock, flags);
 }
 
 /**
  *     ata_eh_about_to_do - about to perform eh_action
- *     @ap: target ATA port
+ *     @link: target ATA link
  *     @dev: target ATA dev for per-dev action (can be NULL)
  *     @action: action about to be performed
  *
  *     Called just before performing EH actions to clear related bits
- *     in @ap->eh_info such that eh actions are not unnecessarily
+ *     in @link->eh_info such that eh actions are not unnecessarily
  *     repeated.
  *
  *     LOCKING:
  *     None.
  */
-static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev,
-                              unsigned int action)
+void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev,
+                       unsigned int action)
 {
+       struct ata_port *ap = link->ap;
+       struct ata_eh_info *ehi = &link->eh_info;
+       struct ata_eh_context *ehc = &link->eh_context;
        unsigned long flags;
-       struct ata_eh_info *ehi = &ap->eh_info;
-       struct ata_eh_context *ehc = &ap->eh_context;
 
        spin_lock_irqsave(ap->lock, flags);
 
@@ -978,7 +1149,7 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev,
                ehi->flags &= ~ATA_EHI_RESET_MODIFIER_MASK;
        }
 
-       ata_eh_clear_action(dev, ehi, action);
+       ata_eh_clear_action(link, dev, ehi, action);
 
        if (!(ehc->i.flags & ATA_EHI_QUIET))
                ap->pflags |= ATA_PFLAG_RECOVERED;
@@ -988,26 +1159,28 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev,
 
 /**
  *     ata_eh_done - EH action complete
- *     @ap: target ATA port
+     @ap: target ATA port
  *     @dev: target ATA dev for per-dev action (can be NULL)
  *     @action: action just completed
  *
  *     Called right after performing EH actions to clear related bits
- *     in @ap->eh_context.
+ *     in @link->eh_context.
  *
  *     LOCKING:
  *     None.
  */
-static void ata_eh_done(struct ata_port *ap, struct ata_device *dev,
-                       unsigned int action)
+void ata_eh_done(struct ata_link *link, struct ata_device *dev,
+                unsigned int action)
 {
+       struct ata_eh_context *ehc = &link->eh_context;
+
        /* if reset is complete, clear all reset actions & reset modifier */
        if (action & ATA_EH_RESET_MASK) {
                action |= ATA_EH_RESET_MASK;
-               ap->eh_context.i.flags &= ~ATA_EHI_RESET_MODIFIER_MASK;
+               ehc->i.flags &= ~ATA_EHI_RESET_MODIFIER_MASK;
        }
 
-       ata_eh_clear_action(dev, &ap->eh_context.i, action);
+       ata_eh_clear_action(link, dev, &ehc->i, action);
 }
 
 /**
@@ -1077,7 +1250,7 @@ static unsigned int ata_read_log_page(struct ata_device *dev,
        tf.protocol = ATA_PROT_PIO;
 
        err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,
-                                    buf, sectors * ATA_SECT_SIZE);
+                                    buf, sectors * ATA_SECT_SIZE, 0);
 
        DPRINTK("EXIT, err_mask=%x\n", err_mask);
        return err_mask;
@@ -1101,7 +1274,7 @@ static unsigned int ata_read_log_page(struct ata_device *dev,
 static int ata_eh_read_log_10h(struct ata_device *dev,
                               int *tag, struct ata_taskfile *tf)
 {
-       u8 *buf = dev->ap->sector_buf;
+       u8 *buf = dev->link->ap->sector_buf;
        unsigned int err_mask;
        u8 csum;
        int i;
@@ -1155,7 +1328,7 @@ static unsigned int atapi_eh_request_sense(struct ata_queued_cmd *qc)
 {
        struct ata_device *dev = qc->dev;
        unsigned char *sense_buf = qc->scsicmd->sense_buffer;
-       struct ata_port *ap = dev->ap;
+       struct ata_port *ap = dev->link->ap;
        struct ata_taskfile tf;
        u8 cdb[ATAPI_CDB_LEN];
 
@@ -1191,12 +1364,12 @@ static unsigned int atapi_eh_request_sense(struct ata_queued_cmd *qc)
        }
 
        return ata_exec_internal(dev, &tf, cdb, DMA_FROM_DEVICE,
-                                sense_buf, SCSI_SENSE_BUFFERSIZE);
+                                sense_buf, SCSI_SENSE_BUFFERSIZE, 0);
 }
 
 /**
  *     ata_eh_analyze_serror - analyze SError for a failed port
- *     @ap: ATA port to analyze SError for
+ *     @link: ATA link to analyze SError for
  *
  *     Analyze SError if available and further determine cause of
  *     failure.
@@ -1204,11 +1377,12 @@ static unsigned int atapi_eh_request_sense(struct ata_queued_cmd *qc)
  *     LOCKING:
  *     None.
  */
-static void ata_eh_analyze_serror(struct ata_port *ap)
+static void ata_eh_analyze_serror(struct ata_link *link)
 {
-       struct ata_eh_context *ehc = &ap->eh_context;
+       struct ata_eh_context *ehc = &link->eh_context;
        u32 serror = ehc->i.serror;
        unsigned int err_mask = 0, action = 0;
+       u32 hotplug_mask;
 
        if (serror & SERR_PERSISTENT) {
                err_mask |= AC_ERR_ATA_BUS;
@@ -1227,7 +1401,20 @@ static void ata_eh_analyze_serror(struct ata_port *ap)
                err_mask |= AC_ERR_SYSTEM;
                action |= ATA_EH_HARDRESET;
        }
-       if (serror & (SERR_PHYRDY_CHG | SERR_DEV_XCHG))
+
+       /* Determine whether a hotplug event has occurred.  Both
+        * SError.N/X are considered hotplug events for enabled or
+        * host links.  For disabled PMP links, only N bit is
+        * considered as X bit is left at 1 for link plugging.
+        */
+       hotplug_mask = 0;
+
+       if (!(link->flags & ATA_LFLAG_DISABLED) || ata_is_host_link(link))
+               hotplug_mask = SERR_PHYRDY_CHG | SERR_DEV_XCHG;
+       else
+               hotplug_mask = SERR_PHYRDY_CHG;
+
+       if (serror & hotplug_mask)
                ata_ehi_hotplugged(&ehc->i);
 
        ehc->i.err_mask |= err_mask;
@@ -1236,7 +1423,7 @@ static void ata_eh_analyze_serror(struct ata_port *ap)
 
 /**
  *     ata_eh_analyze_ncq_error - analyze NCQ error
- *     @ap: ATA port to analyze NCQ error for
+ *     @link: ATA link to analyze NCQ error for
  *
  *     Read log page 10h, determine the offending qc and acquire
  *     error status TF.  For NCQ device errors, all LLDDs have to do
@@ -1246,10 +1433,11 @@ static void ata_eh_analyze_serror(struct ata_port *ap)
  *     LOCKING:
  *     Kernel thread context (may sleep).
  */
-static void ata_eh_analyze_ncq_error(struct ata_port *ap)
+static void ata_eh_analyze_ncq_error(struct ata_link *link)
 {
-       struct ata_eh_context *ehc = &ap->eh_context;
-       struct ata_device *dev = ap->device;
+       struct ata_port *ap = link->ap;
+       struct ata_eh_context *ehc = &link->eh_context;
+       struct ata_device *dev = link->device;
        struct ata_queued_cmd *qc;
        struct ata_taskfile tf;
        int tag, rc;
@@ -1259,7 +1447,7 @@ static void ata_eh_analyze_ncq_error(struct ata_port *ap)
                return;
 
        /* is it NCQ device error? */
-       if (!ap->sactive || !(ehc->i.err_mask & AC_ERR_DEV))
+       if (!link->sactive || !(ehc->i.err_mask & AC_ERR_DEV))
                return;
 
        /* has LLDD analyzed already? */
@@ -1276,13 +1464,13 @@ static void ata_eh_analyze_ncq_error(struct ata_port *ap)
        /* okay, this error is ours */
        rc = ata_eh_read_log_10h(dev, &tag, &tf);
        if (rc) {
-               ata_port_printk(ap, KERN_ERR, "failed to read log page 10h "
+               ata_link_printk(link, KERN_ERR, "failed to read log page 10h "
                                "(errno=%d)\n", rc);
                return;
        }
 
-       if (!(ap->sactive & (1 << tag))) {
-               ata_port_printk(ap, KERN_ERR, "log page 10h reported "
+       if (!(link->sactive & (1 << tag))) {
+               ata_link_printk(link, KERN_ERR, "log page 10h reported "
                                "inactive tag %d\n", tag);
                return;
        }
@@ -1497,7 +1685,7 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io,
        /* speed down? */
        if (verdict & ATA_EH_SPDN_SPEED_DOWN) {
                /* speed down SATA link speed if possible */
-               if (sata_down_spd_limit(dev->ap) == 0) {
+               if (sata_down_spd_limit(dev->link) == 0) {
                        action |= ATA_EH_HARDRESET;
                        goto done;
                }
@@ -1528,7 +1716,7 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io,
         * SATA.  Consider it only for PATA.
         */
        if ((verdict & ATA_EH_SPDN_FALLBACK_TO_PIO) && (dev->spdn_cnt >= 2) &&
-           (dev->ap->cbl != ATA_CBL_SATA) &&
+           (dev->link->ap->cbl != ATA_CBL_SATA) &&
            (dev->xfer_shift != ATA_SHIFT_PIO)) {
                if (ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO) == 0) {
                        dev->spdn_cnt = 0;
@@ -1545,19 +1733,20 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io,
 }
 
 /**
- *     ata_eh_autopsy - analyze error and determine recovery action
- *     @ap: ATA port to perform autopsy on
+ *     ata_eh_link_autopsy - analyze error and determine recovery action
+ *     @link: host link to perform autopsy on
  *
- *     Analyze why @ap failed and determine which recovery action is
- *     needed.  This function also sets more detailed AC_ERR_* values
- *     and fills sense data for ATAPI CHECK SENSE.
+ *     Analyze why @link failed and determine which recovery actions
+ *     are needed.  This function also sets more detailed AC_ERR_*
+ *     values and fills sense data for ATAPI CHECK SENSE.
  *
  *     LOCKING:
  *     Kernel thread context (may sleep).
  */
-static void ata_eh_autopsy(struct ata_port *ap)
+static void ata_eh_link_autopsy(struct ata_link *link)
 {
-       struct ata_eh_context *ehc = &ap->eh_context;
+       struct ata_port *ap = link->ap;
+       struct ata_eh_context *ehc = &link->eh_context;
        unsigned int all_err_mask = 0;
        int tag, is_io = 0;
        u32 serror;
@@ -1569,10 +1758,10 @@ static void ata_eh_autopsy(struct ata_port *ap)
                return;
 
        /* obtain and analyze SError */
-       rc = sata_scr_read(ap, SCR_ERROR, &serror);
+       rc = sata_scr_read(link, SCR_ERROR, &serror);
        if (rc == 0) {
                ehc->i.serror |= serror;
-               ata_eh_analyze_serror(ap);
+               ata_eh_analyze_serror(link);
        } else if (rc != -EOPNOTSUPP) {
                /* SError read failed, force hardreset and probing */
                ata_ehi_schedule_probe(&ehc->i);
@@ -1581,7 +1770,7 @@ static void ata_eh_autopsy(struct ata_port *ap)
        }
 
        /* analyze NCQ failure */
-       ata_eh_analyze_ncq_error(ap);
+       ata_eh_analyze_ncq_error(link);
 
        /* any real error trumps AC_ERR_OTHER */
        if (ehc->i.err_mask & ~AC_ERR_OTHER)
@@ -1592,7 +1781,7 @@ static void ata_eh_autopsy(struct ata_port *ap)
        for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
                struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
 
-               if (!(qc->flags & ATA_QCFLAG_FAILED))
+               if (!(qc->flags & ATA_QCFLAG_FAILED) || qc->dev->link != link)
                        continue;
 
                /* inherit upper level err_mask */
@@ -1646,20 +1835,43 @@ static void ata_eh_autopsy(struct ata_port *ap)
 }
 
 /**
- *     ata_eh_report - report error handling to user
- *     @ap: ATA port EH is going on
+ *     ata_eh_autopsy - analyze error and determine recovery action
+ *     @ap: host port to perform autopsy on
+ *
+ *     Analyze all links of @ap and determine why they failed and
+ *     which recovery actions are needed.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep).
+ */
+void ata_eh_autopsy(struct ata_port *ap)
+{
+       struct ata_link *link;
+
+       __ata_port_for_each_link(link, ap)
+               ata_eh_link_autopsy(link);
+}
+
+/**
+ *     ata_eh_link_report - report error handling to user
+ *     @link: ATA link EH is going on
  *
  *     Report EH to user.
  *
  *     LOCKING:
  *     None.
  */
-static void ata_eh_report(struct ata_port *ap)
+static void ata_eh_link_report(struct ata_link *link)
 {
-       struct ata_eh_context *ehc = &ap->eh_context;
+       struct ata_port *ap = link->ap;
+       struct ata_eh_context *ehc = &link->eh_context;
        const char *frozen, *desc;
+       char tries_buf[6];
        int tag, nr_failed = 0;
 
+       if (ehc->i.flags & ATA_EHI_QUIET)
+               return;
+
        desc = NULL;
        if (ehc->i.desc[0] != '\0')
                desc = ehc->i.desc;
@@ -1667,7 +1879,7 @@ static void ata_eh_report(struct ata_port *ap)
        for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
                struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
 
-               if (!(qc->flags & ATA_QCFLAG_FAILED))
+               if (!(qc->flags & ATA_QCFLAG_FAILED) || qc->dev->link != link)
                        continue;
                if (qc->flags & ATA_QCFLAG_SENSE_VALID && !qc->err_mask)
                        continue;
@@ -1682,22 +1894,48 @@ static void ata_eh_report(struct ata_port *ap)
        if (ap->pflags & ATA_PFLAG_FROZEN)
                frozen = " frozen";
 
+       memset(tries_buf, 0, sizeof(tries_buf));
+       if (ap->eh_tries < ATA_EH_MAX_TRIES)
+               snprintf(tries_buf, sizeof(tries_buf) - 1, " t%d",
+                        ap->eh_tries);
+
        if (ehc->i.dev) {
                ata_dev_printk(ehc->i.dev, KERN_ERR, "exception Emask 0x%x "
-                              "SAct 0x%x SErr 0x%x action 0x%x%s\n",
-                              ehc->i.err_mask, ap->sactive, ehc->i.serror,
-                              ehc->i.action, frozen);
+                              "SAct 0x%x SErr 0x%x action 0x%x%s%s\n",
+                              ehc->i.err_mask, link->sactive, ehc->i.serror,
+                              ehc->i.action, frozen, tries_buf);
                if (desc)
                        ata_dev_printk(ehc->i.dev, KERN_ERR, "%s\n", desc);
        } else {
-               ata_port_printk(ap, KERN_ERR, "exception Emask 0x%x "
-                               "SAct 0x%x SErr 0x%x action 0x%x%s\n",
-                               ehc->i.err_mask, ap->sactive, ehc->i.serror,
-                               ehc->i.action, frozen);
+               ata_link_printk(link, KERN_ERR, "exception Emask 0x%x "
+                               "SAct 0x%x SErr 0x%x action 0x%x%s%s\n",
+                               ehc->i.err_mask, link->sactive, ehc->i.serror,
+                               ehc->i.action, frozen, tries_buf);
                if (desc)
-                       ata_port_printk(ap, KERN_ERR, "%s\n", desc);
+                       ata_link_printk(link, KERN_ERR, "%s\n", desc);
        }
 
+       if (ehc->i.serror)
+               ata_port_printk(ap, KERN_ERR,
+                 "SError: { %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s}\n",
+                 ehc->i.serror & SERR_DATA_RECOVERED ? "RecovData " : "",
+                 ehc->i.serror & SERR_COMM_RECOVERED ? "RecovComm " : "",
+                 ehc->i.serror & SERR_DATA ? "UnrecovData " : "",
+                 ehc->i.serror & SERR_PERSISTENT ? "Persist " : "",
+                 ehc->i.serror & SERR_PROTOCOL ? "Proto " : "",
+                 ehc->i.serror & SERR_INTERNAL ? "HostInt " : "",
+                 ehc->i.serror & SERR_PHYRDY_CHG ? "PHYRdyChg " : "",
+                 ehc->i.serror & SERR_PHY_INT_ERR ? "PHYInt " : "",
+                 ehc->i.serror & SERR_COMM_WAKE ? "CommWake " : "",
+                 ehc->i.serror & SERR_10B_8B_ERR ? "10B8B " : "",
+                 ehc->i.serror & SERR_DISPARITY ? "Dispar " : "",
+                 ehc->i.serror & SERR_CRC ? "BadCRC " : "",
+                 ehc->i.serror & SERR_HANDSHAKE ? "Handshk " : "",
+                 ehc->i.serror & SERR_LINK_SEQ_ERR ? "LinkSeq " : "",
+                 ehc->i.serror & SERR_TRANS_ST_ERROR ? "TrStaTrns " : "",
+                 ehc->i.serror & SERR_UNRECOG_FIS ? "UnrecFIS " : "",
+                 ehc->i.serror & SERR_DEV_XCHG ? "DevExch " : "" );
+
        for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
                static const char *dma_str[] = {
                        [DMA_BIDIRECTIONAL]     = "bidi",
@@ -1708,7 +1946,8 @@ static void ata_eh_report(struct ata_port *ap)
                struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
                struct ata_taskfile *cmd = &qc->tf, *res = &qc->result_tf;
 
-               if (!(qc->flags & ATA_QCFLAG_FAILED) || !qc->err_mask)
+               if (!(qc->flags & ATA_QCFLAG_FAILED) ||
+                   qc->dev->link != link || !qc->err_mask)
                        continue;
 
                ata_dev_printk(qc->dev, KERN_ERR,
@@ -1728,18 +1967,60 @@ static void ata_eh_report(struct ata_port *ap)
                        res->hob_lbal, res->hob_lbam, res->hob_lbah,
                        res->device, qc->err_mask, ata_err_string(qc->err_mask),
                        qc->err_mask & AC_ERR_NCQ ? " <F>" : "");
+
+               if (res->command & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ |
+                                   ATA_ERR) ) {
+                       if (res->command & ATA_BUSY)
+                               ata_dev_printk(qc->dev, KERN_ERR,
+                                 "status: { Busy }\n" );
+                       else
+                               ata_dev_printk(qc->dev, KERN_ERR,
+                                 "status: { %s%s%s%s}\n",
+                                 res->command & ATA_DRDY ? "DRDY " : "",
+                                 res->command & ATA_DF ? "DF " : "",
+                                 res->command & ATA_DRQ ? "DRQ " : "",
+                                 res->command & ATA_ERR ? "ERR " : "" );
+               }
+
+               if (cmd->command != ATA_CMD_PACKET &&
+                   (res->feature & (ATA_ICRC | ATA_UNC | ATA_IDNF |
+                                    ATA_ABORTED)))
+                       ata_dev_printk(qc->dev, KERN_ERR,
+                         "error: { %s%s%s%s}\n",
+                         res->feature & ATA_ICRC ? "ICRC " : "",
+                         res->feature & ATA_UNC ? "UNC " : "",
+                         res->feature & ATA_IDNF ? "IDNF " : "",
+                         res->feature & ATA_ABORTED ? "ABRT " : "" );
        }
 }
 
-static int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset,
+/**
+ *     ata_eh_report - report error handling to user
+ *     @ap: ATA port to report EH about
+ *
+ *     Report EH to user.
+ *
+ *     LOCKING:
+ *     None.
+ */
+void ata_eh_report(struct ata_port *ap)
+{
+       struct ata_link *link;
+
+       __ata_port_for_each_link(link, ap)
+               ata_eh_link_report(link);
+}
+
+static int ata_do_reset(struct ata_link *link, ata_reset_fn_t reset,
                        unsigned int *classes, unsigned long deadline)
 {
-       int i, rc;
+       struct ata_device *dev;
+       int rc;
 
-       for (i = 0; i < ATA_MAX_DEVICES; i++)
-               classes[i] = ATA_DEV_UNKNOWN;
+       ata_link_for_each_dev(dev, link)
+               classes[dev->devno] = ATA_DEV_UNKNOWN;
 
-       rc = reset(ap, classes, deadline);
+       rc = reset(link, classes, deadline);
        if (rc)
                return rc;
 
@@ -1747,71 +2028,87 @@ static int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset,
         * is complete and convert all ATA_DEV_UNKNOWN to
         * ATA_DEV_NONE.
         */
-       for (i = 0; i < ATA_MAX_DEVICES; i++)
-               if (classes[i] != ATA_DEV_UNKNOWN)
+       ata_link_for_each_dev(dev, link)
+               if (classes[dev->devno] != ATA_DEV_UNKNOWN)
                        break;
 
-       if (i < ATA_MAX_DEVICES)
-               for (i = 0; i < ATA_MAX_DEVICES; i++)
-                       if (classes[i] == ATA_DEV_UNKNOWN)
-                               classes[i] = ATA_DEV_NONE;
+       if (dev) {
+               ata_link_for_each_dev(dev, link) {
+                       if (classes[dev->devno] == ATA_DEV_UNKNOWN)
+                               classes[dev->devno] = ATA_DEV_NONE;
+               }
+       }
 
        return 0;
 }
 
-static int ata_eh_followup_srst_needed(int rc, int classify,
+static int ata_eh_followup_srst_needed(struct ata_link *link,
+                                      int rc, int classify,
                                       const unsigned int *classes)
 {
+       if (link->flags & ATA_LFLAG_NO_SRST)
+               return 0;
        if (rc == -EAGAIN)
                return 1;
        if (rc != 0)
                return 0;
-       if (classify && classes[0] == ATA_DEV_UNKNOWN)
+       if ((link->ap->flags & ATA_FLAG_PMP) && ata_is_host_link(link))
+               return 1;
+       if (classify && !(link->flags & ATA_LFLAG_ASSUME_CLASS) &&
+           classes[0] == ATA_DEV_UNKNOWN)
                return 1;
        return 0;
 }
 
-static int ata_eh_reset(struct ata_port *ap, int classify,
-                       ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
-                       ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
+int ata_eh_reset(struct ata_link *link, int classify,
+                ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
+                ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
 {
-       struct ata_eh_context *ehc = &ap->eh_context;
+       struct ata_port *ap = link->ap;
+       struct ata_eh_context *ehc = &link->eh_context;
        unsigned int *classes = ehc->classes;
        int verbose = !(ehc->i.flags & ATA_EHI_QUIET);
        int try = 0;
+       struct ata_device *dev;
        unsigned long deadline;
        unsigned int action;
        ata_reset_fn_t reset;
-       int i, rc;
+       unsigned long flags;
+       int rc;
 
        /* about to reset */
-       ata_eh_about_to_do(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK);
+       spin_lock_irqsave(ap->lock, flags);
+       ap->pflags |= ATA_PFLAG_RESETTING;
+       spin_unlock_irqrestore(ap->lock, flags);
+
+       ata_eh_about_to_do(link, NULL, ehc->i.action & ATA_EH_RESET_MASK);
 
        /* Determine which reset to use and record in ehc->i.action.
         * prereset() may examine and modify it.
         */
        action = ehc->i.action;
        ehc->i.action &= ~ATA_EH_RESET_MASK;
-       if (softreset && (!hardreset || (!sata_set_spd_needed(ap) &&
+       if (softreset && (!hardreset || (!(link->flags & ATA_LFLAG_NO_SRST) &&
+                                        !sata_set_spd_needed(link) &&
                                         !(action & ATA_EH_HARDRESET))))
                ehc->i.action |= ATA_EH_SOFTRESET;
        else
                ehc->i.action |= ATA_EH_HARDRESET;
 
        if (prereset) {
-               rc = prereset(ap, jiffies + ATA_EH_PRERESET_TIMEOUT);
+               rc = prereset(link, jiffies + ATA_EH_PRERESET_TIMEOUT);
                if (rc) {
                        if (rc == -ENOENT) {
-                               ata_port_printk(ap, KERN_DEBUG,
+                               ata_link_printk(link, KERN_DEBUG,
                                                "port disabled. ignoring.\n");
-                               ap->eh_context.i.action &= ~ATA_EH_RESET_MASK;
+                               ehc->i.action &= ~ATA_EH_RESET_MASK;
 
-                               for (i = 0; i < ATA_MAX_DEVICES; i++)
-                                       classes[i] = ATA_DEV_NONE;
+                               ata_link_for_each_dev(dev, link)
+                                       classes[dev->devno] = ATA_DEV_NONE;
 
                                rc = 0;
                        } else
-                               ata_port_printk(ap, KERN_ERR,
+                               ata_link_printk(link, KERN_ERR,
                                        "prereset failed (errno=%d)\n", rc);
                        goto out;
                }
@@ -1824,8 +2121,8 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
                reset = softreset;
        else {
                /* prereset told us not to reset, bang classes and return */
-               for (i = 0; i < ATA_MAX_DEVICES; i++)
-                       classes[i] = ATA_DEV_NONE;
+               ata_link_for_each_dev(dev, link)
+                       classes[dev->devno] = ATA_DEV_NONE;
                rc = 0;
                goto out;
        }
@@ -1843,7 +2140,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
 
        /* shut up during boot probing */
        if (verbose)
-               ata_port_printk(ap, KERN_INFO, "%s resetting port\n",
+               ata_link_printk(link, KERN_INFO, "%s resetting link\n",
                                reset == softreset ? "soft" : "hard");
 
        /* mark that this EH session started with reset */
@@ -1852,49 +2149,54 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
        else
                ehc->i.flags |= ATA_EHI_DID_SOFTRESET;
 
-       rc = ata_do_reset(ap, reset, classes, deadline);
+       rc = ata_do_reset(link, reset, classes, deadline);
 
        if (reset == hardreset &&
-           ata_eh_followup_srst_needed(rc, classify, classes)) {
+           ata_eh_followup_srst_needed(link, rc, classify, classes)) {
                /* okay, let's do follow-up softreset */
                reset = softreset;
 
                if (!reset) {
-                       ata_port_printk(ap, KERN_ERR,
+                       ata_link_printk(link, KERN_ERR,
                                        "follow-up softreset required "
                                        "but no softreset avaliable\n");
                        rc = -EINVAL;
                        goto out;
                }
 
-               ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK);
-               rc = ata_do_reset(ap, reset, classes, deadline);
+               ata_eh_about_to_do(link, NULL, ATA_EH_RESET_MASK);
+               rc = ata_do_reset(link, reset, classes, deadline);
 
-               if (rc == 0 && classify &&
-                   classes[0] == ATA_DEV_UNKNOWN) {
-                       ata_port_printk(ap, KERN_ERR,
+               if (rc == 0 && classify && classes[0] == ATA_DEV_UNKNOWN &&
+                   !(link->flags & ATA_LFLAG_ASSUME_CLASS)) {
+                       ata_link_printk(link, KERN_ERR,
                                        "classification failed\n");
                        rc = -EINVAL;
                        goto out;
                }
        }
 
-       if (rc && try < ARRAY_SIZE(ata_eh_reset_timeouts)) {
+       /* if we skipped follow-up srst, clear rc */
+       if (rc == -EAGAIN)
+               rc = 0;
+
+       if (rc && rc != -ERESTART && try < ARRAY_SIZE(ata_eh_reset_timeouts)) {
                unsigned long now = jiffies;
 
                if (time_before(now, deadline)) {
                        unsigned long delta = deadline - jiffies;
 
-                       ata_port_printk(ap, KERN_WARNING, "reset failed "
+                       ata_link_printk(link, KERN_WARNING, "reset failed "
                                "(errno=%d), retrying in %u secs\n",
                                rc, (jiffies_to_msecs(delta) + 999) / 1000);
 
-                       schedule_timeout_uninterruptible(delta);
+                       while (delta)
+                               delta = schedule_timeout_uninterruptible(delta);
                }
 
                if (rc == -EPIPE ||
                    try == ARRAY_SIZE(ata_eh_reset_timeouts) - 1)
-                       sata_down_spd_limit(ap);
+                       sata_down_spd_limit(link);
                if (hardreset)
                        reset = hardreset;
                goto retry;
@@ -1903,37 +2205,56 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
        if (rc == 0) {
                u32 sstatus;
 
-               /* After the reset, the device state is PIO 0 and the
-                * controller state is undefined.  Record the mode.
-                */
-               for (i = 0; i < ATA_MAX_DEVICES; i++)
-                       ap->device[i].pio_mode = XFER_PIO_0;
+               ata_link_for_each_dev(dev, link) {
+                       /* After the reset, the device state is PIO 0
+                        * and the controller state is undefined.
+                        * Record the mode.
+                        */
+                       dev->pio_mode = XFER_PIO_0;
+
+                       if (ata_link_offline(link))
+                               continue;
+
+                       /* apply class override and convert UNKNOWN to NONE */
+                       if (link->flags & ATA_LFLAG_ASSUME_ATA)
+                               classes[dev->devno] = ATA_DEV_ATA;
+                       else if (link->flags & ATA_LFLAG_ASSUME_SEMB)
+                               classes[dev->devno] = ATA_DEV_SEMB_UNSUP; /* not yet */
+                       else if (classes[dev->devno] == ATA_DEV_UNKNOWN)
+                               classes[dev->devno] = ATA_DEV_NONE;
+               }
 
                /* record current link speed */
-               if (sata_scr_read(ap, SCR_STATUS, &sstatus) == 0)
-                       ap->sata_spd = (sstatus >> 4) & 0xf;
+               if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0)
+                       link->sata_spd = (sstatus >> 4) & 0xf;
 
                if (postreset)
-                       postreset(ap, classes);
+                       postreset(link, classes);
 
                /* reset successful, schedule revalidation */
-               ata_eh_done(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK);
+               ata_eh_done(link, NULL, ehc->i.action & ATA_EH_RESET_MASK);
                ehc->i.action |= ATA_EH_REVALIDATE;
        }
  out:
        /* clear hotplug flag */
        ehc->i.flags &= ~ATA_EHI_HOTPLUGGED;
+
+       spin_lock_irqsave(ap->lock, flags);
+       ap->pflags &= ~ATA_PFLAG_RESETTING;
+       spin_unlock_irqrestore(ap->lock, flags);
+
        return rc;
 }
 
-static int ata_eh_revalidate_and_attach(struct ata_port *ap,
+static int ata_eh_revalidate_and_attach(struct ata_link *link,
                                        struct ata_device **r_failed_dev)
 {
-       struct ata_eh_context *ehc = &ap->eh_context;
+       struct ata_port *ap = link->ap;
+       struct ata_eh_context *ehc = &link->eh_context;
        struct ata_device *dev;
        unsigned int new_mask = 0;
        unsigned long flags;
-       int i, rc = 0;
+       int rc = 0;
 
        DPRINTK("ENTER\n");
 
@@ -1941,27 +2262,28 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
         * be done backwards such that PDIAG- is released by the slave
         * device before the master device is identified.
         */
-       for (i = ATA_MAX_DEVICES - 1; i >= 0; i--) {
-               unsigned int action, readid_flags = 0;
-
-               dev = &ap->device[i];
-               action = ata_eh_dev_action(dev);
+       ata_link_for_each_dev_reverse(dev, link) {
+               unsigned int action = ata_eh_dev_action(dev);
+               unsigned int readid_flags = 0;
 
                if (ehc->i.flags & ATA_EHI_DID_RESET)
                        readid_flags |= ATA_READID_POSTRESET;
 
                if ((action & ATA_EH_REVALIDATE) && ata_dev_enabled(dev)) {
-                       if (ata_port_offline(ap)) {
+                       WARN_ON(dev->class == ATA_DEV_PMP);
+
+                       if (ata_link_offline(link)) {
                                rc = -EIO;
                                goto err;
                        }
 
-                       ata_eh_about_to_do(ap, dev, ATA_EH_REVALIDATE);
-                       rc = ata_dev_revalidate(dev, readid_flags);
+                       ata_eh_about_to_do(link, dev, ATA_EH_REVALIDATE);
+                       rc = ata_dev_revalidate(dev, ehc->classes[dev->devno],
+                                               readid_flags);
                        if (rc)
                                goto err;
 
-                       ata_eh_done(ap, dev, ATA_EH_REVALIDATE);
+                       ata_eh_done(link, dev, ATA_EH_REVALIDATE);
 
                        /* Configuration may have changed, reconfigure
                         * transfer mode.
@@ -1975,11 +2297,14 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
                           ata_class_enabled(ehc->classes[dev->devno])) {
                        dev->class = ehc->classes[dev->devno];
 
-                       rc = ata_dev_read_id(dev, &dev->class, readid_flags,
-                                            dev->id);
+                       if (dev->class == ATA_DEV_PMP)
+                               rc = sata_pmp_attach(dev);
+                       else
+                               rc = ata_dev_read_id(dev, &dev->class,
+                                                    readid_flags, dev->id);
                        switch (rc) {
                        case 0:
-                               new_mask |= 1 << i;
+                               new_mask |= 1 << dev->devno;
                                break;
                        case -ENOENT:
                                /* IDENTIFY was issued to non-existent
@@ -1997,16 +2322,16 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
        }
 
        /* PDIAG- should have been released, ask cable type if post-reset */
-       if ((ehc->i.flags & ATA_EHI_DID_RESET) && ap->ops->cable_detect)
+       if (ata_is_host_link(link) && ap->ops->cable_detect &&
+           (ehc->i.flags & ATA_EHI_DID_RESET))
                ap->cbl = ap->ops->cable_detect(ap);
 
        /* Configure new devices forward such that user doesn't see
         * device detection messages backwards.
         */
-       for (i = 0; i < ATA_MAX_DEVICES; i++) {
-               dev = &ap->device[i];
-
-               if (!(new_mask & (1 << i)))
+       ata_link_for_each_dev(dev, link) {
+               if (!(new_mask & (1 << dev->devno)) ||
+                   dev->class == ATA_DEV_PMP)
                        continue;
 
                ehc->i.flags |= ATA_EHI_PRINTINFO;
@@ -2031,40 +2356,44 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
        return rc;
 }
 
-static int ata_port_nr_enabled(struct ata_port *ap)
+static int ata_link_nr_enabled(struct ata_link *link)
 {
-       int i, cnt = 0;
+       struct ata_device *dev;
+       int cnt = 0;
 
-       for (i = 0; i < ATA_MAX_DEVICES; i++)
-               if (ata_dev_enabled(&ap->device[i]))
+       ata_link_for_each_dev(dev, link)
+               if (ata_dev_enabled(dev))
                        cnt++;
        return cnt;
 }
 
-static int ata_port_nr_vacant(struct ata_port *ap)
+static int ata_link_nr_vacant(struct ata_link *link)
 {
-       int i, cnt = 0;
+       struct ata_device *dev;
+       int cnt = 0;
 
-       for (i = 0; i < ATA_MAX_DEVICES; i++)
-               if (ap->device[i].class == ATA_DEV_UNKNOWN)
+       ata_link_for_each_dev(dev, link)
+               if (dev->class == ATA_DEV_UNKNOWN)
                        cnt++;
        return cnt;
 }
 
-static int ata_eh_skip_recovery(struct ata_port *ap)
+static int ata_eh_skip_recovery(struct ata_link *link)
 {
-       struct ata_eh_context *ehc = &ap->eh_context;
-       int i;
+       struct ata_eh_context *ehc = &link->eh_context;
+       struct ata_device *dev;
+
+       /* skip disabled links */
+       if (link->flags & ATA_LFLAG_DISABLED)
+               return 1;
 
        /* thaw frozen port, resume link and recover failed devices */
-       if ((ap->pflags & ATA_PFLAG_FROZEN) ||
-           (ehc->i.flags & ATA_EHI_RESUME_LINK) || ata_port_nr_enabled(ap))
+       if ((link->ap->pflags & ATA_PFLAG_FROZEN) ||
+           (ehc->i.flags & ATA_EHI_RESUME_LINK) || ata_link_nr_enabled(link))
                return 0;
 
        /* skip if class codes for all vacant slots are ATA_DEV_NONE */
-       for (i = 0; i < ATA_MAX_DEVICES; i++) {
-               struct ata_device *dev = &ap->device[i];
-
+       ata_link_for_each_dev(dev, link) {
                if (dev->class == ATA_DEV_UNKNOWN &&
                    ehc->classes[dev->devno] != ATA_DEV_NONE)
                        return 0;
@@ -2073,10 +2402,9 @@ static int ata_eh_skip_recovery(struct ata_port *ap)
        return 1;
 }
 
-static void ata_eh_handle_dev_fail(struct ata_device *dev, int err)
+static int ata_eh_handle_dev_fail(struct ata_device *dev, int err)
 {
-       struct ata_port *ap = dev->ap;
-       struct ata_eh_context *ehc = &ap->eh_context;
+       struct ata_eh_context *ehc = &dev->link->eh_context;
 
        ehc->tries[dev->devno]--;
 
@@ -2092,7 +2420,7 @@ static void ata_eh_handle_dev_fail(struct ata_device *dev, int err)
                        /* This is the last chance, better to slow
                         * down than lose it.
                         */
-                       sata_down_spd_limit(ap);
+                       sata_down_spd_limit(dev->link);
                        ata_down_xfermask_limit(dev, ATA_DNXFER_PIO);
                }
        }
@@ -2102,7 +2430,7 @@ static void ata_eh_handle_dev_fail(struct ata_device *dev, int err)
                ata_dev_disable(dev);
 
                /* detach if offline */
-               if (ata_port_offline(ap))
+               if (ata_link_offline(dev->link))
                        ata_eh_detach_dev(dev);
 
                /* probe if requested */
@@ -2115,12 +2443,16 @@ static void ata_eh_handle_dev_fail(struct ata_device *dev, int err)
                        ehc->did_probe_mask |= (1 << dev->devno);
                        ehc->i.action |= ATA_EH_SOFTRESET;
                }
+
+               return 1;
        } else {
                /* soft didn't work?  be haaaaard */
                if (ehc->i.flags & ATA_EHI_DID_RESET)
                        ehc->i.action |= ATA_EH_HARDRESET;
                else
                        ehc->i.action |= ATA_EH_SOFTRESET;
+
+               return 0;
        }
 }
 
@@ -2131,12 +2463,13 @@ static void ata_eh_handle_dev_fail(struct ata_device *dev, int err)
  *     @softreset: softreset method (can be NULL)
  *     @hardreset: hardreset method (can be NULL)
  *     @postreset: postreset method (can be NULL)
+ *     @r_failed_link: out parameter for failed link
  *
  *     This is the alpha and omega, eum and yang, heart and soul of
  *     libata exception handling.  On entry, actions required to
- *     recover the port and hotplug requests are recorded in
- *     eh_context.  This function executes all the operations with
- *     appropriate retrials and fallbacks to resurrect failed
+ *     recover each link and hotplug requests are recorded in the
+ *     link's eh_context.  This function executes all the operations
+ *     with appropriate retrials and fallbacks to resurrect failed
  *     devices, detach goners and greet newcomers.
  *
  *     LOCKING:
@@ -2145,104 +2478,171 @@ static void ata_eh_handle_dev_fail(struct ata_device *dev, int err)
  *     RETURNS:
  *     0 on success, -errno on failure.
  */
-static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
-                         ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
-                         ata_postreset_fn_t postreset)
+int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
+                  ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
+                  ata_postreset_fn_t postreset,
+                  struct ata_link **r_failed_link)
 {
-       struct ata_eh_context *ehc = &ap->eh_context;
+       struct ata_link *link;
        struct ata_device *dev;
-       int i, rc;
+       int nr_failed_devs, nr_disabled_devs;
+       int reset, rc;
+       unsigned long flags;
 
        DPRINTK("ENTER\n");
 
        /* prep for recovery */
-       for (i = 0; i < ATA_MAX_DEVICES; i++) {
-               dev = &ap->device[i];
-
-               ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
-
-               /* collect port action mask recorded in dev actions */
-               ehc->i.action |= ehc->i.dev_action[i] & ~ATA_EH_PERDEV_MASK;
-               ehc->i.dev_action[i] &= ATA_EH_PERDEV_MASK;
-
-               /* process hotplug request */
-               if (dev->flags & ATA_DFLAG_DETACH)
-                       ata_eh_detach_dev(dev);
+       ata_port_for_each_link(link, ap) {
+               struct ata_eh_context *ehc = &link->eh_context;
+
+               /* re-enable link? */
+               if (ehc->i.action & ATA_EH_ENABLE_LINK) {
+                       ata_eh_about_to_do(link, NULL, ATA_EH_ENABLE_LINK);
+                       spin_lock_irqsave(ap->lock, flags);
+                       link->flags &= ~ATA_LFLAG_DISABLED;
+                       spin_unlock_irqrestore(ap->lock, flags);
+                       ata_eh_done(link, NULL, ATA_EH_ENABLE_LINK);
+               }
 
-               if (!ata_dev_enabled(dev) &&
-                   ((ehc->i.probe_mask & (1 << dev->devno)) &&
-                    !(ehc->did_probe_mask & (1 << dev->devno)))) {
-                       ata_eh_detach_dev(dev);
-                       ata_dev_init(dev);
-                       ehc->did_probe_mask |= (1 << dev->devno);
-                       ehc->i.action |= ATA_EH_SOFTRESET;
+               ata_link_for_each_dev(dev, link) {
+                       if (link->flags & ATA_LFLAG_NO_RETRY)
+                               ehc->tries[dev->devno] = 1;
+                       else
+                               ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
+
+                       /* collect port action mask recorded in dev actions */
+                       ehc->i.action |= ehc->i.dev_action[dev->devno] &
+                                        ~ATA_EH_PERDEV_MASK;
+                       ehc->i.dev_action[dev->devno] &= ATA_EH_PERDEV_MASK;
+
+                       /* process hotplug request */
+                       if (dev->flags & ATA_DFLAG_DETACH)
+                               ata_eh_detach_dev(dev);
+
+                       if (!ata_dev_enabled(dev) &&
+                           ((ehc->i.probe_mask & (1 << dev->devno)) &&
+                            !(ehc->did_probe_mask & (1 << dev->devno)))) {
+                               ata_eh_detach_dev(dev);
+                               ata_dev_init(dev);
+                               ehc->did_probe_mask |= (1 << dev->devno);
+                               ehc->i.action |= ATA_EH_SOFTRESET;
+                       }
                }
        }
 
  retry:
        rc = 0;
+       nr_failed_devs = 0;
+       nr_disabled_devs = 0;
+       reset = 0;
 
        /* if UNLOADING, finish immediately */
        if (ap->pflags & ATA_PFLAG_UNLOADING)
                goto out;
 
-       /* skip EH if possible. */
-       if (ata_eh_skip_recovery(ap))
-               ehc->i.action = 0;
+       /* prep for EH */
+       ata_port_for_each_link(link, ap) {
+               struct ata_eh_context *ehc = &link->eh_context;
 
-       for (i = 0; i < ATA_MAX_DEVICES; i++)
-               ehc->classes[i] = ATA_DEV_UNKNOWN;
+               /* skip EH if possible. */
+               if (ata_eh_skip_recovery(link))
+                       ehc->i.action = 0;
 
-       /* reset */
-       if (ehc->i.action & ATA_EH_RESET_MASK) {
-               ata_eh_freeze_port(ap);
+               /* do we need to reset? */
+               if (ehc->i.action & ATA_EH_RESET_MASK)
+                       reset = 1;
 
-               rc = ata_eh_reset(ap, ata_port_nr_vacant(ap), prereset,
-                                 softreset, hardreset, postreset);
-               if (rc) {
-                       ata_port_printk(ap, KERN_ERR,
-                                       "reset failed, giving up\n");
-                       goto out;
+               ata_link_for_each_dev(dev, link)
+                       ehc->classes[dev->devno] = ATA_DEV_UNKNOWN;
+       }
+
+       /* reset */
+       if (reset) {
+               /* if PMP is attached, this function only deals with
+                * downstream links, port should stay thawed.
+                */
+               if (!ap->nr_pmp_links)
+                       ata_eh_freeze_port(ap);
+
+               ata_port_for_each_link(link, ap) {
+                       struct ata_eh_context *ehc = &link->eh_context;
+
+                       if (!(ehc->i.action & ATA_EH_RESET_MASK))
+                               continue;
+
+                       rc = ata_eh_reset(link, ata_link_nr_vacant(link),
+                                         prereset, softreset, hardreset,
+                                         postreset);
+                       if (rc) {
+                               ata_link_printk(link, KERN_ERR,
+                                               "reset failed, giving up\n");
+                               goto out;
+                       }
                }
 
-               ata_eh_thaw_port(ap);
+               if (!ap->nr_pmp_links)
+                       ata_eh_thaw_port(ap);
        }
 
-       /* revalidate existing devices and attach new ones */
-       rc = ata_eh_revalidate_and_attach(ap, &dev);
-       if (rc)
-               goto dev_fail;
+       /* the rest */
+       ata_port_for_each_link(link, ap) {
+               struct ata_eh_context *ehc = &link->eh_context;
 
-       /* configure transfer mode if necessary */
-       if (ehc->i.flags & ATA_EHI_SETMODE) {
-               rc = ata_set_mode(ap, &dev);
+               /* revalidate existing devices and attach new ones */
+               rc = ata_eh_revalidate_and_attach(link, &dev);
                if (rc)
                        goto dev_fail;
-               ehc->i.flags &= ~ATA_EHI_SETMODE;
-       }
 
-       goto out;
+               /* if PMP got attached, return, pmp EH will take care of it */
+               if (link->device->class == ATA_DEV_PMP) {
+                       ehc->i.action = 0;
+                       return 0;
+               }
 
- dev_fail:
-       ata_eh_handle_dev_fail(dev, rc);
+               /* configure transfer mode if necessary */
+               if (ehc->i.flags & ATA_EHI_SETMODE) {
+                       rc = ata_set_mode(link, &dev);
+                       if (rc)
+                               goto dev_fail;
+                       ehc->i.flags &= ~ATA_EHI_SETMODE;
+               }
 
-       if (ata_port_nr_enabled(ap)) {
-               ata_port_printk(ap, KERN_WARNING, "failed to recover some "
-                               "devices, retrying in 5 secs\n");
-               ssleep(5);
-       } else {
-               /* no device left, repeat fast */
-               msleep(500);
+               /* this link is okay now */
+               ehc->i.flags = 0;
+               continue;
+
+       dev_fail:
+               nr_failed_devs++;
+               if (ata_eh_handle_dev_fail(dev, rc))
+                       nr_disabled_devs++;
+
+               if (ap->pflags & ATA_PFLAG_FROZEN) {
+                       /* PMP reset requires working host port.
+                        * Can't retry if it's frozen.
+                        */
+                       if (ap->nr_pmp_links)
+                               goto out;
+                       break;
+               }
        }
 
-       goto retry;
+       if (nr_failed_devs) {
+               if (nr_failed_devs != nr_disabled_devs) {
+                       ata_port_printk(ap, KERN_WARNING, "failed to recover "
+                                       "some devices, retrying in 5 secs\n");
+                       ssleep(5);
+               } else {
+                       /* no device left to recover, repeat fast */
+                       msleep(500);
+               }
 
- out:
-       if (rc) {
-               for (i = 0; i < ATA_MAX_DEVICES; i++)
-                       ata_dev_disable(&ap->device[i]);
+               goto retry;
        }
 
+ out:
+       if (rc && r_failed_link)
+               *r_failed_link = link;
+
        DPRINTK("EXIT, rc=%d\n", rc);
        return rc;
 }
@@ -2257,7 +2657,7 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
  *     LOCKING:
  *     None.
  */
-static void ata_eh_finish(struct ata_port *ap)
+void ata_eh_finish(struct ata_port *ap)
 {
        int tag;
 
@@ -2287,6 +2687,10 @@ static void ata_eh_finish(struct ata_port *ap)
                        }
                }
        }
+
+       /* make sure nr_active_links is zero after EH */
+       WARN_ON(ap->nr_active_links);
+       ap->nr_active_links = 0;
 }
 
 /**
@@ -2306,9 +2710,19 @@ void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
               ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
               ata_postreset_fn_t postreset)
 {
+       struct ata_device *dev;
+       int rc;
+
        ata_eh_autopsy(ap);
        ata_eh_report(ap);
-       ata_eh_recover(ap, prereset, softreset, hardreset, postreset);
+
+       rc = ata_eh_recover(ap, prereset, softreset, hardreset, postreset,
+                           NULL);
+       if (rc) {
+               ata_link_for_each_dev(dev, &ap->link)
+                       ata_dev_disable(dev);
+       }
+
        ata_eh_finish(ap);
 }
 
diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c
new file mode 100644 (file)
index 0000000..c0c4dbc
--- /dev/null
@@ -0,0 +1,1191 @@
+/*
+ * libata-pmp.c - libata port multiplier support
+ *
+ * Copyright (c) 2007  SUSE Linux Products GmbH
+ * Copyright (c) 2007  Tejun Heo <teheo@suse.de>
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/libata.h>
+#include "libata.h"
+
+/**
+ *     sata_pmp_read - read PMP register
+ *     @link: link to read PMP register for
+ *     @reg: register to read
+ *     @r_val: resulting value
+ *
+ *     Read PMP register.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep).
+ *
+ *     RETURNS:
+ *     0 on success, AC_ERR_* mask on failure.
+ */
+static unsigned int sata_pmp_read(struct ata_link *link, int reg, u32 *r_val)
+{
+       struct ata_port *ap = link->ap;
+       struct ata_device *pmp_dev = ap->link.device;
+       struct ata_taskfile tf;
+       unsigned int err_mask;
+
+       ata_tf_init(pmp_dev, &tf);
+       tf.command = ATA_CMD_PMP_READ;
+       tf.protocol = ATA_PROT_NODATA;
+       tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+       tf.feature = reg;
+       tf.device = link->pmp;
+
+       err_mask = ata_exec_internal(pmp_dev, &tf, NULL, DMA_NONE, NULL, 0,
+                                    SATA_PMP_SCR_TIMEOUT);
+       if (err_mask)
+               return err_mask;
+
+       *r_val = tf.nsect | tf.lbal << 8 | tf.lbam << 16 | tf.lbah << 24;
+       return 0;
+}
+
+/**
+ *     sata_pmp_write - write PMP register
+ *     @link: link to write PMP register for
+ *     @reg: register to write
+ *     @r_val: value to write
+ *
+ *     Write PMP register.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep).
+ *
+ *     RETURNS:
+ *     0 on success, AC_ERR_* mask on failure.
+ */
+static unsigned int sata_pmp_write(struct ata_link *link, int reg, u32 val)
+{
+       struct ata_port *ap = link->ap;
+       struct ata_device *pmp_dev = ap->link.device;
+       struct ata_taskfile tf;
+
+       ata_tf_init(pmp_dev, &tf);
+       tf.command = ATA_CMD_PMP_WRITE;
+       tf.protocol = ATA_PROT_NODATA;
+       tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+       tf.feature = reg;
+       tf.device = link->pmp;
+       tf.nsect = val & 0xff;
+       tf.lbal = (val >> 8) & 0xff;
+       tf.lbam = (val >> 16) & 0xff;
+       tf.lbah = (val >> 24) & 0xff;
+
+       return ata_exec_internal(pmp_dev, &tf, NULL, DMA_NONE, NULL, 0,
+                                SATA_PMP_SCR_TIMEOUT);
+}
+
+/**
+ *     sata_pmp_qc_defer_cmd_switch - qc_defer for command switching PMP
+ *     @qc: ATA command in question
+ *
+ *     A host which has command switching PMP support cannot issue
+ *     commands to multiple links simultaneously.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host lock)
+ *
+ *     RETURNS:
+ *     ATA_DEFER_* if deferring is needed, 0 otherwise.
+ */
+int sata_pmp_qc_defer_cmd_switch(struct ata_queued_cmd *qc)
+{
+       struct ata_link *link = qc->dev->link;
+       struct ata_port *ap = link->ap;
+
+       if (ap->excl_link == NULL || ap->excl_link == link) {
+               if (ap->nr_active_links == 0 || ata_link_active(link)) {
+                       qc->flags |= ATA_QCFLAG_CLEAR_EXCL;
+                       return ata_std_qc_defer(qc);
+               }
+
+               ap->excl_link = link;
+       }
+
+       return ATA_DEFER_PORT;
+}
+
+/**
+ *     sata_pmp_scr_read - read PSCR
+ *     @link: ATA link to read PSCR for
+ *     @reg: PSCR to read
+ *     @r_val: resulting value
+ *
+ *     Read PSCR @reg into @r_val for @link, to be called from
+ *     ata_scr_read().
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep).
+ *
+ *     RETURNS:
+ *     0 on success, -errno on failure.
+ */
+int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *r_val)
+{
+       unsigned int err_mask;
+
+       if (reg > SATA_PMP_PSCR_CONTROL)
+               return -EINVAL;
+
+       err_mask = sata_pmp_read(link, reg, r_val);
+       if (err_mask) {
+               ata_link_printk(link, KERN_WARNING, "failed to read SCR %d "
+                               "(Emask=0x%x)\n", reg, err_mask);
+               return -EIO;
+       }
+       return 0;
+}
+
+/**
+ *     sata_pmp_scr_write - write PSCR
+ *     @link: ATA link to write PSCR for
+ *     @reg: PSCR to write
+ *     @val: value to be written
+ *
+ *     Write @val to PSCR @reg for @link, to be called from
+ *     ata_scr_write() and ata_scr_write_flush().
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep).
+ *
+ *     RETURNS:
+ *     0 on success, -errno on failure.
+ */
+int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val)
+{
+       unsigned int err_mask;
+
+       if (reg > SATA_PMP_PSCR_CONTROL)
+               return -EINVAL;
+
+       err_mask = sata_pmp_write(link, reg, val);
+       if (err_mask) {
+               ata_link_printk(link, KERN_WARNING, "failed to write SCR %d "
+                               "(Emask=0x%x)\n", reg, err_mask);
+               return -EIO;
+       }
+       return 0;
+}
+
+/**
+ *     sata_pmp_std_prereset - prepare PMP link for reset
+ *     @link: link to be reset
+ *     @deadline: deadline jiffies for the operation
+ *
+ *     @link is about to be reset.  Initialize it.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep)
+ *
+ *     RETURNS:
+ *     0 on success, -errno otherwise.
+ */
+int sata_pmp_std_prereset(struct ata_link *link, unsigned long deadline)
+{
+       struct ata_eh_context *ehc = &link->eh_context;
+       const unsigned long *timing = sata_ehc_deb_timing(ehc);
+       int rc;
+
+       /* force HRST? */
+       if (link->flags & ATA_LFLAG_NO_SRST)
+               ehc->i.action |= ATA_EH_HARDRESET;
+
+       /* handle link resume */
+       if ((ehc->i.flags & ATA_EHI_RESUME_LINK) &&
+           (link->flags & ATA_LFLAG_HRST_TO_RESUME))
+               ehc->i.action |= ATA_EH_HARDRESET;
+
+       /* if we're about to do hardreset, nothing more to do */
+       if (ehc->i.action & ATA_EH_HARDRESET)
+               return 0;
+
+       /* resume link */
+       rc = sata_link_resume(link, timing, deadline);
+       if (rc) {
+               /* phy resume failed */
+               ata_link_printk(link, KERN_WARNING, "failed to resume link "
+                               "for reset (errno=%d)\n", rc);
+               return rc;
+       }
+
+       /* clear SError bits including .X which blocks the port when set */
+       rc = sata_scr_write(link, SCR_ERROR, 0xffffffff);
+       if (rc) {
+               ata_link_printk(link, KERN_ERR,
+                               "failed to clear SError (errno=%d)\n", rc);
+               return rc;
+       }
+
+       return 0;
+}
+
+/**
+ *     sata_pmp_std_hardreset - standard hardreset method for PMP link
+ *     @link: link to be reset
+ *     @class: resulting class of attached device
+ *     @deadline: deadline jiffies for the operation
+ *
+ *     Hardreset PMP port @link.  Note that this function doesn't
+ *     wait for BSY clearance.  There simply isn't a generic way to
+ *     wait the event.  Instead, this function return -EAGAIN thus
+ *     telling libata-EH to followup with softreset.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep)
+ *
+ *     RETURNS:
+ *     0 on success, -errno otherwise.
+ */
+int sata_pmp_std_hardreset(struct ata_link *link, unsigned int *class,
+                          unsigned long deadline)
+{
+       const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
+       u32 tmp;
+       int rc;
+
+       DPRINTK("ENTER\n");
+
+       /* do hardreset */
+       rc = sata_link_hardreset(link, timing, deadline);
+       if (rc) {
+               ata_link_printk(link, KERN_ERR,
+                               "COMRESET failed (errno=%d)\n", rc);
+               goto out;
+       }
+
+       /* clear SError bits including .X which blocks the port when set */
+       rc = sata_scr_write(link, SCR_ERROR, 0xffffffff);
+       if (rc) {
+               ata_link_printk(link, KERN_ERR, "failed to clear SError "
+                               "during hardreset (errno=%d)\n", rc);
+               goto out;
+       }
+
+       /* if device is present, follow up with srst to wait for !BSY */
+       if (ata_link_online(link))
+               rc = -EAGAIN;
+ out:
+       /* if SCR isn't accessible, we need to reset the PMP */
+       if (rc && rc != -EAGAIN && sata_scr_read(link, SCR_STATUS, &tmp))
+               rc = -ERESTART;
+
+       DPRINTK("EXIT, rc=%d\n", rc);
+       return rc;
+}
+
+/**
+ *     ata_std_postreset - standard postreset method for PMP link
+ *     @link: the target ata_link
+ *     @classes: classes of attached devices
+ *
+ *     This function is invoked after a successful reset.  Note that
+ *     the device might have been reset more than once using
+ *     different reset methods before postreset is invoked.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep)
+ */
+void sata_pmp_std_postreset(struct ata_link *link, unsigned int *class)
+{
+       u32 serror;
+
+       DPRINTK("ENTER\n");
+
+       /* clear SError */
+       if (sata_scr_read(link, SCR_ERROR, &serror) == 0)
+               sata_scr_write(link, SCR_ERROR, serror);
+
+       /* print link status */
+       sata_print_link_status(link);
+
+       DPRINTK("EXIT\n");
+}
+
+/**
+ *     sata_pmp_read_gscr - read GSCR block of SATA PMP
+ *     @dev: PMP device
+ *     @gscr: buffer to read GSCR block into
+ *
+ *     Read selected PMP GSCRs from the PMP at @dev.  This will serve
+ *     as configuration and identification info for the PMP.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep).
+ *
+ *     RETURNS:
+ *     0 on success, -errno on failure.
+ */
+static int sata_pmp_read_gscr(struct ata_device *dev, u32 *gscr)
+{
+       static const int gscr_to_read[] = { 0, 1, 2, 32, 33, 64, 96 };
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(gscr_to_read); i++) {
+               int reg = gscr_to_read[i];
+               unsigned int err_mask;
+
+               err_mask = sata_pmp_read(dev->link, reg, &gscr[reg]);
+               if (err_mask) {
+                       ata_dev_printk(dev, KERN_ERR, "failed to read PMP "
+                               "GSCR[%d] (Emask=0x%x)\n", reg, err_mask);
+                       return -EIO;
+               }
+       }
+
+       return 0;
+}
+
+static const char *sata_pmp_spec_rev_str(const u32 *gscr)
+{
+       u32 rev = gscr[SATA_PMP_GSCR_REV];
+
+       if (rev & (1 << 2))
+               return "1.1";
+       if (rev & (1 << 1))
+               return "1.0";
+       return "<unknown>";
+}
+
+static int sata_pmp_configure(struct ata_device *dev, int print_info)
+{
+       struct ata_port *ap = dev->link->ap;
+       u32 *gscr = dev->gscr;
+       unsigned int err_mask = 0;
+       const char *reason;
+       int nr_ports, rc;
+
+       nr_ports = sata_pmp_gscr_ports(gscr);
+
+       if (nr_ports <= 0 || nr_ports > SATA_PMP_MAX_PORTS) {
+               rc = -EINVAL;
+               reason = "invalid nr_ports";
+               goto fail;
+       }
+
+       if ((ap->flags & ATA_FLAG_AN) &&
+           (gscr[SATA_PMP_GSCR_FEAT] & SATA_PMP_FEAT_NOTIFY))
+               dev->flags |= ATA_DFLAG_AN;
+
+       /* monitor SERR_PHYRDY_CHG on fan-out ports */
+       err_mask = sata_pmp_write(dev->link, SATA_PMP_GSCR_ERROR_EN,
+                                 SERR_PHYRDY_CHG);
+       if (err_mask) {
+               rc = -EIO;
+               reason = "failed to write GSCR_ERROR_EN";
+               goto fail;
+       }
+
+       /* turn off notification till fan-out ports are reset and configured */
+       if (gscr[SATA_PMP_GSCR_FEAT_EN] & SATA_PMP_FEAT_NOTIFY) {
+               gscr[SATA_PMP_GSCR_FEAT_EN] &= ~SATA_PMP_FEAT_NOTIFY;
+
+               err_mask = sata_pmp_write(dev->link, SATA_PMP_GSCR_FEAT_EN,
+                                         gscr[SATA_PMP_GSCR_FEAT_EN]);
+               if (err_mask) {
+                       rc = -EIO;
+                       reason = "failed to write GSCR_FEAT_EN";
+                       goto fail;
+               }
+       }
+
+       if (print_info) {
+               ata_dev_printk(dev, KERN_INFO, "Port Multiplier %s, "
+                              "0x%04x:0x%04x r%d, %d ports, feat 0x%x/0x%x\n",
+                              sata_pmp_spec_rev_str(gscr),
+                              sata_pmp_gscr_vendor(gscr),
+                              sata_pmp_gscr_devid(gscr),
+                              sata_pmp_gscr_rev(gscr),
+                              nr_ports, gscr[SATA_PMP_GSCR_FEAT_EN],
+                              gscr[SATA_PMP_GSCR_FEAT]);
+
+               if (!(dev->flags & ATA_DFLAG_AN))
+                       ata_dev_printk(dev, KERN_INFO,
+                               "Asynchronous notification not supported, "
+                               "hotplug won't\n         work on fan-out "
+                               "ports. Use warm-plug instead.\n");
+       }
+
+       return 0;
+
+ fail:
+       ata_dev_printk(dev, KERN_ERR,
+                      "failed to configure Port Multiplier (%s, Emask=0x%x)\n",
+                      reason, err_mask);
+       return rc;
+}
+
+static int sata_pmp_init_links(struct ata_port *ap, int nr_ports)
+{
+       struct ata_link *pmp_link = ap->pmp_link;
+       int i;
+
+       if (!pmp_link) {
+               pmp_link = kzalloc(sizeof(pmp_link[0]) * SATA_PMP_MAX_PORTS,
+                                  GFP_NOIO);
+               if (!pmp_link)
+                       return -ENOMEM;
+
+               for (i = 0; i < SATA_PMP_MAX_PORTS; i++)
+                       ata_link_init(ap, &pmp_link[i], i);
+
+               ap->pmp_link = pmp_link;
+       }
+
+       for (i = 0; i < nr_ports; i++) {
+               struct ata_link *link = &pmp_link[i];
+               struct ata_eh_context *ehc = &link->eh_context;
+
+               link->flags = 0;
+               ehc->i.probe_mask |= 1;
+               ehc->i.action |= ATA_EH_SOFTRESET;
+               ehc->i.flags |= ATA_EHI_RESUME_LINK;
+       }
+
+       return 0;
+}
+
+static void sata_pmp_quirks(struct ata_port *ap)
+{
+       u32 *gscr = ap->link.device->gscr;
+       u16 vendor = sata_pmp_gscr_vendor(gscr);
+       u16 devid = sata_pmp_gscr_devid(gscr);
+       struct ata_link *link;
+
+       if (vendor == 0x1095 && devid == 0x3726) {
+               /* sil3726 quirks */
+               ata_port_for_each_link(link, ap) {
+                       /* SError.N need a kick in the ass to get working */
+                       link->flags |= ATA_LFLAG_HRST_TO_RESUME;
+
+                       /* class code report is unreliable */
+                       if (link->pmp < 5)
+                               link->flags |= ATA_LFLAG_ASSUME_ATA;
+
+                       /* port 5 is for SEMB device and it doesn't like SRST */
+                       if (link->pmp == 5)
+                               link->flags |= ATA_LFLAG_NO_SRST |
+                                              ATA_LFLAG_ASSUME_SEMB;
+               }
+       } else if (vendor == 0x1095 && devid == 0x4723) {
+               /* sil4723 quirks */
+               ata_port_for_each_link(link, ap) {
+                       /* SError.N need a kick in the ass to get working */
+                       link->flags |= ATA_LFLAG_HRST_TO_RESUME;
+
+                       /* class code report is unreliable */
+                       if (link->pmp < 2)
+                               link->flags |= ATA_LFLAG_ASSUME_ATA;
+
+                       /* the config device at port 2 locks up on SRST */
+                       if (link->pmp == 2)
+                               link->flags |= ATA_LFLAG_NO_SRST |
+                                              ATA_LFLAG_ASSUME_ATA;
+               }
+       } else if (vendor == 0x1095 && devid == 0x4726) {
+               /* sil4726 quirks */
+               ata_port_for_each_link(link, ap) {
+                       /* SError.N need a kick in the ass to get working */
+                       link->flags |= ATA_LFLAG_HRST_TO_RESUME;
+
+                       /* class code report is unreliable */
+                       if (link->pmp < 5)
+                               link->flags |= ATA_LFLAG_ASSUME_ATA;
+
+                       /* The config device, which can be either at
+                        * port 0 or 5, locks up on SRST.
+                        */
+                       if (link->pmp == 0 || link->pmp == 5)
+                               link->flags |= ATA_LFLAG_NO_SRST |
+                                              ATA_LFLAG_ASSUME_ATA;
+
+                       /* Port 6 is for SEMB device which doesn't
+                        * like SRST either.
+                        */
+                       if (link->pmp == 6)
+                               link->flags |= ATA_LFLAG_NO_SRST |
+                                              ATA_LFLAG_ASSUME_SEMB;
+               }
+       } else if (vendor == 0x1095 && (devid == 0x5723 || devid == 0x5733 ||
+                                       devid == 0x5734 || devid == 0x5744)) {
+               /* sil5723/5744 quirks */
+
+               /* sil5723/5744 has either two or three downstream
+                * ports depending on operation mode.  The last port
+                * is empty if any actual IO device is available or
+                * occupied by a pseudo configuration device
+                * otherwise.  Don't try hard to recover it.
+                */
+               ap->pmp_link[ap->nr_pmp_links - 1].flags |= ATA_LFLAG_NO_RETRY;
+       } else if (vendor == 0x11ab && devid == 0x4140) {
+               /* Marvell 88SM4140 quirks.  Fan-out ports require PHY
+                * reset to work; other than that, it behaves very
+                * nicely.
+                */
+               ata_port_for_each_link(link, ap)
+                       link->flags |= ATA_LFLAG_HRST_TO_RESUME;
+       }
+}
+
+/**
+ *     sata_pmp_attach - attach a SATA PMP device
+ *     @dev: SATA PMP device to attach
+ *
+ *     Configure and attach SATA PMP device @dev.  This function is
+ *     also responsible for allocating and initializing PMP links.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep).
+ *
+ *     RETURNS:
+ *     0 on success, -errno on failure.
+ */
+int sata_pmp_attach(struct ata_device *dev)
+{
+       struct ata_link *link = dev->link;
+       struct ata_port *ap = link->ap;
+       unsigned long flags;
+       struct ata_link *tlink;
+       int rc;
+
+       /* is it hanging off the right place? */
+       if (!(ap->flags & ATA_FLAG_PMP)) {
+               ata_dev_printk(dev, KERN_ERR,
+                              "host does not support Port Multiplier\n");
+               return -EINVAL;
+       }
+
+       if (!ata_is_host_link(link)) {
+               ata_dev_printk(dev, KERN_ERR,
+                              "Port Multipliers cannot be nested\n");
+               return -EINVAL;
+       }
+
+       if (dev->devno) {
+               ata_dev_printk(dev, KERN_ERR,
+                              "Port Multiplier must be the first device\n");
+               return -EINVAL;
+       }
+
+       WARN_ON(link->pmp != 0);
+       link->pmp = SATA_PMP_CTRL_PORT;
+
+       /* read GSCR block */
+       rc = sata_pmp_read_gscr(dev, dev->gscr);
+       if (rc)
+               goto fail;
+
+       /* config PMP */
+       rc = sata_pmp_configure(dev, 1);
+       if (rc)
+               goto fail;
+
+       rc = sata_pmp_init_links(ap, sata_pmp_gscr_ports(dev->gscr));
+       if (rc) {
+               ata_dev_printk(dev, KERN_INFO,
+                              "failed to initialize PMP links\n");
+               goto fail;
+       }
+
+       /* attach it */
+       spin_lock_irqsave(ap->lock, flags);
+       WARN_ON(ap->nr_pmp_links);
+       ap->nr_pmp_links = sata_pmp_gscr_ports(dev->gscr);
+       spin_unlock_irqrestore(ap->lock, flags);
+
+       sata_pmp_quirks(ap);
+
+       if (ap->ops->pmp_attach)
+               ap->ops->pmp_attach(ap);
+
+       ata_port_for_each_link(tlink, ap)
+               sata_link_init_spd(tlink);
+
+       ata_acpi_associate_sata_port(ap);
+
+       return 0;
+
+ fail:
+       link->pmp = 0;
+       return rc;
+}
+
+/**
+ *     sata_pmp_detach - detach a SATA PMP device
+ *     @dev: SATA PMP device to detach
+ *
+ *     Detach SATA PMP device @dev.  This function is also
+ *     responsible for deconfiguring PMP links.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep).
+ */
+static void sata_pmp_detach(struct ata_device *dev)
+{
+       struct ata_link *link = dev->link;
+       struct ata_port *ap = link->ap;
+       struct ata_link *tlink;
+       unsigned long flags;
+
+       ata_dev_printk(dev, KERN_INFO, "Port Multiplier detaching\n");
+
+       WARN_ON(!ata_is_host_link(link) || dev->devno ||
+               link->pmp != SATA_PMP_CTRL_PORT);
+
+       if (ap->ops->pmp_detach)
+               ap->ops->pmp_detach(ap);
+
+       ata_port_for_each_link(tlink, ap)
+               ata_eh_detach_dev(tlink->device);
+
+       spin_lock_irqsave(ap->lock, flags);
+       ap->nr_pmp_links = 0;
+       link->pmp = 0;
+       spin_unlock_irqrestore(ap->lock, flags);
+
+       ata_acpi_associate_sata_port(ap);
+}
+
+/**
+ *     sata_pmp_same_pmp - does new GSCR matches the configured PMP?
+ *     @dev: PMP device to compare against
+ *     @new_gscr: GSCR block of the new device
+ *
+ *     Compare @new_gscr against @dev and determine whether @dev is
+ *     the PMP described by @new_gscr.
+ *
+ *     LOCKING:
+ *     None.
+ *
+ *     RETURNS:
+ *     1 if @dev matches @new_gscr, 0 otherwise.
+ */
+static int sata_pmp_same_pmp(struct ata_device *dev, const u32 *new_gscr)
+{
+       const u32 *old_gscr = dev->gscr;
+       u16 old_vendor, new_vendor, old_devid, new_devid;
+       int old_nr_ports, new_nr_ports;
+
+       old_vendor = sata_pmp_gscr_vendor(old_gscr);
+       new_vendor = sata_pmp_gscr_vendor(new_gscr);
+       old_devid = sata_pmp_gscr_devid(old_gscr);
+       new_devid = sata_pmp_gscr_devid(new_gscr);
+       old_nr_ports = sata_pmp_gscr_ports(old_gscr);
+       new_nr_ports = sata_pmp_gscr_ports(new_gscr);
+
+       if (old_vendor != new_vendor) {
+               ata_dev_printk(dev, KERN_INFO, "Port Multiplier "
+                              "vendor mismatch '0x%x' != '0x%x'\n",
+                              old_vendor, new_vendor);
+               return 0;
+       }
+
+       if (old_devid != new_devid) {
+               ata_dev_printk(dev, KERN_INFO, "Port Multiplier "
+                              "device ID mismatch '0x%x' != '0x%x'\n",
+                              old_devid, new_devid);
+               return 0;
+       }
+
+       if (old_nr_ports != new_nr_ports) {
+               ata_dev_printk(dev, KERN_INFO, "Port Multiplier "
+                              "nr_ports mismatch '0x%x' != '0x%x'\n",
+                              old_nr_ports, new_nr_ports);
+               return 0;
+       }
+
+       return 1;
+}
+
+/**
+ *     sata_pmp_revalidate - revalidate SATA PMP
+ *     @dev: PMP device to revalidate
+ *     @new_class: new class code
+ *
+ *     Re-read GSCR block and make sure @dev is still attached to the
+ *     port and properly configured.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep).
+ *
+ *     RETURNS:
+ *     0 on success, -errno otherwise.
+ */
+static int sata_pmp_revalidate(struct ata_device *dev, unsigned int new_class)
+{
+       struct ata_link *link = dev->link;
+       struct ata_port *ap = link->ap;
+       u32 *gscr = (void *)ap->sector_buf;
+       int rc;
+
+       DPRINTK("ENTER\n");
+
+       ata_eh_about_to_do(link, NULL, ATA_EH_REVALIDATE);
+
+       if (!ata_dev_enabled(dev)) {
+               rc = -ENODEV;
+               goto fail;
+       }
+
+       /* wrong class? */
+       if (ata_class_enabled(new_class) && new_class != ATA_DEV_PMP) {
+               rc = -ENODEV;
+               goto fail;
+       }
+
+       /* read GSCR */
+       rc = sata_pmp_read_gscr(dev, gscr);
+       if (rc)
+               goto fail;
+
+       /* is the pmp still there? */
+       if (!sata_pmp_same_pmp(dev, gscr)) {
+               rc = -ENODEV;
+               goto fail;
+       }
+
+       memcpy(dev->gscr, gscr, sizeof(gscr[0]) * SATA_PMP_GSCR_DWORDS);
+
+       rc = sata_pmp_configure(dev, 0);
+       if (rc)
+               goto fail;
+
+       ata_eh_done(link, NULL, ATA_EH_REVALIDATE);
+
+       DPRINTK("EXIT, rc=0\n");
+       return 0;
+
+ fail:
+       ata_dev_printk(dev, KERN_ERR,
+                      "PMP revalidation failed (errno=%d)\n", rc);
+       DPRINTK("EXIT, rc=%d\n", rc);
+       return rc;
+}
+
+/**
+ *     sata_pmp_revalidate_quick - revalidate SATA PMP quickly
+ *     @dev: PMP device to revalidate
+ *
+ *     Make sure the attached PMP is accessible.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep).
+ *
+ *     RETURNS:
+ *     0 on success, -errno otherwise.
+ */
+static int sata_pmp_revalidate_quick(struct ata_device *dev)
+{
+       unsigned int err_mask;
+       u32 prod_id;
+
+       err_mask = sata_pmp_read(dev->link, SATA_PMP_GSCR_PROD_ID, &prod_id);
+       if (err_mask) {
+               ata_dev_printk(dev, KERN_ERR, "failed to read PMP product ID "
+                              "(Emask=0x%x)\n", err_mask);
+               return -EIO;
+       }
+
+       if (prod_id != dev->gscr[SATA_PMP_GSCR_PROD_ID]) {
+               ata_dev_printk(dev, KERN_ERR, "PMP product ID mismatch\n");
+               /* something weird is going on, request full PMP recovery */
+               return -EIO;
+       }
+
+       return 0;
+}
+
+/**
+ *     sata_pmp_eh_recover_pmp - recover PMP
+ *     @ap: ATA port PMP is attached to
+ *     @prereset: prereset method (can be NULL)
+ *     @softreset: softreset method
+ *     @hardreset: hardreset method
+ *     @postreset: postreset method (can be NULL)
+ *
+ *     Recover PMP attached to @ap.  Recovery procedure is somewhat
+ *     similar to that of ata_eh_recover() except that reset should
+ *     always be performed in hard->soft sequence and recovery
+ *     failure results in PMP detachment.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep).
+ *
+ *     RETURNS:
+ *     0 on success, -errno on failure.
+ */
+static int sata_pmp_eh_recover_pmp(struct ata_port *ap,
+               ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
+               ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
+{
+       struct ata_link *link = &ap->link;
+       struct ata_eh_context *ehc = &link->eh_context;
+       struct ata_device *dev = link->device;
+       int tries = ATA_EH_PMP_TRIES;
+       int detach = 0, rc = 0;
+       int reval_failed = 0;
+
+       DPRINTK("ENTER\n");
+
+       if (dev->flags & ATA_DFLAG_DETACH) {
+               detach = 1;
+               goto fail;
+       }
+
+ retry:
+       ehc->classes[0] = ATA_DEV_UNKNOWN;
+
+       if (ehc->i.action & ATA_EH_RESET_MASK) {
+               struct ata_link *tlink;
+
+               ata_eh_freeze_port(ap);
+
+               /* reset */
+               ehc->i.action = ATA_EH_HARDRESET;
+               rc = ata_eh_reset(link, 0, prereset, softreset, hardreset,
+                                 postreset);
+               if (rc) {
+                       ata_link_printk(link, KERN_ERR,
+                                       "failed to reset PMP, giving up\n");
+                       goto fail;
+               }
+
+               ata_eh_thaw_port(ap);
+
+               /* PMP is reset, SErrors cannot be trusted, scan all */
+               ata_port_for_each_link(tlink, ap)
+                       ata_ehi_schedule_probe(&tlink->eh_context.i);
+       }
+
+       /* If revalidation is requested, revalidate and reconfigure;
+        * otherwise, do quick revalidation.
+        */
+       if (ehc->i.action & ATA_EH_REVALIDATE)
+               rc = sata_pmp_revalidate(dev, ehc->classes[0]);
+       else
+               rc = sata_pmp_revalidate_quick(dev);
+
+       if (rc) {
+               tries--;
+
+               if (rc == -ENODEV) {
+                       ehc->i.probe_mask |= 1;
+                       detach = 1;
+                       /* give it just two more chances */
+                       tries = min(tries, 2);
+               }
+
+               if (tries) {
+                       int sleep = ehc->i.flags & ATA_EHI_DID_RESET;
+
+                       /* consecutive revalidation failures? speed down */
+                       if (reval_failed)
+                               sata_down_spd_limit(link);
+                       else
+                               reval_failed = 1;
+
+                       ata_dev_printk(dev, KERN_WARNING,
+                                      "retrying hardreset%s\n",
+                                      sleep ? " in 5 secs" : "");
+                       if (sleep)
+                               ssleep(5);
+                       ehc->i.action |= ATA_EH_HARDRESET;
+                       goto retry;
+               } else {
+                       ata_dev_printk(dev, KERN_ERR, "failed to recover PMP "
+                                      "after %d tries, giving up\n",
+                                      ATA_EH_PMP_TRIES);
+                       goto fail;
+               }
+       }
+
+       /* okay, PMP resurrected */
+       ehc->i.flags = 0;
+
+       DPRINTK("EXIT, rc=0\n");
+       return 0;
+
+ fail:
+       sata_pmp_detach(dev);
+       if (detach)
+               ata_eh_detach_dev(dev);
+       else
+               ata_dev_disable(dev);
+
+       DPRINTK("EXIT, rc=%d\n", rc);
+       return rc;
+}
+
+static int sata_pmp_eh_handle_disabled_links(struct ata_port *ap)
+{
+       struct ata_link *link;
+       unsigned long flags;
+       int rc;
+
+       spin_lock_irqsave(ap->lock, flags);
+
+       ata_port_for_each_link(link, ap) {
+               if (!(link->flags & ATA_LFLAG_DISABLED))
+                       continue;
+
+               spin_unlock_irqrestore(ap->lock, flags);
+
+               /* Some PMPs require hardreset sequence to get
+                * SError.N working.
+                */
+               if ((link->flags & ATA_LFLAG_HRST_TO_RESUME) &&
+                   (link->eh_context.i.flags & ATA_EHI_RESUME_LINK))
+                       sata_link_hardreset(link, sata_deb_timing_normal,
+                                           jiffies + ATA_TMOUT_INTERNAL_QUICK);
+
+               /* unconditionally clear SError.N */
+               rc = sata_scr_write(link, SCR_ERROR, SERR_PHYRDY_CHG);
+               if (rc) {
+                       ata_link_printk(link, KERN_ERR, "failed to clear "
+                                       "SError.N (errno=%d)\n", rc);
+                       return rc;
+               }
+
+               spin_lock_irqsave(ap->lock, flags);
+       }
+
+       spin_unlock_irqrestore(ap->lock, flags);
+
+       return 0;
+}
+
+static int sata_pmp_handle_link_fail(struct ata_link *link, int *link_tries)
+{
+       struct ata_port *ap = link->ap;
+       unsigned long flags;
+
+       if (link_tries[link->pmp] && --link_tries[link->pmp])
+               return 1;
+
+       /* disable this link */
+       if (!(link->flags & ATA_LFLAG_DISABLED)) {
+               ata_link_printk(link, KERN_WARNING,
+                       "failed to recover link after %d tries, disabling\n",
+                       ATA_EH_PMP_LINK_TRIES);
+
+               spin_lock_irqsave(ap->lock, flags);
+               link->flags |= ATA_LFLAG_DISABLED;
+               spin_unlock_irqrestore(ap->lock, flags);
+       }
+
+       ata_dev_disable(link->device);
+       link->eh_context.i.action = 0;
+
+       return 0;
+}
+
+/**
+ *     sata_pmp_eh_recover - recover PMP-enabled port
+ *     @ap: ATA port to recover
+ *     @prereset: prereset method (can be NULL)
+ *     @softreset: softreset method
+ *     @hardreset: hardreset method
+ *     @postreset: postreset method (can be NULL)
+ *     @pmp_prereset: PMP prereset method (can be NULL)
+ *     @pmp_softreset: PMP softreset method (can be NULL)
+ *     @pmp_hardreset: PMP hardreset method (can be NULL)
+ *     @pmp_postreset: PMP postreset method (can be NULL)
+ *
+ *     Drive EH recovery operation for PMP enabled port @ap.  This
+ *     function recovers host and PMP ports with proper retrials and
+ *     fallbacks.  Actual recovery operations are performed using
+ *     ata_eh_recover() and sata_pmp_eh_recover_pmp().
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep).
+ *
+ *     RETURNS:
+ *     0 on success, -errno on failure.
+ */
+static int sata_pmp_eh_recover(struct ata_port *ap,
+               ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
+               ata_reset_fn_t hardreset, ata_postreset_fn_t postreset,
+               ata_prereset_fn_t pmp_prereset, ata_reset_fn_t pmp_softreset,
+               ata_reset_fn_t pmp_hardreset, ata_postreset_fn_t pmp_postreset)
+{
+       int pmp_tries, link_tries[SATA_PMP_MAX_PORTS];
+       struct ata_link *pmp_link = &ap->link;
+       struct ata_device *pmp_dev = pmp_link->device;
+       struct ata_eh_context *pmp_ehc = &pmp_link->eh_context;
+       struct ata_link *link;
+       struct ata_device *dev;
+       unsigned int err_mask;
+       u32 gscr_error, sntf;
+       int cnt, rc;
+
+       pmp_tries = ATA_EH_PMP_TRIES;
+       ata_port_for_each_link(link, ap)
+               link_tries[link->pmp] = ATA_EH_PMP_LINK_TRIES;
+
+ retry:
+       /* PMP attached? */
+       if (!ap->nr_pmp_links) {
+               rc = ata_eh_recover(ap, prereset, softreset, hardreset,
+                                   postreset, NULL);
+               if (rc) {
+                       ata_link_for_each_dev(dev, &ap->link)
+                               ata_dev_disable(dev);
+                       return rc;
+               }
+
+               if (pmp_dev->class != ATA_DEV_PMP)
+                       return 0;
+
+               /* new PMP online */
+               ata_port_for_each_link(link, ap)
+                       link_tries[link->pmp] = ATA_EH_PMP_LINK_TRIES;
+
+               /* fall through */
+       }
+
+       /* recover pmp */
+       rc = sata_pmp_eh_recover_pmp(ap, prereset, softreset, hardreset,
+                                    postreset);
+       if (rc)
+               goto pmp_fail;
+
+       /* handle disabled links */
+       rc = sata_pmp_eh_handle_disabled_links(ap);
+       if (rc)
+               goto pmp_fail;
+
+       /* recover links */
+       rc = ata_eh_recover(ap, pmp_prereset, pmp_softreset, pmp_hardreset,
+                           pmp_postreset, &link);
+       if (rc)
+               goto link_fail;
+
+       /* Connection status might have changed while resetting other
+        * links, check SATA_PMP_GSCR_ERROR before returning.
+        */
+
+       /* clear SNotification */
+       rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf);
+       if (rc == 0)
+               sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf);
+
+       /* enable notification */
+       if (pmp_dev->flags & ATA_DFLAG_AN) {
+               pmp_dev->gscr[SATA_PMP_GSCR_FEAT_EN] |= SATA_PMP_FEAT_NOTIFY;
+
+               err_mask = sata_pmp_write(pmp_dev->link, SATA_PMP_GSCR_FEAT_EN,
+                                         pmp_dev->gscr[SATA_PMP_GSCR_FEAT_EN]);
+               if (err_mask) {
+                       ata_dev_printk(pmp_dev, KERN_ERR, "failed to write "
+                                      "PMP_FEAT_EN (Emask=0x%x)\n", err_mask);
+                       rc = -EIO;
+                       goto pmp_fail;
+               }
+       }
+
+       /* check GSCR_ERROR */
+       err_mask = sata_pmp_read(pmp_link, SATA_PMP_GSCR_ERROR, &gscr_error);
+       if (err_mask) {
+               ata_dev_printk(pmp_dev, KERN_ERR, "failed to read "
+                              "PMP_GSCR_ERROR (Emask=0x%x)\n", err_mask);
+               rc = -EIO;
+               goto pmp_fail;
+       }
+
+       cnt = 0;
+       ata_port_for_each_link(link, ap) {
+               if (!(gscr_error & (1 << link->pmp)))
+                       continue;
+
+               if (sata_pmp_handle_link_fail(link, link_tries)) {
+                       ata_ehi_hotplugged(&link->eh_context.i);
+                       cnt++;
+               } else {
+                       ata_link_printk(link, KERN_WARNING,
+                               "PHY status changed but maxed out on retries, "
+                               "giving up\n");
+                       ata_link_printk(link, KERN_WARNING,
+                               "Manully issue scan to resume this link\n");
+               }
+       }
+
+       if (cnt) {
+               ata_port_printk(ap, KERN_INFO, "PMP SError.N set for some "
+                               "ports, repeating recovery\n");
+               goto retry;
+       }
+
+       return 0;
+
+ link_fail:
+       if (sata_pmp_handle_link_fail(link, link_tries)) {
+               pmp_ehc->i.action |= ATA_EH_HARDRESET;
+               goto retry;
+       }
+
+       /* fall through */
+ pmp_fail:
+       /* Control always ends up here after detaching PMP.  Shut up
+        * and return if we're unloading.
+        */
+       if (ap->pflags & ATA_PFLAG_UNLOADING)
+               return rc;
+
+       if (!ap->nr_pmp_links)
+               goto retry;
+
+       if (--pmp_tries) {
+               ata_port_printk(ap, KERN_WARNING,
+                               "failed to recover PMP, retrying in 5 secs\n");
+               pmp_ehc->i.action |= ATA_EH_HARDRESET;
+               ssleep(5);
+               goto retry;
+       }
+
+       ata_port_printk(ap, KERN_ERR,
+                       "failed to recover PMP after %d tries, giving up\n",
+                       ATA_EH_PMP_TRIES);
+       sata_pmp_detach(pmp_dev);
+       ata_dev_disable(pmp_dev);
+
+       return rc;
+}
+
+/**
+ *     sata_pmp_do_eh - do standard error handling for PMP-enabled host
+ *     @ap: host port to handle error for
+ *     @prereset: prereset method (can be NULL)
+ *     @softreset: softreset method
+ *     @hardreset: hardreset method
+ *     @postreset: postreset method (can be NULL)
+ *     @pmp_prereset: PMP prereset method (can be NULL)
+ *     @pmp_softreset: PMP softreset method (can be NULL)
+ *     @pmp_hardreset: PMP hardreset method (can be NULL)
+ *     @pmp_postreset: PMP postreset method (can be NULL)
+ *
+ *     Perform standard error handling sequence for PMP-enabled host
+ *     @ap.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep).
+ */
+void sata_pmp_do_eh(struct ata_port *ap,
+               ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
+               ata_reset_fn_t hardreset, ata_postreset_fn_t postreset,
+               ata_prereset_fn_t pmp_prereset, ata_reset_fn_t pmp_softreset,
+               ata_reset_fn_t pmp_hardreset, ata_postreset_fn_t pmp_postreset)
+{
+       ata_eh_autopsy(ap);
+       ata_eh_report(ap);
+       sata_pmp_eh_recover(ap, prereset, softreset, hardreset, postreset,
+                           pmp_prereset, pmp_softreset, pmp_hardreset,
+                           pmp_postreset);
+       ata_eh_finish(ap);
+}
index e83647651b31f1e12368ec53deaef317cfb33c09..ea53e6a570b428e88cef5018c1318923c2d75667 100644 (file)
@@ -71,11 +71,10 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
 #define ALL_SUB_MPAGES 0xff
 
 
-static const u8 def_rw_recovery_mpage[] = {
+static const u8 def_rw_recovery_mpage[RW_RECOVERY_MPAGE_LEN] = {
        RW_RECOVERY_MPAGE,
        RW_RECOVERY_MPAGE_LEN - 2,
-       (1 << 7) |      /* AWRE, sat-r06 say it shall be 0 */
-           (1 << 6),   /* ARRE (auto read reallocation) */
+       (1 << 7),       /* AWRE */
        0,              /* read retry count */
        0, 0, 0, 0,
        0,              /* write retry count */
@@ -450,13 +449,8 @@ static struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev,
                qc->scsicmd = cmd;
                qc->scsidone = done;
 
-               if (cmd->use_sg) {
-                       qc->__sg = (struct scatterlist *) cmd->request_buffer;
-                       qc->n_elem = cmd->use_sg;
-               } else if (cmd->request_bufflen) {
-                       qc->__sg = &qc->sgent;
-                       qc->n_elem = 1;
-               }
+               qc->__sg = scsi_sglist(cmd);
+               qc->n_elem = scsi_sg_count(cmd);
        } else {
                cmd->result = (DID_OK << 16) | (QUEUE_FULL << 1);
                done(cmd);
@@ -755,6 +749,13 @@ static void ata_scsi_sdev_config(struct scsi_device *sdev)
 {
        sdev->use_10_for_rw = 1;
        sdev->use_10_for_ms = 1;
+
+       /* Schedule policy is determined by ->qc_defer() callback and
+        * it needs to see every deferred qc.  Set dev_blocked to 1 to
+        * prevent SCSI midlayer from automatically deferring
+        * requests.
+        */
+       sdev->max_device_blocked = 1;
 }
 
 static void ata_scsi_dev_config(struct scsi_device *sdev,
@@ -943,6 +944,13 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc)
                goto invalid_fld;       /* LOEJ bit set not supported */
        if (((cdb[4] >> 4) & 0xf) != 0)
                goto invalid_fld;       /* power conditions not supported */
+
+       if (qc->dev->horkage & ATA_HORKAGE_SKIP_PM) {
+               /* the device lacks PM support, finish without doing anything */
+               scmd->result = SAM_STAT_GOOD;
+               return 1;
+       }
+
        if (cdb[4] & 0x1) {
                tf->nsect = 1;  /* 1 sector, lba=0 */
 
@@ -1368,14 +1376,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->eh_info.action |= ATA_EH_REVALIDATE;
+                               ap->link.eh_info.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->eh_info.action |= ATA_EH_REVALIDATE;
+                       ap->link.eh_info.action |= ATA_EH_REVALIDATE;
                        ata_port_schedule_eh(ap);
                        break;
                }
@@ -1421,37 +1429,6 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
        ata_qc_free(qc);
 }
 
-/**
- *     ata_scmd_need_defer - Check whether we need to defer scmd
- *     @dev: ATA device to which the command is addressed
- *     @is_io: Is the command IO (and thus possibly NCQ)?
- *
- *     NCQ and non-NCQ commands cannot run together.  As upper layer
- *     only knows the queue depth, we are responsible for maintaining
- *     exclusion.  This function checks whether a new command can be
- *     issued to @dev.
- *
- *     LOCKING:
- *     spin_lock_irqsave(host lock)
- *
- *     RETURNS:
- *     1 if deferring is needed, 0 otherwise.
- */
-static int ata_scmd_need_defer(struct ata_device *dev, int is_io)
-{
-       struct ata_port *ap = dev->ap;
-       int is_ncq = is_io && ata_ncq_enabled(dev);
-
-       if (is_ncq) {
-               if (!ata_tag_valid(ap->active_tag))
-                       return 0;
-       } else {
-               if (!ata_tag_valid(ap->active_tag) && !ap->sactive)
-                       return 0;
-       }
-       return 1;
-}
-
 /**
  *     ata_scsi_translate - Translate then issue SCSI command to ATA device
  *     @dev: ATA device to which the command is addressed
@@ -1483,14 +1460,12 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,
                              void (*done)(struct scsi_cmnd *),
                              ata_xlat_func_t xlat_func)
 {
+       struct ata_port *ap = dev->link->ap;
        struct ata_queued_cmd *qc;
-       int is_io = xlat_func == ata_scsi_rw_xlat;
+       int rc;
 
        VPRINTK("ENTER\n");
 
-       if (unlikely(ata_scmd_need_defer(dev, is_io)))
-               goto defer;
-
        qc = ata_scsi_qc_new(dev, cmd, done);
        if (!qc)
                goto err_mem;
@@ -1498,17 +1473,13 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,
        /* data is present; dma-map it */
        if (cmd->sc_data_direction == DMA_FROM_DEVICE ||
            cmd->sc_data_direction == DMA_TO_DEVICE) {
-               if (unlikely(cmd->request_bufflen < 1)) {
+               if (unlikely(scsi_bufflen(cmd) < 1)) {
                        ata_dev_printk(dev, KERN_WARNING,
                                       "WARNING: zero len r/w req\n");
                        goto err_did;
                }
 
-               if (cmd->use_sg)
-                       ata_sg_init(qc, cmd->request_buffer, cmd->use_sg);
-               else
-                       ata_sg_init_one(qc, cmd->request_buffer,
-                                       cmd->request_bufflen);
+               ata_sg_init(qc, scsi_sglist(cmd), scsi_sg_count(cmd));
 
                qc->dma_dir = cmd->sc_data_direction;
        }
@@ -1518,6 +1489,11 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,
        if (xlat_func(qc))
                goto early_finish;
 
+       if (ap->ops->qc_defer) {
+               if ((rc = ap->ops->qc_defer(qc)))
+                       goto defer;
+       }
+
        /* select device, send command to hardware */
        ata_qc_issue(qc);
 
@@ -1539,8 +1515,12 @@ err_mem:
        return 0;
 
 defer:
+       ata_qc_free(qc);
        DPRINTK("EXIT - defer\n");
-       return SCSI_MLQUEUE_DEVICE_BUSY;
+       if (rc == ATA_DEFER_LINK)
+               return SCSI_MLQUEUE_DEVICE_BUSY;
+       else
+               return SCSI_MLQUEUE_HOST_BUSY;
 }
 
 /**
@@ -1562,15 +1542,14 @@ static unsigned int ata_scsi_rbuf_get(struct scsi_cmnd *cmd, u8 **buf_out)
        u8 *buf;
        unsigned int buflen;
 
-       if (cmd->use_sg) {
-               struct scatterlist *sg;
+       struct scatterlist *sg = scsi_sglist(cmd);
 
-               sg = (struct scatterlist *) cmd->request_buffer;
+       if (sg) {
                buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
                buflen = sg->length;
        } else {
-               buf = cmd->request_buffer;
-               buflen = cmd->request_bufflen;
+               buf = NULL;
+               buflen = 0;
        }
 
        *buf_out = buf;
@@ -1590,12 +1569,9 @@ static unsigned int ata_scsi_rbuf_get(struct scsi_cmnd *cmd, u8 **buf_out)
 
 static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, u8 *buf)
 {
-       if (cmd->use_sg) {
-               struct scatterlist *sg;
-
-               sg = (struct scatterlist *) cmd->request_buffer;
+       struct scatterlist *sg = scsi_sglist(cmd);
+       if (sg)
                kunmap_atomic(buf - sg->offset, KM_IRQ0);
-       }
 }
 
 /**
@@ -1816,6 +1792,62 @@ unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf,
        return 0;
 }
 
+/**
+ *     ata_scsiop_inq_89 - Simulate INQUIRY VPD page 89, ATA info
+ *     @args: device IDENTIFY data / SCSI command of interest.
+ *     @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
+ *     @buflen: Response buffer length.
+ *
+ *     Yields SAT-specified ATA VPD page.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host lock)
+ */
+
+unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf,
+                             unsigned int buflen)
+{
+       u8 pbuf[60];
+       struct ata_taskfile tf;
+       unsigned int i;
+
+       if (!buflen)
+               return 0;
+
+       memset(&pbuf, 0, sizeof(pbuf));
+       memset(&tf, 0, sizeof(tf));
+
+       pbuf[1] = 0x89;                 /* our page code */
+       pbuf[2] = (0x238 >> 8);         /* page size fixed at 238h */
+       pbuf[3] = (0x238 & 0xff);
+
+       memcpy(&pbuf[8], "linux   ", 8);
+       memcpy(&pbuf[16], "libata          ", 16);
+       memcpy(&pbuf[32], DRV_VERSION, 4);
+       ata_id_string(args->id, &pbuf[32], ATA_ID_FW_REV, 4);
+
+       /* we don't store the ATA device signature, so we fake it */
+
+       tf.command = ATA_DRDY;          /* really, this is Status reg */
+       tf.lbal = 0x1;
+       tf.nsect = 0x1;
+
+       ata_tf_to_fis(&tf, 0, 1, &pbuf[36]);    /* TODO: PMP? */
+       pbuf[36] = 0x34;                /* force D2H Reg FIS (34h) */
+
+       pbuf[56] = ATA_CMD_ID_ATA;
+
+       i = min(buflen, 60U);
+       memcpy(rbuf, &pbuf[0], i);
+       buflen -= i;
+
+       if (!buflen)
+               return 0;
+
+       memcpy(&rbuf[60], &args->id[0], min(buflen, 512U));
+       return 0;
+}
+
 /**
  *     ata_scsiop_noop - Command handler that simply returns success.
  *     @args: device IDENTIFY data / SCSI command of interest.
@@ -2273,8 +2305,8 @@ static void atapi_request_sense(struct ata_queued_cmd *qc)
                qc->tf.feature |= ATAPI_PKT_DMA;
        } else {
                qc->tf.protocol = ATA_PROT_ATAPI;
-               qc->tf.lbam = (8 * 1024) & 0xff;
-               qc->tf.lbah = (8 * 1024) >> 8;
+               qc->tf.lbam = SCSI_SENSE_BUFFERSIZE;
+               qc->tf.lbah = 0;
        }
        qc->nbytes = SCSI_SENSE_BUFFERSIZE;
 
@@ -2383,6 +2415,7 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc)
        struct ata_device *dev = qc->dev;
        int using_pio = (dev->flags & ATA_DFLAG_PIO);
        int nodata = (scmd->sc_data_direction == DMA_NONE);
+       unsigned int nbytes;
 
        memset(qc->cdb, 0, dev->cdb_len);
        memcpy(qc->cdb, scmd->cmnd, scmd->cmd_len);
@@ -2396,20 +2429,26 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc)
        }
 
        qc->tf.command = ATA_CMD_PACKET;
-       qc->nbytes = scmd->request_bufflen;
+       qc->nbytes = scsi_bufflen(scmd);
 
        /* check whether ATAPI DMA is safe */
        if (!using_pio && ata_check_atapi_dma(qc))
                using_pio = 1;
 
+       /* Some controller variants snoop this value for Packet transfers
+          to do state machine and FIFO management. Thus we want to set it
+          properly, and for DMA where it is effectively meaningless */
+       nbytes = min(qc->nbytes, (unsigned int)63 * 1024);
+
+       qc->tf.lbam = (nbytes & 0xFF);
+       qc->tf.lbah = (nbytes >> 8);
+
        if (using_pio || nodata) {
                /* no data, or PIO data xfer */
                if (nodata)
                        qc->tf.protocol = ATA_PROT_ATAPI_NODATA;
                else
                        qc->tf.protocol = ATA_PROT_ATAPI;
-               qc->tf.lbam = (8 * 1024) & 0xff;
-               qc->tf.lbah = (8 * 1024) >> 8;
        } else {
                /* DMA data xfer */
                qc->tf.protocol = ATA_PROT_ATAPI_DMA;
@@ -2420,24 +2459,42 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc)
                        qc->tf.feature |= ATAPI_DMADIR;
        }
 
+
+       /* FIXME: We need to translate 0x05 READ_BLOCK_LIMITS to a MODE_SENSE
+          as ATAPI tape drives don't get this right otherwise */
        return 0;
 }
 
-static struct ata_device * ata_find_dev(struct ata_port *ap, int id)
+static struct ata_device * ata_find_dev(struct ata_port *ap, int devno)
 {
-       if (likely(id < ATA_MAX_DEVICES))
-               return &ap->device[id];
+       if (ap->nr_pmp_links == 0) {
+               if (likely(devno < ata_link_max_devices(&ap->link)))
+                       return &ap->link.device[devno];
+       } else {
+               if (likely(devno < ap->nr_pmp_links))
+                       return &ap->pmp_link[devno].device[0];
+       }
+
        return NULL;
 }
 
 static struct ata_device * __ata_scsi_find_dev(struct ata_port *ap,
                                        const struct scsi_device *scsidev)
 {
+       int devno;
+
        /* skip commands not addressed to targets we simulate */
-       if (unlikely(scsidev->channel || scsidev->lun))
-               return NULL;
+       if (ap->nr_pmp_links == 0) {
+               if (unlikely(scsidev->channel || scsidev->lun))
+                       return NULL;
+               devno = scsidev->id;
+       } else {
+               if (unlikely(scsidev->id || scsidev->lun))
+                       return NULL;
+               devno = scsidev->channel;
+       }
 
-       return ata_find_dev(ap, scsidev->id);
+       return ata_find_dev(ap, devno);
 }
 
 /**
@@ -2458,7 +2515,7 @@ static int ata_scsi_dev_enabled(struct ata_device *dev)
        if (unlikely(!ata_dev_enabled(dev)))
                return 0;
 
-       if (!atapi_enabled || (dev->ap->flags & ATA_FLAG_NO_ATAPI)) {
+       if (!atapi_enabled || (dev->link->ap->flags & ATA_FLAG_NO_ATAPI)) {
                if (unlikely(dev->class == ATA_DEV_ATAPI)) {
                        ata_dev_printk(dev, KERN_WARNING,
                                       "WARNING: ATAPI is %s, device ignored.\n",
@@ -2631,7 +2688,7 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
        case ATA_CMD_WRITE_LONG_ONCE:
                if (tf->protocol != ATA_PROT_PIO || tf->nsect != 1)
                        goto invalid_fld;
-               qc->sect_size = scmd->request_bufflen;
+               qc->sect_size = scsi_bufflen(scmd);
        }
 
        /*
@@ -2661,7 +2718,7 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
         * TODO: find out if we need to do more here to
         *       cover scatter/gather case.
         */
-       qc->nbytes = scmd->request_bufflen;
+       qc->nbytes = scsi_bufflen(scmd);
 
        /* request result TF */
        qc->flags |= ATA_QCFLAG_RESULT_TF;
@@ -2746,28 +2803,48 @@ static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd,
                                      void (*done)(struct scsi_cmnd *),
                                      struct ata_device *dev)
 {
+       u8 scsi_op = scmd->cmnd[0];
+       ata_xlat_func_t xlat_func;
        int rc = 0;
 
-       if (unlikely(!scmd->cmd_len || scmd->cmd_len > dev->cdb_len)) {
-               DPRINTK("bad CDB len=%u, max=%u\n",
-                       scmd->cmd_len, dev->cdb_len);
-               scmd->result = DID_ERROR << 16;
-               done(scmd);
-               return 0;
-       }
-
        if (dev->class == ATA_DEV_ATA) {
-               ata_xlat_func_t xlat_func = ata_get_xlat_func(dev,
-                                                             scmd->cmnd[0]);
+               if (unlikely(!scmd->cmd_len || scmd->cmd_len > dev->cdb_len))
+                       goto bad_cdb_len;
 
-               if (xlat_func)
-                       rc = ata_scsi_translate(dev, scmd, done, xlat_func);
-               else
-                       ata_scsi_simulate(dev, scmd, done);
-       } else
-               rc = ata_scsi_translate(dev, scmd, done, atapi_xlat);
+               xlat_func = ata_get_xlat_func(dev, scsi_op);
+       } else {
+               if (unlikely(!scmd->cmd_len))
+                       goto bad_cdb_len;
+
+               xlat_func = NULL;
+               if (likely((scsi_op != ATA_16) || !atapi_passthru16)) {
+                       /* relay SCSI command to ATAPI device */
+                       if (unlikely(scmd->cmd_len > dev->cdb_len))
+                               goto bad_cdb_len;
+
+                       xlat_func = atapi_xlat;
+               } else {
+                       /* ATA_16 passthru, treat as an ATA command */
+                       if (unlikely(scmd->cmd_len > 16))
+                               goto bad_cdb_len;
+
+                       xlat_func = ata_get_xlat_func(dev, scsi_op);
+               }
+       }
+
+       if (xlat_func)
+               rc = ata_scsi_translate(dev, scmd, done, xlat_func);
+       else
+               ata_scsi_simulate(dev, scmd, done);
 
        return rc;
+
+ bad_cdb_len:
+       DPRINTK("bad CDB len=%u, scsi_op=0x%02x, max=%u\n",
+               scmd->cmd_len, scsi_op, dev->cdb_len);
+       scmd->result = DID_ERROR << 16;
+       done(scmd);
+       return 0;
 }
 
 /**
@@ -2835,6 +2912,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
 {
        struct ata_scsi_args args;
        const u8 *scsicmd = cmd->cmnd;
+       u8 tmp8;
 
        args.dev = dev;
        args.id = dev->id;
@@ -2842,15 +2920,9 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
        args.done = done;
 
        switch(scsicmd[0]) {
-               /* no-op's, complete with success */
-               case SYNCHRONIZE_CACHE:
-               case REZERO_UNIT:
-               case SEEK_6:
-               case SEEK_10:
-               case TEST_UNIT_READY:
-               case FORMAT_UNIT:               /* FIXME: correct? */
-               case SEND_DIAGNOSTIC:           /* FIXME: correct? */
-                       ata_scsi_rbuf_fill(&args, ata_scsiop_noop);
+               /* TODO: worth improving? */
+               case FORMAT_UNIT:
+                       ata_scsi_invalid_field(cmd, done);
                        break;
 
                case INQUIRY:
@@ -2858,14 +2930,23 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
                                ata_scsi_invalid_field(cmd, done);
                        else if ((scsicmd[1] & 1) == 0)    /* is EVPD clear? */
                                ata_scsi_rbuf_fill(&args, ata_scsiop_inq_std);
-                       else if (scsicmd[2] == 0x00)
+                       else switch (scsicmd[2]) {
+                       case 0x00:
                                ata_scsi_rbuf_fill(&args, ata_scsiop_inq_00);
-                       else if (scsicmd[2] == 0x80)
+                               break;
+                       case 0x80:
                                ata_scsi_rbuf_fill(&args, ata_scsiop_inq_80);
-                       else if (scsicmd[2] == 0x83)
+                               break;
+                       case 0x83:
                                ata_scsi_rbuf_fill(&args, ata_scsiop_inq_83);
-                       else
+                               break;
+                       case 0x89:
+                               ata_scsi_rbuf_fill(&args, ata_scsiop_inq_89);
+                               break;
+                       default:
                                ata_scsi_invalid_field(cmd, done);
+                               break;
+                       }
                        break;
 
                case MODE_SENSE:
@@ -2893,8 +2974,33 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
                        ata_scsi_rbuf_fill(&args, ata_scsiop_report_luns);
                        break;
 
-               /* mandatory commands we haven't implemented yet */
                case REQUEST_SENSE:
+                       ata_scsi_set_sense(cmd, 0, 0, 0);
+                       cmd->result = (DRIVER_SENSE << 24);
+                       done(cmd);
+                       break;
+
+               /* if we reach this, then writeback caching is disabled,
+                * turning this into a no-op.
+                */
+               case SYNCHRONIZE_CACHE:
+                       /* fall through */
+
+               /* no-op's, complete with success */
+               case REZERO_UNIT:
+               case SEEK_6:
+               case SEEK_10:
+               case TEST_UNIT_READY:
+                       ata_scsi_rbuf_fill(&args, ata_scsiop_noop);
+                       break;
+
+               case SEND_DIAGNOSTIC:
+                       tmp8 = scsicmd[1] & ~(1 << 3);
+                       if ((tmp8 == 0x4) && (!scsicmd[3]) && (!scsicmd[4]))
+                               ata_scsi_rbuf_fill(&args, ata_scsiop_noop);
+                       else
+                               ata_scsi_invalid_field(cmd, done);
+                       break;
 
                /* all other commands */
                default:
@@ -2928,6 +3034,13 @@ int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht)
                shost->max_channel = 1;
                shost->max_cmd_len = 16;
 
+               /* Schedule policy is determined by ->qc_defer()
+                * callback and it needs to see every deferred qc.
+                * Set host_blocked to 1 to prevent SCSI midlayer from
+                * automatically deferring requests.
+                */
+               shost->max_host_blocked = 1;
+
                rc = scsi_add_host(ap->scsi_host, ap->host->dev);
                if (rc)
                        goto err_add;
@@ -2951,25 +3064,32 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync)
 {
        int tries = 5;
        struct ata_device *last_failed_dev = NULL;
+       struct ata_link *link;
        struct ata_device *dev;
-       unsigned int i;
 
        if (ap->flags & ATA_FLAG_DISABLED)
                return;
 
  repeat:
-       for (i = 0; i < ATA_MAX_DEVICES; i++) {
-               struct scsi_device *sdev;
+       ata_port_for_each_link(link, ap) {
+               ata_link_for_each_dev(dev, link) {
+                       struct scsi_device *sdev;
+                       int channel = 0, id = 0;
 
-               dev = &ap->device[i];
+                       if (!ata_dev_enabled(dev) || dev->sdev)
+                               continue;
 
-               if (!ata_dev_enabled(dev) || dev->sdev)
-                       continue;
+                       if (ata_is_host_link(link))
+                               id = dev->devno;
+                       else
+                               channel = link->pmp;
 
-               sdev = __scsi_add_device(ap->scsi_host, 0, i, 0, NULL);
-               if (!IS_ERR(sdev)) {
-                       dev->sdev = sdev;
-                       scsi_device_put(sdev);
+                       sdev = __scsi_add_device(ap->scsi_host, channel, id, 0,
+                                                NULL);
+                       if (!IS_ERR(sdev)) {
+                               dev->sdev = sdev;
+                               scsi_device_put(sdev);
+                       }
                }
        }
 
@@ -2977,12 +3097,14 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync)
         * failure occurred, scan would have failed silently.  Check
         * whether all devices are attached.
         */
-       for (i = 0; i < ATA_MAX_DEVICES; i++) {
-               dev = &ap->device[i];
-               if (ata_dev_enabled(dev) && !dev->sdev)
-                       break;
+       ata_port_for_each_link(link, ap) {
+               ata_link_for_each_dev(dev, link) {
+                       if (ata_dev_enabled(dev) && !dev->sdev)
+                               goto exit_loop;
+               }
        }
-       if (i == ATA_MAX_DEVICES)
+ exit_loop:
+       if (!link)
                return;
 
        /* we're missing some SCSI devices */
@@ -3049,7 +3171,7 @@ int ata_scsi_offline_dev(struct ata_device *dev)
  */
 static void ata_scsi_remove_dev(struct ata_device *dev)
 {
-       struct ata_port *ap = dev->ap;
+       struct ata_port *ap = dev->link->ap;
        struct scsi_device *sdev;
        unsigned long flags;
 
@@ -3096,6 +3218,43 @@ static void ata_scsi_remove_dev(struct ata_device *dev)
        }
 }
 
+static void ata_scsi_handle_link_detach(struct ata_link *link)
+{
+       struct ata_port *ap = link->ap;
+       struct ata_device *dev;
+
+       ata_link_for_each_dev(dev, link) {
+               unsigned long flags;
+
+               if (!(dev->flags & ATA_DFLAG_DETACHED))
+                       continue;
+
+               spin_lock_irqsave(ap->lock, flags);
+               dev->flags &= ~ATA_DFLAG_DETACHED;
+               spin_unlock_irqrestore(ap->lock, flags);
+
+               ata_scsi_remove_dev(dev);
+       }
+}
+
+/**
+ *     ata_scsi_media_change_notify - send media change event
+ *     @atadev: Pointer to the disk device with media change event
+ *
+ *     Tell the block layer to send a media change notification
+ *     event.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host lock)
+ */
+void ata_scsi_media_change_notify(struct ata_device *dev)
+{
+#ifdef OTHER_AN_PATCHES_HAVE_BEEN_APPLIED
+       if (dev->sdev)
+               scsi_device_event_notify(dev->sdev, SDEV_MEDIA_CHANGE);
+#endif
+}
+
 /**
  *     ata_scsi_hotplug - SCSI part of hotplug
  *     @work: Pointer to ATA port to perform SCSI hotplug on
@@ -3121,20 +3280,14 @@ void ata_scsi_hotplug(struct work_struct *work)
 
        DPRINTK("ENTER\n");
 
-       /* unplug detached devices */
-       for (i = 0; i < ATA_MAX_DEVICES; i++) {
-               struct ata_device *dev = &ap->device[i];
-               unsigned long flags;
-
-               if (!(dev->flags & ATA_DFLAG_DETACHED))
-                       continue;
-
-               spin_lock_irqsave(ap->lock, flags);
-               dev->flags &= ~ATA_DFLAG_DETACHED;
-               spin_unlock_irqrestore(ap->lock, flags);
-
-               ata_scsi_remove_dev(dev);
-       }
+       /* Unplug detached devices.  We cannot use link iterator here
+        * because PMP links have to be scanned even if PMP is
+        * currently not attached.  Iterate manually.
+        */
+       ata_scsi_handle_link_detach(&ap->link);
+       if (ap->pmp_link)
+               for (i = 0; i < SATA_PMP_MAX_PORTS; i++)
+                       ata_scsi_handle_link_detach(&ap->pmp_link[i]);
 
        /* scan for new ones */
        ata_scsi_scan_host(ap, 0);
@@ -3163,27 +3316,42 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
 {
        struct ata_port *ap = ata_shost_to_port(shost);
        unsigned long flags;
-       int rc = 0;
+       int devno, rc = 0;
 
        if (!ap->ops->error_handler)
                return -EOPNOTSUPP;
 
-       if ((channel != SCAN_WILD_CARD && channel != 0) ||
-           (lun != SCAN_WILD_CARD && lun != 0))
+       if (lun != SCAN_WILD_CARD && lun)
                return -EINVAL;
 
+       if (ap->nr_pmp_links == 0) {
+               if (channel != SCAN_WILD_CARD && channel)
+                       return -EINVAL;
+               devno = id;
+       } else {
+               if (id != SCAN_WILD_CARD && id)
+                       return -EINVAL;
+               devno = channel;
+       }
+
        spin_lock_irqsave(ap->lock, flags);
 
-       if (id == SCAN_WILD_CARD) {
-               ap->eh_info.probe_mask |= (1 << ATA_MAX_DEVICES) - 1;
-               ap->eh_info.action |= ATA_EH_SOFTRESET;
+       if (devno == SCAN_WILD_CARD) {
+               struct ata_link *link;
+
+               ata_port_for_each_link(link, ap) {
+                       struct ata_eh_info *ehi = &link->eh_info;
+                       ehi->probe_mask |= (1 << ata_link_max_devices(link)) - 1;
+                       ehi->action |= ATA_EH_SOFTRESET;
+               }
        } else {
-               struct ata_device *dev = ata_find_dev(ap, id);
+               struct ata_device *dev = ata_find_dev(ap, devno);
 
                if (dev) {
-                       ap->eh_info.probe_mask |= 1 << dev->devno;
-                       ap->eh_info.action |= ATA_EH_SOFTRESET;
-                       ap->eh_info.flags |= ATA_EHI_RESUME_LINK;
+                       struct ata_eh_info *ehi = &dev->link->eh_info;
+                       ehi->probe_mask |= 1 << dev->devno;
+                       ehi->action |= ATA_EH_SOFTRESET;
+                       ehi->flags |= ATA_EHI_RESUME_LINK;
                } else
                        rc = -EINVAL;
        }
@@ -3214,24 +3382,26 @@ void ata_scsi_dev_rescan(struct work_struct *work)
 {
        struct ata_port *ap =
                container_of(work, struct ata_port, scsi_rescan_task);
+       struct ata_link *link;
+       struct ata_device *dev;
        unsigned long flags;
-       unsigned int i;
 
        spin_lock_irqsave(ap->lock, flags);
 
-       for (i = 0; i < ATA_MAX_DEVICES; i++) {
-               struct ata_device *dev = &ap->device[i];
-               struct scsi_device *sdev = dev->sdev;
+       ata_port_for_each_link(link, ap) {
+               ata_link_for_each_dev(dev, link) {
+                       struct scsi_device *sdev = dev->sdev;
 
-               if (!ata_dev_enabled(dev) || !sdev)
-                       continue;
-               if (scsi_device_get(sdev))
-                       continue;
+                       if (!ata_dev_enabled(dev) || !sdev)
+                               continue;
+                       if (scsi_device_get(sdev))
+                               continue;
 
-               spin_unlock_irqrestore(ap->lock, flags);
-               scsi_rescan_device(&(sdev->sdev_gendev));
-               scsi_device_put(sdev);
-               spin_lock_irqsave(ap->lock, flags);
+                       spin_unlock_irqrestore(ap->lock, flags);
+                       scsi_rescan_device(&(sdev->sdev_gendev));
+                       scsi_device_put(sdev);
+                       spin_lock_irqsave(ap->lock, flags);
+               }
        }
 
        spin_unlock_irqrestore(ap->lock, flags);
@@ -3359,7 +3529,7 @@ EXPORT_SYMBOL_GPL(ata_sas_port_destroy);
 int ata_sas_slave_configure(struct scsi_device *sdev, struct ata_port *ap)
 {
        ata_scsi_sdev_config(sdev);
-       ata_scsi_dev_config(sdev, ap->device);
+       ata_scsi_dev_config(sdev, ap->link.device);
        return 0;
 }
 EXPORT_SYMBOL_GPL(ata_sas_slave_configure);
@@ -3382,8 +3552,8 @@ int ata_sas_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *),
 
        ata_scsi_dump_cdb(ap, cmd);
 
-       if (likely(ata_scsi_dev_enabled(ap->device)))
-               rc = __ata_scsi_queuecmd(cmd, done, ap->device);
+       if (likely(ata_scsi_dev_enabled(ap->link.device)))
+               rc = __ata_scsi_queuecmd(cmd, done, ap->link.device);
        else {
                cmd->result = (DID_BAD_TARGET << 16);
                done(cmd);
index 8023167bbbeb68623fd9939887010fb74362cb70..026439e05afe5e9a1a75ebaf246123c7fdc6c18b 100644 (file)
@@ -64,46 +64,6 @@ u8 ata_irq_on(struct ata_port *ap)
        return tmp;
 }
 
-u8 ata_dummy_irq_on (struct ata_port *ap)      { return 0; }
-
-/**
- *     ata_irq_ack - Acknowledge a device interrupt.
- *     @ap: Port on which interrupts are enabled.
- *
- *     Wait up to 10 ms for legacy IDE device to become idle (BUSY
- *     or BUSY+DRQ clear).  Obtain dma status and port status from
- *     device.  Clear the interrupt.  Return port status.
- *
- *     LOCKING:
- */
-
-u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq)
-{
-       unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY;
-       u8 host_stat = 0, post_stat = 0, status;
-
-       status = ata_busy_wait(ap, bits, 1000);
-       if (status & bits)
-               if (ata_msg_err(ap))
-                       printk(KERN_ERR "abnormal status 0x%X\n", status);
-
-       if (ap->ioaddr.bmdma_addr) {
-               /* get controller status; clear intr, err bits */
-               host_stat = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
-               iowrite8(host_stat | ATA_DMA_INTR | ATA_DMA_ERR,
-                        ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
-
-               post_stat = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
-       }
-       if (ata_msg_intr(ap))
-               printk(KERN_INFO "%s: irq ack: host_stat 0x%X, new host_stat 0x%X, drv_stat 0x%X\n",
-                       __FUNCTION__,
-                       host_stat, post_stat, status);
-       return status;
-}
-
-u8 ata_dummy_irq_ack(struct ata_port *ap, unsigned int chk_drq) { return 0; }
-
 /**
  *     ata_tf_load - send taskfile registers to host controller
  *     @ap: Port to which output is sent
@@ -445,7 +405,7 @@ void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
        unsigned long flags;
        int thaw = 0;
 
-       qc = __ata_qc_from_tag(ap, ap->active_tag);
+       qc = __ata_qc_from_tag(ap, ap->link.active_tag);
        if (qc && !(qc->flags & ATA_QCFLAG_FAILED))
                qc = NULL;
 
@@ -500,7 +460,7 @@ void ata_bmdma_error_handler(struct ata_port *ap)
        ata_reset_fn_t hardreset;
 
        hardreset = NULL;
-       if (sata_scr_valid(ap))
+       if (sata_scr_valid(&ap->link))
                hardreset = sata_std_hardreset;
 
        ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, hardreset,
@@ -607,6 +567,9 @@ int ata_pci_init_bmdma(struct ata_host *host)
                if ((!(ap->flags & ATA_FLAG_IGN_SIMPLEX)) &&
                    (ioread8(bmdma + 2) & 0x80))
                        host->flags |= ATA_HOST_SIMPLEX;
+
+               ata_port_desc(ap, "bmdma 0x%llx",
+                       (unsigned long long)pci_resource_start(pdev, 4) + 8 * i);
        }
 
        return 0;
@@ -674,6 +637,10 @@ int ata_pci_init_sff_host(struct ata_host *host)
                        ((unsigned long)iomap[base + 1] | ATA_PCI_CTL_OFS);
                ata_std_ports(&ap->ioaddr);
 
+               ata_port_desc(ap, "cmd 0x%llx ctl 0x%llx",
+                       (unsigned long long)pci_resource_start(pdev, base),
+                       (unsigned long long)pci_resource_start(pdev, base + 1));
+
                mask |= 1 << i;
        }
 
@@ -844,24 +811,30 @@ int ata_pci_init_one(struct pci_dev *pdev,
                                      IRQF_SHARED, DRV_NAME, host);
                if (rc)
                        goto err_out;
-               host->irq = pdev->irq;
+
+               ata_port_desc(host->ports[0], "irq %d", pdev->irq);
+               ata_port_desc(host->ports[1], "irq %d", pdev->irq);
        } else {
                if (!ata_port_is_dummy(host->ports[0])) {
-                       host->irq = ATA_PRIMARY_IRQ(pdev);
-                       rc = devm_request_irq(dev, host->irq,
+                       rc = devm_request_irq(dev, ATA_PRIMARY_IRQ(pdev),
                                              pi->port_ops->irq_handler,
                                              IRQF_SHARED, DRV_NAME, host);
                        if (rc)
                                goto err_out;
+
+                       ata_port_desc(host->ports[0], "irq %d",
+                                     ATA_PRIMARY_IRQ(pdev));
                }
 
                if (!ata_port_is_dummy(host->ports[1])) {
-                       host->irq2 = ATA_SECONDARY_IRQ(pdev);
-                       rc = devm_request_irq(dev, host->irq2,
+                       rc = devm_request_irq(dev, ATA_SECONDARY_IRQ(pdev),
                                              pi->port_ops->irq_handler,
                                              IRQF_SHARED, DRV_NAME, host);
                        if (rc)
                                goto err_out;
+
+                       ata_port_desc(host->ports[1], "irq %d",
+                                     ATA_SECONDARY_IRQ(pdev));
                }
        }
 
@@ -909,7 +882,7 @@ unsigned long ata_pci_default_filter(struct ata_device *adev, unsigned long xfer
        /* Filter out DMA modes if the device has been configured by
           the BIOS as PIO only */
 
-       if (adev->ap->ioaddr.bmdma_addr == 0)
+       if (adev->link->ap->ioaddr.bmdma_addr == 0)
                xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
        return xfer_mask;
 }
index 564cd234c805335999bf40fefe0b00eab1f061d1..90df58a3edc95ff4cdab4bc43fc2046c20b430c6 100644 (file)
@@ -29,6 +29,7 @@
 #define __LIBATA_H__
 
 #define DRV_NAME       "libata"
+#define DRV_VERSION    "3.00"  /* must be exactly four chars */
 
 struct ata_scsi_args {
        struct ata_device       *dev;
@@ -56,6 +57,7 @@ extern unsigned int ata_print_id;
 extern struct workqueue_struct *ata_aux_wq;
 extern int atapi_enabled;
 extern int atapi_dmadir;
+extern int atapi_passthru16;
 extern int libata_fua;
 extern int libata_noacpi;
 extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev);
@@ -67,21 +69,23 @@ extern void ata_dev_disable(struct ata_device *dev);
 extern void ata_port_flush_task(struct ata_port *ap);
 extern unsigned ata_exec_internal(struct ata_device *dev,
                                  struct ata_taskfile *tf, const u8 *cdb,
-                                 int dma_dir, void *buf, unsigned int buflen);
+                                 int dma_dir, void *buf, unsigned int buflen,
+                                 unsigned long timeout);
 extern unsigned ata_exec_internal_sg(struct ata_device *dev,
                                     struct ata_taskfile *tf, const u8 *cdb,
                                     int dma_dir, struct scatterlist *sg,
-                                    unsigned int n_elem);
+                                    unsigned int n_elem, unsigned long timeout);
 extern unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd);
 extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
                           unsigned int flags, u16 *id);
 extern int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags);
-extern int ata_dev_revalidate(struct ata_device *dev, unsigned int readid_flags);
+extern int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class,
+                             unsigned int readid_flags);
 extern int ata_dev_configure(struct ata_device *dev);
-extern int sata_down_spd_limit(struct ata_port *ap);
-extern int sata_set_spd_needed(struct ata_port *ap);
+extern int sata_down_spd_limit(struct ata_link *link);
+extern int sata_set_spd_needed(struct ata_link *link);
 extern int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel);
-extern int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev);
+extern int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev);
 extern void ata_sg_clean(struct ata_queued_cmd *qc);
 extern void ata_qc_free(struct ata_queued_cmd *qc);
 extern void ata_qc_issue(struct ata_queued_cmd *qc);
@@ -92,17 +96,21 @@ extern void ata_dev_select(struct ata_port *ap, unsigned int device,
 extern void swap_buf_le16(u16 *buf, unsigned int buf_words);
 extern int ata_flush_cache(struct ata_device *dev);
 extern void ata_dev_init(struct ata_device *dev);
+extern void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp);
+extern int sata_link_init_spd(struct ata_link *link);
 extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg);
 extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg);
 extern struct ata_port *ata_port_alloc(struct ata_host *host);
 
 /* libata-acpi.c */
 #ifdef CONFIG_ATA_ACPI
+extern void ata_acpi_associate_sata_port(struct ata_port *ap);
 extern void ata_acpi_associate(struct ata_host *host);
 extern int ata_acpi_on_suspend(struct ata_port *ap);
 extern void ata_acpi_on_resume(struct ata_port *ap);
 extern int ata_acpi_on_devcfg(struct ata_device *adev);
 #else
+static inline void ata_acpi_associate_sata_port(struct ata_port *ap) { }
 static inline void ata_acpi_associate(struct ata_host *host) { }
 static inline int ata_acpi_on_suspend(struct ata_port *ap) { return 0; }
 static inline void ata_acpi_on_resume(struct ata_port *ap) { }
@@ -114,6 +122,7 @@ extern int ata_scsi_add_hosts(struct ata_host *host,
                              struct scsi_host_template *sht);
 extern void ata_scsi_scan_host(struct ata_port *ap, int sync);
 extern int ata_scsi_offline_dev(struct ata_device *dev);
+extern void ata_scsi_media_change_notify(struct ata_device *dev);
 extern void ata_scsi_hotplug(struct work_struct *work);
 extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
                               unsigned int buflen);
@@ -147,12 +156,32 @@ extern void ata_schedule_scsi_eh(struct Scsi_Host *shost);
 extern void ata_scsi_dev_rescan(struct work_struct *work);
 extern int ata_bus_probe(struct ata_port *ap);
 
+/* libata-pmp.c */
+extern int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *val);
+extern int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val);
+extern int sata_pmp_attach(struct ata_device *dev);
+
 /* libata-eh.c */
 extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
 extern void ata_scsi_error(struct Scsi_Host *host);
 extern void ata_port_wait_eh(struct ata_port *ap);
 extern void ata_eh_fastdrain_timerfn(unsigned long arg);
 extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc);
+extern void ata_eh_detach_dev(struct ata_device *dev);
+extern void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev,
+                              unsigned int action);
+extern void ata_eh_done(struct ata_link *link, struct ata_device *dev,
+                       unsigned int action);
+extern void ata_eh_autopsy(struct ata_port *ap);
+extern void ata_eh_report(struct ata_port *ap);
+extern int ata_eh_reset(struct ata_link *link, int classify,
+                       ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
+                       ata_reset_fn_t hardreset, ata_postreset_fn_t postreset);
+extern int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
+                         ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
+                         ata_postreset_fn_t postreset,
+                         struct ata_link **r_failed_disk);
+extern void ata_eh_finish(struct ata_port *ap);
 
 /* libata-sff.c */
 extern u8 ata_irq_on(struct ata_port *ap);
diff --git a/drivers/ata/pata_acpi.c b/drivers/ata/pata_acpi.c
new file mode 100644 (file)
index 0000000..5d3920f
--- /dev/null
@@ -0,0 +1,395 @@
+/*
+ *     ACPI PATA driver
+ *
+ *     (c) 2007 Red Hat  <alan@redhat.com>
+ */
+
+#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/device.h>
+#include <scsi/scsi_host.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acnames.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acparser.h>
+#include <acpi/acexcep.h>
+#include <acpi/acmacros.h>
+#include <acpi/actypes.h>
+
+#include <linux/libata.h>
+#include <linux/ata.h>
+
+#define DRV_NAME       "pata_acpi"
+#define DRV_VERSION    "0.2.3"
+
+struct pata_acpi {
+       struct ata_acpi_gtm gtm;
+       void *last;
+       unsigned long mask[2];
+};
+
+/**
+ *     pacpi_pre_reset -       check for 40/80 pin
+ *     @ap: Port
+ *     @deadline: deadline jiffies for the operation
+ *
+ *     Perform the PATA port setup we need.
+ */
+
+static int pacpi_pre_reset(struct ata_link *link, unsigned long deadline)
+{
+       struct ata_port *ap = link->ap;
+       struct pata_acpi *acpi = ap->private_data;
+       if (ap->acpi_handle == NULL || ata_acpi_gtm(ap, &acpi->gtm) < 0)
+               return -ENODEV;
+
+       return ata_std_prereset(link, deadline);
+}
+
+/**
+ *     pacpi_cable_detect      -       cable type detection
+ *     @ap: port to detect
+ *
+ *     Perform device specific cable detection
+ */
+
+static int pacpi_cable_detect(struct ata_port *ap)
+{
+       struct pata_acpi *acpi = ap->private_data;
+
+       if ((acpi->mask[0] | acpi->mask[1]) & (0xF8 << ATA_SHIFT_UDMA))
+               return ATA_CBL_PATA80;
+       else
+               return ATA_CBL_PATA40;
+}
+
+/**
+ *     pacpi_error_handler - Setup and error handler
+ *     @ap: Port to handle
+ *
+ *     LOCKING:
+ *     None (inherited from caller).
+ */
+
+static void pacpi_error_handler(struct ata_port *ap)
+{
+       return ata_bmdma_drive_eh(ap, pacpi_pre_reset, ata_std_softreset,
+                                 NULL, ata_std_postreset);
+}
+
+/* Welcome to ACPI, bring a bucket */
+static const unsigned int pio_cycle[7] = {
+       600, 383, 240, 180, 120, 100, 80
+};
+static const unsigned int mwdma_cycle[5] = {
+       480, 150, 120, 100, 80
+};
+static const unsigned int udma_cycle[7] = {
+       120, 80, 60, 45, 30, 20, 15
+};
+
+/**
+ *     pacpi_discover_modes    -       filter non ACPI modes
+ *     @adev: ATA device
+ *     @mask: proposed modes
+ *
+ *     Try the modes available and see which ones the ACPI method will
+ *     set up sensibly. From this we get a mask of ACPI modes we can use
+ */
+
+static unsigned long pacpi_discover_modes(struct ata_port *ap, struct ata_device *adev)
+{
+       int unit = adev->devno;
+       struct pata_acpi *acpi = ap->private_data;
+       int i;
+       u32 t;
+       unsigned long mask = (0x7f << ATA_SHIFT_UDMA) | (0x7 << ATA_SHIFT_MWDMA) | (0x1F << ATA_SHIFT_PIO);
+
+       struct ata_acpi_gtm probe;
+
+       probe = acpi->gtm;
+
+       /* We always use the 0 slot for crap hardware */
+       if (!(probe.flags & 0x10))
+               unit = 0;
+
+       ata_acpi_gtm(ap, &probe);
+
+       /* Start by scanning for PIO modes */
+       for (i = 0; i < 7; i++) {
+               t = probe.drive[unit].pio;
+               if (t <= pio_cycle[i]) {
+                       mask |= (2 << (ATA_SHIFT_PIO + i)) - 1;
+                       break;
+               }
+       }
+
+       /* See if we have MWDMA or UDMA data. We don't bother with MWDMA
+          if UDMA is availabe as this means the BIOS set UDMA and our
+          error changedown if it works is UDMA to PIO anyway */
+       if (probe.flags & (1 << (2 * unit))) {
+               /* MWDMA */
+               for (i = 0; i < 5; i++) {
+                       t = probe.drive[unit].dma;
+                       if (t <= mwdma_cycle[i]) {
+                               mask |= (2 << (ATA_SHIFT_MWDMA + i)) - 1;
+                               break;
+                       }
+               }
+       } else {
+               /* UDMA */
+               for (i = 0; i < 7; i++) {
+                       t = probe.drive[unit].dma;
+                       if (t <= udma_cycle[i]) {
+                               mask |= (2 << (ATA_SHIFT_UDMA + i)) - 1;
+                               break;
+                       }
+               }
+       }
+       if (mask & (0xF8 << ATA_SHIFT_UDMA))
+               ap->cbl = ATA_CBL_PATA80;
+       return mask;
+}
+
+/**
+ *     pacpi_mode_filter       -       mode filter for ACPI
+ *     @adev: device
+ *     @mask: mask of valid modes
+ *
+ *     Filter the valid mode list according to our own specific rules, in
+ *     this case the list of discovered valid modes obtained by ACPI probing
+ */
+
+static unsigned long pacpi_mode_filter(struct ata_device *adev, unsigned long mask)
+{
+       struct pata_acpi *acpi = adev->link->ap->private_data;
+       return ata_pci_default_filter(adev, mask & acpi->mask[adev->devno]);
+}
+
+/**
+ *     pacpi_set_piomode       -       set initial PIO mode data
+ *     @ap: ATA interface
+ *     @adev: ATA device
+ */
+
+static void pacpi_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+       int unit = adev->devno;
+       struct pata_acpi *acpi = ap->private_data;
+
+       if(!(acpi->gtm.flags & 0x10))
+               unit = 0;
+
+       /* Now stuff the nS values into the structure */
+       acpi->gtm.drive[unit].pio = pio_cycle[adev->pio_mode - XFER_PIO_0];
+       ata_acpi_stm(ap, &acpi->gtm);
+       /* See what mode we actually got */
+       ata_acpi_gtm(ap, &acpi->gtm);
+}
+
+/**
+ *     pacpi_set_dmamode       -       set initial DMA mode data
+ *     @ap: ATA interface
+ *     @adev: ATA device
+ */
+
+static void pacpi_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+       int unit = adev->devno;
+       struct pata_acpi *acpi = ap->private_data;
+
+       if(!(acpi->gtm.flags & 0x10))
+               unit = 0;
+
+       /* Now stuff the nS values into the structure */
+       if (adev->dma_mode >= XFER_UDMA_0) {
+               acpi->gtm.drive[unit].dma = udma_cycle[adev->dma_mode - XFER_UDMA_0];
+               acpi->gtm.flags |= (1 << (2 * unit));
+       } else {
+               acpi->gtm.drive[unit].dma = mwdma_cycle[adev->dma_mode - XFER_MW_DMA_0];
+               acpi->gtm.flags &= ~(1 << (2 * unit));
+       }
+       ata_acpi_stm(ap, &acpi->gtm);
+       /* See what mode we actually got */
+       ata_acpi_gtm(ap, &acpi->gtm);
+}
+
+/**
+ *     pacpi_qc_issue_prot     -       command issue
+ *     @qc: command pending
+ *
+ *     Called when the libata layer is about to issue a command. We wrap
+ *     this interface so that we can load the correct ATA timings if
+ *     neccessary.
+ */
+
+static unsigned int pacpi_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+       struct ata_port *ap = qc->ap;
+       struct ata_device *adev = qc->dev;
+       struct pata_acpi *acpi = ap->private_data;
+
+       if (acpi->gtm.flags & 0x10)
+               return ata_qc_issue_prot(qc);
+
+       if (adev != acpi->last) {
+               pacpi_set_piomode(ap, adev);
+               if (adev->dma_mode)
+                       pacpi_set_dmamode(ap, adev);
+               acpi->last = adev;
+       }
+       return ata_qc_issue_prot(qc);
+}
+
+/**
+ *     pacpi_port_start        -       port setup
+ *     @ap: ATA port being set up
+ *
+ *     Use the port_start hook to maintain private control structures
+ */
+
+static int pacpi_port_start(struct ata_port *ap)
+{
+       struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+       struct pata_acpi *acpi;
+
+       int ret;
+
+       if (ap->acpi_handle == NULL)
+               return -ENODEV;
+
+       acpi = ap->private_data = devm_kzalloc(&pdev->dev, sizeof(struct pata_acpi), GFP_KERNEL);
+       if (ap->private_data == NULL)
+               return -ENOMEM;
+       acpi->mask[0] = pacpi_discover_modes(ap, &ap->link.device[0]);
+       acpi->mask[1] = pacpi_discover_modes(ap, &ap->link.device[1]);
+       ret = ata_sff_port_start(ap);
+       if (ret < 0)
+               return ret;
+
+       return ret;
+}
+
+static struct scsi_host_template pacpi_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,
+       /* Use standard CHS mapping rules */
+       .bios_param             = ata_std_bios_param,
+};
+
+static const struct ata_port_operations pacpi_ops = {
+       .set_piomode            = pacpi_set_piomode,
+       .set_dmamode            = pacpi_set_dmamode,
+       .mode_filter            = pacpi_mode_filter,
+
+       /* Task file is PCI ATA format, use helpers */
+       .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          = pacpi_error_handler,
+       .post_internal_cmd      = ata_bmdma_post_internal_cmd,
+       .cable_detect           = pacpi_cable_detect,
+
+       /* BMDMA handling is PCI ATA format, use helpers */
+       .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               = pacpi_qc_issue_prot,
+       .data_xfer              = ata_data_xfer,
+
+       /* Timeout handling */
+       .irq_handler            = ata_interrupt,
+       .irq_clear              = ata_bmdma_irq_clear,
+       .irq_on                 = ata_irq_on,
+
+       /* Generic PATA PCI ATA helpers */
+       .port_start             = pacpi_port_start,
+};
+
+
+/**
+ *     pacpi_init_one - Register ACPI ATA PCI device with kernel services
+ *     @pdev: PCI device to register
+ *     @ent: Entry in pacpi_pci_tbl matching with @pdev
+ *
+ *     Called from kernel PCI layer.
+ *
+ *     LOCKING:
+ *     Inherited from PCI layer (may sleep).
+ *
+ *     RETURNS:
+ *     Zero on success, or -ERRNO value.
+ */
+
+static int pacpi_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
+{
+       static const struct ata_port_info info = {
+               .sht            = &pacpi_sht,
+               .flags          = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+
+               .pio_mask       = 0x1f,
+               .mwdma_mask     = 0x07,
+               .udma_mask      = 0x7f,
+
+               .port_ops       = &pacpi_ops,
+       };
+       const struct ata_port_info *ppi[] = { &info, NULL };
+       return ata_pci_init_one(pdev, ppi);
+}
+
+static const struct pci_device_id pacpi_pci_tbl[] = {
+       { PCI_ANY_ID,           PCI_ANY_ID,                        PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 1},
+       { }     /* terminate list */
+};
+
+static struct pci_driver pacpi_pci_driver = {
+       .name                   = DRV_NAME,
+       .id_table               = pacpi_pci_tbl,
+       .probe                  = pacpi_init_one,
+       .remove                 = ata_pci_remove_one,
+       .suspend                = ata_pci_device_suspend,
+       .resume                 = ata_pci_device_resume,
+};
+
+static int __init pacpi_init(void)
+{
+       return pci_register_driver(&pacpi_pci_driver);
+}
+
+static void __exit pacpi_exit(void)
+{
+       pci_unregister_driver(&pacpi_pci_driver);
+}
+
+module_init(pacpi_init);
+module_exit(pacpi_exit);
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("SCSI low-level driver for ATA in ACPI mode");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, pacpi_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
index 32a10c99c06f22f2623b284fa8a7f9d16b435685..364534e7aff4522105d1c043502e15da2ddfa1d3 100644 (file)
@@ -305,7 +305,6 @@ static struct scsi_host_template ali_sht = {
  */
 
 static struct ata_port_operations ali_early_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = ali_set_piomode,
        .tf_load        = ata_tf_load,
        .tf_read        = ata_tf_read,
@@ -327,9 +326,8 @@ static struct ata_port_operations ali_early_port_ops = {
        .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,
+       .port_start     = ata_sff_port_start,
 };
 
 /*
@@ -337,8 +335,6 @@ static struct ata_port_operations ali_early_port_ops = {
  *     detect
  */
 static struct ata_port_operations ali_20_port_ops = {
-       .port_disable   = ata_port_disable,
-
        .set_piomode    = ali_set_piomode,
        .set_dmamode    = ali_set_dmamode,
        .mode_filter    = ali_20_filter,
@@ -369,16 +365,14 @@ static struct ata_port_operations ali_20_port_ops = {
        .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,
+       .port_start     = ata_sff_port_start,
 };
 
 /*
  *     Port operations for DMA capable ALi with cable detect
  */
 static struct ata_port_operations ali_c2_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = ali_set_piomode,
        .set_dmamode    = ali_set_dmamode,
        .mode_filter    = ata_pci_default_filter,
@@ -408,16 +402,14 @@ static struct ata_port_operations ali_c2_port_ops = {
        .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,
+       .port_start     = ata_sff_port_start,
 };
 
 /*
  *     Port operations for DMA capable ALi with cable detect and LBA48
  */
 static struct ata_port_operations ali_c5_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = ali_set_piomode,
        .set_dmamode    = ali_set_dmamode,
        .mode_filter    = ata_pci_default_filter,
@@ -446,9 +438,8 @@ static struct ata_port_operations ali_c5_port_ops = {
        .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,
+       .port_start     = ata_sff_port_start,
 };
 
 
index 04048fcf6305ef7e9423c7e38e9563f56535225b..c5779ad4abcabf43ec590cdcf00e806e824fd5de 100644 (file)
@@ -119,27 +119,28 @@ static void timing_setup(struct ata_port *ap, struct ata_device *adev, int offse
 }
 
 /**
- *     amd_probe_init          -       perform reset handling
- *     @ap: ATA port
+ *     amd_pre_reset           -       perform reset handling
+ *     @link: ATA link
  *     @deadline: deadline jiffies for the operation
  *
  *     Reset sequence checking enable bits to see which ports are
  *     active.
  */
 
-static int amd_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int amd_pre_reset(struct ata_link *link, unsigned long deadline)
 {
        static const struct pci_bits amd_enable_bits[] = {
                { 0x40, 1, 0x02, 0x02 },
                { 0x40, 1, 0x01, 0x01 }
        };
 
+       struct ata_port *ap = link->ap;
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 
        if (!pci_test_config_bits(pdev, &amd_enable_bits[ap->port_no]))
                return -ENOENT;
 
-       return ata_std_prereset(ap, deadline);
+       return ata_std_prereset(link, deadline);
 }
 
 static void amd_error_handler(struct ata_port *ap)
@@ -221,25 +222,26 @@ static void amd133_set_dmamode(struct ata_port *ap, struct ata_device *adev)
 
 /**
  *     nv_probe_init   -       cable detection
- *     @ap: ATA port
+ *     @lin: ATA link
  *
  *     Perform cable detection. The BIOS stores this in PCI config
  *     space for us.
  */
 
-static int nv_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int nv_pre_reset(struct ata_link *link, unsigned long deadline)
 {
        static const struct pci_bits nv_enable_bits[] = {
                { 0x50, 1, 0x02, 0x02 },
                { 0x50, 1, 0x01, 0x01 }
        };
 
+       struct ata_port *ap = link->ap;
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 
        if (!pci_test_config_bits(pdev, &nv_enable_bits[ap->port_no]))
                return -ENOENT;
 
-       return ata_std_prereset(ap, deadline);
+       return ata_std_prereset(link, deadline);
 }
 
 static void nv_error_handler(struct ata_port *ap)
@@ -268,6 +270,9 @@ static int nv_cable_detect(struct ata_port *ap)
        pci_read_config_word(pdev, 0x62 - 2 * ap->port_no, &udma);
        if ((udma & 0xC4) == 0xC4 || (udma & 0xC400) == 0xC400)
                cbl = ATA_CBL_PATA80;
+       /* And a triple check across suspend/resume with ACPI around */
+       if (ata_acpi_cbl_80wire(ap))
+               cbl = ATA_CBL_PATA80;
        return cbl;
 }
 
@@ -327,7 +332,6 @@ static struct scsi_host_template amd_sht = {
 };
 
 static struct ata_port_operations amd33_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = amd33_set_piomode,
        .set_dmamode    = amd33_set_dmamode,
        .mode_filter    = ata_pci_default_filter,
@@ -356,13 +360,11 @@ static struct ata_port_operations amd33_port_ops = {
        .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,
+       .port_start     = ata_sff_port_start,
 };
 
 static struct ata_port_operations amd66_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = amd66_set_piomode,
        .set_dmamode    = amd66_set_dmamode,
        .mode_filter    = ata_pci_default_filter,
@@ -391,13 +393,11 @@ static struct ata_port_operations amd66_port_ops = {
        .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,
+       .port_start     = ata_sff_port_start,
 };
 
 static struct ata_port_operations amd100_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = amd100_set_piomode,
        .set_dmamode    = amd100_set_dmamode,
        .mode_filter    = ata_pci_default_filter,
@@ -426,13 +426,11 @@ static struct ata_port_operations amd100_port_ops = {
        .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,
+       .port_start     = ata_sff_port_start,
 };
 
 static struct ata_port_operations amd133_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = amd133_set_piomode,
        .set_dmamode    = amd133_set_dmamode,
        .mode_filter    = ata_pci_default_filter,
@@ -461,13 +459,11 @@ static struct ata_port_operations amd133_port_ops = {
        .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,
+       .port_start     = ata_sff_port_start,
 };
 
 static struct ata_port_operations nv100_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = nv100_set_piomode,
        .set_dmamode    = nv100_set_dmamode,
        .mode_filter    = ata_pci_default_filter,
@@ -496,13 +492,11 @@ static struct ata_port_operations nv100_port_ops = {
        .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,
+       .port_start     = ata_sff_port_start,
 };
 
 static struct ata_port_operations nv133_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = nv133_set_piomode,
        .set_dmamode    = nv133_set_dmamode,
        .mode_filter    = ata_pci_default_filter,
@@ -531,9 +525,8 @@ static struct ata_port_operations nv133_port_ops = {
        .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,
+       .port_start     = ata_sff_port_start,
 };
 
 static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
index b5352ebecef93a9cf047b5f6cdb3cd4dc1a10c50..d4218310327b2795c1b1337eb9383ae9e5866b55 100644 (file)
@@ -40,8 +40,9 @@
 
 static int clock = 0;
 
-static int artop6210_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int artop6210_pre_reset(struct ata_link *link, unsigned long deadline)
 {
+       struct ata_port *ap = link->ap;
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        const struct pci_bits artop_enable_bits[] = {
                { 0x4AU, 1U, 0x02UL, 0x02UL },  /* port 0 */
@@ -51,7 +52,7 @@ static int artop6210_pre_reset(struct ata_port *ap, unsigned long deadline)
        if (!pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no]))
                return -ENOENT;
 
-       return ata_std_prereset(ap, deadline);
+       return ata_std_prereset(link, deadline);
 }
 
 /**
@@ -71,27 +72,28 @@ static void artop6210_error_handler(struct ata_port *ap)
 
 /**
  *     artop6260_pre_reset     -       check for 40/80 pin
- *     @ap: Port
+ *     @link: link
  *     @deadline: deadline jiffies for the operation
  *
  *     The ARTOP hardware reports the cable detect bits in register 0x49.
  *     Nothing complicated needed here.
  */
 
-static int artop6260_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int artop6260_pre_reset(struct ata_link *link, unsigned long deadline)
 {
        static const struct pci_bits artop_enable_bits[] = {
                { 0x4AU, 1U, 0x02UL, 0x02UL },  /* port 0 */
                { 0x4AU, 1U, 0x04UL, 0x04UL },  /* port 1 */
        };
 
+       struct ata_port *ap = link->ap;
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 
        /* Odd numbered device ids are the units with enable bits (the -R cards) */
        if (pdev->device % 1 && !pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no]))
                return -ENOENT;
 
-       return ata_std_prereset(ap, deadline);
+       return ata_std_prereset(link, deadline);
 }
 
 /**
@@ -330,7 +332,6 @@ static struct scsi_host_template artop_sht = {
 };
 
 static const struct ata_port_operations artop6210_ops = {
-       .port_disable           = ata_port_disable,
        .set_piomode            = artop6210_set_piomode,
        .set_dmamode            = artop6210_set_dmamode,
        .mode_filter            = ata_pci_default_filter,
@@ -359,13 +360,11 @@ static const struct ata_port_operations artop6210_ops = {
        .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,
+       .port_start             = ata_sff_port_start,
 };
 
 static const struct ata_port_operations artop6260_ops = {
-       .port_disable           = ata_port_disable,
        .set_piomode            = artop6260_set_piomode,
        .set_dmamode            = artop6260_set_dmamode,
 
@@ -392,9 +391,8 @@ static const struct ata_port_operations artop6260_ops = {
        .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,
+       .port_start             = ata_sff_port_start,
 };
 
 
diff --git a/drivers/ata/pata_at32.c b/drivers/ata/pata_at32.c
new file mode 100644 (file)
index 0000000..bb250a4
--- /dev/null
@@ -0,0 +1,441 @@
+/*
+ * AVR32 SMC/CFC PATA Driver
+ *
+ * Copyright (C) 2007 Atmel Norway
+ *
+ * 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.
+ */
+
+#define DEBUG
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <scsi/scsi_host.h>
+#include <linux/ata.h>
+#include <linux/libata.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#include <asm/arch/board.h>
+#include <asm/arch/smc.h>
+
+#define DRV_NAME "pata_at32"
+#define DRV_VERSION "0.0.2"
+
+/*
+ * CompactFlash controller memory layout relative to the base address:
+ *
+ *     Attribute memory:  0000 0000 -> 003f ffff
+ *     Common memory:     0040 0000 -> 007f ffff
+ *     I/O memory:        0080 0000 -> 00bf ffff
+ *     True IDE Mode:     00c0 0000 -> 00df ffff
+ *     Alt IDE Mode:      00e0 0000 -> 00ff ffff
+ *
+ * Only True IDE and Alt True IDE mode are needed for this driver.
+ *
+ *     True IDE mode     => CS0 = 0, CS1 = 1 (cmd, error, stat, etc)
+ *     Alt True IDE mode => CS0 = 1, CS1 = 0 (ctl, alt_stat)
+ */
+#define CF_IDE_OFFSET    0x00c00000
+#define CF_ALT_IDE_OFFSET 0x00e00000
+#define CF_RES_SIZE      2048
+
+/*
+ * Define DEBUG_BUS if you are doing debugging of your own EBI -> PATA
+ * adaptor with a logic analyzer or similar.
+ */
+#undef DEBUG_BUS
+
+/*
+ * ATA PIO modes
+ *
+ *     Name    | Mb/s  | Min cycle time | Mask
+ *     --------+-------+----------------+--------
+ *     Mode 0  | 3.3   | 600 ns         | 0x01
+ *     Mode 1  | 5.2   | 383 ns         | 0x03
+ *     Mode 2  | 8.3   | 240 ns         | 0x07
+ *     Mode 3  | 11.1  | 180 ns         | 0x0f
+ *     Mode 4  | 16.7  | 120 ns         | 0x1f
+ */
+#define PIO_MASK (0x1f)
+
+/*
+ * Struct containing private information about device.
+ */
+struct at32_ide_info {
+       unsigned int            irq;
+       struct resource         res_ide;
+       struct resource         res_alt;
+       void __iomem            *ide_addr;
+       void __iomem            *alt_addr;
+       unsigned int            cs;
+       struct smc_config       smc;
+};
+
+/*
+ * Setup SMC for the given ATA timing.
+ */
+static int pata_at32_setup_timing(struct device *dev,
+                                 struct at32_ide_info *info,
+                                 const struct ata_timing *timing)
+{
+       /* These two values are found through testing */
+       const int min_recover = 25;
+       const int ncs_hold    = 15;
+
+       struct smc_config *smc = &info->smc;
+
+       int active;
+       int recover;
+
+       /* Total cycle time */
+       smc->read_cycle = timing->cyc8b;
+
+       /* DIOR <= CFIOR timings */
+       smc->nrd_setup = timing->setup;
+       smc->nrd_pulse = timing->act8b;
+
+       /* Compute recover, extend total cycle if needed */
+       active  = smc->nrd_setup + smc->nrd_pulse;
+       recover = smc->read_cycle - active;
+
+       if (recover < min_recover) {
+               smc->read_cycle = active + min_recover;
+               recover = min_recover;
+       }
+
+       /* (CS0, CS1, DIR, OE) <= (CFCE1, CFCE2, CFRNW, NCSX) timings */
+       smc->ncs_read_setup  = 0;
+       smc->ncs_read_pulse  = active + ncs_hold;
+
+       /* Write timings same as read timings */
+       smc->write_cycle = smc->read_cycle;
+       smc->nwe_setup = smc->nrd_setup;
+       smc->nwe_pulse = smc->nrd_pulse;
+       smc->ncs_write_setup = smc->ncs_read_setup;
+       smc->ncs_write_pulse = smc->ncs_read_pulse;
+
+       /* Do some debugging output */
+       dev_dbg(dev, "SMC: C=%d S=%d P=%d R=%d NCSS=%d NCSP=%d NCSR=%d\n",
+               smc->read_cycle, smc->nrd_setup, smc->nrd_pulse,
+               recover, smc->ncs_read_setup, smc->ncs_read_pulse,
+               smc->read_cycle - smc->ncs_read_pulse);
+
+       /* Finally, configure the SMC */
+       return smc_set_configuration(info->cs, smc);
+}
+
+/*
+ * Procedures for libATA.
+ */
+static void pata_at32_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+       struct ata_timing timing;
+       struct at32_ide_info *info = ap->host->private_data;
+
+       int ret;
+
+       /* Compute ATA timing */
+       ret = ata_timing_compute(adev, adev->pio_mode, &timing, 1000, 0);
+       if (ret) {
+               dev_warn(ap->dev, "Failed to compute ATA timing %d\n", ret);
+               return;
+       }
+
+       /* Setup SMC to ATA timing */
+       ret = pata_at32_setup_timing(ap->dev, info, &timing);
+       if (ret) {
+               dev_warn(ap->dev, "Failed to setup ATA timing %d\n", ret);
+               return;
+       }
+}
+
+static void pata_at32_irq_clear(struct ata_port *ap)
+{
+       /* No DMA controller yet */
+}
+
+static struct scsi_host_template at32_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 at32_port_ops = {
+       .port_disable           = ata_port_disable,
+       .set_piomode            = pata_at32_set_piomode,
+       .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,
+
+       .freeze                 = ata_bmdma_freeze,
+       .thaw                   = ata_bmdma_thaw,
+       .error_handler          = ata_bmdma_error_handler,
+       .post_internal_cmd      = ata_bmdma_post_internal_cmd,
+       .cable_detect           = ata_cable_40wire,
+
+       .qc_prep                = ata_qc_prep,
+       .qc_issue               = ata_qc_issue_prot,
+
+       .data_xfer              = ata_data_xfer,
+
+       .irq_clear              = pata_at32_irq_clear,
+       .irq_on                 = ata_irq_on,
+       .irq_ack                = ata_irq_ack,
+
+       .port_start             = ata_sff_port_start,
+};
+
+static int __init pata_at32_init_one(struct device *dev,
+                                    struct at32_ide_info *info)
+{
+       struct ata_host *host;
+       struct ata_port *ap;
+
+       host = ata_host_alloc(dev, 1);
+       if (!host)
+               return -ENOMEM;
+
+       ap = host->ports[0];
+
+       /* Setup ATA bindings */
+       ap->ops      = &at32_port_ops;
+       ap->pio_mask = PIO_MASK;
+       ap->flags    = ATA_FLAG_MMIO | ATA_FLAG_SLAVE_POSS
+               | ATA_FLAG_PIO_POLLING;
+
+       /*
+        * Since all 8-bit taskfile transfers has to go on the lower
+        * byte of the data bus and there is a bug in the SMC that
+        * makes it impossible to alter the bus width during runtime,
+        * we need to hardwire the address signals as follows:
+        *
+        *      A_IDE(2:0) <= A_EBI(3:1)
+        *
+        * This makes all addresses on the EBI even, thus all data
+        * will be on the lower byte of the data bus.  All addresses
+        * used by libATA need to be altered according to this.
+        */
+       ap->ioaddr.altstatus_addr = info->alt_addr + (0x06 << 1);
+       ap->ioaddr.ctl_addr       = info->alt_addr + (0x06 << 1);
+
+       ap->ioaddr.data_addr      = info->ide_addr + (ATA_REG_DATA << 1);
+       ap->ioaddr.error_addr     = info->ide_addr + (ATA_REG_ERR << 1);
+       ap->ioaddr.feature_addr   = info->ide_addr + (ATA_REG_FEATURE << 1);
+       ap->ioaddr.nsect_addr     = info->ide_addr + (ATA_REG_NSECT << 1);
+       ap->ioaddr.lbal_addr      = info->ide_addr + (ATA_REG_LBAL << 1);
+       ap->ioaddr.lbam_addr      = info->ide_addr + (ATA_REG_LBAM << 1);
+       ap->ioaddr.lbah_addr      = info->ide_addr + (ATA_REG_LBAH << 1);
+       ap->ioaddr.device_addr    = info->ide_addr + (ATA_REG_DEVICE << 1);
+       ap->ioaddr.status_addr    = info->ide_addr + (ATA_REG_STATUS << 1);
+       ap->ioaddr.command_addr   = info->ide_addr + (ATA_REG_CMD << 1);
+
+       /* Set info as private data of ATA host */
+       host->private_data = info;
+
+       /* Register ATA device and return */
+       return ata_host_activate(host, info->irq, ata_interrupt,
+                                IRQF_SHARED | IRQF_TRIGGER_RISING,
+                                &at32_sht);
+}
+
+/*
+ * This function may come in handy for people analyzing their own
+ * EBI -> PATA adaptors.
+ */
+#ifdef DEBUG_BUS
+
+static void __init pata_at32_debug_bus(struct device *dev,
+                                      struct at32_ide_info *info)
+{
+       const int d1 = 0xff;
+       const int d2 = 0x00;
+
+       int i;
+
+       /* Write 8-bit values (registers) */
+       iowrite8(d1, info->alt_addr + (0x06 << 1));
+       iowrite8(d2, info->alt_addr + (0x06 << 1));
+
+       for (i = 0; i < 8; i++) {
+               iowrite8(d1, info->ide_addr + (i << 1));
+               iowrite8(d2, info->ide_addr + (i << 1));
+       }
+
+       /* Write 16 bit values (data) */
+       iowrite16(d1,      info->ide_addr);
+       iowrite16(d1 << 8, info->ide_addr);
+
+       iowrite16(d1,      info->ide_addr);
+       iowrite16(d1 << 8, info->ide_addr);
+}
+
+#endif
+
+static int __init pata_at32_probe(struct platform_device *pdev)
+{
+       const struct ata_timing initial_timing =
+               {XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0};
+
+       struct device            *dev = &pdev->dev;
+       struct at32_ide_info     *info;
+       struct ide_platform_data *board = pdev->dev.platform_data;
+       struct resource          *res;
+
+       int irq;
+       int ret;
+
+       if (!board)
+               return -ENXIO;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENXIO;
+
+       /* Retrive IRQ */
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0)
+               return irq;
+
+       /* Setup struct containing private infomation */
+       info = kzalloc(sizeof(struct at32_ide_info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       memset(info, 0, sizeof(struct at32_ide_info));
+
+       info->irq = irq;
+       info->cs  = board->cs;
+
+       /* Request memory resources */
+       info->res_ide.start = res->start + CF_IDE_OFFSET;
+       info->res_ide.end   = info->res_ide.start + CF_RES_SIZE - 1;
+       info->res_ide.name  = "ide";
+       info->res_ide.flags = IORESOURCE_MEM;
+
+       ret = request_resource(res, &info->res_ide);
+       if (ret)
+               goto err_req_res_ide;
+
+       info->res_alt.start = res->start + CF_ALT_IDE_OFFSET;
+       info->res_alt.end   = info->res_alt.start + CF_RES_SIZE - 1;
+       info->res_alt.name  = "alt";
+       info->res_alt.flags = IORESOURCE_MEM;
+
+       ret = request_resource(res, &info->res_alt);
+       if (ret)
+               goto err_req_res_alt;
+
+       /* Setup non-timing elements of SMC */
+       info->smc.bus_width      = 2; /* 16 bit data bus */
+       info->smc.nrd_controlled = 1; /* Sample data on rising edge of NRD */
+       info->smc.nwe_controlled = 0; /* Drive data on falling edge of NCS */
+       info->smc.nwait_mode     = 3; /* NWAIT is in READY mode */
+       info->smc.byte_write     = 0; /* Byte select access type */
+       info->smc.tdf_mode       = 0; /* TDF optimization disabled */
+       info->smc.tdf_cycles     = 0; /* No TDF wait cycles */
+
+       /* Setup ATA timing */
+       ret = pata_at32_setup_timing(dev, info, &initial_timing);
+       if (ret)
+               goto err_setup_timing;
+
+       /* Setup ATA addresses */
+       ret = -ENOMEM;
+       info->ide_addr = devm_ioremap(dev, info->res_ide.start, 16);
+       info->alt_addr = devm_ioremap(dev, info->res_alt.start, 16);
+       if (!info->ide_addr || !info->alt_addr)
+               goto err_ioremap;
+
+#ifdef DEBUG_BUS
+       pata_at32_debug_bus(dev, info);
+#endif
+
+       /* Register ATA device */
+       ret = pata_at32_init_one(dev, info);
+       if (ret)
+               goto err_ata_device;
+
+       return 0;
+
+ err_ata_device:
+ err_ioremap:
+ err_setup_timing:
+       release_resource(&info->res_alt);
+ err_req_res_alt:
+       release_resource(&info->res_ide);
+ err_req_res_ide:
+       kfree(info);
+
+       return ret;
+}
+
+static int __exit pata_at32_remove(struct platform_device *pdev)
+{
+       struct ata_host *host = platform_get_drvdata(pdev);
+       struct at32_ide_info *info;
+
+       if (!host)
+               return 0;
+
+       info = host->private_data;
+       ata_host_detach(host);
+
+       if (!info)
+               return 0;
+
+       release_resource(&info->res_ide);
+       release_resource(&info->res_alt);
+
+       kfree(info);
+
+       return 0;
+}
+
+static struct platform_driver pata_at32_driver = {
+       .remove        = __exit_p(pata_at32_remove),
+       .driver        = {
+               .name  = "at32_ide",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init pata_at32_init(void)
+{
+       return platform_driver_probe(&pata_at32_driver, pata_at32_probe);
+}
+
+static void __exit pata_at32_exit(void)
+{
+       platform_driver_unregister(&pata_at32_driver);
+}
+
+module_init(pata_at32_init);
+module_exit(pata_at32_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("AVR32 SMC/CFC PATA Driver");
+MODULE_AUTHOR("Kristoffer Nyborg Gregertsen <kngregertsen@norway.atmel.com>");
+MODULE_VERSION(DRV_VERSION);
index 86f85a2cab7e3a8edd54244f995232e85919cea4..9623f52955306d690ff7f78713ff24a7f6de08db 100644 (file)
@@ -33,8 +33,9 @@ enum {
        ATIIXP_IDE_UDMA_MODE    = 0x56
 };
 
-static int atiixp_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int atiixp_pre_reset(struct ata_link *link, unsigned long deadline)
 {
+       struct ata_port *ap = link->ap;
        static const struct pci_bits atiixp_enable_bits[] = {
                { 0x48, 1, 0x01, 0x00 },
                { 0x48, 1, 0x08, 0x00 }
@@ -44,7 +45,7 @@ static int atiixp_pre_reset(struct ata_port *ap, unsigned long deadline)
        if (!pci_test_config_bits(pdev, &atiixp_enable_bits[ap->port_no]))
                return -ENOENT;
 
-       return ata_std_prereset(ap, deadline);
+       return ata_std_prereset(link, deadline);
 }
 
 static void atiixp_error_handler(struct ata_port *ap)
@@ -172,6 +173,9 @@ static void atiixp_set_dmamode(struct ata_port *ap, struct ata_device *adev)
  *
  *     When DMA begins we need to ensure that the UDMA control
  *     register for the channel is correctly set.
+ *
+ *     Note: The host lock held by the libata layer protects
+ *     us from two channels both trying to set DMA bits at once
  */
 
 static void atiixp_bmdma_start(struct ata_queued_cmd *qc)
@@ -198,6 +202,9 @@ static void atiixp_bmdma_start(struct ata_queued_cmd *qc)
  *
  *     DMA has completed. Clear the UDMA flag as the next operations will
  *     be PIO ones not UDMA data transfer.
+ *
+ *     Note: The host lock held by the libata layer protects
+ *     us from two channels both trying to set DMA bits at once
  */
 
 static void atiixp_bmdma_stop(struct ata_queued_cmd *qc)
@@ -232,7 +239,6 @@ static struct scsi_host_template atiixp_sht = {
 };
 
 static struct ata_port_operations atiixp_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = atiixp_set_piomode,
        .set_dmamode    = atiixp_set_dmamode,
        .mode_filter    = ata_pci_default_filter,
@@ -261,9 +267,8 @@ static struct ata_port_operations atiixp_port_ops = {
        .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,
+       .port_start     = ata_sff_port_start,
 };
 
 static int atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c
new file mode 100644 (file)
index 0000000..747549e
--- /dev/null
@@ -0,0 +1,1627 @@
+/*
+ * File:         drivers/ata/pata_bf54x.c
+ * Author:       Sonic Zhang <sonic.zhang@analog.com>
+ *
+ * Created:
+ * Description:  PATA Driver for blackfin 54x
+ *
+ * Modified:
+ *               Copyright 2007 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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; 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, see the file COPYING, or 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/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <linux/platform_device.h>
+#include <asm/dma.h>
+#include <asm/gpio.h>
+#include <asm/portmux.h>
+
+#define DRV_NAME               "pata-bf54x"
+#define DRV_VERSION            "0.9"
+
+#define ATA_REG_CTRL           0x0E
+#define ATA_REG_ALTSTATUS      ATA_REG_CTRL
+
+/* These are the offset of the controller's registers */
+#define ATAPI_OFFSET_CONTROL           0x00
+#define ATAPI_OFFSET_STATUS            0x04
+#define ATAPI_OFFSET_DEV_ADDR          0x08
+#define ATAPI_OFFSET_DEV_TXBUF         0x0c
+#define ATAPI_OFFSET_DEV_RXBUF         0x10
+#define ATAPI_OFFSET_INT_MASK          0x14
+#define ATAPI_OFFSET_INT_STATUS                0x18
+#define ATAPI_OFFSET_XFER_LEN          0x1c
+#define ATAPI_OFFSET_LINE_STATUS       0x20
+#define ATAPI_OFFSET_SM_STATE          0x24
+#define ATAPI_OFFSET_TERMINATE         0x28
+#define ATAPI_OFFSET_PIO_TFRCNT                0x2c
+#define ATAPI_OFFSET_DMA_TFRCNT                0x30
+#define ATAPI_OFFSET_UMAIN_TFRCNT      0x34
+#define ATAPI_OFFSET_UDMAOUT_TFRCNT    0x38
+#define ATAPI_OFFSET_REG_TIM_0         0x40
+#define ATAPI_OFFSET_PIO_TIM_0         0x44
+#define ATAPI_OFFSET_PIO_TIM_1         0x48
+#define ATAPI_OFFSET_MULTI_TIM_0       0x50
+#define ATAPI_OFFSET_MULTI_TIM_1       0x54
+#define ATAPI_OFFSET_MULTI_TIM_2       0x58
+#define ATAPI_OFFSET_ULTRA_TIM_0       0x60
+#define ATAPI_OFFSET_ULTRA_TIM_1       0x64
+#define ATAPI_OFFSET_ULTRA_TIM_2       0x68
+#define ATAPI_OFFSET_ULTRA_TIM_3       0x6c
+
+
+#define ATAPI_GET_CONTROL(base)\
+       bfin_read16(base + ATAPI_OFFSET_CONTROL)
+#define ATAPI_SET_CONTROL(base, val)\
+       bfin_write16(base + ATAPI_OFFSET_CONTROL, val)
+#define ATAPI_GET_STATUS(base)\
+       bfin_read16(base + ATAPI_OFFSET_STATUS)
+#define ATAPI_GET_DEV_ADDR(base)\
+       bfin_read16(base + ATAPI_OFFSET_DEV_ADDR)
+#define ATAPI_SET_DEV_ADDR(base, val)\
+       bfin_write16(base + ATAPI_OFFSET_DEV_ADDR, val)
+#define ATAPI_GET_DEV_TXBUF(base)\
+       bfin_read16(base + ATAPI_OFFSET_DEV_TXBUF)
+#define ATAPI_SET_DEV_TXBUF(base, val)\
+       bfin_write16(base + ATAPI_OFFSET_DEV_TXBUF, val)
+#define ATAPI_GET_DEV_RXBUF(base)\
+       bfin_read16(base + ATAPI_OFFSET_DEV_RXBUF)
+#define ATAPI_SET_DEV_RXBUF(base, val)\
+       bfin_write16(base + ATAPI_OFFSET_DEV_RXBUF, val)
+#define ATAPI_GET_INT_MASK(base)\
+       bfin_read16(base + ATAPI_OFFSET_INT_MASK)
+#define ATAPI_SET_INT_MASK(base, val)\
+       bfin_write16(base + ATAPI_OFFSET_INT_MASK, val)
+#define ATAPI_GET_INT_STATUS(base)\
+       bfin_read16(base + ATAPI_OFFSET_INT_STATUS)
+#define ATAPI_SET_INT_STATUS(base, val)\
+       bfin_write16(base + ATAPI_OFFSET_INT_STATUS, val)
+#define ATAPI_GET_XFER_LEN(base)\
+       bfin_read16(base + ATAPI_OFFSET_XFER_LEN)
+#define ATAPI_SET_XFER_LEN(base, val)\
+       bfin_write16(base + ATAPI_OFFSET_XFER_LEN, val)
+#define ATAPI_GET_LINE_STATUS(base)\
+       bfin_read16(base + ATAPI_OFFSET_LINE_STATUS)
+#define ATAPI_GET_SM_STATE(base)\
+       bfin_read16(base + ATAPI_OFFSET_SM_STATE)
+#define ATAPI_GET_TERMINATE(base)\
+       bfin_read16(base + ATAPI_OFFSET_TERMINATE)
+#define ATAPI_SET_TERMINATE(base, val)\
+       bfin_write16(base + ATAPI_OFFSET_TERMINATE, val)
+#define ATAPI_GET_PIO_TFRCNT(base)\
+       bfin_read16(base + ATAPI_OFFSET_PIO_TFRCNT)
+#define ATAPI_GET_DMA_TFRCNT(base)\
+       bfin_read16(base + ATAPI_OFFSET_DMA_TFRCNT)
+#define ATAPI_GET_UMAIN_TFRCNT(base)\
+       bfin_read16(base + ATAPI_OFFSET_UMAIN_TFRCNT)
+#define ATAPI_GET_UDMAOUT_TFRCNT(base)\
+       bfin_read16(base + ATAPI_OFFSET_UDMAOUT_TFRCNT)
+#define ATAPI_GET_REG_TIM_0(base)\
+       bfin_read16(base + ATAPI_OFFSET_REG_TIM_0)
+#define ATAPI_SET_REG_TIM_0(base, val)\
+       bfin_write16(base + ATAPI_OFFSET_REG_TIM_0, val)
+#define ATAPI_GET_PIO_TIM_0(base)\
+       bfin_read16(base + ATAPI_OFFSET_PIO_TIM_0)
+#define ATAPI_SET_PIO_TIM_0(base, val)\
+       bfin_write16(base + ATAPI_OFFSET_PIO_TIM_0, val)
+#define ATAPI_GET_PIO_TIM_1(base)\
+       bfin_read16(base + ATAPI_OFFSET_PIO_TIM_1)
+#define ATAPI_SET_PIO_TIM_1(base, val)\
+       bfin_write16(base + ATAPI_OFFSET_PIO_TIM_1, val)
+#define ATAPI_GET_MULTI_TIM_0(base)\
+       bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_0)
+#define ATAPI_SET_MULTI_TIM_0(base, val)\
+       bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_0, val)
+#define ATAPI_GET_MULTI_TIM_1(base)\
+       bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_1)
+#define ATAPI_SET_MULTI_TIM_1(base, val)\
+       bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_1, val)
+#define ATAPI_GET_MULTI_TIM_2(base)\
+       bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_2)
+#define ATAPI_SET_MULTI_TIM_2(base, val)\
+       bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_2, val)
+#define ATAPI_GET_ULTRA_TIM_0(base)\
+       bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_0)
+#define ATAPI_SET_ULTRA_TIM_0(base, val)\
+       bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_0, val)
+#define ATAPI_GET_ULTRA_TIM_1(base)\
+       bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_1)
+#define ATAPI_SET_ULTRA_TIM_1(base, val)\
+       bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_1, val)
+#define ATAPI_GET_ULTRA_TIM_2(base)\
+       bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_2)
+#define ATAPI_SET_ULTRA_TIM_2(base, val)\
+       bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_2, val)
+#define ATAPI_GET_ULTRA_TIM_3(base)\
+       bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_3)
+#define ATAPI_SET_ULTRA_TIM_3(base, val)\
+       bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_3, val)
+
+/**
+ * PIO Mode - Frequency compatibility
+ */
+/* mode: 0         1         2         3         4 */
+static const u32 pio_fsclk[] =
+{ 33333333, 33333333, 33333333, 33333333, 33333333 };
+
+/**
+ * MDMA Mode - Frequency compatibility
+ */
+/*               mode:      0         1         2        */
+static const u32 mdma_fsclk[] = { 33333333, 33333333, 33333333 };
+
+/**
+ * UDMA Mode - Frequency compatibility
+ *
+ * UDMA5 - 100 MB/s   - SCLK  = 133 MHz
+ * UDMA4 - 66 MB/s    - SCLK >=  80 MHz
+ * UDMA3 - 44.4 MB/s  - SCLK >=  50 MHz
+ * UDMA2 - 33 MB/s    - SCLK >=  40 MHz
+ */
+/* mode: 0         1         2         3         4          5 */
+static const u32 udma_fsclk[] =
+{ 33333333, 33333333, 40000000, 50000000, 80000000, 133333333 };
+
+/**
+ * Register transfer timing table
+ */
+/*               mode:       0    1    2    3    4    */
+/* Cycle Time                     */
+static const u32 reg_t0min[]   = { 600, 383, 330, 180, 120 };
+/* DIOR/DIOW to end cycle         */
+static const u32 reg_t2min[]   = { 290, 290, 290, 70,  25  };
+/* DIOR/DIOW asserted pulse width */
+static const u32 reg_teocmin[] = { 290, 290, 290, 80,  70  };
+
+/**
+ * PIO timing table
+ */
+/*               mode:       0    1    2    3    4    */
+/* Cycle Time                     */
+static const u32 pio_t0min[]   = { 600, 383, 240, 180, 120 };
+/* Address valid to DIOR/DIORW    */
+static const u32 pio_t1min[]   = { 70,  50,  30,  30,  25  };
+/* DIOR/DIOW to end cycle         */
+static const u32 pio_t2min[]   = { 165, 125, 100, 80,  70  };
+/* DIOR/DIOW asserted pulse width */
+static const u32 pio_teocmin[] = { 165, 125, 100, 70,  25  };
+/* DIOW data hold                 */
+static const u32 pio_t4min[]   = { 30,  20,  15,  10,  10  };
+
+/* ******************************************************************
+ * Multiword DMA timing table
+ * ******************************************************************
+ */
+/*               mode:       0   1    2        */
+/* Cycle Time                     */
+static const u32 mdma_t0min[]  = { 480, 150, 120 };
+/* DIOR/DIOW asserted pulse width */
+static const u32 mdma_tdmin[]  = { 215, 80,  70  };
+/* DMACK to read data released    */
+static const u32 mdma_thmin[]  = { 20,  15,  10  };
+/* DIOR/DIOW to DMACK hold        */
+static const u32 mdma_tjmin[]  = { 20,  5,   5   };
+/* DIOR negated pulse width       */
+static const u32 mdma_tkrmin[] = { 50,  50,  25  };
+/* DIOR negated pulse width       */
+static const u32 mdma_tkwmin[] = { 215, 50,  25  };
+/* CS[1:0] valid to DIOR/DIOW     */
+static const u32 mdma_tmmin[]  = { 50,  30,  25  };
+/* DMACK to read data released    */
+static const u32 mdma_tzmax[]  = { 20,  25,  25  };
+
+/**
+ * Ultra DMA timing table
+ */
+/*               mode:         0    1    2    3    4    5       */
+static const u32 udma_tcycmin[]  = { 112, 73,  54,  39,  25,  17 };
+static const u32 udma_tdvsmin[]  = { 70,  48,  31,  20,  7,   5  };
+static const u32 udma_tenvmax[]  = { 70,  70,  70,  55,  55,  50 };
+static const u32 udma_trpmin[]   = { 160, 125, 100, 100, 100, 85 };
+static const u32 udma_tmin[]     = { 5,   5,   5,   5,   3,   3  };
+
+
+static const u32 udma_tmlimin = 20;
+static const u32 udma_tzahmin = 20;
+static const u32 udma_tenvmin = 20;
+static const u32 udma_tackmin = 20;
+static const u32 udma_tssmin = 50;
+
+/**
+ *
+ *     Function:       num_clocks_min
+ *
+ *     Description:
+ *     calculate number of SCLK cycles to meet minimum timing
+ */
+static unsigned short num_clocks_min(unsigned long tmin,
+                               unsigned long fsclk)
+{
+       unsigned long tmp ;
+       unsigned short result;
+
+       tmp = tmin * (fsclk/1000/1000) / 1000;
+       result = (unsigned short)tmp;
+       if ((tmp*1000*1000) < (tmin*(fsclk/1000))) {
+               result++;
+       }
+
+       return result;
+}
+
+/**
+ *     bfin_set_piomode - Initialize host controller PATA PIO timings
+ *     @ap: Port whose timings we are configuring
+ *     @adev: um
+ *
+ *     Set PIO mode for device.
+ *
+ *     LOCKING:
+ *     None (inherited from caller).
+ */
+
+static void bfin_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+       int mode = adev->pio_mode - XFER_PIO_0;
+       void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+       unsigned int fsclk = get_sclk();
+       unsigned short teoc_reg, t2_reg, teoc_pio;
+       unsigned short t4_reg, t2_pio, t1_reg;
+       unsigned short n0, n6, t6min = 5;
+
+       /* the most restrictive timing value is t6 and tc, the DIOW - data hold
+       * If one SCLK pulse is longer than this minimum value then register
+       * transfers cannot be supported at this frequency.
+       */
+       n6 = num_clocks_min(t6min, fsclk);
+       if (mode >= 0 && mode <= 4 && n6 >= 1) {
+               pr_debug("set piomode: mode=%d, fsclk=%ud\n", mode, fsclk);
+               /* calculate the timing values for register transfers. */
+               while (mode > 0 && pio_fsclk[mode] > fsclk)
+                       mode--;
+
+               /* DIOR/DIOW to end cycle time */
+               t2_reg = num_clocks_min(reg_t2min[mode], fsclk);
+               /* DIOR/DIOW asserted pulse width */
+               teoc_reg = num_clocks_min(reg_teocmin[mode], fsclk);
+               /* Cycle Time */
+               n0  = num_clocks_min(reg_t0min[mode], fsclk);
+
+               /* increase t2 until we meed the minimum cycle length */
+               if (t2_reg + teoc_reg < n0)
+                       t2_reg = n0 - teoc_reg;
+
+               /* calculate the timing values for pio transfers. */
+
+               /* DIOR/DIOW to end cycle time */
+               t2_pio = num_clocks_min(pio_t2min[mode], fsclk);
+               /* DIOR/DIOW asserted pulse width */
+               teoc_pio = num_clocks_min(pio_teocmin[mode], fsclk);
+               /* Cycle Time */
+               n0  = num_clocks_min(pio_t0min[mode], fsclk);
+
+               /* increase t2 until we meed the minimum cycle length */
+               if (t2_pio + teoc_pio < n0)
+                       t2_pio = n0 - teoc_pio;
+
+               /* Address valid to DIOR/DIORW */
+               t1_reg = num_clocks_min(pio_t1min[mode], fsclk);
+
+               /* DIOW data hold */
+               t4_reg = num_clocks_min(pio_t4min[mode], fsclk);
+
+               ATAPI_SET_REG_TIM_0(base, (teoc_reg<<8 | t2_reg));
+               ATAPI_SET_PIO_TIM_0(base, (t4_reg<<12 | t2_pio<<4 | t1_reg));
+               ATAPI_SET_PIO_TIM_1(base, teoc_pio);
+               if (mode > 2) {
+                       ATAPI_SET_CONTROL(base,
+                               ATAPI_GET_CONTROL(base) | IORDY_EN);
+               } else {
+                       ATAPI_SET_CONTROL(base,
+                               ATAPI_GET_CONTROL(base) & ~IORDY_EN);
+               }
+
+               /* Disable host ATAPI PIO interrupts */
+               ATAPI_SET_INT_MASK(base, ATAPI_GET_INT_MASK(base)
+                       & ~(PIO_DONE_MASK | HOST_TERM_XFER_MASK));
+               SSYNC();
+       }
+}
+
+/**
+ *     bfin_set_dmamode - Initialize host controller PATA DMA timings
+ *     @ap: Port whose timings we are configuring
+ *     @adev: um
+ *     @udma: udma mode, 0 - 6
+ *
+ *     Set UDMA mode for device.
+ *
+ *     LOCKING:
+ *     None (inherited from caller).
+ */
+
+static void bfin_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+       int mode;
+       void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+       unsigned long fsclk = get_sclk();
+       unsigned short tenv, tack, tcyc_tdvs, tdvs, tmli, tss, trp, tzah;
+       unsigned short tm, td, tkr, tkw, teoc, th;
+       unsigned short n0, nf, tfmin = 5;
+       unsigned short nmin, tcyc;
+
+       mode = adev->dma_mode - XFER_UDMA_0;
+       if (mode >= 0 && mode <= 5) {
+               pr_debug("set udmamode: mode=%d\n", mode);
+               /* the most restrictive timing value is t6 and tc,
+                * the DIOW - data hold. If one SCLK pulse is longer
+                * than this minimum value then register
+                * transfers cannot be supported at this frequency.
+                */
+               while (mode > 0 && udma_fsclk[mode] > fsclk)
+                       mode--;
+
+               nmin = num_clocks_min(udma_tmin[mode], fsclk);
+               if (nmin >= 1) {
+                       /* calculate the timing values for Ultra DMA. */
+                       tdvs = num_clocks_min(udma_tdvsmin[mode], fsclk);
+                       tcyc = num_clocks_min(udma_tcycmin[mode], fsclk);
+                       tcyc_tdvs = 2;
+
+                       /* increase tcyc - tdvs (tcyc_tdvs) until we meed
+                        * the minimum cycle length
+                        */
+                       if (tdvs + tcyc_tdvs < tcyc)
+                               tcyc_tdvs = tcyc - tdvs;
+
+                       /* Mow assign the values required for the timing
+                        * registers
+                        */
+                       if (tcyc_tdvs < 2)
+                               tcyc_tdvs = 2;
+
+                       if (tdvs < 2)
+                               tdvs = 2;
+
+                       tack = num_clocks_min(udma_tackmin, fsclk);
+                       tss = num_clocks_min(udma_tssmin, fsclk);
+                       tmli = num_clocks_min(udma_tmlimin, fsclk);
+                       tzah = num_clocks_min(udma_tzahmin, fsclk);
+                       trp = num_clocks_min(udma_trpmin[mode], fsclk);
+                       tenv = num_clocks_min(udma_tenvmin, fsclk);
+                       if (tenv <= udma_tenvmax[mode]) {
+                               ATAPI_SET_ULTRA_TIM_0(base, (tenv<<8 | tack));
+                               ATAPI_SET_ULTRA_TIM_1(base,
+                                       (tcyc_tdvs<<8 | tdvs));
+                               ATAPI_SET_ULTRA_TIM_2(base, (tmli<<8 | tss));
+                               ATAPI_SET_ULTRA_TIM_3(base, (trp<<8 | tzah));
+
+                               /* Enable host ATAPI Untra DMA interrupts */
+                               ATAPI_SET_INT_MASK(base,
+                                       ATAPI_GET_INT_MASK(base)
+                                       | UDMAIN_DONE_MASK
+                                       | UDMAOUT_DONE_MASK
+                                       | UDMAIN_TERM_MASK
+                                       | UDMAOUT_TERM_MASK);
+                       }
+               }
+       }
+
+       mode = adev->dma_mode - XFER_MW_DMA_0;
+       if (mode >= 0 && mode <= 2) {
+               pr_debug("set mdmamode: mode=%d\n", mode);
+               /* the most restrictive timing value is tf, the DMACK to
+                * read data released. If one SCLK pulse is longer than
+                * this maximum value then the MDMA mode
+                * cannot be supported at this frequency.
+                */
+               while (mode > 0 && mdma_fsclk[mode] > fsclk)
+                       mode--;
+
+               nf = num_clocks_min(tfmin, fsclk);
+               if (nf >= 1) {
+                       /* calculate the timing values for Multi-word DMA. */
+
+                       /* DIOR/DIOW asserted pulse width */
+                       td = num_clocks_min(mdma_tdmin[mode], fsclk);
+
+                       /* DIOR negated pulse width */
+                       tkw = num_clocks_min(mdma_tkwmin[mode], fsclk);
+
+                       /* Cycle Time */
+                       n0  = num_clocks_min(mdma_t0min[mode], fsclk);
+
+                       /* increase tk until we meed the minimum cycle length */
+                       if (tkw + td < n0)
+                               tkw = n0 - td;
+
+                       /* DIOR negated pulse width - read */
+                       tkr = num_clocks_min(mdma_tkrmin[mode], fsclk);
+                       /* CS{1:0] valid to DIOR/DIOW */
+                       tm = num_clocks_min(mdma_tmmin[mode], fsclk);
+                       /* DIOR/DIOW to DMACK hold */
+                       teoc = num_clocks_min(mdma_tjmin[mode], fsclk);
+                       /* DIOW Data hold */
+                       th = num_clocks_min(mdma_thmin[mode], fsclk);
+
+                       ATAPI_SET_MULTI_TIM_0(base, (tm<<8 | td));
+                       ATAPI_SET_MULTI_TIM_1(base, (tkr<<8 | tkw));
+                       ATAPI_SET_MULTI_TIM_2(base, (teoc<<8 | th));
+
+                       /* Enable host ATAPI Multi DMA interrupts */
+                       ATAPI_SET_INT_MASK(base, ATAPI_GET_INT_MASK(base)
+                               | MULTI_DONE_MASK | MULTI_TERM_MASK);
+                       SSYNC();
+               }
+       }
+       return;
+}
+
+/**
+ *
+ *    Function:       wait_complete
+ *
+ *    Description:    Waits the interrupt from device
+ *
+ */
+static inline void wait_complete(void __iomem *base, unsigned short mask)
+{
+       unsigned short status;
+       unsigned int i = 0;
+
+#define PATA_BF54X_WAIT_TIMEOUT                10000
+
+       for (i = 0; i < PATA_BF54X_WAIT_TIMEOUT; i++) {
+               status = ATAPI_GET_INT_STATUS(base) & mask;
+               if (status)
+                       break;
+       }
+
+       ATAPI_SET_INT_STATUS(base, mask);
+}
+
+/**
+ *
+ *    Function:       write_atapi_register
+ *
+ *    Description:    Writes to ATA Device Resgister
+ *
+ */
+
+static void write_atapi_register(void __iomem *base,
+               unsigned long ata_reg, unsigned short value)
+{
+       /* Program the ATA_DEV_TXBUF register with write data (to be
+        * written into the device).
+        */
+       ATAPI_SET_DEV_TXBUF(base, value);
+
+       /* Program the ATA_DEV_ADDR register with address of the
+        * device register (0x01 to 0x0F).
+        */
+       ATAPI_SET_DEV_ADDR(base, ata_reg);
+
+       /* Program the ATA_CTRL register with dir set to write (1)
+        */
+       ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | XFER_DIR));
+
+       /* ensure PIO DMA is not set */
+       ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA));
+
+       /* and start the transfer */
+       ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START));
+
+       /* Wait for the interrupt to indicate the end of the transfer.
+        * (We need to wait on and clear rhe ATA_DEV_INT interrupt status)
+        */
+       wait_complete(base, PIO_DONE_INT);
+}
+
+/**
+ *
+ *     Function:       read_atapi_register
+ *
+ *Description:    Reads from ATA Device Resgister
+ *
+ */
+
+static unsigned short read_atapi_register(void __iomem *base,
+               unsigned long ata_reg)
+{
+       /* Program the ATA_DEV_ADDR register with address of the
+        * device register (0x01 to 0x0F).
+        */
+       ATAPI_SET_DEV_ADDR(base, ata_reg);
+
+       /* Program the ATA_CTRL register with dir set to read (0) and
+        */
+       ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~XFER_DIR));
+
+       /* ensure PIO DMA is not set */
+       ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA));
+
+       /* and start the transfer */
+       ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START));
+
+       /* Wait for the interrupt to indicate the end of the transfer.
+        * (PIO_DONE interrupt is set and it doesn't seem to matter
+        * that we don't clear it)
+        */
+       wait_complete(base, PIO_DONE_INT);
+
+       /* Read the ATA_DEV_RXBUF register with write data (to be
+        * written into the device).
+        */
+       return ATAPI_GET_DEV_RXBUF(base);
+}
+
+/**
+ *
+ *    Function:       write_atapi_register_data
+ *
+ *    Description:    Writes to ATA Device Resgister
+ *
+ */
+
+static void write_atapi_data(void __iomem *base,
+               int len, unsigned short *buf)
+{
+       int i;
+
+       /* Set transfer length to 1 */
+       ATAPI_SET_XFER_LEN(base, 1);
+
+       /* Program the ATA_DEV_ADDR register with address of the
+        * ATA_REG_DATA
+        */
+       ATAPI_SET_DEV_ADDR(base, ATA_REG_DATA);
+
+       /* Program the ATA_CTRL register with dir set to write (1)
+        */
+       ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | XFER_DIR));
+
+       /* ensure PIO DMA is not set */
+       ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA));
+
+       for (i = 0; i < len; i++) {
+               /* Program the ATA_DEV_TXBUF register with write data (to be
+                * written into the device).
+                */
+               ATAPI_SET_DEV_TXBUF(base, buf[i]);
+
+               /* and start the transfer */
+               ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START));
+
+               /* Wait for the interrupt to indicate the end of the transfer.
+                * (We need to wait on and clear rhe ATA_DEV_INT
+                * interrupt status)
+                */
+               wait_complete(base, PIO_DONE_INT);
+       }
+}
+
+/**
+ *
+ *     Function:       read_atapi_register_data
+ *
+ *     Description:    Reads from ATA Device Resgister
+ *
+ */
+
+static void read_atapi_data(void __iomem *base,
+               int len, unsigned short *buf)
+{
+       int i;
+
+       /* Set transfer length to 1 */
+       ATAPI_SET_XFER_LEN(base, 1);
+
+       /* Program the ATA_DEV_ADDR register with address of the
+        * ATA_REG_DATA
+        */
+       ATAPI_SET_DEV_ADDR(base, ATA_REG_DATA);
+
+       /* Program the ATA_CTRL register with dir set to read (0) and
+        */
+       ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~XFER_DIR));
+
+       /* ensure PIO DMA is not set */
+       ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA));
+
+       for (i = 0; i < len; i++) {
+               /* and start the transfer */
+               ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START));
+
+               /* Wait for the interrupt to indicate the end of the transfer.
+                * (PIO_DONE interrupt is set and it doesn't seem to matter
+                * that we don't clear it)
+                */
+               wait_complete(base, PIO_DONE_INT);
+
+               /* Read the ATA_DEV_RXBUF register with write data (to be
+                * written into the device).
+                */
+               buf[i] = ATAPI_GET_DEV_RXBUF(base);
+       }
+}
+
+/**
+ *     bfin_tf_load - send taskfile registers to host controller
+ *     @ap: Port to which output is sent
+ *     @tf: ATA taskfile register set
+ *
+ *     Note: Original code is ata_tf_load().
+ */
+
+static void bfin_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
+{
+       void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+       unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+
+       if (tf->ctl != ap->last_ctl) {
+               write_atapi_register(base, ATA_REG_CTRL, tf->ctl);
+               ap->last_ctl = tf->ctl;
+               ata_wait_idle(ap);
+       }
+
+       if (is_addr) {
+               if (tf->flags & ATA_TFLAG_LBA48) {
+                       write_atapi_register(base, ATA_REG_FEATURE,
+                                               tf->hob_feature);
+                       write_atapi_register(base, ATA_REG_NSECT,
+                                               tf->hob_nsect);
+                       write_atapi_register(base, ATA_REG_LBAL, tf->hob_lbal);
+                       write_atapi_register(base, ATA_REG_LBAM, tf->hob_lbam);
+                       write_atapi_register(base, ATA_REG_LBAH, tf->hob_lbah);
+                       pr_debug("hob: feat 0x%X nsect 0x%X, lba 0x%X "
+                                "0x%X 0x%X\n",
+                               tf->hob_feature,
+                               tf->hob_nsect,
+                               tf->hob_lbal,
+                               tf->hob_lbam,
+                               tf->hob_lbah);
+               }
+
+               write_atapi_register(base, ATA_REG_FEATURE, tf->feature);
+               write_atapi_register(base, ATA_REG_NSECT, tf->nsect);
+               write_atapi_register(base, ATA_REG_LBAL, tf->lbal);
+               write_atapi_register(base, ATA_REG_LBAM, tf->lbam);
+               write_atapi_register(base, ATA_REG_LBAH, tf->lbah);
+               pr_debug("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
+                       tf->feature,
+                       tf->nsect,
+                       tf->lbal,
+                       tf->lbam,
+                       tf->lbah);
+       }
+
+       if (tf->flags & ATA_TFLAG_DEVICE) {
+               write_atapi_register(base, ATA_REG_DEVICE, tf->device);
+               pr_debug("device 0x%X\n", tf->device);
+       }
+
+       ata_wait_idle(ap);
+}
+
+/**
+ *     bfin_check_status - Read device status reg & clear interrupt
+ *     @ap: port where the device is
+ *
+ *     Note: Original code is ata_check_status().
+ */
+
+static u8 bfin_check_status(struct ata_port *ap)
+{
+       void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+       return read_atapi_register(base, ATA_REG_STATUS);
+}
+
+/**
+ *     bfin_tf_read - input device's ATA taskfile shadow registers
+ *     @ap: Port from which input is read
+ *     @tf: ATA taskfile register set for storing input
+ *
+ *     Note: Original code is ata_tf_read().
+ */
+
+static void bfin_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+       void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+
+       tf->command = bfin_check_status(ap);
+       tf->feature = read_atapi_register(base, ATA_REG_ERR);
+       tf->nsect = read_atapi_register(base, ATA_REG_NSECT);
+       tf->lbal = read_atapi_register(base, ATA_REG_LBAL);
+       tf->lbam = read_atapi_register(base, ATA_REG_LBAM);
+       tf->lbah = read_atapi_register(base, ATA_REG_LBAH);
+       tf->device = read_atapi_register(base, ATA_REG_DEVICE);
+
+       if (tf->flags & ATA_TFLAG_LBA48) {
+               write_atapi_register(base, ATA_REG_CTRL, tf->ctl | ATA_HOB);
+               tf->hob_feature = read_atapi_register(base, ATA_REG_ERR);
+               tf->hob_nsect = read_atapi_register(base, ATA_REG_NSECT);
+               tf->hob_lbal = read_atapi_register(base, ATA_REG_LBAL);
+               tf->hob_lbam = read_atapi_register(base, ATA_REG_LBAM);
+               tf->hob_lbah = read_atapi_register(base, ATA_REG_LBAH);
+       }
+}
+
+/**
+ *     bfin_exec_command - issue ATA command to host controller
+ *     @ap: port to which command is being issued
+ *     @tf: ATA taskfile register set
+ *
+ *     Note: Original code is ata_exec_command().
+ */
+
+static void bfin_exec_command(struct ata_port *ap,
+                             const struct ata_taskfile *tf)
+{
+       void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+       pr_debug("ata%u: cmd 0x%X\n", ap->print_id, tf->command);
+
+       write_atapi_register(base, ATA_REG_CMD, tf->command);
+       ata_pause(ap);
+}
+
+/**
+ *     bfin_check_altstatus - Read device alternate status reg
+ *     @ap: port where the device is
+ */
+
+static u8 bfin_check_altstatus(struct ata_port *ap)
+{
+       void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+       return read_atapi_register(base, ATA_REG_ALTSTATUS);
+}
+
+/**
+ *     bfin_std_dev_select - Select device 0/1 on ATA bus
+ *     @ap: ATA channel to manipulate
+ *     @device: ATA device (numbered from zero) to select
+ *
+ *     Note: Original code is ata_std_dev_select().
+ */
+
+static void bfin_std_dev_select(struct ata_port *ap, unsigned int device)
+{
+       void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+       u8 tmp;
+
+       if (device == 0)
+               tmp = ATA_DEVICE_OBS;
+       else
+               tmp = ATA_DEVICE_OBS | ATA_DEV1;
+
+       write_atapi_register(base, ATA_REG_DEVICE, tmp);
+       ata_pause(ap);
+}
+
+/**
+ *     bfin_bmdma_setup - Set up IDE DMA transaction
+ *     @qc: Info associated with this ATA transaction.
+ *
+ *     Note: Original code is ata_bmdma_setup().
+ */
+
+static void bfin_bmdma_setup(struct ata_queued_cmd *qc)
+{
+       unsigned short config = WDSIZE_16;
+       struct scatterlist *sg;
+
+       pr_debug("in atapi dma setup\n");
+       /* Program the ATA_CTRL register with dir */
+       if (qc->tf.flags & ATA_TFLAG_WRITE) {
+               /* fill the ATAPI DMA controller */
+               set_dma_config(CH_ATAPI_TX, config);
+               set_dma_x_modify(CH_ATAPI_TX, 2);
+               ata_for_each_sg(sg, qc) {
+                       set_dma_start_addr(CH_ATAPI_TX, sg_dma_address(sg));
+                       set_dma_x_count(CH_ATAPI_TX, sg_dma_len(sg) >> 1);
+               }
+       } else {
+               config |= WNR;
+               /* fill the ATAPI DMA controller */
+               set_dma_config(CH_ATAPI_RX, config);
+               set_dma_x_modify(CH_ATAPI_RX, 2);
+               ata_for_each_sg(sg, qc) {
+                       set_dma_start_addr(CH_ATAPI_RX, sg_dma_address(sg));
+                       set_dma_x_count(CH_ATAPI_RX, sg_dma_len(sg) >> 1);
+               }
+       }
+}
+
+/**
+ *     bfin_bmdma_start - Start an IDE DMA transaction
+ *     @qc: Info associated with this ATA transaction.
+ *
+ *     Note: Original code is ata_bmdma_start().
+ */
+
+static void bfin_bmdma_start(struct ata_queued_cmd *qc)
+{
+       struct ata_port *ap = qc->ap;
+       void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+       struct scatterlist *sg;
+
+       pr_debug("in atapi dma start\n");
+       if (!(ap->udma_mask || ap->mwdma_mask))
+               return;
+
+       /* start ATAPI DMA controller*/
+       if (qc->tf.flags & ATA_TFLAG_WRITE) {
+               /*
+                * On blackfin arch, uncacheable memory is not
+                * allocated with flag GFP_DMA. DMA buffer from
+                * common kenel code should be flushed if WB
+                * data cache is enabled. Otherwise, this loop
+                * is an empty loop and optimized out.
+                */
+               ata_for_each_sg(sg, qc) {
+                       flush_dcache_range(sg_dma_address(sg),
+                               sg_dma_address(sg) + sg_dma_len(sg));
+               }
+               enable_dma(CH_ATAPI_TX);
+               pr_debug("enable udma write\n");
+
+               /* Send ATA DMA write command */
+               bfin_exec_command(ap, &qc->tf);
+
+               /* set ATA DMA write direction */
+               ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base)
+                       | XFER_DIR));
+       } else {
+               enable_dma(CH_ATAPI_RX);
+               pr_debug("enable udma read\n");
+
+               /* Send ATA DMA read command */
+               bfin_exec_command(ap, &qc->tf);
+
+               /* set ATA DMA read direction */
+               ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base)
+                       & ~XFER_DIR));
+       }
+
+       /* Reset all transfer count */
+       ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | TFRCNT_RST);
+
+               /* Set transfer length to buffer len */
+       ata_for_each_sg(sg, qc) {
+               ATAPI_SET_XFER_LEN(base, (sg_dma_len(sg) >> 1));
+       }
+
+       /* Enable ATA DMA operation*/
+       if (ap->udma_mask)
+               ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base)
+                       | ULTRA_START);
+       else
+               ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base)
+                       | MULTI_START);
+}
+
+/**
+ *     bfin_bmdma_stop - Stop IDE DMA transfer
+ *     @qc: Command we are ending DMA for
+ */
+
+static void bfin_bmdma_stop(struct ata_queued_cmd *qc)
+{
+       struct ata_port *ap = qc->ap;
+       struct scatterlist *sg;
+
+       pr_debug("in atapi dma stop\n");
+       if (!(ap->udma_mask || ap->mwdma_mask))
+               return;
+
+       /* stop ATAPI DMA controller*/
+       if (qc->tf.flags & ATA_TFLAG_WRITE)
+               disable_dma(CH_ATAPI_TX);
+       else {
+               disable_dma(CH_ATAPI_RX);
+               if (ap->hsm_task_state & HSM_ST_LAST) {
+                       /*
+                        * On blackfin arch, uncacheable memory is not
+                        * allocated with flag GFP_DMA. DMA buffer from
+                        * common kenel code should be invalidated if
+                        * data cache is enabled. Otherwise, this loop
+                        * is an empty loop and optimized out.
+                        */
+                       ata_for_each_sg(sg, qc) {
+                               invalidate_dcache_range(
+                                       sg_dma_address(sg),
+                                       sg_dma_address(sg)
+                                       + sg_dma_len(sg));
+                       }
+               }
+       }
+}
+
+/**
+ *     bfin_devchk - PATA device presence detection
+ *     @ap: ATA channel to examine
+ *     @device: Device to examine (starting at zero)
+ *
+ *     Note: Original code is ata_devchk().
+ */
+
+static unsigned int bfin_devchk(struct ata_port *ap,
+                               unsigned int device)
+{
+       void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+       u8 nsect, lbal;
+
+       bfin_std_dev_select(ap, device);
+
+       write_atapi_register(base, ATA_REG_NSECT, 0x55);
+       write_atapi_register(base, ATA_REG_LBAL, 0xaa);
+
+       write_atapi_register(base, ATA_REG_NSECT, 0xaa);
+       write_atapi_register(base, ATA_REG_LBAL, 0x55);
+
+       write_atapi_register(base, ATA_REG_NSECT, 0x55);
+       write_atapi_register(base, ATA_REG_LBAL, 0xaa);
+
+       nsect = read_atapi_register(base, ATA_REG_NSECT);
+       lbal = read_atapi_register(base, ATA_REG_LBAL);
+
+       if ((nsect == 0x55) && (lbal == 0xaa))
+               return 1;       /* we found a device */
+
+       return 0;               /* nothing found */
+}
+
+/**
+ *     bfin_bus_post_reset - PATA device post reset
+ *
+ *     Note: Original code is ata_bus_post_reset().
+ */
+
+static void bfin_bus_post_reset(struct ata_port *ap, unsigned int devmask)
+{
+       void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+       unsigned int dev0 = devmask & (1 << 0);
+       unsigned int dev1 = devmask & (1 << 1);
+       unsigned long timeout;
+
+       /* if device 0 was found in ata_devchk, wait for its
+        * BSY bit to clear
+        */
+       if (dev0)
+               ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+
+       /* if device 1 was found in ata_devchk, wait for
+        * register access, then wait for BSY to clear
+        */
+       timeout = jiffies + ATA_TMOUT_BOOT;
+       while (dev1) {
+               u8 nsect, lbal;
+
+               bfin_std_dev_select(ap, 1);
+               nsect = read_atapi_register(base, ATA_REG_NSECT);
+               lbal = read_atapi_register(base, ATA_REG_LBAL);
+               if ((nsect == 1) && (lbal == 1))
+                       break;
+               if (time_after(jiffies, timeout)) {
+                       dev1 = 0;
+                       break;
+               }
+               msleep(50);     /* give drive a breather */
+       }
+       if (dev1)
+               ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+
+       /* is all this really necessary? */
+       bfin_std_dev_select(ap, 0);
+       if (dev1)
+               bfin_std_dev_select(ap, 1);
+       if (dev0)
+               bfin_std_dev_select(ap, 0);
+}
+
+/**
+ *     bfin_bus_softreset - PATA device software reset
+ *
+ *     Note: Original code is ata_bus_softreset().
+ */
+
+static unsigned int bfin_bus_softreset(struct ata_port *ap,
+                                      unsigned int devmask)
+{
+       void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+
+       /* software reset.  causes dev0 to be selected */
+       write_atapi_register(base, ATA_REG_CTRL, ap->ctl);
+       udelay(20);
+       write_atapi_register(base, ATA_REG_CTRL, ap->ctl | ATA_SRST);
+       udelay(20);
+       write_atapi_register(base, ATA_REG_CTRL, ap->ctl);
+
+       /* spec mandates ">= 2ms" before checking status.
+        * We wait 150ms, because that was the magic delay used for
+        * ATAPI devices in Hale Landis's ATADRVR, for the period of time
+        * between when the ATA command register is written, and then
+        * status is checked.  Because waiting for "a while" before
+        * checking status is fine, post SRST, we perform this magic
+        * delay here as well.
+        *
+        * Old drivers/ide uses the 2mS rule and then waits for ready
+        */
+       msleep(150);
+
+       /* Before we perform post reset processing we want to see if
+        * the bus shows 0xFF because the odd clown forgets the D7
+        * pulldown resistor.
+        */
+       if (bfin_check_status(ap) == 0xFF)
+               return 0;
+
+       bfin_bus_post_reset(ap, devmask);
+
+       return 0;
+}
+
+/**
+ *     bfin_std_softreset - reset host port via ATA SRST
+ *     @ap: port to reset
+ *     @classes: resulting classes of attached devices
+ *
+ *     Note: Original code is ata_std_softreset().
+ */
+
+static int bfin_std_softreset(struct ata_port *ap, unsigned int *classes,
+               unsigned long deadline)
+{
+       unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
+       unsigned int devmask = 0, err_mask;
+       u8 err;
+
+       if (ata_port_offline(ap)) {
+               classes[0] = ATA_DEV_NONE;
+               goto out;
+       }
+
+       /* determine if device 0/1 are present */
+       if (bfin_devchk(ap, 0))
+               devmask |= (1 << 0);
+       if (slave_possible && bfin_devchk(ap, 1))
+               devmask |= (1 << 1);
+
+       /* select device 0 again */
+       bfin_std_dev_select(ap, 0);
+
+       /* issue bus reset */
+       err_mask = bfin_bus_softreset(ap, devmask);
+       if (err_mask) {
+               ata_port_printk(ap, KERN_ERR, "SRST failed (err_mask=0x%x)\n",
+                               err_mask);
+               return -EIO;
+       }
+
+       /* determine by signature whether we have ATA or ATAPI devices */
+       classes[0] = ata_dev_try_classify(ap, 0, &err);
+       if (slave_possible && err != 0x81)
+               classes[1] = ata_dev_try_classify(ap, 1, &err);
+
+ out:
+       return 0;
+}
+
+/**
+ *     bfin_bmdma_status - Read IDE DMA status
+ *     @ap: Port associated with this ATA transaction.
+ */
+
+static unsigned char bfin_bmdma_status(struct ata_port *ap)
+{
+       unsigned char host_stat = 0;
+       void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+       unsigned short int_status = ATAPI_GET_INT_STATUS(base);
+
+       if (ATAPI_GET_STATUS(base) & (MULTI_XFER_ON|ULTRA_XFER_ON)) {
+               host_stat = ATA_DMA_ACTIVE;
+       }
+       if (int_status & (MULTI_DONE_INT|UDMAIN_DONE_INT|UDMAOUT_DONE_INT)) {
+               host_stat = ATA_DMA_INTR;
+       }
+       if (int_status & (MULTI_TERM_INT|UDMAIN_TERM_INT|UDMAOUT_TERM_INT)) {
+               host_stat = ATA_DMA_ERR;
+       }
+
+       return host_stat;
+}
+
+/**
+ *     bfin_data_xfer - Transfer data by PIO
+ *     @adev: device for this I/O
+ *     @buf: data buffer
+ *     @buflen: buffer length
+ *     @write_data: read/write
+ *
+ *     Note: Original code is ata_data_xfer().
+ */
+
+static void bfin_data_xfer(struct ata_device *adev, unsigned char *buf,
+                          unsigned int buflen, int write_data)
+{
+       struct ata_port *ap = adev->ap;
+       unsigned int words = buflen >> 1;
+       unsigned short *buf16 = (u16 *) buf;
+       void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+
+       /* Transfer multiple of 2 bytes */
+       if (write_data) {
+               write_atapi_data(base, words, buf16);
+       } else {
+               read_atapi_data(base, words, buf16);
+       }
+
+       /* Transfer trailing 1 byte, if any. */
+       if (unlikely(buflen & 0x01)) {
+               unsigned short align_buf[1] = { 0 };
+               unsigned char *trailing_buf = buf + buflen - 1;
+
+               if (write_data) {
+                       memcpy(align_buf, trailing_buf, 1);
+                       write_atapi_data(base, 1, align_buf);
+               } else {
+                       read_atapi_data(base, 1, align_buf);
+                       memcpy(trailing_buf, align_buf, 1);
+               }
+       }
+}
+
+/**
+ *     bfin_irq_clear - Clear ATAPI interrupt.
+ *     @ap: Port associated with this ATA transaction.
+ *
+ *     Note: Original code is ata_bmdma_irq_clear().
+ */
+
+static void bfin_irq_clear(struct ata_port *ap)
+{
+       void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+
+       pr_debug("in atapi irq clear\n");
+       ATAPI_SET_INT_STATUS(base, 0x1FF);
+}
+
+/**
+ *     bfin_irq_on - Enable interrupts on a port.
+ *     @ap: Port on which interrupts are enabled.
+ *
+ *     Note: Original code is ata_irq_on().
+ */
+
+static unsigned char bfin_irq_on(struct ata_port *ap)
+{
+       void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+       u8 tmp;
+
+       pr_debug("in atapi irq on\n");
+       ap->ctl &= ~ATA_NIEN;
+       ap->last_ctl = ap->ctl;
+
+       write_atapi_register(base, ATA_REG_CTRL, ap->ctl);
+       tmp = ata_wait_idle(ap);
+
+       bfin_irq_clear(ap);
+
+       return tmp;
+}
+
+/**
+ *     bfin_irq_ack - Acknowledge a device interrupt.
+ *     @ap: Port on which interrupts are enabled.
+ *
+ *     Note: Original code is ata_irq_ack().
+ */
+
+static unsigned char bfin_irq_ack(struct ata_port *ap, unsigned int chk_drq)
+{
+       void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+       unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY;
+       unsigned char status;
+
+       pr_debug("in atapi irq ack\n");
+       status = ata_busy_wait(ap, bits, 1000);
+       if (status & bits)
+               if (ata_msg_err(ap))
+                       dev_err(ap->dev, "abnormal status 0x%X\n", status);
+
+       /* get controller status; clear intr, err bits */
+       ATAPI_SET_INT_STATUS(base, ATAPI_GET_INT_STATUS(base)|ATAPI_DEV_INT
+               | MULTI_DONE_INT | UDMAIN_DONE_INT | UDMAOUT_DONE_INT
+               | MULTI_TERM_INT | UDMAIN_TERM_INT | UDMAOUT_TERM_INT);
+
+       return bfin_bmdma_status(ap);
+}
+
+/**
+ *     bfin_bmdma_freeze - Freeze DMA controller port
+ *     @ap: port to freeze
+ *
+ *     Note: Original code is ata_bmdma_freeze().
+ */
+
+static void bfin_bmdma_freeze(struct ata_port *ap)
+{
+       void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+
+       pr_debug("in atapi dma freeze\n");
+       ap->ctl |= ATA_NIEN;
+       ap->last_ctl = ap->ctl;
+
+       write_atapi_register(base, ATA_REG_CTRL, ap->ctl);
+
+       /* Under certain circumstances, some controllers raise IRQ on
+        * ATA_NIEN manipulation.  Also, many controllers fail to mask
+        * previously pending IRQ on ATA_NIEN assertion.  Clear it.
+        */
+       ata_chk_status(ap);
+
+       bfin_irq_clear(ap);
+}
+
+/**
+ *     bfin_bmdma_thaw - Thaw DMA controller port
+ *     @ap: port to thaw
+ *
+ *     Note: Original code is ata_bmdma_thaw().
+ */
+
+void bfin_bmdma_thaw(struct ata_port *ap)
+{
+       bfin_check_status(ap);
+       bfin_irq_clear(ap);
+       bfin_irq_on(ap);
+}
+
+/**
+ *     bfin_std_postreset - standard postreset callback
+ *     @ap: the target ata_port
+ *     @classes: classes of attached devices
+ *
+ *     Note: Original code is ata_std_postreset().
+ */
+
+static void bfin_std_postreset(struct ata_port *ap, unsigned int *classes)
+{
+       void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+
+       /* re-enable interrupts */
+       bfin_irq_on(ap);
+
+       /* is double-select really necessary? */
+       if (classes[0] != ATA_DEV_NONE)
+               bfin_std_dev_select(ap, 1);
+       if (classes[1] != ATA_DEV_NONE)
+               bfin_std_dev_select(ap, 0);
+
+       /* bail out if no device is present */
+       if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) {
+               return;
+       }
+
+       /* set up device control */
+       write_atapi_register(base, ATA_REG_CTRL, ap->ctl);
+}
+
+/**
+ *     bfin_error_handler - Stock error handler for DMA controller
+ *     @ap: port to handle error for
+ */
+
+static void bfin_error_handler(struct ata_port *ap)
+{
+       ata_bmdma_drive_eh(ap, ata_std_prereset, bfin_std_softreset, NULL,
+                          bfin_std_postreset);
+}
+
+static void bfin_port_stop(struct ata_port *ap)
+{
+       pr_debug("in atapi port stop\n");
+       if (ap->udma_mask != 0 || ap->mwdma_mask != 0) {
+               free_dma(CH_ATAPI_RX);
+               free_dma(CH_ATAPI_TX);
+       }
+}
+
+static int bfin_port_start(struct ata_port *ap)
+{
+       pr_debug("in atapi port start\n");
+       if (!(ap->udma_mask || ap->mwdma_mask))
+               return 0;
+
+       if (request_dma(CH_ATAPI_RX, "BFIN ATAPI RX DMA") >= 0) {
+               if (request_dma(CH_ATAPI_TX,
+                       "BFIN ATAPI TX DMA") >= 0)
+                       return 0;
+
+               free_dma(CH_ATAPI_RX);
+       }
+
+       ap->udma_mask = 0;
+       ap->mwdma_mask = 0;
+       dev_err(ap->dev, "Unable to request ATAPI DMA!"
+               " Continue in PIO mode.\n");
+
+       return 0;
+}
+
+static struct scsi_host_template bfin_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           = SG_NONE,
+       .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,
+#ifdef CONFIG_PM
+       .resume                 = ata_scsi_device_resume,
+       .suspend                = ata_scsi_device_suspend,
+#endif
+};
+
+static const struct ata_port_operations bfin_pata_ops = {
+       .port_disable           = ata_port_disable,
+       .set_piomode            = bfin_set_piomode,
+       .set_dmamode            = bfin_set_dmamode,
+
+       .tf_load                = bfin_tf_load,
+       .tf_read                = bfin_tf_read,
+       .exec_command           = bfin_exec_command,
+       .check_status           = bfin_check_status,
+       .check_altstatus        = bfin_check_altstatus,
+       .dev_select             = bfin_std_dev_select,
+
+       .bmdma_setup            = bfin_bmdma_setup,
+       .bmdma_start            = bfin_bmdma_start,
+       .bmdma_stop             = bfin_bmdma_stop,
+       .bmdma_status           = bfin_bmdma_status,
+       .data_xfer              = bfin_data_xfer,
+
+       .qc_prep                = ata_noop_qc_prep,
+       .qc_issue               = ata_qc_issue_prot,
+
+       .freeze                 = bfin_bmdma_freeze,
+       .thaw                   = bfin_bmdma_thaw,
+       .error_handler          = bfin_error_handler,
+       .post_internal_cmd      = bfin_bmdma_stop,
+
+       .irq_handler            = ata_interrupt,
+       .irq_clear              = bfin_irq_clear,
+       .irq_on                 = bfin_irq_on,
+       .irq_ack                = bfin_irq_ack,
+
+       .port_start             = bfin_port_start,
+       .port_stop              = bfin_port_stop,
+};
+
+static struct ata_port_info bfin_port_info[] = {
+       {
+               .sht            = &bfin_sht,
+               .flags          = ATA_FLAG_SLAVE_POSS
+                               | ATA_FLAG_MMIO
+                               | ATA_FLAG_NO_LEGACY,
+               .pio_mask       = 0x1f, /* pio0-4 */
+               .mwdma_mask     = 0,
+#ifdef CONFIG_PATA_BF54X_DMA
+               .udma_mask      = ATA_UDMA5,
+#else
+               .udma_mask      = 0,
+#endif
+               .port_ops       = &bfin_pata_ops,
+       },
+};
+
+/**
+ *     bfin_reset_controller - initialize BF54x ATAPI controller.
+ */
+
+static int bfin_reset_controller(struct ata_host *host)
+{
+       void __iomem *base = (void __iomem *)host->ports[0]->ioaddr.ctl_addr;
+       int count;
+       unsigned short status;
+
+       /* Disable all ATAPI interrupts */
+       ATAPI_SET_INT_MASK(base, 0);
+       SSYNC();
+
+       /* Assert the RESET signal 25us*/
+       ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | DEV_RST);
+       udelay(30);
+
+       /* Negate the RESET signal for 2ms*/
+       ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) & ~DEV_RST);
+       msleep(2);
+
+       /* Wait on Busy flag to clear */
+       count = 10000000;
+       do {
+               status = read_atapi_register(base, ATA_REG_STATUS);
+       } while (count-- && (status & ATA_BUSY));
+
+       /* Enable only ATAPI Device interrupt */
+       ATAPI_SET_INT_MASK(base, 1);
+       SSYNC();
+
+       return (!count);
+}
+
+/**
+ *     atapi_io_port - define atapi peripheral port pins.
+ */
+static unsigned short atapi_io_port[] = {
+       P_ATAPI_RESET,
+       P_ATAPI_DIOR,
+       P_ATAPI_DIOW,
+       P_ATAPI_CS0,
+       P_ATAPI_CS1,
+       P_ATAPI_DMACK,
+       P_ATAPI_DMARQ,
+       P_ATAPI_INTRQ,
+       P_ATAPI_IORDY,
+       0
+};
+
+/**
+ *     bfin_atapi_probe        -       attach a bfin atapi interface
+ *     @pdev: platform device
+ *
+ *     Register a bfin atapi interface.
+ *
+ *
+ *     Platform devices are expected to contain 2 resources per port:
+ *
+ *             - I/O Base (IORESOURCE_IO)
+ *             - IRQ      (IORESOURCE_IRQ)
+ *
+ */
+static int __devinit bfin_atapi_probe(struct platform_device *pdev)
+{
+       int board_idx = 0;
+       struct resource *res;
+       struct ata_host *host;
+       const struct ata_port_info *ppi[] =
+               { &bfin_port_info[board_idx], NULL };
+
+       /*
+        * Simple resource validation ..
+        */
+       if (unlikely(pdev->num_resources != 2)) {
+               dev_err(&pdev->dev, "invalid number of resources\n");
+               return -EINVAL;
+       }
+
+       /*
+        * Get the register base first
+        */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL)
+               return -EINVAL;
+
+       /*
+        * Now that that's out of the way, wire up the port..
+        */
+       host = ata_host_alloc_pinfo(&pdev->dev, ppi, 1);
+       if (!host)
+               return -ENOMEM;
+
+       host->ports[0]->ioaddr.ctl_addr = (void *)res->start;
+
+       if (peripheral_request_list(atapi_io_port, "atapi-io-port")) {
+               dev_err(&pdev->dev, "Requesting Peripherals faild\n");
+               return -EFAULT;
+       }
+
+       if (bfin_reset_controller(host)) {
+               peripheral_free_list(atapi_io_port);
+               dev_err(&pdev->dev, "Fail to reset ATAPI device\n");
+               return -EFAULT;
+       }
+
+       if (ata_host_activate(host, platform_get_irq(pdev, 0),
+               ata_interrupt, IRQF_SHARED, &bfin_sht) != 0) {
+               peripheral_free_list(atapi_io_port);
+               dev_err(&pdev->dev, "Fail to attach ATAPI device\n");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+/**
+ *     bfin_atapi_remove       -       unplug a bfin atapi interface
+ *     @pdev: platform device
+ *
+ *     A bfin atapi device has been unplugged. Perform the needed
+ *     cleanup. Also called on module unload for any active devices.
+ */
+static int __devexit bfin_atapi_remove(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct ata_host *host = dev_get_drvdata(dev);
+
+       ata_host_detach(host);
+
+       peripheral_free_list(atapi_io_port);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+int bfin_atapi_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       return 0;
+}
+
+int bfin_atapi_resume(struct platform_device *pdev)
+{
+       return 0;
+}
+#endif
+
+static struct platform_driver bfin_atapi_driver = {
+       .probe                  = bfin_atapi_probe,
+       .remove                 = __devexit_p(bfin_atapi_remove),
+       .driver = {
+               .name           = DRV_NAME,
+               .owner          = THIS_MODULE,
+#ifdef CONFIG_PM
+               .suspend        = bfin_atapi_suspend,
+               .resume         = bfin_atapi_resume,
+#endif
+       },
+};
+
+static int __init bfin_atapi_init(void)
+{
+       pr_info("register bfin atapi driver\n");
+       return platform_driver_register(&bfin_atapi_driver);
+}
+
+static void __exit bfin_atapi_exit(void)
+{
+       platform_driver_unregister(&bfin_atapi_driver);
+}
+
+module_init(bfin_atapi_init);
+module_exit(bfin_atapi_exit);
+
+MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
+MODULE_DESCRIPTION("PATA driver for blackfin 54x ATAPI controller");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
index 0feb5ae8c4867fe48be92e2f784ba80df19ff392..43d198f909680f926464e1583e650166c193b435 100644 (file)
@@ -153,7 +153,7 @@ static int cmd640_port_start(struct ata_port *ap)
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        struct cmd640_reg *timing;
 
-       int ret = ata_port_start(ap);
+       int ret = ata_sff_port_start(ap);
        if (ret < 0)
                return ret;
 
@@ -184,7 +184,6 @@ static struct scsi_host_template cmd640_sht = {
 };
 
 static struct ata_port_operations cmd640_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = cmd640_set_piomode,
        .mode_filter    = ata_pci_default_filter,
        .tf_load        = ata_tf_load,
@@ -213,7 +212,6 @@ static struct ata_port_operations cmd640_port_ops = {
        .irq_handler    = ata_interrupt,
        .irq_clear      = ata_bmdma_irq_clear,
        .irq_on         = ata_irq_on,
-       .irq_ack        = ata_irq_ack,
 
        .port_start     = cmd640_port_start,
 };
index e34b632487d74772efa858d87fe2ce8e66626f4a..9e412c26b2a360202f951055071c4a3d82abd3da 100644 (file)
@@ -31,7 +31,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_cmd64x"
-#define DRV_VERSION "0.2.4"
+#define DRV_VERSION "0.2.5"
 
 /*
  * CMD64x specific registers definition.
@@ -88,14 +88,15 @@ static int cmd648_cable_detect(struct ata_port *ap)
 }
 
 /**
- *     cmd64x_set_piomode      -       set initial PIO mode data
+ *     cmd64x_set_piomode      -       set PIO and MWDMA timing
  *     @ap: ATA interface
  *     @adev: ATA device
+ *     @mode: mode
  *
- *     Called to do the PIO mode setup.
+ *     Called to do the PIO and MWDMA mode setup.
  */
 
-static void cmd64x_set_piomode(struct ata_port *ap, struct ata_device *adev)
+static void cmd64x_set_timing(struct ata_port *ap, struct ata_device *adev, u8 mode)
 {
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        struct ata_timing t;
@@ -117,8 +118,9 @@ static void cmd64x_set_piomode(struct ata_port *ap, struct ata_device *adev)
        int arttim = arttim_port[ap->port_no][adev->devno];
        int drwtim = drwtim_port[ap->port_no][adev->devno];
 
-
-       if (ata_timing_compute(adev, adev->pio_mode, &t, T, 0) < 0) {
+       /* ata_timing_compute is smart and will produce timings for MWDMA
+          that don't violate the drives PIO capabilities. */
+       if (ata_timing_compute(adev, mode, &t, T, 0) < 0) {
                printk(KERN_ERR DRV_NAME ": mode computation failed.\n");
                return;
        }
@@ -167,6 +169,20 @@ static void cmd64x_set_piomode(struct ata_port *ap, struct ata_device *adev)
        pci_write_config_byte(pdev, drwtim, (t.active << 4) | t.recover);
 }
 
+/**
+ *     cmd64x_set_piomode      -       set initial PIO mode data
+ *     @ap: ATA interface
+ *     @adev: ATA device
+ *
+ *     Used when configuring the devices ot set the PIO timings. All the
+ *     actual work is done by the PIO/MWDMA setting helper
+ */
+
+static void cmd64x_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+       cmd64x_set_timing(ap, adev, adev->pio_mode);
+}
+
 /**
  *     cmd64x_set_dmamode      -       set initial DMA mode data
  *     @ap: ATA interface
@@ -180,9 +196,6 @@ static void cmd64x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
        static const u8 udma_data[] = {
                0x30, 0x20, 0x10, 0x20, 0x10, 0x00
        };
-       static const u8 mwdma_data[] = {
-               0x30, 0x20, 0x10
-       };
 
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        u8 regU, regD;
@@ -208,8 +221,10 @@ static void cmd64x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
                regU |= 1 << adev->devno; /* UDMA on */
                if (adev->dma_mode > 2) /* 15nS timing */
                        regU |= 4 << adev->devno;
-       } else
-               regD |= mwdma_data[adev->dma_mode - XFER_MW_DMA_0] << shift;
+       } else {
+               regU &= ~ (1 << adev->devno);   /* UDMA off */
+               cmd64x_set_timing(ap, adev, adev->dma_mode);
+       }
 
        regD |= 0x20 << adev->devno;
 
@@ -269,7 +284,6 @@ static struct scsi_host_template cmd64x_sht = {
 };
 
 static struct ata_port_operations cmd64x_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = cmd64x_set_piomode,
        .set_dmamode    = cmd64x_set_dmamode,
        .mode_filter    = ata_pci_default_filter,
@@ -298,13 +312,11 @@ static struct ata_port_operations cmd64x_port_ops = {
        .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,
 };
 
 static struct ata_port_operations cmd646r1_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = cmd64x_set_piomode,
        .set_dmamode    = cmd64x_set_dmamode,
        .mode_filter    = ata_pci_default_filter,
@@ -333,13 +345,11 @@ static struct ata_port_operations cmd646r1_port_ops = {
        .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,
 };
 
 static struct ata_port_operations cmd648_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = cmd64x_set_piomode,
        .set_dmamode    = cmd64x_set_dmamode,
        .mode_filter    = ata_pci_default_filter,
@@ -368,7 +378,6 @@ static struct ata_port_operations cmd648_port_ops = {
        .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,
 };
index e2459088cdcd2015bb4810a8d80249d062b541d5..33f7f0843f4f21f95b4684725c6e505888abdd09 100644 (file)
@@ -158,7 +158,6 @@ static struct scsi_host_template cs5520_sht = {
 };
 
 static struct ata_port_operations cs5520_port_ops = {
-       .port_disable           = ata_port_disable,
        .set_piomode            = cs5520_set_piomode,
        .set_dmamode            = cs5520_set_dmamode,
 
@@ -184,13 +183,14 @@ static struct ata_port_operations cs5520_port_ops = {
 
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
-       .irq_ack                = ata_irq_ack,
 
-       .port_start             = ata_port_start,
+       .port_start             = ata_sff_port_start,
 };
 
 static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 {
+       static const unsigned int cmd_port[] = { 0x1F0, 0x170 };
+       static const unsigned int ctl_port[] = { 0x3F6, 0x376 };
        struct ata_port_info pi = {
                .flags          = ATA_FLAG_SLAVE_POSS,
                .pio_mask       = 0x1f,
@@ -244,10 +244,10 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi
        }
 
        /* Map IO ports and initialize host accordingly */
-       iomap[0] = devm_ioport_map(&pdev->dev, 0x1F0, 8);
-       iomap[1] = devm_ioport_map(&pdev->dev, 0x3F6, 1);
-       iomap[2] = devm_ioport_map(&pdev->dev, 0x170, 8);
-       iomap[3] = devm_ioport_map(&pdev->dev, 0x376, 1);
+       iomap[0] = devm_ioport_map(&pdev->dev, cmd_port[0], 8);
+       iomap[1] = devm_ioport_map(&pdev->dev, ctl_port[0], 1);
+       iomap[2] = devm_ioport_map(&pdev->dev, cmd_port[1], 8);
+       iomap[3] = devm_ioport_map(&pdev->dev, ctl_port[1], 1);
        iomap[4] = pcim_iomap(pdev, 2, 0);
 
        if (!iomap[0] || !iomap[1] || !iomap[2] || !iomap[3] || !iomap[4])
@@ -260,6 +260,10 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi
        ioaddr->bmdma_addr = iomap[4];
        ata_std_ports(ioaddr);
 
+       ata_port_desc(host->ports[0],
+                     "cmd 0x%x ctl 0x%x", cmd_port[0], ctl_port[0]);
+       ata_port_pbar_desc(host->ports[0], 4, 0, "bmdma");
+
        ioaddr = &host->ports[1]->ioaddr;
        ioaddr->cmd_addr = iomap[2];
        ioaddr->ctl_addr = iomap[3];
@@ -267,6 +271,10 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi
        ioaddr->bmdma_addr = iomap[4] + 8;
        ata_std_ports(ioaddr);
 
+       ata_port_desc(host->ports[1],
+                     "cmd 0x%x ctl 0x%x", cmd_port[1], ctl_port[1]);
+       ata_port_pbar_desc(host->ports[1], 4, 8, "bmdma");
+
        /* activate the host */
        pci_set_master(pdev);
        rc = ata_host_start(host);
@@ -285,33 +293,12 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi
                if (rc)
                        return rc;
 
-               if (i == 0)
-                       host->irq = irq[0];
-               else
-                       host->irq2 = irq[1];
+               ata_port_desc(ap, "irq %d", irq[i]);
        }
 
        return ata_host_register(host, &cs5520_sht);
 }
 
-/**
- *     cs5520_remove_one       -       device unload
- *     @pdev: PCI device being removed
- *
- *     Handle an unplug/unload event for a PCI device. Unload the
- *     PCI driver but do not use the default handler as we manage
- *     resources ourself and *MUST NOT* disable the device as it has
- *     other functions.
- */
-
-static void __devexit cs5520_remove_one(struct pci_dev *pdev)
-{
-       struct device *dev = pci_dev_to_dev(pdev);
-       struct ata_host *host = dev_get_drvdata(dev);
-
-       ata_host_detach(host);
-}
-
 #ifdef CONFIG_PM
 /**
  *     cs5520_reinit_one       -       device resume
@@ -368,7 +355,7 @@ static struct pci_driver cs5520_pci_driver = {
        .name           = DRV_NAME,
        .id_table       = pata_cs5520,
        .probe          = cs5520_init_one,
-       .remove         = cs5520_remove_one,
+       .remove         = ata_pci_remove_one,
 #ifdef CONFIG_PM
        .suspend        = cs5520_pci_device_suspend,
        .resume         = cs5520_reinit_one,
index eaaea848b649bc2ee54a232bd33e4ca58b7953fc..57e827e4109e939ac9e83561f8284bf19a0d6a9e 100644 (file)
@@ -179,7 +179,6 @@ static struct scsi_host_template cs5530_sht = {
 };
 
 static struct ata_port_operations cs5530_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = cs5530_set_piomode,
        .set_dmamode    = cs5530_set_dmamode,
        .mode_filter    = ata_pci_default_filter,
@@ -209,9 +208,8 @@ static struct ata_port_operations cs5530_port_ops = {
        .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,
+       .port_start     = ata_sff_port_start,
 };
 
 static const struct dmi_system_id palmax_dmi_table[] = {
index 360b6f32e17ec2ca06cf5b748c3c8c170d71fbe6..3578593a882b503921ca139d2dfec11192ab2467 100644 (file)
@@ -176,7 +176,6 @@ static struct scsi_host_template cs5535_sht = {
 };
 
 static struct ata_port_operations cs5535_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = cs5535_set_piomode,
        .set_dmamode    = cs5535_set_dmamode,
        .mode_filter    = ata_pci_default_filter,
@@ -206,9 +205,8 @@ static struct ata_port_operations cs5535_port_ops = {
        .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,
+       .port_start     = ata_sff_port_start,
 };
 
 /**
index 6cbc8778bf4f2fd2766f1ae837d88216820afcfd..fc5f9c4e5d87977e3459369e20757c55164b6da0 100644 (file)
@@ -128,7 +128,6 @@ static struct scsi_host_template cy82c693_sht = {
 };
 
 static struct ata_port_operations cy82c693_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = cy82c693_set_piomode,
        .set_dmamode    = cy82c693_set_dmamode,
        .mode_filter    = ata_pci_default_filter,
@@ -158,9 +157,8 @@ static struct ata_port_operations cy82c693_port_ops = {
        .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,
+       .port_start     = ata_sff_port_start,
 };
 
 static int cy82c693_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
index c8ba59c5611429749b0fc06779acc12e592254bd..043dcd35106c0877aed1ce07e91a8f6a9d4b8892 100644 (file)
 
 /**
  *     efar_pre_reset  -       Enable bits
- *     @ap: Port
+ *     @link: ATA link
  *     @deadline: deadline jiffies for the operation
  *
  *     Perform cable detection for the EFAR ATA interface. This is
  *     different to the PIIX arrangement
  */
 
-static int efar_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int efar_pre_reset(struct ata_link *link, unsigned long deadline)
 {
        static const struct pci_bits efar_enable_bits[] = {
                { 0x41U, 1U, 0x80UL, 0x80UL },  /* port 0 */
                { 0x43U, 1U, 0x80UL, 0x80UL },  /* port 1 */
        };
+       struct ata_port *ap = link->ap;
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 
        if (!pci_test_config_bits(pdev, &efar_enable_bits[ap->port_no]))
                return -ENOENT;
 
-       return ata_std_prereset(ap, deadline);
+       return ata_std_prereset(link, deadline);
 }
 
 /**
@@ -250,7 +251,6 @@ static struct scsi_host_template efar_sht = {
 };
 
 static const struct ata_port_operations efar_ops = {
-       .port_disable           = ata_port_disable,
        .set_piomode            = efar_set_piomode,
        .set_dmamode            = efar_set_dmamode,
        .mode_filter            = ata_pci_default_filter,
@@ -278,9 +278,8 @@ static const struct ata_port_operations efar_ops = {
        .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,
+       .port_start             = ata_sff_port_start,
 };
 
 
index 6f7d34ad19ef34152e966434c577c1cb69c88a3e..0713872cf65c64c936c14a15aacda6c7f851f640 100644 (file)
@@ -312,7 +312,6 @@ static struct scsi_host_template hpt36x_sht = {
  */
 
 static struct ata_port_operations hpt366_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = hpt366_set_piomode,
        .set_dmamode    = hpt366_set_dmamode,
        .mode_filter    = hpt366_filter,
@@ -342,9 +341,8 @@ static struct ata_port_operations hpt366_port_ops = {
        .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,
+       .port_start     = ata_sff_port_start,
 };
 
 /**
index c5ddd937dbf21a438af2cbe8fb0f2c385b88a774..e61cb1fd57b209d518665a6798e0f5d03ed7e1b9 100644 (file)
@@ -304,15 +304,16 @@ static unsigned long hpt370a_filter(struct ata_device *adev, unsigned long mask)
 
 /**
  *     hpt37x_pre_reset        -       reset the hpt37x bus
- *     @ap: ATA port to reset
+ *     @link: ATA link to reset
  *     @deadline: deadline jiffies for the operation
  *
  *     Perform the initial reset handling for the 370/372 and 374 func 0
  */
 
-static int hpt37x_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int hpt37x_pre_reset(struct ata_link *link, unsigned long deadline)
 {
        u8 scr2, ata66;
+       struct ata_port *ap = link->ap;
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        static const struct pci_bits hpt37x_enable_bits[] = {
                { 0x50, 1, 0x04, 0x04 },
@@ -337,7 +338,7 @@ static int hpt37x_pre_reset(struct ata_port *ap, unsigned long deadline)
        pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
        udelay(100);
 
-       return ata_std_prereset(ap, deadline);
+       return ata_std_prereset(link, deadline);
 }
 
 /**
@@ -352,7 +353,7 @@ static void hpt37x_error_handler(struct ata_port *ap)
        ata_bmdma_drive_eh(ap, hpt37x_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
 }
 
-static int hpt374_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int hpt374_pre_reset(struct ata_link *link, unsigned long deadline)
 {
        static const struct pci_bits hpt37x_enable_bits[] = {
                { 0x50, 1, 0x04, 0x04 },
@@ -360,6 +361,7 @@ static int hpt374_pre_reset(struct ata_port *ap, unsigned long deadline)
        };
        u16 mcr3, mcr6;
        u8 ata66;
+       struct ata_port *ap = link->ap;
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 
        if (!pci_test_config_bits(pdev, &hpt37x_enable_bits[ap->port_no]))
@@ -387,7 +389,7 @@ static int hpt374_pre_reset(struct ata_port *ap, unsigned long deadline)
        pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
        udelay(100);
 
-       return ata_std_prereset(ap, deadline);
+       return ata_std_prereset(link, deadline);
 }
 
 /**
@@ -642,7 +644,6 @@ static struct scsi_host_template hpt37x_sht = {
  */
 
 static struct ata_port_operations hpt370_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = hpt370_set_piomode,
        .set_dmamode    = hpt370_set_dmamode,
        .mode_filter    = hpt370_filter,
@@ -671,9 +672,8 @@ static struct ata_port_operations hpt370_port_ops = {
        .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,
+       .port_start     = ata_sff_port_start,
 };
 
 /*
@@ -681,7 +681,6 @@ static struct ata_port_operations hpt370_port_ops = {
  */
 
 static struct ata_port_operations hpt370a_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = hpt370_set_piomode,
        .set_dmamode    = hpt370_set_dmamode,
        .mode_filter    = hpt370a_filter,
@@ -710,9 +709,8 @@ static struct ata_port_operations hpt370a_port_ops = {
        .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,
+       .port_start     = ata_sff_port_start,
 };
 
 /*
@@ -721,7 +719,6 @@ static struct ata_port_operations hpt370a_port_ops = {
  */
 
 static struct ata_port_operations hpt372_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = hpt372_set_piomode,
        .set_dmamode    = hpt372_set_dmamode,
        .mode_filter    = ata_pci_default_filter,
@@ -750,9 +747,8 @@ static struct ata_port_operations hpt372_port_ops = {
        .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,
+       .port_start     = ata_sff_port_start,
 };
 
 /*
@@ -761,7 +757,6 @@ static struct ata_port_operations hpt372_port_ops = {
  */
 
 static struct ata_port_operations hpt374_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = hpt372_set_piomode,
        .set_dmamode    = hpt372_set_dmamode,
        .mode_filter    = ata_pci_default_filter,
@@ -790,9 +785,8 @@ static struct ata_port_operations hpt374_port_ops = {
        .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,
+       .port_start     = ata_sff_port_start,
 };
 
 /**
index f8f234bfc8ce2bc1ef075fccedd6df98d52fec2f..9f1c084f846f4d3fbbe75d7013cc3065685b3a31 100644 (file)
@@ -141,21 +141,22 @@ static int hpt3x2n_cable_detect(struct ata_port *ap)
 
 /**
  *     hpt3x2n_pre_reset       -       reset the hpt3x2n bus
- *     @ap: ATA port to reset
+ *     @link: ATA link to reset
  *     @deadline: deadline jiffies for the operation
  *
  *     Perform the initial reset handling for the 3x2n series controllers.
  *     Reset the hardware and state machine,
  */
 
-static int hpt3xn_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int hpt3xn_pre_reset(struct ata_link *link, unsigned long deadline)
 {
+       struct ata_port *ap = link->ap;
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        /* Reset the state machine */
        pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
        udelay(100);
 
-       return ata_std_prereset(ap, deadline);
+       return ata_std_prereset(link, deadline);
 }
 
 /**
@@ -360,7 +361,6 @@ static struct scsi_host_template hpt3x2n_sht = {
  */
 
 static struct ata_port_operations hpt3x2n_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = hpt3x2n_set_piomode,
        .set_dmamode    = hpt3x2n_set_dmamode,
        .mode_filter    = ata_pci_default_filter,
@@ -390,9 +390,8 @@ static struct ata_port_operations hpt3x2n_port_ops = {
        .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,
+       .port_start     = ata_sff_port_start,
 };
 
 /**
index be0f05efac6d1c93a87628b37d1a3d62afc9ad4e..cb8bdb6887dea6322e22cdb20290311b5234bf0b 100644 (file)
@@ -120,7 +120,6 @@ static struct scsi_host_template hpt3x3_sht = {
 };
 
 static struct ata_port_operations hpt3x3_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = hpt3x3_set_piomode,
 #if defined(CONFIG_PATA_HPT3X3_DMA)
        .set_dmamode    = hpt3x3_set_dmamode,
@@ -153,9 +152,8 @@ static struct ata_port_operations hpt3x3_port_ops = {
        .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,
+       .port_start     = ata_sff_port_start,
 };
 
 /**
@@ -239,7 +237,8 @@ static int hpt3x3_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
        base = host->iomap[4];  /* Bus mastering base */
 
        for (i = 0; i < host->n_ports; i++) {
-               struct ata_ioports *ioaddr = &host->ports[i]->ioaddr;
+               struct ata_port *ap = host->ports[i];
+               struct ata_ioports *ioaddr = &ap->ioaddr;
 
                ioaddr->cmd_addr = base + offset_cmd[i];
                ioaddr->altstatus_addr =
@@ -247,6 +246,9 @@ static int hpt3x3_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
                ioaddr->scr_addr = NULL;
                ata_std_ports(ioaddr);
                ioaddr->bmdma_addr = base + 8 * i;
+
+               ata_port_pbar_desc(ap, 4, -1, "ioport");
+               ata_port_pbar_desc(ap, 4, offset_cmd[i], "cmd");
        }
        pci_set_master(pdev);
        return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED,
index 64a711776c453b51e4c5be2f01bddcfbfb1fe0f9..be30923566c53c88e8ba67f5675f653e48043d98 100644 (file)
@@ -70,6 +70,8 @@ struct pata_icside_info {
        unsigned int            mwdma_mask;
        unsigned int            nr_ports;
        const struct portinfo   *port[2];
+       unsigned long           raw_base;
+       unsigned long           raw_ioc_base;
 };
 
 #define ICS_TYPE_A3IN  0
@@ -357,26 +359,7 @@ static void pata_icside_error_handler(struct ata_port *ap)
                           pata_icside_postreset);
 }
 
-static u8 pata_icside_irq_ack(struct ata_port *ap, unsigned int chk_drq)
-{
-       unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY;
-       u8 status;
-
-       status = ata_busy_wait(ap, bits, 1000);
-       if (status & bits)
-               if (ata_msg_err(ap))
-                       printk(KERN_ERR "abnormal status 0x%X\n", status);
-
-       if (ata_msg_intr(ap))
-               printk(KERN_INFO "%s: irq ack: drv_stat 0x%X\n",
-                       __FUNCTION__, status);
-
-       return status;
-}
-
 static struct ata_port_operations pata_icside_port_ops = {
-       .port_disable           = ata_port_disable,
-
        .set_dmamode            = pata_icside_set_dmamode,
 
        .tf_load                = ata_tf_load,
@@ -403,7 +386,6 @@ static struct ata_port_operations pata_icside_port_ops = {
 
        .irq_clear              = ata_dummy_noret,
        .irq_on                 = ata_irq_on,
-       .irq_ack                = pata_icside_irq_ack,
 
        .port_start             = pata_icside_port_start,
 
@@ -412,9 +394,10 @@ static struct ata_port_operations pata_icside_port_ops = {
 };
 
 static void __devinit
-pata_icside_setup_ioaddr(struct ata_ioports *ioaddr, void __iomem *base,
+pata_icside_setup_ioaddr(struct ata_port *ap, void __iomem *base,
                         const struct portinfo *info)
 {
+       struct ata_ioports *ioaddr = &ap->ioaddr;
        void __iomem *cmd = base + info->dataoffset;
 
        ioaddr->cmd_addr        = cmd;
@@ -431,6 +414,13 @@ pata_icside_setup_ioaddr(struct ata_ioports *ioaddr, void __iomem *base,
 
        ioaddr->ctl_addr        = base + info->ctrloffset;
        ioaddr->altstatus_addr  = ioaddr->ctl_addr;
+
+       ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx",
+                     info->raw_base + info->dataoffset,
+                     info->raw_base + info->ctrloffset);
+
+       if (info->raw_ioc_base)
+               ata_port_desc(ap, "iocbase 0x%lx", info->raw_ioc_base);
 }
 
 static int __devinit pata_icside_register_v5(struct pata_icside_info *info)
@@ -451,6 +441,8 @@ static int __devinit pata_icside_register_v5(struct pata_icside_info *info)
        info->nr_ports = 1;
        info->port[0] = &pata_icside_portinfo_v5;
 
+       info->raw_base = ecard_resource_start(ec, ECARD_RES_MEMC);
+
        return 0;
 }
 
@@ -491,6 +483,9 @@ static int __devinit pata_icside_register_v6(struct pata_icside_info *info)
        info->port[0] = &pata_icside_portinfo_v6_1;
        info->port[1] = &pata_icside_portinfo_v6_2;
 
+       info->raw_base = ecard_resource_start(ec, ECARD_RES_EASI);
+       info->raw_ioc_base = ecard_resource_start(ec, ECARD_RES_IOCFAST);
+
        return icside_dma_init(info);
 }
 
@@ -527,7 +522,7 @@ static int __devinit pata_icside_add_ports(struct pata_icside_info *info)
                ap->flags |= ATA_FLAG_SLAVE_POSS;
                ap->ops = &pata_icside_port_ops;
 
-               pata_icside_setup_ioaddr(&ap->ioaddr, info->base, info->port[i]);
+               pata_icside_setup_ioaddr(ap, info->base, info->port[i]);
        }
 
        return ata_host_activate(host, ec->irq, ata_interrupt, 0,
index 9e553c54203a32e5f44dfeac976de05d3af6a581..88ab0e1d353fb506d1ac1de6b3b9eac1d81d6bb9 100644 (file)
@@ -38,7 +38,6 @@ static struct scsi_host_template isapnp_sht = {
 };
 
 static struct ata_port_operations isapnp_port_ops = {
-       .port_disable   = ata_port_disable,
        .tf_load        = ata_tf_load,
        .tf_read        = ata_tf_read,
        .check_status   = ata_check_status,
@@ -58,9 +57,8 @@ static struct ata_port_operations isapnp_port_ops = {
 
        .irq_clear      = ata_bmdma_irq_clear,
        .irq_on         = ata_irq_on,
-       .irq_ack        = ata_irq_ack,
 
-       .port_start     = ata_port_start,
+       .port_start     = ata_sff_port_start,
 };
 
 /**
@@ -112,6 +110,10 @@ static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev
 
        ata_std_ports(&ap->ioaddr);
 
+       ata_port_desc(ap, "cmd 0x%llx ctl 0x%llx",
+                     (unsigned long long)pnp_port_start(idev, 0),
+                     (unsigned long long)pnp_port_start(idev, 1));
+
        /* activate */
        return ata_host_activate(host, pnp_irq(idev, 0), ata_interrupt, 0,
                                 &isapnp_sht);
index b8af55e8915695a45538522092e1f387ce9ce483..1eda821e5e395b32dd78a86bc8c7ab2bd58fd537 100644 (file)
 
 /**
  *     it8213_pre_reset        -       check for 40/80 pin
- *     @ap: Port
+ *     @link: link
  *     @deadline: deadline jiffies for the operation
  *
  *     Filter out ports by the enable bits before doing the normal reset
  *     and probe.
  */
 
-static int it8213_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int it8213_pre_reset(struct ata_link *link, unsigned long deadline)
 {
        static const struct pci_bits it8213_enable_bits[] = {
                { 0x41U, 1U, 0x80UL, 0x80UL },  /* port 0 */
        };
+       struct ata_port *ap = link->ap;
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        if (!pci_test_config_bits(pdev, &it8213_enable_bits[ap->port_no]))
                return -ENOENT;
 
-       return ata_std_prereset(ap, deadline);
+       return ata_std_prereset(link, deadline);
 }
 
 /**
@@ -260,7 +261,6 @@ static struct scsi_host_template it8213_sht = {
 };
 
 static const struct ata_port_operations it8213_ops = {
-       .port_disable           = ata_port_disable,
        .set_piomode            = it8213_set_piomode,
        .set_dmamode            = it8213_set_dmamode,
        .mode_filter            = ata_pci_default_filter,
@@ -288,9 +288,8 @@ static const struct ata_port_operations it8213_ops = {
        .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,
+       .port_start             = ata_sff_port_start,
 };
 
 
index 5d8b91e70ecd82b41b33b3ab407eeb650599d9ff..988ef736b936ca7db206d62fbc6a9809bbdcff76 100644 (file)
@@ -391,7 +391,7 @@ static void it821x_passthru_dev_select(struct ata_port *ap,
 {
        struct it821x_dev *itdev = ap->private_data;
        if (itdev && device != itdev->last_device) {
-               struct ata_device *adev = &ap->device[device];
+               struct ata_device *adev = &ap->link.device[device];
                it821x_program(ap, adev, itdev->pio[adev->devno]);
                itdev->last_device = device;
        }
@@ -450,7 +450,7 @@ static unsigned int it821x_passthru_qc_issue_prot(struct ata_queued_cmd *qc)
 
 /**
  *     it821x_smart_set_mode   -       mode setting
- *     @ap: interface to set up
+ *     @link: interface to set up
  *     @unused: device that failed (error only)
  *
  *     Use a non standard set_mode function. We don't want to be tuned.
@@ -459,12 +459,11 @@ static unsigned int it821x_passthru_qc_issue_prot(struct ata_queued_cmd *qc)
  *     and respect them.
  */
 
-static int it821x_smart_set_mode(struct ata_port *ap, struct ata_device **unused)
+static int it821x_smart_set_mode(struct ata_link *link, struct ata_device **unused)
 {
-       int i;
+       struct ata_device *dev;
 
-       for (i = 0; i < ATA_MAX_DEVICES; i++) {
-               struct ata_device *dev = &ap->device[i];
+       ata_link_for_each_dev(dev, link) {
                if (ata_dev_enabled(dev)) {
                        /* We don't really care */
                        dev->pio_mode = XFER_PIO_0;
@@ -564,7 +563,7 @@ static int it821x_port_start(struct ata_port *ap)
        struct it821x_dev *itdev;
        u8 conf;
 
-       int ret = ata_port_start(ap);
+       int ret = ata_sff_port_start(ap);
        if (ret < 0)
                return ret;
 
@@ -621,7 +620,6 @@ static struct scsi_host_template it821x_sht = {
 
 static struct ata_port_operations it821x_smart_port_ops = {
        .set_mode       = it821x_smart_set_mode,
-       .port_disable   = ata_port_disable,
        .tf_load        = ata_tf_load,
        .tf_read        = ata_tf_read,
        .mode_filter    = ata_pci_default_filter,
@@ -651,13 +649,11 @@ static struct ata_port_operations it821x_smart_port_ops = {
        .irq_handler    = ata_interrupt,
        .irq_clear      = ata_bmdma_irq_clear,
        .irq_on         = ata_irq_on,
-       .irq_ack        = ata_irq_ack,
 
        .port_start     = it821x_port_start,
 };
 
 static struct ata_port_operations it821x_passthru_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = it821x_passthru_set_piomode,
        .set_dmamode    = it821x_passthru_set_dmamode,
        .mode_filter    = ata_pci_default_filter,
@@ -688,7 +684,6 @@ static struct ata_port_operations it821x_passthru_port_ops = {
        .irq_clear      = ata_bmdma_irq_clear,
        .irq_handler    = ata_interrupt,
        .irq_on         = ata_irq_on,
-       .irq_ack        = ata_irq_ack,
 
        .port_start     = it821x_port_start,
 };
index 5dea3584c6c2fc439846b190b2d3627bf22a6156..fcd532afbf2e011c9b4d5183430945d409c702eb 100644 (file)
 #define DRV_NAME       "pata_ixp4xx_cf"
 #define DRV_VERSION    "0.2"
 
-static int ixp4xx_set_mode(struct ata_port *ap, struct ata_device **error)
+static int ixp4xx_set_mode(struct ata_link *link, struct ata_device **error)
 {
-       int i;
+       struct ata_device *dev;
 
-       for (i = 0; i < ATA_MAX_DEVICES; i++) {
-               struct ata_device *dev = &ap->device[i];
+       ata_link_for_each_dev(dev, link) {
                if (ata_dev_enabled(dev)) {
                        ata_dev_printk(dev, KERN_INFO, "configured for PIO0\n");
                        dev->pio_mode = XFER_PIO_0;
@@ -49,7 +48,7 @@ static void ixp4xx_mmio_data_xfer(struct ata_device *adev, unsigned char *buf,
        unsigned int i;
        unsigned int words = buflen >> 1;
        u16 *buf16 = (u16 *) buf;
-       struct ata_port *ap = adev->ap;
+       struct ata_port *ap = adev->link->ap;
        void __iomem *mmio = ap->ioaddr.data_addr;
        struct ixp4xx_pata_data *data = ap->host->dev->platform_data;
 
@@ -108,7 +107,6 @@ static struct ata_port_operations ixp4xx_port_ops = {
        .set_mode               = ixp4xx_set_mode,
        .mode_filter            = ata_pci_default_filter,
 
-       .port_disable           = ata_port_disable,
        .tf_load                = ata_tf_load,
        .tf_read                = ata_tf_read,
        .exec_command           = ata_exec_command,
@@ -128,14 +126,17 @@ static struct ata_port_operations ixp4xx_port_ops = {
        .irq_handler            = ata_interrupt,
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
-       .irq_ack                = ata_dummy_irq_ack,
 
        .port_start             = ata_port_start,
 };
 
 static void ixp4xx_setup_port(struct ata_ioports *ioaddr,
-                               struct ixp4xx_pata_data *data)
+                             struct ixp4xx_pata_data *data,
+                             unsigned long raw_cs0, unsigned long raw_cs1)
 {
+       unsigned long raw_cmd = raw_cs0;
+       unsigned long raw_ctl = raw_cs1 + 0x06;
+
        ioaddr->cmd_addr        = data->cs0;
        ioaddr->altstatus_addr  = data->cs1 + 0x06;
        ioaddr->ctl_addr        = data->cs1 + 0x06;
@@ -161,7 +162,12 @@ static void ixp4xx_setup_port(struct ata_ioports *ioaddr,
        *(unsigned long *)&ioaddr->device_addr          ^= 0x03;
        *(unsigned long *)&ioaddr->status_addr          ^= 0x03;
        *(unsigned long *)&ioaddr->command_addr         ^= 0x03;
+
+       raw_cmd ^= 0x03;
+       raw_ctl ^= 0x03;
 #endif
+
+       ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", raw_cmd, raw_ctl);
 }
 
 static __devinit int ixp4xx_pata_probe(struct platform_device *pdev)
@@ -206,7 +212,7 @@ static __devinit int ixp4xx_pata_probe(struct platform_device *pdev)
        ap->pio_mask = 0x1f; /* PIO4 */
        ap->flags |= ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY | ATA_FLAG_NO_ATAPI;
 
-       ixp4xx_setup_port(&ap->ioaddr, data);
+       ixp4xx_setup_port(ap, data, cs0->start, cs1->start);
 
        dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
 
index 4d67f238eee25ddf5f0e6ee917f7b8b0141de9b3..225a7223a726066bdc14181d225dfc16a541b298 100644 (file)
@@ -29,7 +29,7 @@ typedef enum {
 
 /**
  *     jmicron_pre_reset       -       check for 40/80 pin
- *     @ap: Port
+ *     @link: ATA link
  *     @deadline: deadline jiffies for the operation
  *
  *     Perform the PATA port setup we need.
@@ -39,9 +39,9 @@ typedef enum {
  *     and setup here. We assume that has been done by init_one and the
  *     BIOS.
  */
-
-static int jmicron_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int jmicron_pre_reset(struct ata_link *link, unsigned long deadline)
 {
+       struct ata_port *ap = link->ap;
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        u32 control;
        u32 control5;
@@ -103,7 +103,7 @@ static int jmicron_pre_reset(struct ata_port *ap, unsigned long deadline)
                ap->cbl = ATA_CBL_SATA;
                break;
        }
-       return ata_std_prereset(ap, deadline);
+       return ata_std_prereset(link, deadline);
 }
 
 /**
@@ -141,8 +141,6 @@ static struct scsi_host_template jmicron_sht = {
 };
 
 static const struct ata_port_operations jmicron_ops = {
-       .port_disable           = ata_port_disable,
-
        /* Task file is PCI ATA format, use helpers */
        .tf_load                = ata_tf_load,
        .tf_read                = ata_tf_read,
@@ -168,7 +166,6 @@ static const struct ata_port_operations jmicron_ops = {
        .irq_handler            = ata_interrupt,
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
-       .irq_ack                = ata_irq_ack,
 
        /* Generic PATA PCI ATA helpers */
        .port_start             = ata_port_start,
@@ -207,17 +204,8 @@ static int jmicron_init_one (struct pci_dev *pdev, const struct pci_device_id *i
 }
 
 static const struct pci_device_id jmicron_pci_tbl[] = {
-       { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361,
-         PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 361 },
-       { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363,
-         PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 363 },
-       { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365,
-         PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 365 },
-       { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366,
-         PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 366 },
-       { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368,
-         PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 368 },
-
+       { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+         PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 0 },
        { }     /* terminate list */
 };
 
index edffc25d2d3fa4b84540c49fc11ca82525456ac5..7bed8d806381eb45b83f6d47c91ddfaf7c754f90 100644 (file)
@@ -96,7 +96,7 @@ static int iordy_mask = 0xFFFFFFFF;   /* Use iordy if available */
 
 /**
  *     legacy_set_mode         -       mode setting
- *     @ap: IDE interface
+ *     @link: IDE link
  *     @unused: Device that failed when error is returned
  *
  *     Use a non standard set_mode function. We don't want to be tuned.
@@ -107,12 +107,11 @@ static int iordy_mask = 0xFFFFFFFF;       /* Use iordy if available */
  *     expand on this as per hdparm in the base kernel.
  */
 
-static int legacy_set_mode(struct ata_port *ap, struct ata_device **unused)
+static int legacy_set_mode(struct ata_link *link, struct ata_device **unused)
 {
-       int i;
+       struct ata_device *dev;
 
-       for (i = 0; i < ATA_MAX_DEVICES; i++) {
-               struct ata_device *dev = &ap->device[i];
+       ata_link_for_each_dev(dev, link) {
                if (ata_dev_enabled(dev)) {
                        ata_dev_printk(dev, KERN_INFO, "configured for PIO\n");
                        dev->pio_mode = XFER_PIO_0;
@@ -151,7 +150,6 @@ static struct scsi_host_template legacy_sht = {
  */
 
 static struct ata_port_operations simple_port_ops = {
-       .port_disable   = ata_port_disable,
        .tf_load        = ata_tf_load,
        .tf_read        = ata_tf_read,
        .check_status   = ata_check_status,
@@ -172,7 +170,6 @@ static struct ata_port_operations simple_port_ops = {
        .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,
 };
@@ -180,7 +177,6 @@ static struct ata_port_operations simple_port_ops = {
 static struct ata_port_operations legacy_port_ops = {
        .set_mode       = legacy_set_mode,
 
-       .port_disable   = ata_port_disable,
        .tf_load        = ata_tf_load,
        .tf_read        = ata_tf_read,
        .check_status   = ata_check_status,
@@ -201,7 +197,6 @@ static struct ata_port_operations legacy_port_ops = {
        .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,
 };
@@ -256,7 +251,7 @@ static void pdc20230_set_piomode(struct ata_port *ap, struct ata_device *adev)
 
 static void pdc_data_xfer_vlb(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data)
 {
-       struct ata_port *ap = adev->ap;
+       struct ata_port *ap = adev->link->ap;
        int slop = buflen & 3;
        unsigned long flags;
 
@@ -296,7 +291,6 @@ static void pdc_data_xfer_vlb(struct ata_device *adev, unsigned char *buf, unsig
 static struct ata_port_operations pdc20230_port_ops = {
        .set_piomode    = pdc20230_set_piomode,
 
-       .port_disable   = ata_port_disable,
        .tf_load        = ata_tf_load,
        .tf_read        = ata_tf_read,
        .check_status   = ata_check_status,
@@ -317,7 +311,6 @@ static struct ata_port_operations pdc20230_port_ops = {
        .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,
 };
@@ -352,7 +345,6 @@ static void ht6560a_set_piomode(struct ata_port *ap, struct ata_device *adev)
 static struct ata_port_operations ht6560a_port_ops = {
        .set_piomode    = ht6560a_set_piomode,
 
-       .port_disable   = ata_port_disable,
        .tf_load        = ata_tf_load,
        .tf_read        = ata_tf_read,
        .check_status   = ata_check_status,
@@ -373,7 +365,6 @@ static struct ata_port_operations ht6560a_port_ops = {
        .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,
 };
@@ -419,7 +410,6 @@ static void ht6560b_set_piomode(struct ata_port *ap, struct ata_device *adev)
 static struct ata_port_operations ht6560b_port_ops = {
        .set_piomode    = ht6560b_set_piomode,
 
-       .port_disable   = ata_port_disable,
        .tf_load        = ata_tf_load,
        .tf_read        = ata_tf_read,
        .check_status   = ata_check_status,
@@ -440,7 +430,6 @@ static struct ata_port_operations ht6560b_port_ops = {
        .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,
 };
@@ -541,7 +530,6 @@ static void opti82c611a_set_piomode(struct ata_port *ap, struct ata_device *adev
 static struct ata_port_operations opti82c611a_port_ops = {
        .set_piomode    = opti82c611a_set_piomode,
 
-       .port_disable   = ata_port_disable,
        .tf_load        = ata_tf_load,
        .tf_read        = ata_tf_read,
        .check_status   = ata_check_status,
@@ -562,7 +550,6 @@ static struct ata_port_operations opti82c611a_port_ops = {
        .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,
 };
@@ -675,7 +662,6 @@ static unsigned int opti82c46x_qc_issue_prot(struct ata_queued_cmd *qc)
 static struct ata_port_operations opti82c46x_port_ops = {
        .set_piomode    = opti82c46x_set_piomode,
 
-       .port_disable   = ata_port_disable,
        .tf_load        = ata_tf_load,
        .tf_read        = ata_tf_read,
        .check_status   = ata_check_status,
@@ -696,7 +682,6 @@ static struct ata_port_operations opti82c46x_port_ops = {
        .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,
 };
@@ -814,6 +799,8 @@ static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl
        ata_std_ports(&ap->ioaddr);
        ap->private_data = ld;
 
+       ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", io, ctrl);
+
        ret = ata_host_activate(host, irq, ata_interrupt, 0, &legacy_sht);
        if (ret)
                goto fail;
index b45506f1ef73e0db979a1614ffaa58048a63f721..9afc8a32b2269ecd5ea11ab2df0d7c91684b8d0f 100644 (file)
 
 /**
  *     marvell_pre_reset       -       check for 40/80 pin
- *     @ap: Port
+ *     @link: link
  *     @deadline: deadline jiffies for the operation
  *
  *     Perform the PATA port setup we need.
  */
 
-static int marvell_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int marvell_pre_reset(struct ata_link *link, unsigned long deadline)
 {
+       struct ata_port *ap = link->ap;
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        u32 devices;
        void __iomem *barp;
@@ -54,7 +55,7 @@ static int marvell_pre_reset(struct ata_port *ap, unsigned long deadline)
            (!(devices & 0x10)))        /* PATA enable ? */
                return -ENOENT;
 
-       return ata_std_prereset(ap, deadline);
+       return ata_std_prereset(link, deadline);
 }
 
 static int marvell_cable_detect(struct ata_port *ap)
@@ -110,8 +111,6 @@ static struct scsi_host_template marvell_sht = {
 };
 
 static const struct ata_port_operations marvell_ops = {
-       .port_disable           = ata_port_disable,
-
        /* Task file is PCI ATA format, use helpers */
        .tf_load                = ata_tf_load,
        .tf_read                = ata_tf_read,
@@ -138,10 +137,9 @@ static const struct ata_port_operations marvell_ops = {
        .irq_handler            = ata_interrupt,
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
-       .irq_ack                = ata_irq_ack,
 
        /* Generic PATA PCI ATA helpers */
-       .port_start             = ata_port_start,
+       .port_start             = ata_sff_port_start,
 };
 
 
index 099f4cdc4cd9823919c19489504c242993a74d6f..50c56e2814c1e0c6a777ed7ef80534d8e9012d73 100644 (file)
@@ -283,7 +283,6 @@ static struct scsi_host_template mpc52xx_ata_sht = {
 };
 
 static struct ata_port_operations mpc52xx_ata_port_ops = {
-       .port_disable           = ata_port_disable,
        .set_piomode            = mpc52xx_ata_set_piomode,
        .dev_select             = mpc52xx_ata_dev_select,
        .tf_load                = ata_tf_load,
@@ -299,17 +298,16 @@ static struct ata_port_operations mpc52xx_ata_port_ops = {
        .data_xfer              = ata_data_xfer,
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
-       .irq_ack                = ata_irq_ack,
        .port_start             = ata_port_start,
 };
 
 static int __devinit
-mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv)
+mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv,
+                    unsigned long raw_ata_regs)
 {
        struct ata_host *host;
        struct ata_port *ap;
        struct ata_ioports *aio;
-       int rc;
 
        host = ata_host_alloc(dev, 1);
        if (!host)
@@ -338,6 +336,8 @@ mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv)
        aio->status_addr        = &priv->ata_regs->tf_command;
        aio->command_addr       = &priv->ata_regs->tf_command;
 
+       ata_port_desc(ap, "ata_regs 0x%lx", raw_ata_regs);
+
        /* activate host */
        return ata_host_activate(host, priv->ata_irq, ata_interrupt, 0,
                                 &mpc52xx_ata_sht);
@@ -434,7 +434,7 @@ mpc52xx_ata_probe(struct of_device *op, const struct of_device_id *match)
        }
 
        /* Register ourselves to libata */
-       rv = mpc52xx_ata_init_one(&op->dev, priv);
+       rv = mpc52xx_ata_init_one(&op->dev, priv, res_mem.start);
        if (rv) {
                printk(KERN_ERR DRV_NAME ": "
                        "Error while registering to ATA layer\n");
index 4ea42838297e68701343d86e7b05cd727b801128..d5483087a3faa366db7895c15d26bcf827c38bd7 100644 (file)
@@ -46,15 +46,16 @@ enum {
        SECONDARY = (1 << 14)
 };
 
-static int mpiix_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int mpiix_pre_reset(struct ata_link *link, unsigned long deadline)
 {
+       struct ata_port *ap = link->ap;
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        static const struct pci_bits mpiix_enable_bits = { 0x6D, 1, 0x80, 0x80 };
 
        if (!pci_test_config_bits(pdev, &mpiix_enable_bits))
                return -ENOENT;
 
-       return ata_std_prereset(ap, deadline);
+       return ata_std_prereset(link, deadline);
 }
 
 /**
@@ -168,7 +169,6 @@ static struct scsi_host_template mpiix_sht = {
 };
 
 static struct ata_port_operations mpiix_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = mpiix_set_piomode,
 
        .tf_load        = ata_tf_load,
@@ -189,9 +189,8 @@ static struct ata_port_operations mpiix_port_ops = {
 
        .irq_clear      = ata_bmdma_irq_clear,
        .irq_on         = ata_irq_on,
-       .irq_ack        = ata_irq_ack,
 
-       .port_start     = ata_port_start,
+       .port_start     = ata_sff_port_start,
 };
 
 static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
@@ -202,7 +201,7 @@ static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
        struct ata_port *ap;
        void __iomem *cmd_addr, *ctl_addr;
        u16 idetim;
-       int irq;
+       int cmd, ctl, irq;
 
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n");
@@ -210,6 +209,7 @@ static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
        host = ata_host_alloc(&dev->dev, 1);
        if (!host)
                return -ENOMEM;
+       ap = host->ports[0];
 
        /* MPIIX has many functions which can be turned on or off according
           to other devices present. Make sure IDE is enabled before we try
@@ -221,25 +221,28 @@ static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 
        /* See if it's primary or secondary channel... */
        if (!(idetim & SECONDARY)) {
+               cmd = 0x1F0;
+               ctl = 0x3F6;
                irq = 14;
-               cmd_addr = devm_ioport_map(&dev->dev, 0x1F0, 8);
-               ctl_addr = devm_ioport_map(&dev->dev, 0x3F6, 1);
        } else {
+               cmd = 0x170;
+               ctl = 0x376;
                irq = 15;
-               cmd_addr = devm_ioport_map(&dev->dev, 0x170, 8);
-               ctl_addr = devm_ioport_map(&dev->dev, 0x376, 1);
        }
 
+       cmd_addr = devm_ioport_map(&dev->dev, cmd, 8);
+       ctl_addr = devm_ioport_map(&dev->dev, ctl, 1);
        if (!cmd_addr || !ctl_addr)
                return -ENOMEM;
 
+       ata_port_desc(ap, "cmd 0x%x ctl 0x%x", cmd, ctl);
+
        /* We do our own plumbing to avoid leaking special cases for whacko
           ancient hardware into the core code. There are two issues to
           worry about.  #1 The chip is a bridge so if in legacy mode and
           without BARs set fools the setup.  #2 If you pci_disable_device
           the MPIIX your box goes castors up */
 
-       ap = host->ports[0];
        ap->ops = &mpiix_port_ops;
        ap->pio_mask = 0x1F;
        ap->flags |= ATA_FLAG_SLAVE_POSS;
index 40eb574828bf759b1b8a103c8431305819197e2e..25c922abd5540e820ab5a6f879ea982306767c01 100644 (file)
@@ -40,8 +40,6 @@ static struct scsi_host_template netcell_sht = {
 };
 
 static const struct ata_port_operations netcell_ops = {
-       .port_disable           = ata_port_disable,
-
        /* Task file is PCI ATA format, use helpers */
        .tf_load                = ata_tf_load,
        .tf_read                = ata_tf_read,
@@ -68,10 +66,9 @@ static const struct ata_port_operations netcell_ops = {
        .irq_handler            = ata_interrupt,
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
-       .irq_ack                = ata_irq_ack,
 
        /* Generic PATA PCI ATA helpers */
-       .port_start             = ata_port_start,
+       .port_start             = ata_sff_port_start,
 };
 
 
index 2f5d714ebfc4d5c7c844e2405e0ccb6b4bf3d193..6e8e55745b7b3943c6e9c757a38236ee7cfb65f1 100644 (file)
 
 /**
  *     ns87410_pre_reset               -       probe begin
- *     @ap: ATA port
+ *     @link: ATA link
  *     @deadline: deadline jiffies for the operation
  *
  *     Check enabled ports
  */
 
-static int ns87410_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int ns87410_pre_reset(struct ata_link *link, unsigned long deadline)
 {
+       struct ata_port *ap = link->ap;
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        static const struct pci_bits ns87410_enable_bits[] = {
                { 0x43, 1, 0x08, 0x08 },
@@ -49,7 +50,7 @@ static int ns87410_pre_reset(struct ata_port *ap, unsigned long deadline)
        if (!pci_test_config_bits(pdev, &ns87410_enable_bits[ap->port_no]))
                return -ENOENT;
 
-       return ata_std_prereset(ap, deadline);
+       return ata_std_prereset(link, deadline);
 }
 
 /**
@@ -161,7 +162,6 @@ static struct scsi_host_template ns87410_sht = {
 };
 
 static struct ata_port_operations ns87410_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = ns87410_set_piomode,
 
        .tf_load        = ata_tf_load,
@@ -184,9 +184,8 @@ static struct ata_port_operations ns87410_port_ops = {
        .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,
+       .port_start     = ata_sff_port_start,
 };
 
 static int ns87410_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_ns87415.c b/drivers/ata/pata_ns87415.c
new file mode 100644 (file)
index 0000000..bb97ef5
--- /dev/null
@@ -0,0 +1,467 @@
+/*
+ *    pata_ns87415.c - NS87415 (non PARISC) PATA
+ *
+ *     (C) 2005 Red Hat <alan@redhat.com>
+ *
+ *    This is a fairly generic MWDMA controller. It has some limitations
+ *    as it requires timing reloads on PIO/DMA transitions but it is otherwise
+ *    fairly well designed.
+ *
+ *    This driver assumes the firmware has left the chip in a valid ST506
+ *    compliant state, either legacy IRQ 14/15 or native INTA shared. You
+ *    may need to add platform code if your system fails to do this.
+ *
+ *    The same cell appears in the 87560 controller used by some PARISC
+ *    systems. This has its own special mountain of errata.
+ *
+ *    TODO:
+ *     Test PARISC SuperIO
+ *     Get someone to test on SPARC
+ *     Implement lazy pio/dma switching for better performance 
+ *     8bit shared timing.
+ *     See if we need to kill the FIFO for ATAPI
+ */
+
+#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/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <linux/ata.h>
+
+#define DRV_NAME       "pata_ns87415"
+#define DRV_VERSION    "0.0.1"
+
+/**
+ *     ns87415_set_mode - Initialize host controller mode timings
+ *     @ap: Port whose timings we are configuring
+ *     @adev: Device whose timings we are configuring
+ *     @mode: Mode to set
+ *
+ *     Program the mode registers for this controller, channel and
+ *     device. Because the chip is quite an old design we have to do this
+ *     for PIO/DMA switches.
+ *
+ *     LOCKING:
+ *     None (inherited from caller).
+ */
+
+static void ns87415_set_mode(struct ata_port *ap, struct ata_device *adev, u8 mode)
+{
+       struct pci_dev *dev     = to_pci_dev(ap->host->dev);
+       int unit                = 2 * ap->port_no + adev->devno;
+       int timing              = 0x44 + 2 * unit;
+       unsigned long T         = 1000000000 / 33333;   /* PCI clocks */
+       struct ata_timing t;
+       u16 clocking;
+       u8 iordy;
+       u8 status;
+       
+       /* Timing register format is 17 - low nybble read timing with
+          the high nybble being 16 - x for recovery time in PCI clocks */
+   
+       ata_timing_compute(adev, adev->pio_mode, &t, T, 0);
+
+       clocking = 17 - FIT(t.active, 2, 17);
+       clocking |= (16 - FIT(t.recover, 1, 16)) << 4;
+       /* Use the same timing for read and write bytes */
+       clocking |= (clocking << 8);
+       pci_write_config_word(dev, timing, clocking);
+       
+       /* Set the IORDY enable versus DMA enable on or off properly */
+       pci_read_config_byte(dev, 0x42, &iordy);
+       iordy &= ~(1 << (4 + unit));
+       if (mode >= XFER_MW_DMA_0 || !ata_pio_need_iordy(adev))
+               iordy |= (1 << (4 + unit));
+
+       /* Paranoia: We shouldn't ever get here with busy write buffers
+          but if so wait */
+
+       pci_read_config_byte(dev, 0x43, &status);
+       while (status & 0x03) {
+               udelay(1);
+               pci_read_config_byte(dev, 0x43, &status);
+       }
+       /* Flip the IORDY/DMA bits now we are sure the write buffers are
+          clear */
+       pci_write_config_byte(dev, 0x42, iordy);
+
+       /* TODO: Set byte 54 command timing to the best 8bit
+          mode shared by all four devices */
+}
+
+/**
+ *     ns87415_set_piomode - Initialize host controller PATA PIO timings
+ *     @ap: Port whose timings we are configuring
+ *     @adev: Device to program
+ *
+ *     Set PIO mode for device, in host controller PCI config space.
+ *
+ *     LOCKING:
+ *     None (inherited from caller).
+ */
+
+static void ns87415_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+       ns87415_set_mode(ap, adev, adev->pio_mode);
+}
+
+/**
+ *     ns87415_bmdma_setup             -       Set up DMA
+ *     @qc: Command block
+ *
+ *     Set up for bus masterng DMA. We have to do this ourselves
+ *     rather than use the helper due to a chip erratum
+ */
+
+static void ns87415_bmdma_setup(struct ata_queued_cmd *qc)
+{
+       struct ata_port *ap = qc->ap;
+       unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
+       u8 dmactl;
+
+       /* load PRD table addr. */
+       mb();   /* make sure PRD table writes are visible to controller */
+       iowrite32(ap->prd_dma, 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 | ATA_DMA_START);
+       /* Due to an erratum we need to write these bits to the wrong
+          place - which does save us an I/O bizarrely */
+       dmactl |= ATA_DMA_INTR | ATA_DMA_ERR;
+       if (!rw)
+               dmactl |= ATA_DMA_WR;
+       iowrite8(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+       /* issue r/w command */
+       ap->ops->exec_command(ap, &qc->tf);
+}
+
+/**
+ *     ns87415_bmdma_start             -       Begin DMA transfer
+ *     @qc: Command block
+ *
+ *     Switch the timings for the chip and set up for a DMA transfer
+ *     before the DMA burst begins.
+ *
+ *     FIXME: We should do lazy switching on bmdma_start versus
+ *     ata_pio_data_xfer for better performance.
+ */
+
+static void ns87415_bmdma_start(struct ata_queued_cmd *qc)
+{
+       ns87415_set_mode(qc->ap, qc->dev, qc->dev->dma_mode);
+       ata_bmdma_start(qc);
+}
+
+/**
+ *     ns87415_bmdma_stop              -       End DMA transfer
+ *     @qc: Command block
+ *
+ *     End DMA mode and switch the controller back into PIO mode
+ */
+
+static void ns87415_bmdma_stop(struct ata_queued_cmd *qc)
+{
+       ata_bmdma_stop(qc);
+       ns87415_set_mode(qc->ap, qc->dev, qc->dev->pio_mode);
+}
+
+/**
+ *     ns87415_bmdma_irq_clear         -       Clear interrupt
+ *     @ap: Channel to clear
+ *
+ *     Erratum: Due to a chip bug regisers 02 and 0A bit 1 and 2 (the
+ *     error bits) are reset by writing to register 00 or 08.
+ */
+
+static void ns87415_bmdma_irq_clear(struct ata_port *ap)
+{
+       void __iomem *mmio = ap->ioaddr.bmdma_addr;
+
+       if (!mmio)
+               return;
+       iowrite8((ioread8(mmio + ATA_DMA_CMD) | ATA_DMA_INTR | ATA_DMA_ERR), 
+                       mmio + ATA_DMA_CMD);
+}
+
+/**
+ *     ns87415_check_atapi_dma         -       ATAPI DMA filter
+ *     @qc: Command block
+ *
+ *     Disable ATAPI DMA (for now). We may be able to do DMA if we
+ *     kill the prefetching. This isn't clear.
+ */
+
+static int ns87415_check_atapi_dma(struct ata_queued_cmd *qc)
+{
+       return -EOPNOTSUPP;
+}
+
+#if defined(CONFIG_SUPERIO)
+
+/* SUPERIO 87560 is a PoS chip that NatSem denies exists.
+ * Unfortunately, it's built-in on all Astro-based PA-RISC workstations
+ * which use the integrated NS87514 cell for CD-ROM support.
+ * i.e we have to support for CD-ROM installs.
+ * See drivers/parisc/superio.c for more gory details.
+ *
+ * Workarounds taken from drivers/ide/pci/ns87415.c
+ */
+
+#include <asm/superio.h>
+
+/**
+ *     ns87560_read_buggy      -       workaround buggy Super I/O chip
+ *     @port: Port to read
+ *
+ *     Work around chipset problems in the 87560 SuperIO chip
+ */
+
+static u8 ns87560_read_buggy(void __iomem *port)
+{
+       u8 tmp;
+       int retries = SUPERIO_IDE_MAX_RETRIES;
+       do {
+               tmp = ioread8(port);
+               if (tmp != 0)
+                       return tmp;
+               udelay(50);
+       } while(retries-- > 0);
+       return tmp;
+}
+
+/**
+ *     ns87560_check_status
+ *     @ap: channel to check
+ *
+ *     Return the status of the channel working around the
+ *     87560 flaws.
+ */
+
+static u8 ns87560_check_status(struct ata_port *ap)
+{
+       return ns87560_read_buggy(ap->ioaddr.status_addr);
+}
+
+/**
+ *     ns87560_tf_read - input device's ATA taskfile shadow registers
+ *     @ap: Port from which input is read
+ *     @tf: ATA taskfile register set for storing input
+ *
+ *     Reads ATA taskfile registers for currently-selected device
+ *     into @tf. Work around the 87560 bugs.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+void ns87560_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+       struct ata_ioports *ioaddr = &ap->ioaddr;
+
+       tf->command = ns87560_check_status(ap);
+       tf->feature = ioread8(ioaddr->error_addr);
+       tf->nsect = ioread8(ioaddr->nsect_addr);
+       tf->lbal = ioread8(ioaddr->lbal_addr);
+       tf->lbam = ioread8(ioaddr->lbam_addr);
+       tf->lbah = ioread8(ioaddr->lbah_addr);
+       tf->device = ns87560_read_buggy(ioaddr->device_addr);
+
+       if (tf->flags & ATA_TFLAG_LBA48) {
+               iowrite8(tf->ctl | ATA_HOB, ioaddr->ctl_addr);
+               tf->hob_feature = ioread8(ioaddr->error_addr);
+               tf->hob_nsect = ioread8(ioaddr->nsect_addr);
+               tf->hob_lbal = ioread8(ioaddr->lbal_addr);
+               tf->hob_lbam = ioread8(ioaddr->lbam_addr);
+               tf->hob_lbah = ioread8(ioaddr->lbah_addr);
+               iowrite8(tf->ctl, ioaddr->ctl_addr);
+               ap->last_ctl = tf->ctl;
+       }
+}
+
+/**
+ *     ns87560_bmdma_status
+ *     @ap: channel to check
+ *
+ *     Return the DMA status of the channel working around the
+ *     87560 flaws.
+ */
+
+static u8 ns87560_bmdma_status(struct ata_port *ap)
+{
+       return ns87560_read_buggy(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+}
+
+static const struct ata_port_operations ns87560_pata_ops = {
+       .set_piomode            = ns87415_set_piomode,
+       .mode_filter            = ata_pci_default_filter,
+
+       .tf_load                = ata_tf_load,
+       .tf_read                = ns87560_tf_read,
+       .check_status           = ns87560_check_status,
+       .check_atapi_dma        = ns87415_check_atapi_dma,
+       .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           = ata_cable_40wire,
+
+       .bmdma_setup            = ns87415_bmdma_setup,
+       .bmdma_start            = ns87415_bmdma_start,
+       .bmdma_stop             = ns87415_bmdma_stop,
+       .bmdma_status           = ns87560_bmdma_status,
+       .qc_prep                = ata_qc_prep,
+       .qc_issue               = ata_qc_issue_prot,
+       .data_xfer              = ata_data_xfer,
+
+       .irq_handler            = ata_interrupt,
+       .irq_clear              = ns87415_bmdma_irq_clear,
+       .irq_on                 = ata_irq_on,
+
+       .port_start             = ata_sff_port_start,
+};
+
+#endif         /* 87560 SuperIO Support */
+
+
+static const struct ata_port_operations ns87415_pata_ops = {
+       .set_piomode            = ns87415_set_piomode,
+       .mode_filter            = ata_pci_default_filter,
+
+       .tf_load                = ata_tf_load,
+       .tf_read                = ata_tf_read,
+       .check_status           = ata_check_status,
+       .check_atapi_dma        = ns87415_check_atapi_dma,
+       .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           = ata_cable_40wire,
+
+       .bmdma_setup            = ns87415_bmdma_setup,
+       .bmdma_start            = ns87415_bmdma_start,
+       .bmdma_stop             = ns87415_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              = ns87415_bmdma_irq_clear,
+       .irq_on                 = ata_irq_on,
+
+       .port_start             = ata_sff_port_start,
+};
+
+static struct scsi_host_template ns87415_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,
+};
+
+
+/**
+ *     ns87415_init_one - Register 87415 ATA PCI device with kernel services
+ *     @pdev: PCI device to register
+ *     @ent: Entry in ns87415_pci_tbl matching with @pdev
+ *
+ *     Called from kernel PCI layer.  We probe for combined mode (sigh),
+ *     and then hand over control to libata, for it to do the rest.
+ *
+ *     LOCKING:
+ *     Inherited from PCI layer (may sleep).
+ *
+ *     RETURNS:
+ *     Zero on success, or -ERRNO value.
+ */
+
+static int ns87415_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+       static int printed_version;
+       static const struct ata_port_info info = {
+               .sht            = &ns87415_sht,
+               .flags          = ATA_FLAG_SLAVE_POSS,
+               .pio_mask       = 0x1f, /* pio0-4 */
+               .mwdma_mask     = 0x07, /* mwdma0-2 */
+               .port_ops       = &ns87415_pata_ops,
+       };
+       const struct ata_port_info *ppi[] = { &info, NULL };
+#if defined(CONFIG_SUPERIO)
+       static const struct ata_port_info info87560 = {
+               .sht            = &ns87415_sht,
+               .flags          = ATA_FLAG_SLAVE_POSS,
+               .pio_mask       = 0x1f, /* pio0-4 */
+               .mwdma_mask     = 0x07, /* mwdma0-2 */
+               .port_ops       = &ns87560_pata_ops,
+       };
+
+       if (PCI_SLOT(pdev->devfn) == 0x0E)
+               ppi[0] = &info87560;
+#endif
+       if (!printed_version++)
+               dev_printk(KERN_DEBUG, &pdev->dev,
+                          "version " DRV_VERSION "\n");
+       /* Select 512 byte sectors */
+       pci_write_config_byte(pdev, 0x55, 0xEE);
+       /* Select PIO0 8bit clocking */
+       pci_write_config_byte(pdev, 0x54, 0xB7);
+       return ata_pci_init_one(pdev, ppi);
+}
+
+static const struct pci_device_id ns87415_pci_tbl[] = {
+       { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_87415), },
+
+       { }     /* terminate list */
+};
+
+static struct pci_driver ns87415_pci_driver = {
+       .name                   = DRV_NAME,
+       .id_table               = ns87415_pci_tbl,
+       .probe                  = ns87415_init_one,
+       .remove                 = ata_pci_remove_one,
+#ifdef CONFIG_PM
+       .suspend                = ata_pci_device_suspend,
+       .resume                 = ata_pci_device_resume,
+#endif
+};
+
+static int __init ns87415_init(void)
+{
+       return pci_register_driver(&ns87415_pci_driver);
+}
+
+static void __exit ns87415_exit(void)
+{
+       pci_unregister_driver(&ns87415_pci_driver);
+}
+
+module_init(ns87415_init);
+module_exit(ns87415_exit);
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("ATA low-level driver for NS87415 controllers");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, ns87415_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
index 091a70a0ef1cf0cd391e16e83568cf01103b7dad..3cd5eb2b6c9191383ee2fa64acc81d7e129d9315 100644 (file)
 
 /**
  *     oldpiix_pre_reset               -       probe begin
- *     @ap: ATA port
+ *     @link: ATA link
  *     @deadline: deadline jiffies for the operation
  *
  *     Set up cable type and use generic probe init
  */
 
-static int oldpiix_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int oldpiix_pre_reset(struct ata_link *link, unsigned long deadline)
 {
+       struct ata_port *ap = link->ap;
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        static const struct pci_bits oldpiix_enable_bits[] = {
                { 0x41U, 1U, 0x80UL, 0x80UL },  /* port 0 */
@@ -46,7 +47,7 @@ static int oldpiix_pre_reset(struct ata_port *ap, unsigned long deadline)
        if (!pci_test_config_bits(pdev, &oldpiix_enable_bits[ap->port_no]))
                return -ENOENT;
 
-       return ata_std_prereset(ap, deadline);
+       return ata_std_prereset(link, deadline);
 }
 
 /**
@@ -237,7 +238,6 @@ static struct scsi_host_template oldpiix_sht = {
 };
 
 static const struct ata_port_operations oldpiix_pata_ops = {
-       .port_disable           = ata_port_disable,
        .set_piomode            = oldpiix_set_piomode,
        .set_dmamode            = oldpiix_set_dmamode,
        .mode_filter            = ata_pci_default_filter,
@@ -265,9 +265,8 @@ static const struct ata_port_operations oldpiix_pata_ops = {
        .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,
+       .port_start             = ata_sff_port_start,
 };
 
 
index 458bf67f766fd246cf89539f13bc54b175322e13..8f79447b6151a006629ce1b0aea6a94d7f030b4d 100644 (file)
@@ -46,14 +46,15 @@ enum {
 
 /**
  *     opti_pre_reset          -       probe begin
- *     @ap: ATA port
+ *     @link: ATA link
  *     @deadline: deadline jiffies for the operation
  *
  *     Set up cable type and use generic probe init
  */
 
-static int opti_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int opti_pre_reset(struct ata_link *link, unsigned long deadline)
 {
+       struct ata_port *ap = link->ap;
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        static const struct pci_bits opti_enable_bits[] = {
                { 0x45, 1, 0x80, 0x00 },
@@ -63,7 +64,7 @@ static int opti_pre_reset(struct ata_port *ap, unsigned long deadline)
        if (!pci_test_config_bits(pdev, &opti_enable_bits[ap->port_no]))
                return -ENOENT;
 
-       return ata_std_prereset(ap, deadline);
+       return ata_std_prereset(link, deadline);
 }
 
 /**
@@ -182,7 +183,6 @@ static struct scsi_host_template opti_sht = {
 };
 
 static struct ata_port_operations opti_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = opti_set_piomode,
        .tf_load        = ata_tf_load,
        .tf_read        = ata_tf_read,
@@ -209,9 +209,8 @@ static struct ata_port_operations opti_port_ops = {
        .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,
+       .port_start     = ata_sff_port_start,
 };
 
 static int opti_init_one(struct pci_dev *dev, const struct pci_device_id *id)
index f89bdfde16d067469528557f0036dbaf5304a65e..6b07b5b48532ff015a9f6ef08dd7619e1c7561d6 100644 (file)
@@ -47,14 +47,15 @@ static int pci_clock;       /* 0 = 33 1 = 25 */
 
 /**
  *     optidma_pre_reset               -       probe begin
- *     @ap: ATA port
+ *     @link: ATA link
  *     @deadline: deadline jiffies for the operation
  *
  *     Set up cable type and use generic probe init
  */
 
-static int optidma_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int optidma_pre_reset(struct ata_link *link, unsigned long deadline)
 {
+       struct ata_port *ap = link->ap;
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        static const struct pci_bits optidma_enable_bits = {
                0x40, 1, 0x08, 0x00
@@ -63,7 +64,7 @@ static int optidma_pre_reset(struct ata_port *ap, unsigned long deadline)
        if (ap->port_no && !pci_test_config_bits(pdev, &optidma_enable_bits))
                return -ENOENT;
 
-       return ata_std_prereset(ap, deadline);
+       return ata_std_prereset(link, deadline);
 }
 
 /**
@@ -323,25 +324,26 @@ static u8 optidma_make_bits43(struct ata_device *adev)
 
 /**
  *     optidma_set_mode        -       mode setup
- *     @ap: port to set up
+ *     @link: link to set up
  *
  *     Use the standard setup to tune the chipset and then finalise the
  *     configuration by writing the nibble of extra bits of data into
  *     the chip.
  */
 
-static int optidma_set_mode(struct ata_port *ap, struct ata_device **r_failed)
+static int optidma_set_mode(struct ata_link *link, struct ata_device **r_failed)
 {
+       struct ata_port *ap = link->ap;
        u8 r;
        int nybble = 4 * ap->port_no;
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-       int rc  = ata_do_set_mode(ap, r_failed);
+       int rc  = ata_do_set_mode(link, r_failed);
        if (rc == 0) {
                pci_read_config_byte(pdev, 0x43, &r);
 
                r &= (0x0F << nybble);
-               r |= (optidma_make_bits43(&ap->device[0]) +
-                    (optidma_make_bits43(&ap->device[0]) << 2)) << nybble;
+               r |= (optidma_make_bits43(&link->device[0]) +
+                    (optidma_make_bits43(&link->device[0]) << 2)) << nybble;
                pci_write_config_byte(pdev, 0x43, r);
        }
        return rc;
@@ -366,7 +368,6 @@ static struct scsi_host_template optidma_sht = {
 };
 
 static struct ata_port_operations optidma_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = optidma_set_pio_mode,
        .set_dmamode    = optidma_set_dma_mode,
 
@@ -396,13 +397,11 @@ static struct ata_port_operations optidma_port_ops = {
        .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,
+       .port_start     = ata_sff_port_start,
 };
 
 static struct ata_port_operations optiplus_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = optiplus_set_pio_mode,
        .set_dmamode    = optiplus_set_dma_mode,
 
@@ -432,9 +431,8 @@ static struct ata_port_operations optiplus_port_ops = {
        .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,
+       .port_start     = ata_sff_port_start,
 };
 
 /**
index 0f2b027624d6e71273c01a4147f3d6afe2462da1..782ff4ada9d1f1c90299ff127e336a5ac911e749 100644 (file)
@@ -56,7 +56,7 @@ struct ata_pcmcia_info {
 
 /**
  *     pcmcia_set_mode -       PCMCIA specific mode setup
- *     @ap: Port
+ *     @link: link
  *     @r_failed_dev: Return pointer for failed device
  *
  *     Perform the tuning and setup of the devices and timings, which
@@ -65,13 +65,13 @@ struct ata_pcmcia_info {
  *     decode, which alas is embarrassingly common in the PC world
  */
 
-static int pcmcia_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
+static int pcmcia_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
 {
-       struct ata_device *master = &ap->device[0];
-       struct ata_device *slave = &ap->device[1];
+       struct ata_device *master = &link->device[0];
+       struct ata_device *slave = &link->device[1];
 
        if (!ata_dev_enabled(master) || !ata_dev_enabled(slave))
-               return ata_do_set_mode(ap, r_failed_dev);
+               return ata_do_set_mode(link, r_failed_dev);
 
        if (memcmp(master->id + ATA_ID_FW_REV,  slave->id + ATA_ID_FW_REV,
                           ATA_ID_FW_REV_LEN + ATA_ID_PROD_LEN) == 0)
@@ -84,7 +84,7 @@ static int pcmcia_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev
                        ata_dev_disable(slave);
                }
        }
-       return ata_do_set_mode(ap, r_failed_dev);
+       return ata_do_set_mode(link, r_failed_dev);
 }
 
 static struct scsi_host_template pcmcia_sht = {
@@ -107,7 +107,6 @@ static struct scsi_host_template pcmcia_sht = {
 
 static struct ata_port_operations pcmcia_port_ops = {
        .set_mode       = pcmcia_set_mode,
-       .port_disable   = ata_port_disable,
        .tf_load        = ata_tf_load,
        .tf_read        = ata_tf_read,
        .check_status   = ata_check_status,
@@ -127,7 +126,6 @@ static struct ata_port_operations pcmcia_port_ops = {
 
        .irq_clear      = ata_bmdma_irq_clear,
        .irq_on         = ata_irq_on,
-       .irq_ack        = ata_irq_ack,
 
        .port_start     = ata_sff_port_start,
 };
@@ -304,6 +302,8 @@ next_entry:
        ap->ioaddr.ctl_addr = ctl_addr;
        ata_std_ports(&ap->ioaddr);
 
+       ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", io_base, ctl_base);
+
        /* activate */
        ret = ata_host_activate(host, pdev->irq.AssignedIRQ, ata_interrupt,
                                IRQF_SHARED, &pcmcia_sht);
index bb64a986e8f5496028fd174452eeb22872285f7c..3d3f1558cdee7e9be3c9e92e3059c711b4ad3478 100644 (file)
@@ -69,7 +69,7 @@ static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev);
 static int pdc2027x_check_atapi_dma(struct ata_queued_cmd *qc);
 static unsigned long pdc2027x_mode_filter(struct ata_device *adev, unsigned long mask);
 static int pdc2027x_cable_detect(struct ata_port *ap);
-static int pdc2027x_set_mode(struct ata_port *ap, struct ata_device **r_failed);
+static int pdc2027x_set_mode(struct ata_link *link, struct ata_device **r_failed);
 
 /*
  * ATA Timing Tables based on 133MHz controller clock.
@@ -147,7 +147,6 @@ static struct scsi_host_template pdc2027x_sht = {
 };
 
 static struct ata_port_operations pdc2027x_pata100_ops = {
-       .port_disable           = ata_port_disable,
        .mode_filter            = ata_pci_default_filter,
 
        .tf_load                = ata_tf_load,
@@ -173,13 +172,11 @@ static struct ata_port_operations pdc2027x_pata100_ops = {
 
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
-       .irq_ack                = ata_irq_ack,
 
-       .port_start             = ata_port_start,
+       .port_start             = ata_sff_port_start,
 };
 
 static struct ata_port_operations pdc2027x_pata133_ops = {
-       .port_disable           = ata_port_disable,
        .set_piomode            = pdc2027x_set_piomode,
        .set_dmamode            = pdc2027x_set_dmamode,
        .set_mode               = pdc2027x_set_mode,
@@ -208,9 +205,8 @@ static struct ata_port_operations pdc2027x_pata133_ops = {
 
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
-       .irq_ack                = ata_irq_ack,
 
-       .port_start             = ata_port_start,
+       .port_start             = ata_sff_port_start,
 };
 
 static struct ata_port_info pdc2027x_port_info[] = {
@@ -277,7 +273,7 @@ static int pdc2027x_cable_detect(struct ata_port *ap)
        u32 cgcr;
 
        /* check cable detect results */
-       cgcr = readl(port_mmio(ap, PDC_GLOBAL_CTL));
+       cgcr = ioread32(port_mmio(ap, PDC_GLOBAL_CTL));
        if (cgcr & (1 << 26))
                goto cbl40;
 
@@ -295,12 +291,12 @@ cbl40:
  */
 static inline int pdc2027x_port_enabled(struct ata_port *ap)
 {
-       return readb(port_mmio(ap, PDC_ATA_CTL)) & 0x02;
+       return ioread8(port_mmio(ap, PDC_ATA_CTL)) & 0x02;
 }
 
 /**
  *     pdc2027x_prereset - prereset for PATA host controller
- *     @ap: Target port
+ *     @link: Target link
  *     @deadline: deadline jiffies for the operation
  *
  *     Probeinit including cable detection.
@@ -309,12 +305,12 @@ static inline int pdc2027x_port_enabled(struct ata_port *ap)
  *     None (inherited from caller).
  */
 
-static int pdc2027x_prereset(struct ata_port *ap, unsigned long deadline)
+static int pdc2027x_prereset(struct ata_link *link, unsigned long deadline)
 {
        /* Check whether port enabled */
-       if (!pdc2027x_port_enabled(ap))
+       if (!pdc2027x_port_enabled(link->ap))
                return -ENOENT;
-       return ata_std_prereset(ap, deadline);
+       return ata_std_prereset(link, deadline);
 }
 
 /**
@@ -387,16 +383,16 @@ static void pdc2027x_set_piomode(struct ata_port *ap, struct ata_device *adev)
        /* Set the PIO timing registers using value table for 133MHz */
        PDPRINTK("Set pio regs... \n");
 
-       ctcr0 = readl(dev_mmio(ap, adev, PDC_CTCR0));
+       ctcr0 = ioread32(dev_mmio(ap, adev, PDC_CTCR0));
        ctcr0 &= 0xffff0000;
        ctcr0 |= pdc2027x_pio_timing_tbl[pio].value0 |
                (pdc2027x_pio_timing_tbl[pio].value1 << 8);
-       writel(ctcr0, dev_mmio(ap, adev, PDC_CTCR0));
+       iowrite32(ctcr0, dev_mmio(ap, adev, PDC_CTCR0));
 
-       ctcr1 = readl(dev_mmio(ap, adev, PDC_CTCR1));
+       ctcr1 = ioread32(dev_mmio(ap, adev, PDC_CTCR1));
        ctcr1 &= 0x00ffffff;
        ctcr1 |= (pdc2027x_pio_timing_tbl[pio].value2 << 24);
-       writel(ctcr1, dev_mmio(ap, adev, PDC_CTCR1));
+       iowrite32(ctcr1, dev_mmio(ap, adev, PDC_CTCR1));
 
        PDPRINTK("Set pio regs done\n");
 
@@ -430,18 +426,18 @@ static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
                         * If tHOLD is '1', the hardware will add half clock for data hold time.
                         * This code segment seems to be no effect. tHOLD will be overwritten below.
                         */
-                       ctcr1 = readl(dev_mmio(ap, adev, PDC_CTCR1));
-                       writel(ctcr1 & ~(1 << 7), dev_mmio(ap, adev, PDC_CTCR1));
+                       ctcr1 = ioread32(dev_mmio(ap, adev, PDC_CTCR1));
+                       iowrite32(ctcr1 & ~(1 << 7), dev_mmio(ap, adev, PDC_CTCR1));
                }
 
                PDPRINTK("Set udma regs... \n");
 
-               ctcr1 = readl(dev_mmio(ap, adev, PDC_CTCR1));
+               ctcr1 = ioread32(dev_mmio(ap, adev, PDC_CTCR1));
                ctcr1 &= 0xff000000;
                ctcr1 |= pdc2027x_udma_timing_tbl[udma_mode].value0 |
                        (pdc2027x_udma_timing_tbl[udma_mode].value1 << 8) |
                        (pdc2027x_udma_timing_tbl[udma_mode].value2 << 16);
-               writel(ctcr1, dev_mmio(ap, adev, PDC_CTCR1));
+               iowrite32(ctcr1, dev_mmio(ap, adev, PDC_CTCR1));
 
                PDPRINTK("Set udma regs done\n");
 
@@ -453,13 +449,13 @@ static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
                unsigned int mdma_mode = dma_mode & 0x07;
 
                PDPRINTK("Set mdma regs... \n");
-               ctcr0 = readl(dev_mmio(ap, adev, PDC_CTCR0));
+               ctcr0 = ioread32(dev_mmio(ap, adev, PDC_CTCR0));
 
                ctcr0 &= 0x0000ffff;
                ctcr0 |= (pdc2027x_mdma_timing_tbl[mdma_mode].value0 << 16) |
                        (pdc2027x_mdma_timing_tbl[mdma_mode].value1 << 24);
 
-               writel(ctcr0, dev_mmio(ap, adev, PDC_CTCR0));
+               iowrite32(ctcr0, dev_mmio(ap, adev, PDC_CTCR0));
                PDPRINTK("Set mdma regs done\n");
 
                PDPRINTK("Set to mdma mode[%u] \n", mdma_mode);
@@ -470,24 +466,24 @@ static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
 
 /**
  *     pdc2027x_set_mode - Set the timing registers back to correct values.
- *     @ap: Port to configure
+ *     @link: link to configure
  *     @r_failed: Returned device for failure
  *
  *     The pdc2027x hardware will look at "SET FEATURES" and change the timing registers
  *     automatically. The values set by the hardware might be incorrect, under 133Mhz PLL.
  *     This function overwrites the possibly incorrect values set by the hardware to be correct.
  */
-static int pdc2027x_set_mode(struct ata_port *ap, struct ata_device **r_failed)
+static int pdc2027x_set_mode(struct ata_link *link, struct ata_device **r_failed)
 {
-       int i;
-
-       i = ata_do_set_mode(ap, r_failed);
-       if (i < 0)
-               return i;
+       struct ata_port *ap = link->ap;
+       struct ata_device *dev;
+       int rc;
 
-       for (i = 0; i < ATA_MAX_DEVICES; i++) {
-               struct ata_device *dev = &ap->device[i];
+       rc = ata_do_set_mode(link, r_failed);
+       if (rc < 0)
+               return rc;
 
+       ata_link_for_each_dev(dev, link) {
                if (ata_dev_enabled(dev)) {
 
                        pdc2027x_set_piomode(ap, dev);
@@ -496,9 +492,9 @@ static int pdc2027x_set_mode(struct ata_port *ap, struct ata_device **r_failed)
                         * Enable prefetch if the device support PIO only.
                         */
                        if (dev->xfer_shift == ATA_SHIFT_PIO) {
-                               u32 ctcr1 = readl(dev_mmio(ap, dev, PDC_CTCR1));
+                               u32 ctcr1 = ioread32(dev_mmio(ap, dev, PDC_CTCR1));
                                ctcr1 |= (1 << 25);
-                               writel(ctcr1, dev_mmio(ap, dev, PDC_CTCR1));
+                               iowrite32(ctcr1, dev_mmio(ap, dev, PDC_CTCR1));
 
                                PDPRINTK("Turn on prefetch\n");
                        } else {
@@ -563,14 +559,12 @@ static long pdc_read_counter(struct ata_host *host)
        u32 bccrl, bccrh, bccrlv, bccrhv;
 
 retry:
-       bccrl = readl(mmio_base + PDC_BYTE_COUNT) & 0x7fff;
-       bccrh = readl(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff;
-       rmb();
+       bccrl = ioread32(mmio_base + PDC_BYTE_COUNT) & 0x7fff;
+       bccrh = ioread32(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff;
 
        /* Read the counter values again for verification */
-       bccrlv = readl(mmio_base + PDC_BYTE_COUNT) & 0x7fff;
-       bccrhv = readl(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff;
-       rmb();
+       bccrlv = ioread32(mmio_base + PDC_BYTE_COUNT) & 0x7fff;
+       bccrhv = ioread32(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff;
 
        counter = (bccrh << 15) | bccrl;
 
@@ -619,7 +613,7 @@ static void pdc_adjust_pll(struct ata_host *host, long pll_clock, unsigned int b
        /* Show the current clock value of PLL control register
         * (maybe already configured by the firmware)
         */
-       pll_ctl = readw(mmio_base + PDC_PLL_CTL);
+       pll_ctl = ioread16(mmio_base + PDC_PLL_CTL);
 
        PDPRINTK("pll_ctl[%X]\n", pll_ctl);
 #endif
@@ -659,8 +653,8 @@ static void pdc_adjust_pll(struct ata_host *host, long pll_clock, unsigned int b
 
        PDPRINTK("Writing pll_ctl[%X]\n", pll_ctl);
 
-       writew(pll_ctl, mmio_base + PDC_PLL_CTL);
-       readw(mmio_base + PDC_PLL_CTL); /* flush */
+       iowrite16(pll_ctl, mmio_base + PDC_PLL_CTL);
+       ioread16(mmio_base + PDC_PLL_CTL); /* flush */
 
        /* Wait the PLL circuit to be stable */
        mdelay(30);
@@ -670,7 +664,7 @@ static void pdc_adjust_pll(struct ata_host *host, long pll_clock, unsigned int b
         *  Show the current clock value of PLL control register
         * (maybe configured by the firmware)
         */
-       pll_ctl = readw(mmio_base + PDC_PLL_CTL);
+       pll_ctl = ioread16(mmio_base + PDC_PLL_CTL);
 
        PDPRINTK("pll_ctl[%X]\n", pll_ctl);
 #endif
@@ -693,10 +687,10 @@ static long pdc_detect_pll_input_clock(struct ata_host *host)
        long pll_clock, usec_elapsed;
 
        /* Start the test mode */
-       scr = readl(mmio_base + PDC_SYS_CTL);
+       scr = ioread32(mmio_base + PDC_SYS_CTL);
        PDPRINTK("scr[%X]\n", scr);
-       writel(scr | (0x01 << 14), mmio_base + PDC_SYS_CTL);
-       readl(mmio_base + PDC_SYS_CTL); /* flush */
+       iowrite32(scr | (0x01 << 14), mmio_base + PDC_SYS_CTL);
+       ioread32(mmio_base + PDC_SYS_CTL); /* flush */
 
        /* Read current counter value */
        start_count = pdc_read_counter(host);
@@ -710,10 +704,10 @@ static long pdc_detect_pll_input_clock(struct ata_host *host)
        do_gettimeofday(&end_time);
 
        /* Stop the test mode */
-       scr = readl(mmio_base + PDC_SYS_CTL);
+       scr = ioread32(mmio_base + PDC_SYS_CTL);
        PDPRINTK("scr[%X]\n", scr);
-       writel(scr & ~(0x01 << 14), mmio_base + PDC_SYS_CTL);
-       readl(mmio_base + PDC_SYS_CTL); /* flush */
+       iowrite32(scr & ~(0x01 << 14), mmio_base + PDC_SYS_CTL);
+       ioread32(mmio_base + PDC_SYS_CTL); /* flush */
 
        /* calculate the input clock in Hz */
        usec_elapsed = (end_time.tv_sec - start_time.tv_sec) * 1000000 +
@@ -745,9 +739,6 @@ static int pdc_hardware_init(struct ata_host *host, unsigned int board_idx)
         */
        pll_clock = pdc_detect_pll_input_clock(host);
 
-       if (pll_clock < 0) /* counter overflow? Try again. */
-               pll_clock = pdc_detect_pll_input_clock(host);
-
        dev_printk(KERN_INFO, host->dev, "PLL input clock %ld kHz\n", pll_clock/1000);
 
        /* Adjust PLL control register */
@@ -791,12 +782,14 @@ static void pdc_ata_setup_port(struct ata_ioports *port, void __iomem *base)
 static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        static int printed_version;
+       static const unsigned long cmd_offset[] = { 0x17c0, 0x15c0 };
+       static const unsigned long bmdma_offset[] = { 0x1000, 0x1008 };
        unsigned int board_idx = (unsigned int) ent->driver_data;
        const struct ata_port_info *ppi[] =
                { &pdc2027x_port_info[board_idx], NULL };
        struct ata_host *host;
        void __iomem *mmio_base;
-       int rc;
+       int i, rc;
 
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
@@ -826,10 +819,15 @@ static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_de
 
        mmio_base = host->iomap[PDC_MMIO_BAR];
 
-       pdc_ata_setup_port(&host->ports[0]->ioaddr, mmio_base + 0x17c0);
-       host->ports[0]->ioaddr.bmdma_addr = mmio_base + 0x1000;
-       pdc_ata_setup_port(&host->ports[1]->ioaddr, mmio_base + 0x15c0);
-       host->ports[1]->ioaddr.bmdma_addr = mmio_base + 0x1008;
+       for (i = 0; i < 2; i++) {
+               struct ata_port *ap = host->ports[i];
+
+               pdc_ata_setup_port(&ap->ioaddr, mmio_base + cmd_offset[i]);
+               ap->ioaddr.bmdma_addr = mmio_base + bmdma_offset[i];
+
+               ata_port_pbar_desc(ap, PDC_MMIO_BAR, -1, "mmio");
+               ata_port_pbar_desc(ap, PDC_MMIO_BAR, cmd_offset[i], "cmd");
+       }
 
        //pci_enable_intx(pdev);
 
index 92447bed5e7716f615b423672bf0e52e524ce1f9..65d951618c605d1c9e908a508c528014ac4b2b6c 100644 (file)
@@ -9,7 +9,7 @@
  * First cut with LBA48/ATAPI
  *
  * TODO:
- *     Channel interlock/reset on both required
+ *     Channel interlock/reset on both required ?
  */
 
 #include <linux/kernel.h>
@@ -22,7 +22,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_pdc202xx_old"
-#define DRV_VERSION "0.4.2"
+#define DRV_VERSION "0.4.3"
 
 static int pdc2026x_cable_detect(struct ata_port *ap)
 {
@@ -106,9 +106,9 @@ static void pdc202xx_set_dmamode(struct ata_port *ap, struct ata_device *adev)
                { 0x20, 0x01 }
        };
        static u8 mdma_timing[3][2] = {
-               { 0x60, 0x03 },
-               { 0x60, 0x04 },
                { 0xe0, 0x0f },
+               { 0x60, 0x04 },
+               { 0x60, 0x03 },
        };
        u8 r_bp, r_cp;
 
@@ -139,6 +139,9 @@ static void pdc202xx_set_dmamode(struct ata_port *ap, struct ata_device *adev)
  *
  *     In UDMA3 or higher we have to clock switch for the duration of the
  *     DMA transfer sequence.
+ *
+ *     Note: The host lock held by the libata layer protects
+ *     us from two channels both trying to set DMA bits at once
  */
 
 static void pdc2026x_bmdma_start(struct ata_queued_cmd *qc)
@@ -187,6 +190,9 @@ static void pdc2026x_bmdma_start(struct ata_queued_cmd *qc)
  *
  *     After a DMA completes we need to put the clock back to 33MHz for
  *     PIO timings.
+ *
+ *     Note: The host lock held by the libata layer protects
+ *     us from two channels both trying to set DMA bits at once
  */
 
 static void pdc2026x_bmdma_stop(struct ata_queued_cmd *qc)
@@ -206,7 +212,6 @@ static void pdc2026x_bmdma_stop(struct ata_queued_cmd *qc)
                iowrite32(0, atapi_reg);
                iowrite8(ioread8(clock) & ~sel66, clock);
        }
-       /* Check we keep host level locking here */
        /* Flip back to 33Mhz for PIO */
        if (adev->dma_mode >= XFER_UDMA_2)
                iowrite8(ioread8(clock) & ~sel66, clock);
@@ -247,7 +252,6 @@ static struct scsi_host_template pdc202xx_sht = {
 };
 
 static struct ata_port_operations pdc2024x_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = pdc202xx_set_piomode,
        .set_dmamode    = pdc202xx_set_dmamode,
        .mode_filter    = ata_pci_default_filter,
@@ -275,13 +279,11 @@ static struct ata_port_operations pdc2024x_port_ops = {
        .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,
+       .port_start     = ata_sff_port_start,
 };
 
 static struct ata_port_operations pdc2026x_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = pdc202xx_set_piomode,
        .set_dmamode    = pdc202xx_set_dmamode,
        .mode_filter    = ata_pci_default_filter,
@@ -310,9 +312,8 @@ static struct ata_port_operations pdc2026x_port_ops = {
        .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,
+       .port_start     = ata_sff_port_start,
 };
 
 static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
index 5086d03f2d7c54883bb5c9ffaf4eba749bb32089..fc72a965643d8951f45e5957d98fc5924fefae24 100644 (file)
@@ -30,13 +30,11 @@ static int pio_mask = 1;
  * Provide our own set_mode() as we don't want to change anything that has
  * already been configured..
  */
-static int pata_platform_set_mode(struct ata_port *ap, struct ata_device **unused)
+static int pata_platform_set_mode(struct ata_link *link, struct ata_device **unused)
 {
-       int i;
-
-       for (i = 0; i < ATA_MAX_DEVICES; i++) {
-               struct ata_device *dev = &ap->device[i];
+       struct ata_device *dev;
 
+       ata_link_for_each_dev(dev, link) {
                if (ata_dev_enabled(dev)) {
                        /* We don't really care */
                        dev->pio_mode = dev->xfer_mode = XFER_PIO_0;
@@ -71,7 +69,6 @@ static struct scsi_host_template pata_platform_sht = {
 static struct ata_port_operations pata_platform_port_ops = {
        .set_mode               = pata_platform_set_mode,
 
-       .port_disable           = ata_port_disable,
        .tf_load                = ata_tf_load,
        .tf_read                = ata_tf_read,
        .check_status           = ata_check_status,
@@ -91,7 +88,6 @@ static struct ata_port_operations pata_platform_port_ops = {
 
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
-       .irq_ack                = ata_irq_ack,
 
        .port_start             = ata_dummy_ret0,
 };
@@ -209,9 +205,13 @@ static int __devinit pata_platform_probe(struct platform_device *pdev)
 
        ap->ioaddr.altstatus_addr = ap->ioaddr.ctl_addr;
 
-       pp_info = (struct pata_platform_info *)(pdev->dev.platform_data);
+       pp_info = pdev->dev.platform_data;
        pata_platform_setup_port(&ap->ioaddr, pp_info);
 
+       ata_port_desc(ap, "%s cmd 0x%llx ctl 0x%llx", mmio ? "mmio" : "ioport",
+                     (unsigned long long)io_res->start,
+                     (unsigned long long)ctl_res->start);
+
        /* activate */
        return ata_host_activate(host, platform_get_irq(pdev, 0),
                                 ata_interrupt, pp_info ? pp_info->irq_flags
index 1998c19e8743efd95c230002f52301b6124fd72e..7d4c696c4cb6b8cb5ccaa86a6ed893856ae3497f 100644 (file)
@@ -126,7 +126,7 @@ static unsigned int qdi_qc_issue_prot(struct ata_queued_cmd *qc)
 
 static void qdi_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data)
 {
-       struct ata_port *ap = adev->ap;
+       struct ata_port *ap = adev->link->ap;
        int slop = buflen & 3;
 
        if (ata_id_has_dword_io(adev->id)) {
@@ -170,7 +170,6 @@ static struct scsi_host_template qdi_sht = {
 };
 
 static struct ata_port_operations qdi6500_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = qdi6500_set_piomode,
 
        .tf_load        = ata_tf_load,
@@ -192,13 +191,11 @@ static struct ata_port_operations qdi6500_port_ops = {
 
        .irq_clear      = ata_bmdma_irq_clear,
        .irq_on         = ata_irq_on,
-       .irq_ack        = ata_irq_ack,
 
-       .port_start     = ata_port_start,
+       .port_start     = ata_sff_port_start,
 };
 
 static struct ata_port_operations qdi6580_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = qdi6580_set_piomode,
 
        .tf_load        = ata_tf_load,
@@ -220,9 +217,8 @@ static struct ata_port_operations qdi6580_port_ops = {
 
        .irq_clear      = ata_bmdma_irq_clear,
        .irq_on         = ata_irq_on,
-       .irq_ack        = ata_irq_ack,
 
-       .port_start     = ata_port_start,
+       .port_start     = ata_sff_port_start,
 };
 
 /**
@@ -238,6 +234,7 @@ static struct ata_port_operations qdi6580_port_ops = {
 
 static __init int qdi_init_one(unsigned long port, int type, unsigned long io, int irq, int fast)
 {
+       unsigned long ctl = io + 0x206;
        struct platform_device *pdev;
        struct ata_host *host;
        struct ata_port *ap;
@@ -254,7 +251,7 @@ static __init int qdi_init_one(unsigned long port, int type, unsigned long io, i
 
        ret = -ENOMEM;
        io_addr = devm_ioport_map(&pdev->dev, io, 8);
-       ctl_addr = devm_ioport_map(&pdev->dev, io + 0x206, 1);
+       ctl_addr = devm_ioport_map(&pdev->dev, ctl, 1);
        if (!io_addr || !ctl_addr)
                goto fail;
 
@@ -279,6 +276,8 @@ static __init int qdi_init_one(unsigned long port, int type, unsigned long io, i
        ap->ioaddr.ctl_addr = ctl_addr;
        ata_std_ports(&ap->ioaddr);
 
+       ata_port_desc(ap, "cmd %lx ctl %lx", io, ctl);
+
        /*
         *      Hook in a private data structure per channel
         */
index 7d1aabed422db6bd11c45c6f951171bed7a2c564..d5b76497f4a24ad891776e5d0a1b71d221954f05 100644 (file)
@@ -203,7 +203,6 @@ static struct scsi_host_template radisys_sht = {
 };
 
 static const struct ata_port_operations radisys_pata_ops = {
-       .port_disable           = ata_port_disable,
        .set_piomode            = radisys_set_piomode,
        .set_dmamode            = radisys_set_dmamode,
        .mode_filter            = ata_pci_default_filter,
@@ -231,9 +230,8 @@ static const struct ata_port_operations radisys_pata_ops = {
        .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,
+       .port_start             = ata_sff_port_start,
 };
 
 
index 7632fcb070ca8b1a85562fb0aee9ed2e1bdbfc35..ba8a31c55edb5fef3ab9a856fc395932b2ae7847 100644 (file)
@@ -26,7 +26,7 @@
 
 /**
  *     rz1000_set_mode         -       mode setting function
- *     @ap: ATA interface
+ *     @link: ATA link
  *     @unused: returned device on set_mode failure
  *
  *     Use a non standard set_mode function. We don't want to be tuned. We
  *     whacked out.
  */
 
-static int rz1000_set_mode(struct ata_port *ap, struct ata_device **unused)
+static int rz1000_set_mode(struct ata_link *link, struct ata_device **unused)
 {
-       int i;
+       struct ata_device *dev;
 
-       for (i = 0; i < ATA_MAX_DEVICES; i++) {
-               struct ata_device *dev = &ap->device[i];
+       ata_link_for_each_dev(dev, link) {
                if (ata_dev_enabled(dev)) {
                        /* We don't really care */
                        dev->pio_mode = XFER_PIO_0;
@@ -74,7 +73,6 @@ static struct scsi_host_template rz1000_sht = {
 static struct ata_port_operations rz1000_port_ops = {
        .set_mode       = rz1000_set_mode,
 
-       .port_disable   = ata_port_disable,
        .tf_load        = ata_tf_load,
        .tf_read        = ata_tf_read,
        .check_status   = ata_check_status,
@@ -100,9 +98,8 @@ static struct ata_port_operations rz1000_port_ops = {
        .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,
+       .port_start     = ata_sff_port_start,
 };
 
 static int rz1000_fifo_disable(struct pci_dev *pdev)
index 5edf67b1f3bf593f4ffc5e04c9eb46cfe83aac08..21ebc485ca4b4d71913a0ae302b35ba7f2924e35 100644 (file)
@@ -197,7 +197,6 @@ static struct scsi_host_template sc1200_sht = {
 };
 
 static struct ata_port_operations sc1200_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = sc1200_set_piomode,
        .set_dmamode    = sc1200_set_dmamode,
        .mode_filter    = ata_pci_default_filter,
@@ -227,9 +226,8 @@ static struct ata_port_operations sc1200_port_ops = {
        .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,
+       .port_start     = ata_sff_port_start,
 };
 
 /**
index 2d048ef25a5a11babbef2c2ef9f705adaf14e50d..55576138faea7a421bb83fec45b3eacfb21e9196 100644 (file)
@@ -603,16 +603,17 @@ static unsigned int scc_bus_softreset(struct ata_port *ap, unsigned int devmask,
  *     Note: Original code is ata_std_softreset().
  */
 
-static int scc_std_softreset (struct ata_port *ap, unsigned int *classes,
-                              unsigned long deadline)
+static int scc_std_softreset(struct ata_link *link, unsigned int *classes,
+                             unsigned long deadline)
 {
+       struct ata_port *ap = link->ap;
        unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
        unsigned int devmask = 0, err_mask;
        u8 err;
 
        DPRINTK("ENTER\n");
 
-       if (ata_port_offline(ap)) {
+       if (ata_link_offline(link)) {
                classes[0] = ATA_DEV_NONE;
                goto out;
        }
@@ -636,9 +637,11 @@ static int scc_std_softreset (struct ata_port *ap, unsigned int *classes,
        }
 
        /* determine by signature whether we have ATA or ATAPI devices */
-       classes[0] = ata_dev_try_classify(ap, 0, &err);
+       classes[0] = ata_dev_try_classify(&ap->link.device[0],
+                                         devmask & (1 << 0), &err);
        if (slave_possible && err != 0x81)
-               classes[1] = ata_dev_try_classify(ap, 1, &err);
+               classes[1] = ata_dev_try_classify(&ap->link.device[1],
+                                                 devmask & (1 << 1), &err);
 
  out:
        DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]);
@@ -701,7 +704,7 @@ static void scc_bmdma_stop (struct ata_queued_cmd *qc)
                        printk(KERN_WARNING "%s: Internal Bus Error\n", DRV_NAME);
                        out_be32(bmid_base + SCC_DMA_INTST, INTSTS_BMSINT);
                        /* TBD: SW reset */
-                       scc_std_softreset(ap, &classes, deadline);
+                       scc_std_softreset(&ap->link, &classes, deadline);
                        continue;
                }
 
@@ -740,7 +743,7 @@ static u8 scc_bmdma_status (struct ata_port *ap)
        void __iomem *mmio = ap->ioaddr.bmdma_addr;
        u8 host_stat = in_be32(mmio + SCC_DMA_STATUS);
        u32 int_status = in_be32(mmio + SCC_DMA_INTST);
-       struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
+       struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag);
        static int retry = 0;
 
        /* return if IOS_SS is cleared */
@@ -785,7 +788,7 @@ static u8 scc_bmdma_status (struct ata_port *ap)
 static void scc_data_xfer (struct ata_device *adev, unsigned char *buf,
                           unsigned int buflen, int write_data)
 {
-       struct ata_port *ap = adev->ap;
+       struct ata_port *ap = adev->link->ap;
        unsigned int words = buflen >> 1;
        unsigned int i;
        u16 *buf16 = (u16 *) buf;
@@ -838,38 +841,6 @@ static u8 scc_irq_on (struct ata_port *ap)
        return tmp;
 }
 
-/**
- *     scc_irq_ack - Acknowledge a device interrupt.
- *     @ap: Port on which interrupts are enabled.
- *
- *     Note: Original code is ata_irq_ack().
- */
-
-static u8 scc_irq_ack (struct ata_port *ap, unsigned int chk_drq)
-{
-       unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY;
-       u8 host_stat, post_stat, status;
-
-       status = ata_busy_wait(ap, bits, 1000);
-       if (status & bits)
-               if (ata_msg_err(ap))
-                       printk(KERN_ERR "abnormal status 0x%X\n", status);
-
-       /* get controller status; clear intr, err bits */
-       host_stat = in_be32(ap->ioaddr.bmdma_addr + SCC_DMA_STATUS);
-       out_be32(ap->ioaddr.bmdma_addr + SCC_DMA_STATUS,
-                host_stat | ATA_DMA_INTR | ATA_DMA_ERR);
-
-       post_stat = in_be32(ap->ioaddr.bmdma_addr + SCC_DMA_STATUS);
-
-       if (ata_msg_intr(ap))
-               printk(KERN_INFO "%s: irq ack: host_stat 0x%X, new host_stat 0x%X, drv_stat 0x%X\n",
-                      __FUNCTION__,
-                      host_stat, post_stat, status);
-
-       return status;
-}
-
 /**
  *     scc_bmdma_freeze - Freeze BMDMA controller port
  *     @ap: port to freeze
@@ -901,10 +872,10 @@ static void scc_bmdma_freeze (struct ata_port *ap)
  *     @deadline: deadline jiffies for the operation
  */
 
-static int scc_pata_prereset(struct ata_port *ap, unsigned long deadline)
+static int scc_pata_prereset(struct ata_link *link, unsigned long deadline)
 {
-       ap->cbl = ATA_CBL_PATA80;
-       return ata_std_prereset(ap, deadline);
+       link->ap->cbl = ATA_CBL_PATA80;
+       return ata_std_prereset(link, deadline);
 }
 
 /**
@@ -915,8 +886,10 @@ static int scc_pata_prereset(struct ata_port *ap, unsigned long deadline)
  *     Note: Original code is ata_std_postreset().
  */
 
-static void scc_std_postreset (struct ata_port *ap, unsigned int *classes)
+static void scc_std_postreset(struct ata_link *link, unsigned int *classes)
 {
+       struct ata_port *ap = link->ap;
+
        DPRINTK("ENTER\n");
 
        /* is double-select really necessary? */
@@ -1020,7 +993,6 @@ static struct scsi_host_template scc_sht = {
 };
 
 static const struct ata_port_operations scc_pata_ops = {
-       .port_disable           = ata_port_disable,
        .set_piomode            = scc_set_piomode,
        .set_dmamode            = scc_set_dmamode,
        .mode_filter            = scc_mode_filter,
@@ -1047,7 +1019,6 @@ static const struct ata_port_operations scc_pata_ops = {
 
        .irq_clear              = scc_bmdma_irq_clear,
        .irq_on                 = scc_irq_on,
-       .irq_ack                = scc_irq_ack,
 
        .port_start             = scc_port_start,
        .port_stop              = scc_port_stop,
@@ -1193,6 +1164,9 @@ static int scc_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
                return rc;
        host->iomap = pcim_iomap_table(pdev);
 
+       ata_port_pbar_desc(host->ports[0], SCC_CTRL_BAR, -1, "ctrl");
+       ata_port_pbar_desc(host->ports[0], SCC_BMID_BAR, -1, "bmid");
+
        rc = scc_host_init(host);
        if (rc)
                return rc;
index 0faf99c8f13e4c8f85885c4d4c8d7941e4c6e6ce..df68806df4be195e07295c58e113f60defdcdc7d 100644 (file)
@@ -318,7 +318,6 @@ static struct scsi_host_template serverworks_sht = {
 };
 
 static struct ata_port_operations serverworks_osb4_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = serverworks_set_piomode,
        .set_dmamode    = serverworks_set_dmamode,
        .mode_filter    = serverworks_osb4_filter,
@@ -348,13 +347,11 @@ static struct ata_port_operations serverworks_osb4_port_ops = {
        .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,
+       .port_start     = ata_sff_port_start,
 };
 
 static struct ata_port_operations serverworks_csb_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = serverworks_set_piomode,
        .set_dmamode    = serverworks_set_dmamode,
        .mode_filter    = serverworks_csb_filter,
@@ -384,9 +381,8 @@ static struct ata_port_operations serverworks_csb_port_ops = {
        .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,
+       .port_start     = ata_sff_port_start,
 };
 
 static int serverworks_fixup_osb4(struct pci_dev *pdev)
index 40395804a66fef72b3f280f1d7af87c7d4e6a32f..2eb75cd74a961cb70bf2281598b417f17f47b521 100644 (file)
@@ -95,15 +95,16 @@ static int sil680_cable_detect(struct ata_port *ap) {
 
 /**
  *     sil680_bus_reset        -       reset the SIL680 bus
- *     @ap: ATA port to reset
+ *     @link: ATA link to reset
  *     @deadline: deadline jiffies for the operation
  *
  *     Perform the SIL680 housekeeping when doing an ATA bus reset
  */
 
-static int sil680_bus_reset(struct ata_port *ap,unsigned int *classes,
+static int sil680_bus_reset(struct ata_link *link, unsigned int *classes,
                            unsigned long deadline)
 {
+       struct ata_port *ap = link->ap;
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        unsigned long addr = sil680_selreg(ap, 0);
        u8 reset;
@@ -112,7 +113,7 @@ static int sil680_bus_reset(struct ata_port *ap,unsigned int *classes,
        pci_write_config_byte(pdev, addr, reset | 0x03);
        udelay(25);
        pci_write_config_byte(pdev, addr, reset);
-       return ata_std_softreset(ap, classes, deadline);
+       return ata_std_softreset(link, classes, deadline);
 }
 
 static void sil680_error_handler(struct ata_port *ap)
@@ -237,7 +238,6 @@ static struct scsi_host_template sil680_sht = {
 };
 
 static struct ata_port_operations sil680_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = sil680_set_piomode,
        .set_dmamode    = sil680_set_dmamode,
        .mode_filter    = ata_pci_default_filter,
@@ -266,9 +266,8 @@ static struct ata_port_operations sil680_port_ops = {
        .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,
+       .port_start     = ata_sff_port_start,
 };
 
 /**
index cce2834b2b60990140071be8ad10ec3fbcee2b84..3b5be77e861c77139eab0cc15f4f9fd26c3954db 100644 (file)
@@ -84,7 +84,7 @@ static int sis_short_ata40(struct pci_dev *dev)
 
 static int sis_old_port_base(struct ata_device *adev)
 {
-       return  0x40 + (4 * adev->ap->port_no) +  (2 * adev->devno);
+       return  0x40 + (4 * adev->link->ap->port_no) +  (2 * adev->devno);
 }
 
 /**
@@ -133,19 +133,20 @@ static int sis_66_cable_detect(struct ata_port *ap)
 
 /**
  *     sis_pre_reset           -       probe begin
- *     @ap: ATA port
+ *     @link: ATA link
  *     @deadline: deadline jiffies for the operation
  *
  *     Set up cable type and use generic probe init
  */
 
-static int sis_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int sis_pre_reset(struct ata_link *link, unsigned long deadline)
 {
        static const struct pci_bits sis_enable_bits[] = {
                { 0x4aU, 1U, 0x02UL, 0x02UL },  /* port 0 */
                { 0x4aU, 1U, 0x04UL, 0x04UL },  /* port 1 */
        };
 
+       struct ata_port *ap = link->ap;
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 
        if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no]))
@@ -154,7 +155,7 @@ static int sis_pre_reset(struct ata_port *ap, unsigned long deadline)
        /* Clear the FIFO settings. We can't enable the FIFO until
           we know we are poking at a disk */
        pci_write_config_byte(pdev, 0x4B, 0);
-       return ata_std_prereset(ap, deadline);
+       return ata_std_prereset(link, deadline);
 }
 
 
@@ -530,7 +531,6 @@ static struct scsi_host_template sis_sht = {
 };
 
 static const struct ata_port_operations sis_133_ops = {
-       .port_disable           = ata_port_disable,
        .set_piomode            = sis_133_set_piomode,
        .set_dmamode            = sis_133_set_dmamode,
        .mode_filter            = ata_pci_default_filter,
@@ -558,13 +558,11 @@ static const struct ata_port_operations sis_133_ops = {
        .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,
+       .port_start             = ata_sff_port_start,
 };
 
 static const struct ata_port_operations sis_133_for_sata_ops = {
-       .port_disable           = ata_port_disable,
        .set_piomode            = sis_133_set_piomode,
        .set_dmamode            = sis_133_set_dmamode,
        .mode_filter            = ata_pci_default_filter,
@@ -592,13 +590,11 @@ static const struct ata_port_operations sis_133_for_sata_ops = {
        .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,
+       .port_start             = ata_sff_port_start,
 };
 
 static const struct ata_port_operations sis_133_early_ops = {
-       .port_disable           = ata_port_disable,
        .set_piomode            = sis_100_set_piomode,
        .set_dmamode            = sis_133_early_set_dmamode,
        .mode_filter            = ata_pci_default_filter,
@@ -626,13 +622,11 @@ static const struct ata_port_operations sis_133_early_ops = {
        .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,
+       .port_start             = ata_sff_port_start,
 };
 
 static const struct ata_port_operations sis_100_ops = {
-       .port_disable           = ata_port_disable,
        .set_piomode            = sis_100_set_piomode,
        .set_dmamode            = sis_100_set_dmamode,
        .mode_filter            = ata_pci_default_filter,
@@ -660,13 +654,11 @@ static const struct ata_port_operations sis_100_ops = {
        .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,
+       .port_start             = ata_sff_port_start,
 };
 
 static const struct ata_port_operations sis_66_ops = {
-       .port_disable           = ata_port_disable,
        .set_piomode            = sis_old_set_piomode,
        .set_dmamode            = sis_66_set_dmamode,
        .mode_filter            = ata_pci_default_filter,
@@ -694,13 +686,11 @@ static const struct ata_port_operations sis_66_ops = {
        .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,
+       .port_start             = ata_sff_port_start,
 };
 
 static const struct ata_port_operations sis_old_ops = {
-       .port_disable           = ata_port_disable,
        .set_piomode            = sis_old_set_piomode,
        .set_dmamode            = sis_old_set_dmamode,
        .mode_filter            = ata_pci_default_filter,
@@ -728,9 +718,8 @@ static const struct ata_port_operations sis_old_ops = {
        .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,
+       .port_start             = ata_sff_port_start,
 };
 
 static const struct ata_port_info sis_info = {
index c0f43bb25956d15a7bfdf4188038c952d35cd3d0..1388cef52c073d4dc3045e16103ca904acdce942 100644 (file)
@@ -43,23 +43,24 @@ enum {
 
 /**
  *     sl82c105_pre_reset              -       probe begin
- *     @ap: ATA port
+ *     @link: ATA link
  *     @deadline: deadline jiffies for the operation
  *
  *     Set up cable type and use generic probe init
  */
 
-static int sl82c105_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int sl82c105_pre_reset(struct ata_link *link, unsigned long deadline)
 {
        static const struct pci_bits sl82c105_enable_bits[] = {
                { 0x40, 1, 0x01, 0x01 },
                { 0x40, 1, 0x10, 0x10 }
        };
+       struct ata_port *ap = link->ap;
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 
        if (ap->port_no && !pci_test_config_bits(pdev, &sl82c105_enable_bits[ap->port_no]))
                return -ENOENT;
-       return ata_std_prereset(ap, deadline);
+       return ata_std_prereset(link, deadline);
 }
 
 
@@ -224,7 +225,6 @@ static struct scsi_host_template sl82c105_sht = {
 };
 
 static struct ata_port_operations sl82c105_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = sl82c105_set_piomode,
        .mode_filter    = ata_pci_default_filter,
 
@@ -253,9 +253,8 @@ static struct ata_port_operations sl82c105_port_ops = {
        .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,
+       .port_start     = ata_sff_port_start,
 };
 
 /**
index af21f443db6e4e080226aaa12ce11ea6f4e69280..403eafcffe12c47ce9ad439d2dedd04d4ac2d440 100644 (file)
 
 /**
  *     triflex_prereset                -       probe begin
- *     @ap: ATA port
+ *     @link: ATA link
  *     @deadline: deadline jiffies for the operation
  *
  *     Set up cable type and use generic probe init
  */
 
-static int triflex_prereset(struct ata_port *ap, unsigned long deadline)
+static int triflex_prereset(struct ata_link *link, unsigned long deadline)
 {
        static const struct pci_bits triflex_enable_bits[] = {
                { 0x80, 1, 0x01, 0x01 },
                { 0x80, 1, 0x02, 0x02 }
        };
 
+       struct ata_port *ap = link->ap;
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 
        if (!pci_test_config_bits(pdev, &triflex_enable_bits[ap->port_no]))
                return -ENOENT;
 
-       return ata_std_prereset(ap, deadline);
+       return ata_std_prereset(link, deadline);
 }
 
 
@@ -197,7 +198,6 @@ static struct scsi_host_template triflex_sht = {
 };
 
 static struct ata_port_operations triflex_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = triflex_set_piomode,
        .mode_filter    = ata_pci_default_filter,
 
@@ -226,9 +226,8 @@ static struct ata_port_operations triflex_port_ops = {
        .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,
+       .port_start     = ata_sff_port_start,
 };
 
 static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id)
index f143db4559e0d5ad1cd4e3ec80d95b7708c2f471..5d41b6612d7f2626189e6a2653f47153f0cfd282 100644 (file)
@@ -184,11 +184,15 @@ static int via_cable_detect(struct ata_port *ap) {
           two drives */
        if (ata66 & (0x10100000 >> (16 * ap->port_no)))
                return ATA_CBL_PATA80;
+       /* Check with ACPI so we can spot BIOS reported SATA bridges */
+       if (ata_acpi_cbl_80wire(ap))
+               return ATA_CBL_PATA80;
        return ATA_CBL_PATA40;
 }
 
-static int via_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int via_pre_reset(struct ata_link *link, unsigned long deadline)
 {
+       struct ata_port *ap = link->ap;
        const struct via_isa_bridge *config = ap->host->private_data;
 
        if (!(config->flags & VIA_NO_ENABLES)) {
@@ -201,7 +205,7 @@ static int via_pre_reset(struct ata_port *ap, unsigned long deadline)
                        return -ENOENT;
        }
 
-       return ata_std_prereset(ap, deadline);
+       return ata_std_prereset(link, deadline);
 }
 
 
@@ -344,7 +348,6 @@ static struct scsi_host_template via_sht = {
 };
 
 static struct ata_port_operations via_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = via_set_piomode,
        .set_dmamode    = via_set_dmamode,
        .mode_filter    = ata_pci_default_filter,
@@ -374,13 +377,11 @@ static struct ata_port_operations via_port_ops = {
        .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,
+       .port_start     = ata_sff_port_start,
 };
 
 static struct ata_port_operations via_port_ops_noirq = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = via_set_piomode,
        .set_dmamode    = via_set_dmamode,
        .mode_filter    = ata_pci_default_filter,
@@ -410,9 +411,8 @@ static struct ata_port_operations via_port_ops_noirq = {
        .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,
+       .port_start     = ata_sff_port_start,
 };
 
 /**
index 83abfeca4057592b63af9285522ceeb9219aa6e5..549cbbe9fd07f21162baa54cd16270fc3f79b6b1 100644 (file)
@@ -94,7 +94,7 @@ static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev)
 
 static void winbond_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data)
 {
-       struct ata_port *ap = adev->ap;
+       struct ata_port *ap = adev->link->ap;
        int slop = buflen & 3;
 
        if (ata_id_has_dword_io(adev->id)) {
@@ -138,7 +138,6 @@ static struct scsi_host_template winbond_sht = {
 };
 
 static struct ata_port_operations winbond_port_ops = {
-       .port_disable   = ata_port_disable,
        .set_piomode    = winbond_set_piomode,
 
        .tf_load        = ata_tf_load,
@@ -160,9 +159,8 @@ static struct ata_port_operations winbond_port_ops = {
 
        .irq_clear      = ata_bmdma_irq_clear,
        .irq_on         = ata_irq_on,
-       .irq_ack        = ata_irq_ack,
 
-       .port_start     = ata_port_start,
+       .port_start     = ata_sff_port_start,
 };
 
 /**
@@ -199,6 +197,7 @@ static __init int winbond_init_one(unsigned long port)
 
        for (i = 0; i < 2 ; i ++) {
                unsigned long cmd_port = 0x1F0 - (0x80 * i);
+               unsigned long ctl_port = cmd_port + 0x206;
                struct ata_host *host;
                struct ata_port *ap;
                void __iomem *cmd_addr, *ctl_addr;
@@ -214,14 +213,16 @@ static __init int winbond_init_one(unsigned long port)
                host = ata_host_alloc(&pdev->dev, 1);
                if (!host)
                        goto err_unregister;
+               ap = host->ports[0];
 
                rc = -ENOMEM;
                cmd_addr = devm_ioport_map(&pdev->dev, cmd_port, 8);
-               ctl_addr = devm_ioport_map(&pdev->dev, cmd_port + 0x0206, 1);
+               ctl_addr = devm_ioport_map(&pdev->dev, ctl_port, 1);
                if (!cmd_addr || !ctl_addr)
                        goto err_unregister;
 
-               ap = host->ports[0];
+               ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", cmd_port, ctl_port);
+
                ap->ops = &winbond_port_ops;
                ap->pio_mask = 0x1F;
                ap->flags |= ATA_FLAG_SLAVE_POSS;
index 5c79271401afc29ecb216ab46b6c46b7b82ff1a5..8d1b03d5bcb1e65d63c5b67121791e8fe1eee77a 100644 (file)
@@ -92,6 +92,8 @@ enum {
 
        /* CPB bits */
        cDONE                   = (1 << 0),
+       cATERR                  = (1 << 3),
+
        cVLD                    = (1 << 0),
        cDAT                    = (1 << 2),
        cIEN                    = (1 << 3),
@@ -131,14 +133,15 @@ static int adma_ata_init_one (struct pci_dev *pdev,
 static int adma_port_start(struct ata_port *ap);
 static void adma_host_stop(struct ata_host *host);
 static void adma_port_stop(struct ata_port *ap);
-static void adma_phy_reset(struct ata_port *ap);
 static void adma_qc_prep(struct ata_queued_cmd *qc);
 static unsigned int adma_qc_issue(struct ata_queued_cmd *qc);
 static int adma_check_atapi_dma(struct ata_queued_cmd *qc);
 static void adma_bmdma_stop(struct ata_queued_cmd *qc);
 static u8 adma_bmdma_status(struct ata_port *ap);
 static void adma_irq_clear(struct ata_port *ap);
-static void adma_eng_timeout(struct ata_port *ap);
+static void adma_freeze(struct ata_port *ap);
+static void adma_thaw(struct ata_port *ap);
+static void adma_error_handler(struct ata_port *ap);
 
 static struct scsi_host_template adma_ata_sht = {
        .module                 = THIS_MODULE,
@@ -159,21 +162,20 @@ static struct scsi_host_template adma_ata_sht = {
 };
 
 static const struct ata_port_operations adma_ata_ops = {
-       .port_disable           = ata_port_disable,
        .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,
-       .phy_reset              = adma_phy_reset,
        .check_atapi_dma        = adma_check_atapi_dma,
        .data_xfer              = ata_data_xfer,
        .qc_prep                = adma_qc_prep,
        .qc_issue               = adma_qc_issue,
-       .eng_timeout            = adma_eng_timeout,
+       .freeze                 = adma_freeze,
+       .thaw                   = adma_thaw,
+       .error_handler          = adma_error_handler,
        .irq_clear              = adma_irq_clear,
        .irq_on                 = ata_irq_on,
-       .irq_ack                = ata_irq_ack,
        .port_start             = adma_port_start,
        .port_stop              = adma_port_stop,
        .host_stop              = adma_host_stop,
@@ -184,7 +186,7 @@ static const struct ata_port_operations adma_ata_ops = {
 static struct ata_port_info adma_port_info[] = {
        /* board_1841_idx */
        {
-               .flags          = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST |
+               .flags          = ATA_FLAG_SLAVE_POSS |
                                  ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO |
                                  ATA_FLAG_PIO_POLLING,
                .pio_mask       = 0x10, /* pio4 */
@@ -273,24 +275,42 @@ static inline void adma_enter_reg_mode(struct ata_port *ap)
        readb(chan + ADMA_STATUS);      /* flush */
 }
 
-static void adma_phy_reset(struct ata_port *ap)
+static void adma_freeze(struct ata_port *ap)
 {
-       struct adma_port_priv *pp = ap->private_data;
+       void __iomem *chan = ADMA_PORT_REGS(ap);
+
+       /* mask/clear ATA interrupts */
+       writeb(ATA_NIEN, ap->ioaddr.ctl_addr);
+       ata_check_status(ap);
 
-       pp->state = adma_state_idle;
+       /* reset ADMA to idle state */
+       writew(aPIOMD4 | aNIEN | aRSTADM, chan + ADMA_CONTROL);
+       udelay(2);
+       writew(aPIOMD4 | aNIEN, chan + ADMA_CONTROL);
+       udelay(2);
+}
+
+static void adma_thaw(struct ata_port *ap)
+{
        adma_reinit_engine(ap);
-       ata_port_probe(ap);
-       ata_bus_reset(ap);
 }
 
-static void adma_eng_timeout(struct ata_port *ap)
+static int adma_prereset(struct ata_link *link, unsigned long deadline)
 {
+       struct ata_port *ap = link->ap;
        struct adma_port_priv *pp = ap->private_data;
 
        if (pp->state != adma_state_idle) /* healthy paranoia */
                pp->state = adma_state_mmio;
        adma_reinit_engine(ap);
-       ata_eng_timeout(ap);
+
+       return ata_std_prereset(link, deadline);
+}
+
+static void adma_error_handler(struct ata_port *ap)
+{
+       ata_do_eh(ap, adma_prereset, ata_std_softreset, NULL,
+                 ata_std_postreset);
 }
 
 static int adma_fill_sg(struct ata_queued_cmd *qc)
@@ -464,14 +484,33 @@ static inline unsigned int adma_intr_pkt(struct ata_host *host)
                pp = ap->private_data;
                if (!pp || pp->state != adma_state_pkt)
                        continue;
-               qc = ata_qc_from_tag(ap, ap->active_tag);
+               qc = ata_qc_from_tag(ap, ap->link.active_tag);
                if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
-                       if ((status & (aPERR | aPSD | aUIRQ)))
+                       if (status & aPERR)
+                               qc->err_mask |= AC_ERR_HOST_BUS;
+                       else if ((status & (aPSD | aUIRQ)))
                                qc->err_mask |= AC_ERR_OTHER;
+
+                       if (pp->pkt[0] & cATERR)
+                               qc->err_mask |= AC_ERR_DEV;
                        else if (pp->pkt[0] != cDONE)
                                qc->err_mask |= AC_ERR_OTHER;
 
-                       ata_qc_complete(qc);
+                       if (!qc->err_mask)
+                               ata_qc_complete(qc);
+                       else {
+                               struct ata_eh_info *ehi = &ap->link.eh_info;
+                               ata_ehi_clear_desc(ehi);
+                               ata_ehi_push_desc(ehi,
+                                       "ADMA-status 0x%02X", status);
+                               ata_ehi_push_desc(ehi,
+                                       "pkt[0] 0x%02X", pp->pkt[0]);
+
+                               if (qc->err_mask == AC_ERR_DEV)
+                                       ata_port_abort(ap);
+                               else
+                                       ata_port_freeze(ap);
+                       }
                }
        }
        return handled;
@@ -489,7 +528,7 @@ static inline unsigned int adma_intr_mmio(struct ata_host *host)
                        struct adma_port_priv *pp = ap->private_data;
                        if (!pp || pp->state != adma_state_mmio)
                                continue;
-                       qc = ata_qc_from_tag(ap, ap->active_tag);
+                       qc = ata_qc_from_tag(ap, ap->link.active_tag);
                        if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
 
                                /* check main status, clearing INTRQ */
@@ -502,7 +541,20 @@ static inline unsigned int adma_intr_mmio(struct ata_host *host)
                                /* complete taskfile transaction */
                                pp->state = adma_state_idle;
                                qc->err_mask |= ac_err_mask(status);
-                               ata_qc_complete(qc);
+                               if (!qc->err_mask)
+                                       ata_qc_complete(qc);
+                               else {
+                                       struct ata_eh_info *ehi =
+                                               &ap->link.eh_info;
+                                       ata_ehi_clear_desc(ehi);
+                                       ata_ehi_push_desc(ehi,
+                                               "status 0x%02X", status);
+
+                                       if (qc->err_mask == AC_ERR_DEV)
+                                               ata_port_abort(ap);
+                                       else
+                                               ata_port_freeze(ap);
+                               }
                                handled = 1;
                        }
                }
@@ -652,9 +704,16 @@ static int adma_ata_init_one(struct pci_dev *pdev,
        if (rc)
                return rc;
 
-       for (port_no = 0; port_no < ADMA_PORTS; ++port_no)
-               adma_ata_setup_port(&host->ports[port_no]->ioaddr,
-                                   ADMA_ATA_REGS(mmio_base, port_no));
+       for (port_no = 0; port_no < ADMA_PORTS; ++port_no) {
+               struct ata_port *ap = host->ports[port_no];
+               void __iomem *port_base = ADMA_ATA_REGS(mmio_base, port_no);
+               unsigned int offset = port_base - mmio_base;
+
+               adma_ata_setup_port(&ap->ioaddr, port_base);
+
+               ata_port_pbar_desc(ap, ADMA_MMIO_BAR, -1, "mmio");
+               ata_port_pbar_desc(ap, ADMA_MMIO_BAR, offset, "port");
+       }
 
        /* initialize adapter */
        adma_host_init(host, board_idx);
index fdbed8ecdfc20d66cabcb5deef7eac904e240431..08595f34b3e8cdaa2df597b799cf9a479fe713d1 100644 (file)
@@ -285,7 +285,7 @@ static void inic_irq_clear(struct ata_port *ap)
 static void inic_host_intr(struct ata_port *ap)
 {
        void __iomem *port_base = inic_port_base(ap);
-       struct ata_eh_info *ehi = &ap->eh_info;
+       struct ata_eh_info *ehi = &ap->link.eh_info;
        u8 irq_stat;
 
        /* fetch and clear irq */
@@ -293,7 +293,8 @@ static void inic_host_intr(struct ata_port *ap)
        writeb(irq_stat, port_base + PORT_IRQ_STAT);
 
        if (likely(!(irq_stat & PIRQ_ERR))) {
-               struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
+               struct ata_queued_cmd *qc =
+                       ata_qc_from_tag(ap, ap->link.active_tag);
 
                if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) {
                        ata_chk_status(ap);     /* clear ATA interrupt */
@@ -416,12 +417,13 @@ static void inic_thaw(struct ata_port *ap)
  * SRST and SControl hardreset don't give valid signature on this
  * controller.  Only controller specific hardreset mechanism works.
  */
-static int inic_hardreset(struct ata_port *ap, unsigned int *class,
+static int inic_hardreset(struct ata_link *link, unsigned int *class,
                          unsigned long deadline)
 {
+       struct ata_port *ap = link->ap;
        void __iomem *port_base = inic_port_base(ap);
        void __iomem *idma_ctl = port_base + PORT_IDMA_CTL;
-       const unsigned long *timing = sata_ehc_deb_timing(&ap->eh_context);
+       const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
        u16 val;
        int rc;
 
@@ -434,15 +436,15 @@ static int inic_hardreset(struct ata_port *ap, unsigned int *class,
        msleep(1);
        writew(val & ~IDMA_CTL_RST_ATA, idma_ctl);
 
-       rc = sata_phy_resume(ap, timing, deadline);
+       rc = sata_link_resume(link, timing, deadline);
        if (rc) {
-               ata_port_printk(ap, KERN_WARNING, "failed to resume "
+               ata_link_printk(link, KERN_WARNING, "failed to resume "
                                "link after reset (errno=%d)\n", rc);
                return rc;
        }
 
        *class = ATA_DEV_NONE;
-       if (ata_port_online(ap)) {
+       if (ata_link_online(link)) {
                struct ata_taskfile tf;
 
                /* wait a while before checking status */
@@ -451,7 +453,7 @@ static int inic_hardreset(struct ata_port *ap, unsigned int *class,
                rc = ata_wait_ready(ap, deadline);
                /* link occupied, -ENODEV too is an error */
                if (rc) {
-                       ata_port_printk(ap, KERN_WARNING, "device not ready "
+                       ata_link_printk(link, KERN_WARNING, "device not ready "
                                        "after hardreset (errno=%d)\n", rc);
                        return rc;
                }
@@ -550,7 +552,6 @@ static int inic_port_start(struct ata_port *ap)
 }
 
 static struct ata_port_operations inic_port_ops = {
-       .port_disable           = ata_port_disable,
        .tf_load                = ata_tf_load,
        .tf_read                = ata_tf_read,
        .check_status           = ata_check_status,
@@ -567,7 +568,6 @@ static struct ata_port_operations inic_port_ops = {
 
        .irq_clear              = inic_irq_clear,
        .irq_on                 = ata_irq_on,
-       .irq_ack                = ata_irq_ack,
 
        .qc_prep                = ata_qc_prep,
        .qc_issue               = inic_qc_issue,
@@ -693,16 +693,24 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        host->iomap = iomap = pcim_iomap_table(pdev);
 
        for (i = 0; i < NR_PORTS; i++) {
-               struct ata_ioports *port = &host->ports[i]->ioaddr;
-               void __iomem *port_base = iomap[MMIO_BAR] + i * PORT_SIZE;
+               struct ata_port *ap = host->ports[i];
+               struct ata_ioports *port = &ap->ioaddr;
+               unsigned int offset = i * PORT_SIZE;
 
                port->cmd_addr = iomap[2 * i];
                port->altstatus_addr =
                port->ctl_addr = (void __iomem *)
                        ((unsigned long)iomap[2 * i + 1] | ATA_PCI_CTL_OFS);
-               port->scr_addr = port_base + PORT_SCR;
+               port->scr_addr = iomap[MMIO_BAR] + offset + PORT_SCR;
 
                ata_std_ports(port);
+
+               ata_port_pbar_desc(ap, MMIO_BAR, -1, "mmio");
+               ata_port_pbar_desc(ap, MMIO_BAR, offset, "port");
+               ata_port_desc(ap, "cmd 0x%llx ctl 0x%llx",
+                 (unsigned long long)pci_resource_start(pdev, 2 * i),
+                 (unsigned long long)pci_resource_start(pdev, (2 * i + 1)) |
+                                     ATA_PCI_CTL_OFS);
        }
 
        hpriv->cached_hctl = readw(iomap[MMIO_BAR] + HOST_CTL);
index d9832e234e44ccd5cdfea2e83b6d59925782276e..4df8311968e9e3f04325a7823cc53d78c21f1754 100644 (file)
@@ -483,8 +483,6 @@ static struct scsi_host_template mv6_sht = {
 };
 
 static const struct ata_port_operations mv5_ops = {
-       .port_disable           = ata_port_disable,
-
        .tf_load                = ata_tf_load,
        .tf_read                = ata_tf_read,
        .check_status           = ata_check_status,
@@ -499,7 +497,6 @@ static const struct ata_port_operations mv5_ops = {
 
        .irq_clear              = mv_irq_clear,
        .irq_on                 = ata_irq_on,
-       .irq_ack                = ata_irq_ack,
 
        .error_handler          = mv_error_handler,
        .post_internal_cmd      = mv_post_int_cmd,
@@ -514,8 +511,6 @@ static const struct ata_port_operations mv5_ops = {
 };
 
 static const struct ata_port_operations mv6_ops = {
-       .port_disable           = ata_port_disable,
-
        .tf_load                = ata_tf_load,
        .tf_read                = ata_tf_read,
        .check_status           = ata_check_status,
@@ -530,7 +525,6 @@ static const struct ata_port_operations mv6_ops = {
 
        .irq_clear              = mv_irq_clear,
        .irq_on                 = ata_irq_on,
-       .irq_ack                = ata_irq_ack,
 
        .error_handler          = mv_error_handler,
        .post_internal_cmd      = mv_post_int_cmd,
@@ -545,8 +539,6 @@ static const struct ata_port_operations mv6_ops = {
 };
 
 static const struct ata_port_operations mv_iie_ops = {
-       .port_disable           = ata_port_disable,
-
        .tf_load                = ata_tf_load,
        .tf_read                = ata_tf_read,
        .check_status           = ata_check_status,
@@ -561,7 +553,6 @@ static const struct ata_port_operations mv_iie_ops = {
 
        .irq_clear              = mv_irq_clear,
        .irq_on                 = ata_irq_on,
-       .irq_ack                = ata_irq_ack,
 
        .error_handler          = mv_error_handler,
        .post_internal_cmd      = mv_post_int_cmd,
@@ -1415,7 +1406,7 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
        struct mv_host_priv *hpriv = ap->host->private_data;
        unsigned int edma_enabled = (pp->pp_flags & MV_PP_FLAG_EDMA_EN);
        unsigned int action = 0, err_mask = 0;
-       struct ata_eh_info *ehi = &ap->eh_info;
+       struct ata_eh_info *ehi = &ap->link.eh_info;
 
        ata_ehi_clear_desc(ehi);
 
@@ -1423,8 +1414,8 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
                /* just a guess: do we need to do this? should we
                 * expand this, and do it in all cases?
                 */
-               sata_scr_read(ap, SCR_ERROR, &serr);
-               sata_scr_write_flush(ap, SCR_ERROR, serr);
+               sata_scr_read(&ap->link, SCR_ERROR, &serr);
+               sata_scr_write_flush(&ap->link, SCR_ERROR, serr);
        }
 
        edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
@@ -1468,8 +1459,8 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
                }
 
                if (edma_err_cause & EDMA_ERR_SERR) {
-                       sata_scr_read(ap, SCR_ERROR, &serr);
-                       sata_scr_write_flush(ap, SCR_ERROR, serr);
+                       sata_scr_read(&ap->link, SCR_ERROR, &serr);
+                       sata_scr_write_flush(&ap->link, SCR_ERROR, serr);
                        err_mask = AC_ERR_ATA_BUS;
                        action |= ATA_EH_HARDRESET;
                }
@@ -1508,7 +1499,7 @@ static void mv_intr_pio(struct ata_port *ap)
                return;
 
        /* get active ATA command */
-       qc = ata_qc_from_tag(ap, ap->active_tag);
+       qc = ata_qc_from_tag(ap, ap->link.active_tag);
        if (unlikely(!qc))                      /* no active tag */
                return;
        if (qc->tf.flags & ATA_TFLAG_POLLING)   /* polling; we don't own qc */
@@ -1543,7 +1534,7 @@ static void mv_intr_edma(struct ata_port *ap)
 
                /* 50xx: get active ATA command */
                if (IS_GEN_I(hpriv))
-                       tag = ap->active_tag;
+                       tag = ap->link.active_tag;
 
                /* Gen II/IIE: get active ATA command via tag, to enable
                 * support for queueing.  this works transparently for
@@ -1646,7 +1637,7 @@ static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc)
                if (unlikely(have_err_bits)) {
                        struct ata_queued_cmd *qc;
 
-                       qc = ata_qc_from_tag(ap, ap->active_tag);
+                       qc = ata_qc_from_tag(ap, ap->link.active_tag);
                        if (qc && (qc->tf.flags & ATA_TFLAG_POLLING))
                                continue;
 
@@ -1687,15 +1678,15 @@ static void mv_pci_error(struct ata_host *host, void __iomem *mmio)
 
        for (i = 0; i < host->n_ports; i++) {
                ap = host->ports[i];
-               if (!ata_port_offline(ap)) {
-                       ehi = &ap->eh_info;
+               if (!ata_link_offline(&ap->link)) {
+                       ehi = &ap->link.eh_info;
                        ata_ehi_clear_desc(ehi);
                        if (!printed++)
                                ata_ehi_push_desc(ehi,
                                        "PCI err cause 0x%08x", err_cause);
                        err_mask = AC_ERR_HOST_BUS;
                        ehi->action = ATA_EH_HARDRESET;
-                       qc = ata_qc_from_tag(ap, ap->active_tag);
+                       qc = ata_qc_from_tag(ap, ap->link.active_tag);
                        if (qc)
                                qc->err_mask |= err_mask;
                        else
@@ -2198,14 +2189,14 @@ static void mv_phy_reset(struct ata_port *ap, unsigned int *class,
 
        /* Issue COMRESET via SControl */
 comreset_retry:
-       sata_scr_write_flush(ap, SCR_CONTROL, 0x301);
+       sata_scr_write_flush(&ap->link, SCR_CONTROL, 0x301);
        msleep(1);
 
-       sata_scr_write_flush(ap, SCR_CONTROL, 0x300);
+       sata_scr_write_flush(&ap->link, SCR_CONTROL, 0x300);
        msleep(20);
 
        do {
-               sata_scr_read(ap, SCR_STATUS, &sstatus);
+               sata_scr_read(&ap->link, SCR_STATUS, &sstatus);
                if (((sstatus & 0x3) == 3) || ((sstatus & 0x3) == 0))
                        break;
 
@@ -2230,7 +2221,7 @@ comreset_retry:
        }
 #endif
 
-       if (ata_port_offline(ap)) {
+       if (ata_link_offline(&ap->link)) {
                *class = ATA_DEV_NONE;
                return;
        }
@@ -2257,7 +2248,7 @@ comreset_retry:
         */
 
        /* finally, read device signature from TF registers */
-       *class = ata_dev_try_classify(ap, 0, NULL);
+       *class = ata_dev_try_classify(ap->link.device, 1, NULL);
 
        writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
 
@@ -2266,10 +2257,11 @@ comreset_retry:
        VPRINTK("EXIT\n");
 }
 
-static int mv_prereset(struct ata_port *ap, unsigned long deadline)
+static int mv_prereset(struct ata_link *link, unsigned long deadline)
 {
+       struct ata_port *ap = link->ap;
        struct mv_port_priv *pp = ap->private_data;
-       struct ata_eh_context *ehc = &ap->eh_context;
+       struct ata_eh_context *ehc = &link->eh_context;
        int rc;
 
        rc = mv_stop_dma(ap);
@@ -2285,7 +2277,7 @@ static int mv_prereset(struct ata_port *ap, unsigned long deadline)
        if (ehc->i.action & ATA_EH_HARDRESET)
                return 0;
 
-       if (ata_port_online(ap))
+       if (ata_link_online(link))
                rc = ata_wait_ready(ap, deadline);
        else
                rc = -ENODEV;
@@ -2293,9 +2285,10 @@ static int mv_prereset(struct ata_port *ap, unsigned long deadline)
        return rc;
 }
 
-static int mv_hardreset(struct ata_port *ap, unsigned int *class,
+static int mv_hardreset(struct ata_link *link, unsigned int *class,
                        unsigned long deadline)
 {
+       struct ata_port *ap = link->ap;
        struct mv_host_priv *hpriv = ap->host->private_data;
        void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
 
@@ -2308,16 +2301,17 @@ static int mv_hardreset(struct ata_port *ap, unsigned int *class,
        return 0;
 }
 
-static void mv_postreset(struct ata_port *ap, unsigned int *classes)
+static void mv_postreset(struct ata_link *link, unsigned int *classes)
 {
+       struct ata_port *ap = link->ap;
        u32 serr;
 
        /* print link status */
-       sata_print_link_status(ap);
+       sata_print_link_status(link);
 
        /* clear SError */
-       sata_scr_read(ap, SCR_ERROR, &serr);
-       sata_scr_write_flush(ap, SCR_ERROR, serr);
+       sata_scr_read(link, SCR_ERROR, &serr);
+       sata_scr_write_flush(link, SCR_ERROR, serr);
 
        /* bail out if no device is present */
        if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) {
@@ -2590,8 +2584,14 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx)
        }
 
        for (port = 0; port < host->n_ports; port++) {
+               struct ata_port *ap = host->ports[port];
                void __iomem *port_mmio = mv_port_base(mmio, port);
-               mv_port_init(&host->ports[port]->ioaddr, port_mmio);
+               unsigned int offset = port_mmio - mmio;
+
+               mv_port_init(&ap->ioaddr, port_mmio);
+
+               ata_port_pbar_desc(ap, MV_PRIMARY_BAR, -1, "mmio");
+               ata_port_pbar_desc(ap, MV_PRIMARY_BAR, offset, "port");
        }
 
        for (hc = 0; hc < n_hc; hc++) {
index 40dc73139858832e644118e606e608430f9d5cb5..40557fe2ffdf98c74a8822a754d063f7ab0c4b7a 100644 (file)
@@ -340,7 +340,6 @@ static struct scsi_host_template nv_adma_sht = {
 };
 
 static const struct ata_port_operations nv_generic_ops = {
-       .port_disable           = ata_port_disable,
        .tf_load                = ata_tf_load,
        .tf_read                = ata_tf_read,
        .exec_command           = ata_exec_command,
@@ -359,14 +358,12 @@ static const struct ata_port_operations nv_generic_ops = {
        .data_xfer              = ata_data_xfer,
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
-       .irq_ack                = ata_irq_ack,
        .scr_read               = nv_scr_read,
        .scr_write              = nv_scr_write,
        .port_start             = ata_port_start,
 };
 
 static const struct ata_port_operations nv_nf2_ops = {
-       .port_disable           = ata_port_disable,
        .tf_load                = ata_tf_load,
        .tf_read                = ata_tf_read,
        .exec_command           = ata_exec_command,
@@ -385,14 +382,12 @@ static const struct ata_port_operations nv_nf2_ops = {
        .data_xfer              = ata_data_xfer,
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
-       .irq_ack                = ata_irq_ack,
        .scr_read               = nv_scr_read,
        .scr_write              = nv_scr_write,
        .port_start             = ata_port_start,
 };
 
 static const struct ata_port_operations nv_ck804_ops = {
-       .port_disable           = ata_port_disable,
        .tf_load                = ata_tf_load,
        .tf_read                = ata_tf_read,
        .exec_command           = ata_exec_command,
@@ -411,7 +406,6 @@ static const struct ata_port_operations nv_ck804_ops = {
        .data_xfer              = ata_data_xfer,
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
-       .irq_ack                = ata_irq_ack,
        .scr_read               = nv_scr_read,
        .scr_write              = nv_scr_write,
        .port_start             = ata_port_start,
@@ -419,7 +413,6 @@ static const struct ata_port_operations nv_ck804_ops = {
 };
 
 static const struct ata_port_operations nv_adma_ops = {
-       .port_disable           = ata_port_disable,
        .tf_load                = ata_tf_load,
        .tf_read                = nv_adma_tf_read,
        .check_atapi_dma        = nv_adma_check_atapi_dma,
@@ -430,6 +423,7 @@ static const struct ata_port_operations nv_adma_ops = {
        .bmdma_start            = ata_bmdma_start,
        .bmdma_stop             = ata_bmdma_stop,
        .bmdma_status           = ata_bmdma_status,
+       .qc_defer               = ata_std_qc_defer,
        .qc_prep                = nv_adma_qc_prep,
        .qc_issue               = nv_adma_qc_issue,
        .freeze                 = nv_adma_freeze,
@@ -439,7 +433,6 @@ static const struct ata_port_operations nv_adma_ops = {
        .data_xfer              = ata_data_xfer,
        .irq_clear              = nv_adma_irq_clear,
        .irq_on                 = ata_irq_on,
-       .irq_ack                = ata_irq_ack,
        .scr_read               = nv_scr_read,
        .scr_write              = nv_scr_write,
        .port_start             = nv_adma_port_start,
@@ -455,8 +448,8 @@ static const struct ata_port_info nv_port_info[] = {
        /* generic */
        {
                .sht            = &nv_sht,
-               .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-                                 ATA_FLAG_HRST_TO_RESUME,
+               .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+               .link_flags     = ATA_LFLAG_HRST_TO_RESUME,
                .pio_mask       = NV_PIO_MASK,
                .mwdma_mask     = NV_MWDMA_MASK,
                .udma_mask      = NV_UDMA_MASK,
@@ -466,8 +459,8 @@ static const struct ata_port_info nv_port_info[] = {
        /* nforce2/3 */
        {
                .sht            = &nv_sht,
-               .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-                                 ATA_FLAG_HRST_TO_RESUME,
+               .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+               .link_flags     = ATA_LFLAG_HRST_TO_RESUME,
                .pio_mask       = NV_PIO_MASK,
                .mwdma_mask     = NV_MWDMA_MASK,
                .udma_mask      = NV_UDMA_MASK,
@@ -477,8 +470,8 @@ static const struct ata_port_info nv_port_info[] = {
        /* ck804 */
        {
                .sht            = &nv_sht,
-               .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-                                 ATA_FLAG_HRST_TO_RESUME,
+               .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+               .link_flags     = ATA_LFLAG_HRST_TO_RESUME,
                .pio_mask       = NV_PIO_MASK,
                .mwdma_mask     = NV_MWDMA_MASK,
                .udma_mask      = NV_UDMA_MASK,
@@ -489,8 +482,8 @@ static const struct ata_port_info nv_port_info[] = {
        {
                .sht            = &nv_adma_sht,
                .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-                                 ATA_FLAG_HRST_TO_RESUME |
                                  ATA_FLAG_MMIO | 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,
@@ -594,7 +587,7 @@ static int nv_adma_slave_config(struct scsi_device *sdev)
                /* Not a proper libata device, ignore */
                return rc;
 
-       if (ap->device[sdev->id].class == ATA_DEV_ATAPI) {
+       if (ap->link.device[sdev->id].class == ATA_DEV_ATAPI) {
                /*
                 * NVIDIA reports that ADMA mode does not support ATAPI commands.
                 * Therefore ATAPI commands are sent through the legacy interface.
@@ -711,7 +704,7 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err)
                     flags & (NV_CPB_RESP_ATA_ERR |
                              NV_CPB_RESP_CMD_ERR |
                              NV_CPB_RESP_CPB_ERR)))) {
-               struct ata_eh_info *ehi = &ap->eh_info;
+               struct ata_eh_info *ehi = &ap->link.eh_info;
                int freeze = 0;
 
                ata_ehi_clear_desc(ehi);
@@ -747,7 +740,7 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err)
                        DPRINTK("Completing qc from tag %d\n",cpb_num);
                        ata_qc_complete(qc);
                } else {
-                       struct ata_eh_info *ehi = &ap->eh_info;
+                       struct ata_eh_info *ehi = &ap->link.eh_info;
                        /* Notifier bits set without a command may indicate the drive
                           is misbehaving. Raise host state machine violation on this
                           condition. */
@@ -764,7 +757,7 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err)
 
 static int nv_host_intr(struct ata_port *ap, u8 irq_stat)
 {
-       struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
+       struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag);
 
        /* freeze if hotplugged */
        if (unlikely(irq_stat & (NV_INT_ADDED | NV_INT_REMOVED))) {
@@ -817,7 +810,7 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
                        if (pp->flags & NV_ADMA_PORT_REGISTER_MODE) {
                                u8 irq_stat = readb(host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804)
                                        >> (NV_INT_PORT_SHIFT * i);
-                               if(ata_tag_valid(ap->active_tag))
+                               if(ata_tag_valid(ap->link.active_tag))
                                        /** NV_INT_DEV indication seems unreliable at times
                                            at least in ADMA mode. Force it on always when a
                                            command is active, to prevent losing interrupts. */
@@ -852,7 +845,7 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
                                               NV_ADMA_STAT_HOTUNPLUG |
                                               NV_ADMA_STAT_TIMEOUT |
                                               NV_ADMA_STAT_SERROR))) {
-                               struct ata_eh_info *ehi = &ap->eh_info;
+                               struct ata_eh_info *ehi = &ap->link.eh_info;
 
                                ata_ehi_clear_desc(ehi);
                                __ata_ehi_push_desc(ehi, "ADMA status 0x%08x: ", status );
@@ -879,10 +872,10 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
                                u32 check_commands;
                                int pos, error = 0;
 
-                               if(ata_tag_valid(ap->active_tag))
-                                       check_commands = 1 << ap->active_tag;
+                               if(ata_tag_valid(ap->link.active_tag))
+                                       check_commands = 1 << ap->link.active_tag;
                                else
-                                       check_commands = ap->sactive;
+                                       check_commands = ap->link.sactive;
 
                                /** Check CPBs for completed commands */
                                while ((pos = ffs(check_commands)) && !error) {
@@ -1333,7 +1326,7 @@ static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance)
                    !(ap->flags & ATA_FLAG_DISABLED)) {
                        struct ata_queued_cmd *qc;
 
-                       qc = ata_qc_from_tag(ap, ap->active_tag);
+                       qc = ata_qc_from_tag(ap, ap->link.active_tag);
                        if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
                                handled += ata_host_intr(ap, qc);
                        else
@@ -1459,7 +1452,7 @@ static void nv_ck804_thaw(struct ata_port *ap)
        writeb(mask, mmio_base + NV_INT_ENABLE_CK804);
 }
 
-static int nv_hardreset(struct ata_port *ap, unsigned int *class,
+static int nv_hardreset(struct ata_link *link, unsigned int *class,
                        unsigned long deadline)
 {
        unsigned int dummy;
@@ -1468,7 +1461,7 @@ static int nv_hardreset(struct ata_port *ap, unsigned int *class,
         * some controllers.  Don't classify on hardreset.  For more
         * info, see http://bugme.osdl.org/show_bug.cgi?id=3352
         */
-       return sata_std_hardreset(ap, &dummy, deadline);
+       return sata_std_hardreset(link, &dummy, deadline);
 }
 
 static void nv_error_handler(struct ata_port *ap)
@@ -1485,7 +1478,7 @@ static void nv_adma_error_handler(struct ata_port *ap)
                int i;
                u16 tmp;
 
-               if(ata_tag_valid(ap->active_tag) || ap->sactive) {
+               if(ata_tag_valid(ap->link.active_tag) || ap->link.sactive) {
                        u32 notifier = readl(mmio + NV_ADMA_NOTIFIER);
                        u32 notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR);
                        u32 gen_ctl = readl(pp->gen_block + NV_ADMA_GEN_CTL);
@@ -1501,8 +1494,8 @@ static void nv_adma_error_handler(struct ata_port *ap)
 
                        for( i=0;i<NV_ADMA_MAX_CPBS;i++) {
                                struct nv_adma_cpb *cpb = &pp->cpb[i];
-                               if( (ata_tag_valid(ap->active_tag) && i == ap->active_tag) ||
-                                   ap->sactive & (1 << i) )
+                               if( (ata_tag_valid(ap->link.active_tag) && i == ap->link.active_tag) ||
+                                   ap->link.sactive & (1 << i) )
                                        ata_port_printk(ap, KERN_ERR,
                                                "CPB %d: ctl_flags 0x%x, resp_flags 0x%x\n",
                                                i, cpb->ctl_flags, cpb->resp_flags);
index 25698cf0dce01beea9c469701dfe8415190c4b69..903213153b5d98ada9df5d817f3a06506a52e053 100644 (file)
@@ -167,7 +167,6 @@ static struct scsi_host_template pdc_ata_sht = {
 };
 
 static const struct ata_port_operations pdc_sata_ops = {
-       .port_disable           = ata_port_disable,
        .tf_load                = pdc_tf_load_mmio,
        .tf_read                = ata_tf_read,
        .check_status           = ata_check_status,
@@ -185,7 +184,6 @@ static const struct ata_port_operations pdc_sata_ops = {
        .data_xfer              = ata_data_xfer,
        .irq_clear              = pdc_irq_clear,
        .irq_on                 = ata_irq_on,
-       .irq_ack                = ata_irq_ack,
 
        .scr_read               = pdc_sata_scr_read,
        .scr_write              = pdc_sata_scr_write,
@@ -194,7 +192,6 @@ static const struct ata_port_operations pdc_sata_ops = {
 
 /* First-generation chips need a more restrictive ->check_atapi_dma op */
 static const struct ata_port_operations pdc_old_sata_ops = {
-       .port_disable           = ata_port_disable,
        .tf_load                = pdc_tf_load_mmio,
        .tf_read                = ata_tf_read,
        .check_status           = ata_check_status,
@@ -212,7 +209,6 @@ static const struct ata_port_operations pdc_old_sata_ops = {
        .data_xfer              = ata_data_xfer,
        .irq_clear              = pdc_irq_clear,
        .irq_on                 = ata_irq_on,
-       .irq_ack                = ata_irq_ack,
 
        .scr_read               = pdc_sata_scr_read,
        .scr_write              = pdc_sata_scr_write,
@@ -220,7 +216,6 @@ static const struct ata_port_operations pdc_old_sata_ops = {
 };
 
 static const struct ata_port_operations pdc_pata_ops = {
-       .port_disable           = ata_port_disable,
        .tf_load                = pdc_tf_load_mmio,
        .tf_read                = ata_tf_read,
        .check_status           = ata_check_status,
@@ -238,7 +233,6 @@ static const struct ata_port_operations pdc_pata_ops = {
        .data_xfer              = ata_data_xfer,
        .irq_clear              = pdc_irq_clear,
        .irq_on                 = ata_irq_on,
-       .irq_ack                = ata_irq_ack,
 
        .port_start             = pdc_common_port_start,
 };
@@ -475,7 +469,7 @@ static void pdc_atapi_pkt(struct ata_queued_cmd *qc)
        buf32[2] = 0;                           /* no next-packet */
 
        /* select drive */
-       if (sata_scr_valid(ap)) {
+       if (sata_scr_valid(&ap->link)) {
                dev_sel = PDC_DEVICE_SATA;
        } else {
                dev_sel = ATA_DEVICE_OBS;
@@ -626,7 +620,7 @@ static void pdc_post_internal_cmd(struct ata_queued_cmd *qc)
 static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc,
                           u32 port_status, u32 err_mask)
 {
-       struct ata_eh_info *ehi = &ap->eh_info;
+       struct ata_eh_info *ehi = &ap->link.eh_info;
        unsigned int ac_err_mask = 0;
 
        ata_ehi_clear_desc(ehi);
@@ -643,7 +637,7 @@ static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc,
                           | PDC_PCI_SYS_ERR | PDC1_PCI_PARITY_ERR))
                ac_err_mask |= AC_ERR_HOST_BUS;
 
-       if (sata_scr_valid(ap)) {
+       if (sata_scr_valid(&ap->link)) {
                u32 serror;
 
                pdc_sata_scr_read(ap, SCR_ERROR, &serror);
@@ -773,7 +767,7 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance)
                tmp = hotplug_status & (0x11 << ata_no);
                if (tmp && ap &&
                    !(ap->flags & ATA_FLAG_DISABLED)) {
-                       struct ata_eh_info *ehi = &ap->eh_info;
+                       struct ata_eh_info *ehi = &ap->link.eh_info;
                        ata_ehi_clear_desc(ehi);
                        ata_ehi_hotplugged(ehi);
                        ata_ehi_push_desc(ehi, "hotplug_status %#x", tmp);
@@ -788,7 +782,7 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance)
                    !(ap->flags & ATA_FLAG_DISABLED)) {
                        struct ata_queued_cmd *qc;
 
-                       qc = ata_qc_from_tag(ap, ap->active_tag);
+                       qc = ata_qc_from_tag(ap, ap->link.active_tag);
                        if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
                                handled += pdc_host_intr(ap, qc);
                }
@@ -1009,10 +1003,15 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
 
        is_sataii_tx4 = pdc_is_sataii_tx4(pi->flags);
        for (i = 0; i < host->n_ports; i++) {
+               struct ata_port *ap = host->ports[i];
                unsigned int ata_no = pdc_port_no_to_ata_no(i, is_sataii_tx4);
-               pdc_ata_setup_port(host->ports[i],
-                                  base + 0x200 + ata_no * 0x80,
-                                  base + 0x400 + ata_no * 0x100);
+               unsigned int port_offset = 0x200 + ata_no * 0x80;
+               unsigned int scr_offset = 0x400 + ata_no * 0x100;
+
+               pdc_ata_setup_port(ap, base + port_offset, base + scr_offset);
+
+               ata_port_pbar_desc(ap, PDC_MMIO_BAR, -1, "mmio");
+               ata_port_pbar_desc(ap, PDC_MMIO_BAR, port_offset, "port");
        }
 
        /* initialize adapter */
index 5e1dfdda698f0626baeb6194ff4cfc87038289a7..c4c4cd29eebba87bfc84e8eeb9c2e20c41bc5e74 100644 (file)
@@ -145,7 +145,6 @@ static struct scsi_host_template qs_ata_sht = {
 };
 
 static const struct ata_port_operations qs_ata_ops = {
-       .port_disable           = ata_port_disable,
        .tf_load                = ata_tf_load,
        .tf_read                = ata_tf_read,
        .check_status           = ata_check_status,
@@ -159,7 +158,6 @@ static const struct ata_port_operations qs_ata_ops = {
        .eng_timeout            = qs_eng_timeout,
        .irq_clear              = qs_irq_clear,
        .irq_on                 = ata_irq_on,
-       .irq_ack                = ata_irq_ack,
        .scr_read               = qs_scr_read,
        .scr_write              = qs_scr_write,
        .port_start             = qs_port_start,
@@ -404,7 +402,7 @@ static inline unsigned int qs_intr_pkt(struct ata_host *host)
                                struct qs_port_priv *pp = ap->private_data;
                                if (!pp || pp->state != qs_state_pkt)
                                        continue;
-                               qc = ata_qc_from_tag(ap, ap->active_tag);
+                               qc = ata_qc_from_tag(ap, ap->link.active_tag);
                                if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
                                        switch (sHST) {
                                        case 0: /* successful CPB */
@@ -437,7 +435,7 @@ static inline unsigned int qs_intr_mmio(struct ata_host *host)
                        struct qs_port_priv *pp = ap->private_data;
                        if (!pp || pp->state != qs_state_mmio)
                                continue;
-                       qc = ata_qc_from_tag(ap, ap->active_tag);
+                       qc = ata_qc_from_tag(ap, ap->link.active_tag);
                        if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
 
                                /* check main status, clearing INTRQ */
@@ -637,9 +635,14 @@ static int qs_ata_init_one(struct pci_dev *pdev,
                return rc;
 
        for (port_no = 0; port_no < host->n_ports; ++port_no) {
-               void __iomem *chan =
-                       host->iomap[QS_MMIO_BAR] + (port_no * 0x4000);
-               qs_ata_setup_port(&host->ports[port_no]->ioaddr, chan);
+               struct ata_port *ap = host->ports[port_no];
+               unsigned int offset = port_no * 0x4000;
+               void __iomem *chan = host->iomap[QS_MMIO_BAR] + offset;
+
+               qs_ata_setup_port(&ap->ioaddr, chan);
+
+               ata_port_pbar_desc(ap, QS_MMIO_BAR, -1, "mmio");
+               ata_port_pbar_desc(ap, QS_MMIO_BAR, offset, "port");
        }
 
        /* initialize adapter */
index 8c72e714b4564d52ad6fa0bc584e25af1217dd55..ea3a0ab7e027baf1d684f45eee9739c8f4ac8f55 100644 (file)
@@ -59,7 +59,8 @@ enum {
        SIL_FLAG_MOD15WRITE     = (1 << 30),
 
        SIL_DFL_PORT_FLAGS      = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-                                 ATA_FLAG_MMIO | ATA_FLAG_HRST_TO_RESUME,
+                                 ATA_FLAG_MMIO,
+       SIL_DFL_LINK_FLAGS      = ATA_LFLAG_HRST_TO_RESUME,
 
        /*
         * Controller IDs
@@ -117,7 +118,7 @@ static int sil_pci_device_resume(struct pci_dev *pdev);
 static void sil_dev_config(struct ata_device *dev);
 static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
 static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
-static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed);
+static int sil_set_mode(struct ata_link *link, struct ata_device **r_failed);
 static void sil_freeze(struct ata_port *ap);
 static void sil_thaw(struct ata_port *ap);
 
@@ -185,7 +186,6 @@ static struct scsi_host_template sil_sht = {
 };
 
 static const struct ata_port_operations sil_ops = {
-       .port_disable           = ata_port_disable,
        .dev_config             = sil_dev_config,
        .tf_load                = ata_tf_load,
        .tf_read                = ata_tf_read,
@@ -206,7 +206,6 @@ static const struct ata_port_operations sil_ops = {
        .post_internal_cmd      = ata_bmdma_post_internal_cmd,
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
-       .irq_ack                = ata_irq_ack,
        .scr_read               = sil_scr_read,
        .scr_write              = sil_scr_write,
        .port_start             = ata_port_start,
@@ -216,6 +215,7 @@ static const struct ata_port_info sil_port_info[] = {
        /* sil_3112 */
        {
                .flags          = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE,
+               .link_flags     = SIL_DFL_LINK_FLAGS,
                .pio_mask       = 0x1f,                 /* pio0-4 */
                .mwdma_mask     = 0x07,                 /* mwdma0-2 */
                .udma_mask      = ATA_UDMA5,
@@ -225,6 +225,7 @@ static const struct ata_port_info sil_port_info[] = {
        {
                .flags          = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE |
                                  SIL_FLAG_NO_SATA_IRQ,
+               .link_flags     = SIL_DFL_LINK_FLAGS,
                .pio_mask       = 0x1f,                 /* pio0-4 */
                .mwdma_mask     = 0x07,                 /* mwdma0-2 */
                .udma_mask      = ATA_UDMA5,
@@ -233,6 +234,7 @@ static const struct ata_port_info sil_port_info[] = {
        /* sil_3512 */
        {
                .flags          = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
+               .link_flags     = SIL_DFL_LINK_FLAGS,
                .pio_mask       = 0x1f,                 /* pio0-4 */
                .mwdma_mask     = 0x07,                 /* mwdma0-2 */
                .udma_mask      = ATA_UDMA5,
@@ -241,6 +243,7 @@ static const struct ata_port_info sil_port_info[] = {
        /* sil_3114 */
        {
                .flags          = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
+               .link_flags     = SIL_DFL_LINK_FLAGS,
                .pio_mask       = 0x1f,                 /* pio0-4 */
                .mwdma_mask     = 0x07,                 /* mwdma0-2 */
                .udma_mask      = ATA_UDMA5,
@@ -290,35 +293,33 @@ static unsigned char sil_get_device_cache_line(struct pci_dev *pdev)
 
 /**
  *     sil_set_mode            -       wrap set_mode functions
- *     @ap: port to set up
+ *     @link: link to set up
  *     @r_failed: returned device when we fail
  *
  *     Wrap the libata method for device setup as after the setup we need
  *     to inspect the results and do some configuration work
  */
 
-static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed)
+static int sil_set_mode(struct ata_link *link, struct ata_device **r_failed)
 {
-       struct ata_host *host = ap->host;
-       struct ata_device *dev;
-       void __iomem *mmio_base = host->iomap[SIL_MMIO_BAR];
+       struct ata_port *ap = link->ap;
+       void __iomem *mmio_base = ap->host->iomap[SIL_MMIO_BAR];
        void __iomem *addr = mmio_base + sil_port[ap->port_no].xfer_mode;
-       u32 tmp, dev_mode[2];
-       unsigned int i;
+       struct ata_device *dev;
+       u32 tmp, dev_mode[2] = { };
        int rc;
 
-       rc = ata_do_set_mode(ap, r_failed);
+       rc = ata_do_set_mode(link, r_failed);
        if (rc)
                return rc;
 
-       for (i = 0; i < 2; i++) {
-               dev = &ap->device[i];
+       ata_link_for_each_dev(dev, link) {
                if (!ata_dev_enabled(dev))
-                       dev_mode[i] = 0;        /* PIO0/1/2 */
+                       dev_mode[dev->devno] = 0;       /* PIO0/1/2 */
                else if (dev->flags & ATA_DFLAG_PIO)
-                       dev_mode[i] = 1;        /* PIO3/4 */
+                       dev_mode[dev->devno] = 1;       /* PIO3/4 */
                else
-                       dev_mode[i] = 3;        /* UDMA */
+                       dev_mode[dev->devno] = 3;       /* UDMA */
                /* value 2 indicates MDMA */
        }
 
@@ -374,8 +375,8 @@ static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
 
 static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
 {
-       struct ata_eh_info *ehi = &ap->eh_info;
-       struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
+       struct ata_eh_info *ehi = &ap->link.eh_info;
+       struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag);
        u8 status;
 
        if (unlikely(bmdma2 & SIL_DMA_SATA_IRQ)) {
@@ -394,8 +395,8 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
                 * repeat probing needlessly.
                 */
                if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
-                       ata_ehi_hotplugged(&ap->eh_info);
-                       ap->eh_info.serror |= serror;
+                       ata_ehi_hotplugged(&ap->link.eh_info);
+                       ap->link.eh_info.serror |= serror;
                }
 
                goto freeze;
@@ -562,8 +563,8 @@ static void sil_thaw(struct ata_port *ap)
  */
 static void sil_dev_config(struct ata_device *dev)
 {
-       struct ata_port *ap = dev->ap;
-       int print_info = ap->eh_context.i.flags & ATA_EHI_PRINTINFO;
+       struct ata_port *ap = dev->link->ap;
+       int print_info = ap->link.eh_context.i.flags & ATA_EHI_PRINTINFO;
        unsigned int n, quirks = 0;
        unsigned char model_num[ATA_ID_PROD_LEN + 1];
 
@@ -686,7 +687,8 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        mmio_base = host->iomap[SIL_MMIO_BAR];
 
        for (i = 0; i < host->n_ports; i++) {
-               struct ata_ioports *ioaddr = &host->ports[i]->ioaddr;
+               struct ata_port *ap = host->ports[i];
+               struct ata_ioports *ioaddr = &ap->ioaddr;
 
                ioaddr->cmd_addr = mmio_base + sil_port[i].tf;
                ioaddr->altstatus_addr =
@@ -694,6 +696,9 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
                ioaddr->bmdma_addr = mmio_base + sil_port[i].bmdma;
                ioaddr->scr_addr = mmio_base + sil_port[i].scr;
                ata_std_ports(ioaddr);
+
+               ata_port_pbar_desc(ap, SIL_MMIO_BAR, -1, "mmio");
+               ata_port_pbar_desc(ap, SIL_MMIO_BAR, sil_port[i].tf, "tf");
        }
 
        /* initialize and activate */
index 233e886933959c63f3a5d8d1ea04df0f0a2dfb6b..b0619278454a17e513f374640065996bc3622ed9 100644 (file)
@@ -30,7 +30,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME       "sata_sil24"
-#define DRV_VERSION    "1.0"
+#define DRV_VERSION    "1.1"
 
 /*
  * Port request block (PRB) 32 bytes
@@ -168,7 +168,7 @@ enum {
 
        DEF_PORT_IRQ            = PORT_IRQ_COMPLETE | PORT_IRQ_ERROR |
                                  PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG |
-                                 PORT_IRQ_UNK_FIS,
+                                 PORT_IRQ_UNK_FIS | PORT_IRQ_SDB_NOTIFY,
 
        /* bits[27:16] are unmasked (raw) */
        PORT_IRQ_RAW_SHIFT      = 16,
@@ -237,8 +237,9 @@ enum {
        /* host flags */
        SIL24_COMMON_FLAGS      = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
                                  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
-                                 ATA_FLAG_NCQ | ATA_FLAG_SKIP_D2H_BSY |
-                                 ATA_FLAG_ACPI_SATA,
+                                 ATA_FLAG_NCQ | ATA_FLAG_ACPI_SATA |
+                                 ATA_FLAG_AN | ATA_FLAG_PMP,
+       SIL24_COMMON_LFLAGS     = ATA_LFLAG_SKIP_D2H_BSY,
        SIL24_FLAG_PCIX_IRQ_WOC = (1 << 24), /* IRQ loss errata on PCI-X */
 
        IRQ_STAT_4PORTS         = 0xf,
@@ -322,6 +323,7 @@ struct sil24_port_priv {
        union sil24_cmd_block *cmd_block;       /* 32 cmd blocks */
        dma_addr_t cmd_block_dma;               /* DMA base addr for them */
        struct ata_taskfile tf;                 /* Cached taskfile registers */
+       int do_port_rst;
 };
 
 static void sil24_dev_config(struct ata_device *dev);
@@ -329,9 +331,12 @@ static u8 sil24_check_status(struct ata_port *ap);
 static int sil24_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val);
 static int sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val);
 static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
+static int sil24_qc_defer(struct ata_queued_cmd *qc);
 static void sil24_qc_prep(struct ata_queued_cmd *qc);
 static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc);
 static void sil24_irq_clear(struct ata_port *ap);
+static void sil24_pmp_attach(struct ata_port *ap);
+static void sil24_pmp_detach(struct ata_port *ap);
 static void sil24_freeze(struct ata_port *ap);
 static void sil24_thaw(struct ata_port *ap);
 static void sil24_error_handler(struct ata_port *ap);
@@ -340,6 +345,7 @@ static int sil24_port_start(struct ata_port *ap);
 static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
 #ifdef CONFIG_PM
 static int sil24_pci_device_resume(struct pci_dev *pdev);
+static int sil24_port_resume(struct ata_port *ap);
 #endif
 
 static const struct pci_device_id sil24_pci_tbl[] = {
@@ -384,8 +390,6 @@ static struct scsi_host_template sil24_sht = {
 };
 
 static const struct ata_port_operations sil24_ops = {
-       .port_disable           = ata_port_disable,
-
        .dev_config             = sil24_dev_config,
 
        .check_status           = sil24_check_status,
@@ -394,22 +398,28 @@ static const struct ata_port_operations sil24_ops = {
 
        .tf_read                = sil24_tf_read,
 
+       .qc_defer               = sil24_qc_defer,
        .qc_prep                = sil24_qc_prep,
        .qc_issue               = sil24_qc_issue,
 
        .irq_clear              = sil24_irq_clear,
-       .irq_on                 = ata_dummy_irq_on,
-       .irq_ack                = ata_dummy_irq_ack,
 
        .scr_read               = sil24_scr_read,
        .scr_write              = sil24_scr_write,
 
+       .pmp_attach             = sil24_pmp_attach,
+       .pmp_detach             = sil24_pmp_detach,
+
        .freeze                 = sil24_freeze,
        .thaw                   = sil24_thaw,
        .error_handler          = sil24_error_handler,
        .post_internal_cmd      = sil24_post_internal_cmd,
 
        .port_start             = sil24_port_start,
+
+#ifdef CONFIG_PM
+       .port_resume            = sil24_port_resume,
+#endif
 };
 
 /*
@@ -424,6 +434,7 @@ static const struct ata_port_info sil24_port_info[] = {
        {
                .flags          = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(4) |
                                  SIL24_FLAG_PCIX_IRQ_WOC,
+               .link_flags     = SIL24_COMMON_LFLAGS,
                .pio_mask       = 0x1f,                 /* pio0-4 */
                .mwdma_mask     = 0x07,                 /* mwdma0-2 */
                .udma_mask      = ATA_UDMA5,            /* udma0-5 */
@@ -432,6 +443,7 @@ static const struct ata_port_info sil24_port_info[] = {
        /* sil_3132 */
        {
                .flags          = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(2),
+               .link_flags     = SIL24_COMMON_LFLAGS,
                .pio_mask       = 0x1f,                 /* pio0-4 */
                .mwdma_mask     = 0x07,                 /* mwdma0-2 */
                .udma_mask      = ATA_UDMA5,            /* udma0-5 */
@@ -440,6 +452,7 @@ static const struct ata_port_info sil24_port_info[] = {
        /* sil_3131/sil_3531 */
        {
                .flags          = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(1),
+               .link_flags     = SIL24_COMMON_LFLAGS,
                .pio_mask       = 0x1f,                 /* pio0-4 */
                .mwdma_mask     = 0x07,                 /* mwdma0-2 */
                .udma_mask      = ATA_UDMA5,            /* udma0-5 */
@@ -456,7 +469,7 @@ static int sil24_tag(int tag)
 
 static void sil24_dev_config(struct ata_device *dev)
 {
-       void __iomem *port = dev->ap->ioaddr.cmd_addr;
+       void __iomem *port = dev->link->ap->ioaddr.cmd_addr;
 
        if (dev->cdb_len == 16)
                writel(PORT_CS_CDB16, port + PORT_CTRL_STAT);
@@ -520,19 +533,78 @@ static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
        *tf = pp->tf;
 }
 
+static void sil24_config_port(struct ata_port *ap)
+{
+       void __iomem *port = ap->ioaddr.cmd_addr;
+
+       /* configure IRQ WoC */
+       if (ap->flags & SIL24_FLAG_PCIX_IRQ_WOC)
+               writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
+       else
+               writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
+
+       /* zero error counters. */
+       writel(0x8000, port + PORT_DECODE_ERR_THRESH);
+       writel(0x8000, port + PORT_CRC_ERR_THRESH);
+       writel(0x8000, port + PORT_HSHK_ERR_THRESH);
+       writel(0x0000, port + PORT_DECODE_ERR_CNT);
+       writel(0x0000, port + PORT_CRC_ERR_CNT);
+       writel(0x0000, port + PORT_HSHK_ERR_CNT);
+
+       /* always use 64bit activation */
+       writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
+
+       /* clear port multiplier enable and resume bits */
+       writel(PORT_CS_PMP_EN | PORT_CS_PMP_RESUME, port + PORT_CTRL_CLR);
+}
+
+static void sil24_config_pmp(struct ata_port *ap, int attached)
+{
+       void __iomem *port = ap->ioaddr.cmd_addr;
+
+       if (attached)
+               writel(PORT_CS_PMP_EN, port + PORT_CTRL_STAT);
+       else
+               writel(PORT_CS_PMP_EN, port + PORT_CTRL_CLR);
+}
+
+static void sil24_clear_pmp(struct ata_port *ap)
+{
+       void __iomem *port = ap->ioaddr.cmd_addr;
+       int i;
+
+       writel(PORT_CS_PMP_RESUME, port + PORT_CTRL_CLR);
+
+       for (i = 0; i < SATA_PMP_MAX_PORTS; i++) {
+               void __iomem *pmp_base = port + PORT_PMP + i * PORT_PMP_SIZE;
+
+               writel(0, pmp_base + PORT_PMP_STATUS);
+               writel(0, pmp_base + PORT_PMP_QACTIVE);
+       }
+}
+
 static int sil24_init_port(struct ata_port *ap)
 {
        void __iomem *port = ap->ioaddr.cmd_addr;
+       struct sil24_port_priv *pp = ap->private_data;
        u32 tmp;
 
+       /* clear PMP error status */
+       if (ap->nr_pmp_links)
+               sil24_clear_pmp(ap);
+
        writel(PORT_CS_INIT, port + PORT_CTRL_STAT);
        ata_wait_register(port + PORT_CTRL_STAT,
                          PORT_CS_INIT, PORT_CS_INIT, 10, 100);
        tmp = ata_wait_register(port + PORT_CTRL_STAT,
                                PORT_CS_RDY, 0, 10, 100);
 
-       if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY)
+       if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY) {
+               pp->do_port_rst = 1;
+               ap->link.eh_context.i.action |= ATA_EH_HARDRESET;
                return -EIO;
+       }
+
        return 0;
 }
 
@@ -583,9 +655,10 @@ static int sil24_exec_polled_cmd(struct ata_port *ap, int pmp,
        return rc;
 }
 
-static int sil24_do_softreset(struct ata_port *ap, unsigned int *class,
+static int sil24_do_softreset(struct ata_link *link, unsigned int *class,
                              int pmp, unsigned long deadline)
 {
+       struct ata_port *ap = link->ap;
        unsigned long timeout_msec = 0;
        struct ata_taskfile tf;
        const char *reason;
@@ -593,7 +666,7 @@ static int sil24_do_softreset(struct ata_port *ap, unsigned int *class,
 
        DPRINTK("ENTER\n");
 
-       if (ata_port_offline(ap)) {
+       if (ata_link_offline(link)) {
                DPRINTK("PHY reports no device\n");
                *class = ATA_DEV_NONE;
                goto out;
@@ -609,7 +682,7 @@ static int sil24_do_softreset(struct ata_port *ap, unsigned int *class,
        if (time_after(deadline, jiffies))
                timeout_msec = jiffies_to_msecs(deadline - jiffies);
 
-       ata_tf_init(ap->device, &tf);   /* doesn't really matter */
+       ata_tf_init(link->device, &tf); /* doesn't really matter */
        rc = sil24_exec_polled_cmd(ap, pmp, &tf, 0, PRB_CTRL_SRST,
                                   timeout_msec);
        if (rc == -EBUSY) {
@@ -631,29 +704,54 @@ static int sil24_do_softreset(struct ata_port *ap, unsigned int *class,
        return 0;
 
  err:
-       ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
+       ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason);
        return -EIO;
 }
 
-static int sil24_softreset(struct ata_port *ap, unsigned int *class,
+static int sil24_softreset(struct ata_link *link, unsigned int *class,
                           unsigned long deadline)
 {
-       return sil24_do_softreset(ap, class, 0, deadline);
+       return sil24_do_softreset(link, class, SATA_PMP_CTRL_PORT, deadline);
 }
 
-static int sil24_hardreset(struct ata_port *ap, unsigned int *class,
+static int sil24_hardreset(struct ata_link *link, unsigned int *class,
                           unsigned long deadline)
 {
+       struct ata_port *ap = link->ap;
        void __iomem *port = ap->ioaddr.cmd_addr;
+       struct sil24_port_priv *pp = ap->private_data;
+       int did_port_rst = 0;
        const char *reason;
        int tout_msec, rc;
        u32 tmp;
 
+ retry:
+       /* Sometimes, DEV_RST is not enough to recover the controller.
+        * This happens often after PM DMA CS errata.
+        */
+       if (pp->do_port_rst) {
+               ata_port_printk(ap, KERN_WARNING, "controller in dubious "
+                               "state, performing PORT_RST\n");
+
+               writel(PORT_CS_PORT_RST, port + PORT_CTRL_STAT);
+               msleep(10);
+               writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
+               ata_wait_register(port + PORT_CTRL_STAT, PORT_CS_RDY, 0,
+                                 10, 5000);
+
+               /* restore port configuration */
+               sil24_config_port(ap);
+               sil24_config_pmp(ap, ap->nr_pmp_links);
+
+               pp->do_port_rst = 0;
+               did_port_rst = 1;
+       }
+
        /* sil24 does the right thing(tm) without any protection */
-       sata_set_spd(ap);
+       sata_set_spd(link);
 
        tout_msec = 100;
-       if (ata_port_online(ap))
+       if (ata_link_online(link))
                tout_msec = 5000;
 
        writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT);
@@ -663,14 +761,14 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class,
        /* SStatus oscillates between zero and valid status after
         * DEV_RST, debounce it.
         */
-       rc = sata_phy_debounce(ap, sata_deb_timing_long, deadline);
+       rc = sata_link_debounce(link, sata_deb_timing_long, deadline);
        if (rc) {
                reason = "PHY debouncing failed";
                goto err;
        }
 
        if (tmp & PORT_CS_DEV_RST) {
-               if (ata_port_offline(ap))
+               if (ata_link_offline(link))
                        return 0;
                reason = "link not ready";
                goto err;
@@ -685,7 +783,12 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class,
        return -EAGAIN;
 
  err:
-       ata_port_printk(ap, KERN_ERR, "hardreset failed (%s)\n", reason);
+       if (!did_port_rst) {
+               pp->do_port_rst = 1;
+               goto retry;
+       }
+
+       ata_link_printk(link, KERN_ERR, "hardreset failed (%s)\n", reason);
        return -EIO;
 }
 
@@ -705,6 +808,38 @@ static inline void sil24_fill_sg(struct ata_queued_cmd *qc,
        }
 }
 
+static int sil24_qc_defer(struct ata_queued_cmd *qc)
+{
+       struct ata_link *link = qc->dev->link;
+       struct ata_port *ap = link->ap;
+       u8 prot = qc->tf.protocol;
+       int is_atapi = (prot == ATA_PROT_ATAPI ||
+                       prot == ATA_PROT_ATAPI_NODATA ||
+                       prot == ATA_PROT_ATAPI_DMA);
+
+       /* ATAPI commands completing with CHECK_SENSE cause various
+        * weird problems if other commands are active.  PMP DMA CS
+        * errata doesn't cover all and HSM violation occurs even with
+        * only one other device active.  Always run an ATAPI command
+        * by itself.
+        */
+       if (unlikely(ap->excl_link)) {
+               if (link == ap->excl_link) {
+                       if (ap->nr_active_links)
+                               return ATA_DEFER_PORT;
+                       qc->flags |= ATA_QCFLAG_CLEAR_EXCL;
+               } else
+                       return ATA_DEFER_PORT;
+       } else if (unlikely(is_atapi)) {
+               ap->excl_link = link;
+               if (ap->nr_active_links)
+                       return ATA_DEFER_PORT;
+               qc->flags |= ATA_QCFLAG_CLEAR_EXCL;
+       }
+
+       return ata_std_qc_defer(qc);
+}
+
 static void sil24_qc_prep(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
@@ -748,7 +883,7 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc)
        }
 
        prb->ctrl = cpu_to_le16(ctrl);
-       ata_tf_to_fis(&qc->tf, 0, 1, prb->fis);
+       ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, prb->fis);
 
        if (qc->flags & ATA_QCFLAG_DMAMAP)
                sil24_fill_sg(qc, sge);
@@ -777,6 +912,39 @@ static void sil24_irq_clear(struct ata_port *ap)
        /* unused */
 }
 
+static void sil24_pmp_attach(struct ata_port *ap)
+{
+       sil24_config_pmp(ap, 1);
+       sil24_init_port(ap);
+}
+
+static void sil24_pmp_detach(struct ata_port *ap)
+{
+       sil24_init_port(ap);
+       sil24_config_pmp(ap, 0);
+}
+
+static int sil24_pmp_softreset(struct ata_link *link, unsigned int *class,
+                              unsigned long deadline)
+{
+       return sil24_do_softreset(link, class, link->pmp, deadline);
+}
+
+static int sil24_pmp_hardreset(struct ata_link *link, unsigned int *class,
+                              unsigned long deadline)
+{
+       int rc;
+
+       rc = sil24_init_port(link->ap);
+       if (rc) {
+               ata_link_printk(link, KERN_ERR,
+                               "hardreset failed (port not ready)\n");
+               return rc;
+       }
+
+       return sata_pmp_std_hardreset(link, class, deadline);
+}
+
 static void sil24_freeze(struct ata_port *ap)
 {
        void __iomem *port = ap->ioaddr.cmd_addr;
@@ -804,8 +972,10 @@ static void sil24_error_intr(struct ata_port *ap)
 {
        void __iomem *port = ap->ioaddr.cmd_addr;
        struct sil24_port_priv *pp = ap->private_data;
-       struct ata_eh_info *ehi = &ap->eh_info;
-       int freeze = 0;
+       struct ata_queued_cmd *qc = NULL;
+       struct ata_link *link;
+       struct ata_eh_info *ehi;
+       int abort = 0, freeze = 0;
        u32 irq_stat;
 
        /* on error, we need to clear IRQ explicitly */
@@ -813,10 +983,17 @@ static void sil24_error_intr(struct ata_port *ap)
        writel(irq_stat, port + PORT_IRQ_STAT);
 
        /* first, analyze and record host port events */
+       link = &ap->link;
+       ehi = &link->eh_info;
        ata_ehi_clear_desc(ehi);
 
        ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat);
 
+       if (irq_stat & PORT_IRQ_SDB_NOTIFY) {
+               ata_ehi_push_desc(ehi, "SDB notify");
+               sata_async_notification(ap);
+       }
+
        if (irq_stat & (PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG)) {
                ata_ehi_hotplugged(ehi);
                ata_ehi_push_desc(ehi, "%s",
@@ -836,8 +1013,44 @@ static void sil24_error_intr(struct ata_port *ap)
        if (irq_stat & PORT_IRQ_ERROR) {
                struct sil24_cerr_info *ci = NULL;
                unsigned int err_mask = 0, action = 0;
-               struct ata_queued_cmd *qc;
-               u32 cerr;
+               u32 context, cerr;
+               int pmp;
+
+               abort = 1;
+
+               /* DMA Context Switch Failure in Port Multiplier Mode
+                * errata.  If we have active commands to 3 or more
+                * devices, any error condition on active devices can
+                * corrupt DMA context switching.
+                */
+               if (ap->nr_active_links >= 3) {
+                       ehi->err_mask |= AC_ERR_OTHER;
+                       ehi->action |= ATA_EH_HARDRESET;
+                       ata_ehi_push_desc(ehi, "PMP DMA CS errata");
+                       pp->do_port_rst = 1;
+                       freeze = 1;
+               }
+
+               /* find out the offending link and qc */
+               if (ap->nr_pmp_links) {
+                       context = readl(port + PORT_CONTEXT);
+                       pmp = (context >> 5) & 0xf;
+
+                       if (pmp < ap->nr_pmp_links) {
+                               link = &ap->pmp_link[pmp];
+                               ehi = &link->eh_info;
+                               qc = ata_qc_from_tag(ap, link->active_tag);
+
+                               ata_ehi_clear_desc(ehi);
+                               ata_ehi_push_desc(ehi, "irq_stat 0x%08x",
+                                                 irq_stat);
+                       } else {
+                               err_mask |= AC_ERR_HSM;
+                               action |= ATA_EH_HARDRESET;
+                               freeze = 1;
+                       }
+               } else
+                       qc = ata_qc_from_tag(ap, link->active_tag);
 
                /* analyze CMD_ERR */
                cerr = readl(port + PORT_CMD_ERR);
@@ -856,7 +1069,6 @@ static void sil24_error_intr(struct ata_port *ap)
                }
 
                /* record error info */
-               qc = ata_qc_from_tag(ap, ap->active_tag);
                if (qc) {
                        sil24_read_tf(ap, qc->tag, &pp->tf);
                        qc->err_mask |= err_mask;
@@ -864,13 +1076,21 @@ static void sil24_error_intr(struct ata_port *ap)
                        ehi->err_mask |= err_mask;
 
                ehi->action |= action;
+
+               /* if PMP, resume */
+               if (ap->nr_pmp_links)
+                       writel(PORT_CS_PMP_RESUME, port + PORT_CTRL_STAT);
        }
 
        /* freeze or abort */
        if (freeze)
                ata_port_freeze(ap);
-       else
-               ata_port_abort(ap);
+       else if (abort) {
+               if (qc)
+                       ata_link_abort(qc->dev->link);
+               else
+                       ata_port_abort(ap);
+       }
 }
 
 static void sil24_finish_qc(struct ata_queued_cmd *qc)
@@ -910,7 +1130,7 @@ static inline void sil24_host_intr(struct ata_port *ap)
        if (rc > 0)
                return;
        if (rc < 0) {
-               struct ata_eh_info *ehi = &ap->eh_info;
+               struct ata_eh_info *ehi = &ap->link.eh_info;
                ehi->err_mask |= AC_ERR_HSM;
                ehi->action |= ATA_EH_SOFTRESET;
                ata_port_freeze(ap);
@@ -921,7 +1141,7 @@ static inline void sil24_host_intr(struct ata_port *ap)
        if (!(ap->flags & SIL24_FLAG_PCIX_IRQ_WOC) && ata_ratelimit())
                ata_port_printk(ap, KERN_INFO, "spurious interrupt "
                        "(slot_stat 0x%x active_tag %d sactive 0x%x)\n",
-                       slot_stat, ap->active_tag, ap->sactive);
+                       slot_stat, ap->link.active_tag, ap->link.sactive);
 }
 
 static irqreturn_t sil24_interrupt(int irq, void *dev_instance)
@@ -963,16 +1183,18 @@ static irqreturn_t sil24_interrupt(int irq, void *dev_instance)
 
 static void sil24_error_handler(struct ata_port *ap)
 {
-       struct ata_eh_context *ehc = &ap->eh_context;
+       struct sil24_port_priv *pp = ap->private_data;
 
-       if (sil24_init_port(ap)) {
+       if (sil24_init_port(ap))
                ata_eh_freeze_port(ap);
-               ehc->i.action |= ATA_EH_HARDRESET;
-       }
 
        /* perform recovery */
-       ata_do_eh(ap, ata_std_prereset, sil24_softreset, sil24_hardreset,
-                 ata_std_postreset);
+       sata_pmp_do_eh(ap, ata_std_prereset, sil24_softreset, sil24_hardreset,
+                      ata_std_postreset, sata_pmp_std_prereset,
+                      sil24_pmp_softreset, sil24_pmp_hardreset,
+                      sata_pmp_std_postreset);
+
+       pp->do_port_rst = 0;
 }
 
 static void sil24_post_internal_cmd(struct ata_queued_cmd *qc)
@@ -980,8 +1202,8 @@ static void sil24_post_internal_cmd(struct ata_queued_cmd *qc)
        struct ata_port *ap = qc->ap;
 
        /* make DMA engine forget about the failed command */
-       if (qc->flags & ATA_QCFLAG_FAILED)
-               sil24_init_port(ap);
+       if ((qc->flags & ATA_QCFLAG_FAILED) && sil24_init_port(ap))
+               ata_eh_freeze_port(ap);
 }
 
 static int sil24_port_start(struct ata_port *ap)
@@ -1019,7 +1241,6 @@ static int sil24_port_start(struct ata_port *ap)
 static void sil24_init_controller(struct ata_host *host)
 {
        void __iomem *host_base = host->iomap[SIL24_HOST_BAR];
-       void __iomem *port_base = host->iomap[SIL24_PORT_BAR];
        u32 tmp;
        int i;
 
@@ -1031,7 +1252,8 @@ static void sil24_init_controller(struct ata_host *host)
 
        /* init ports */
        for (i = 0; i < host->n_ports; i++) {
-               void __iomem *port = port_base + i * PORT_REGS_SIZE;
+               struct ata_port *ap = host->ports[i];
+               void __iomem *port = ap->ioaddr.cmd_addr;
 
                /* Initial PHY setting */
                writel(0x20c, port + PORT_PHY_CFG);
@@ -1048,26 +1270,8 @@ static void sil24_init_controller(struct ata_host *host)
                                           "failed to clear port RST\n");
                }
 
-               /* Configure IRQ WoC */
-               if (host->ports[0]->flags & SIL24_FLAG_PCIX_IRQ_WOC)
-                       writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
-               else
-                       writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
-
-               /* Zero error counters. */
-               writel(0x8000, port + PORT_DECODE_ERR_THRESH);
-               writel(0x8000, port + PORT_CRC_ERR_THRESH);
-               writel(0x8000, port + PORT_HSHK_ERR_THRESH);
-               writel(0x0000, port + PORT_DECODE_ERR_CNT);
-               writel(0x0000, port + PORT_CRC_ERR_CNT);
-               writel(0x0000, port + PORT_HSHK_ERR_CNT);
-
-               /* Always use 64bit activation */
-               writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
-
-               /* Clear port multiplier enable and resume bits */
-               writel(PORT_CS_PMP_EN | PORT_CS_PMP_RESUME,
-                      port + PORT_CTRL_CLR);
+               /* configure port */
+               sil24_config_port(ap);
        }
 
        /* Turn on interrupts */
@@ -1118,12 +1322,15 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        host->iomap = iomap;
 
        for (i = 0; i < host->n_ports; i++) {
-               void __iomem *port = iomap[SIL24_PORT_BAR] + i * PORT_REGS_SIZE;
+               struct ata_port *ap = host->ports[i];
+               size_t offset = ap->port_no * PORT_REGS_SIZE;
+               void __iomem *port = iomap[SIL24_PORT_BAR] + offset;
 
                host->ports[i]->ioaddr.cmd_addr = port;
                host->ports[i]->ioaddr.scr_addr = port + PORT_SCONTROL;
 
-               ata_std_ports(&host->ports[i]->ioaddr);
+               ata_port_pbar_desc(ap, SIL24_HOST_BAR, -1, "host");
+               ata_port_pbar_desc(ap, SIL24_PORT_BAR, offset, "port");
        }
 
        /* configure and activate the device */
@@ -1179,6 +1386,12 @@ static int sil24_pci_device_resume(struct pci_dev *pdev)
 
        return 0;
 }
+
+static int sil24_port_resume(struct ata_port *ap)
+{
+       sil24_config_pmp(ap, ap->nr_pmp_links);
+       return 0;
+}
 #endif
 
 static int __init sil24_init(void)
index 41c1d6e8f1feb037afc6a278dfd17652dc644380..8d98a9fb0a42d12162f744204b25c279a3706dde 100644 (file)
@@ -104,7 +104,6 @@ static struct scsi_host_template sis_sht = {
 };
 
 static const struct ata_port_operations sis_ops = {
-       .port_disable           = ata_port_disable,
        .tf_load                = ata_tf_load,
        .tf_read                = ata_tf_read,
        .check_status           = ata_check_status,
@@ -123,7 +122,6 @@ static const struct ata_port_operations sis_ops = {
        .post_internal_cmd      = ata_bmdma_post_internal_cmd,
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
-       .irq_ack                = ata_irq_ack,
        .scr_read               = sis_scr_read,
        .scr_write              = sis_scr_write,
        .port_start             = ata_port_start,
index d9678e7bc3a9a3e36cfb71710d9c0e8db723a391..12d613c48c19100b101d3608dcca720b6cae22a2 100644 (file)
@@ -329,7 +329,6 @@ static struct scsi_host_template k2_sata_sht = {
 
 
 static const struct ata_port_operations k2_sata_ops = {
-       .port_disable           = ata_port_disable,
        .tf_load                = k2_sata_tf_load,
        .tf_read                = k2_sata_tf_read,
        .check_status           = k2_stat_check_status,
@@ -349,7 +348,6 @@ static const struct ata_port_operations k2_sata_ops = {
        .post_internal_cmd      = ata_bmdma_post_internal_cmd,
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
-       .irq_ack                = ata_irq_ack,
        .scr_read               = k2_sata_scr_read,
        .scr_write              = k2_sata_scr_write,
        .port_start             = ata_port_start,
@@ -445,9 +443,15 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
        /* different controllers have different number of ports - currently 4 or 8 */
        /* All ports are on the same function. Multi-function device is no
         * longer available. This should not be seen in any system. */
-       for (i = 0; i < host->n_ports; i++)
-               k2_sata_setup_port(&host->ports[i]->ioaddr,
-                                  mmio_base + i * K2_SATA_PORT_OFFSET);
+       for (i = 0; i < host->n_ports; i++) {
+               struct ata_port *ap = host->ports[i];
+               unsigned int offset = i * K2_SATA_PORT_OFFSET;
+
+               k2_sata_setup_port(&ap->ioaddr, mmio_base + offset);
+
+               ata_port_pbar_desc(ap, 5, -1, "mmio");
+               ata_port_pbar_desc(ap, 5, offset, "port");
+       }
 
        rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
        if (rc)
index 97aefdd87be4d28ee62556c54c2522eb11f51393..9f9f7b30654a3b5ff05b0dd1ad35140167a00689 100644 (file)
@@ -254,7 +254,6 @@ static struct scsi_host_template pdc_sata_sht = {
 };
 
 static const struct ata_port_operations pdc_20621_ops = {
-       .port_disable           = ata_port_disable,
        .tf_load                = pdc_tf_load_mmio,
        .tf_read                = ata_tf_read,
        .check_status           = ata_check_status,
@@ -267,7 +266,6 @@ static const struct ata_port_operations pdc_20621_ops = {
        .eng_timeout            = pdc_eng_timeout,
        .irq_clear              = pdc20621_irq_clear,
        .irq_on                 = ata_irq_on,
-       .irq_ack                = ata_irq_ack,
        .port_start             = pdc_port_start,
 };
 
@@ -854,7 +852,7 @@ static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance)
                    !(ap->flags & ATA_FLAG_DISABLED)) {
                        struct ata_queued_cmd *qc;
 
-                       qc = ata_qc_from_tag(ap, ap->active_tag);
+                       qc = ata_qc_from_tag(ap, ap->link.active_tag);
                        if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
                                handled += pdc20621_host_intr(ap, qc, (i > 4),
                                                              mmio_base);
@@ -881,7 +879,7 @@ static void pdc_eng_timeout(struct ata_port *ap)
 
        spin_lock_irqsave(&host->lock, flags);
 
-       qc = ata_qc_from_tag(ap, ap->active_tag);
+       qc = ata_qc_from_tag(ap, ap->link.active_tag);
 
        switch (qc->tf.protocol) {
        case ATA_PROT_DMA:
@@ -1383,9 +1381,8 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *
        const struct ata_port_info *ppi[] =
                { &pdc_port_info[ent->driver_data], NULL };
        struct ata_host *host;
-       void __iomem *base;
        struct pdc_host_priv *hpriv;
-       int rc;
+       int i, rc;
 
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
@@ -1411,11 +1408,17 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *
                return rc;
        host->iomap = pcim_iomap_table(pdev);
 
-       base = host->iomap[PDC_MMIO_BAR] + PDC_CHIP0_OFS;
-       pdc_sata_setup_port(&host->ports[0]->ioaddr, base + 0x200);
-       pdc_sata_setup_port(&host->ports[1]->ioaddr, base + 0x280);
-       pdc_sata_setup_port(&host->ports[2]->ioaddr, base + 0x300);
-       pdc_sata_setup_port(&host->ports[3]->ioaddr, base + 0x380);
+       for (i = 0; i < 4; i++) {
+               struct ata_port *ap = host->ports[i];
+               void __iomem *base = host->iomap[PDC_MMIO_BAR] + PDC_CHIP0_OFS;
+               unsigned int offset = 0x200 + i * 0x80;
+
+               pdc_sata_setup_port(&ap->ioaddr, base + offset);
+
+               ata_port_pbar_desc(ap, PDC_MMIO_BAR, -1, "mmio");
+               ata_port_pbar_desc(ap, PDC_DIMM_BAR, -1, "dimm");
+               ata_port_pbar_desc(ap, PDC_MMIO_BAR, offset, "port");
+       }
 
        /* configure and activate */
        rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
index e6b8b45279afb8f670c74664239360c284fa2a66..d394da085ae45e57f3909560a1d18e02be809b80 100644 (file)
@@ -94,8 +94,6 @@ static struct scsi_host_template uli_sht = {
 };
 
 static const struct ata_port_operations uli_ops = {
-       .port_disable           = ata_port_disable,
-
        .tf_load                = ata_tf_load,
        .tf_read                = ata_tf_read,
        .check_status           = ata_check_status,
@@ -117,7 +115,6 @@ static const struct ata_port_operations uli_ops = {
 
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
-       .irq_ack                = ata_irq_ack,
 
        .scr_read               = uli_scr_read,
        .scr_write              = uli_scr_write,
@@ -242,6 +239,12 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
                hpriv->scr_cfg_addr[2] = ULI5287_BASE + ULI5287_OFFS*4;
                ata_std_ports(ioaddr);
 
+               ata_port_desc(host->ports[2],
+                       "cmd 0x%llx ctl 0x%llx bmdma 0x%llx",
+                       (unsigned long long)pci_resource_start(pdev, 0) + 8,
+                       ((unsigned long long)pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS) + 4,
+                       (unsigned long long)pci_resource_start(pdev, 4) + 16);
+
                ioaddr = &host->ports[3]->ioaddr;
                ioaddr->cmd_addr = iomap[2] + 8;
                ioaddr->altstatus_addr =
@@ -250,6 +253,13 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
                ioaddr->bmdma_addr = iomap[4] + 24;
                hpriv->scr_cfg_addr[3] = ULI5287_BASE + ULI5287_OFFS*5;
                ata_std_ports(ioaddr);
+
+               ata_port_desc(host->ports[2],
+                       "cmd 0x%llx ctl 0x%llx bmdma 0x%llx",
+                       (unsigned long long)pci_resource_start(pdev, 2) + 9,
+                       ((unsigned long long)pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS) + 4,
+                       (unsigned long long)pci_resource_start(pdev, 4) + 24);
+
                break;
 
        case uli_5289:
index 57fd30de8f0dda9c811a8fd377bc1eb40f4434f2..cc6ee0890f56c1ddcb24581bbad7bbc27ae2640e 100644 (file)
@@ -57,7 +57,6 @@ enum {
        SATA_CHAN_ENAB          = 0x40, /* SATA channel enable */
        SATA_INT_GATE           = 0x41, /* SATA interrupt gating */
        SATA_NATIVE_MODE        = 0x42, /* Native mode enable */
-       SATA_PATA_SHARING       = 0x49, /* PATA/SATA sharing func ctrl */
        PATA_UDMA_TIMING        = 0xB3, /* PATA timing for DMA/ cable detect */
        PATA_PIO_TIMING         = 0xAB, /* PATA timing register */
 
@@ -68,7 +67,6 @@ enum {
        NATIVE_MODE_ALL         = (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4),
 
        SATA_EXT_PHY            = (1 << 6), /* 0==use PATA, 1==ext phy */
-       SATA_2DEV               = (1 << 5), /* SATA is master/slave */
 };
 
 static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
@@ -122,8 +120,6 @@ static struct scsi_host_template svia_sht = {
 };
 
 static const struct ata_port_operations vt6420_sata_ops = {
-       .port_disable           = ata_port_disable,
-
        .tf_load                = ata_tf_load,
        .tf_read                = ata_tf_read,
        .check_status           = ata_check_status,
@@ -146,14 +142,11 @@ static const struct ata_port_operations vt6420_sata_ops = {
 
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
-       .irq_ack                = ata_irq_ack,
 
        .port_start             = ata_port_start,
 };
 
 static const struct ata_port_operations vt6421_pata_ops = {
-       .port_disable           = ata_port_disable,
-
        .set_piomode            = vt6421_set_pio_mode,
        .set_dmamode            = vt6421_set_dma_mode,
 
@@ -180,14 +173,11 @@ static const struct ata_port_operations vt6421_pata_ops = {
 
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
-       .irq_ack                = ata_irq_ack,
 
        .port_start             = ata_port_start,
 };
 
 static const struct ata_port_operations vt6421_sata_ops = {
-       .port_disable           = ata_port_disable,
-
        .tf_load                = ata_tf_load,
        .tf_read                = ata_tf_read,
        .check_status           = ata_check_status,
@@ -211,7 +201,6 @@ static const struct ata_port_operations vt6421_sata_ops = {
 
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
-       .irq_ack                = ata_irq_ack,
 
        .scr_read               = svia_scr_read,
        .scr_write              = svia_scr_write,
@@ -276,7 +265,7 @@ static void svia_noop_freeze(struct ata_port *ap)
 
 /**
  *     vt6420_prereset - prereset for vt6420
- *     @ap: target ATA port
+ *     @link: target ATA link
  *     @deadline: deadline jiffies for the operation
  *
  *     SCR registers on vt6420 are pieces of shit and may hang the
@@ -294,9 +283,10 @@ static void svia_noop_freeze(struct ata_port *ap)
  *     RETURNS:
  *     0 on success, -errno otherwise.
  */
-static int vt6420_prereset(struct ata_port *ap, unsigned long deadline)
+static int vt6420_prereset(struct ata_link *link, unsigned long deadline)
 {
-       struct ata_eh_context *ehc = &ap->eh_context;
+       struct ata_port *ap = link->ap;
+       struct ata_eh_context *ehc = &ap->link.eh_context;
        unsigned long timeout = jiffies + (HZ * 5);
        u32 sstatus, scontrol;
        int online;
@@ -407,6 +397,9 @@ static void vt6421_init_addrs(struct ata_port *ap)
        ioaddr->scr_addr = vt6421_scr_addr(iomap[5], ap->port_no);
 
        ata_std_ports(ioaddr);
+
+       ata_port_pbar_desc(ap, ap->port_no, -1, "port");
+       ata_port_pbar_desc(ap, 4, ap->port_no * 8, "bmdma");
 }
 
 static int vt6420_prepare_host(struct pci_dev *pdev, struct ata_host **r_host)
@@ -512,8 +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;
-       u8 tmp8;
+       const unsigned *bar_sizes;
 
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
@@ -522,19 +514,10 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        if (rc)
                return rc;
 
-       if (board_id == vt6420) {
-               pci_read_config_byte(pdev, SATA_PATA_SHARING, &tmp8);
-               if (tmp8 & SATA_2DEV) {
-                       dev_printk(KERN_ERR, &pdev->dev,
-                                  "SATA master/slave not supported (0x%x)\n",
-                                  (int) tmp8);
-                       return -EIO;
-               }
-
+       if (board_id == vt6420)
                bar_sizes = &svia_bar_sizes[0];
-       } else {
+       else
                bar_sizes = &vt6421_bar_sizes[0];
-       }
 
        for (i = 0; i < ARRAY_SIZE(svia_bar_sizes); i++)
                if ((pci_resource_start(pdev, i) == 0) ||
index 1920915dfa2ca41f5856d591b1fd1fd740b971ff..0d9be168487326504ba799b38bab2091c1ed4ab2 100644 (file)
@@ -240,7 +240,7 @@ static void vsc_port_intr(u8 port_status, struct ata_port *ap)
                return;
        }
 
-       qc = ata_qc_from_tag(ap, ap->active_tag);
+       qc = ata_qc_from_tag(ap, ap->link.active_tag);
        if (qc && likely(!(qc->tf.flags & ATA_TFLAG_POLLING)))
                handled = ata_host_intr(ap, qc);
 
@@ -317,7 +317,6 @@ static struct scsi_host_template vsc_sata_sht = {
 
 
 static const struct ata_port_operations vsc_sata_ops = {
-       .port_disable           = ata_port_disable,
        .tf_load                = vsc_sata_tf_load,
        .tf_read                = vsc_sata_tf_read,
        .exec_command           = ata_exec_command,
@@ -336,7 +335,6 @@ static const struct ata_port_operations vsc_sata_ops = {
        .post_internal_cmd      = ata_bmdma_post_internal_cmd,
        .irq_clear              = ata_bmdma_irq_clear,
        .irq_on                 = ata_irq_on,
-       .irq_ack                = ata_irq_ack,
        .scr_read               = vsc_sata_scr_read,
        .scr_write              = vsc_sata_scr_write,
        .port_start             = ata_port_start,
@@ -408,9 +406,15 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d
 
        mmio_base = host->iomap[VSC_MMIO_BAR];
 
-       for (i = 0; i < host->n_ports; i++)
-               vsc_sata_setup_port(&host->ports[i]->ioaddr,
-                                   mmio_base + (i + 1) * VSC_SATA_PORT_OFFSET);
+       for (i = 0; i < host->n_ports; i++) {
+               struct ata_port *ap = host->ports[i];
+               unsigned int offset = (i + 1) * VSC_SATA_PORT_OFFSET;
+
+               vsc_sata_setup_port(&ap->ioaddr, mmio_base + offset);
+
+               ata_port_pbar_desc(ap, VSC_MMIO_BAR, -1, "mmio");
+               ata_port_pbar_desc(ap, VSC_MMIO_BAR, offset, "port");
+       }
 
        /*
         * Use 32 bit DMA mask, because 64 bit address support is poor.
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 5d6312e3349062cee54d204163bb5407d300a1bb..d7da109c24fd298a5bf6cd527bb3b0fdad783d7a 100644 (file)
@@ -1,5 +1,13 @@
 menu "Generic Driver Options"
 
+config UEVENT_HELPER_PATH
+       string "path to uevent helper"
+       depends on HOTPLUG
+       default "/sbin/hotplug"
+       help
+         Path to uevent helper program forked by the kernel for
+         every uevent.
+
 config STANDALONE
        bool "Select only drivers that don't need compile-time external firmware" if EXPERIMENTAL
        default y
index 47eb02d9f1afdc30489a9520ae44ba334a4bd9ea..10b2fb6c9ce68fdbae4a9a4822a298ead5c3732b 100644 (file)
@@ -18,8 +18,6 @@ extern int attribute_container_init(void);
 extern int bus_add_device(struct device * dev);
 extern void bus_attach_device(struct device * dev);
 extern void bus_remove_device(struct device * dev);
-extern struct bus_type *get_bus(struct bus_type * bus);
-extern void put_bus(struct bus_type * bus);
 
 extern int bus_add_driver(struct device_driver *);
 extern void bus_remove_driver(struct device_driver *);
index 61c67526a656c29d05a1a1e93bba6f4e86872a14..9a19b071c573aaa7d6fc17cdaa1f86e4a1d38580 100644 (file)
 static int __must_check bus_rescan_devices_helper(struct device *dev,
                                                void *data);
 
+static struct bus_type *bus_get(struct bus_type *bus)
+{
+       return bus ? container_of(kset_get(&bus->subsys),
+                               struct bus_type, subsys) : NULL;
+}
+
+static void bus_put(struct bus_type *bus)
+{
+       kset_put(&bus->subsys);
+}
+
 static ssize_t
 drv_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
 {
@@ -78,7 +89,7 @@ static void driver_release(struct kobject * kobj)
         */
 }
 
-static struct kobj_type ktype_driver = {
+static struct kobj_type driver_ktype = {
        .sysfs_ops      = &driver_sysfs_ops,
        .release        = driver_release,
 };
@@ -122,9 +133,9 @@ static struct sysfs_ops bus_sysfs_ops = {
 int bus_create_file(struct bus_type * bus, struct bus_attribute * attr)
 {
        int error;
-       if (get_bus(bus)) {
+       if (bus_get(bus)) {
                error = sysfs_create_file(&bus->subsys.kobj, &attr->attr);
-               put_bus(bus);
+               bus_put(bus);
        } else
                error = -EINVAL;
        return error;
@@ -132,9 +143,9 @@ int bus_create_file(struct bus_type * bus, struct bus_attribute * attr)
 
 void bus_remove_file(struct bus_type * bus, struct bus_attribute * attr)
 {
-       if (get_bus(bus)) {
+       if (bus_get(bus)) {
                sysfs_remove_file(&bus->subsys.kobj, &attr->attr);
-               put_bus(bus);
+               bus_put(bus);
        }
 }
 
@@ -172,7 +183,7 @@ static int driver_helper(struct device *dev, void *data)
 static ssize_t driver_unbind(struct device_driver *drv,
                             const char *buf, size_t count)
 {
-       struct bus_type *bus = get_bus(drv->bus);
+       struct bus_type *bus = bus_get(drv->bus);
        struct device *dev;
        int err = -ENODEV;
 
@@ -186,7 +197,7 @@ static ssize_t driver_unbind(struct device_driver *drv,
                err = count;
        }
        put_device(dev);
-       put_bus(bus);
+       bus_put(bus);
        return err;
 }
 static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind);
@@ -199,7 +210,7 @@ static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind);
 static ssize_t driver_bind(struct device_driver *drv,
                           const char *buf, size_t count)
 {
-       struct bus_type *bus = get_bus(drv->bus);
+       struct bus_type *bus = bus_get(drv->bus);
        struct device *dev;
        int err = -ENODEV;
 
@@ -219,7 +230,7 @@ static ssize_t driver_bind(struct device_driver *drv,
                        err = -ENODEV;
        }
        put_device(dev);
-       put_bus(bus);
+       bus_put(bus);
        return err;
 }
 static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind);
@@ -430,7 +441,7 @@ static inline void remove_deprecated_bus_links(struct device *dev) { }
  */
 int bus_add_device(struct device * dev)
 {
-       struct bus_type * bus = get_bus(dev->bus);
+       struct bus_type * bus = bus_get(dev->bus);
        int error = 0;
 
        if (bus) {
@@ -459,7 +470,7 @@ out_subsys:
 out_id:
        device_remove_attrs(bus, dev);
 out_put:
-       put_bus(dev->bus);
+       bus_put(dev->bus);
        return error;
 }
 
@@ -509,7 +520,7 @@ void bus_remove_device(struct device * dev)
                }
                pr_debug("bus %s: remove device %s\n", dev->bus->name, dev->bus_id);
                device_release_driver(dev);
-               put_bus(dev->bus);
+               bus_put(dev->bus);
        }
 }
 
@@ -568,32 +579,29 @@ static void remove_bind_files(struct device_driver *drv)
        driver_remove_file(drv, &driver_attr_unbind);
 }
 
+static BUS_ATTR(drivers_probe, S_IWUSR, NULL, store_drivers_probe);
+static BUS_ATTR(drivers_autoprobe, S_IWUSR | S_IRUGO,
+               show_drivers_autoprobe, store_drivers_autoprobe);
+
 static int add_probe_files(struct bus_type *bus)
 {
        int retval;
 
-       bus->drivers_probe_attr.attr.name = "drivers_probe";
-       bus->drivers_probe_attr.attr.mode = S_IWUSR;
-       bus->drivers_probe_attr.store = store_drivers_probe;
-       retval = bus_create_file(bus, &bus->drivers_probe_attr);
+       retval = bus_create_file(bus, &bus_attr_drivers_probe);
        if (retval)
                goto out;
 
-       bus->drivers_autoprobe_attr.attr.name = "drivers_autoprobe";
-       bus->drivers_autoprobe_attr.attr.mode = S_IWUSR | S_IRUGO;
-       bus->drivers_autoprobe_attr.show = show_drivers_autoprobe;
-       bus->drivers_autoprobe_attr.store = store_drivers_autoprobe;
-       retval = bus_create_file(bus, &bus->drivers_autoprobe_attr);
+       retval = bus_create_file(bus, &bus_attr_drivers_autoprobe);
        if (retval)
-               bus_remove_file(bus, &bus->drivers_probe_attr);
+               bus_remove_file(bus, &bus_attr_drivers_probe);
 out:
        return retval;
 }
 
 static void remove_probe_files(struct bus_type *bus)
 {
-       bus_remove_file(bus, &bus->drivers_autoprobe_attr);
-       bus_remove_file(bus, &bus->drivers_probe_attr);
+       bus_remove_file(bus, &bus_attr_drivers_autoprobe);
+       bus_remove_file(bus, &bus_attr_drivers_probe);
 }
 #else
 static inline int add_bind_files(struct device_driver *drv) { return 0; }
@@ -602,6 +610,17 @@ static inline int add_probe_files(struct bus_type *bus) { return 0; }
 static inline void remove_probe_files(struct bus_type *bus) {}
 #endif
 
+static ssize_t driver_uevent_store(struct device_driver *drv,
+                                  const char *buf, size_t count)
+{
+       enum kobject_action action;
+
+       if (kobject_action_type(buf, count, &action) == 0)
+               kobject_uevent(&drv->kobj, action);
+       return count;
+}
+static DRIVER_ATTR(uevent, S_IWUSR, NULL, driver_uevent_store);
+
 /**
  *     bus_add_driver - Add a driver to the bus.
  *     @drv:   driver.
@@ -609,7 +628,7 @@ static inline void remove_probe_files(struct bus_type *bus) {}
  */
 int bus_add_driver(struct device_driver *drv)
 {
-       struct bus_type * bus = get_bus(drv->bus);
+       struct bus_type * bus = bus_get(drv->bus);
        int error = 0;
 
        if (!bus)
@@ -632,6 +651,11 @@ int bus_add_driver(struct device_driver *drv)
        klist_add_tail(&drv->knode_bus, &bus->klist_drivers);
        module_add_driver(drv->owner, drv);
 
+       error = driver_create_file(drv, &driver_attr_uevent);
+       if (error) {
+               printk(KERN_ERR "%s: uevent attr (%s) failed\n",
+                       __FUNCTION__, drv->name);
+       }
        error = driver_add_attrs(bus, drv);
        if (error) {
                /* How the hell do we get out of this pickle? Give up */
@@ -649,7 +673,7 @@ int bus_add_driver(struct device_driver *drv)
 out_unregister:
        kobject_unregister(&drv->kobj);
 out_put_bus:
-       put_bus(bus);
+       bus_put(bus);
        return error;
 }
 
@@ -669,12 +693,13 @@ void bus_remove_driver(struct device_driver * drv)
 
        remove_bind_files(drv);
        driver_remove_attrs(drv->bus, drv);
+       driver_remove_file(drv, &driver_attr_uevent);
        klist_remove(&drv->knode_bus);
        pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name);
        driver_detach(drv);
        module_remove_driver(drv);
        kobject_unregister(&drv->kobj);
-       put_bus(drv->bus);
+       bus_put(drv->bus);
 }
 
 
@@ -729,18 +754,6 @@ int device_reprobe(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(device_reprobe);
 
-struct bus_type *get_bus(struct bus_type *bus)
-{
-       return bus ? container_of(subsys_get(&bus->subsys),
-                               struct bus_type, subsys) : NULL;
-}
-
-void put_bus(struct bus_type * bus)
-{
-       subsys_put(&bus->subsys);
-}
-
-
 /**
  *     find_bus - locate bus by name.
  *     @name:  name of bus.
@@ -808,6 +821,17 @@ static void klist_devices_put(struct klist_node *n)
        put_device(dev);
 }
 
+static ssize_t bus_uevent_store(struct bus_type *bus,
+                               const char *buf, size_t count)
+{
+       enum kobject_action action;
+
+       if (kobject_action_type(buf, count, &action) == 0)
+               kobject_uevent(&bus->subsys.kobj, action);
+       return count;
+}
+static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store);
+
 /**
  *     bus_register - register a bus with the system.
  *     @bus:   bus.
@@ -826,11 +850,16 @@ int bus_register(struct bus_type * bus)
        if (retval)
                goto out;
 
-       subsys_set_kset(bus, bus_subsys);
+       bus->subsys.kobj.kset = &bus_subsys;
+
        retval = subsystem_register(&bus->subsys);
        if (retval)
                goto out;
 
+       retval = bus_create_file(bus, &bus_attr_uevent);
+       if (retval)
+               goto bus_uevent_fail;
+
        kobject_set_name(&bus->devices.kobj, "devices");
        bus->devices.kobj.parent = &bus->subsys.kobj;
        retval = kset_register(&bus->devices);
@@ -839,7 +868,7 @@ int bus_register(struct bus_type * bus)
 
        kobject_set_name(&bus->drivers.kobj, "drivers");
        bus->drivers.kobj.parent = &bus->subsys.kobj;
-       bus->drivers.ktype = &ktype_driver;
+       bus->drivers.ktype = &driver_ktype;
        retval = kset_register(&bus->drivers);
        if (retval)
                goto bus_drivers_fail;
@@ -866,6 +895,8 @@ bus_probe_files_fail:
 bus_drivers_fail:
        kset_unregister(&bus->devices);
 bus_devices_fail:
+       bus_remove_file(bus, &bus_attr_uevent);
+bus_uevent_fail:
        subsystem_unregister(&bus->subsys);
 out:
        return retval;
@@ -876,7 +907,7 @@ out:
  *     @bus:   bus.
  *
  *     Unregister the child subsystems and the bus itself.
- *     Finally, we call put_bus() to release the refcount
+ *     Finally, we call bus_put() to release the refcount
  */
 void bus_unregister(struct bus_type * bus)
 {
@@ -885,6 +916,7 @@ void bus_unregister(struct bus_type * bus)
        remove_probe_files(bus);
        kset_unregister(&bus->drivers);
        kset_unregister(&bus->devices);
+       bus_remove_file(bus, &bus_attr_uevent);
        subsystem_unregister(&bus->subsys);
 }
 
index 4d2222618b780f47dfa54e40246dbd9e4c8bdcc7..a863bb091e11db26e6e996dfa6fb341285d11991 100644 (file)
@@ -65,13 +65,13 @@ static struct sysfs_ops class_sysfs_ops = {
        .store  = class_attr_store,
 };
 
-static struct kobj_type ktype_class = {
+static struct kobj_type class_ktype = {
        .sysfs_ops      = &class_sysfs_ops,
        .release        = class_release,
 };
 
 /* Hotplug events for classes go to the class_obj subsys */
-static decl_subsys(class, &ktype_class, NULL);
+static decl_subsys(class, &class_ktype, NULL);
 
 
 int class_create_file(struct class * cls, const struct class_attribute * attr)
@@ -93,14 +93,14 @@ void class_remove_file(struct class * cls, const struct class_attribute * attr)
 static struct class *class_get(struct class *cls)
 {
        if (cls)
-               return container_of(subsys_get(&cls->subsys), struct class, subsys);
+               return container_of(kset_get(&cls->subsys), struct class, subsys);
        return NULL;
 }
 
 static void class_put(struct class * cls)
 {
        if (cls)
-               subsys_put(&cls->subsys);
+               kset_put(&cls->subsys);
 }
 
 
@@ -149,7 +149,7 @@ int class_register(struct class * cls)
        if (error)
                return error;
 
-       subsys_set_kset(cls, class_subsys);
+       cls->subsys.kobj.kset = &class_subsys;
 
        error = subsystem_register(&cls->subsys);
        if (!error) {
@@ -180,8 +180,7 @@ static void class_device_create_release(struct class_device *class_dev)
 
 /* needed to allow these devices to have parent class devices */
 static int class_device_create_uevent(struct class_device *class_dev,
-                                      char **envp, int num_envp,
-                                      char *buffer, int buffer_size)
+                                     struct kobj_uevent_env *env)
 {
        pr_debug("%s called for %s\n", __FUNCTION__, class_dev->class_id);
        return 0;
@@ -324,7 +323,7 @@ static void class_dev_release(struct kobject * kobj)
        }
 }
 
-static struct kobj_type ktype_class_device = {
+static struct kobj_type class_device_ktype = {
        .sysfs_ops      = &class_dev_sysfs_ops,
        .release        = class_dev_release,
 };
@@ -333,7 +332,7 @@ static int class_uevent_filter(struct kset *kset, struct kobject *kobj)
 {
        struct kobj_type *ktype = get_ktype(kobj);
 
-       if (ktype == &ktype_class_device) {
+       if (ktype == &class_device_ktype) {
                struct class_device *class_dev = to_class_dev(kobj);
                if (class_dev->class)
                        return 1;
@@ -403,64 +402,43 @@ static void remove_deprecated_class_device_links(struct class_device *cd)
 { }
 #endif
 
-static int class_uevent(struct kset *kset, struct kobject *kobj, char **envp,
-                        int num_envp, char *buffer, int buffer_size)
+static int class_uevent(struct kset *kset, struct kobject *kobj,
+                       struct kobj_uevent_env *env)
 {
        struct class_device *class_dev = to_class_dev(kobj);
        struct device *dev = class_dev->dev;
-       int i = 0;
-       int length = 0;
        int retval = 0;
 
        pr_debug("%s - name = %s\n", __FUNCTION__, class_dev->class_id);
 
        if (MAJOR(class_dev->devt)) {
-               add_uevent_var(envp, num_envp, &i,
-                              buffer, buffer_size, &length,
-                              "MAJOR=%u", MAJOR(class_dev->devt));
+               add_uevent_var(env, "MAJOR=%u", MAJOR(class_dev->devt));
 
-               add_uevent_var(envp, num_envp, &i,
-                              buffer, buffer_size, &length,
-                              "MINOR=%u", MINOR(class_dev->devt));
+               add_uevent_var(env, "MINOR=%u", MINOR(class_dev->devt));
        }
 
        if (dev) {
                const char *path = kobject_get_path(&dev->kobj, GFP_KERNEL);
                if (path) {
-                       add_uevent_var(envp, num_envp, &i,
-                                      buffer, buffer_size, &length,
-                                      "PHYSDEVPATH=%s", path);
+                       add_uevent_var(env, "PHYSDEVPATH=%s", path);
                        kfree(path);
                }
 
                if (dev->bus)
-                       add_uevent_var(envp, num_envp, &i,
-                                      buffer, buffer_size, &length,
-                                      "PHYSDEVBUS=%s", dev->bus->name);
+                       add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name);
 
                if (dev->driver)
-                       add_uevent_var(envp, num_envp, &i,
-                                      buffer, buffer_size, &length,
-                                      "PHYSDEVDRIVER=%s", dev->driver->name);
+                       add_uevent_var(env, "PHYSDEVDRIVER=%s", dev->driver->name);
        }
 
-       /* terminate, set to next free slot, shrink available space */
-       envp[i] = NULL;
-       envp = &envp[i];
-       num_envp -= i;
-       buffer = &buffer[length];
-       buffer_size -= length;
-
        if (class_dev->uevent) {
                /* have the class device specific function add its stuff */
-               retval = class_dev->uevent(class_dev, envp, num_envp,
-                                           buffer, buffer_size);
+               retval = class_dev->uevent(class_dev, env);
                if (retval)
                        pr_debug("class_dev->uevent() returned %d\n", retval);
        } else if (class_dev->class->uevent) {
                /* have the class specific function add its stuff */
-               retval = class_dev->class->uevent(class_dev, envp, num_envp,
-                                                  buffer, buffer_size);
+               retval = class_dev->class->uevent(class_dev, env);
                if (retval)
                        pr_debug("class->uevent() returned %d\n", retval);
        }
@@ -474,7 +452,7 @@ static struct kset_uevent_ops class_uevent_ops = {
        .uevent =       class_uevent,
 };
 
-static decl_subsys(class_obj, &ktype_class_device, &class_uevent_ops);
+static decl_subsys(class_obj, &class_device_ktype, &class_uevent_ops);
 
 
 static int class_device_add_attrs(struct class_device * cd)
@@ -883,7 +861,7 @@ int __init classes_init(void)
 
        /* ick, this is ugly, the things we go through to keep from showing up
         * in sysfs... */
-       subsystem_init(&class_obj_subsys);
+       kset_init(&class_obj_subsys);
        if (!class_obj_subsys.kobj.parent)
                class_obj_subsys.kobj.parent = &class_obj_subsys.kobj;
        return 0;
index ec86d6fc2360bbb3fa6286a1972a7f82f36c3699..c1343414d285e29f57fe17e089e635be20af3aed 100644 (file)
@@ -108,7 +108,7 @@ static void device_release(struct kobject * kobj)
        }
 }
 
-static struct kobj_type ktype_device = {
+static struct kobj_type device_ktype = {
        .release        = device_release,
        .sysfs_ops      = &dev_sysfs_ops,
 };
@@ -118,7 +118,7 @@ static int dev_uevent_filter(struct kset *kset, struct kobject *kobj)
 {
        struct kobj_type *ktype = get_ktype(kobj);
 
-       if (ktype == &ktype_device) {
+       if (ktype == &device_ktype) {
                struct device *dev = to_dev(kobj);
                if (dev->uevent_suppress)
                        return 0;
@@ -141,33 +141,23 @@ static const char *dev_uevent_name(struct kset *kset, struct kobject *kobj)
        return NULL;
 }
 
-static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp,
-                       int num_envp, char *buffer, int buffer_size)
+static int dev_uevent(struct kset *kset, struct kobject *kobj,
+                     struct kobj_uevent_env *env)
 {
        struct device *dev = to_dev(kobj);
-       int i = 0;
-       int length = 0;
        int retval = 0;
 
        /* add the major/minor if present */
        if (MAJOR(dev->devt)) {
-               add_uevent_var(envp, num_envp, &i,
-                              buffer, buffer_size, &length,
-                              "MAJOR=%u", MAJOR(dev->devt));
-               add_uevent_var(envp, num_envp, &i,
-                              buffer, buffer_size, &length,
-                              "MINOR=%u", MINOR(dev->devt));
+               add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt));
+               add_uevent_var(env, "MINOR=%u", MINOR(dev->devt));
        }
 
        if (dev->type && dev->type->name)
-               add_uevent_var(envp, num_envp, &i,
-                              buffer, buffer_size, &length,
-                              "DEVTYPE=%s", dev->type->name);
+               add_uevent_var(env, "DEVTYPE=%s", dev->type->name);
 
        if (dev->driver)
-               add_uevent_var(envp, num_envp, &i,
-                              buffer, buffer_size, &length,
-                              "DRIVER=%s", dev->driver->name);
+               add_uevent_var(env, "DRIVER=%s", dev->driver->name);
 
 #ifdef CONFIG_SYSFS_DEPRECATED
        if (dev->class) {
@@ -181,59 +171,43 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp,
 
                        path = kobject_get_path(&parent->kobj, GFP_KERNEL);
                        if (path) {
-                               add_uevent_var(envp, num_envp, &i,
-                                              buffer, buffer_size, &length,
-                                              "PHYSDEVPATH=%s", path);
+                               add_uevent_var(env, "PHYSDEVPATH=%s", path);
                                kfree(path);
                        }
 
-                       add_uevent_var(envp, num_envp, &i,
-                                      buffer, buffer_size, &length,
-                                      "PHYSDEVBUS=%s", parent->bus->name);
+                       add_uevent_var(env, "PHYSDEVBUS=%s", parent->bus->name);
 
                        if (parent->driver)
-                               add_uevent_var(envp, num_envp, &i,
-                                              buffer, buffer_size, &length,
-                                              "PHYSDEVDRIVER=%s", parent->driver->name);
+                               add_uevent_var(env, "PHYSDEVDRIVER=%s",
+                                              parent->driver->name);
                }
        } else if (dev->bus) {
-               add_uevent_var(envp, num_envp, &i,
-                              buffer, buffer_size, &length,
-                              "PHYSDEVBUS=%s", dev->bus->name);
+               add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name);
 
                if (dev->driver)
-                       add_uevent_var(envp, num_envp, &i,
-                                      buffer, buffer_size, &length,
-                                      "PHYSDEVDRIVER=%s", dev->driver->name);
+                       add_uevent_var(env, "PHYSDEVDRIVER=%s", dev->driver->name);
        }
 #endif
 
-       /* terminate, set to next free slot, shrink available space */
-       envp[i] = NULL;
-       envp = &envp[i];
-       num_envp -= i;
-       buffer = &buffer[length];
-       buffer_size -= length;
-
+       /* have the bus specific function add its stuff */
        if (dev->bus && dev->bus->uevent) {
-               /* have the bus specific function add its stuff */
-               retval = dev->bus->uevent(dev, envp, num_envp, buffer, buffer_size);
+               retval = dev->bus->uevent(dev, env);
                if (retval)
                        pr_debug ("%s: bus uevent() returned %d\n",
                                  __FUNCTION__, retval);
        }
 
+       /* have the class specific function add its stuff */
        if (dev->class && dev->class->dev_uevent) {
-               /* have the class specific function add its stuff */
-               retval = dev->class->dev_uevent(dev, envp, num_envp, buffer, buffer_size);
+               retval = dev->class->dev_uevent(dev, env);
                if (retval)
                        pr_debug("%s: class uevent() returned %d\n",
                                 __FUNCTION__, retval);
        }
 
+       /* have the device type specific fuction add its stuff */
        if (dev->type && dev->type->uevent) {
-               /* have the device type specific fuction add its stuff */
-               retval = dev->type->uevent(dev, envp, num_envp, buffer, buffer_size);
+               retval = dev->type->uevent(dev, env);
                if (retval)
                        pr_debug("%s: dev_type uevent() returned %d\n",
                                 __FUNCTION__, retval);
@@ -253,22 +227,18 @@ static ssize_t show_uevent(struct device *dev, struct device_attribute *attr,
 {
        struct kobject *top_kobj;
        struct kset *kset;
-       char *envp[32];
-       char *data = NULL;
-       char *pos;
+       struct kobj_uevent_env *env = NULL;
        int i;
        size_t count = 0;
        int retval;
 
        /* search the kset, the device belongs to */
        top_kobj = &dev->kobj;
-       if (!top_kobj->kset && top_kobj->parent) {
-               do {
-                       top_kobj = top_kobj->parent;
-               } while (!top_kobj->kset && top_kobj->parent);
-       }
+       while (!top_kobj->kset && top_kobj->parent)
+               top_kobj = top_kobj->parent;
        if (!top_kobj->kset)
                goto out;
+
        kset = top_kobj->kset;
        if (!kset->uevent_ops || !kset->uevent_ops->uevent)
                goto out;
@@ -278,43 +248,29 @@ static ssize_t show_uevent(struct device *dev, struct device_attribute *attr,
                if (!kset->uevent_ops->filter(kset, &dev->kobj))
                        goto out;
 
-       data = (char *)get_zeroed_page(GFP_KERNEL);
-       if (!data)
+       env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
+       if (!env)
                return -ENOMEM;
 
        /* let the kset specific function add its keys */
-       pos = data;
-       memset(envp, 0, sizeof(envp));
-       retval = kset->uevent_ops->uevent(kset, &dev->kobj,
-                                         envp, ARRAY_SIZE(envp),
-                                         pos, PAGE_SIZE);
+       retval = kset->uevent_ops->uevent(kset, &dev->kobj, env);
        if (retval)
                goto out;
 
        /* copy keys to file */
-       for (i = 0; envp[i]; i++) {
-               pos = &buf[count];
-               count += sprintf(pos, "%s\n", envp[i]);
-       }
+       for (i = 0; i < env->envp_idx; i++)
+               count += sprintf(&buf[count], "%s\n", env->envp[i]);
 out:
-       free_page((unsigned long)data);
+       kfree(env);
        return count;
 }
 
 static ssize_t store_uevent(struct device *dev, struct device_attribute *attr,
                            const char *buf, size_t count)
 {
-       size_t len = count;
        enum kobject_action action;
 
-       if (len && buf[len-1] == '\n')
-               len--;
-
-       for (action = 0; action < KOBJ_MAX; action++) {
-               if (strncmp(kobject_actions[action], buf, len) != 0)
-                       continue;
-               if (kobject_actions[action][len] != '\0')
-                       continue;
+       if (kobject_action_type(buf, count, &action) == 0) {
                kobject_uevent(&dev->kobj, action);
                goto out;
        }
@@ -449,7 +405,7 @@ static struct device_attribute devt_attr =
  *     devices_subsys - structure to be registered with kobject core.
  */
 
-decl_subsys(devices, &ktype_device, &device_uevent_ops);
+decl_subsys(devices, &device_ktype, &device_uevent_ops);
 
 
 /**
index b24efd4e3e3de2c1f681c68936c52eca839cd8ea..0295855a3eefe58ddf48bc9061123e3177be67f8 100644 (file)
@@ -88,19 +88,14 @@ static CLASS_ATTR(timeout, 0644, firmware_timeout_show, firmware_timeout_store);
 
 static void fw_dev_release(struct device *dev);
 
-static int firmware_uevent(struct device *dev, char **envp, int num_envp,
-                          char *buffer, int buffer_size)
+static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        struct firmware_priv *fw_priv = dev_get_drvdata(dev);
-       int i = 0, len = 0;
 
-       if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
-                          "FIRMWARE=%s", fw_priv->fw_id))
+       if (add_uevent_var(env, "FIRMWARE=%s", fw_priv->fw_id))
                return -ENOMEM;
-       if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
-                          "TIMEOUT=%i", loading_timeout))
+       if (add_uevent_var(env, "TIMEOUT=%i", loading_timeout))
                return -ENOMEM;
-       envp[i] = NULL;
 
        return 0;
 }
@@ -297,8 +292,7 @@ firmware_class_timeout(u_long data)
 
 static inline void fw_setup_device_id(struct device *f_dev, struct device *dev)
 {
-       /* XXX warning we should watch out for name collisions */
-       strlcpy(f_dev->bus_id, dev->bus_id, BUS_ID_SIZE);
+       snprintf(f_dev->bus_id, BUS_ID_SIZE, "firmware-%s", dev->bus_id);
 }
 
 static int fw_register_device(struct device **dev_p, const char *fw_name,
index 74b96795d2f58606ae5d048618405c6e73b53db9..7a1390cd6aad67f407d750a050caa192a9ab8f21 100644 (file)
@@ -34,8 +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 kobject *kobj, char **envp,
-                       int num_envp, char *buffer, int buffer_size)
+static int memory_uevent(struct kset *kset, struct kobject *obj, struct kobj_uevent_env *env)
 {
        int retval = 0;
 
index 869ff8c001460929a6b5721129b434c9cd50ef4f..fb56092414821645342071f5c0da32ef2a486b4b 100644 (file)
@@ -160,13 +160,8 @@ static void platform_device_release(struct device *dev)
  *
  *     Create a platform device object which can have other objects attached
  *     to it, and which will have attached objects freed when it is released.
- *
- *     This device will be marked as not supporting hotpluggable drivers; no
- *     device add/remove uevents will be generated.  In the unusual case that
- *     the device isn't being dynamically allocated as a legacy "probe the
- *     hardware" driver, infrastructure code should reverse this marking.
  */
-struct platform_device *platform_device_alloc(const char *name, unsigned int id)
+struct platform_device *platform_device_alloc(const char *name, int id)
 {
        struct platform_object *pa;
 
@@ -177,12 +172,6 @@ struct platform_device *platform_device_alloc(const char *name, unsigned int id)
                pa->pdev.id = id;
                device_initialize(&pa->pdev.dev);
                pa->pdev.dev.release = platform_device_release;
-
-               /* prevent hotplug "modprobe $(MODALIAS)" from causing trouble in
-                * legacy probe-the-hardware drivers, which don't properly split
-                * out device enumeration logic from drivers.
-                */
-               pa->pdev.dev.uevent_suppress = 1;
        }
 
        return pa ? &pa->pdev : NULL;
@@ -256,7 +245,8 @@ int platform_device_add(struct platform_device *pdev)
        pdev->dev.bus = &platform_bus_type;
 
        if (pdev->id != -1)
-               snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%u", pdev->name, pdev->id);
+               snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%d", pdev->name,
+                        pdev->id);
        else
                strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE);
 
@@ -370,7 +360,7 @@ EXPORT_SYMBOL_GPL(platform_device_unregister);
  *     the Linux driver model.  In particular, when such drivers are built
  *     as modules, they can't be "hotplugged".
  */
-struct platform_device *platform_device_register_simple(char *name, unsigned int id,
+struct platform_device *platform_device_register_simple(char *name, int id,
                                                        struct resource *res, unsigned int num)
 {
        struct platform_device *pdev;
@@ -530,7 +520,7 @@ static ssize_t
 modalias_show(struct device *dev, struct device_attribute *a, char *buf)
 {
        struct platform_device  *pdev = to_platform_device(dev);
-       int len = snprintf(buf, PAGE_SIZE, "%s\n", pdev->name);
+       int len = snprintf(buf, PAGE_SIZE, "platform:%s\n", pdev->name);
 
        return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
 }
@@ -540,13 +530,11 @@ static struct device_attribute platform_dev_attrs[] = {
        __ATTR_NULL,
 };
 
-static int platform_uevent(struct device *dev, char **envp, int num_envp,
-               char *buffer, int buffer_size)
+static int platform_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        struct platform_device  *pdev = to_platform_device(dev);
 
-       envp[0] = buffer;
-       snprintf(buffer, buffer_size, "MODALIAS=%s", pdev->name);
+       add_uevent_var(env, "MODALIAS=platform:%s", pdev->name);
        return 0;
 }
 
index 9caeaea753a3e00623fae4c41d72ffceaef1643c..a803733c839ec9119abbc9f35004e184f4d0a2dd 100644 (file)
@@ -1,5 +1,5 @@
 obj-y                  := shutdown.o
-obj-$(CONFIG_PM_SLEEP) += main.o suspend.o resume.o sysfs.o
+obj-$(CONFIG_PM_SLEEP) += main.o sysfs.o
 obj-$(CONFIG_PM_TRACE) += trace.o
 
 ifeq ($(CONFIG_DEBUG_DRIVER),y)
index eb9f38d0aa58f3d13928923627d66512e3255c38..0ab4ab21f564378a20c3855c2170e01ffec3f3a2 100644 (file)
  */
 
 #include <linux/device.h>
+#include <linux/kallsyms.h>
 #include <linux/mutex.h>
+#include <linux/pm.h>
+#include <linux/resume-trace.h>
 
+#include "../base.h"
 #include "power.h"
 
 LIST_HEAD(dpm_active);
-LIST_HEAD(dpm_off);
-LIST_HEAD(dpm_off_irq);
+static LIST_HEAD(dpm_off);
+static LIST_HEAD(dpm_off_irq);
 
-DEFINE_MUTEX(dpm_mtx);
-DEFINE_MUTEX(dpm_list_mtx);
+static DEFINE_MUTEX(dpm_mtx);
+static DEFINE_MUTEX(dpm_list_mtx);
 
 int (*platform_enable_wakeup)(struct device *dev, int is_on);
 
+
 int device_pm_add(struct device *dev)
 {
        int error;
@@ -61,3 +66,334 @@ void device_pm_remove(struct device *dev)
 }
 
 
+/*------------------------- Resume routines -------------------------*/
+
+/**
+ *     resume_device - Restore state for one device.
+ *     @dev:   Device.
+ *
+ */
+
+static int resume_device(struct device * dev)
+{
+       int error = 0;
+
+       TRACE_DEVICE(dev);
+       TRACE_RESUME(0);
+
+       down(&dev->sem);
+
+       if (dev->bus && dev->bus->resume) {
+               dev_dbg(dev,"resuming\n");
+               error = dev->bus->resume(dev);
+       }
+
+       if (!error && dev->type && dev->type->resume) {
+               dev_dbg(dev,"resuming\n");
+               error = dev->type->resume(dev);
+       }
+
+       if (!error && dev->class && dev->class->resume) {
+               dev_dbg(dev,"class resume\n");
+               error = dev->class->resume(dev);
+       }
+
+       up(&dev->sem);
+
+       TRACE_RESUME(error);
+       return error;
+}
+
+
+static int resume_device_early(struct device * dev)
+{
+       int error = 0;
+
+       TRACE_DEVICE(dev);
+       TRACE_RESUME(0);
+       if (dev->bus && dev->bus->resume_early) {
+               dev_dbg(dev,"EARLY resume\n");
+               error = dev->bus->resume_early(dev);
+       }
+       TRACE_RESUME(error);
+       return error;
+}
+
+/*
+ * Resume the devices that have either not gone through
+ * the late suspend, or that did go through it but also
+ * went through the early resume
+ */
+static void dpm_resume(void)
+{
+       mutex_lock(&dpm_list_mtx);
+       while(!list_empty(&dpm_off)) {
+               struct list_head * entry = dpm_off.next;
+               struct device * dev = to_device(entry);
+
+               get_device(dev);
+               list_move_tail(entry, &dpm_active);
+
+               mutex_unlock(&dpm_list_mtx);
+               resume_device(dev);
+               mutex_lock(&dpm_list_mtx);
+               put_device(dev);
+       }
+       mutex_unlock(&dpm_list_mtx);
+}
+
+
+/**
+ *     device_resume - Restore state of each device in system.
+ *
+ *     Walk the dpm_off list, remove each entry, resume the device,
+ *     then add it to the dpm_active list.
+ */
+
+void device_resume(void)
+{
+       might_sleep();
+       mutex_lock(&dpm_mtx);
+       dpm_resume();
+       mutex_unlock(&dpm_mtx);
+}
+
+EXPORT_SYMBOL_GPL(device_resume);
+
+
+/**
+ *     dpm_power_up - Power on some devices.
+ *
+ *     Walk the dpm_off_irq list and power each device up. This
+ *     is used for devices that required they be powered down with
+ *     interrupts disabled. As devices are powered on, they are moved
+ *     to the dpm_active list.
+ *
+ *     Interrupts must be disabled when calling this.
+ */
+
+static void dpm_power_up(void)
+{
+       while(!list_empty(&dpm_off_irq)) {
+               struct list_head * entry = dpm_off_irq.next;
+               struct device * dev = to_device(entry);
+
+               list_move_tail(entry, &dpm_off);
+               resume_device_early(dev);
+       }
+}
+
+
+/**
+ *     device_power_up - Turn on all devices that need special attention.
+ *
+ *     Power on system devices then devices that required we shut them down
+ *     with interrupts disabled.
+ *     Called with interrupts disabled.
+ */
+
+void device_power_up(void)
+{
+       sysdev_resume();
+       dpm_power_up();
+}
+
+EXPORT_SYMBOL_GPL(device_power_up);
+
+
+/*------------------------- Suspend routines -------------------------*/
+
+/*
+ * The entries in the dpm_active list are in a depth first order, simply
+ * because children are guaranteed to be discovered after parents, and
+ * are inserted at the back of the list on discovery.
+ *
+ * All list on the suspend path are done in reverse order, so we operate
+ * on the leaves of the device tree (or forests, depending on how you want
+ * to look at it ;) first. As nodes are removed from the back of the list,
+ * they are inserted into the front of their destintation lists.
+ *
+ * Things are the reverse on the resume path - iterations are done in
+ * forward order, and nodes are inserted at the back of their destination
+ * lists. This way, the ancestors will be accessed before their descendents.
+ */
+
+static inline char *suspend_verb(u32 event)
+{
+       switch (event) {
+       case PM_EVENT_SUSPEND:  return "suspend";
+       case PM_EVENT_FREEZE:   return "freeze";
+       case PM_EVENT_PRETHAW:  return "prethaw";
+       default:                return "(unknown suspend event)";
+       }
+}
+
+
+static void
+suspend_device_dbg(struct device *dev, pm_message_t state, char *info)
+{
+       dev_dbg(dev, "%s%s%s\n", info, suspend_verb(state.event),
+               ((state.event == PM_EVENT_SUSPEND) && device_may_wakeup(dev)) ?
+               ", may wakeup" : "");
+}
+
+/**
+ *     suspend_device - Save state of one device.
+ *     @dev:   Device.
+ *     @state: Power state device is entering.
+ */
+
+static int suspend_device(struct device * dev, pm_message_t state)
+{
+       int error = 0;
+
+       down(&dev->sem);
+       if (dev->power.power_state.event) {
+               dev_dbg(dev, "PM: suspend %d-->%d\n",
+                       dev->power.power_state.event, state.event);
+       }
+
+       if (dev->class && dev->class->suspend) {
+               suspend_device_dbg(dev, state, "class ");
+               error = dev->class->suspend(dev, state);
+               suspend_report_result(dev->class->suspend, error);
+       }
+
+       if (!error && dev->type && dev->type->suspend) {
+               suspend_device_dbg(dev, state, "type ");
+               error = dev->type->suspend(dev, state);
+               suspend_report_result(dev->type->suspend, error);
+       }
+
+       if (!error && dev->bus && dev->bus->suspend) {
+               suspend_device_dbg(dev, state, "");
+               error = dev->bus->suspend(dev, state);
+               suspend_report_result(dev->bus->suspend, error);
+       }
+       up(&dev->sem);
+       return error;
+}
+
+
+/*
+ * This is called with interrupts off, only a single CPU
+ * running. We can't acquire a mutex or semaphore (and we don't
+ * need the protection)
+ */
+static int suspend_device_late(struct device *dev, pm_message_t state)
+{
+       int error = 0;
+
+       if (dev->bus && dev->bus->suspend_late) {
+               suspend_device_dbg(dev, state, "LATE ");
+               error = dev->bus->suspend_late(dev, state);
+               suspend_report_result(dev->bus->suspend_late, error);
+       }
+       return error;
+}
+
+/**
+ *     device_suspend - Save state and stop all devices in system.
+ *     @state:         Power state to put each device in.
+ *
+ *     Walk the dpm_active list, call ->suspend() for each device, and move
+ *     it to the dpm_off list.
+ *
+ *     (For historical reasons, if it returns -EAGAIN, that used to mean
+ *     that the device would be called again with interrupts disabled.
+ *     These days, we use the "suspend_late()" callback for that, so we
+ *     print a warning and consider it an error).
+ *
+ *     If we get a different error, try and back out.
+ *
+ *     If we hit a failure with any of the devices, call device_resume()
+ *     above to bring the suspended devices back to life.
+ *
+ */
+
+int device_suspend(pm_message_t state)
+{
+       int error = 0;
+
+       might_sleep();
+       mutex_lock(&dpm_mtx);
+       mutex_lock(&dpm_list_mtx);
+       while (!list_empty(&dpm_active) && error == 0) {
+               struct list_head * entry = dpm_active.prev;
+               struct device * dev = to_device(entry);
+
+               get_device(dev);
+               mutex_unlock(&dpm_list_mtx);
+
+               error = suspend_device(dev, state);
+
+               mutex_lock(&dpm_list_mtx);
+
+               /* Check if the device got removed */
+               if (!list_empty(&dev->power.entry)) {
+                       /* Move it to the dpm_off list */
+                       if (!error)
+                               list_move(&dev->power.entry, &dpm_off);
+               }
+               if (error)
+                       printk(KERN_ERR "Could not suspend device %s: "
+                               "error %d%s\n",
+                               kobject_name(&dev->kobj), error,
+                               error == -EAGAIN ? " (please convert to suspend_late)" : "");
+               put_device(dev);
+       }
+       mutex_unlock(&dpm_list_mtx);
+       if (error)
+               dpm_resume();
+
+       mutex_unlock(&dpm_mtx);
+       return error;
+}
+
+EXPORT_SYMBOL_GPL(device_suspend);
+
+/**
+ *     device_power_down - Shut down special devices.
+ *     @state:         Power state to enter.
+ *
+ *     Walk the dpm_off_irq list, calling ->power_down() for each device that
+ *     couldn't power down the device with interrupts enabled. When we're
+ *     done, power down system devices.
+ */
+
+int device_power_down(pm_message_t state)
+{
+       int error = 0;
+       struct device * dev;
+
+       while (!list_empty(&dpm_off)) {
+               struct list_head * entry = dpm_off.prev;
+
+               dev = to_device(entry);
+               error = suspend_device_late(dev, state);
+               if (error)
+                       goto Error;
+               list_move(&dev->power.entry, &dpm_off_irq);
+       }
+
+       error = sysdev_suspend(state);
+ Done:
+       return error;
+ Error:
+       printk(KERN_ERR "Could not power down device %s: "
+               "error %d\n", kobject_name(&dev->kobj), error);
+       dpm_power_up();
+       goto Done;
+}
+
+EXPORT_SYMBOL_GPL(device_power_down);
+
+void __suspend_report_result(const char *function, void *fn, int ret)
+{
+       if (ret) {
+               printk(KERN_ERR "%s(): ", function);
+               print_fn_descriptor_symbol("%s() returns ", (unsigned long)fn);
+               printk("%d\n", ret);
+       }
+}
+EXPORT_SYMBOL_GPL(__suspend_report_result);
index 8ba0830cbc03fa6fe50d8bc27be7b5c3e770259c..5c4efd493fa503919b787ed6e5f6d3a4747282c5 100644 (file)
@@ -11,32 +11,11 @@ extern void device_shutdown(void);
  * main.c
  */
 
-/*
- * Used to synchronize global power management operations.
- */
-extern struct mutex dpm_mtx;
-
-/*
- * Used to serialize changes to the dpm_* lists.
- */
-extern struct mutex dpm_list_mtx;
-
-/*
- * The PM lists.
- */
-extern struct list_head dpm_active;
-extern struct list_head dpm_off;
-extern struct list_head dpm_off_irq;
-
-
-static inline struct dev_pm_info * to_pm_info(struct list_head * entry)
-{
-       return container_of(entry, struct dev_pm_info, entry);
-}
+extern struct list_head dpm_active;    /* The active device list */
 
 static inline struct device * to_device(struct list_head * entry)
 {
-       return container_of(to_pm_info(entry), struct device, power);
+       return container_of(entry, struct device, power.entry);
 }
 
 extern int device_pm_add(struct device *);
@@ -49,19 +28,6 @@ extern void device_pm_remove(struct device *);
 extern int dpm_sysfs_add(struct device *);
 extern void dpm_sysfs_remove(struct device *);
 
-/*
- * resume.c
- */
-
-extern void dpm_resume(void);
-extern void dpm_power_up(void);
-extern int resume_device(struct device *);
-
-/*
- * suspend.c
- */
-extern int suspend_device(struct device *, pm_message_t);
-
 #else /* CONFIG_PM_SLEEP */
 
 
diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c
deleted file mode 100644 (file)
index 00fd84a..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * resume.c - Functions for waking devices up.
- *
- * Copyright (c) 2003 Patrick Mochel
- * Copyright (c) 2003 Open Source Development Labs
- *
- * This file is released under the GPLv2
- *
- */
-
-#include <linux/device.h>
-#include <linux/resume-trace.h>
-#include "../base.h"
-#include "power.h"
-
-
-/**
- *     resume_device - Restore state for one device.
- *     @dev:   Device.
- *
- */
-
-int resume_device(struct device * dev)
-{
-       int error = 0;
-
-       TRACE_DEVICE(dev);
-       TRACE_RESUME(0);
-
-       down(&dev->sem);
-
-       if (dev->bus && dev->bus->resume) {
-               dev_dbg(dev,"resuming\n");
-               error = dev->bus->resume(dev);
-       }
-
-       if (!error && dev->type && dev->type->resume) {
-               dev_dbg(dev,"resuming\n");
-               error = dev->type->resume(dev);
-       }
-
-       if (!error && dev->class && dev->class->resume) {
-               dev_dbg(dev,"class resume\n");
-               error = dev->class->resume(dev);
-       }
-
-       up(&dev->sem);
-
-       TRACE_RESUME(error);
-       return error;
-}
-
-
-static int resume_device_early(struct device * dev)
-{
-       int error = 0;
-
-       TRACE_DEVICE(dev);
-       TRACE_RESUME(0);
-       if (dev->bus && dev->bus->resume_early) {
-               dev_dbg(dev,"EARLY resume\n");
-               error = dev->bus->resume_early(dev);
-       }
-       TRACE_RESUME(error);
-       return error;
-}
-
-/*
- * Resume the devices that have either not gone through
- * the late suspend, or that did go through it but also
- * went through the early resume
- */
-void dpm_resume(void)
-{
-       mutex_lock(&dpm_list_mtx);
-       while(!list_empty(&dpm_off)) {
-               struct list_head * entry = dpm_off.next;
-               struct device * dev = to_device(entry);
-
-               get_device(dev);
-               list_move_tail(entry, &dpm_active);
-
-               mutex_unlock(&dpm_list_mtx);
-               resume_device(dev);
-               mutex_lock(&dpm_list_mtx);
-               put_device(dev);
-       }
-       mutex_unlock(&dpm_list_mtx);
-}
-
-
-/**
- *     device_resume - Restore state of each device in system.
- *
- *     Walk the dpm_off list, remove each entry, resume the device,
- *     then add it to the dpm_active list.
- */
-
-void device_resume(void)
-{
-       might_sleep();
-       mutex_lock(&dpm_mtx);
-       dpm_resume();
-       mutex_unlock(&dpm_mtx);
-}
-
-EXPORT_SYMBOL_GPL(device_resume);
-
-
-/**
- *     dpm_power_up - Power on some devices.
- *
- *     Walk the dpm_off_irq list and power each device up. This
- *     is used for devices that required they be powered down with
- *     interrupts disabled. As devices are powered on, they are moved
- *     to the dpm_active list.
- *
- *     Interrupts must be disabled when calling this.
- */
-
-void dpm_power_up(void)
-{
-       while(!list_empty(&dpm_off_irq)) {
-               struct list_head * entry = dpm_off_irq.next;
-               struct device * dev = to_device(entry);
-
-               list_move_tail(entry, &dpm_off);
-               resume_device_early(dev);
-       }
-}
-
-
-/**
- *     device_power_up - Turn on all devices that need special attention.
- *
- *     Power on system devices then devices that required we shut them down
- *     with interrupts disabled.
- *     Called with interrupts disabled.
- */
-
-void device_power_up(void)
-{
-       sysdev_resume();
-       dpm_power_up();
-}
-
-EXPORT_SYMBOL_GPL(device_power_up);
-
-
diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c
deleted file mode 100644 (file)
index 26df9b2..0000000
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * suspend.c - Functions for putting devices to sleep.
- *
- * Copyright (c) 2003 Patrick Mochel
- * Copyright (c) 2003 Open Source Development Labs
- *
- * This file is released under the GPLv2
- *
- */
-
-#include <linux/device.h>
-#include <linux/kallsyms.h>
-#include <linux/pm.h>
-#include "../base.h"
-#include "power.h"
-
-/*
- * The entries in the dpm_active list are in a depth first order, simply
- * because children are guaranteed to be discovered after parents, and
- * are inserted at the back of the list on discovery.
- *
- * All list on the suspend path are done in reverse order, so we operate
- * on the leaves of the device tree (or forests, depending on how you want
- * to look at it ;) first. As nodes are removed from the back of the list,
- * they are inserted into the front of their destintation lists.
- *
- * Things are the reverse on the resume path - iterations are done in
- * forward order, and nodes are inserted at the back of their destination
- * lists. This way, the ancestors will be accessed before their descendents.
- */
-
-static inline char *suspend_verb(u32 event)
-{
-       switch (event) {
-       case PM_EVENT_SUSPEND:  return "suspend";
-       case PM_EVENT_FREEZE:   return "freeze";
-       case PM_EVENT_PRETHAW:  return "prethaw";
-       default:                return "(unknown suspend event)";
-       }
-}
-
-
-static void
-suspend_device_dbg(struct device *dev, pm_message_t state, char *info)
-{
-       dev_dbg(dev, "%s%s%s\n", info, suspend_verb(state.event),
-               ((state.event == PM_EVENT_SUSPEND) && device_may_wakeup(dev)) ?
-               ", may wakeup" : "");
-}
-
-/**
- *     suspend_device - Save state of one device.
- *     @dev:   Device.
- *     @state: Power state device is entering.
- */
-
-int suspend_device(struct device * dev, pm_message_t state)
-{
-       int error = 0;
-
-       down(&dev->sem);
-       if (dev->power.power_state.event) {
-               dev_dbg(dev, "PM: suspend %d-->%d\n",
-                       dev->power.power_state.event, state.event);
-       }
-
-       if (dev->class && dev->class->suspend) {
-               suspend_device_dbg(dev, state, "class ");
-               error = dev->class->suspend(dev, state);
-               suspend_report_result(dev->class->suspend, error);
-       }
-
-       if (!error && dev->type && dev->type->suspend) {
-               suspend_device_dbg(dev, state, "type ");
-               error = dev->type->suspend(dev, state);
-               suspend_report_result(dev->type->suspend, error);
-       }
-
-       if (!error && dev->bus && dev->bus->suspend) {
-               suspend_device_dbg(dev, state, "");
-               error = dev->bus->suspend(dev, state);
-               suspend_report_result(dev->bus->suspend, error);
-       }
-       up(&dev->sem);
-       return error;
-}
-
-
-/*
- * This is called with interrupts off, only a single CPU
- * running. We can't acquire a mutex or semaphore (and we don't
- * need the protection)
- */
-static int suspend_device_late(struct device *dev, pm_message_t state)
-{
-       int error = 0;
-
-       if (dev->bus && dev->bus->suspend_late) {
-               suspend_device_dbg(dev, state, "LATE ");
-               error = dev->bus->suspend_late(dev, state);
-               suspend_report_result(dev->bus->suspend_late, error);
-       }
-       return error;
-}
-
-/**
- *     device_suspend - Save state and stop all devices in system.
- *     @state:         Power state to put each device in.
- *
- *     Walk the dpm_active list, call ->suspend() for each device, and move
- *     it to the dpm_off list.
- *
- *     (For historical reasons, if it returns -EAGAIN, that used to mean
- *     that the device would be called again with interrupts disabled.
- *     These days, we use the "suspend_late()" callback for that, so we
- *     print a warning and consider it an error).
- *
- *     If we get a different error, try and back out.
- *
- *     If we hit a failure with any of the devices, call device_resume()
- *     above to bring the suspended devices back to life.
- *
- */
-
-int device_suspend(pm_message_t state)
-{
-       int error = 0;
-
-       might_sleep();
-       mutex_lock(&dpm_mtx);
-       mutex_lock(&dpm_list_mtx);
-       while (!list_empty(&dpm_active) && error == 0) {
-               struct list_head * entry = dpm_active.prev;
-               struct device * dev = to_device(entry);
-
-               get_device(dev);
-               mutex_unlock(&dpm_list_mtx);
-
-               error = suspend_device(dev, state);
-
-               mutex_lock(&dpm_list_mtx);
-
-               /* Check if the device got removed */
-               if (!list_empty(&dev->power.entry)) {
-                       /* Move it to the dpm_off list */
-                       if (!error)
-                               list_move(&dev->power.entry, &dpm_off);
-               }
-               if (error)
-                       printk(KERN_ERR "Could not suspend device %s: "
-                               "error %d%s\n",
-                               kobject_name(&dev->kobj), error,
-                               error == -EAGAIN ? " (please convert to suspend_late)" : "");
-               put_device(dev);
-       }
-       mutex_unlock(&dpm_list_mtx);
-       if (error)
-               dpm_resume();
-
-       mutex_unlock(&dpm_mtx);
-       return error;
-}
-
-EXPORT_SYMBOL_GPL(device_suspend);
-
-/**
- *     device_power_down - Shut down special devices.
- *     @state:         Power state to enter.
- *
- *     Walk the dpm_off_irq list, calling ->power_down() for each device that
- *     couldn't power down the device with interrupts enabled. When we're
- *     done, power down system devices.
- */
-
-int device_power_down(pm_message_t state)
-{
-       int error = 0;
-       struct device * dev;
-
-       while (!list_empty(&dpm_off)) {
-               struct list_head * entry = dpm_off.prev;
-
-               dev = to_device(entry);
-               error = suspend_device_late(dev, state);
-               if (error)
-                       goto Error;
-               list_move(&dev->power.entry, &dpm_off_irq);
-       }
-
-       error = sysdev_suspend(state);
- Done:
-       return error;
- Error:
-       printk(KERN_ERR "Could not power down device %s: "
-               "error %d\n", kobject_name(&dev->kobj), error);
-       dpm_power_up();
-       goto Done;
-}
-
-EXPORT_SYMBOL_GPL(device_power_down);
-
-void __suspend_report_result(const char *function, void *fn, int ret)
-{
-       if (ret) {
-               printk(KERN_ERR "%s(): ", function);
-               print_fn_descriptor_symbol("%s() returns ", (unsigned long)fn);
-               printk("%d\n", ret);
-       }
-}
-EXPORT_SYMBOL_GPL(__suspend_report_result);
index 18febe26caa1c3640fc9d4df27e6a66775b4665f..ac7ff6d0c6e5c34460cfd1fcf4d76678b3e0533f 100644 (file)
@@ -139,7 +139,7 @@ int sysdev_class_register(struct sysdev_class * cls)
                 kobject_name(&cls->kset.kobj));
        INIT_LIST_HEAD(&cls->drivers);
        cls->kset.kobj.parent = &system_subsys.kobj;
-       kset_set_kset_s(cls, system_subsys);
+       cls->kset.kobj.kset = &system_subsys;
        return kset_register(&cls->kset);
 }
 
@@ -153,25 +153,22 @@ void sysdev_class_unregister(struct sysdev_class * cls)
 EXPORT_SYMBOL_GPL(sysdev_class_register);
 EXPORT_SYMBOL_GPL(sysdev_class_unregister);
 
-
-static LIST_HEAD(sysdev_drivers);
 static DEFINE_MUTEX(sysdev_drivers_lock);
 
 /**
  *     sysdev_driver_register - Register auxillary driver
- *     @cls:   Device class driver belongs to.
+ *     @cls:   Device class driver belongs to.
  *     @drv:   Driver.
  *
- *     If @cls is valid, then @drv is inserted into @cls->drivers to be
+ *     @drv is inserted into @cls->drivers to be
  *     called on each operation on devices of that class. The refcount
  *     of @cls is incremented.
- *     Otherwise, @drv is inserted into sysdev_drivers, and called for
- *     each device.
  */
 
-int sysdev_driver_register(struct sysdev_class * cls,
-                          struct sysdev_driver * drv)
+int sysdev_driver_register(struct sysdev_class *cls, struct sysdev_driver *drv)
 {
+       int err = 0;
+
        mutex_lock(&sysdev_drivers_lock);
        if (cls && kset_get(&cls->kset)) {
                list_add_tail(&drv->entry, &cls->drivers);
@@ -182,10 +179,13 @@ int sysdev_driver_register(struct sysdev_class * cls,
                        list_for_each_entry(dev, &cls->kset.list, kobj.entry)
                                drv->add(dev);
                }
-       } else
-               list_add_tail(&drv->entry, &sysdev_drivers);
+       } else {
+               err = -EINVAL;
+               printk(KERN_ERR "%s: invalid device class\n", __FUNCTION__);
+               WARN_ON(1);
+       }
        mutex_unlock(&sysdev_drivers_lock);
-       return 0;
+       return err;
 }
 
 
@@ -251,12 +251,6 @@ int sysdev_register(struct sys_device * sysdev)
                 * code that should have called us.
                 */
 
-               /* Notify global drivers */
-               list_for_each_entry(drv, &sysdev_drivers, entry) {
-                       if (drv->add)
-                               drv->add(sysdev);
-               }
-
                /* Notify class auxillary drivers */
                list_for_each_entry(drv, &cls->drivers, entry) {
                        if (drv->add)
@@ -272,11 +266,6 @@ void sysdev_unregister(struct sys_device * sysdev)
        struct sysdev_driver * drv;
 
        mutex_lock(&sysdev_drivers_lock);
-       list_for_each_entry(drv, &sysdev_drivers, entry) {
-               if (drv->remove)
-                       drv->remove(sysdev);
-       }
-
        list_for_each_entry(drv, &sysdev->cls->drivers, entry) {
                if (drv->remove)
                        drv->remove(sysdev);
@@ -293,7 +282,7 @@ void sysdev_unregister(struct sys_device * sysdev)
  *
  *     Loop over each class of system devices, and the devices in each
  *     of those classes. For each device, we call the shutdown method for
- *     each driver registered for the device - the globals, the auxillaries,
+ *     each driver registered for the device - the auxillaries,
  *     and the class driver.
  *
  *     Note: The list is iterated in reverse order, so that we shut down
@@ -320,13 +309,7 @@ void sysdev_shutdown(void)
                        struct sysdev_driver * drv;
                        pr_debug(" %s\n", kobject_name(&sysdev->kobj));
 
-                       /* Call global drivers first. */
-                       list_for_each_entry(drv, &sysdev_drivers, entry) {
-                               if (drv->shutdown)
-                                       drv->shutdown(sysdev);
-                       }
-
-                       /* Call auxillary drivers next. */
+                       /* Call auxillary drivers first */
                        list_for_each_entry(drv, &cls->drivers, entry) {
                                if (drv->shutdown)
                                        drv->shutdown(sysdev);
@@ -354,12 +337,6 @@ static void __sysdev_resume(struct sys_device *dev)
                if (drv->resume)
                        drv->resume(dev);
        }
-
-       /* Call global drivers. */
-       list_for_each_entry(drv, &sysdev_drivers, entry) {
-               if (drv->resume)
-                       drv->resume(dev);
-       }
 }
 
 /**
@@ -393,16 +370,7 @@ int sysdev_suspend(pm_message_t state)
                list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) {
                        pr_debug(" %s\n", kobject_name(&sysdev->kobj));
 
-                       /* Call global drivers first. */
-                       list_for_each_entry(drv, &sysdev_drivers, entry) {
-                               if (drv->suspend) {
-                                       ret = drv->suspend(sysdev, state);
-                                       if (ret)
-                                               goto gbl_driver;
-                               }
-                       }
-
-                       /* Call auxillary drivers next. */
+                       /* Call auxillary drivers first */
                        list_for_each_entry(drv, &cls->drivers, entry) {
                                if (drv->suspend) {
                                        ret = drv->suspend(sysdev, state);
@@ -436,18 +404,7 @@ aux_driver:
                if (err_drv->resume)
                        err_drv->resume(sysdev);
        }
-       drv = NULL;
 
-gbl_driver:
-       if (drv)
-               printk(KERN_ERR "sysdev driver suspend failed for %s\n",
-                               kobject_name(&sysdev->kobj));
-       list_for_each_entry(err_drv, &sysdev_drivers, entry) {
-               if (err_drv == drv)
-                       break;
-               if (err_drv->resume)
-                       err_drv->resume(sysdev);
-       }
        /* resume other sysdevs in current class */
        list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) {
                if (err_dev == sysdev)
index 4245b7f80a49de11d2709ffd66a23f7d371137a3..ca4d7f0d09b79af954b814ce11299b4e69e996b8 100644 (file)
@@ -361,8 +361,7 @@ config BLK_DEV_RAM_SIZE
        default "4096"
        help
          The default value is 4096 kilobytes. Only change this if you know
-         what are you doing. If you are using IBM S/390, then set this to
-         8192.
+         what are you doing.
 
 config BLK_DEV_RAM_BLOCKSIZE
        int "Default RAM disk block size (bytes)"
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 9b8278e1f4f85ba0363ef0e65f7b41d04e84f0a6..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;
@@ -513,7 +513,7 @@ static int __init dsp56k_init_driver(void)
                err = PTR_ERR(dsp56k_class);
                goto out_chrdev;
        }
-       class_device_create(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), NULL, "dsp56k");
+       device_create(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), "dsp56k");
 
        printk(banner);
        goto out;
@@ -527,7 +527,7 @@ module_init(dsp56k_init_driver);
 
 static void __exit dsp56k_cleanup_driver(void)
 {
-       class_device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0));
+       device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0));
        class_destroy(dsp56k_class);
        unregister_chrdev(DSP56K_MAJOR, "dsp56k");
 }
index 8d74b8745e6010712f15faabef630b8103ac4c61..bd94d5f9e62b62191b10f3525c43819d1ff2882f 100644 (file)
@@ -411,8 +411,8 @@ cleanup_module(void)
                        iiResetDelay( i2BoardPtrTable[i] );
                        /* free io addresses and Tibet */
                        release_region( ip2config.addr[i], 8 );
-                       class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i));
-                       class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1));
+                       device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i));
+                       device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1));
                }
                /* Disable and remove interrupt handler. */
                if ( (ip2config.irq[i] > 0) && have_requested_irq(ip2config.irq[i]) ) { 
@@ -718,12 +718,12 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize)
                        }
 
                        if ( NULL != ( pB = i2BoardPtrTable[i] ) ) {
-                               class_device_create(ip2_class, NULL,
+                               device_create(ip2_class, NULL,
                                                MKDEV(IP2_IPL_MAJOR, 4 * i),
-                                               NULL, "ipl%d", i);
-                               class_device_create(ip2_class, NULL,
+                                               "ipl%d", i);
+                               device_create(ip2_class, NULL,
                                                MKDEV(IP2_IPL_MAJOR, 4 * i + 1),
-                                               NULL, "stat%d", i);
+                                               "stat%d", i);
 
                            for ( box = 0; box < ABS_MAX_BOXES; ++box )
                            {
index c2aa44ee6eb6d89848e68ee42e1b3cba4a799ab7..0246a2b8ce4848ad918f24506623dd58d830df5a 100644 (file)
@@ -865,7 +865,7 @@ static void ipmi_new_smi(int if_num, struct device *device)
        entry->dev = dev;
 
        mutex_lock(&reg_list_mutex);
-       class_device_create(ipmi_class, NULL, dev, device, "ipmi%d", if_num);
+       device_create(ipmi_class, device, dev, "ipmi%d", if_num);
        list_add(&entry->link, &reg_list);
        mutex_unlock(&reg_list_mutex);
 }
@@ -883,7 +883,7 @@ static void ipmi_smi_gone(int if_num)
                        break;
                }
        }
-       class_device_destroy(ipmi_class, dev);
+       device_destroy(ipmi_class, dev);
        mutex_unlock(&reg_list_mutex);
 }
 
@@ -938,7 +938,7 @@ static __exit void cleanup_ipmi(void)
        mutex_lock(&reg_list_mutex);
        list_for_each_entry_safe(entry, entry2, &reg_list, link) {
                list_del(&entry->link);
-               class_device_destroy(ipmi_class, entry->dev);
+               device_destroy(ipmi_class, entry->dev);
                kfree(entry);
        }
        mutex_unlock(&reg_list_mutex);
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 3c66f402f9d7b177bc42687ce08711184e45bc3a..1f27be1ec3d4c1ddf36bccb67cb96c2244683f14 100644 (file)
@@ -4624,9 +4624,8 @@ static int __init istallion_module_init(void)
 
        istallion_class = class_create(THIS_MODULE, "staliomem");
        for (i = 0; i < 4; i++)
-               class_device_create(istallion_class, NULL,
-                               MKDEV(STL_SIOMEMMAJOR, i),
-                               NULL, "staliomem%d", i);
+               device_create(istallion_class, NULL, MKDEV(STL_SIOMEMMAJOR, i),
+                             "staliomem%d", i);
 
        return 0;
 err_deinit:
@@ -4659,8 +4658,7 @@ static void __exit istallion_module_exit(void)
        unregister_chrdev(STL_SIOMEMMAJOR, "staliomem");
 
        for (j = 0; j < 4; j++)
-               class_device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR,
-                                       j));
+               device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR, j));
        class_destroy(istallion_class);
 
        pci_unregister_driver(&stli_pcidriver);
index 62051f8b0910cb97c04fc58e364f0996437c60be..c59e2a0996cc9a11c87447b0e34bbd41412f9340 100644 (file)
@@ -799,8 +799,7 @@ static int lp_register(int nr, struct parport *port)
        if (reset)
                lp_reset(nr);
 
-       class_device_create(lp_class, NULL, MKDEV(LP_MAJOR, nr), port->dev,
-                               "lp%d", nr);
+       device_create(lp_class, port->dev, MKDEV(LP_MAJOR, nr), "lp%d", nr);
 
        printk(KERN_INFO "lp%d: using %s (%s).\n", nr, port->name, 
               (port->irq == PARPORT_IRQ_NONE)?"polling":"interrupt-driven");
@@ -971,7 +970,7 @@ static void lp_cleanup_module (void)
                if (lp_table[offset].dev == NULL)
                        continue;
                parport_unregister_device(lp_table[offset].dev);
-               class_device_destroy(lp_class, MKDEV(LP_MAJOR, offset));
+               device_destroy(lp_class, MKDEV(LP_MAJOR, offset));
        }
        class_destroy(lp_class);
 }
index 4177f6db83e9c45336bf0b604dd113424b8076ad..cc5d77797defc66781da7c8c390bbfdc693b09a8 100644 (file)
@@ -1863,8 +1863,7 @@ static int cm4000_probe(struct pcmcia_device *link)
                return ret;
        }
 
-       class_device_create(cmm_class, NULL, MKDEV(major, i), NULL,
-                           "cmm%d", i);
+       device_create(cmm_class, NULL, MKDEV(major, i), "cmm%d", i);
 
        return 0;
 }
@@ -1888,7 +1887,7 @@ static void cm4000_detach(struct pcmcia_device *link)
        dev_table[devno] = NULL;
        kfree(dev);
 
-       class_device_destroy(cmm_class, MKDEV(major, devno));
+       device_destroy(cmm_class, MKDEV(major, devno));
 
        return;
 }
index b24a3e7bbb9f23b409a77dfb2ffc4ff93a0c9f26..a0b9c8728d5685c80b51807ee7faa377ca2cf456 100644 (file)
@@ -642,8 +642,7 @@ static int reader_probe(struct pcmcia_device *link)
                return ret;
        }
 
-       class_device_create(cmx_class, NULL, MKDEV(major, i), NULL,
-                           "cmx%d", i);
+       device_create(cmx_class, NULL, MKDEV(major, i), "cmx%d", i);
 
        return 0;
 }
@@ -666,7 +665,7 @@ static void reader_detach(struct pcmcia_device *link)
        dev_table[devno] = NULL;
        kfree(dev);
 
-       class_device_destroy(cmx_class, MKDEV(major, devno));
+       device_destroy(cmx_class, MKDEV(major, devno));
 
        return;
 }
index de14aea34e11f215765c8b718efe65ff595e795a..73de77105fea9c9a58c8ed704fab7626b2bfb2d1 100644 (file)
@@ -248,14 +248,19 @@ static int pty_bsd_ioctl(struct tty_struct *tty, struct file *file,
        return -ENOIOCTLCMD;
 }
 
+static int legacy_count = CONFIG_LEGACY_PTY_COUNT;
+module_param(legacy_count, int, 0);
+
 static void __init legacy_pty_init(void)
 {
+       if (legacy_count <= 0)
+               return;
 
-       pty_driver = alloc_tty_driver(NR_PTYS);
+       pty_driver = alloc_tty_driver(legacy_count);
        if (!pty_driver)
                panic("Couldn't allocate pty driver");
 
-       pty_slave_driver = alloc_tty_driver(NR_PTYS);
+       pty_slave_driver = alloc_tty_driver(legacy_count);
        if (!pty_slave_driver)
                panic("Couldn't allocate pty slave driver");
 
index 1f0d7c60c94420fb98fd23791bc38ba1b8266b37..bbfa0e241cba38928c8a5b5157a7a2a3ac178d2a 100644 (file)
@@ -255,10 +255,7 @@ static const struct file_operations raw_ctl_fops = {
        .owner  =       THIS_MODULE,
 };
 
-static struct cdev raw_cdev = {
-       .kobj   =       {.name = "raw", },
-       .owner  =       THIS_MODULE,
-};
+static struct cdev raw_cdev;
 
 static int __init raw_init(void)
 {
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 52753e723eaae5cf361a5b06cc097b2a7ce0da25..b9c1dba6bd01fe2882f404d90b2bd745872b50e9 100644 (file)
@@ -441,8 +441,7 @@ scdrv_init(void)
                                continue;
                        }
 
-                       class_device_create(snsc_class, NULL, dev, NULL,
-                                               "%s", devname);
+                       device_create(snsc_class, NULL, dev, "%s", devname);
 
                        ia64_sn_irtr_intr_enable(scd->scd_nasid,
                                                 0 /*ignored */ ,
index 4a80b2f864e0b6e5edc468bc33342b4ffd612c3e..45758d5b56ef88f3c2700fb218b55d6b71994b90 100644 (file)
@@ -4778,9 +4778,8 @@ static int __init stallion_module_init(void)
        if (IS_ERR(stallion_class))
                printk("STALLION: failed to create class\n");
        for (i = 0; i < 4; i++)
-               class_device_create(stallion_class, NULL,
-                                   MKDEV(STL_SIOMEMMAJOR, i), NULL,
-                                   "staliomem%d", i);
+               device_create(stallion_class, NULL, MKDEV(STL_SIOMEMMAJOR, i),
+                             "staliomem%d", i);
 
        return 0;
 err_unrtty:
@@ -4816,7 +4815,7 @@ static void __exit stallion_module_exit(void)
        }
 
        for (i = 0; i < 4; i++)
-               class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i));
+               device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i));
        unregister_chrdev(STL_SIOMEMMAJOR, "staliomem");
        class_destroy(stallion_class);
 
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 35b40b9965344877e113210a7725f6657912abdd..cef55c40654f680aae7f0282a7ef7bdbfdf39179 100644 (file)
@@ -441,8 +441,8 @@ tipar_register(int nr, struct parport *port)
                goto out;
        }
 
-       class_device_create(tipar_class, NULL, MKDEV(TIPAR_MAJOR,
-                       TIPAR_MINOR + nr), port->dev, "par%d", nr);
+       device_create(tipar_class, port->dev, MKDEV(TIPAR_MAJOR,
+                       TIPAR_MINOR + nr), "par%d", nr);
 
        /* Display informations */
        pr_info("tipar%d: using %s (%s)\n", nr, port->name, (port->irq ==
@@ -534,7 +534,7 @@ tipar_cleanup_module(void)
                if (table[i].dev == NULL)
                        continue;
                parport_unregister_device(table[i].dev);
-               class_device_destroy(tipar_class, MKDEV(TIPAR_MAJOR, i));
+               device_destroy(tipar_class, MKDEV(TIPAR_MAJOR, i));
        }
        class_destroy(tipar_class);
 
index f1d60f0cef8f860b3b402a680e98f71214e975d7..db7a731e2362dc747925991feb0fb06d3a86785c 100644 (file)
@@ -871,10 +871,10 @@ static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id)
        state[i].cur_part = 0;
        for (j = 0; j < MAX_PARTITIONS; ++j)
                state[i].part_stat_rwi[j] = VIOT_IDLE;
-       class_device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i), NULL,
+       device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i),
                        "iseries!vt%d", i);
-       class_device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80),
-                       NULL, "iseries!nvt%d", i);
+       device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80),
+                       "iseries!nvt%d", i);
        printk(VIOTAPE_KERN_INFO "tape iseries/vt%d is iSeries "
                        "resource %10.10s type %4.4s, model %3.3s\n",
                        i, viotape_unitinfo[i].rsrcname,
@@ -886,8 +886,8 @@ static int viotape_remove(struct vio_dev *vdev)
 {
        int i = vdev->unit_address;
 
-       class_device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80));
-       class_device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i));
+       device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80));
+       device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i));
        return 0;
 }
 
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 993fa7b89253404adbd4cba3eb900dfdcd8f2393..721f86f4f0085d3a4caf11c7365ae18643825c84 100644 (file)
@@ -56,10 +56,6 @@ config CPU_FREQ_STAT_DETAILS
 
          If in doubt, say N.
 
-# Note that it is not currently possible to set the other governors (such as ondemand)
-# as the default, since if they fail to initialise, cpufreq will be
-# left in an undefined state.
-
 choice
        prompt "Default CPUFreq governor"
        default CPU_FREQ_DEFAULT_GOV_USERSPACE if CPU_FREQ_SA1100 || CPU_FREQ_SA1110
@@ -85,6 +81,29 @@ config CPU_FREQ_DEFAULT_GOV_USERSPACE
          program shall be able to set the CPU dynamically without having
          to enable the userspace governor manually.
 
+config CPU_FREQ_DEFAULT_GOV_ONDEMAND
+       bool "ondemand"
+       select CPU_FREQ_GOV_ONDEMAND
+       select CPU_FREQ_GOV_PERFORMANCE
+       help
+         Use the CPUFreq governor 'ondemand' as default. This allows
+         you to get a full dynamic frequency capable system by simply
+         loading your cpufreq low-level hardware driver.
+         Be aware that not all cpufreq drivers support the ondemand
+         governor. If unsure have a look at the help section of the
+         driver. Fallback governor will be the performance governor.
+
+config CPU_FREQ_DEFAULT_GOV_CONSERVATIVE
+       bool "conservative"
+       select CPU_FREQ_GOV_CONSERVATIVE
+       select CPU_FREQ_GOV_PERFORMANCE
+       help
+         Use the CPUFreq governor 'conservative' as default. This allows
+         you to get a full dynamic frequency capable system by simply
+         loading your cpufreq low-level hardware driver.
+         Be aware that not all cpufreq drivers support the conservative
+         governor. If unsure have a look at the help section of the
+         driver. Fallback governor will be the performance governor.
 endchoice
 
 config CPU_FREQ_GOV_PERFORMANCE
index 2f6a73c01b718318d583123f66aaa6c622dca6a0..5e626b12b97eb758b12a652d4fd8e5967ee76307 100644 (file)
@@ -763,6 +763,8 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
        init_completion(&policy->kobj_unregister);
        INIT_WORK(&policy->update, handle_update);
 
+       /* Set governor before ->init, so that driver could check it */
+       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        /* call driver. From then on the cpufreq must be able
         * to accept all calls to ->verify and ->setpolicy for this CPU
         */
@@ -828,7 +830,7 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
        /* prepare interface data */
        policy->kobj.parent = &sys_dev->kobj;
        policy->kobj.ktype = &ktype_cpufreq;
-       strlcpy(policy->kobj.name, "cpufreq", KOBJ_NAME_LEN);
+       kobject_set_name(&policy->kobj, "cpufreq");
 
        ret = kobject_register(&policy->kobj);
        if (ret) {
@@ -1109,12 +1111,7 @@ unsigned int cpufreq_quick_get(unsigned int cpu)
        unsigned int ret_freq = 0;
 
        if (policy) {
-               if (unlikely(lock_policy_rwsem_read(cpu)))
-                       return ret_freq;
-
                ret_freq = policy->cur;
-
-               unlock_policy_rwsem_read(cpu);
                cpufreq_cpu_put(policy);
        }
 
@@ -1483,6 +1480,31 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
 {
        int ret;
 
+       /* Only must be defined when default governor is known to have latency
+          restrictions, like e.g. conservative or ondemand.
+          That this is the case is already ensured in Kconfig
+       */
+#ifdef CONFIG_CPU_FREQ_GOV_PERFORMANCE
+       struct cpufreq_governor *gov = &cpufreq_gov_performance;
+#else
+       struct cpufreq_governor *gov = NULL;
+#endif
+
+       if (policy->governor->max_transition_latency &&
+           policy->cpuinfo.transition_latency >
+           policy->governor->max_transition_latency) {
+               if (!gov)
+                       return -EINVAL;
+               else {
+                       printk(KERN_WARNING "%s governor failed, too long"
+                              " transition latency of HW, fallback"
+                              " to %s governor\n",
+                              policy->governor->name,
+                              gov->name);
+                       policy->governor = gov;
+               }
+       }
+
        if (!try_module_get(policy->governor->owner))
                return -EINVAL;
 
@@ -1703,7 +1725,7 @@ int cpufreq_update_policy(unsigned int cpu)
 }
 EXPORT_SYMBOL(cpufreq_update_policy);
 
-static int cpufreq_cpu_callback(struct notifier_block *nfb,
+static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb,
                                        unsigned long action, void *hcpu)
 {
        unsigned int cpu = (unsigned long)hcpu;
index 26f440ccc3fb358e9525ecabee819ae52b7afa26..4bd33ce8a6f3398a0aa37995582e619c3b938590 100644 (file)
@@ -58,7 +58,7 @@ static unsigned int                           def_sampling_rate;
 #define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER   (1000)
 #define DEF_SAMPLING_DOWN_FACTOR               (1)
 #define MAX_SAMPLING_DOWN_FACTOR               (10)
-#define TRANSITION_LATENCY_LIMIT               (10 * 1000)
+#define TRANSITION_LATENCY_LIMIT               (10 * 1000 * 1000)
 
 static void do_dbs_timer(struct work_struct *work);
 
@@ -466,9 +466,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
                    (!policy->cur))
                        return -EINVAL;
 
-               if (policy->cpuinfo.transition_latency >
-                               (TRANSITION_LATENCY_LIMIT * 1000))
-                       return -EINVAL;
                if (this_dbs_info->enable) /* Already enabled */
                        break;
                 
@@ -551,15 +548,17 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
        return 0;
 }
 
-static struct cpufreq_governor cpufreq_gov_dbs = {
-       .name           = "conservative",
-       .governor       = cpufreq_governor_dbs,
-       .owner          = THIS_MODULE,
+struct cpufreq_governor cpufreq_gov_conservative = {
+       .name                   = "conservative",
+       .governor               = cpufreq_governor_dbs,
+       .max_transition_latency = TRANSITION_LATENCY_LIMIT,
+       .owner                  = THIS_MODULE,
 };
+EXPORT_SYMBOL(cpufreq_gov_conservative);
 
 static int __init cpufreq_gov_dbs_init(void)
 {
-       return cpufreq_register_governor(&cpufreq_gov_dbs);
+       return cpufreq_register_governor(&cpufreq_gov_conservative);
 }
 
 static void __exit cpufreq_gov_dbs_exit(void)
@@ -567,7 +566,7 @@ static void __exit cpufreq_gov_dbs_exit(void)
        /* Make sure that the scheduled work is indeed not running */
        flush_scheduled_work();
 
-       cpufreq_unregister_governor(&cpufreq_gov_dbs);
+       cpufreq_unregister_governor(&cpufreq_gov_conservative);
 }
 
 
index e794527e49251d10564e703805b1965844c12b65..369f44595150f7e568fff7802d8047ca645f0ffd 100644 (file)
@@ -47,7 +47,7 @@ static unsigned int def_sampling_rate;
                        (def_sampling_rate / MIN_SAMPLING_RATE_RATIO)
 #define MAX_SAMPLING_RATE                      (500 * def_sampling_rate)
 #define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER   (1000)
-#define TRANSITION_LATENCY_LIMIT               (10 * 1000)
+#define TRANSITION_LATENCY_LIMIT               (10 * 1000 * 1000)
 
 static void do_dbs_timer(struct work_struct *work);
 
@@ -508,12 +508,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
                if ((!cpu_online(cpu)) || (!policy->cur))
                        return -EINVAL;
 
-               if (policy->cpuinfo.transition_latency >
-                               (TRANSITION_LATENCY_LIMIT * 1000)) {
-                       printk(KERN_WARNING "ondemand governor failed to load "
-                              "due to too long transition latency\n");
-                       return -EINVAL;
-               }
                if (this_dbs_info->enable) /* Already enabled */
                        break;
 
@@ -585,11 +579,13 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
        return 0;
 }
 
-static struct cpufreq_governor cpufreq_gov_dbs = {
-       .name = "ondemand",
-       .governor = cpufreq_governor_dbs,
-       .owner = THIS_MODULE,
+struct cpufreq_governor cpufreq_gov_ondemand = {
+       .name                   = "ondemand",
+       .governor               = cpufreq_governor_dbs,
+       .max_transition_latency = TRANSITION_LATENCY_LIMIT,
+       .owner                  = THIS_MODULE,
 };
+EXPORT_SYMBOL(cpufreq_gov_ondemand);
 
 static int __init cpufreq_gov_dbs_init(void)
 {
@@ -598,12 +594,12 @@ static int __init cpufreq_gov_dbs_init(void)
                printk(KERN_ERR "Creation of kondemand failed\n");
                return -EFAULT;
        }
-       return cpufreq_register_governor(&cpufreq_gov_dbs);
+       return cpufreq_register_governor(&cpufreq_gov_ondemand);
 }
 
 static void __exit cpufreq_gov_dbs_exit(void)
 {
-       cpufreq_unregister_governor(&cpufreq_gov_dbs);
+       cpufreq_unregister_governor(&cpufreq_gov_ondemand);
        destroy_workqueue(kondemand_wq);
 }
 
index 917b9bab9ccbc924a6e583997cf96dc03e09071f..8a45d0f93e262716690a070c017883b4910da88d 100644 (file)
@@ -164,8 +164,7 @@ freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq)
        return -1;
 }
 
-static void
-cpufreq_stats_free_table (unsigned int cpu)
+static void __cpuexit cpufreq_stats_free_table(unsigned int cpu)
 {
        struct cpufreq_stats *stat = cpufreq_stats_table[cpu];
        struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
@@ -305,8 +304,9 @@ cpufreq_stat_notifier_trans (struct notifier_block *nb, unsigned long val,
        return 0;
 }
 
-static int cpufreq_stat_cpu_callback(struct notifier_block *nfb,
-                                       unsigned long action, void *hcpu)
+static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb,
+                                              unsigned long action,
+                                              void *hcpu)
 {
        unsigned int cpu = (unsigned long)hcpu;
 
@@ -323,7 +323,7 @@ static int cpufreq_stat_cpu_callback(struct notifier_block *nfb,
        return NOTIFY_OK;
 }
 
-static struct notifier_block cpufreq_stat_cpu_notifier =
+static struct notifier_block cpufreq_stat_cpu_notifier __cpuinitdata =
 {
        .notifier_call = cpufreq_stat_cpu_callback,
 };
@@ -356,8 +356,7 @@ __init cpufreq_stats_init(void)
 
        register_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
        for_each_online_cpu(cpu) {
-               cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier,
-                               CPU_ONLINE, (void *)(long)cpu);
+               cpufreq_update_policy(cpu);
        }
        return 0;
 }
@@ -372,13 +371,12 @@ __exit cpufreq_stats_exit(void)
                        CPUFREQ_TRANSITION_NOTIFIER);
        unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
        for_each_online_cpu(cpu) {
-               cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier,
-                                               CPU_DEAD, (void *)(long)cpu);
+               cpufreq_stats_free_table(cpu);
        }
 }
 
 MODULE_AUTHOR ("Zou Nan hai <nanhai.zou@intel.com>");
-MODULE_DESCRIPTION ("'cpufreq_stats' - A driver to export cpufreq stats"
+MODULE_DESCRIPTION ("'cpufreq_stats' - A driver to export cpufreq stats "
                                "through sysfs filesystem");
 MODULE_LICENSE ("GPL");
 
index 4a0576bd06fc93bab9b2028b695ff7907a13f9c4..3706b2bc0987f8a5a22cc5784054dce95bf17973 100644 (file)
@@ -743,7 +743,7 @@ static struct kobj_type ktype_mc_set_attribs = {
  *     /sys/devices/system/edac/mc
  */
 static struct kset mc_kset = {
-       .kobj = {.name = "mc", .ktype = &ktype_mc_set_attribs },
+       .kobj = {.ktype = &ktype_mc_set_attribs },
        .ktype = &ktype_mci,
 };
 
@@ -1010,6 +1010,7 @@ int edac_sysfs_setup_mc_kset(void)
        }
 
        /* Init the MC's kobject */
+       kobject_set_name(&mc_kset.kobj, "mc");
        mc_kset.kobj.parent = &edac_class->kset.kobj;
 
        /* register the mc_kset */
index d944647c82c2e0dfc771fb286a3554569e0f487c..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,
@@ -128,16 +128,11 @@ static int eisa_bus_match (struct device *dev, struct device_driver *drv)
        return 0;
 }
 
-static int eisa_bus_uevent(struct device *dev, char **envp, int num_envp,
-                          char *buffer, int buffer_size)
+static int eisa_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        struct eisa_device *edev = to_eisa_device(dev);
-       int i = 0;
-       int length = 0;
 
-       add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
-                      "MODALIAS=" EISA_DEVICE_MODALIAS_FMT, edev->id.sig);
-       envp[i] = NULL;
+       add_uevent_var(env, "MODALIAS=" EISA_DEVICE_MODALIAS_FMT, edev->id.sig);
        return 0;
 }
 
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 2b6586341635b9ed57dafc5f6ebb977924177010..56681b3b297baa43ed5b756151933b9a57f05f2c 100644 (file)
@@ -130,23 +130,16 @@ static int get_modalias(struct fw_unit *unit, char *buffer, size_t buffer_size)
 }
 
 static int
-fw_unit_uevent(struct device *dev, char **envp, int num_envp,
-              char *buffer, int buffer_size)
+fw_unit_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        struct fw_unit *unit = fw_unit(dev);
        char modalias[64];
-       int length = 0;
-       int i = 0;
 
        get_modalias(unit, modalias, sizeof(modalias));
 
-       if (add_uevent_var(envp, num_envp, &i,
-                          buffer, buffer_size, &length,
-                          "MODALIAS=%s", modalias))
+       if (add_uevent_var(env, "MODALIAS=%s", modalias))
                return -ENOMEM;
 
-       envp[i] = NULL;
-
        return 0;
 }
 
index 59c3b5aa89f41a9fba29ce500049cbed721e9e40..b6e1eb77d14847c0f7d25f836c76bcfe6e76c554 100644 (file)
 #include <linux/device.h>
 #include <linux/autoconf.h>
 
-#define DEFINE_DMI_ATTR(_name, _mode, _show)           \
-static struct device_attribute sys_dmi_##_name##_attr =        \
-       __ATTR(_name, _mode, _show, NULL);
-
-#define DEFINE_DMI_ATTR_WITH_SHOW(_name, _mode, _field)                        \
-static ssize_t sys_dmi_##_name##_show(struct device *dev,              \
-                                     struct device_attribute *attr,    \
-                                     char *page)                       \
-{                                                                      \
-       ssize_t len;                                                    \
-       len = scnprintf(page, PAGE_SIZE, "%s\n", dmi_get_system_info(_field)); \
-       page[len-1] = '\n';                                             \
-       return len;                                                     \
-}                                                                      \
-DEFINE_DMI_ATTR(_name, _mode, sys_dmi_##_name##_show);
+struct dmi_device_attribute{
+       struct device_attribute dev_attr;
+       int field;
+};
+#define to_dmi_dev_attr(_dev_attr) \
+       container_of(_dev_attr, struct dmi_device_attribute, dev_attr)
+
+static ssize_t sys_dmi_field_show(struct device *dev,
+                                 struct device_attribute *attr,
+                                 char *page)
+{
+       int field = to_dmi_dev_attr(attr)->field;
+       ssize_t len;
+       len = scnprintf(page, PAGE_SIZE, "%s\n", dmi_get_system_info(field));
+       page[len-1] = '\n';
+       return len;
+}
+
+#define DMI_ATTR(_name, _mode, _show, _field)                  \
+       { .dev_attr = __ATTR(_name, _mode, _show, NULL),        \
+         .field = _field }
+
+#define DEFINE_DMI_ATTR_WITH_SHOW(_name, _mode, _field)                \
+static struct dmi_device_attribute sys_dmi_##_name##_attr =    \
+       DMI_ATTR(_name, _mode, sys_dmi_field_show, _field);
 
 DEFINE_DMI_ATTR_WITH_SHOW(bios_vendor,         0444, DMI_BIOS_VENDOR);
 DEFINE_DMI_ATTR_WITH_SHOW(bios_version,                0444, DMI_BIOS_VERSION);
@@ -121,7 +131,8 @@ static ssize_t sys_dmi_modalias_show(struct device *dev,
        return r+1;
 }
 
-DEFINE_DMI_ATTR(modalias, 0444, sys_dmi_modalias_show);
+static struct device_attribute sys_dmi_modalias_attr =
+       __ATTR(modalias, 0444, sys_dmi_modalias_show, NULL);
 
 static struct attribute *sys_dmi_attributes[DMI_STRING_MAX+2];
 
@@ -134,14 +145,17 @@ static struct attribute_group* sys_dmi_attribute_groups[] = {
        NULL
 };
 
-static int dmi_dev_uevent(struct device *dev, char **envp,
-                           int num_envp, char *buffer, int buffer_size)
+static int dmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
-       strcpy(buffer, "MODALIAS=");
-       get_modalias(buffer+9, buffer_size-9);
-       envp[0] = buffer;
-       envp[1] = NULL;
-
+       ssize_t len;
+
+       if (add_uevent_var(env, "MODALIAS="))
+               return -ENOMEM;
+       len = get_modalias(&env->buf[env->buflen - 1],
+                          sizeof(env->buf) - env->buflen);
+       if (len >= (sizeof(env->buf) - env->buflen))
+               return -ENOMEM;
+       env->buflen += len;
        return 0;
 }
 
@@ -157,7 +171,7 @@ static struct device *dmi_dev;
 
 #define ADD_DMI_ATTR(_name, _field) \
        if (dmi_get_system_info(_field)) \
-               sys_dmi_attributes[i++] = & sys_dmi_##_name##_attr.attr;
+               sys_dmi_attributes[i++] = &sys_dmi_##_name##_attr.dev_attr.attr;
 
 extern int dmi_available;
 
index 0fb730ee1da845f75af2e19ba28b5eba34386301..6942e065e6095d2fe55188843f0f7d4dce36dd2a 100644 (file)
@@ -625,13 +625,13 @@ static void edd_release(struct kobject * kobj)
        kfree(dev);
 }
 
-static struct kobj_type ktype_edd = {
+static struct kobj_type edd_ktype = {
        .release        = edd_release,
        .sysfs_ops      = &edd_attr_ops,
        .default_attrs  = def_attrs,
 };
 
-static decl_subsys(edd,&ktype_edd,NULL);
+static decl_subsys(edd, &edd_ktype, NULL);
 
 
 /**
index bfd2d67df689d8ccb33138c78935b73ae7363d31..858a7b95933bf21993ddd81d178b17ed3d2cc62d 100644 (file)
@@ -402,7 +402,7 @@ static struct attribute *def_attrs[] = {
        NULL,
 };
 
-static struct kobj_type ktype_efivar = {
+static struct kobj_type efivar_ktype = {
        .release = efivar_release,
        .sysfs_ops = &efivar_attr_ops,
        .default_attrs = def_attrs,
@@ -583,7 +583,7 @@ static struct subsys_attribute *efi_subsys_attrs[] = {
        NULL,   /* maybe more in the future? */
 };
 
-static decl_subsys(vars, &ktype_efivar, NULL);
+static decl_subsys(vars, &efivar_ktype, NULL);
 static decl_subsys(efi, NULL, NULL);
 
 /*
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 192953b29b2843e243d41102b7367d5181c2d7a4..e47f88170806f0cff4ec3ac56b9d63273e5cad9f 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
@@ -172,7 +182,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
@@ -206,19 +216,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.
@@ -228,7 +258,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.
@@ -236,6 +266,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
@@ -265,6 +309,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
@@ -401,7 +458,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
@@ -466,13 +523,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 56213b7f8188ecbf39417ba75a431bc48cddeff3..f37fd7ebf65ad80b2173796b415d2b9cebacb51d 100644 (file)
@@ -127,7 +127,7 @@ static s16 rest_x;
 static s16 rest_y;
 static struct timer_list applesmc_timer;
 static struct input_dev *applesmc_idev;
-static struct class_device *hwmon_class_dev;
+static struct device *hwmon_dev;
 
 /* Indicates whether this computer has an accelerometer. */
 static unsigned int applesmc_accelerometer;
@@ -1287,9 +1287,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;
        }
 
@@ -1331,7 +1331,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 d663e6960d934e70c294babea743eb7ae7459d51..e73d58c43f386a349856cdb95f2935510c2a79fe 100644 (file)
@@ -67,20 +67,16 @@ static int i2c_device_match(struct device *dev, struct device_driver *drv)
 #ifdef CONFIG_HOTPLUG
 
 /* uevent helps with hotplug: modprobe -q $(MODALIAS) */
-static int i2c_device_uevent(struct device *dev, char **envp, int num_envp,
-                     char *buffer, int buffer_size)
+static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        struct i2c_client       *client = to_i2c_client(dev);
-       int                     i = 0, length = 0;
 
        /* by definition, legacy drivers can't hotplug */
        if (dev->driver || !client->driver_name)
                return 0;
 
-       if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
-                       "MODALIAS=%s", client->driver_name))
+       if (add_uevent_var(env, "MODALIAS=%s", client->driver_name))
                return -ENOMEM;
-       envp[i] = NULL;
        dev_dbg(dev, "uevent\n");
        return 0;
 }
@@ -190,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,
@@ -201,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
@@ -230,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;
 
@@ -283,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);
@@ -301,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,
@@ -934,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!
@@ -1310,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 e96212ce5729126cf099f997285845bce53d6216..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;
@@ -1663,20 +1663,13 @@ static struct device_attribute ide_dev_attrs[] = {
        __ATTR_NULL
 };
 
-static int ide_uevent(struct device *dev, char **envp, int num_envp,
-                     char *buffer, int buffer_size)
+static int ide_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        ide_drive_t *drive = to_ide_device(dev);
-       int i = 0;
-       int length = 0;
-
-       add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
-                      "MEDIA=%s", media_string(drive));
-       add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
-                      "DRIVENAME=%s", drive->name);
-       add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
-                      "MODALIAS=ide:m-%s", media_string(drive));
-       envp[i] = NULL;
+
+       add_uevent_var(env, "MEDIA=%s", media_string(drive));
+       add_uevent_var(env, "DRIVENAME=%s", drive->name);
+       add_uevent_var(env, "MODALIAS=ide:m-%s", media_string(drive));
        return 0;
 }
 
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 2ffd53461db6877eb6a108d90fca478a40387f12..1939fee616ec4b8ac4c47ff8b0e3aac0d21a366b 100644 (file)
@@ -153,8 +153,7 @@ struct host_info {
 };
 
 static int nodemgr_bus_match(struct device * dev, struct device_driver * drv);
-static int nodemgr_uevent(struct device *dev, char **envp, int num_envp,
-                         char *buffer, int buffer_size);
+static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env);
 static void nodemgr_resume_ne(struct node_entry *ne);
 static void nodemgr_remove_ne(struct node_entry *ne);
 static struct node_entry *find_entry_by_guid(u64 guid);
@@ -1160,12 +1159,9 @@ static void nodemgr_process_root_directory(struct host_info *hi, struct node_ent
 
 #ifdef CONFIG_HOTPLUG
 
-static int nodemgr_uevent(struct device *dev, char **envp, int num_envp,
-                         char *buffer, int buffer_size)
+static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        struct unit_directory *ud;
-       int i = 0;
-       int length = 0;
        int retval = 0;
        /* ieee1394:venNmoNspNverN */
        char buf[8 + 1 + 3 + 8 + 2 + 8 + 2 + 8 + 3 + 8 + 1];
@@ -1180,9 +1176,7 @@ static int nodemgr_uevent(struct device *dev, char **envp, int num_envp,
 
 #define PUT_ENVP(fmt,val)                                      \
 do {                                                           \
-       retval = add_uevent_var(envp, num_envp, &i,             \
-                               buffer, buffer_size, &length,   \
-                               fmt, val);                      \
+       retval = add_uevent_var(env, fmt, val);         \
        if (retval)                                             \
                return retval;                                  \
 } while (0)
@@ -1201,15 +1195,12 @@ do {                                                            \
 
 #undef PUT_ENVP
 
-       envp[i] = NULL;
-
        return 0;
 }
 
 #else
 
-static int nodemgr_uevent(struct device *dev, char **envp, int num_envp,
-                         char *buffer, int buffer_size)
+static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        return -ENODEV;
 }
index 70b77ae67422da6d1fc624a7dc1242a9cbe06af2..3d40506813250e6ba429e8e71224a9e077ce032e 100644 (file)
@@ -434,21 +434,18 @@ static void ib_device_release(struct class_device *cdev)
        kfree(dev);
 }
 
-static int ib_device_uevent(struct class_device *cdev, char **envp,
-                           int num_envp, char *buf, int size)
+static int ib_device_uevent(struct class_device *cdev,
+                           struct kobj_uevent_env *env)
 {
        struct ib_device *dev = container_of(cdev, struct ib_device, class_dev);
-       int i = 0, len = 0;
 
-       if (add_uevent_var(envp, num_envp, &i, buf, size, &len,
-                          "NAME=%s", dev->name))
+       if (add_uevent_var(env, "NAME=%s", dev->name))
                return -ENOMEM;
 
        /*
         * It would be nice to pass the node GUID with the event...
         */
 
-       envp[i] = NULL;
        return 0;
 }
 
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 5fe7555866230509e48f3a0526858704de27b5b9..5dc361c954e2aa92a3632117bdd4575bc9f23382 100644 (file)
@@ -859,87 +859,66 @@ static void input_dev_release(struct device *device)
  * Input uevent interface - loading event handlers based on
  * device bitfields.
  */
-static int input_add_uevent_bm_var(char **envp, int num_envp, int *cur_index,
-                                  char *buffer, int buffer_size, int *cur_len,
+static int input_add_uevent_bm_var(struct kobj_uevent_env *env,
                                   const char *name, unsigned long *bitmap, int max)
 {
-       if (*cur_index >= num_envp - 1)
-               return -ENOMEM;
-
-       envp[*cur_index] = buffer + *cur_len;
+       int len;
 
-       *cur_len += snprintf(buffer + *cur_len, max(buffer_size - *cur_len, 0), name);
-       if (*cur_len >= buffer_size)
+       if (add_uevent_var(env, "%s=", name))
                return -ENOMEM;
 
-       *cur_len += input_print_bitmap(buffer + *cur_len,
-                                       max(buffer_size - *cur_len, 0),
-                                       bitmap, max, 0) + 1;
-       if (*cur_len > buffer_size)
+       len = input_print_bitmap(&env->buf[env->buflen - 1],
+                                sizeof(env->buf) - env->buflen,
+                                bitmap, max, 0);
+       if (len >= (sizeof(env->buf) - env->buflen))
                return -ENOMEM;
 
-       (*cur_index)++;
+       env->buflen += len;
        return 0;
 }
 
-static int input_add_uevent_modalias_var(char **envp, int num_envp, int *cur_index,
-                                        char *buffer, int buffer_size, int *cur_len,
+static int input_add_uevent_modalias_var(struct kobj_uevent_env *env,
                                         struct input_dev *dev)
 {
-       if (*cur_index >= num_envp - 1)
-               return -ENOMEM;
-
-       envp[*cur_index] = buffer + *cur_len;
+       int len;
 
-       *cur_len += snprintf(buffer + *cur_len, max(buffer_size - *cur_len, 0),
-                            "MODALIAS=");
-       if (*cur_len >= buffer_size)
+       if (add_uevent_var(env, "MODALIAS="))
                return -ENOMEM;
 
-       *cur_len += input_print_modalias(buffer + *cur_len,
-                                        max(buffer_size - *cur_len, 0),
-                                        dev, 0) + 1;
-       if (*cur_len > buffer_size)
+       len = input_print_modalias(&env->buf[env->buflen - 1],
+                                  sizeof(env->buf) - env->buflen,
+                                  dev, 0);
+       if (len >= (sizeof(env->buf) - env->buflen))
                return -ENOMEM;
 
-       (*cur_index)++;
+       env->buflen += len;
        return 0;
 }
 
 #define INPUT_ADD_HOTPLUG_VAR(fmt, val...)                             \
        do {                                                            \
-               int err = add_uevent_var(envp, num_envp, &i,            \
-                                       buffer, buffer_size, &len,      \
-                                       fmt, val);                      \
+               int err = add_uevent_var(env, fmt, val);                \
                if (err)                                                \
                        return err;                                     \
        } while (0)
 
 #define INPUT_ADD_HOTPLUG_BM_VAR(name, bm, max)                                \
        do {                                                            \
-               int err = input_add_uevent_bm_var(envp, num_envp, &i,   \
-                                       buffer, buffer_size, &len,      \
-                                       name, bm, max);                 \
+               int err = input_add_uevent_bm_var(env, name, bm, max);  \
                if (err)                                                \
                        return err;                                     \
        } while (0)
 
 #define INPUT_ADD_HOTPLUG_MODALIAS_VAR(dev)                            \
        do {                                                            \
-               int err = input_add_uevent_modalias_var(envp,           \
-                                       num_envp, &i,                   \
-                                       buffer, buffer_size, &len,      \
-                                       dev);                           \
+               int err = input_add_uevent_modalias_var(env, dev);      \
                if (err)                                                \
                        return err;                                     \
        } while (0)
 
-static int input_dev_uevent(struct device *device, char **envp,
-                           int num_envp, char *buffer, int buffer_size)
+static int input_dev_uevent(struct device *device, struct kobj_uevent_env *env)
 {
        struct input_dev *dev = to_input_dev(device);
-       int i = 0;
-       int len = 0;
 
        INPUT_ADD_HOTPLUG_VAR("PRODUCT=%x/%x/%x/%x",
                                dev->id.bustype, dev->id.vendor,
@@ -971,7 +950,6 @@ static int input_dev_uevent(struct device *device, char **envp,
 
        INPUT_ADD_HOTPLUG_MODALIAS_VAR(dev);
 
-       envp[i] = NULL;
        return 0;
 }
 
index ded1d6ac6ff3eac662e64137271a2174731d9507..f948d3a14a930383b9d2afeb78c09393114a07a7 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;
 
@@ -86,21 +219,20 @@ static int __init atakbd_init(void)
 {
        int i;
 
-       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,17 @@ 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 */
+       if (input_register_device(atakbd_dev)) {
+               input_free_device(atakbd_dev);
+               return -ENOMEM;
+       }
 
        atari_input_keyboard_interrupt_hook = atakbd_interrupt;
 
-       printk(KERN_INFO "input: %s at IKBD ACIA\n", atakbd_dev->name);
-
        return 0;
 }
 
index 906bf5e8de89c568f243a7656fc82a3e93d8319c..c19f77fbaf2a9ffb7646f03bfcb8493797830f93 100644 (file)
 #include <linux/init.h>
 #include <linux/input.h>
 #include <linux/platform_device.h>
-#include <asm/8253pit.h>
 #include <asm/io.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
 MODULE_DESCRIPTION("PC Speaker beeper driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pcspkr");
 
 #ifdef CONFIG_X86
 /* Use the global PIT lock ! */
 #include <asm/i8253.h>
 #else
+#include <asm/8253pit.h>
 static DEFINE_SPINLOCK(i8253_lock);
 #endif
 
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 372ca493119483006acb3deaae1cbbc7e7b0d920..b3bc15acd3f5604979874f4311c5f56daf8fd1eb 100644 (file)
@@ -876,18 +876,14 @@ static int serio_bus_match(struct device *dev, struct device_driver *drv)
 
 #define SERIO_ADD_UEVENT_VAR(fmt, val...)                              \
        do {                                                            \
-               int err = add_uevent_var(envp, num_envp, &i,    \
-                                       buffer, buffer_size, &len,      \
-                                       fmt, val);                      \
+               int err = add_uevent_var(env, fmt, val);                \
                if (err)                                                \
                        return err;                                     \
        } while (0)
 
-static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size)
+static int serio_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        struct serio *serio;
-       int i = 0;
-       int len = 0;
 
        if (!dev)
                return -ENODEV;
@@ -900,7 +896,6 @@ static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buf
        SERIO_ADD_UEVENT_VAR("SERIO_EXTRA=%02x", serio->id.extra);
        SERIO_ADD_UEVENT_VAR("MODALIAS=serio:ty%02Xpr%02Xid%02Xex%02X",
                                serio->id.type, serio->id.proto, serio->id.id, serio->id.extra);
-       envp[i] = NULL;
 
        return 0;
 }
@@ -908,7 +903,7 @@ static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buf
 
 #else
 
-static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size)
+static int serio_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        return -ENODEV;
 }
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 b04a178e502102e96270963a1028e22c7c5cae83..f8b79783c8b375128a50bf119785e849e1b3e7f1 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/isapnp.h>
 #include <linux/interrupt.h>
 
-extern const char *CardType[];
 static const char *avm_pci_rev = "$Revision: 1.29.2.4 $";
 
 #define  AVM_FRITZ_PCI         1
@@ -726,100 +725,15 @@ AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return(0);
 }
 
-#ifdef CONFIG_PCI
-static struct pci_dev *dev_avm __devinitdata = NULL;
-#endif
-#ifdef __ISAPNP__
-static struct pnp_card *pnp_avm_c __devinitdata = NULL;
-#endif
-
-int __devinit
-setup_avm_pcipnp(struct IsdnCard *card)
+static int __devinit avm_setup_rest(struct IsdnCardState *cs)
 {
        u_int val, ver;
-       struct IsdnCardState *cs = card->cs;
-       char tmp[64];
 
-       strcpy(tmp, avm_pci_rev);
-       printk(KERN_INFO "HiSax: AVM PCI driver Rev. %s\n", HiSax_getrev(tmp));
-       if (cs->typ != ISDN_CTYPE_FRITZPCI)
-               return (0);
-       if (card->para[1]) {
-               /* old manual method */
-               cs->hw.avm.cfg_reg = card->para[1];
-               cs->irq = card->para[0];
-               cs->subtyp = AVM_FRITZ_PNP;
-               goto ready;
-       }
-#ifdef __ISAPNP__
-       if (isapnp_present()) {
-               struct pnp_dev *pnp_avm_d = NULL;
-               if ((pnp_avm_c = pnp_find_card(
-                       ISAPNP_VENDOR('A', 'V', 'M'),
-                       ISAPNP_FUNCTION(0x0900), pnp_avm_c))) {
-                       if ((pnp_avm_d = pnp_find_dev(pnp_avm_c,
-                               ISAPNP_VENDOR('A', 'V', 'M'),
-                               ISAPNP_FUNCTION(0x0900), pnp_avm_d))) {
-                               int err;
-
-                               pnp_disable_dev(pnp_avm_d);
-                               err = pnp_activate_dev(pnp_avm_d);
-                               if (err<0) {
-                                       printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
-                                               __FUNCTION__, err);
-                                       return(0);
-                               }
-                               cs->hw.avm.cfg_reg =
-                                       pnp_port_start(pnp_avm_d, 0);
-                               cs->irq = pnp_irq(pnp_avm_d, 0);
-                               if (!cs->irq) {
-                                       printk(KERN_ERR "FritzPnP:No IRQ\n");
-                                       return(0);
-                               }
-                               if (!cs->hw.avm.cfg_reg) {
-                                       printk(KERN_ERR "FritzPnP:No IO address\n");
-                                       return(0);
-                               }
-                               cs->subtyp = AVM_FRITZ_PNP;
-                               goto ready;
-                       }
-               }
-       } else {
-               printk(KERN_INFO "FritzPnP: no ISA PnP present\n");
-       }
-#endif
-#ifdef CONFIG_PCI
-       if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM,
-               PCI_DEVICE_ID_AVM_A1,  dev_avm))) {
-               if (pci_enable_device(dev_avm))
-                       return(0);
-               cs->irq = dev_avm->irq;
-               if (!cs->irq) {
-                       printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n");
-                       return(0);
-               }
-               cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1);
-               if (!cs->hw.avm.cfg_reg) {
-                       printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n");
-                       return(0);
-               }
-               cs->subtyp = AVM_FRITZ_PCI;
-       } else {
-               printk(KERN_WARNING "FritzPCI: No PCI card found\n");
-               return(0);
-       }
-       cs->irq_flags |= IRQF_SHARED;
-#else
-       printk(KERN_WARNING "FritzPCI: NO_PCI_BIOS\n");
-       return (0);
-#endif /* CONFIG_PCI */
-ready:
        cs->hw.avm.isac = cs->hw.avm.cfg_reg + 0x10;
        if (!request_region(cs->hw.avm.cfg_reg, 32,
                (cs->subtyp == AVM_FRITZ_PCI) ? "avm PCI" : "avm PnP")) {
                printk(KERN_WARNING
-                      "HiSax: %s config port %x-%x already in use\n",
-                      CardType[card->typ],
+                      "HiSax: Fritz!PCI/PNP config port %x-%x already in use\n",
                       cs->hw.avm.cfg_reg,
                       cs->hw.avm.cfg_reg + 31);
                return (0);
@@ -860,3 +774,137 @@ ready:
        ISACVersion(cs, (cs->subtyp == AVM_FRITZ_PCI) ? "AVM PCI:" : "AVM PnP:");
        return (1);
 }
+
+#ifndef __ISAPNP__
+
+static int __devinit avm_pnp_setup(struct IsdnCardState *cs)
+{
+       return(1);      /* no-op: success */
+}
+
+#else
+
+static struct pnp_card *pnp_avm_c __devinitdata = NULL;
+
+static int __devinit avm_pnp_setup(struct IsdnCardState *cs)
+{
+       struct pnp_dev *pnp_avm_d = NULL;
+
+       if (!isapnp_present())
+               return(1);      /* no-op: success */
+
+       if ((pnp_avm_c = pnp_find_card(
+               ISAPNP_VENDOR('A', 'V', 'M'),
+               ISAPNP_FUNCTION(0x0900), pnp_avm_c))) {
+               if ((pnp_avm_d = pnp_find_dev(pnp_avm_c,
+                       ISAPNP_VENDOR('A', 'V', 'M'),
+                       ISAPNP_FUNCTION(0x0900), pnp_avm_d))) {
+                       int err;
+
+                       pnp_disable_dev(pnp_avm_d);
+                       err = pnp_activate_dev(pnp_avm_d);
+                       if (err<0) {
+                               printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+                                       __FUNCTION__, err);
+                               return(0);
+                       }
+                       cs->hw.avm.cfg_reg =
+                               pnp_port_start(pnp_avm_d, 0);
+                       cs->irq = pnp_irq(pnp_avm_d, 0);
+                       if (!cs->irq) {
+                               printk(KERN_ERR "FritzPnP:No IRQ\n");
+                               return(0);
+                       }
+                       if (!cs->hw.avm.cfg_reg) {
+                               printk(KERN_ERR "FritzPnP:No IO address\n");
+                               return(0);
+                       }
+                       cs->subtyp = AVM_FRITZ_PNP;
+
+                       return (2);     /* goto 'ready' label */
+               }
+       }
+
+       return (1);
+}
+
+#endif /* __ISAPNP__ */
+
+#ifndef CONFIG_PCI
+
+static int __devinit avm_pci_setup(struct IsdnCardState *cs)
+{
+       return(1);      /* no-op: success */
+}
+
+#else
+
+static struct pci_dev *dev_avm __devinitdata = NULL;
+
+static int __devinit avm_pci_setup(struct IsdnCardState *cs)
+{
+       if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM,
+               PCI_DEVICE_ID_AVM_A1, dev_avm))) {
+
+               if (pci_enable_device(dev_avm))
+                       return(0);
+
+               cs->irq = dev_avm->irq;
+               if (!cs->irq) {
+                       printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n");
+                       return(0);
+               }
+
+               cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1);
+               if (!cs->hw.avm.cfg_reg) {
+                       printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n");
+                       return(0);
+               }
+
+               cs->subtyp = AVM_FRITZ_PCI;
+       } else {
+               printk(KERN_WARNING "FritzPCI: No PCI card found\n");
+               return(0);
+       }
+
+       cs->irq_flags |= IRQF_SHARED;
+
+       return (1);
+}
+
+#endif /* CONFIG_PCI */
+
+int __devinit
+setup_avm_pcipnp(struct IsdnCard *card)
+{
+       struct IsdnCardState *cs = card->cs;
+       char tmp[64];
+       int rc;
+
+       strcpy(tmp, avm_pci_rev);
+       printk(KERN_INFO "HiSax: AVM PCI driver Rev. %s\n", HiSax_getrev(tmp));
+
+       if (cs->typ != ISDN_CTYPE_FRITZPCI)
+               return (0);
+
+       if (card->para[1]) {
+               /* old manual method */
+               cs->hw.avm.cfg_reg = card->para[1];
+               cs->irq = card->para[0];
+               cs->subtyp = AVM_FRITZ_PNP;
+               goto ready;
+       }
+
+       rc = avm_pnp_setup(cs);
+       if (rc < 1)
+               return (0);
+       if (rc == 2)
+               goto ready;
+
+       rc = avm_pci_setup(cs);
+       if (rc < 1)
+               return (0);
+
+ready:
+       return avm_setup_rest(cs);
+}
index 6339bb443f624e56f4fbfe97b3f400d968e5d8ac..99ef3b43fcd79ebf276dfcd6ce48c0b60f80433f 100644 (file)
@@ -20,8 +20,6 @@
 #include <linux/pci.h>
 #include "bkm_ax.h"
 
-#ifdef CONFIG_PCI
-
 #define        ATTEMPT_PCI_REMAPPING   /* Required for PLX rev 1 */
 
 extern const char *CardType[];
@@ -279,12 +277,9 @@ static u_char pci_bus __devinitdata = 0;
 static u_char pci_device_fn __devinitdata = 0;
 static u_char pci_irq __devinitdata = 0;
 
-#endif /* CONFIG_PCI */
-
 int __devinit
 setup_sct_quadro(struct IsdnCard *card)
 {
-#ifdef CONFIG_PCI
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
        u_int found = 0;
@@ -442,7 +437,4 @@ setup_sct_quadro(struct IsdnCard *card)
                sct_quadro_subtypes[cs->subtyp],
                readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ID));
        return (1);
-#else
-       printk(KERN_ERR "HiSax: bkm_a8 only supported on PCI Systems\n");
-#endif /* CONFIG_PCI */
 }
index 6eebeb441bfd1ec7482a9b42bbdfd198c65acf86..82674507874647a07504e295c1a890962ce2dd98 100644 (file)
@@ -25,8 +25,6 @@
 #include <linux/pci.h>
 #include <linux/isapnp.h>
 
-extern const char *CardType[];
-
 static const char *Diva_revision = "$Revision: 1.33.2.6 $";
 
 #define byteout(addr,val) outb(val,addr)
@@ -906,225 +904,15 @@ Diva_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return(0);
 }
 
-static struct pci_dev *dev_diva __devinitdata = NULL;
-static struct pci_dev *dev_diva_u __devinitdata = NULL;
-static struct pci_dev *dev_diva201 __devinitdata = NULL;
-static struct pci_dev *dev_diva202 __devinitdata = NULL;
-
-#ifdef __ISAPNP__
-static struct isapnp_device_id diva_ids[] __devinitdata = {
-       { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
-         ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), 
-         (unsigned long) "Diva picola" },
-       { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
-         ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x51), 
-         (unsigned long) "Diva picola" },
-       { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
-         ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), 
-         (unsigned long) "Diva 2.0" },
-       { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
-         ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x71), 
-         (unsigned long) "Diva 2.0" },
-       { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
-         ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), 
-         (unsigned long) "Diva 2.01" },
-       { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
-         ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0xA1), 
-         (unsigned long) "Diva 2.01" },
-       { 0, }
-};
-
-static struct isapnp_device_id *ipid __devinitdata = &diva_ids[0];
-static struct pnp_card *pnp_c __devinitdata = NULL;
-#endif
-
-
-int __devinit
-setup_diva(struct IsdnCard *card)
+static int __devinit setup_diva_common(struct IsdnCardState *cs)
 {
-       int bytecnt = 8;
+       int bytecnt;
        u_char val;
-       struct IsdnCardState *cs = card->cs;
-       char tmp[64];
-
-       strcpy(tmp, Diva_revision);
-       printk(KERN_INFO "HiSax: Eicon.Diehl Diva driver Rev. %s\n", HiSax_getrev(tmp));
-       if (cs->typ != ISDN_CTYPE_DIEHLDIVA)
-               return(0);
-       cs->hw.diva.status = 0;
-       if (card->para[1]) {
-               cs->hw.diva.ctrl_reg = 0;
-               cs->hw.diva.cfg_reg = card->para[1];
-               val = readreg(cs->hw.diva.cfg_reg + DIVA_IPAC_ADR,
-                       cs->hw.diva.cfg_reg + DIVA_IPAC_DATA, IPAC_ID);
-               printk(KERN_INFO "Diva: IPAC version %x\n", val);
-               if ((val == 1) || (val==2)) {
-                       cs->subtyp = DIVA_IPAC_ISA;
-                       cs->hw.diva.ctrl = 0;
-                       cs->hw.diva.isac = card->para[1] + DIVA_IPAC_DATA;
-                       cs->hw.diva.hscx = card->para[1] + DIVA_IPAC_DATA;
-                       cs->hw.diva.isac_adr = card->para[1] + DIVA_IPAC_ADR;
-                       cs->hw.diva.hscx_adr = card->para[1] + DIVA_IPAC_ADR;
-                       test_and_set_bit(HW_IPAC, &cs->HW_Flags);
-               } else {
-                       cs->subtyp = DIVA_ISA;
-                       cs->hw.diva.ctrl = card->para[1] + DIVA_ISA_CTRL;
-                       cs->hw.diva.isac = card->para[1] + DIVA_ISA_ISAC_DATA;
-                       cs->hw.diva.hscx = card->para[1] + DIVA_HSCX_DATA;
-                       cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR;
-                       cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR;
-               }
-               cs->irq = card->para[0];
-       } else {
-#ifdef __ISAPNP__
-               if (isapnp_present()) {
-                       struct pnp_dev *pnp_d;
-                       while(ipid->card_vendor) {
-                               if ((pnp_c = pnp_find_card(ipid->card_vendor,
-                                       ipid->card_device, pnp_c))) {
-                                       pnp_d = NULL;
-                                       if ((pnp_d = pnp_find_dev(pnp_c,
-                                               ipid->vendor, ipid->function, pnp_d))) {
-                                               int err;
-
-                                               printk(KERN_INFO "HiSax: %s detected\n",
-                                                       (char *)ipid->driver_data);
-                                               pnp_disable_dev(pnp_d);
-                                               err = pnp_activate_dev(pnp_d);
-                                               if (err<0) {
-                                                       printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
-                                                               __FUNCTION__, err);
-                                                       return(0);
-                                               }
-                                               card->para[1] = pnp_port_start(pnp_d, 0);
-                                               card->para[0] = pnp_irq(pnp_d, 0);
-                                               if (!card->para[0] || !card->para[1]) {
-                                                       printk(KERN_ERR "Diva PnP:some resources are missing %ld/%lx\n",
-                                                               card->para[0], card->para[1]);
-                                                       pnp_disable_dev(pnp_d); 
-                                                       return(0);
-                                               }
-                                               cs->hw.diva.cfg_reg  = card->para[1];
-                                               cs->irq = card->para[0];
-                                               if (ipid->function == ISAPNP_FUNCTION(0xA1)) {
-                                                       cs->subtyp = DIVA_IPAC_ISA;
-                                                       cs->hw.diva.ctrl = 0;
-                                                       cs->hw.diva.isac =
-                                                               card->para[1] + DIVA_IPAC_DATA;
-                                                       cs->hw.diva.hscx =
-                                                               card->para[1] + DIVA_IPAC_DATA;
-                                                       cs->hw.diva.isac_adr =
-                                                               card->para[1] + DIVA_IPAC_ADR;
-                                                       cs->hw.diva.hscx_adr =
-                                                               card->para[1] + DIVA_IPAC_ADR;
-                                                       test_and_set_bit(HW_IPAC, &cs->HW_Flags);
-                                               } else {
-                                                       cs->subtyp = DIVA_ISA;
-                                                       cs->hw.diva.ctrl =
-                                                               card->para[1] + DIVA_ISA_CTRL;
-                                                       cs->hw.diva.isac =
-                                                               card->para[1] + DIVA_ISA_ISAC_DATA;
-                                                       cs->hw.diva.hscx =
-                                                               card->para[1] + DIVA_HSCX_DATA;
-                                                       cs->hw.diva.isac_adr =
-                                                               card->para[1] + DIVA_ISA_ISAC_ADR;
-                                                       cs->hw.diva.hscx_adr =
-                                                               card->para[1] + DIVA_HSCX_ADR;
-                                               }
-                                               goto ready;
-                                       } else {
-                                               printk(KERN_ERR "Diva PnP: PnP error card found, no device\n");
-                                               return(0);
-                                       }
-                               }
-                               ipid++;
-                               pnp_c=NULL;
-                       } 
-                       if (!ipid->card_vendor) {
-                               printk(KERN_INFO "Diva PnP: no ISAPnP card found\n");
-                       }
-               }
-#endif
-#ifdef CONFIG_PCI
-               cs->subtyp = 0;
-               if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON,
-                       PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) {
-                       if (pci_enable_device(dev_diva))
-                               return(0);
-                       cs->subtyp = DIVA_PCI;
-                       cs->irq = dev_diva->irq;
-                       cs->hw.diva.cfg_reg = pci_resource_start(dev_diva, 2);
-               } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_ID_EICON,
-                       PCI_DEVICE_ID_EICON_DIVA20_U, dev_diva_u))) {
-                       if (pci_enable_device(dev_diva_u))
-                               return(0);
-                       cs->subtyp = DIVA_PCI;
-                       cs->irq = dev_diva_u->irq;
-                       cs->hw.diva.cfg_reg = pci_resource_start(dev_diva_u, 2);
-               } else if ((dev_diva201 = pci_find_device(PCI_VENDOR_ID_EICON,
-                       PCI_DEVICE_ID_EICON_DIVA201, dev_diva201))) {
-                       if (pci_enable_device(dev_diva201))
-                               return(0);
-                       cs->subtyp = DIVA_IPAC_PCI;
-                       cs->irq = dev_diva201->irq;
-                       cs->hw.diva.pci_cfg =
-                               (ulong) ioremap(pci_resource_start(dev_diva201, 0), 4096);
-                       cs->hw.diva.cfg_reg =
-                               (ulong) ioremap(pci_resource_start(dev_diva201, 1), 4096);
-               } else if ((dev_diva202 = pci_find_device(PCI_VENDOR_ID_EICON,
-                       PCI_DEVICE_ID_EICON_DIVA202, dev_diva202))) {
-                       if (pci_enable_device(dev_diva202))
-                               return(0);
-                       cs->subtyp = DIVA_IPACX_PCI;
-                       cs->irq = dev_diva202->irq;
-                       cs->hw.diva.pci_cfg =
-                               (ulong) ioremap(pci_resource_start(dev_diva202, 0), 4096);
-                       cs->hw.diva.cfg_reg =
-                               (ulong) ioremap(pci_resource_start(dev_diva202, 1), 4096);
-               } else {
-                       printk(KERN_WARNING "Diva: No PCI card found\n");
-                       return(0);
-               }
-
-               if (!cs->irq) {
-                       printk(KERN_WARNING "Diva: No IRQ for PCI card found\n");
-                       iounmap_diva(cs);
-                       return(0);
-               }
-
-               if (!cs->hw.diva.cfg_reg) {
-                       printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n");
-                       iounmap_diva(cs);
-                       return(0);
-               }
-               cs->irq_flags |= IRQF_SHARED;
-#else
-               printk(KERN_WARNING "Diva: cfgreg 0 and NO_PCI_BIOS\n");
-               printk(KERN_WARNING "Diva: unable to config DIVA PCI\n");
-               return (0);
-#endif /* CONFIG_PCI */
-               if ((cs->subtyp == DIVA_IPAC_PCI) ||
-                   (cs->subtyp == DIVA_IPACX_PCI)   ) {
-                       cs->hw.diva.ctrl = 0;
-                       cs->hw.diva.isac = 0;
-                       cs->hw.diva.hscx = 0;
-                       cs->hw.diva.isac_adr = 0;
-                       cs->hw.diva.hscx_adr = 0;
-                       test_and_set_bit(HW_IPAC, &cs->HW_Flags);
-                       bytecnt = 0;
-               } else {
-                       cs->hw.diva.ctrl = cs->hw.diva.cfg_reg + DIVA_PCI_CTRL;
-                       cs->hw.diva.isac = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_DATA;
-                       cs->hw.diva.hscx = cs->hw.diva.cfg_reg + DIVA_HSCX_DATA;
-                       cs->hw.diva.isac_adr = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_ADR;
-                       cs->hw.diva.hscx_adr = cs->hw.diva.cfg_reg + DIVA_HSCX_ADR;
-                       bytecnt = 32;
-               }
-       }
 
-#ifdef __ISAPNP__
-ready:
-#endif
+       if ((cs->subtyp == DIVA_ISA) || (cs->subtyp == DIVA_IPAC_ISA))
+               bytecnt = 8;
+       else
+               bytecnt = 32;
 
        printk(KERN_INFO
                "Diva: %s card configured at %#lx IRQ %d\n",
@@ -1145,7 +933,7 @@ ready:
                if (!request_region(cs->hw.diva.cfg_reg, bytecnt, "diva isdn")) {
                        printk(KERN_WARNING
                               "HiSax: %s config port %lx-%lx already in use\n",
-                              CardType[card->typ],
+                              "diva",
                               cs->hw.diva.cfg_reg,
                               cs->hw.diva.cfg_reg + bytecnt);
                        iounmap_diva(cs);
@@ -1206,3 +994,290 @@ ready:
        }
        return (1);
 }
+
+#ifdef CONFIG_ISA
+
+static int __devinit setup_diva_isa(struct IsdnCard *card)
+{
+       struct IsdnCardState *cs = card->cs;
+       u_char val;
+
+       if (!card->para[1])
+               return (-1);    /* card not found; continue search */
+
+       cs->hw.diva.ctrl_reg = 0;
+       cs->hw.diva.cfg_reg = card->para[1];
+       val = readreg(cs->hw.diva.cfg_reg + DIVA_IPAC_ADR,
+               cs->hw.diva.cfg_reg + DIVA_IPAC_DATA, IPAC_ID);
+       printk(KERN_INFO "Diva: IPAC version %x\n", val);
+       if ((val == 1) || (val==2)) {
+               cs->subtyp = DIVA_IPAC_ISA;
+               cs->hw.diva.ctrl = 0;
+               cs->hw.diva.isac = card->para[1] + DIVA_IPAC_DATA;
+               cs->hw.diva.hscx = card->para[1] + DIVA_IPAC_DATA;
+               cs->hw.diva.isac_adr = card->para[1] + DIVA_IPAC_ADR;
+               cs->hw.diva.hscx_adr = card->para[1] + DIVA_IPAC_ADR;
+               test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+       } else {
+               cs->subtyp = DIVA_ISA;
+               cs->hw.diva.ctrl = card->para[1] + DIVA_ISA_CTRL;
+               cs->hw.diva.isac = card->para[1] + DIVA_ISA_ISAC_DATA;
+               cs->hw.diva.hscx = card->para[1] + DIVA_HSCX_DATA;
+               cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR;
+               cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR;
+       }
+       cs->irq = card->para[0];
+
+       return (1);             /* card found */
+}
+
+#else  /* if !CONFIG_ISA */
+
+static int __devinit setup_diva_isa(struct IsdnCard *card)
+{
+       return (-1);    /* card not found; continue search */
+}
+
+#endif /* CONFIG_ISA */
+
+#ifdef __ISAPNP__
+static struct isapnp_device_id diva_ids[] __devinitdata = {
+       { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
+         ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), 
+         (unsigned long) "Diva picola" },
+       { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
+         ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x51), 
+         (unsigned long) "Diva picola" },
+       { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
+         ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), 
+         (unsigned long) "Diva 2.0" },
+       { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
+         ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x71), 
+         (unsigned long) "Diva 2.0" },
+       { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
+         ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), 
+         (unsigned long) "Diva 2.01" },
+       { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
+         ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0xA1), 
+         (unsigned long) "Diva 2.01" },
+       { 0, }
+};
+
+static struct isapnp_device_id *ipid __devinitdata = &diva_ids[0];
+static struct pnp_card *pnp_c __devinitdata = NULL;
+
+static int __devinit setup_diva_isapnp(struct IsdnCard *card)
+{
+       struct IsdnCardState *cs = card->cs;
+       struct pnp_dev *pnp_d;
+
+       if (!isapnp_present())
+               return (-1);    /* card not found; continue search */
+
+       while(ipid->card_vendor) {
+               if ((pnp_c = pnp_find_card(ipid->card_vendor,
+                       ipid->card_device, pnp_c))) {
+                       pnp_d = NULL;
+                       if ((pnp_d = pnp_find_dev(pnp_c,
+                               ipid->vendor, ipid->function, pnp_d))) {
+                               int err;
+
+                               printk(KERN_INFO "HiSax: %s detected\n",
+                                       (char *)ipid->driver_data);
+                               pnp_disable_dev(pnp_d);
+                               err = pnp_activate_dev(pnp_d);
+                               if (err<0) {
+                                       printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+                                               __FUNCTION__, err);
+                                       return(0);
+                               }
+                               card->para[1] = pnp_port_start(pnp_d, 0);
+                               card->para[0] = pnp_irq(pnp_d, 0);
+                               if (!card->para[0] || !card->para[1]) {
+                                       printk(KERN_ERR "Diva PnP:some resources are missing %ld/%lx\n",
+                                               card->para[0], card->para[1]);
+                                       pnp_disable_dev(pnp_d); 
+                                       return(0);
+                               }
+                               cs->hw.diva.cfg_reg  = card->para[1];
+                               cs->irq = card->para[0];
+                               if (ipid->function == ISAPNP_FUNCTION(0xA1)) {
+                                       cs->subtyp = DIVA_IPAC_ISA;
+                                       cs->hw.diva.ctrl = 0;
+                                       cs->hw.diva.isac =
+                                               card->para[1] + DIVA_IPAC_DATA;
+                                       cs->hw.diva.hscx =
+                                               card->para[1] + DIVA_IPAC_DATA;
+                                       cs->hw.diva.isac_adr =
+                                               card->para[1] + DIVA_IPAC_ADR;
+                                       cs->hw.diva.hscx_adr =
+                                               card->para[1] + DIVA_IPAC_ADR;
+                                       test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+                               } else {
+                                       cs->subtyp = DIVA_ISA;
+                                       cs->hw.diva.ctrl =
+                                               card->para[1] + DIVA_ISA_CTRL;
+                                       cs->hw.diva.isac =
+                                               card->para[1] + DIVA_ISA_ISAC_DATA;
+                                       cs->hw.diva.hscx =
+                                               card->para[1] + DIVA_HSCX_DATA;
+                                       cs->hw.diva.isac_adr =
+                                               card->para[1] + DIVA_ISA_ISAC_ADR;
+                                       cs->hw.diva.hscx_adr =
+                                               card->para[1] + DIVA_HSCX_ADR;
+                               }
+                               return (1);             /* card found */
+                       } else {
+                               printk(KERN_ERR "Diva PnP: PnP error card found, no device\n");
+                               return(0);
+                       }
+               }
+               ipid++;
+               pnp_c=NULL;
+       } 
+
+       return (-1);    /* card not found; continue search */
+}
+
+#else  /* if !ISAPNP */
+
+static int __devinit setup_diva_isapnp(struct IsdnCard *card)
+{
+       return (-1);    /* card not found; continue search */
+}
+
+#endif /* ISAPNP */
+
+#ifdef CONFIG_PCI
+static struct pci_dev *dev_diva __devinitdata = NULL;
+static struct pci_dev *dev_diva_u __devinitdata = NULL;
+static struct pci_dev *dev_diva201 __devinitdata = NULL;
+static struct pci_dev *dev_diva202 __devinitdata = NULL;
+
+static int __devinit setup_diva_pci(struct IsdnCard *card)
+{
+       struct IsdnCardState *cs = card->cs;
+
+       cs->subtyp = 0;
+       if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON,
+               PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) {
+               if (pci_enable_device(dev_diva))
+                       return(0);
+               cs->subtyp = DIVA_PCI;
+               cs->irq = dev_diva->irq;
+               cs->hw.diva.cfg_reg = pci_resource_start(dev_diva, 2);
+       } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_ID_EICON,
+               PCI_DEVICE_ID_EICON_DIVA20_U, dev_diva_u))) {
+               if (pci_enable_device(dev_diva_u))
+                       return(0);
+               cs->subtyp = DIVA_PCI;
+               cs->irq = dev_diva_u->irq;
+               cs->hw.diva.cfg_reg = pci_resource_start(dev_diva_u, 2);
+       } else if ((dev_diva201 = pci_find_device(PCI_VENDOR_ID_EICON,
+               PCI_DEVICE_ID_EICON_DIVA201, dev_diva201))) {
+               if (pci_enable_device(dev_diva201))
+                       return(0);
+               cs->subtyp = DIVA_IPAC_PCI;
+               cs->irq = dev_diva201->irq;
+               cs->hw.diva.pci_cfg =
+                       (ulong) ioremap(pci_resource_start(dev_diva201, 0), 4096);
+               cs->hw.diva.cfg_reg =
+                       (ulong) ioremap(pci_resource_start(dev_diva201, 1), 4096);
+       } else if ((dev_diva202 = pci_find_device(PCI_VENDOR_ID_EICON,
+               PCI_DEVICE_ID_EICON_DIVA202, dev_diva202))) {
+               if (pci_enable_device(dev_diva202))
+                       return(0);
+               cs->subtyp = DIVA_IPACX_PCI;
+               cs->irq = dev_diva202->irq;
+               cs->hw.diva.pci_cfg =
+                       (ulong) ioremap(pci_resource_start(dev_diva202, 0), 4096);
+               cs->hw.diva.cfg_reg =
+                       (ulong) ioremap(pci_resource_start(dev_diva202, 1), 4096);
+       } else {
+               return (-1);    /* card not found; continue search */
+       }
+
+       if (!cs->irq) {
+               printk(KERN_WARNING "Diva: No IRQ for PCI card found\n");
+               iounmap_diva(cs);
+               return(0);
+       }
+
+       if (!cs->hw.diva.cfg_reg) {
+               printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n");
+               iounmap_diva(cs);
+               return(0);
+       }
+       cs->irq_flags |= IRQF_SHARED;
+
+       if ((cs->subtyp == DIVA_IPAC_PCI) ||
+           (cs->subtyp == DIVA_IPACX_PCI)   ) {
+               cs->hw.diva.ctrl = 0;
+               cs->hw.diva.isac = 0;
+               cs->hw.diva.hscx = 0;
+               cs->hw.diva.isac_adr = 0;
+               cs->hw.diva.hscx_adr = 0;
+               test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+       } else {
+               cs->hw.diva.ctrl = cs->hw.diva.cfg_reg + DIVA_PCI_CTRL;
+               cs->hw.diva.isac = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_DATA;
+               cs->hw.diva.hscx = cs->hw.diva.cfg_reg + DIVA_HSCX_DATA;
+               cs->hw.diva.isac_adr = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_ADR;
+               cs->hw.diva.hscx_adr = cs->hw.diva.cfg_reg + DIVA_HSCX_ADR;
+       }
+
+       return (1);             /* card found */
+}
+
+#else  /* if !CONFIG_PCI */
+
+static int __devinit setup_diva_pci(struct IsdnCard *card)
+{
+       return (-1);    /* card not found; continue search */
+}
+
+#endif /* CONFIG_PCI */
+
+int __devinit
+setup_diva(struct IsdnCard *card)
+{
+       int rc, have_card = 0;
+       struct IsdnCardState *cs = card->cs;
+       char tmp[64];
+
+       strcpy(tmp, Diva_revision);
+       printk(KERN_INFO "HiSax: Eicon.Diehl Diva driver Rev. %s\n", HiSax_getrev(tmp));
+       if (cs->typ != ISDN_CTYPE_DIEHLDIVA)
+               return(0);
+       cs->hw.diva.status = 0;
+
+       rc = setup_diva_isa(card);
+       if (!rc)
+               return rc;
+       if (rc > 0) {
+               have_card = 1;
+               goto ready;
+       }
+
+       rc = setup_diva_isapnp(card);
+       if (!rc)
+               return rc;
+       if (rc > 0) {
+               have_card = 1;
+               goto ready;
+       }
+
+       rc = setup_diva_pci(card);
+       if (!rc)
+               return rc;
+       if (rc > 0)
+               have_card = 1;
+
+ready:
+       if (!have_card) {
+               printk(KERN_WARNING "Diva: No ISA, ISAPNP or PCI card found\n");
+               return(0);
+       }
+
+       return setup_diva_common(card->cs);
+}
index fab3e4ea05957c1b7abe9fa147011d871355c045..948a9b290fd1146933a9d1cb38a9d6993db989a2 100644 (file)
@@ -30,8 +30,6 @@
 #include <linux/serial.h>
 #include <linux/serial_reg.h>
 
-extern const char *CardType[];
-
 static const char *Elsa_revision = "$Revision: 2.32.2.4 $";
 static const char *Elsa_Types[] =
 {"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro",
@@ -832,8 +830,75 @@ probe_elsa(struct IsdnCardState *cs)
        return (CARD_portlist[i]);
 }
 
-static         struct pci_dev *dev_qs1000 __devinitdata = NULL;
-static         struct pci_dev *dev_qs3000 __devinitdata = NULL;
+static int __devinit
+setup_elsa_isa(struct IsdnCard *card)
+{
+       struct IsdnCardState *cs = card->cs;
+       u_char val;
+
+       cs->hw.elsa.base = card->para[0];
+       printk(KERN_INFO "Elsa: Microlink IO probing\n");
+       if (cs->hw.elsa.base) {
+               if (!(cs->subtyp = probe_elsa_adr(cs->hw.elsa.base,
+                                                 cs->typ))) {
+                       printk(KERN_WARNING
+                              "Elsa: no Elsa Microlink at %#lx\n",
+                              cs->hw.elsa.base);
+                       return (0);
+               }
+       } else
+               cs->hw.elsa.base = probe_elsa(cs);
+
+       if (!cs->hw.elsa.base) {
+               printk(KERN_WARNING
+                      "No Elsa Microlink found\n");
+               return (0);
+       }
+
+       cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
+       cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
+       cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
+       cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
+       cs->hw.elsa.itac = cs->hw.elsa.base + ELSA_ITAC;
+       cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
+       cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
+       cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
+       val = bytein(cs->hw.elsa.cfg);
+       if (cs->subtyp == ELSA_PC) {
+               const u_char CARD_IrqTab[8] =
+               {7, 3, 5, 9, 0, 0, 0, 0};
+               cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PC) >> 2];
+       } else if (cs->subtyp == ELSA_PCC8) {
+               const u_char CARD_IrqTab[8] =
+               {7, 3, 5, 9, 0, 0, 0, 0};
+               cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PCC8) >> 4];
+       } else {
+               const u_char CARD_IrqTab[8] =
+               {15, 10, 15, 3, 11, 5, 11, 9};
+               cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX) >> 3];
+       }
+       val = bytein(cs->hw.elsa.ale) & ELSA_HW_RELEASE;
+       if (val < 3)
+               val |= 8;
+       val += 'A' - 3;
+       if (val == 'B' || val == 'C')
+               val ^= 1;
+       if ((cs->subtyp == ELSA_PCFPRO) && (val = 'G'))
+               val = 'C';
+       printk(KERN_INFO
+              "Elsa: %s found at %#lx Rev.:%c IRQ %d\n",
+              Elsa_Types[cs->subtyp],
+              cs->hw.elsa.base,
+              val, cs->irq);
+       val = bytein(cs->hw.elsa.ale) & ELSA_S0_POWER_BAD;
+       if (val) {
+               printk(KERN_WARNING
+                  "Elsa: Microlink S0 bus power bad\n");
+               cs->hw.elsa.status |= ELSA_BAD_PWR;
+       }
+
+       return (1);
+}
 
 #ifdef __ISAPNP__
 static struct isapnp_device_id elsa_ids[] __devinitdata = {
@@ -848,233 +913,194 @@ static struct isapnp_device_id elsa_ids[] __devinitdata = {
 
 static struct isapnp_device_id *ipid __devinitdata = &elsa_ids[0];
 static struct pnp_card *pnp_c __devinitdata = NULL;
-#endif
+#endif /* __ISAPNP__ */
 
-int __devinit
-setup_elsa(struct IsdnCard *card)
+static int __devinit
+setup_elsa_isapnp(struct IsdnCard *card)
 {
-       int bytecnt;
-       u_char val;
        struct IsdnCardState *cs = card->cs;
-       char tmp[64];
 
-       strcpy(tmp, Elsa_revision);
-       printk(KERN_INFO "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp));
-       cs->hw.elsa.ctrl_reg = 0;
-       cs->hw.elsa.status = 0;
-       cs->hw.elsa.MFlag = 0;
-       cs->subtyp = 0;
-       if (cs->typ == ISDN_CTYPE_ELSA) {
-               cs->hw.elsa.base = card->para[0];
-               printk(KERN_INFO "Elsa: Microlink IO probing\n");
-               if (cs->hw.elsa.base) {
-                       if (!(cs->subtyp = probe_elsa_adr(cs->hw.elsa.base,
-                                                         cs->typ))) {
-                               printk(KERN_WARNING
-                                      "Elsa: no Elsa Microlink at %#lx\n",
-                                      cs->hw.elsa.base);
-                               return (0);
-                       }
-               } else
-                       cs->hw.elsa.base = probe_elsa(cs);
-               if (cs->hw.elsa.base) {
-                       cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
-                       cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
-                       cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
-                       cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
-                       cs->hw.elsa.itac = cs->hw.elsa.base + ELSA_ITAC;
-                       cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
-                       cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
-                       cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
-                       val = bytein(cs->hw.elsa.cfg);
-                       if (cs->subtyp == ELSA_PC) {
-                               const u_char CARD_IrqTab[8] =
-                               {7, 3, 5, 9, 0, 0, 0, 0};
-                               cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PC) >> 2];
-                       } else if (cs->subtyp == ELSA_PCC8) {
-                               const u_char CARD_IrqTab[8] =
-                               {7, 3, 5, 9, 0, 0, 0, 0};
-                               cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PCC8) >> 4];
-                       } else {
-                               const u_char CARD_IrqTab[8] =
-                               {15, 10, 15, 3, 11, 5, 11, 9};
-                               cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX) >> 3];
-                       }
-                       val = bytein(cs->hw.elsa.ale) & ELSA_HW_RELEASE;
-                       if (val < 3)
-                               val |= 8;
-                       val += 'A' - 3;
-                       if (val == 'B' || val == 'C')
-                               val ^= 1;
-                       if ((cs->subtyp == ELSA_PCFPRO) && (val = 'G'))
-                               val = 'C';
-                       printk(KERN_INFO
-                              "Elsa: %s found at %#lx Rev.:%c IRQ %d\n",
-                              Elsa_Types[cs->subtyp],
-                              cs->hw.elsa.base,
-                              val, cs->irq);
-                       val = bytein(cs->hw.elsa.ale) & ELSA_S0_POWER_BAD;
-                       if (val) {
-                               printk(KERN_WARNING
-                                  "Elsa: Microlink S0 bus power bad\n");
-                               cs->hw.elsa.status |= ELSA_BAD_PWR;
-                       }
-               } else {
-                       printk(KERN_WARNING
-                              "No Elsa Microlink found\n");
-                       return (0);
-               }
-       } else if (cs->typ == ISDN_CTYPE_ELSA_PNP) {
 #ifdef __ISAPNP__
-               if (!card->para[1] && isapnp_present()) {
-                       struct pnp_dev *pnp_d;
-                       while(ipid->card_vendor) {
-                               if ((pnp_c = pnp_find_card(ipid->card_vendor,
-                                       ipid->card_device, pnp_c))) {
-                                       pnp_d = NULL;
-                                       if ((pnp_d = pnp_find_dev(pnp_c,
-                                               ipid->vendor, ipid->function, pnp_d))) {
-                                               int err;
-
-                                               printk(KERN_INFO "HiSax: %s detected\n",
-                                                       (char *)ipid->driver_data);
+       if (!card->para[1] && isapnp_present()) {
+               struct pnp_dev *pnp_d;
+               while(ipid->card_vendor) {
+                       if ((pnp_c = pnp_find_card(ipid->card_vendor,
+                               ipid->card_device, pnp_c))) {
+                               pnp_d = NULL;
+                               if ((pnp_d = pnp_find_dev(pnp_c,
+                                       ipid->vendor, ipid->function, pnp_d))) {
+                                       int err;
+
+                                       printk(KERN_INFO "HiSax: %s detected\n",
+                                               (char *)ipid->driver_data);
+                                       pnp_disable_dev(pnp_d);
+                                       err = pnp_activate_dev(pnp_d);
+                                       if (err<0) {
+                                               printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+                                                       __FUNCTION__, err);
+                                               return(0);
+                                       }
+                                       card->para[1] = pnp_port_start(pnp_d, 0);
+                                       card->para[0] = pnp_irq(pnp_d, 0);
+
+                                       if (!card->para[0] || !card->para[1]) {
+                                               printk(KERN_ERR "Elsa PnP:some resources are missing %ld/%lx\n",
+                                                       card->para[0], card->para[1]);
                                                pnp_disable_dev(pnp_d);
-                                               err = pnp_activate_dev(pnp_d);
-                                               if (err<0) {
-                                                       printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
-                                                               __FUNCTION__, err);
-                                                       return(0);
-                                               }
-                                               card->para[1] = pnp_port_start(pnp_d, 0);
-                                               card->para[0] = pnp_irq(pnp_d, 0);
-
-                                               if (!card->para[0] || !card->para[1]) {
-                                                       printk(KERN_ERR "Elsa PnP:some resources are missing %ld/%lx\n",
-                                                               card->para[0], card->para[1]);
-                                                       pnp_disable_dev(pnp_d);
-                                                       return(0);
-                                               }
-                                               if (ipid->function == ISAPNP_FUNCTION(0x133))
-                                                       cs->subtyp = ELSA_QS1000;
-                                               else
-                                                       cs->subtyp = ELSA_QS3000;
-                                               break;
-                                       } else {
-                                               printk(KERN_ERR "Elsa PnP: PnP error card found, no device\n");
                                                return(0);
                                        }
+                                       if (ipid->function == ISAPNP_FUNCTION(0x133))
+                                               cs->subtyp = ELSA_QS1000;
+                                       else
+                                               cs->subtyp = ELSA_QS3000;
+                                       break;
+                               } else {
+                                       printk(KERN_ERR "Elsa PnP: PnP error card found, no device\n");
+                                       return(0);
                                }
-                               ipid++;
-                               pnp_c=NULL;
-                       } 
-                       if (!ipid->card_vendor) {
-                               printk(KERN_INFO "Elsa PnP: no ISAPnP card found\n");
-                               return(0);
                        }
+                       ipid++;
+                       pnp_c=NULL;
+               } 
+               if (!ipid->card_vendor) {
+                       printk(KERN_INFO "Elsa PnP: no ISAPnP card found\n");
+                       return(0);
                }
-#endif
-               if (card->para[1] && card->para[0]) { 
-                       cs->hw.elsa.base = card->para[1];
-                       cs->irq = card->para[0];
-                       if (!cs->subtyp)
-                               cs->subtyp = ELSA_QS1000;
-               } else {
-                       printk(KERN_ERR "Elsa PnP: no parameter\n");
-               }
-               cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
-               cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
-               cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
-               cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
-               cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
-               cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
-               cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
-               printk(KERN_INFO
-                      "Elsa: %s defined at %#lx IRQ %d\n",
-                      Elsa_Types[cs->subtyp],
-                      cs->hw.elsa.base,
-                      cs->irq);
-       } else if (cs->typ == ISDN_CTYPE_ELSA_PCMCIA) {
+       }
+#endif /* __ISAPNP__ */
+
+       if (card->para[1] && card->para[0]) { 
                cs->hw.elsa.base = card->para[1];
                cs->irq = card->para[0];
-               val = readreg(cs->hw.elsa.base + 0, cs->hw.elsa.base + 2, IPAC_ID);
-               if ((val == 1) || (val == 2)) { /* IPAC version 1.1/1.2 */
-                       cs->subtyp = ELSA_PCMCIA_IPAC;
-                       cs->hw.elsa.ale = cs->hw.elsa.base + 0;
-                       cs->hw.elsa.isac = cs->hw.elsa.base + 2;
-                       cs->hw.elsa.hscx = cs->hw.elsa.base + 2;
-                       test_and_set_bit(HW_IPAC, &cs->HW_Flags);
-               } else {
-                       cs->subtyp = ELSA_PCMCIA;
-                       cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE_PCM;
-                       cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC_PCM;
-                       cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
-               }
-               cs->hw.elsa.timer = 0;
-               cs->hw.elsa.trig = 0;
-               cs->hw.elsa.ctrl = 0;
-               cs->irq_flags |= IRQF_SHARED;
-               printk(KERN_INFO
-                      "Elsa: %s defined at %#lx IRQ %d\n",
-                      Elsa_Types[cs->subtyp],
-                      cs->hw.elsa.base,
-                      cs->irq);
-       } else if (cs->typ == ISDN_CTYPE_ELSA_PCI) {
+               if (!cs->subtyp)
+                       cs->subtyp = ELSA_QS1000;
+       } else {
+               printk(KERN_ERR "Elsa PnP: no parameter\n");
+       }
+       cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
+       cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
+       cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
+       cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
+       cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
+       cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
+       cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
+       printk(KERN_INFO
+              "Elsa: %s defined at %#lx IRQ %d\n",
+              Elsa_Types[cs->subtyp],
+              cs->hw.elsa.base,
+              cs->irq);
+
+       return (1);
+}
+
+static void __devinit
+setup_elsa_pcmcia(struct IsdnCard *card)
+{
+       struct IsdnCardState *cs = card->cs;
+       u_char val;
+
+       cs->hw.elsa.base = card->para[1];
+       cs->irq = card->para[0];
+       val = readreg(cs->hw.elsa.base + 0, cs->hw.elsa.base + 2, IPAC_ID);
+       if ((val == 1) || (val == 2)) { /* IPAC version 1.1/1.2 */
+               cs->subtyp = ELSA_PCMCIA_IPAC;
+               cs->hw.elsa.ale = cs->hw.elsa.base + 0;
+               cs->hw.elsa.isac = cs->hw.elsa.base + 2;
+               cs->hw.elsa.hscx = cs->hw.elsa.base + 2;
+               test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+       } else {
+               cs->subtyp = ELSA_PCMCIA;
+               cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE_PCM;
+               cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC_PCM;
+               cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
+       }
+       cs->hw.elsa.timer = 0;
+       cs->hw.elsa.trig = 0;
+       cs->hw.elsa.ctrl = 0;
+       cs->irq_flags |= IRQF_SHARED;
+       printk(KERN_INFO
+              "Elsa: %s defined at %#lx IRQ %d\n",
+              Elsa_Types[cs->subtyp],
+              cs->hw.elsa.base,
+              cs->irq);
+}
+
 #ifdef CONFIG_PCI
-               cs->subtyp = 0;
-               if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ID_ELSA,
-                       PCI_DEVICE_ID_ELSA_MICROLINK, dev_qs1000))) {
-                       if (pci_enable_device(dev_qs1000))
-                               return(0);
-                       cs->subtyp = ELSA_QS1000PCI;
-                       cs->irq = dev_qs1000->irq;
-                       cs->hw.elsa.cfg = pci_resource_start(dev_qs1000, 1);
-                       cs->hw.elsa.base = pci_resource_start(dev_qs1000, 3);
-               } else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ID_ELSA,
-                       PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) {
-                       if (pci_enable_device(dev_qs3000))
-                               return(0);
-                       cs->subtyp = ELSA_QS3000PCI;
-                       cs->irq = dev_qs3000->irq;
-                       cs->hw.elsa.cfg = pci_resource_start(dev_qs3000, 1);
-                       cs->hw.elsa.base = pci_resource_start(dev_qs3000, 3);
-               } else {
-                       printk(KERN_WARNING "Elsa: No PCI card found\n");
+static         struct pci_dev *dev_qs1000 __devinitdata = NULL;
+static         struct pci_dev *dev_qs3000 __devinitdata = NULL;
+
+static int __devinit
+setup_elsa_pci(struct IsdnCard *card)
+{
+       struct IsdnCardState *cs = card->cs;
+
+       cs->subtyp = 0;
+       if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ID_ELSA,
+               PCI_DEVICE_ID_ELSA_MICROLINK, dev_qs1000))) {
+               if (pci_enable_device(dev_qs1000))
                        return(0);
-               }
-               if (!cs->irq) {
-                       printk(KERN_WARNING "Elsa: No IRQ for PCI card found\n");
+               cs->subtyp = ELSA_QS1000PCI;
+               cs->irq = dev_qs1000->irq;
+               cs->hw.elsa.cfg = pci_resource_start(dev_qs1000, 1);
+               cs->hw.elsa.base = pci_resource_start(dev_qs1000, 3);
+       } else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ID_ELSA,
+               PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) {
+               if (pci_enable_device(dev_qs3000))
                        return(0);
-               }
+               cs->subtyp = ELSA_QS3000PCI;
+               cs->irq = dev_qs3000->irq;
+               cs->hw.elsa.cfg = pci_resource_start(dev_qs3000, 1);
+               cs->hw.elsa.base = pci_resource_start(dev_qs3000, 3);
+       } else {
+               printk(KERN_WARNING "Elsa: No PCI card found\n");
+               return(0);
+       }
+       if (!cs->irq) {
+               printk(KERN_WARNING "Elsa: No IRQ for PCI card found\n");
+               return(0);
+       }
+
+       if (!(cs->hw.elsa.base && cs->hw.elsa.cfg)) {
+               printk(KERN_WARNING "Elsa: No IO-Adr for PCI card found\n");
+               return(0);
+       }
+       if ((cs->hw.elsa.cfg & 0xff) || (cs->hw.elsa.base & 0xf)) {
+               printk(KERN_WARNING "Elsa: You may have a wrong PCI bios\n");
+               printk(KERN_WARNING "Elsa: If your system hangs now, read\n");
+               printk(KERN_WARNING "Elsa: Documentation/isdn/README.HiSax\n");
+       }
+       cs->hw.elsa.ale  = cs->hw.elsa.base;
+       cs->hw.elsa.isac = cs->hw.elsa.base +1;
+       cs->hw.elsa.hscx = cs->hw.elsa.base +1; 
+       test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+       cs->hw.elsa.timer = 0;
+       cs->hw.elsa.trig  = 0;
+       cs->irq_flags |= IRQF_SHARED;
+       printk(KERN_INFO
+              "Elsa: %s defined at %#lx/0x%x IRQ %d\n",
+              Elsa_Types[cs->subtyp],
+              cs->hw.elsa.base,
+              cs->hw.elsa.cfg,
+              cs->irq);
+
+       return (1);
+}
 
-               if (!(cs->hw.elsa.base && cs->hw.elsa.cfg)) {
-                       printk(KERN_WARNING "Elsa: No IO-Adr for PCI card found\n");
-                       return(0);
-               }
-               if ((cs->hw.elsa.cfg & 0xff) || (cs->hw.elsa.base & 0xf)) {
-                       printk(KERN_WARNING "Elsa: You may have a wrong PCI bios\n");
-                       printk(KERN_WARNING "Elsa: If your system hangs now, read\n");
-                       printk(KERN_WARNING "Elsa: Documentation/isdn/README.HiSax\n");
-               }
-               cs->hw.elsa.ale  = cs->hw.elsa.base;
-               cs->hw.elsa.isac = cs->hw.elsa.base +1;
-               cs->hw.elsa.hscx = cs->hw.elsa.base +1; 
-               test_and_set_bit(HW_IPAC, &cs->HW_Flags);
-               cs->hw.elsa.timer = 0;
-               cs->hw.elsa.trig  = 0;
-               cs->irq_flags |= IRQF_SHARED;
-               printk(KERN_INFO
-                      "Elsa: %s defined at %#lx/0x%x IRQ %d\n",
-                      Elsa_Types[cs->subtyp],
-                      cs->hw.elsa.base,
-                      cs->hw.elsa.cfg,
-                      cs->irq);
 #else
-               printk(KERN_WARNING "Elsa: Elsa PCI and NO_PCI_BIOS\n");
-               printk(KERN_WARNING "Elsa: unable to config Elsa PCI\n");
-               return (0);
+
+static int __devinit
+setup_elsa_pci(struct IsdnCard *card)
+{
+       return (1);
+}
 #endif /* CONFIG_PCI */
-       } else 
-               return (0);
+
+static int __devinit
+setup_elsa_common(struct IsdnCard *card)
+{
+       struct IsdnCardState *cs = card->cs;
+       u_char val;
+       int bytecnt;
 
        switch (cs->subtyp) {
                case ELSA_PC:
@@ -1104,8 +1130,7 @@ setup_elsa(struct IsdnCard *card)
           here, it would fail. */
        if (cs->typ != ISDN_CTYPE_ELSA_PCMCIA && !request_region(cs->hw.elsa.base, bytecnt, "elsa isdn")) {
                printk(KERN_WARNING
-                      "HiSax: %s config port %#lx-%#lx already in use\n",
-                      CardType[card->typ],
+                      "HiSax: ELSA config port %#lx-%#lx already in use\n",
                       cs->hw.elsa.base,
                       cs->hw.elsa.base + bytecnt);
                return (0);
@@ -1113,8 +1138,7 @@ setup_elsa(struct IsdnCard *card)
        if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI)) {
                if (!request_region(cs->hw.elsa.cfg, 0x80, "elsa isdn pci")) {
                        printk(KERN_WARNING
-                              "HiSax: %s pci port %x-%x already in use\n",
-                               CardType[card->typ],
+                              "HiSax: ELSA pci port %x-%x already in use\n",
                                cs->hw.elsa.cfg,
                                cs->hw.elsa.cfg + 0x80);
                        release_region(cs->hw.elsa.base, bytecnt);
@@ -1186,3 +1210,41 @@ setup_elsa(struct IsdnCard *card)
        }
        return (1);
 }
+
+int __devinit
+setup_elsa(struct IsdnCard *card)
+{
+       int rc;
+       struct IsdnCardState *cs = card->cs;
+       char tmp[64];
+
+       strcpy(tmp, Elsa_revision);
+       printk(KERN_INFO "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp));
+       cs->hw.elsa.ctrl_reg = 0;
+       cs->hw.elsa.status = 0;
+       cs->hw.elsa.MFlag = 0;
+       cs->subtyp = 0;
+
+       if (cs->typ == ISDN_CTYPE_ELSA) {
+               rc = setup_elsa_isa(card);
+               if (!rc)
+                       return (0);
+
+       } else if (cs->typ == ISDN_CTYPE_ELSA_PNP) {
+               rc = setup_elsa_isapnp(card);
+               if (!rc)
+                       return (0);
+
+       } else if (cs->typ == ISDN_CTYPE_ELSA_PCMCIA)
+               setup_elsa_pcmcia(card);
+
+       else if (cs->typ == ISDN_CTYPE_ELSA_PCI) {
+               rc = setup_elsa_pci(card);
+               if (!rc)
+                       return (0);
+
+       } else 
+               return (0);
+
+       return setup_elsa_common(card);
+}
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 ad06f3cc60fb9c478fdbb2c7560e95b9996e4212..03dfc32166a09ea057e861d8eaa93d47e6239dfe 100644 (file)
@@ -518,8 +518,6 @@ Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return(0);
 }
 
-static struct pci_dev *dev_sedl __devinitdata = NULL;
-
 #ifdef __ISAPNP__
 static struct isapnp_device_id sedl_ids[] __devinitdata = {
        { ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x01),
@@ -533,15 +531,158 @@ static struct isapnp_device_id sedl_ids[] __devinitdata = {
 
 static struct isapnp_device_id *ipid __devinitdata = &sedl_ids[0];
 static struct pnp_card *pnp_c __devinitdata = NULL;
-#endif
+
+static int __devinit
+setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt)
+{
+       struct IsdnCardState *cs = card->cs;
+       struct pnp_dev *pnp_d;
+
+       if (!isapnp_present())
+               return -1;
+
+       while(ipid->card_vendor) {
+               if ((pnp_c = pnp_find_card(ipid->card_vendor,
+                       ipid->card_device, pnp_c))) {
+                       pnp_d = NULL;
+                       if ((pnp_d = pnp_find_dev(pnp_c,
+                               ipid->vendor, ipid->function, pnp_d))) {
+                               int err;
+
+                               printk(KERN_INFO "HiSax: %s detected\n",
+                                       (char *)ipid->driver_data);
+                               pnp_disable_dev(pnp_d);
+                               err = pnp_activate_dev(pnp_d);
+                               if (err<0) {
+                                       printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+                                               __FUNCTION__, err);
+                                       return(0);
+                               }
+                               card->para[1] = pnp_port_start(pnp_d, 0);
+                               card->para[0] = pnp_irq(pnp_d, 0);
+
+                               if (!card->para[0] || !card->para[1]) {
+                                       printk(KERN_ERR "Sedlbauer PnP:some resources are missing %ld/%lx\n",
+                                               card->para[0], card->para[1]);
+                                       pnp_disable_dev(pnp_d);
+                                       return(0);
+                               }
+                               cs->hw.sedl.cfg_reg = card->para[1];
+                               cs->irq = card->para[0];
+                               if (ipid->function == ISAPNP_FUNCTION(0x2)) {
+                                       cs->subtyp = SEDL_SPEED_FAX;
+                                       cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
+                                       *bytecnt = 16;
+                               } else {
+                                       cs->subtyp = SEDL_SPEED_CARD_WIN;
+                                       cs->hw.sedl.chip = SEDL_CHIP_TEST;
+                               }
+
+                               return (1);
+                       } else {
+                               printk(KERN_ERR "Sedlbauer PnP: PnP error card found, no device\n");
+                               return(0);
+                       }
+               }
+               ipid++;
+               pnp_c = NULL;
+       } 
+
+       printk(KERN_INFO "Sedlbauer PnP: no ISAPnP card found\n");
+       return -1;
+}
+#else
+
+static int __devinit
+setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt)
+{
+       return -1;
+}
+#endif /* __ISAPNP__ */
+
+#ifdef CONFIG_PCI
+static struct pci_dev *dev_sedl __devinitdata = NULL;
+
+static int __devinit
+setup_sedlbauer_pci(struct IsdnCard *card)
+{
+       struct IsdnCardState *cs = card->cs;
+       u16 sub_vendor_id, sub_id;
+
+       if ((dev_sedl = pci_find_device(PCI_VENDOR_ID_TIGERJET,
+                       PCI_DEVICE_ID_TIGERJET_100, dev_sedl))) {
+               if (pci_enable_device(dev_sedl))
+                       return(0);
+               cs->irq = dev_sedl->irq;
+               if (!cs->irq) {
+                       printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n");
+                       return(0);
+               }
+               cs->hw.sedl.cfg_reg = pci_resource_start(dev_sedl, 0);
+       } else {
+               printk(KERN_WARNING "Sedlbauer: No PCI card found\n");
+               return(0);
+       }
+       cs->irq_flags |= IRQF_SHARED;
+       cs->hw.sedl.bus = SEDL_BUS_PCI;
+       sub_vendor_id = dev_sedl->subsystem_vendor;
+       sub_id = dev_sedl->subsystem_device;
+       printk(KERN_INFO "Sedlbauer: PCI subvendor:%x subid %x\n",
+               sub_vendor_id, sub_id);
+       printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n",
+               cs->hw.sedl.cfg_reg);
+       if (sub_id != PCI_SUB_ID_SEDLBAUER) {
+               printk(KERN_ERR "Sedlbauer: unknown sub id %#x\n", sub_id);
+               return(0);
+       }
+       if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PYRAMID) {
+               cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
+               cs->subtyp = SEDL_SPEEDFAX_PYRAMID;
+       } else if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PCI) {
+               cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
+               cs->subtyp = SEDL_SPEEDFAX_PCI;
+       } else if (sub_vendor_id == PCI_SUBVENDOR_HST_SAPHIR3) {
+               cs->hw.sedl.chip = SEDL_CHIP_IPAC;
+               cs->subtyp = HST_SAPHIR3;
+       } else if (sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER_PCI) {
+               cs->hw.sedl.chip = SEDL_CHIP_IPAC;
+               cs->subtyp = SEDL_SPEED_PCI;
+       } else {
+               printk(KERN_ERR "Sedlbauer: unknown sub vendor id %#x\n",
+                       sub_vendor_id);
+               return(0);
+       }
+
+       cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON;
+       cs->hw.sedl.reset_off = SEDL_ISAR_PCI_ISAR_RESET_OFF;
+       byteout(cs->hw.sedl.cfg_reg, 0xff);
+       byteout(cs->hw.sedl.cfg_reg, 0x00);
+       byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd);
+       byteout(cs->hw.sedl.cfg_reg+ 5, 0); /* disable all IRQ */
+       byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on);
+       mdelay(2);
+       byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
+       mdelay(10);
+
+       return (1);
+}
+
+#else
+
+static int __devinit
+setup_sedlbauer_pci(struct IsdnCard *card)
+{
+       return (1);
+}
+
+#endif /* CONFIG_PCI */
 
 int __devinit
 setup_sedlbauer(struct IsdnCard *card)
 {
-       int bytecnt, ver, val;
+       int bytecnt = 8, ver, val, rc;
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
-       u16 sub_vendor_id, sub_id;
 
        strcpy(tmp, Sedlbauer_revision);
        printk(KERN_INFO "HiSax: Sedlbauer driver Rev. %s\n", HiSax_getrev(tmp));
@@ -569,124 +710,21 @@ setup_sedlbauer(struct IsdnCard *card)
                        bytecnt = 16;
                }
        } else {
-#ifdef __ISAPNP__
-               if (isapnp_present()) {
-                       struct pnp_dev *pnp_d;
-                       while(ipid->card_vendor) {
-                               if ((pnp_c = pnp_find_card(ipid->card_vendor,
-                                       ipid->card_device, pnp_c))) {
-                                       pnp_d = NULL;
-                                       if ((pnp_d = pnp_find_dev(pnp_c,
-                                               ipid->vendor, ipid->function, pnp_d))) {
-                                               int err;
-
-                                               printk(KERN_INFO "HiSax: %s detected\n",
-                                                       (char *)ipid->driver_data);
-                                               pnp_disable_dev(pnp_d);
-                                               err = pnp_activate_dev(pnp_d);
-                                               if (err<0) {
-                                                       printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
-                                                               __FUNCTION__, err);
-                                                       return(0);
-                                               }
-                                               card->para[1] = pnp_port_start(pnp_d, 0);
-                                               card->para[0] = pnp_irq(pnp_d, 0);
-
-                                               if (!card->para[0] || !card->para[1]) {
-                                                       printk(KERN_ERR "Sedlbauer PnP:some resources are missing %ld/%lx\n",
-                                                               card->para[0], card->para[1]);
-                                                       pnp_disable_dev(pnp_d);
-                                                       return(0);
-                                               }
-                                               cs->hw.sedl.cfg_reg = card->para[1];
-                                               cs->irq = card->para[0];
-                                               if (ipid->function == ISAPNP_FUNCTION(0x2)) {
-                                                       cs->subtyp = SEDL_SPEED_FAX;
-                                                       cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
-                                                       bytecnt = 16;
-                                               } else {
-                                                       cs->subtyp = SEDL_SPEED_CARD_WIN;
-                                                       cs->hw.sedl.chip = SEDL_CHIP_TEST;
-                                               }
-                                               goto ready;
-                                       } else {
-                                               printk(KERN_ERR "Sedlbauer PnP: PnP error card found, no device\n");
-                                               return(0);
-                                       }
-                               }
-                               ipid++;
-                               pnp_c = NULL;
-                       } 
-                       if (!ipid->card_vendor) {
-                               printk(KERN_INFO "Sedlbauer PnP: no ISAPnP card found\n");
-                       }
-               }
-#endif
-/* Probe for Sedlbauer speed pci */
-#ifdef CONFIG_PCI
-               if ((dev_sedl = pci_find_device(PCI_VENDOR_ID_TIGERJET,
-                               PCI_DEVICE_ID_TIGERJET_100, dev_sedl))) {
-                       if (pci_enable_device(dev_sedl))
-                               return(0);
-                       cs->irq = dev_sedl->irq;
-                       if (!cs->irq) {
-                               printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n");
-                               return(0);
-                       }
-                       cs->hw.sedl.cfg_reg = pci_resource_start(dev_sedl, 0);
-               } else {
-                       printk(KERN_WARNING "Sedlbauer: No PCI card found\n");
-                       return(0);
-               }
-               cs->irq_flags |= IRQF_SHARED;
-               cs->hw.sedl.bus = SEDL_BUS_PCI;
-               sub_vendor_id = dev_sedl->subsystem_vendor;
-               sub_id = dev_sedl->subsystem_device;
-               printk(KERN_INFO "Sedlbauer: PCI subvendor:%x subid %x\n",
-                       sub_vendor_id, sub_id);
-               printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n",
-                       cs->hw.sedl.cfg_reg);
-               if (sub_id != PCI_SUB_ID_SEDLBAUER) {
-                       printk(KERN_ERR "Sedlbauer: unknown sub id %#x\n", sub_id);
-                       return(0);
-               }
-               if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PYRAMID) {
-                       cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
-                       cs->subtyp = SEDL_SPEEDFAX_PYRAMID;
-               } else if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PCI) {
-                       cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
-                       cs->subtyp = SEDL_SPEEDFAX_PCI;
-               } else if (sub_vendor_id == PCI_SUBVENDOR_HST_SAPHIR3) {
-                       cs->hw.sedl.chip = SEDL_CHIP_IPAC;
-                       cs->subtyp = HST_SAPHIR3;
-               } else if (sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER_PCI) {
-                       cs->hw.sedl.chip = SEDL_CHIP_IPAC;
-                       cs->subtyp = SEDL_SPEED_PCI;
-               } else {
-                       printk(KERN_ERR "Sedlbauer: unknown sub vendor id %#x\n",
-                               sub_vendor_id);
-                       return(0);
-               }
+               rc = setup_sedlbauer_isapnp(card, &bytecnt);
+               if (!rc)
+                       return (0);
+               if (rc > 0)
+                       goto ready;
+
+               /* Probe for Sedlbauer speed pci */
+               rc = setup_sedlbauer_pci(card);
+               if (!rc)
+                       return (0);
+
                bytecnt = 256;
-               cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON;
-               cs->hw.sedl.reset_off = SEDL_ISAR_PCI_ISAR_RESET_OFF;
-               byteout(cs->hw.sedl.cfg_reg, 0xff);
-               byteout(cs->hw.sedl.cfg_reg, 0x00);
-               byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd);
-               byteout(cs->hw.sedl.cfg_reg+ 5, 0); /* disable all IRQ */
-               byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on);
-               mdelay(2);
-               byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
-               mdelay(10);
-#else
-               printk(KERN_WARNING "Sedlbauer: NO_PCI_BIOS\n");
-               return (0);
-#endif /* CONFIG_PCI */
        }       
 
-#ifdef __ISAPNP__
 ready: 
-#endif
 
        /* In case of the sedlbauer pcmcia card, this region is in use,
         * reserved for us by the card manager. So we do not check it
index d09f6d033f156c96c46a8411a5e41dc14c3abf88..4393003ae162b5d7a7bd83991c3d53909d0f894d 100644 (file)
@@ -295,11 +295,12 @@ setup_telespci(struct IsdnCard *card)
 #ifdef __BIG_ENDIAN
 #error "not running on big endian machines now"
 #endif
+
        strcpy(tmp, telespci_revision);
        printk(KERN_INFO "HiSax: Teles/PCI driver Rev. %s\n", HiSax_getrev(tmp));
        if (cs->typ != ISDN_CTYPE_TELESPCI)
                return (0);
-#ifdef CONFIG_PCI
+
        if ((dev_tel = pci_find_device (PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36120, dev_tel))) {
                if (pci_enable_device(dev_tel))
                        return(0);
@@ -317,11 +318,6 @@ setup_telespci(struct IsdnCard *card)
                printk(KERN_WARNING "TelesPCI: No PCI card found\n");
                return(0);
        }
-#else
-       printk(KERN_WARNING "HiSax: Teles/PCI and NO_PCI_BIOS\n");
-       printk(KERN_WARNING "HiSax: Teles/PCI unable to config\n");
-       return (0);
-#endif /* CONFIG_PCI */
 
        /* Initialize Zoran PCI controller */
        writel(0x00000000, cs->hw.teles0.membase + 0x28);
index 3aeceaf9769e5dc30a7cbefd30b4995082f8c7f6..39129b94f8be503340686e7122584dfa8a14021a 100644 (file)
@@ -1009,7 +1009,7 @@ setup_w6692(struct IsdnCard *card)
        printk(KERN_INFO "HiSax: W6692 driver Rev. %s\n", HiSax_getrev(tmp));
        if (cs->typ != ISDN_CTYPE_W6692)
                return (0);
-#ifdef CONFIG_PCI
+
        while (id_list[id_idx].vendor_id) {
                dev_w6692 = pci_find_device(id_list[id_idx].vendor_id,
                                            id_list[id_idx].device_id,
@@ -1061,11 +1061,6 @@ setup_w6692(struct IsdnCard *card)
                       cs->hw.w6692.iobase + 255);
                return (0);
        }
-#else
-       printk(KERN_WARNING "HiSax: W6692 and NO_PCI_BIOS\n");
-       printk(KERN_WARNING "HiSax: W6692 unable to config\n");
-       return (0);
-#endif                         /* CONFIG_PCI */
 
        printk(KERN_INFO
               "HiSax: %s config irq:%d I/O:%x\n",
index 9e01748a176e95c2726c2842ff102bca5fd3c4eb..b7cc5c2f08c66c2ed38a01752b5ced0fe4ee3eb0 100644 (file)
 #include "hysdn_defs.h"
 
 static struct pci_device_id hysdn_pci_tbl[] = {
-       {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_METRO},
-       {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2},
-       {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_ERGO},
-       {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO},
+       { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
+         PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_METRO, 0, 0, BD_METRO },
+       { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
+         PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2, 0, 0, BD_CHAMP2 },
+       { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
+         PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_ERGO, 0, 0, BD_ERGO },
+       { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
+         PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO, 0, 0, BD_ERGO },
+
        { }                             /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(pci, hysdn_pci_tbl);
@@ -34,128 +39,7 @@ MODULE_LICENSE("GPL");
 static char *hysdn_init_revision = "$Revision: 1.6.6.6 $";
 static int cardmax;            /* number of found cards */
 hysdn_card *card_root = NULL;  /* pointer to first card */
-
-/**********************************************/
-/* table assigning PCI-sub ids to board types */
-/* the last entry contains all 0              */
-/**********************************************/
-static struct {
-       unsigned short subid;           /* PCI sub id */
-       unsigned char cardtyp;          /* card type assigned */
-} pci_subid_map[] = {
-
-       {
-               PCI_SUBDEVICE_ID_HYPERCOPE_METRO, BD_METRO
-       },
-       {
-               PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2, BD_CHAMP2
-       },
-       {
-               PCI_SUBDEVICE_ID_HYPERCOPE_ERGO, BD_ERGO
-       },
-       {
-               PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO, BD_ERGO
-       },
-       {
-               0, 0
-       }                       /* terminating entry */
-};
-
-
-/*********************************************************************/
-/* search_cards searches for available cards in the pci config data. */
-/* If a card is found, the card structure is allocated and the cards */
-/* ressources are reserved. cardmax is incremented.                  */
-/*********************************************************************/
-static void
-search_cards(void)
-{
-       struct pci_dev *akt_pcidev = NULL;
-       hysdn_card *card, *card_last;
-       int i;
-
-       card_root = NULL;
-       card_last = NULL;
-       while ((akt_pcidev = pci_find_device(PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
-                                            akt_pcidev)) != NULL) {
-               if (pci_enable_device(akt_pcidev))
-                       continue;
-
-               if (!(card = kzalloc(sizeof(hysdn_card), GFP_KERNEL))) {
-                       printk(KERN_ERR "HYSDN: unable to alloc device mem \n");
-                       return;
-               }
-               card->myid = cardmax;   /* set own id */
-               card->bus = akt_pcidev->bus->number;
-               card->devfn = akt_pcidev->devfn;        /* slot + function */
-               card->subsysid = akt_pcidev->subsystem_device;
-               card->irq = akt_pcidev->irq;
-               card->iobase = pci_resource_start(akt_pcidev, PCI_REG_PLX_IO_BASE);
-               card->plxbase = pci_resource_start(akt_pcidev, PCI_REG_PLX_MEM_BASE);
-               card->membase = pci_resource_start(akt_pcidev, PCI_REG_MEMORY_BASE);
-               card->brdtype = BD_NONE;        /* unknown */
-               card->debug_flags = DEF_DEB_FLAGS;      /* set default debug */
-               card->faxchans = 0;     /* default no fax channels */
-               card->bchans = 2;       /* and 2 b-channels */
-               for (i = 0; pci_subid_map[i].subid; i++)
-                       if (pci_subid_map[i].subid == card->subsysid) {
-                               card->brdtype = pci_subid_map[i].cardtyp;
-                               break;
-                       }
-               if (card->brdtype != BD_NONE) {
-                       if (ergo_inithardware(card)) {
-                               printk(KERN_WARNING "HYSDN: card at io 0x%04x already in use\n", card->iobase);
-                               kfree(card);
-                               continue;
-                       }
-               } else {
-                       printk(KERN_WARNING "HYSDN: unknown card id 0x%04x\n", card->subsysid);
-                       kfree(card);    /* release mem */
-                       continue;
-               }
-               cardmax++;
-               card->next = NULL;      /*end of chain */
-               if (card_last)
-                       card_last->next = card;         /* pointer to next card */
-               else
-                       card_root = card;
-               card_last = card;       /* new chain end */
-       }                       /* device found */
-}                              /* search_cards */
-
-/************************************************************************************/
-/* free_resources frees the acquired PCI resources and returns the allocated memory */
-/************************************************************************************/
-static void
-free_resources(void)
-{
-       hysdn_card *card;
-
-       while (card_root) {
-               card = card_root;
-               if (card->releasehardware)
-                       card->releasehardware(card);    /* free all hardware resources */
-               card_root = card_root->next;    /* remove card from chain */
-               kfree(card);    /* return mem */
-
-       }                       /* while card_root */
-}                              /* free_resources */
-
-/**************************************************************************/
-/* stop_cards disables (hardware resets) all cards and disables interrupt */
-/**************************************************************************/
-static void
-stop_cards(void)
-{
-       hysdn_card *card;
-
-       card = card_root;       /* first in chain */
-       while (card) {
-               if (card->stopcard)
-                       card->stopcard(card);
-               card = card->next;      /* remove card from chain */
-       }                       /* while card */
-}                              /* stop_cards */
+static hysdn_card *card_last = NULL;   /* pointer to first card */
 
 
 /****************************************************************************/
@@ -191,31 +75,138 @@ hysdn_getrev(const char *revision)
 /* and the module is added to the list in /proc/modules, otherwise an error */
 /* is assumed and the module will not be kept in memory.                    */
 /****************************************************************************/
+
+static int __devinit hysdn_pci_init_one(struct pci_dev *akt_pcidev,
+                                       const struct pci_device_id *ent)
+{
+       hysdn_card *card;
+       int rc;
+
+       rc = pci_enable_device(akt_pcidev);
+       if (rc)
+               return rc;
+
+       if (!(card = kzalloc(sizeof(hysdn_card), GFP_KERNEL))) {
+               printk(KERN_ERR "HYSDN: unable to alloc device mem \n");
+               rc = -ENOMEM;
+               goto err_out;
+       }
+       card->myid = cardmax;   /* set own id */
+       card->bus = akt_pcidev->bus->number;
+       card->devfn = akt_pcidev->devfn;        /* slot + function */
+       card->subsysid = akt_pcidev->subsystem_device;
+       card->irq = akt_pcidev->irq;
+       card->iobase = pci_resource_start(akt_pcidev, PCI_REG_PLX_IO_BASE);
+       card->plxbase = pci_resource_start(akt_pcidev, PCI_REG_PLX_MEM_BASE);
+       card->membase = pci_resource_start(akt_pcidev, PCI_REG_MEMORY_BASE);
+       card->brdtype = BD_NONE;        /* unknown */
+       card->debug_flags = DEF_DEB_FLAGS;      /* set default debug */
+       card->faxchans = 0;     /* default no fax channels */
+       card->bchans = 2;       /* and 2 b-channels */
+       card->brdtype = ent->driver_data;
+
+       if (ergo_inithardware(card)) {
+               printk(KERN_WARNING "HYSDN: card at io 0x%04x already in use\n", card->iobase);
+               rc = -EBUSY;
+               goto err_out_card;
+       }
+
+       cardmax++;
+       card->next = NULL;      /*end of chain */
+       if (card_last)
+               card_last->next = card;         /* pointer to next card */
+       else
+               card_root = card;
+       card_last = card;       /* new chain end */
+
+       pci_set_drvdata(akt_pcidev, card);
+       return 0;
+
+err_out_card:
+       kfree(card);
+err_out:
+       pci_disable_device(akt_pcidev);
+       return rc;
+}
+
+static void __devexit hysdn_pci_remove_one(struct pci_dev *akt_pcidev)
+{
+       hysdn_card *card = pci_get_drvdata(akt_pcidev);
+
+       pci_set_drvdata(akt_pcidev, NULL);
+
+       if (card->stopcard)
+               card->stopcard(card);
+
+#ifdef CONFIG_HYSDN_CAPI
+       hycapi_capi_release(card);
+#endif
+
+       if (card->releasehardware)
+               card->releasehardware(card);   /* free all hardware resources */
+
+       if (card == card_root) {
+               card_root = card_root->next;
+               if (!card_root)
+                       card_last = NULL;
+       } else {
+               hysdn_card *tmp = card_root;
+               while (tmp) {
+                       if (tmp->next == card)
+                               tmp->next = card->next;
+                       card_last = tmp;
+                       tmp = tmp->next;
+               }
+       }
+
+       kfree(card);
+       pci_disable_device(akt_pcidev);
+}
+
+static struct pci_driver hysdn_pci_driver = {
+       .name           = "hysdn",
+       .id_table       = hysdn_pci_tbl,
+       .probe          = hysdn_pci_init_one,
+       .remove         = __devexit_p(hysdn_pci_remove_one),
+};
+
+static int hysdn_have_procfs;
+
 static int __init
 hysdn_init(void)
 {
        char tmp[50];
+       int rc;
 
        strcpy(tmp, hysdn_init_revision);
        printk(KERN_NOTICE "HYSDN: module Rev: %s loaded\n", hysdn_getrev(tmp));
        strcpy(tmp, hysdn_net_revision);
        printk(KERN_NOTICE "HYSDN: network interface Rev: %s \n", hysdn_getrev(tmp));
-       search_cards();
+
+       rc = pci_register_driver(&hysdn_pci_driver);
+       if (rc)
+               return rc;
+
        printk(KERN_INFO "HYSDN: %d card(s) found.\n", cardmax);
 
-       if (hysdn_procconf_init()) {
-               free_resources();       /* proc file_sys not created */
-               return (-1);
-       }
+       if (!hysdn_procconf_init())
+               hysdn_have_procfs = 1;
+
 #ifdef CONFIG_HYSDN_CAPI
        if(cardmax > 0) {
                if(hycapi_init()) {
                        printk(KERN_ERR "HYCAPI: init failed\n");
-                       return(-1);
+
+                       if (hysdn_have_procfs)
+                               hysdn_procconf_release();
+
+                       pci_unregister_driver(&hysdn_pci_driver);
+                       return -ESPIPE;
                }
        }
 #endif /* CONFIG_HYSDN_CAPI */
-       return (0);             /* no error */
+
+       return 0;               /* no error */
 }                              /* init_module */
 
 
@@ -230,20 +221,15 @@ hysdn_init(void)
 static void __exit
 hysdn_exit(void)
 {
+       if (hysdn_have_procfs)
+               hysdn_procconf_release();
+
+       pci_unregister_driver(&hysdn_pci_driver);
+
 #ifdef CONFIG_HYSDN_CAPI
-       hysdn_card *card;
-#endif /* CONFIG_HYSDN_CAPI */
-       stop_cards();
-#ifdef CONFIG_HYSDN_CAPI
-       card = card_root;       /* first in chain */
-       while (card) {
-               hycapi_capi_release(card);
-               card = card->next;      /* remove card from chain */
-       }                       /* while card */
        hycapi_cleanup();
 #endif /* CONFIG_HYSDN_CAPI */
-       hysdn_procconf_release();
-       free_resources();
+
        printk(KERN_NOTICE "HYSDN: module unloaded\n");
 }                              /* cleanup_module */
 
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 e8f102ea9b03918aeeaa3ac2311858d4c24b0b54..acf1b81b47cbeccf74d85cc6bc9f66ee998afbbb 100644 (file)
@@ -3076,8 +3076,7 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data)
        mddev->gendisk = disk;
        mutex_unlock(&disks_mutex);
        mddev->kobj.parent = &disk->kobj;
-       mddev->kobj.k_name = NULL;
-       snprintf(mddev->kobj.name, KOBJ_NAME_LEN, "%s", "md");
+       kobject_set_name(&mddev->kobj, "%s", "md");
        mddev->kobj.ktype = &md_ktype;
        if (kobject_register(&mddev->kobj))
                printk(KERN_WARNING "md: cannot register %s/md - name in use\n",
index 56231d8edc079a5306a3a487bdf04373db83b757..18738faecbbc51adc7f9311c066779cafdee0b88 100644 (file)
@@ -103,10 +103,7 @@ static struct file_operations dvb_device_fops =
        .open =         dvb_device_open,
 };
 
-static struct cdev dvb_device_cdev = {
-       .kobj   = {.name = "dvb", },
-       .owner  =       THIS_MODULE,
-};
+static struct cdev dvb_device_cdev;
 
 int dvb_generic_open(struct inode *inode, struct file *file)
 {
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 7a78d6b34738827e1b74eca6df1260aad0ad4201..2ee3c3049e8f3dd1a9154821cbfdf1b989305c5d 100644 (file)
@@ -905,8 +905,8 @@ struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *mp,
 }
 
 
-static int pvr2_sysfs_hotplug(struct device *cd,char **envp,
-                             int numenvp,char *buf,int size)
+static int pvr2_sysfs_hotplug(struct device *d,
+                             struct kobj_uevent_env *env)
 {
        /* Even though we don't do anything here, we still need this function
           because sysfs will still try to call it. */
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 d195fb088f4a05a7678ea7e289e5f18a503e64c7..8f77949f93dd879097604fcc817122bfcef60fbc 100644 (file)
@@ -57,16 +57,11 @@ static int tifm_bus_match(struct device *dev, struct device_driver *drv)
        return 0;
 }
 
-static int tifm_uevent(struct device *dev, char **envp, int num_envp,
-                      char *buffer, int buffer_size)
+static int tifm_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
-       int i = 0;
-       int length = 0;
 
-       if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
-                          "TIFM_CARD_TYPE=%s",
-                          tifm_media_type_name(sock->type, 1)))
+       if (add_uevent_var(env, "TIFM_CARD_TYPE=%s", tifm_media_type_name(sock->type, 1)))
                return -ENOMEM;
 
        return 0;
index 8d6f6014870f2cebfa8030fca45549b1cfc7fe30..b0c22cad9423f2878c8742f48801f422967c32df 100644 (file)
@@ -58,12 +58,11 @@ static int mmc_bus_match(struct device *dev, struct device_driver *drv)
 }
 
 static int
-mmc_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf,
-               int buf_size)
+mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        struct mmc_card *card = dev_to_mmc_card(dev);
        const char *type;
-       int i = 0, length = 0;
+       int retval = 0;
 
        switch (card->type) {
        case MMC_TYPE_MMC:
@@ -80,20 +79,14 @@ mmc_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf,
        }
 
        if (type) {
-               if (add_uevent_var(envp, num_envp, &i,
-                               buf, buf_size, &length,
-                               "MMC_TYPE=%s", type))
-                       return -ENOMEM;
+               retval = add_uevent_var(env, "MMC_TYPE=%s", type);
+               if (retval)
+                       return retval;
        }
 
-       if (add_uevent_var(envp, num_envp, &i,
-                       buf, buf_size, &length,
-                       "MMC_NAME=%s", mmc_card_name(card)))
-               return -ENOMEM;
+       retval = add_uevent_var(env, "MMC_NAME=%s", mmc_card_name(card));
 
-       envp[i] = NULL;
-
-       return 0;
+       return retval;
 }
 
 static int mmc_bus_probe(struct device *dev)
index 64fbc9759a30757426de0270b0afa25d5c31ea94..c65d203a846d6e91dc5689e0bee82311474468a2 100644 (file)
@@ -143,7 +143,7 @@ void mmc_remove_host(struct mmc_host *host)
 
        device_del(&host->class_dev);
 
-       led_trigger_unregister(host->led);
+       led_trigger_unregister_simple(host->led);
 
        spin_lock(&mmc_host_lock);
        idr_remove(&mmc_host_idr, host->index);
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..cb933ac
--- /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/dma-mapping.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/mach/flash.h>
+
+static void pxa2xx_map_inval_cache(struct map_info *map, unsigned long from,
+                                     ssize_t len)
+{
+       consistent_sync((char *)map->cached + from, len, DMA_FROM_DEVICE);
+}
+
+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 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 d68accea380bb3adcf40aaeece00d607d006d4bc..78ed633ceb829e121161a8a230a1350d9de06017 100644 (file)
@@ -2652,10 +2652,10 @@ static int bnx2_poll_work(struct bnx2 *bp, int work_done, int budget)
                REG_RD(bp, BNX2_HC_COMMAND);
        }
 
-       if (bp->status_blk->status_tx_quick_consumer_index0 != bp->hw_tx_cons)
+       if (sblk->status_tx_quick_consumer_index0 != bp->hw_tx_cons)
                bnx2_tx_int(bp);
 
-       if (bp->status_blk->status_rx_quick_consumer_index0 != bp->hw_rx_cons)
+       if (sblk->status_rx_quick_consumer_index0 != bp->hw_rx_cons)
                work_done += bnx2_rx_int(bp, budget - work_done);
 
        return work_done;
@@ -2665,6 +2665,7 @@ static int bnx2_poll(struct napi_struct *napi, int budget)
 {
        struct bnx2 *bp = container_of(napi, struct bnx2, napi);
        int work_done = 0;
+       struct status_block *sblk = bp->status_blk;
 
        while (1) {
                work_done = bnx2_poll_work(bp, work_done, budget);
@@ -2672,16 +2673,19 @@ static int bnx2_poll(struct napi_struct *napi, int budget)
                if (unlikely(work_done >= budget))
                        break;
 
+               /* bp->last_status_idx is used below to tell the hw how
+                * much work has been processed, so we must read it before
+                * checking for more work.
+                */
+               bp->last_status_idx = sblk->status_idx;
+               rmb();
                if (likely(!bnx2_has_work(bp))) {
-                       bp->last_status_idx = bp->status_blk->status_idx;
-                       rmb();
-
                        netif_rx_complete(bp->dev, napi);
                        if (likely(bp->flags & USING_MSI_FLAG)) {
                                REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
                                       BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
                                       bp->last_status_idx);
-                               return 0;
+                               break;
                        }
                        REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
                               BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
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 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 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 4ac161e1ca12674f4ab4614d04f9cd8e60f6b567..7d7758f3ad8c1afb4d4b767d1e25061728f4fade 100644 (file)
@@ -1183,7 +1183,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_
                                         pool_count[i], pool_size[i],
                                         pool_active[i]);
                kobj->parent = &dev->dev.kobj;
-               sprintf(kobj->name, "pool%d", i);
+               kobject_set_name(kobj, "pool%d", i);
                kobj->ktype = &ktype_veth_pool;
                kobject_register(kobj);
        }
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 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 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 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 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 e795c33b982de885e0ab290d3d325ede7b06b114..30b1cca8144ce360b23db4106983fb9c1cf45822 100644 (file)
@@ -3576,7 +3576,7 @@ static int tg3_poll_work(struct tg3 *tp, int work_done, int budget)
        if (sblk->idx[0].tx_consumer != tp->tx_cons) {
                tg3_tx(tp);
                if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING))
-                       return 0;
+                       return work_done;
        }
 
        /* run RX thread, within the bounds set by NAPI.
@@ -3593,6 +3593,7 @@ static int tg3_poll(struct napi_struct *napi, int budget)
 {
        struct tg3 *tp = container_of(napi, struct tg3, napi);
        int work_done = 0;
+       struct tg3_hw_status *sblk = tp->hw_status;
 
        while (1) {
                work_done = tg3_poll_work(tp, work_done, budget);
@@ -3603,15 +3604,17 @@ static int tg3_poll(struct napi_struct *napi, int budget)
                if (unlikely(work_done >= budget))
                        break;
 
-               if (likely(!tg3_has_work(tp))) {
-                       struct tg3_hw_status *sblk = tp->hw_status;
-
-                       if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) {
-                               tp->last_tag = sblk->status_tag;
-                               rmb();
-                       } else
-                               sblk->status &= ~SD_STATUS_UPDATED;
+               if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) {
+                       /* tp->last_tag is used in tg3_restart_ints() below
+                        * to tell the hw how much work has been processed,
+                        * so we must read it before checking for more work.
+                        */
+                       tp->last_tag = sblk->status_tag;
+                       rmb();
+               } else
+                       sblk->status &= ~SD_STATUS_UPDATED;
 
+               if (likely(!tg3_has_work(tp))) {
                        netif_rx_complete(tp->dev, napi);
                        tg3_restart_ints(tp);
                        break;
@@ -3621,9 +3624,10 @@ static int tg3_poll(struct napi_struct *napi, int budget)
        return work_done;
 
 tx_recovery:
+       /* work_done is guaranteed to be less than budget. */
        netif_rx_complete(tp->dev, napi);
        schedule_work(&tp->reset_task);
-       return 0;
+       return work_done;
 }
 
 static void tg3_irq_quiesce(struct tg3 *tp)
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 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 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 1c97e7dd130b75d35b81ca848006a91ea3ab9ad6..2b5352a7dffc21a5020512f86f761aca2e8ec2b1 100644 (file)
@@ -3,12 +3,9 @@
 #include <linux/module.h>
 #include "pci.h"
 
-int pci_uevent(struct device *dev, char **envp, int num_envp,
-              char *buffer, int buffer_size)
+int pci_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        struct pci_dev *pdev;
-       int i = 0;
-       int length = 0;
 
        if (!dev)
                return -ENODEV;
@@ -17,37 +14,24 @@ int pci_uevent(struct device *dev, char **envp, int num_envp,
        if (!pdev)
                return -ENODEV;
 
-       if (add_uevent_var(envp, num_envp, &i,
-                          buffer, buffer_size, &length,
-                          "PCI_CLASS=%04X", pdev->class))
+       if (add_uevent_var(env, "PCI_CLASS=%04X", pdev->class))
                return -ENOMEM;
 
-       if (add_uevent_var(envp, num_envp, &i,
-                          buffer, buffer_size, &length,
-                          "PCI_ID=%04X:%04X", pdev->vendor, pdev->device))
+       if (add_uevent_var(env, "PCI_ID=%04X:%04X", pdev->vendor, pdev->device))
                return -ENOMEM;
 
-       if (add_uevent_var(envp, num_envp, &i,
-                          buffer, buffer_size, &length,
-                          "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor,
+       if (add_uevent_var(env, "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor,
                           pdev->subsystem_device))
                return -ENOMEM;
 
-       if (add_uevent_var(envp, num_envp, &i,
-                          buffer, buffer_size, &length,
-                          "PCI_SLOT_NAME=%s", pci_name(pdev)))
+       if (add_uevent_var(env, "PCI_SLOT_NAME=%s", pci_name(pdev)))
                return -ENOMEM;
 
-       if (add_uevent_var(envp, num_envp, &i,
-                          buffer, buffer_size, &length,
-                          "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x",
+       if (add_uevent_var(env, "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x",
                           pdev->vendor, pdev->device,
                           pdev->subsystem_vendor, pdev->subsystem_device,
                           (u8)(pdev->class >> 16), (u8)(pdev->class >> 8),
                           (u8)(pdev->class)))
                return -ENOMEM;
-
-       envp[i] = NULL;
-
        return 0;
 }
index 2305cc450a4572da1d9dc0a57783a500db3a91a0..a96b739b2d35e2ccf1453ffeb92550850fbe3b89 100644 (file)
@@ -549,7 +549,7 @@ get_slot_mapping(struct pci_bus *bus, u8 bus_num, u8 dev_num, u8 *slot)
                         * slot. */
                        bus->number = tbus;
                        pci_bus_read_config_dword(bus, PCI_DEVFN(tdevice, 0),
-                                               PCI_REVISION_ID, &work);
+                                               PCI_CLASS_REVISION, &work);
 
                        if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) {
                                pci_bus_read_config_dword(bus,
index 37d72f123a80f65d05c703446b7f353aa55d8844..3ef0a4875a62a21ee4eff4d44e568f8632364918 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/smp_lock.h>
 #include <linux/pci.h>
 #include <linux/pci_hotplug.h>
+#include <linux/kthread.h>
 #include "cpqphp.h"
 
 static u32 configure_new_device(struct controller* ctrl, struct pci_func *func,
@@ -45,34 +46,20 @@ static int configure_new_function(struct controller* ctrl, struct pci_func *func
                        u8 behind_bridge, struct resource_lists *resources);
 static void interrupt_event_handler(struct controller *ctrl);
 
-static struct semaphore event_semaphore;       /* mutex for process loop (up if something to process) */
-static struct semaphore event_exit;            /* guard ensure thread has exited before calling it quits */
-static int event_finished;
-static unsigned long pushbutton_pending;       /* = 0 */
 
-/* things needed for the long_delay function */
-static struct semaphore                delay_sem;
-static wait_queue_head_t       delay_wait;
+static struct task_struct *cpqhp_event_thread;
+static unsigned long pushbutton_pending;       /* = 0 */
 
 /* delay is in jiffies to wait for */
 static void long_delay(int delay)
 {
-       DECLARE_WAITQUEUE(wait, current);
-       
-       /* only allow 1 customer into the delay queue at once
-        * yes this makes some people wait even longer, but who really cares?
-        * this is for _huge_ delays to make the hardware happy as the 
-        * signals bounce around
+       /*
+        * XXX(hch): if someone is bored please convert all callers
+        * to call msleep_interruptible directly.  They really want
+        * to specify timeouts in natural units and spend a lot of
+        * effort converting them to jiffies..
         */
-       down (&delay_sem);
-
-       init_waitqueue_head(&delay_wait);
-
-       add_wait_queue(&delay_wait, &wait);
        msleep_interruptible(jiffies_to_msecs(delay));
-       remove_wait_queue(&delay_wait, &wait);
-       
-       up(&delay_sem);
 }
 
 
@@ -955,8 +942,8 @@ irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data)
        }
 
        if (schedule_flag) {
-               up(&event_semaphore);
-               dbg("Signal event_semaphore\n");
+               wake_up_process(cpqhp_event_thread);
+               dbg("Waking even thread");
        }
        return IRQ_HANDLED;
 }
@@ -973,16 +960,13 @@ struct pci_func *cpqhp_slot_create(u8 busnumber)
        struct pci_func *new_slot;
        struct pci_func *next;
 
-       new_slot = kmalloc(sizeof(*new_slot), GFP_KERNEL);
-
+       new_slot = kzalloc(sizeof(*new_slot), GFP_KERNEL);
        if (new_slot == NULL) {
                /* I'm not dead yet!
                 * You will be. */
                return new_slot;
        }
 
-       memset(new_slot, 0, sizeof(struct pci_func));
-
        new_slot->next = NULL;
        new_slot->configured = 1;
 
@@ -1738,7 +1722,7 @@ static u32 remove_board(struct pci_func * func, u32 replace_flag, struct control
 static void pushbutton_helper_thread(unsigned long data)
 {
        pushbutton_pending = data;
-       up(&event_semaphore);
+       wake_up_process(cpqhp_event_thread);
 }
 
 
@@ -1747,13 +1731,13 @@ static int event_thread(void* data)
 {
        struct controller *ctrl;
 
-       daemonize("phpd_event");
-
        while (1) {
                dbg("!!!!event_thread sleeping\n");
-               down_interruptible (&event_semaphore);
-               dbg("event_thread woken finished = %d\n", event_finished);
-               if (event_finished) break;
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule();
+
+               if (kthread_should_stop())
+                       break;
                /* Do stuff here */
                if (pushbutton_pending)
                        cpqhp_pushbutton_thread(pushbutton_pending);
@@ -1762,38 +1746,24 @@ static int event_thread(void* data)
                                interrupt_event_handler(ctrl);
        }
        dbg("event_thread signals exit\n");
-       up(&event_exit);
        return 0;
 }
 
-
 int cpqhp_event_start_thread(void)
 {
-       int pid;
-
-       /* initialize our semaphores */
-       init_MUTEX(&delay_sem);
-       init_MUTEX_LOCKED(&event_semaphore);
-       init_MUTEX_LOCKED(&event_exit);
-       event_finished=0;
-
-       pid = kernel_thread(event_thread, NULL, 0);
-       if (pid < 0) {
+       cpqhp_event_thread = kthread_run(event_thread, NULL, "phpd_event");
+       if (IS_ERR(cpqhp_event_thread)) {
                err ("Can't start up our event thread\n");
-               return -1;
+               return PTR_ERR(cpqhp_event_thread);
        }
-       dbg("Our event thread pid = %d\n", pid);
+
        return 0;
 }
 
 
 void cpqhp_event_stop_thread(void)
 {
-       event_finished = 1;
-       dbg("event_thread finish command given\n");
-       up(&event_semaphore);
-       dbg("wait for event_thread to exit\n");
-       down(&event_exit);
+       kthread_stop(cpqhp_event_thread);
 }
 
 
index d06ccb69e411a01f67c01b2d0c90239d55834d52..c31e7bf34502338b469f80c7690cfc6effffc665 100644 (file)
@@ -35,7 +35,7 @@
 #include <linux/init.h>
 #include <linux/mutex.h>
 #include <linux/sched.h>
-
+#include <linux/kthread.h>
 #include "ibmphp.h"
 
 static int to_debug = 0;
@@ -101,12 +101,11 @@ static int to_debug = 0;
 //----------------------------------------------------------------------------
 // global variables
 //----------------------------------------------------------------------------
-static int ibmphp_shutdown;
-static int tid_poll;
 static struct mutex sem_hpcaccess;     // lock access to HPC
 static struct semaphore semOperations; // lock all operations and
                                        // access to data structures
 static struct semaphore sem_exit;      // make sure polling thread goes away
+static struct task_struct *ibmphp_poll_thread;
 //----------------------------------------------------------------------------
 // local function prototypes
 //----------------------------------------------------------------------------
@@ -116,10 +115,9 @@ static u8 hpc_writecmdtoindex (u8, u8);
 static u8 hpc_readcmdtoindex (u8, u8);
 static void get_hpc_access (void);
 static void free_hpc_access (void);
-static void poll_hpc (void);
+static int poll_hpc(void *data);
 static int process_changeinstatus (struct slot *, struct slot *);
 static int process_changeinlatch (u8, u8, struct controller *);
-static int hpc_poll_thread (void *);
 static int hpc_wait_ctlr_notworking (int, struct controller *, void __iomem *, u8 *);
 //----------------------------------------------------------------------------
 
@@ -137,8 +135,6 @@ void __init ibmphp_hpc_initvars (void)
        init_MUTEX (&semOperations);
        init_MUTEX_LOCKED (&sem_exit);
        to_debug = 0;
-       ibmphp_shutdown = 0;
-       tid_poll = 0;
 
        debug ("%s - Exit\n", __FUNCTION__);
 }
@@ -819,7 +815,7 @@ void ibmphp_unlock_operations (void)
 #define POLL_LATCH_REGISTER    0
 #define POLL_SLOTS             1
 #define POLL_SLEEP             2
-static void poll_hpc (void)
+static int poll_hpc(void *data)
 {
        struct slot myslot;
        struct slot *pslot = NULL;
@@ -833,10 +829,7 @@ static void poll_hpc (void)
 
        debug ("%s - Entry\n", __FUNCTION__);
 
-       while (!ibmphp_shutdown) {
-               if (ibmphp_shutdown) 
-                       break;
-               
+       while (!kthread_should_stop()) {
                /* try to get the lock to do some kind of hardware access */
                down (&semOperations);
 
@@ -896,7 +889,7 @@ static void poll_hpc (void)
                        up (&semOperations);
                        msleep(POLL_INTERVAL_SEC * 1000);
 
-                       if (ibmphp_shutdown) 
+                       if (kthread_should_stop())
                                break;
                        
                        down (&semOperations);
@@ -915,6 +908,7 @@ static void poll_hpc (void)
        }
        up (&sem_exit);
        debug ("%s - Exit\n", __FUNCTION__);
+       return 0;
 }
 
 
@@ -1049,29 +1043,6 @@ static int process_changeinlatch (u8 old, u8 new, struct controller *ctrl)
        return rc;
 }
 
-/*----------------------------------------------------------------------
-* Name:    hpc_poll_thread
-*
-* Action:  polling
-*
-* Return   0
-* Value:
-*---------------------------------------------------------------------*/
-static int hpc_poll_thread (void *data)
-{
-       debug ("%s - Entry\n", __FUNCTION__);
-
-       daemonize("hpc_poll");
-       allow_signal(SIGKILL);
-
-       poll_hpc ();
-
-       tid_poll = 0;
-       debug ("%s - Exit\n", __FUNCTION__);
-       return 0;
-}
-
-
 /*----------------------------------------------------------------------
 * Name:    ibmphp_hpc_start_poll_thread
 *
@@ -1079,18 +1050,14 @@ static int hpc_poll_thread (void *data)
 *---------------------------------------------------------------------*/
 int __init ibmphp_hpc_start_poll_thread (void)
 {
-       int rc = 0;
-
        debug ("%s - Entry\n", __FUNCTION__);
 
-       tid_poll = kernel_thread (hpc_poll_thread, NULL, 0);
-       if (tid_poll < 0) {
+       ibmphp_poll_thread = kthread_run(poll_hpc, NULL, "hpc_poll");
+       if (IS_ERR(ibmphp_poll_thread)) {
                err ("%s - Error, thread not started\n", __FUNCTION__);
-               rc = -1;
+               return PTR_ERR(ibmphp_poll_thread);
        }
-
-       debug ("%s - Exit tid_poll[%d] rc[%d]\n", __FUNCTION__, tid_poll, rc);
-       return rc;
+       return 0;
 }
 
 /*----------------------------------------------------------------------
@@ -1102,7 +1069,7 @@ void __exit ibmphp_hpc_stop_poll_thread (void)
 {
        debug ("%s - Entry\n", __FUNCTION__);
 
-       ibmphp_shutdown = 1;
+       kthread_stop(ibmphp_poll_thread);
        debug ("before locking operations \n");
        ibmphp_lock_operations ();
        debug ("after locking operations \n");
index bd433ef6bfc66ffd4381f6e9714debc98d370751..01c351c176ac27267bc03cdfdcf6c2f0d64e1467 100644 (file)
@@ -689,71 +689,9 @@ 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;
 
-       /*
-       * check all fields in the info structure, and update timestamps
-       * for the files referring to the fields that have now changed.
-       */
-       if ((has_power_file(slot) == 0) &&
-           (slot->info->power_status != info->power_status)) {
-               retval = sysfs_update_file(&slot->kobj,
-                                          &hotplug_slot_attr_power.attr);
-               if (retval)
-                       return retval;
-       }
-
-       if ((has_attention_file(slot) == 0) &&
-           (slot->info->attention_status != info->attention_status)) {
-               retval = sysfs_update_file(&slot->kobj,
-                                          &hotplug_slot_attr_attention.attr);
-               if (retval)
-                       return retval;
-       }
-
-       if ((has_latch_file(slot) == 0) &&
-           (slot->info->latch_status != info->latch_status)) {
-               retval = sysfs_update_file(&slot->kobj,
-                                          &hotplug_slot_attr_latch.attr);
-               if (retval)
-                       return retval;
-       }
-
-       if ((has_adapter_file(slot) == 0) &&
-           (slot->info->adapter_status != info->adapter_status)) {
-               retval = sysfs_update_file(&slot->kobj,
-                                          &hotplug_slot_attr_presence.attr);
-               if (retval)
-                       return retval;
-       }
-
-       if ((has_address_file(slot) == 0) &&
-           (slot->info->address != info->address)) {
-               retval = sysfs_update_file(&slot->kobj,
-                                          &hotplug_slot_attr_address.attr);
-               if (retval)
-                       return retval;
-       }
-
-       if ((has_max_bus_speed_file(slot) == 0) &&
-           (slot->info->max_bus_speed != info->max_bus_speed)) {
-               retval = sysfs_update_file(&slot->kobj,
-                                          &hotplug_slot_attr_max_bus_speed.attr);
-               if (retval)
-                       return retval;
-       }
-
-       if ((has_cur_bus_speed_file(slot) == 0) &&
-           (slot->info->cur_bus_speed != info->cur_bus_speed)) {
-               retval = sysfs_update_file(&slot->kobj,
-                                          &hotplug_slot_attr_cur_bus_speed.attr);
-               if (retval)
-                       return retval;
-       }
-
        memcpy (slot->info, info, sizeof (struct hotplug_slot_info));
 
        return 0;
index e5d3f0b4f45a274fb371bc623f47dd16aa33ab51..6462ac3b405fcc722f1f57e345e441a94138410a 100644 (file)
@@ -304,8 +304,8 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
        dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
        hotplug_slot->info->attention_status = status;
-       
-       if (ATTN_LED(slot->ctrl->ctrlcap)) 
+
+       if (ATTN_LED(slot->ctrl->ctrlcap))
                slot->hpc_ops->set_attention_status(slot, status);
 
        return 0;
@@ -405,7 +405,7 @@ static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe
        int retval;
 
        dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
-       
+
        retval = slot->hpc_ops->get_max_bus_speed(slot, value);
        if (retval < 0)
                *value = PCI_SPEED_UNKNOWN;
@@ -419,7 +419,7 @@ static int get_cur_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe
        int retval;
 
        dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
-       
+
        retval = slot->hpc_ops->get_cur_bus_speed(slot, value);
        if (retval < 0)
                *value = PCI_SPEED_UNKNOWN;
@@ -434,7 +434,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
        struct slot *t_slot;
        u8 value;
        struct pci_dev *pdev;
-       
+
        ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
        if (!ctrl) {
                err("%s : out of memory\n", __FUNCTION__);
@@ -502,23 +502,23 @@ static void pciehp_remove (struct pcie_device *dev)
 #ifdef CONFIG_PM
 static int pciehp_suspend (struct pcie_device *dev, pm_message_t state)
 {
-       printk("%s ENTRY\n", __FUNCTION__);     
+       printk("%s ENTRY\n", __FUNCTION__);
        return 0;
 }
 
 static int pciehp_resume (struct pcie_device *dev)
 {
-       printk("%s ENTRY\n", __FUNCTION__);     
+       printk("%s ENTRY\n", __FUNCTION__);
        return 0;
 }
 #endif
 
-static struct pcie_port_service_id port_pci_ids[] = { { 
-       .vendor = PCI_ANY_ID, 
+static struct pcie_port_service_id port_pci_ids[] = { {
+       .vendor = PCI_ANY_ID,
        .device = PCI_ANY_ID,
        .port_type = PCIE_ANY_PORT,
        .service_type = PCIE_PORT_SERVICE_HP,
-       .driver_data =  0, 
+       .driver_data =  0,
        }, { /* end: all zeroes */ }
 };
 static const char device_name[] = "hpdriver";
@@ -540,10 +540,6 @@ static int __init pcied_init(void)
 {
        int retval = 0;
 
-#ifdef CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE
-       pciehp_poll_mode = 1;
-#endif
-
        retval = pcie_port_service_register(&hpdriver_portdrv);
        dbg("pcie_port_service_register = %d\n", retval);
        info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
index 98e541ffef3d5f9ae0d90d91f5c66b358bfc4783..c8cb49c5a7525ac838e2da871f56c5a1fd3cf6a5 100644 (file)
@@ -173,7 +173,7 @@ u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl)
        return 1;
 }
 
-/* The following routines constitute the bulk of the 
+/* The following routines constitute the bulk of the
    hotplug controller logic
  */
 
@@ -181,7 +181,7 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot)
 {
        /* turn off slot, turn on Amber LED, turn off Green LED if supported*/
        if (POWER_CTRL(ctrl->ctrlcap)) {
-               if (pslot->hpc_ops->power_off_slot(pslot)) {   
+               if (pslot->hpc_ops->power_off_slot(pslot)) {
                        err("%s: Issue of Slot Power Off command failed\n",
                            __FUNCTION__);
                        return;
@@ -189,7 +189,7 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot)
        }
 
        if (PWR_LED(ctrl->ctrlcap))
-               pslot->hpc_ops->green_led_off(pslot);   
+               pslot->hpc_ops->green_led_off(pslot);
 
        if (ATTN_LED(ctrl->ctrlcap)) {
                if (pslot->hpc_ops->set_attention_status(pslot, 1)) {
@@ -231,7 +231,7 @@ static int board_added(struct slot *p_slot)
                if (retval)
                        return retval;
        }
-       
+
        if (PWR_LED(ctrl->ctrlcap))
                p_slot->hpc_ops->green_led_blink(p_slot);
 
@@ -548,7 +548,7 @@ int pciehp_enable_slot(struct slot *p_slot)
                mutex_unlock(&p_slot->ctrl->crit_sect);
                return -ENODEV;
        }
-       if (MRL_SENS(p_slot->ctrl->ctrlcap)) {  
+       if (MRL_SENS(p_slot->ctrl->ctrlcap)) {
                rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
                if (rc || getstatus) {
                        info("%s: latch open on slot(%s)\n", __FUNCTION__,
@@ -557,8 +557,8 @@ int pciehp_enable_slot(struct slot *p_slot)
                        return -ENODEV;
                }
        }
-       
-       if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {        
+
+       if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {
                rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
                if (rc || getstatus) {
                        info("%s: already enabled on slot(%s)\n", __FUNCTION__,
@@ -593,7 +593,7 @@ int pciehp_disable_slot(struct slot *p_slot)
        /* Check to see if (latch closed, card present, power on) */
        mutex_lock(&p_slot->ctrl->crit_sect);
 
-       if (!HP_SUPR_RM(p_slot->ctrl->ctrlcap)) {       
+       if (!HP_SUPR_RM(p_slot->ctrl->ctrlcap)) {
                ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
                if (ret || !getstatus) {
                        info("%s: no adapter on slot(%s)\n", __FUNCTION__,
@@ -603,7 +603,7 @@ int pciehp_disable_slot(struct slot *p_slot)
                }
        }
 
-       if (MRL_SENS(p_slot->ctrl->ctrlcap)) {  
+       if (MRL_SENS(p_slot->ctrl->ctrlcap)) {
                ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
                if (ret || getstatus) {
                        info("%s: latch open on slot(%s)\n", __FUNCTION__,
@@ -613,7 +613,7 @@ int pciehp_disable_slot(struct slot *p_slot)
                }
        }
 
-       if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {        
+       if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {
                ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
                if (ret || !getstatus) {
                        info("%s: already disabled slot(%s)\n", __FUNCTION__,
index 016eea94a8a5729d1cf6e5908a2c6a205d4b6149..06d025b8b13f6a8f276e396bfc36a742c5a676a4 100644 (file)
 
 #include "../pci.h"
 #include "pciehp.h"
-#ifdef DEBUG
-#define DBG_K_TRACE_ENTRY      ((unsigned int)0x00000001)      /* On function entry */
-#define DBG_K_TRACE_EXIT       ((unsigned int)0x00000002)      /* On function exit */
-#define DBG_K_INFO             ((unsigned int)0x00000004)      /* Info messages */
-#define DBG_K_ERROR            ((unsigned int)0x00000008)      /* Error messages */
-#define DBG_K_TRACE            (DBG_K_TRACE_ENTRY|DBG_K_TRACE_EXIT)
-#define DBG_K_STANDARD         (DBG_K_INFO|DBG_K_ERROR|DBG_K_TRACE)
-/* Redefine this flagword to set debug level */
-#define DEBUG_LEVEL            DBG_K_STANDARD
-
-#define DEFINE_DBG_BUFFER     char __dbg_str_buf[256];
-
-#define DBG_PRINT( dbg_flags, args... )              \
-       do {                                             \
-         if ( DEBUG_LEVEL & ( dbg_flags ) )             \
-         {                                              \
-           int len;                                     \
-           len = sprintf( __dbg_str_buf, "%s:%d: %s: ", \
-                 __FILE__, __LINE__, __FUNCTION__ );    \
-           sprintf( __dbg_str_buf + len, args );        \
-           printk( KERN_NOTICE "%s\n", __dbg_str_buf ); \
-         }                                              \
-       } while (0)
-
-#define DBG_ENTER_ROUTINE      DBG_PRINT (DBG_K_TRACE_ENTRY, "%s", "[Entry]");
-#define DBG_LEAVE_ROUTINE      DBG_PRINT (DBG_K_TRACE_EXIT, "%s", "[Exit]");
-#else
-#define DEFINE_DBG_BUFFER
-#define DBG_ENTER_ROUTINE
-#define DBG_LEAVE_ROUTINE
-#endif                         /* DEBUG */
 
 static atomic_t pciehp_num_controllers = ATOMIC_INIT(0);
 
@@ -160,10 +129,10 @@ static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value)
 /* Link Width Encoding */
 #define LNK_X1         0x01
 #define LNK_X2         0x02
-#define LNK_X4         0x04    
+#define LNK_X4         0x04
 #define LNK_X8         0x08
 #define LNK_X12                0x0C
-#define LNK_X16                0x10    
+#define LNK_X16                0x10
 #define LNK_X32                0x20
 
 /*Field definitions of Link Status Register */
@@ -221,8 +190,6 @@ static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value)
 #define EMI_STATE              0x0080
 #define EMI_STATUS_BIT         7
 
-DEFINE_DBG_BUFFER              /* Debug string buffer for entire HPC defined here */
-
 static irqreturn_t pcie_isr(int irq, void *dev_id);
 static void start_int_poll_timer(struct controller *ctrl, int sec);
 
@@ -231,14 +198,12 @@ static void int_poll_timeout(unsigned long data)
 {
        struct controller *ctrl = (struct controller *)data;
 
-       DBG_ENTER_ROUTINE
-
        /* Poll for interrupt events.  regs == NULL => polling */
        pcie_isr(0, ctrl);
 
        init_timer(&ctrl->poll_timer);
        if (!pciehp_poll_time)
-               pciehp_poll_time = 2; /* reset timer to poll in 2 secs if user doesn't specify at module installation*/
+               pciehp_poll_time = 2; /* default polling interval is 2 sec */
 
        start_int_poll_timer(ctrl, pciehp_poll_time);
 }
@@ -289,8 +254,6 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask)
        u16 slot_ctrl;
        unsigned long flags;
 
-       DBG_ENTER_ROUTINE 
-
        mutex_lock(&ctrl->ctrl_lock);
 
        retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
@@ -299,7 +262,7 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask)
                goto out;
        }
 
-       if ((slot_status & CMD_COMPLETED) == CMD_COMPLETED ) { 
+       if ((slot_status & CMD_COMPLETED) == CMD_COMPLETED ) {
                /* After 1 sec and CMD_COMPLETED still not set, just
                   proceed forward to issue the next command according
                   to spec.  Just print out the error message */
@@ -332,7 +295,6 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask)
                retval = pcie_wait_cmd(ctrl);
  out:
        mutex_unlock(&ctrl->ctrl_lock);
-       DBG_LEAVE_ROUTINE 
        return retval;
 }
 
@@ -341,8 +303,6 @@ static int hpc_check_lnk_status(struct controller *ctrl)
        u16 lnk_status;
        int retval = 0;
 
-       DBG_ENTER_ROUTINE 
-
        retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
        if (retval) {
                err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__);
@@ -350,26 +310,22 @@ static int hpc_check_lnk_status(struct controller *ctrl)
        }
 
        dbg("%s: lnk_status = %x\n", __FUNCTION__, lnk_status);
-       if ( (lnk_status & LNK_TRN) || (lnk_status & LNK_TRN_ERR) || 
+       if ( (lnk_status & LNK_TRN) || (lnk_status & LNK_TRN_ERR) ||
                !(lnk_status & NEG_LINK_WD)) {
                err("%s : Link Training Error occurs \n", __FUNCTION__);
                retval = -1;
                return retval;
        }
 
-       DBG_LEAVE_ROUTINE 
        return retval;
 }
 
-
 static int hpc_get_attention_status(struct slot *slot, u8 *status)
 {
        struct controller *ctrl = slot->ctrl;
        u16 slot_ctrl;
        u8 atten_led_state;
        int retval = 0;
-       
-       DBG_ENTER_ROUTINE 
 
        retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
        if (retval) {
@@ -400,7 +356,6 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status)
                break;
        }
 
-       DBG_LEAVE_ROUTINE 
        return 0;
 }
 
@@ -410,8 +365,6 @@ static int hpc_get_power_status(struct slot *slot, u8 *status)
        u16 slot_ctrl;
        u8 pwr_state;
        int     retval = 0;
-       
-       DBG_ENTER_ROUTINE 
 
        retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
        if (retval) {
@@ -428,35 +381,30 @@ static int hpc_get_power_status(struct slot *slot, u8 *status)
                *status = 1;
                break;
        case 1:
-               *status = 0;    
+               *status = 0;
                break;
        default:
                *status = 0xFF;
                break;
        }
 
-       DBG_LEAVE_ROUTINE 
        return retval;
 }
 
-
 static int hpc_get_latch_status(struct slot *slot, u8 *status)
 {
        struct controller *ctrl = slot->ctrl;
        u16 slot_status;
        int retval = 0;
 
-       DBG_ENTER_ROUTINE 
-
        retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
        if (retval) {
                err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
                return retval;
        }
 
-       *status = (((slot_status & MRL_STATE) >> 5) == 0) ? 0 : 1;  
+       *status = (((slot_status & MRL_STATE) >> 5) == 0) ? 0 : 1;
 
-       DBG_LEAVE_ROUTINE 
        return 0;
 }
 
@@ -467,8 +415,6 @@ static int hpc_get_adapter_status(struct slot *slot, u8 *status)
        u8 card_state;
        int retval = 0;
 
-       DBG_ENTER_ROUTINE 
-
        retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
        if (retval) {
                err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
@@ -477,7 +423,6 @@ static int hpc_get_adapter_status(struct slot *slot, u8 *status)
        card_state = (u8)((slot_status & PRSN_STATE) >> 6);
        *status = (card_state == 1) ? 1 : 0;
 
-       DBG_LEAVE_ROUTINE 
        return 0;
 }
 
@@ -488,16 +433,13 @@ static int hpc_query_power_fault(struct slot *slot)
        u8 pwr_fault;
        int retval = 0;
 
-       DBG_ENTER_ROUTINE 
-
        retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
        if (retval) {
                err("%s: Cannot check for power fault\n", __FUNCTION__);
                return retval;
        }
        pwr_fault = (u8)((slot_status & PWR_FAULT_DETECTED) >> 1);
-       
-       DBG_LEAVE_ROUTINE
+
        return pwr_fault;
 }
 
@@ -507,8 +449,6 @@ static int hpc_get_emi_status(struct slot *slot, u8 *status)
        u16 slot_status;
        int retval = 0;
 
-       DBG_ENTER_ROUTINE
-
        retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
        if (retval) {
                err("%s : Cannot check EMI status\n", __FUNCTION__);
@@ -516,7 +456,6 @@ static int hpc_get_emi_status(struct slot *slot, u8 *status)
        }
        *status = (slot_status & EMI_STATE) >> EMI_STATUS_BIT;
 
-       DBG_LEAVE_ROUTINE
        return retval;
 }
 
@@ -526,8 +465,6 @@ static int hpc_toggle_emi(struct slot *slot)
        u16 cmd_mask;
        int rc;
 
-       DBG_ENTER_ROUTINE
-
        slot_cmd = EMI_CTRL;
        cmd_mask = EMI_CTRL;
        if (!pciehp_poll_mode) {
@@ -537,7 +474,7 @@ static int hpc_toggle_emi(struct slot *slot)
 
        rc = pcie_write_cmd(slot, slot_cmd, cmd_mask);
        slot->last_emi_toggle = get_seconds();
-       DBG_LEAVE_ROUTINE
+
        return rc;
 }
 
@@ -548,8 +485,6 @@ static int hpc_set_attention_status(struct slot *slot, u8 value)
        u16 cmd_mask;
        int rc;
 
-       DBG_ENTER_ROUTINE
-
        cmd_mask = ATTN_LED_CTRL;
        switch (value) {
                case 0 :        /* turn off */
@@ -572,19 +507,15 @@ static int hpc_set_attention_status(struct slot *slot, u8 value)
        rc = pcie_write_cmd(slot, slot_cmd, cmd_mask);
        dbg("%s: SLOTCTRL %x write cmd %x\n",
            __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
-       
-       DBG_LEAVE_ROUTINE
+
        return rc;
 }
 
-
 static void hpc_set_green_led_on(struct slot *slot)
 {
        struct controller *ctrl = slot->ctrl;
        u16 slot_cmd;
        u16 cmd_mask;
-               
-       DBG_ENTER_ROUTINE
 
        slot_cmd = 0x0100;
        cmd_mask = PWR_LED_CTRL;
@@ -597,8 +528,6 @@ static void hpc_set_green_led_on(struct slot *slot)
 
        dbg("%s: SLOTCTRL %x write cmd %x\n",
            __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
-       DBG_LEAVE_ROUTINE
-       return;
 }
 
 static void hpc_set_green_led_off(struct slot *slot)
@@ -607,8 +536,6 @@ static void hpc_set_green_led_off(struct slot *slot)
        u16 slot_cmd;
        u16 cmd_mask;
 
-       DBG_ENTER_ROUTINE
-
        slot_cmd = 0x0300;
        cmd_mask = PWR_LED_CTRL;
        if (!pciehp_poll_mode) {
@@ -619,9 +546,6 @@ static void hpc_set_green_led_off(struct slot *slot)
        pcie_write_cmd(slot, slot_cmd, cmd_mask);
        dbg("%s: SLOTCTRL %x write cmd %x\n",
            __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
-
-       DBG_LEAVE_ROUTINE
-       return;
 }
 
 static void hpc_set_green_led_blink(struct slot *slot)
@@ -629,8 +553,6 @@ static void hpc_set_green_led_blink(struct slot *slot)
        struct controller *ctrl = slot->ctrl;
        u16 slot_cmd;
        u16 cmd_mask;
-       
-       DBG_ENTER_ROUTINE
 
        slot_cmd = 0x0200;
        cmd_mask = PWR_LED_CTRL;
@@ -643,14 +565,10 @@ static void hpc_set_green_led_blink(struct slot *slot)
 
        dbg("%s: SLOTCTRL %x write cmd %x\n",
            __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
-       DBG_LEAVE_ROUTINE
-       return;
 }
 
 static void hpc_release_ctlr(struct controller *ctrl)
 {
-       DBG_ENTER_ROUTINE 
-
        if (pciehp_poll_mode)
                del_timer(&ctrl->poll_timer);
        else
@@ -662,8 +580,6 @@ static void hpc_release_ctlr(struct controller *ctrl)
         */
        if (atomic_dec_and_test(&pciehp_num_controllers))
                destroy_workqueue(pciehp_wq);
-
-       DBG_LEAVE_ROUTINE
 }
 
 static int hpc_power_on_slot(struct slot * slot)
@@ -674,8 +590,6 @@ static int hpc_power_on_slot(struct slot * slot)
        u16 slot_status;
        int retval = 0;
 
-       DBG_ENTER_ROUTINE 
-
        dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot);
 
        /* Clear sticky power-fault bit from previous power failures */
@@ -719,8 +633,6 @@ static int hpc_power_on_slot(struct slot * slot)
        dbg("%s: SLOTCTRL %x write cmd %x\n",
            __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
 
-       DBG_LEAVE_ROUTINE
-
        return retval;
 }
 
@@ -731,8 +643,6 @@ static int hpc_power_off_slot(struct slot * slot)
        u16 cmd_mask;
        int retval = 0;
 
-       DBG_ENTER_ROUTINE 
-
        dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot);
 
        slot_cmd = POWER_OFF;
@@ -764,8 +674,6 @@ static int hpc_power_off_slot(struct slot * slot)
        dbg("%s: SLOTCTRL %x write cmd %x\n",
            __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
 
-       DBG_LEAVE_ROUTINE
-
        return retval;
 }
 
@@ -784,8 +692,8 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
                return IRQ_NONE;
        }
 
-       intr_detect = ( ATTN_BUTTN_PRESSED | PWR_FAULT_DETECTED | MRL_SENS_CHANGED |
-                                       PRSN_DETECT_CHANGED | CMD_COMPLETED );
+       intr_detect = (ATTN_BUTTN_PRESSED | PWR_FAULT_DETECTED |
+                      MRL_SENS_CHANGED | PRSN_DETECT_CHANGED | CMD_COMPLETED);
 
        intr_loc = slot_status & intr_detect;
 
@@ -807,7 +715,8 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
 
                dbg("%s: pciehp_readw(SLOTCTRL) with value %x\n",
                    __FUNCTION__, temp_word);
-               temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00;
+               temp_word = (temp_word & ~HP_INTR_ENABLE &
+                            ~CMD_CMPL_INTR_ENABLE) | 0x00;
                rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
                if (rc) {
                        err("%s: Cannot write to SLOTCTRL register\n",
@@ -825,7 +734,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
                }
                dbg("%s: pciehp_readw(SLOTSTATUS) with value %x\n",
                    __FUNCTION__, slot_status);
-               
+
                /* Clear command complete interrupt caused by this write */
                temp_word = 0x1f;
                rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
@@ -835,10 +744,10 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
                        return IRQ_NONE;
                }
        }
-       
+
        if (intr_loc & CMD_COMPLETED) {
-               /* 
-                * Command Complete Interrupt Pending 
+               /*
+                * Command Complete Interrupt Pending
                 */
                ctrl->cmd_busy = 0;
                wake_up_interruptible(&ctrl->queue);
@@ -892,7 +801,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
                            __FUNCTION__);
                        return IRQ_NONE;
                }
-               
+
                /* Clear command complete interrupt caused by this write */
                temp_word = 0x1F;
                rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
@@ -904,19 +813,17 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
                dbg("%s: pciehp_writew(SLOTSTATUS) with value %x\n",
                    __FUNCTION__, temp_word);
        }
-       
+
        return IRQ_HANDLED;
 }
 
-static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
+static int hpc_get_max_lnk_speed(struct slot *slot, enum pci_bus_speed *value)
 {
        struct controller *ctrl = slot->ctrl;
        enum pcie_link_speed lnk_speed;
        u32     lnk_cap;
        int retval = 0;
 
-       DBG_ENTER_ROUTINE 
-
        retval = pciehp_readl(ctrl, LNKCAP, &lnk_cap);
        if (retval) {
                err("%s: Cannot read LNKCAP register\n", __FUNCTION__);
@@ -934,19 +841,18 @@ static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
 
        *value = lnk_speed;
        dbg("Max link speed = %d\n", lnk_speed);
-       DBG_LEAVE_ROUTINE 
+
        return retval;
 }
 
-static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value)
+static int hpc_get_max_lnk_width(struct slot *slot,
+                                enum pcie_link_width *value)
 {
        struct controller *ctrl = slot->ctrl;
        enum pcie_link_width lnk_wdth;
        u32     lnk_cap;
        int retval = 0;
 
-       DBG_ENTER_ROUTINE 
-
        retval = pciehp_readl(ctrl, LNKCAP, &lnk_cap);
        if (retval) {
                err("%s: Cannot read LNKCAP register\n", __FUNCTION__);
@@ -985,19 +891,17 @@ static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value
 
        *value = lnk_wdth;
        dbg("Max link width = %d\n", lnk_wdth);
-       DBG_LEAVE_ROUTINE 
+
        return retval;
 }
 
-static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
+static int hpc_get_cur_lnk_speed(struct slot *slot, enum pci_bus_speed *value)
 {
        struct controller *ctrl = slot->ctrl;
        enum pcie_link_speed lnk_speed = PCI_SPEED_UNKNOWN;
        int retval = 0;
        u16 lnk_status;
 
-       DBG_ENTER_ROUTINE 
-
        retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
        if (retval) {
                err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__);
@@ -1015,25 +919,24 @@ static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
 
        *value = lnk_speed;
        dbg("Current link speed = %d\n", lnk_speed);
-       DBG_LEAVE_ROUTINE 
+
        return retval;
 }
 
-static int hpc_get_cur_lnk_width (struct slot *slot, enum pcie_link_width *value)
+static int hpc_get_cur_lnk_width(struct slot *slot,
+                                enum pcie_link_width *value)
 {
        struct controller *ctrl = slot->ctrl;
        enum pcie_link_width lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN;
        int retval = 0;
        u16 lnk_status;
 
-       DBG_ENTER_ROUTINE 
-
        retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
        if (retval) {
                err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__);
                return retval;
        }
-       
+
        switch ((lnk_status & 0x03F0) >> 4){
        case 0:
                lnk_wdth = PCIE_LNK_WIDTH_RESRV;
@@ -1066,7 +969,7 @@ static int hpc_get_cur_lnk_width (struct slot *slot, enum pcie_link_width *value
 
        *value = lnk_wdth;
        dbg("Current link width = %d\n", lnk_wdth);
-       DBG_LEAVE_ROUTINE 
+
        return retval;
 }
 
@@ -1085,12 +988,12 @@ static struct hpc_ops pciehp_hpc_ops = {
        .get_cur_bus_speed              = hpc_get_cur_lnk_speed,
        .get_max_lnk_width              = hpc_get_max_lnk_width,
        .get_cur_lnk_width              = hpc_get_cur_lnk_width,
-       
+
        .query_power_fault              = hpc_query_power_fault,
        .green_led_on                   = hpc_set_green_led_on,
        .green_led_off                  = hpc_set_green_led_off,
        .green_led_blink                = hpc_set_green_led_blink,
-       
+
        .release_ctlr                   = hpc_release_ctlr,
        .check_lnk_status               = hpc_check_lnk_status,
 };
@@ -1138,6 +1041,7 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev)
                dbg("Trying to get hotplug control for %s \n",
                        (char *)string.pointer);
                status = pci_osc_control_set(handle,
+                               OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL |
                                OSC_PCI_EXPRESS_NATIVE_HP_CONTROL);
                if (status == AE_NOT_FOUND)
                        status = acpi_run_oshp(handle);
@@ -1163,8 +1067,6 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev)
 }
 #endif
 
-
-
 int pcie_init(struct controller * ctrl, struct pcie_device *dev)
 {
        int rc;
@@ -1176,8 +1078,6 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
        u16 slot_status, slot_ctrl;
        struct pci_dev *pdev;
 
-       DBG_ENTER_ROUTINE
-       
        pdev = dev->port;
        ctrl->pci_dev = pdev;   /* save pci_dev in context */
 
@@ -1201,9 +1101,11 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
        dbg("%s: CAPREG offset %x cap_reg %x\n",
            __FUNCTION__, ctrl->cap_base + CAPREG, cap_reg);
 
-       if (((cap_reg & SLOT_IMPL) == 0) || (((cap_reg & DEV_PORT_TYPE) != 0x0040)
+       if (((cap_reg & SLOT_IMPL) == 0) ||
+           (((cap_reg & DEV_PORT_TYPE) != 0x0040)
                && ((cap_reg & DEV_PORT_TYPE) != 0x0060))) {
-               dbg("%s : This is not a root port or the port is not connected to a slot\n", __FUNCTION__);
+               dbg("%s : This is not a root port or the port is not "
+                   "connected to a slot\n", __FUNCTION__);
                goto abort_free_ctlr;
        }
 
@@ -1236,14 +1138,15 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
        dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n",
            __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
 
-       for ( rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++)
+       for (rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++)
                if (pci_resource_len(pdev, rc) > 0)
                        dbg("pci resource[%d] start=0x%llx(len=0x%llx)\n", rc,
                            (unsigned long long)pci_resource_start(pdev, rc),
                            (unsigned long long)pci_resource_len(pdev, rc));
 
-       info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, 
-               pdev->subsystem_vendor, pdev->subsystem_device);
+       info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n",
+            pdev->vendor, pdev->device,
+            pdev->subsystem_vendor, pdev->subsystem_device);
 
        mutex_init(&ctrl->crit_sect);
        mutex_init(&ctrl->ctrl_lock);
@@ -1267,7 +1170,8 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
 
        dbg("%s: SLOTCTRL %x value read %x\n",
            __FUNCTION__, ctrl->cap_base + SLOTCTRL, temp_word);
-       temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00;
+       temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) |
+               0x00;
 
        rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
        if (rc) {
@@ -1330,14 +1234,14 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
 
        if (ATTN_BUTTN(slot_cap))
                intr_enable = intr_enable | ATTN_BUTTN_ENABLE;
-       
+
        if (POWER_CTRL(slot_cap))
                intr_enable = intr_enable | PWR_FAULT_DETECT_ENABLE;
-       
+
        if (MRL_SENS(slot_cap))
                intr_enable = intr_enable | MRL_DETECT_ENABLE;
 
-       temp_word = (temp_word & ~intr_enable) | intr_enable; 
+       temp_word = (temp_word & ~intr_enable) | intr_enable;
 
        if (pciehp_poll_mode) {
                temp_word = (temp_word & ~HP_INTR_ENABLE) | 0x0;
@@ -1345,7 +1249,10 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
                temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE;
        }
 
-       /* Unmask Hot-plug Interrupt Enable for the interrupt notification mechanism case */
+       /*
+        * Unmask Hot-plug Interrupt Enable for the interrupt
+        * notification mechanism case.
+        */
        rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
        if (rc) {
                err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
@@ -1356,14 +1263,14 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
                err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
                goto abort_disable_intr;
        }
-       
+
        temp_word =  0x1F; /* Clear all events */
        rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
        if (rc) {
                err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
                goto abort_disable_intr;
        }
-       
+
        if (pciehp_force) {
                dbg("Bypassing BIOS check for pciehp use on %s\n",
                                pci_name(ctrl->pci_dev));
@@ -1375,10 +1282,9 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
 
        ctrl->hpc_ops = &pciehp_hpc_ops;
 
-       DBG_LEAVE_ROUTINE
        return 0;
 
-       /* We end up here for the many possible ways to fail this API.  */
+       /* We end up here for the many possible ways to fail this API. */
 abort_disable_intr:
        rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
        if (!rc) {
@@ -1395,6 +1301,5 @@ abort_free_irq:
                free_irq(ctrl->pci_dev->irq, ctrl);
 
 abort_free_ctlr:
-       DBG_LEAVE_ROUTINE
        return -1;
 }
index 854aaea09e4db788bc048739ffbe9b20bc8e0140..c424aded13fb43fb108d41870d1c4f46c207de28 100644 (file)
@@ -243,9 +243,10 @@ int pciehp_configure_device(struct slot *p_slot)
 
 int pciehp_unconfigure_device(struct slot *p_slot)
 {
-       int rc = 0;
+       int ret, rc = 0;
        int j;
        u8 bctl = 0;
+       u8 presence = 0;
        struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate;
 
        dbg("%s: bus/dev = %x/%x\n", __FUNCTION__, p_slot->bus,
@@ -263,23 +264,28 @@ int pciehp_unconfigure_device(struct slot *p_slot)
                        continue;
                }
                if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
-                       pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, &bctl);
-                       if (bctl & PCI_BRIDGE_CTL_VGA) {
-                               err("Cannot remove display device %s\n",
+                       ret = p_slot->hpc_ops->get_adapter_status(p_slot,
+                                                               &presence);
+                       if (!ret && presence) {
+                               pci_read_config_byte(temp, PCI_BRIDGE_CONTROL,
+                                       &bctl);
+                               if (bctl & PCI_BRIDGE_CTL_VGA) {
+                                       err("Cannot remove display device %s\n",
                                                pci_name(temp));
-                               pci_dev_put(temp);
-                               continue;
+                                       pci_dev_put(temp);
+                                       continue;
+                               }
                        }
                }
                pci_remove_bus_device(temp);
                pci_dev_put(temp);
        }
-       /* 
+       /*
         * Some PCI Express root ports require fixup after hot-plug operation.
         */
-       if (pcie_mch_quirk) 
+       if (pcie_mch_quirk)
                pci_fixup_device(pci_fixup_final, p_slot->ctrl->pci_dev);
-       
+
        return rc;
 }
 
index df076064a3e07d2980d0cea2bbab5e8ab557bbd7..a080fedf03327fb0b8fe92a940cc71f68ec25c2e 100644 (file)
@@ -129,17 +129,17 @@ struct kobj_type ktype_dlpar_io = {
 };
 
 struct kset dlpar_io_kset = {
-       .kobj = {.name = DLPAR_KOBJ_NAME,
-                .ktype = &ktype_dlpar_io,
+       .kobj = {.ktype = &ktype_dlpar_io,
                 .parent = &pci_hotplug_slots_subsys.kobj},
        .ktype = &ktype_dlpar_io,
 };
 
 int dlpar_sysfs_init(void)
 {
+       kobject_set_name(&dlpar_io_kset.kobj, DLPAR_KOBJ_NAME);
        if (kset_register(&dlpar_io_kset)) {
                printk(KERN_ERR "rpadlpar_io: cannot register kset for %s\n",
-                               dlpar_io_kset.kobj.name);
+                               kobject_name(&dlpar_io_kset.kobj));
                return -EINVAL;
        }
 
index be1df85e5e2d5ae08b5a3f562cb462589495f409..87e01615053dc1fb228b05473e1bdac2d32b8e6c 100644 (file)
@@ -132,7 +132,7 @@ void read_msi_msg(unsigned int irq, struct msi_msg *msg)
                        pci_read_config_word(dev, msi_data_reg(pos, 1), &data);
                } else {
                        msg->address_hi = 0;
-                       pci_read_config_word(dev, msi_data_reg(pos, 1), &data);
+                       pci_read_config_word(dev, msi_data_reg(pos, 0), &data);
                }
                msg->data = data;
                break;
index 004bc248727096b3702b5b8e3f02fc89b6cb8ef1..6e2760b6c20a4cc1d1ce08ebb4d64dd87872c2d0 100644 (file)
@@ -54,7 +54,6 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count)
        if (!dynid)
                return -ENOMEM;
 
-       INIT_LIST_HEAD(&dynid->node);
        dynid->id.vendor = vendor;
        dynid->id.device = device;
        dynid->id.subvendor = subvendor;
@@ -65,7 +64,7 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count)
                driver_data : 0UL;
 
        spin_lock(&pdrv->dynids.lock);
-       list_add_tail(&pdrv->dynids.list, &dynid->node);
+       list_add_tail(&dynid->node, &pdrv->dynids.list);
        spin_unlock(&pdrv->dynids.lock);
 
        if (get_driver(&pdrv->driver)) {
@@ -532,8 +531,7 @@ void pci_dev_put(struct pci_dev *dev)
 }
 
 #ifndef CONFIG_HOTPLUG
-int pci_uevent(struct device *dev, char **envp, int num_envp,
-              char *buffer, int buffer_size)
+int pci_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        return -ENODEV;
 }
index 37c00f6fd8010d3dc7b0b4582fea08394e20317f..71d561fda0a2bb0903cf91ccaf78ae6a9b37f07d 100644 (file)
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include <linux/string.h>
+#include <linux/log2.h>
 #include <asm/dma.h>   /* isa_dma_bridge_buggy */
 #include "pci.h"
 
 unsigned int pci_pm_d3_delay = 10;
 
+#ifdef CONFIG_PCI_DOMAINS
+int pci_domains_supported = 1;
+#endif
+
 #define DEFAULT_CARDBUS_IO_SIZE                (256)
 #define DEFAULT_CARDBUS_MEM_SIZE       (64*1024*1024)
 /* pci=cbmemsize=nnM,cbiosize=nn can override this */
@@ -653,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);
@@ -1454,7 +1459,7 @@ int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc)
        int cap, err = -EINVAL;
        u32 stat, cmd, v, o;
 
-       if (mmrbc < 512 || mmrbc > 4096 || (mmrbc & (mmrbc-1)))
+       if (mmrbc < 512 || mmrbc > 4096 || !is_power_of_2(mmrbc))
                goto out;
 
        v = ffs(mmrbc) - 10;
@@ -1526,7 +1531,7 @@ int pcie_set_readrq(struct pci_dev *dev, int rq)
        int cap, err = -EINVAL;
        u16 ctl, v;
 
-       if (rq < 128 || rq > 4096 || (rq & (rq-1)))
+       if (rq < 128 || rq > 4096 || !is_power_of_2(rq))
                goto out;
 
        v = (ffs(rq) - 8) << 12;
@@ -1566,6 +1571,13 @@ int pci_select_bars(struct pci_dev *dev, unsigned long flags)
        return bars;
 }
 
+static void __devinit pci_no_domains(void)
+{
+#ifdef CONFIG_PCI_DOMAINS
+       pci_domains_supported = 0;
+#endif
+}
+
 static int __devinit pci_init(void)
 {
        struct pci_dev *dev = NULL;
@@ -1585,6 +1597,10 @@ static int __devinit pci_setup(char *str)
                if (*str && (str = pcibios_setup(str)) && *str) {
                        if (!strcmp(str, "nomsi")) {
                                pci_no_msi();
+                       } else if (!strcmp(str, "noaer")) {
+                               pci_no_aer();
+                       } else if (!strcmp(str, "nodomains")) {
+                               pci_no_domains();
                        } else if (!strncmp(str, "cbiosize=", 9)) {
                                pci_cardbus_io_size = memparse(str + 9, &str);
                        } else if (!strncmp(str, "cbmemsize=", 10)) {
index 4c36e80f6d26b26f590a45bfa1551c53440d0b4a..6fda33de84e85527f49b048db6889cd90815c75a 100644 (file)
@@ -1,7 +1,6 @@
 /* Functions internal to the PCI core code */
 
-extern int pci_uevent(struct device *dev, char **envp, int num_envp,
-                     char *buffer, int buffer_size);
+extern int pci_uevent(struct device *dev, struct kobj_uevent_env *env);
 extern int pci_create_sysfs_dev_files(struct pci_dev *pdev);
 extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev);
 extern void pci_cleanup_rom(struct pci_dev *dev);
@@ -52,6 +51,12 @@ void pci_restore_msi_state(struct pci_dev *dev);
 static inline void pci_restore_msi_state(struct pci_dev *dev) {}
 #endif
 
+#ifdef CONFIG_PCIEAER
+void pci_no_aer(void);
+#else
+static inline void pci_no_aer(void) { }
+#endif
+
 static inline int pci_no_d1d2(struct pci_dev *dev)
 {
        unsigned int parent_dstates = 0;
index 0ad92a8ad8b1a831007dc58cd47554a7be0ac68a..287a9311716c66b98fd06e7a44a3dff43738f27f 100644 (file)
@@ -25,13 +25,4 @@ config HOTPLUG_PCI_PCIE
 
          When in doubt, say N.
 
-config HOTPLUG_PCI_PCIE_POLL_EVENT_MODE
-       bool "Use polling mechanism for hot-plug events (for testing purpose)"
-       depends on HOTPLUG_PCI_PCIE
-       help
-         Say Y here if you want to use the polling mechanism for hot-plug 
-         events for early platform testing.
-          
-         When in doubt, say N.
-
 source "drivers/pci/pcie/aer/Kconfig"
index ad90a01b0dfc3c1ddd578ba677079ac0b3ebf5e9..7a62f7dd9009ab49a2deeb5d372fd45ceb881548 100644 (file)
@@ -81,6 +81,13 @@ static struct pcie_port_service_driver aerdriver = {
        .reset_link     = aer_root_reset,
 };
 
+static int pcie_aer_disable;
+
+void pci_no_aer(void)
+{
+       pcie_aer_disable = 1;   /* has priority over 'forceload' */
+}
+
 /**
  * aer_irq - Root Port's ISR
  * @irq: IRQ assigned to Root Port
@@ -327,6 +334,8 @@ static void aer_error_resume(struct pci_dev *dev)
  **/
 static int __init aer_service_init(void)
 {
+       if (pcie_aer_disable)
+               return -ENXIO;
        return pcie_port_service_register(&aerdriver);
 }
 
index 171ca712e523b0453c44f1657fff8d0564de9ad1..5db6b6690b596bb4ff5079673731e67c2773780d 100644 (file)
@@ -276,8 +276,7 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
                        sz = pci_size(l, sz, (u32)PCI_ROM_ADDRESS_MASK);
                        if (sz) {
                                res->flags = (l & IORESOURCE_ROM_ENABLE) |
-                                 IORESOURCE_MEM | IORESOURCE_PREFETCH |
-                                 IORESOURCE_READONLY | IORESOURCE_CACHEABLE;
+                                 IORESOURCE_MEM | IORESOURCE_READONLY;
                                res->start = l & PCI_ROM_ADDRESS_MASK;
                                res->end = res->start + (unsigned long) sz;
                        }
@@ -597,7 +596,7 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass
                pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses);
 
                if (!is_cardbus) {
-                       child->bridge_ctl = bctl | PCI_BRIDGE_CTL_NO_ISA;
+                       child->bridge_ctl = bctl;
                        /*
                         * Adjust subordinate busnr in parent buses.
                         * We do this before scanning for children because
@@ -744,22 +743,46 @@ static int pci_setup_device(struct pci_dev * dev)
                 */
                if (class == PCI_CLASS_STORAGE_IDE) {
                        u8 progif;
+                       struct pci_bus_region region;
+
                        pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
                        if ((progif & 1) == 0) {
-                               dev->resource[0].start = 0x1F0;
-                               dev->resource[0].end = 0x1F7;
-                               dev->resource[0].flags = LEGACY_IO_RESOURCE;
-                               dev->resource[1].start = 0x3F6;
-                               dev->resource[1].end = 0x3F6;
-                               dev->resource[1].flags = LEGACY_IO_RESOURCE;
+                               struct resource resource = {
+                                       .start = 0x1F0,
+                                       .end = 0x1F7,
+                                       .flags = LEGACY_IO_RESOURCE,
+                               };
+
+                               pcibios_resource_to_bus(dev, &region, &resource);
+                               dev->resource[0].start = region.start;
+                               dev->resource[0].end = region.end;
+                               dev->resource[0].flags = resource.flags;
+                               resource.start = 0x3F6;
+                               resource.end = 0x3F6;
+                               resource.flags = LEGACY_IO_RESOURCE;
+                               pcibios_resource_to_bus(dev, &region, &resource);
+                               dev->resource[1].start = region.start;
+                               dev->resource[1].end = region.end;
+                               dev->resource[1].flags = resource.flags;
                        }
                        if ((progif & 4) == 0) {
-                               dev->resource[2].start = 0x170;
-                               dev->resource[2].end = 0x177;
-                               dev->resource[2].flags = LEGACY_IO_RESOURCE;
-                               dev->resource[3].start = 0x376;
-                               dev->resource[3].end = 0x376;
-                               dev->resource[3].flags = LEGACY_IO_RESOURCE;
+                               struct resource resource = {
+                                       .start = 0x170,
+                                       .end = 0x177,
+                                       .flags = LEGACY_IO_RESOURCE,
+                               };
+
+                               pcibios_resource_to_bus(dev, &region, &resource);
+                               dev->resource[2].start = region.start;
+                               dev->resource[2].end = region.end;
+                               dev->resource[2].flags = resource.flags;
+                               resource.start = 0x376;
+                               resource.end = 0x376;
+                               resource.flags = LEGACY_IO_RESOURCE;
+                               pcibios_resource_to_bus(dev, &region, &resource);
+                               dev->resource[3].start = region.start;
+                               dev->resource[3].end = region.end;
+                               dev->resource[3].flags = resource.flags;
                        }
                }
                break;
index 90adc62d07ffb7006f820fe32486aea6abaa5377..716439e25dd283fcf4ecce43c9966bd33d044a27 100644 (file)
@@ -60,7 +60,7 @@ proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *pp
         */
 
        if (capable(CAP_SYS_ADMIN))
-               size = dev->cfg_size;
+               size = dp->size;
        else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
                size = 128;
        else
@@ -129,11 +129,11 @@ proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *pp
 static ssize_t
 proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, loff_t *ppos)
 {
-       const struct inode *ino = file->f_path.dentry->d_inode;
+       struct inode *ino = file->f_path.dentry->d_inode;
        const struct proc_dir_entry *dp = PDE(ino);
        struct pci_dev *dev = dp->data;
        int pos = *ppos;
-       int size = dev->cfg_size;
+       int size = dp->size;
        int cnt;
 
        if (pos >= size)
@@ -193,6 +193,7 @@ proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, lof
        }
 
        *ppos = pos;
+       i_size_write(ino, dp->size);
        return nbytes;
 }
 
index 50f2dd9e1bb2cac61a58d132c52046ac88fc5d66..59d4da2734c1f5f0f69fc41d7b0c04ef60358e09 100644 (file)
@@ -472,11 +472,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,      PCI_DEVICE_ID_INTEL_ICH8_3, quirk_
  */
 static void __devinit quirk_vt82c586_acpi(struct pci_dev *dev)
 {
-       u8 rev;
        u32 region;
 
-       pci_read_config_byte(dev, PCI_CLASS_REVISION, &rev);
-       if (rev & 0x10) {
+       if (dev->revision & 0x10) {
                pci_read_config_dword(dev, 0x48, &region);
                region &= PCI_BASE_ADDRESS_IO_MASK;
                quirk_io_region(dev, region, 256, PCI_BRIDGE_RESOURCES, "vt82c586 ACPI");
@@ -629,12 +627,9 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk
  */
 static void __init quirk_amd_8131_mmrbc(struct pci_dev *dev)
 {
-       unsigned char revid;
-
-       pci_read_config_byte(dev, PCI_REVISION_ID, &revid);
-       if (dev->subordinate && revid <= 0x12) {
+       if (dev->subordinate && dev->revision <= 0x12) {
                printk(KERN_INFO "AMD8131 rev %x detected, disabling PCI-X "
-                               "MMRBC\n", revid);
+                               "MMRBC\n", dev->revision);
                dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MMRBC;
        }
 }
@@ -930,38 +925,6 @@ static void __init quirk_eisa_bridge(struct pci_dev *dev)
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82375,      quirk_eisa_bridge );
 
-/*
- * On the MSI-K8T-Neo2Fir Board, the internal Soundcard is disabled
- * when a PCI-Soundcard is added. The BIOS only gives Options
- * "Disabled" and "AUTO". This Quirk Sets the corresponding
- * Register-Value to enable the Soundcard.
- *
- * FIXME: Presently this quirk will run on anything that has an 8237
- * which isn't correct, we need to check DMI tables or something in
- * order to make sure it only runs on the MSI-K8T-Neo2Fir.  Because it
- * runs everywhere at present we suppress the printk output in most
- * irrelevant cases.
- */
-static void k8t_sound_hostbridge(struct pci_dev *dev)
-{
-       unsigned char val;
-
-       pci_read_config_byte(dev, 0x50, &val);
-       if (val == 0xc8) {
-               /* Assume it's probably a MSI-K8T-Neo2Fir */
-               printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, attempting to turn soundcard ON\n");
-               pci_write_config_byte(dev, 0x50, val & (~0x40));
-
-               /* Verify the Change for Status output */
-               pci_read_config_byte(dev, 0x50, &val);
-               if (val & 0x40)
-                       printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, soundcard still off\n");
-               else
-                       printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, soundcard on\n");
-       }
-}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_hostbridge);
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_hostbridge);
 
 /*
  * On ASUS P4B boards, the SMBus PCI Device within the ICH2/4 southbridge
index 5e5191ec8de65931f916c4659e42cf1758e49409..401e03c920bdf034c3849ea01c03d6a5adc8fabc 100644 (file)
@@ -472,7 +472,12 @@ void pci_bus_size_bridges(struct pci_bus *bus)
                break;
 
        case PCI_CLASS_BRIDGE_PCI:
+               /* don't size subtractive decoding (transparent)
+                * PCI-to-PCI bridges */
+               if (bus->self->transparent)
+                       break;
                pci_bridge_check_ranges(bus);
+               /* fall through */
        default:
                pbus_size_io(bus);
                /* If the bridge supports prefetchable range, size it
index 568f1877315c5532d39052e4e615f1304a48cb93..05ca2ed9eb51fdc24340a3244a087e4680ae86ce 100644 (file)
@@ -48,7 +48,7 @@ pdev_fixup_irq(struct pci_dev *dev,
        dev->irq = irq;
 
        pr_debug("PCI: fixup irq: (%s) got %d\n",
-               dev->dev.kobj.name, dev->irq);
+               kobject_name(&dev->dev.kobj), dev->irq);
 
        /* Always tell the device, so the driver knows what is
           the real IRQ to use; the device does not use it. */
index f8b13f0270d744f87d766072599de14760aa821e..a0aca46ce877b455770e7fc48f39dc4c206dc925 100644 (file)
@@ -907,18 +907,14 @@ int pcmcia_insert_card(struct pcmcia_socket *skt)
 EXPORT_SYMBOL(pcmcia_insert_card);
 
 
-static int pcmcia_socket_uevent(struct device *dev, char **envp,
-                               int num_envp, char *buffer, int buffer_size)
+static int pcmcia_socket_uevent(struct device *dev,
+                               struct kobj_uevent_env *env)
 {
        struct pcmcia_socket *s = container_of(dev, struct pcmcia_socket, dev);
-       int i = 0, length = 0;
 
-       if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
-                          &length, "SOCKET_NO=%u", s->sock))
+       if (add_uevent_var(env, "SOCKET_NO=%u", s->sock))
                return -ENOMEM;
 
-       envp[i] = NULL;
-
        return 0;
 }
 
index a99607142fc81ee029ee136c443f82d18c83ec1a..55baa1f0fcbb5f8893456d117a5439bf7f1a950c 100644 (file)
@@ -1064,11 +1064,10 @@ static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) {
 
 #ifdef CONFIG_HOTPLUG
 
-static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp,
-                            char *buffer, int buffer_size)
+static int pcmcia_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        struct pcmcia_device *p_dev;
-       int i, length = 0;
+       int i;
        u32 hash[4] = { 0, 0, 0, 0};
 
        if (!dev)
@@ -1083,23 +1082,13 @@ static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp,
                hash[i] = crc32(0, p_dev->prod_id[i], strlen(p_dev->prod_id[i]));
        }
 
-       i = 0;
-
-       if (add_uevent_var(envp, num_envp, &i,
-                          buffer, buffer_size, &length,
-                          "SOCKET_NO=%u",
-                          p_dev->socket->sock))
+       if (add_uevent_var(env, "SOCKET_NO=%u", p_dev->socket->sock))
                return -ENOMEM;
 
-       if (add_uevent_var(envp, num_envp, &i,
-                          buffer, buffer_size, &length,
-                          "DEVICE_NO=%02X",
-                          p_dev->device_no))
+       if (add_uevent_var(env, "DEVICE_NO=%02X", p_dev->device_no))
                return -ENOMEM;
 
-       if (add_uevent_var(envp, num_envp, &i,
-                          buffer, buffer_size, &length,
-                          "MODALIAS=pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X"
+       if (add_uevent_var(env, "MODALIAS=pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X"
                           "pa%08Xpb%08Xpc%08Xpd%08X",
                           p_dev->has_manf_id ? p_dev->manf_id : 0,
                           p_dev->has_card_id ? p_dev->card_id : 0,
@@ -1112,15 +1101,12 @@ static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp,
                           hash[3]))
                return -ENOMEM;
 
-       envp[i] = NULL;
-
        return 0;
 }
 
 #else
 
-static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp,
-                             char *buffer, int buffer_size)
+static int pcmcia_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        return -ENODEV;
 }
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 383107ba4bd3f8859c8fde3c8c722e734c9fd229..f6722ba0dd1ea44e75bd64675b426f903d2ed286 100644 (file)
@@ -175,7 +175,6 @@ static int __init mst_pcmcia_init(void)
        if (!mst_pcmcia_device)
                return -ENOMEM;
 
-       mst_pcmcia_device->dev.uevent_suppress = 0;
        mst_pcmcia_device->dev.platform_data = &mst_pcmcia_ops;
 
        ret = platform_device_add(mst_pcmcia_device);
@@ -195,3 +194,4 @@ fs_initcall(mst_pcmcia_init);
 module_exit(mst_pcmcia_exit);
 
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa2xx-pcmcia");
index a2daa3f531b28855144eac20da587e017c4cca37..d5c33bd78d685fcb3a52a26a60ad6359530cbdfe 100644 (file)
@@ -261,7 +261,6 @@ static int __init sharpsl_pcmcia_init(void)
        if (!sharpsl_pcmcia_device)
                return -ENOMEM;
 
-       sharpsl_pcmcia_device->dev.uevent_suppress = 0;
        sharpsl_pcmcia_device->dev.platform_data = &sharpsl_pcmcia_ops;
        sharpsl_pcmcia_device->dev.parent = platform_scoop_config->devs[0].dev;
 
@@ -284,3 +283,4 @@ module_exit(sharpsl_pcmcia_exit);
 
 MODULE_DESCRIPTION("Sharp SL Series PCMCIA Support");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa2xx-pcmcia");
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 a9880d468ee482be9e0a4f22a3813e5c26a312bb..f38ba482be75a52ed50e9715a021f2f4c1fda08d 100644 (file)
@@ -14,8 +14,7 @@
 
 extern int power_supply_create_attrs(struct power_supply *psy);
 extern void power_supply_remove_attrs(struct power_supply *psy);
-extern int power_supply_uevent(struct device *dev, char **envp, int num_envp,
-                              char *buffer, int buffer_size);
+extern int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env);
 
 #else
 
index de3155b21285df91c29def0571409e28973bdbdc..249f61bae6396105b2466739c504dd2b6557b775 100644 (file)
@@ -195,11 +195,10 @@ static char *kstruprdup(const char *str, gfp_t gfp)
        return ret;
 }
 
-int power_supply_uevent(struct device *dev, char **envp, int num_envp,
-                       char *buffer, int buffer_size)
+int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        struct power_supply *psy = dev_get_drvdata(dev);
-       int i = 0, length = 0, ret = 0, j;
+       int ret = 0, j;
        char *prop_buf;
        char *attrname;
 
@@ -212,8 +211,7 @@ int power_supply_uevent(struct device *dev, char **envp, int num_envp,
 
        dev_dbg(dev, "POWER_SUPPLY_NAME=%s\n", psy->name);
 
-       ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
-                            &length, "POWER_SUPPLY_NAME=%s", psy->name);
+       ret = add_uevent_var(env, "POWER_SUPPLY_NAME=%s", psy->name);
        if (ret)
                return ret;
 
@@ -243,9 +241,7 @@ int power_supply_uevent(struct device *dev, char **envp, int num_envp,
 
                dev_dbg(dev, "Static prop %s=%s\n", attrname, prop_buf);
 
-               ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
-                                    &length, "POWER_SUPPLY_%s=%s",
-                                    attrname, prop_buf);
+               ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf);
                kfree(attrname);
                if (ret)
                        goto out;
@@ -282,14 +278,11 @@ int power_supply_uevent(struct device *dev, char **envp, int num_envp,
 
                dev_dbg(dev, "prop %s=%s\n", attrname, prop_buf);
 
-               ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
-                                    &length, "POWER_SUPPLY_%s=%s",
-                                    attrname, prop_buf);
+               ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf);
                kfree(attrname);
                if (ret)
                        goto out;
        }
-       envp[i] = NULL;
 
 out:
        free_page((unsigned long)prop_buf);
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 aeda52682446cc475770b918e82cdb3ae4a0431c..d427daeef511bd1bfaddf153b9c1c363da4e9cf3 100644 (file)
@@ -53,6 +53,7 @@
 #include <linux/genhd.h>
 #include <linux/hdreg.h>
 #include <linux/interrupt.h>
+#include <linux/log2.h>
 #include <asm/ccwdev.h>
 #include <linux/workqueue.h>
 #include <asm/debug.h>
@@ -456,7 +457,7 @@ dasd_free_chunk(struct list_head *chunk_list, void *mem)
 static inline int
 dasd_check_blocksize(int bsize)
 {
-       if (bsize < 512 || bsize > 4096 || (bsize & (bsize - 1)) != 0)
+       if (bsize < 512 || bsize > 4096 || !is_power_of_2(bsize))
                return -EMEDIUMTYPE;
        return 0;
 }
index 0fbacc8b106345cd6255fc6d46a94775bbb27963..f231bc21b1cafd3465dcf97cc3c4f6618b5b804c 100644 (file)
@@ -230,7 +230,7 @@ static int xpram_make_request(struct request_queue *q, struct bio *bio)
                }
        }
        set_bit(BIO_UPTODATE, &bio->bi_flags);
-       bio_end_io(bio, 0);
+       bio_endio(bio, 0);
        return 0;
 fail:
        bio_io_error(bio);
index 6000bdee4082830b87e978d0b5538e2765ff2c98..0e1f35c9ed9d4e0be6dc928d0d3bf69182799149 100644 (file)
@@ -667,6 +667,9 @@ raw3215_probe (struct ccw_device *cdev)
        struct raw3215_info *raw;
        int line;
 
+       /* Console is special. */
+       if (raw3215[0] && (cdev->dev.driver_data == raw3215[0]))
+               return 0;
        raw = kmalloc(sizeof(struct raw3215_info) +
                      RAW3215_INBUF_SIZE, GFP_KERNEL|GFP_DMA);
        if (raw == NULL)
index fd3479119eb4e1bc568a4f5d5b5e428bc6a5d8d8..0b040557db02d5ee67ad91c4179f4179d14d6a54 100644 (file)
@@ -22,6 +22,7 @@
 #include <asm/ebcdic.h>
 
 #include "raw3270.h"
+#include "tty3270.h"
 #include "ctrlchar.h"
 
 #define CON3270_OUTPUT_BUFFER_SIZE 1024
@@ -507,8 +508,6 @@ con3270_write(struct console *co, const char *str, unsigned int count)
        spin_unlock_irqrestore(&cp->view.lock,flags);
 }
 
-extern struct tty_driver *tty3270_driver;
-
 static struct tty_driver *
 con3270_device(struct console *c, int *index)
 {
index fa62e69440578375fb8028721a6e2c8c0a52ad96..25629b92dec362ef2e22c4343ca383e0976e49c8 100644 (file)
@@ -93,6 +93,7 @@ static volatile enum sclp_mask_state_t {
 #define SCLP_RETRY_INTERVAL    30
 
 static void sclp_process_queue(void);
+static void __sclp_make_read_req(void);
 static int sclp_init_mask(int calculate);
 static int sclp_init(void);
 
@@ -115,7 +116,6 @@ sclp_service_call(sclp_cmdw_t command, void *sccb)
        return 0;
 }
 
-static inline void __sclp_make_read_req(void);
 
 static void
 __sclp_queue_read_req(void)
@@ -318,8 +318,7 @@ sclp_read_cb(struct sclp_req *req, void *data)
 }
 
 /* Prepare read event data request. Called while sclp_lock is locked. */
-static inline void
-__sclp_make_read_req(void)
+static void __sclp_make_read_req(void)
 {
        struct sccb_header *sccb;
 
index 9f244c591eeb320c3533368f84a53595d6c5ae4c..da25f8e24152b7da94a52c79eff4903fabe17eae 100644 (file)
@@ -708,16 +708,22 @@ static void tape_3590_med_state_set(struct tape_device *device,
 
        c_info = &TAPE_3590_CRYPT_INFO(device);
 
-       if (sense->masst == MSENSE_UNASSOCIATED) {
+       DBF_EVENT(6, "medium state: %x:%x\n", sense->macst, sense->masst);
+       switch (sense->macst) {
+       case 0x04:
+       case 0x05:
+       case 0x06:
                tape_med_state_set(device, MS_UNLOADED);
                TAPE_3590_CRYPT_INFO(device).medium_status = 0;
                return;
-       }
-       if (sense->masst != MSENSE_ASSOCIATED_MOUNT) {
-               PRINT_ERR("Unknown medium state: %x\n", sense->masst);
+       case 0x08:
+       case 0x09:
+               tape_med_state_set(device, MS_LOADED);
+               break;
+       default:
+               tape_med_state_set(device, MS_UNKNOWN);
                return;
        }
-       tape_med_state_set(device, MS_LOADED);
        c_info->medium_status |= TAPE390_MEDIUM_LOADED_MASK;
        if (sense->flags & MSENSE_CRYPT_MASK) {
                PRINT_INFO("Medium is encrypted (%04x)\n", sense->flags);
@@ -835,15 +841,17 @@ tape_3590_unsolicited_irq(struct tape_device *device, struct irb *irb)
                /* Probably result of halt ssch */
                return TAPE_IO_PENDING;
        else if (irb->scsw.dstat == 0x85)
-               /* Device Ready -> check medium state */
-               tape_3590_schedule_work(device, TO_MSEN);
-       else if (irb->scsw.dstat & DEV_STAT_ATTENTION)
+               /* Device Ready */
+               DBF_EVENT(3, "unsol.irq! tape ready: %08x\n", device->cdev_id);
+       else if (irb->scsw.dstat & DEV_STAT_ATTENTION) {
                tape_3590_schedule_work(device, TO_READ_ATTMSG);
-       else {
+       else {
                DBF_EVENT(3, "unsol.irq! dev end: %08x\n", device->cdev_id);
                PRINT_WARN("Unsolicited IRQ (Device End) caught.\n");
                tape_dump_sense(device, NULL, irb);
        }
+       /* check medium state */
+       tape_3590_schedule_work(device, TO_MSEN);
        return TAPE_IO_SUCCESS;
 }
 
index bc33068b9ce2b3556bdc02ee0878ded5fb5233cc..70b1980a08b66380c075355d81101c90a784032f 100644 (file)
@@ -25,8 +25,8 @@
 #include <asm/ebcdic.h>
 #include <asm/uaccess.h>
 
-
 #include "raw3270.h"
+#include "tty3270.h"
 #include "keyboard.h"
 
 #define TTY3270_CHAR_BUF_SIZE 256
@@ -1338,8 +1338,11 @@ tty3270_getpar(struct tty3270 *tp, int ix)
 static void
 tty3270_goto_xy(struct tty3270 *tp, int cx, int cy)
 {
-       tp->cx = min_t(int, tp->view.cols - 1, max_t(int, 0, cx));
-       cy = min_t(int, tp->view.rows - 3, max_t(int, 0, cy));
+       int max_cx = max(0, cx);
+       int max_cy = max(0, cy);
+
+       tp->cx = min_t(int, tp->view.cols - 1, max_cx);
+       cy = min_t(int, tp->view.rows - 3, max_cy);
        if (cy != tp->cy) {
                tty3270_convert_line(tp, tp->cy);
                tp->cy = cy;
diff --git a/drivers/s390/char/tty3270.h b/drivers/s390/char/tty3270.h
new file mode 100644 (file)
index 0000000..799da57
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ *  drivers/s390/char/tty3270.h
+ *
+ *    Copyright IBM Corp. 2007
+ *
+ */
+
+#ifndef __DRIVERS_S390_CHAR_TTY3270_H
+#define __DRIVERS_S390_CHAR_TTY3270_H
+
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+
+extern struct tty_driver *tty3270_driver;
+
+#endif /* __DRIVERS_S390_CHAR_TTY3270_H */
index 680b9b58b80ea0ce6479b8085cdf9b70767289fd..6f40facb1c4d7e3b8f89c49e254bf22dcc959189 100644 (file)
@@ -66,8 +66,8 @@ static int __diag288(enum vmwdt_func func, unsigned int timeout,
                "0:     la      %0,0\n"
                "1:\n"
                EX_TABLE(0b,1b)
-               : "=d" (err) : "d"(__func), "d"(__timeout),
-                 "d"(__cmdp), "d"(__cmdl), "0" (-EINVAL) : "1", "cc");
+               : "+d" (err) : "d"(__func), "d"(__timeout),
+                 "d"(__cmdp), "d"(__cmdl) : "1", "cc");
        return err;
 }
 
index 3712ede167235fcecd2ceeab4b0b9faac7f74461..7073daf77981005e7edfe0c6f59c08b2a3251212 100644 (file)
@@ -141,15 +141,16 @@ static int memcpy_real(void *dest, unsigned long src, size_t count)
 
        if (count == 0)
                return 0;
-       flags = __raw_local_irq_stnsm(0xf8); /* switch to real mode */
+       flags = __raw_local_irq_stnsm(0xf8UL); /* switch to real mode */
        asm volatile (
                "0:     mvcle   %1,%2,0x0\n"
                "1:     jo      0b\n"
                "       lhi     %0,0x0\n"
                "2:\n"
                EX_TABLE(1b,2b)
-               : "+d" (rc)
-               : "d" (_dest), "d" (_src), "d" (_len1), "d" (_len2)
+               : "+d" (rc), "+d" (_dest), "+d" (_src), "+d" (_len1),
+                 "+d" (_len2), "=m" (*((long*)dest))
+               : "m" (*((long*)src))
                : "cc", "memory");
        __raw_local_irq_ssm(flags);
 
index b0a18f5176aa3e07ecde788944f4061d1f0974d6..5baa517c3b6625665f98dadada2679ec7da4e641 100644 (file)
@@ -44,8 +44,7 @@ ccwgroup_bus_match (struct device * dev, struct device_driver * drv)
        return 0;
 }
 static int
-ccwgroup_uevent (struct device *dev, char **envp, int num_envp, char *buffer,
-                 int buffer_size)
+ccwgroup_uevent (struct device *dev, struct kobj_uevent_env *env)
 {
        /* TODO */
        return 0;
@@ -152,16 +151,24 @@ __ccwgroup_create_symlinks(struct ccwgroup_device *gdev)
        return 0;
 }
 
-/*
- * try to add a new ccwgroup device for one driver
- * argc and argv[] are a list of bus_id's of devices
- * belonging to the driver.
+/**
+ * ccwgroup_create() - create and register a ccw group device
+ * @root: parent device for the new device
+ * @creator_id: identifier of creating driver
+ * @cdrv: ccw driver of slave devices
+ * @argc: number of slave devices
+ * @argv: bus ids of slave devices
+ *
+ * Create and register a new ccw group device as a child of @root. Slave
+ * devices are obtained from the list of bus ids given in @argv[] and must all
+ * belong to @cdrv.
+ * Returns:
+ *  %0 on success and an error code on failure.
+ * Context:
+ *  non-atomic
  */
-int
-ccwgroup_create(struct device *root,
-               unsigned int creator_id,
-               struct ccw_driver *cdrv,
-               int argc, char *argv[])
+int ccwgroup_create(struct device *root, unsigned int creator_id,
+                   struct ccw_driver *cdrv, int argc, char *argv[])
 {
        struct ccwgroup_device *gdev;
        int i;
@@ -390,8 +397,13 @@ static struct bus_type ccwgroup_bus_type = {
        .remove = ccwgroup_remove,
 };
 
-int
-ccwgroup_driver_register (struct ccwgroup_driver *cdriver)
+/**
+ * ccwgroup_driver_register() - register a ccw group driver
+ * @cdriver: driver to be registered
+ *
+ * This function is mainly a wrapper around driver_register().
+ */
+int ccwgroup_driver_register(struct ccwgroup_driver *cdriver)
 {
        /* register our new driver with the core */
        cdriver->driver.bus = &ccwgroup_bus_type;
@@ -406,8 +418,13 @@ __ccwgroup_match_all(struct device *dev, void *data)
        return 1;
 }
 
-void
-ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver)
+/**
+ * ccwgroup_driver_unregister() - deregister a ccw group driver
+ * @cdriver: driver to be deregistered
+ *
+ * This function is mainly a wrapper around driver_unregister().
+ */
+void ccwgroup_driver_unregister(struct ccwgroup_driver *cdriver)
 {
        struct device *dev;
 
@@ -427,8 +444,16 @@ ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver)
        driver_unregister(&cdriver->driver);
 }
 
-int
-ccwgroup_probe_ccwdev(struct ccw_device *cdev)
+/**
+ * ccwgroup_probe_ccwdev() - probe function for slave devices
+ * @cdev: ccw device to be probed
+ *
+ * This is a dummy probe function for ccw devices that are slave devices in
+ * a ccw group device.
+ * Returns:
+ *  always %0
+ */
+int ccwgroup_probe_ccwdev(struct ccw_device *cdev)
 {
        return 0;
 }
@@ -452,8 +477,15 @@ __ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev)
        return NULL;
 }
 
-void
-ccwgroup_remove_ccwdev(struct ccw_device *cdev)
+/**
+ * ccwgroup_remove_ccwdev() - remove function for slave devices
+ * @cdev: ccw device to be removed
+ *
+ * This is a remove function for ccw devices that are slave devices in a ccw
+ * group device. It sets the ccw device offline and also deregisters the
+ * embedding ccw group device.
+ */
+void ccwgroup_remove_ccwdev(struct ccw_device *cdev)
 {
        struct ccwgroup_device *gdev;
 
index 920dd71e643457fbf541842f07e380e5a80cd407..42c1f4659adb41d605557f7cb254937e15781d08 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/jiffies.h>
 #include <linux/wait.h>
 #include <linux/mutex.h>
-#include <asm/errno.h>
+#include <linux/errno.h>
 #include <asm/chpid.h>
 #include <asm/sclp.h>
 
@@ -55,7 +55,7 @@ static wait_queue_head_t cfg_wait_queue;
 /* Return channel_path struct for given chpid. */
 static inline struct channel_path *chpid_to_chp(struct chp_id chpid)
 {
-       return css[chpid.cssid]->chps[chpid.id];
+       return channel_subsystems[chpid.cssid]->chps[chpid.id];
 }
 
 /* Set vary state for given chpid. */
@@ -86,7 +86,7 @@ u8 chp_get_sch_opm(struct subchannel *sch)
 
        opm = 0;
        chp_id_init(&chpid);
-       for (i=0; i < 8; i++) {
+       for (i = 0; i < 8; i++) {
                opm <<= 1;
                chpid.id = sch->schib.pmcw.chpid[i];
                if (chp_get_status(chpid) != 0)
@@ -118,7 +118,7 @@ static int s390_vary_chpid(struct chp_id chpid, int on)
 
        sprintf(dbf_text, on?"varyon%x.%02x":"varyoff%x.%02x", chpid.cssid,
                chpid.id);
-       CIO_TRACE_EVENT( 2, dbf_text);
+       CIO_TRACE_EVENT(2, dbf_text);
 
        status = chp_get_status(chpid);
        if (!on && !status) {
@@ -140,9 +140,11 @@ static ssize_t chp_measurement_chars_read(struct kobject *kobj,
                                          char *buf, loff_t off, size_t count)
 {
        struct channel_path *chp;
+       struct device *device;
        unsigned int size;
 
-       chp = to_channelpath(container_of(kobj, struct device, kobj));
+       device = container_of(kobj, struct device, kobj);
+       chp = to_channelpath(device);
        if (!chp->cmg_chars)
                return 0;
 
@@ -193,9 +195,11 @@ static ssize_t chp_measurement_read(struct kobject *kobj,
 {
        struct channel_path *chp;
        struct channel_subsystem *css;
+       struct device *device;
        unsigned int size;
 
-       chp = to_channelpath(container_of(kobj, struct device, kobj));
+       device = container_of(kobj, struct device, kobj);
+       chp = to_channelpath(device);
        css = to_css(chp->dev.parent);
 
        size = sizeof(struct cmg_entry);
@@ -353,7 +357,7 @@ static ssize_t chp_shared_show(struct device *dev,
 
 static DEVICE_ATTR(shared, 0444, chp_shared_show, NULL);
 
-static struct attribute * chp_attrs[] = {
+static struct attribute *chp_attrs[] = {
        &dev_attr_status.attr,
        &dev_attr_configure.attr,
        &dev_attr_type.attr,
@@ -395,7 +399,7 @@ int chp_new(struct chp_id chpid)
        /* fill in status, etc. */
        chp->chpid = chpid;
        chp->state = 1;
-       chp->dev.parent = &css[chpid.cssid]->device;
+       chp->dev.parent = &channel_subsystems[chpid.cssid]->device;
        chp->dev.release = chp_release;
        snprintf(chp->dev.bus_id, BUS_ID_SIZE, "chp%x.%02x", chpid.cssid,
                 chpid.id);
@@ -430,18 +434,18 @@ int chp_new(struct chp_id chpid)
                device_unregister(&chp->dev);
                goto out_free;
        }
-       mutex_lock(&css[chpid.cssid]->mutex);
-       if (css[chpid.cssid]->cm_enabled) {
+       mutex_lock(&channel_subsystems[chpid.cssid]->mutex);
+       if (channel_subsystems[chpid.cssid]->cm_enabled) {
                ret = chp_add_cmg_attr(chp);
                if (ret) {
                        sysfs_remove_group(&chp->dev.kobj, &chp_attr_group);
                        device_unregister(&chp->dev);
-                       mutex_unlock(&css[chpid.cssid]->mutex);
+                       mutex_unlock(&channel_subsystems[chpid.cssid]->mutex);
                        goto out_free;
                }
        }
-       css[chpid.cssid]->chps[chpid.id] = chp;
-       mutex_unlock(&css[chpid.cssid]->mutex);
+       channel_subsystems[chpid.cssid]->chps[chpid.id] = chp;
+       mutex_unlock(&channel_subsystems[chpid.cssid]->mutex);
        return ret;
 out_free:
        kfree(chp);
index f2708d65be5a1d8bb14cedb874b950f21859f5f8..46905345159e6705036d7d20030de558a534b60d 100644 (file)
@@ -619,6 +619,11 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
        sch->schib.pmcw.ena = 0;
        if ((sch->lpm & (sch->lpm - 1)) != 0)
                sch->schib.pmcw.mp = 1; /* multipath mode */
+       /* clean up possible residual cmf stuff */
+       sch->schib.pmcw.mme = 0;
+       sch->schib.pmcw.mbfc = 0;
+       sch->schib.pmcw.mbi = 0;
+       sch->schib.mba = 0;
        return 0;
 out:
        if (!cio_is_console(schid))
index 34a796913b0604a787630beae9be87952982a8dc..b960f66843e4919e1645806258368763fcaeec84 100644 (file)
@@ -45,7 +45,8 @@
 #include "ioasm.h"
 #include "chsc.h"
 
-/* parameter to enable cmf during boot, possible uses are:
+/*
+ * parameter to enable cmf during boot, possible uses are:
  *  "s390cmf" -- enable cmf and allocate 2 MB of ram so measuring can be
  *               used on any subchannel
  *  "s390cmf=<num>" -- enable cmf and allocate enough memory to measure
@@ -73,18 +74,20 @@ enum cmb_index {
  * enum cmb_format - types of supported measurement block formats
  *
  * @CMF_BASIC:      traditional channel measurement blocks supported
- *                 by all machines that we run on
+ *                 by all machines that we run on
  * @CMF_EXTENDED:   improved format that was introduced with the z990
- *                 machine
- * @CMF_AUTODETECT: default: use extended format when running on a z990
- *                  or later machine, otherwise fall back to basic format
- **/
+ *                 machine
+ * @CMF_AUTODETECT: default: use extended format when running on a machine
+ *                 supporting extended format, otherwise fall back to
+ *                 basic format
+ */
 enum cmb_format {
        CMF_BASIC,
        CMF_EXTENDED,
        CMF_AUTODETECT = -1,
 };
-/**
+
+/*
  * format - actual format for all measurement blocks
  *
  * The format module parameter can be set to a value of 0 (zero)
@@ -105,20 +108,21 @@ module_param(format, bool, 0444);
  *             either with the help of a special pool or with kmalloc
  * @free:      free memory allocated with @alloc
  * @set:       enable or disable measurement
+ * @read:      read a measurement entry at an index
  * @readall:   read a measurement block in a common format
  * @reset:     clear the data in the associated measurement block and
  *             reset its time stamp
  * @align:     align an allocated block so that the hardware can use it
  */
 struct cmb_operations {
-       int (*alloc)  (struct ccw_device*);
-       void(*free)   (struct ccw_device*);
-       int (*set)    (struct ccw_device*, u32);
-       u64 (*read)   (struct ccw_device*, int);
-       int (*readall)(struct ccw_device*, struct cmbdata *);
-       void (*reset) (struct ccw_device*);
-       void * (*align) (void *);
-
+       int  (*alloc)  (struct ccw_device *);
+       void (*free)   (struct ccw_device *);
+       int  (*set)    (struct ccw_device *, u32);
+       u64  (*read)   (struct ccw_device *, int);
+       int  (*readall)(struct ccw_device *, struct cmbdata *);
+       void (*reset)  (struct ccw_device *);
+       void *(*align) (void *);
+/* private: */
        struct attribute_group *attr_group;
 };
 static struct cmb_operations *cmbops;
@@ -130,9 +134,11 @@ struct cmb_data {
        unsigned long long last_update;  /* when last_block was updated */
 };
 
-/* our user interface is designed in terms of nanoseconds,
+/*
+ * Our user interface is designed in terms of nanoseconds,
  * while the hardware measures total times in its own
- * unit.*/
+ * unit.
+ */
 static inline u64 time_to_nsec(u32 value)
 {
        return ((u64)value) * 128000ull;
@@ -159,12 +165,13 @@ static inline u64 time_to_avg_nsec(u32 value, u32 count)
        return ret;
 }
 
-/* activate or deactivate the channel monitor. When area is NULL,
+/*
+ * Activate or deactivate the channel monitor. When area is NULL,
  * the monitor is deactivated. The channel monitor needs to
  * be active in order to measure subchannels, which also need
- * to be enabled. */
-static inline void
-cmf_activate(void *area, unsigned int onoff)
+ * to be enabled.
+ */
+static inline void cmf_activate(void *area, unsigned int onoff)
 {
        register void * __gpr2 asm("2");
        register long __gpr1 asm("1");
@@ -175,8 +182,8 @@ cmf_activate(void *area, unsigned int onoff)
        asm("schm" : : "d" (__gpr2), "d" (__gpr1) );
 }
 
-static int
-set_schib(struct ccw_device *cdev, u32 mme, int mbfc, unsigned long address)
+static int set_schib(struct ccw_device *cdev, u32 mme, int mbfc,
+                    unsigned long address)
 {
        int ret;
        int retry;
@@ -466,6 +473,7 @@ static void cmf_generic_reset(struct ccw_device *cdev)
  *
  * @mem:       pointer to CMBs (only in basic measurement mode)
  * @list:      contains a linked list of all subchannels
+ * @num_channels: number of channels to be measured
  * @lock:      protect concurrent access to @mem and @list
  */
 struct cmb_area {
@@ -481,28 +489,36 @@ static struct cmb_area cmb_area = {
        .num_channels  = 1024,
 };
 
-\f
 /* ****** old style CMB handling ********/
 
-/** int maxchannels
- *
+/*
  * Basic channel measurement blocks are allocated in one contiguous
  * block of memory, which can not be moved as long as any channel
  * is active. Therefore, a maximum number of subchannels needs to
  * be defined somewhere. This is a module parameter, defaulting to
  * a resonable value of 1024, or 32 kb of memory.
  * Current kernels don't allow kmalloc with more than 128kb, so the
- * maximum is 4096
+ * maximum is 4096.
  */
 
 module_param_named(maxchannels, cmb_area.num_channels, uint, 0444);
 
 /**
  * struct cmb - basic channel measurement block
+ * @ssch_rsch_count: number of ssch and rsch
+ * @sample_count: number of samples
+ * @device_connect_time: time of device connect
+ * @function_pending_time: time of function pending
+ * @device_disconnect_time: time of device disconnect
+ * @control_unit_queuing_time: time of control unit queuing
+ * @device_active_only_time: time of device active only
+ * @reserved: unused in basic measurement mode
+ *
+ * The measurement block as used by the hardware. The fields are described
+ * further in z/Architecture Principles of Operation, chapter 17.
  *
- * cmb as used by the hardware the fields are described in z/Architecture
- * Principles of Operation, chapter 17.
- * The area to be a contiguous array and may not be reallocated or freed.
+ * The cmb area made up from these blocks must be a contiguous array and may
+ * not be reallocated or freed.
  * Only one cmb area can be present in the system.
  */
 struct cmb {
@@ -516,8 +532,9 @@ struct cmb {
        u32 reserved[2];
 };
 
-/* insert a single device into the cmb_area list
- * called with cmb_area.lock held from alloc_cmb
+/*
+ * Insert a single device into the cmb_area list.
+ * Called with cmb_area.lock held from alloc_cmb.
  */
 static int alloc_cmb_single(struct ccw_device *cdev,
                            struct cmb_data *cmb_data)
@@ -532,9 +549,11 @@ static int alloc_cmb_single(struct ccw_device *cdev,
                goto out;
        }
 
-       /* find first unused cmb in cmb_area.mem.
-        * this is a little tricky: cmb_area.list
-        * remains sorted by ->cmb->hw_data pointers */
+       /*
+        * Find first unused cmb in cmb_area.mem.
+        * This is a little tricky: cmb_area.list
+        * remains sorted by ->cmb->hw_data pointers.
+        */
        cmb = cmb_area.mem;
        list_for_each_entry(node, &cmb_area.list, cmb_list) {
                struct cmb_data *data;
@@ -558,8 +577,7 @@ out:
        return ret;
 }
 
-static int
-alloc_cmb (struct ccw_device *cdev)
+static int alloc_cmb(struct ccw_device *cdev)
 {
        int ret;
        struct cmb *mem;
@@ -670,7 +688,7 @@ static int set_cmb(struct ccw_device *cdev, u32 mme)
        return set_schib_wait(cdev, mme, 0, offset);
 }
 
-static u64 read_cmb (struct ccw_device *cdev, int index)
+static u64 read_cmb(struct ccw_device *cdev, int index)
 {
        struct cmb *cmb;
        u32 val;
@@ -720,7 +738,7 @@ out:
        return ret;
 }
 
-static int readall_cmb (struct ccw_device *cdev, struct cmbdata *data)
+static int readall_cmb(struct ccw_device *cdev, struct cmbdata *data)
 {
        struct cmb *cmb;
        struct cmb_data *cmb_data;
@@ -793,14 +811,25 @@ static struct cmb_operations cmbops_basic = {
        .align      = align_cmb,
        .attr_group = &cmf_attr_group,
 };
-\f
+
 /* ******** extended cmb handling ********/
 
 /**
  * struct cmbe - extended channel measurement block
+ * @ssch_rsch_count: number of ssch and rsch
+ * @sample_count: number of samples
+ * @device_connect_time: time of device connect
+ * @function_pending_time: time of function pending
+ * @device_disconnect_time: time of device disconnect
+ * @control_unit_queuing_time: time of control unit queuing
+ * @device_active_only_time: time of device active only
+ * @device_busy_time: time of device busy
+ * @initial_command_response_time: initial command response time
+ * @reserved: unused
  *
- * cmb as used by the hardware, may be in any 64 bit physical location,
- * the fields are described in z/Architecture Principles of Operation,
+ * The measurement block as used by the hardware. May be in any 64 bit physical
+ * location.
+ * The fields are described further in z/Architecture Principles of Operation,
  * third edition, chapter 17.
  */
 struct cmbe {
@@ -816,10 +845,12 @@ struct cmbe {
        u32 reserved[7];
 };
 
-/* kmalloc only guarantees 8 byte alignment, but we need cmbe
+/*
+ * kmalloc only guarantees 8 byte alignment, but we need cmbe
  * pointers to be naturally aligned. Make sure to allocate
- * enough space for two cmbes */
-static inline struct cmbe* cmbe_align(struct cmbe *c)
+ * enough space for two cmbes.
+ */
+static inline struct cmbe *cmbe_align(struct cmbe *c)
 {
        unsigned long addr;
        addr = ((unsigned long)c + sizeof (struct cmbe) - sizeof(long)) &
@@ -827,7 +858,7 @@ static inline struct cmbe* cmbe_align(struct cmbe *c)
        return (struct cmbe*)addr;
 }
 
-static int alloc_cmbe (struct ccw_device *cdev)
+static int alloc_cmbe(struct ccw_device *cdev)
 {
        struct cmbe *cmbe;
        struct cmb_data *cmb_data;
@@ -873,7 +904,7 @@ out_free:
        return ret;
 }
 
-static void free_cmbe (struct ccw_device *cdev)
+static void free_cmbe(struct ccw_device *cdev)
 {
        struct cmb_data *cmb_data;
 
@@ -912,7 +943,7 @@ static int set_cmbe(struct ccw_device *cdev, u32 mme)
 }
 
 
-static u64 read_cmbe (struct ccw_device *cdev, int index)
+static u64 read_cmbe(struct ccw_device *cdev, int index)
 {
        struct cmbe *cmb;
        struct cmb_data *cmb_data;
@@ -970,7 +1001,7 @@ out:
        return ret;
 }
 
-static int readall_cmbe (struct ccw_device *cdev, struct cmbdata *data)
+static int readall_cmbe(struct ccw_device *cdev, struct cmbdata *data)
 {
        struct cmbe *cmb;
        struct cmb_data *cmb_data;
@@ -1047,17 +1078,16 @@ static struct cmb_operations cmbops_extended = {
        .align      = align_cmbe,
        .attr_group = &cmf_attr_group_ext,
 };
-\f
 
-static ssize_t
-cmb_show_attr(struct device *dev, char *buf, enum cmb_index idx)
+static ssize_t cmb_show_attr(struct device *dev, char *buf, enum cmb_index idx)
 {
        return sprintf(buf, "%lld\n",
                (unsigned long long) cmf_read(to_ccwdev(dev), idx));
 }
 
-static ssize_t
-cmb_show_avg_sample_interval(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t cmb_show_avg_sample_interval(struct device *dev,
+                                           struct device_attribute *attr,
+                                           char *buf)
 {
        struct ccw_device *cdev;
        long interval;
@@ -1079,8 +1109,9 @@ cmb_show_avg_sample_interval(struct device *dev, struct device_attribute *attr,
        return sprintf(buf, "%ld\n", interval);
 }
 
-static ssize_t
-cmb_show_avg_utilization(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t cmb_show_avg_utilization(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
 {
        struct cmbdata data;
        u64 utilization;
@@ -1112,14 +1143,16 @@ cmb_show_avg_utilization(struct device *dev, struct device_attribute *attr, char
 }
 
 #define cmf_attr(name) \
-static ssize_t show_ ## name (struct device * dev, struct device_attribute *attr, char * buf) \
-{ return cmb_show_attr((dev), buf, cmb_ ## name); } \
-static DEVICE_ATTR(name, 0444, show_ ## name, NULL);
+static ssize_t show_##name(struct device *dev, \
+                          struct device_attribute *attr, char *buf)    \
+{ return cmb_show_attr((dev), buf, cmb_##name); } \
+static DEVICE_ATTR(name, 0444, show_##name, NULL);
 
 #define cmf_attr_avg(name) \
-static ssize_t show_avg_ ## name (struct device * dev, struct device_attribute *attr, char * buf) \
-{ return cmb_show_attr((dev), buf, cmb_ ## name); } \
-static DEVICE_ATTR(avg_ ## name, 0444, show_avg_ ## name, NULL);
+static ssize_t show_avg_##name(struct device *dev, \
+                              struct device_attribute *attr, char *buf) \
+{ return cmb_show_attr((dev), buf, cmb_##name); } \
+static DEVICE_ATTR(avg_##name, 0444, show_avg_##name, NULL);
 
 cmf_attr(ssch_rsch_count);
 cmf_attr(sample_count);
@@ -1131,7 +1164,8 @@ cmf_attr_avg(device_active_only_time);
 cmf_attr_avg(device_busy_time);
 cmf_attr_avg(initial_command_response_time);
 
-static DEVICE_ATTR(avg_sample_interval, 0444, cmb_show_avg_sample_interval, NULL);
+static DEVICE_ATTR(avg_sample_interval, 0444, cmb_show_avg_sample_interval,
+                  NULL);
 static DEVICE_ATTR(avg_utilization, 0444, cmb_show_avg_utilization, NULL);
 
 static struct attribute *cmf_attributes[] = {
@@ -1172,12 +1206,16 @@ static struct attribute_group cmf_attr_group_ext = {
        .attrs = cmf_attributes_ext,
 };
 
-static ssize_t cmb_enable_show(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t cmb_enable_show(struct device *dev,
+                              struct device_attribute *attr,
+                              char *buf)
 {
        return sprintf(buf, "%d\n", to_ccwdev(dev)->private->cmb ? 1 : 0);
 }
 
-static ssize_t cmb_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t c)
+static ssize_t cmb_enable_store(struct device *dev,
+                               struct device_attribute *attr, const char *buf,
+                               size_t c)
 {
        struct ccw_device *cdev;
        int ret;
@@ -1202,9 +1240,16 @@ static ssize_t cmb_enable_store(struct device *dev, struct device_attribute *att
 
 DEVICE_ATTR(cmb_enable, 0644, cmb_enable_show, cmb_enable_store);
 
-/* enable_cmf/disable_cmf: module interface for cmf (de)activation */
-int
-enable_cmf(struct ccw_device *cdev)
+/**
+ * enable_cmf() - switch on the channel measurement for a specific device
+ *  @cdev:     The ccw device to be enabled
+ *
+ *  Returns %0 for success or a negative error value.
+ *
+ *  Context:
+ *    non-atomic
+ */
+int enable_cmf(struct ccw_device *cdev)
 {
        int ret;
 
@@ -1225,8 +1270,16 @@ enable_cmf(struct ccw_device *cdev)
        return ret;
 }
 
-int
-disable_cmf(struct ccw_device *cdev)
+/**
+ * disable_cmf() - switch off the channel measurement for a specific device
+ *  @cdev:     The ccw device to be disabled
+ *
+ *  Returns %0 for success or a negative error value.
+ *
+ *  Context:
+ *    non-atomic
+ */
+int disable_cmf(struct ccw_device *cdev)
 {
        int ret;
 
@@ -1238,14 +1291,32 @@ disable_cmf(struct ccw_device *cdev)
        return ret;
 }
 
-u64
-cmf_read(struct ccw_device *cdev, int index)
+/**
+ * cmf_read() - read one value from the current channel measurement block
+ * @cdev:      the channel to be read
+ * @index:     the index of the value to be read
+ *
+ * Returns the value read or %0 if the value cannot be read.
+ *
+ *  Context:
+ *    any
+ */
+u64 cmf_read(struct ccw_device *cdev, int index)
 {
        return cmbops->read(cdev, index);
 }
 
-int
-cmf_readall(struct ccw_device *cdev, struct cmbdata *data)
+/**
+ * cmf_readall() - read the current channel measurement block
+ * @cdev:      the channel to be read
+ * @data:      a pointer to a data block that will be filled
+ *
+ * Returns %0 on success, a negative error value otherwise.
+ *
+ *  Context:
+ *    any
+ */
+int cmf_readall(struct ccw_device *cdev, struct cmbdata *data)
 {
        return cmbops->readall(cdev, data);
 }
@@ -1257,15 +1328,16 @@ int cmf_reenable(struct ccw_device *cdev)
        return cmbops->set(cdev, 2);
 }
 
-static int __init
-init_cmf(void)
+static int __init init_cmf(void)
 {
        char *format_string;
        char *detect_string = "parameter";
 
-       /* We cannot really autoprobe this. If the user did not give a parameter,
-          see if we are running on z990 or up, otherwise fall back to basic mode. */
-
+       /*
+        * If the user did not give a parameter, see if we are running on a
+        * machine supporting extended measurement blocks, otherwise fall back
+        * to basic mode.
+        */
        if (format == CMF_AUTODETECT) {
                if (!css_characteristics_avail ||
                    !css_general_characteristics.ext_mb) {
@@ -1284,7 +1356,7 @@ init_cmf(void)
                cmbops = &cmbops_basic;
                break;
        case CMF_EXTENDED:
-               format_string = "extended";
+               format_string = "extended";
                cmbops = &cmbops_extended;
                break;
        default:
index 5635e656c1a369b92bd0027c0e8beca261baed3c..5d83dd471461a6b13124348709cca88e191eb6e6 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/slab.h>
 #include <linux/errno.h>
 #include <linux/list.h>
+#include <linux/reboot.h>
 
 #include "css.h"
 #include "cio.h"
@@ -27,7 +28,7 @@ int css_init_done = 0;
 static int need_reprobe = 0;
 static int max_ssid = 0;
 
-struct channel_subsystem *css[__MAX_CSSID + 1];
+struct channel_subsystem *channel_subsystems[__MAX_CSSID + 1];
 
 int css_characteristics_avail = 0;
 
@@ -177,7 +178,7 @@ static int css_register_subchannel(struct subchannel *sch)
        int ret;
 
        /* Initialize the subchannel structure */
-       sch->dev.parent = &css[0]->device;
+       sch->dev.parent = &channel_subsystems[0]->device;
        sch->dev.bus = &css_bus_type;
        sch->dev.release = &css_subchannel_release;
        sch->dev.groups = subch_attr_groups;
@@ -606,30 +607,55 @@ static int __init setup_css(int nr)
 {
        u32 tod_high;
        int ret;
+       struct channel_subsystem *css;
 
-       memset(css[nr], 0, sizeof(struct channel_subsystem));
-       css[nr]->pseudo_subchannel =
-               kzalloc(sizeof(*css[nr]->pseudo_subchannel), GFP_KERNEL);
-       if (!css[nr]->pseudo_subchannel)
+       css = channel_subsystems[nr];
+       memset(css, 0, sizeof(struct channel_subsystem));
+       css->pseudo_subchannel =
+               kzalloc(sizeof(*css->pseudo_subchannel), GFP_KERNEL);
+       if (!css->pseudo_subchannel)
                return -ENOMEM;
-       css[nr]->pseudo_subchannel->dev.parent = &css[nr]->device;
-       css[nr]->pseudo_subchannel->dev.release = css_subchannel_release;
-       sprintf(css[nr]->pseudo_subchannel->dev.bus_id, "defunct");
-       ret = cio_create_sch_lock(css[nr]->pseudo_subchannel);
+       css->pseudo_subchannel->dev.parent = &css->device;
+       css->pseudo_subchannel->dev.release = css_subchannel_release;
+       sprintf(css->pseudo_subchannel->dev.bus_id, "defunct");
+       ret = cio_create_sch_lock(css->pseudo_subchannel);
        if (ret) {
-               kfree(css[nr]->pseudo_subchannel);
+               kfree(css->pseudo_subchannel);
                return ret;
        }
-       mutex_init(&css[nr]->mutex);
-       css[nr]->valid = 1;
-       css[nr]->cssid = nr;
-       sprintf(css[nr]->device.bus_id, "css%x", nr);
-       css[nr]->device.release = channel_subsystem_release;
+       mutex_init(&css->mutex);
+       css->valid = 1;
+       css->cssid = nr;
+       sprintf(css->device.bus_id, "css%x", nr);
+       css->device.release = channel_subsystem_release;
        tod_high = (u32) (get_clock() >> 32);
-       css_generate_pgid(css[nr], tod_high);
+       css_generate_pgid(css, tod_high);
        return 0;
 }
 
+static int css_reboot_event(struct notifier_block *this,
+                           unsigned long event,
+                           void *ptr)
+{
+       int ret, i;
+
+       ret = NOTIFY_DONE;
+       for (i = 0; i <= __MAX_CSSID; i++) {
+               struct channel_subsystem *css;
+
+               css = channel_subsystems[i];
+               if (css->cm_enabled)
+                       if (chsc_secm(css, 0))
+                               ret = NOTIFY_BAD;
+       }
+
+       return ret;
+}
+
+static struct notifier_block css_reboot_notifier = {
+       .notifier_call = css_reboot_event,
+};
+
 /*
  * Now that the driver core is running, we can setup our channel subsystem.
  * The struct subchannel's are created during probing (except for the
@@ -670,51 +696,63 @@ init_channel_subsystem (void)
        }
        /* Setup css structure. */
        for (i = 0; i <= __MAX_CSSID; i++) {
-               css[i] = kmalloc(sizeof(struct channel_subsystem), GFP_KERNEL);
-               if (!css[i]) {
+               struct channel_subsystem *css;
+
+               css = kmalloc(sizeof(struct channel_subsystem), GFP_KERNEL);
+               if (!css) {
                        ret = -ENOMEM;
                        goto out_unregister;
                }
+               channel_subsystems[i] = css;
                ret = setup_css(i);
                if (ret)
                        goto out_free;
-               ret = device_register(&css[i]->device);
+               ret = device_register(&css->device);
                if (ret)
                        goto out_free_all;
                if (css_characteristics_avail &&
                    css_chsc_characteristics.secm) {
-                       ret = device_create_file(&css[i]->device,
+                       ret = device_create_file(&css->device,
                                                 &dev_attr_cm_enable);
                        if (ret)
                                goto out_device;
                }
-               ret = device_register(&css[i]->pseudo_subchannel->dev);
+               ret = device_register(&css->pseudo_subchannel->dev);
                if (ret)
                        goto out_file;
        }
+       ret = register_reboot_notifier(&css_reboot_notifier);
+       if (ret)
+               goto out_pseudo;
        css_init_done = 1;
 
        ctl_set_bit(6, 28);
 
        for_each_subchannel(__init_channel_subsystem, NULL);
        return 0;
+out_pseudo:
+       device_unregister(&channel_subsystems[i]->pseudo_subchannel->dev);
 out_file:
-       device_remove_file(&css[i]->device, &dev_attr_cm_enable);
+       device_remove_file(&channel_subsystems[i]->device,
+                          &dev_attr_cm_enable);
 out_device:
-       device_unregister(&css[i]->device);
+       device_unregister(&channel_subsystems[i]->device);
 out_free_all:
-       kfree(css[i]->pseudo_subchannel->lock);
-       kfree(css[i]->pseudo_subchannel);
+       kfree(channel_subsystems[i]->pseudo_subchannel->lock);
+       kfree(channel_subsystems[i]->pseudo_subchannel);
 out_free:
-       kfree(css[i]);
+       kfree(channel_subsystems[i]);
 out_unregister:
        while (i > 0) {
+               struct channel_subsystem *css;
+
                i--;
-               device_unregister(&css[i]->pseudo_subchannel->dev);
+               css = channel_subsystems[i];
+               device_unregister(&css->pseudo_subchannel->dev);
                if (css_characteristics_avail && css_chsc_characteristics.secm)
-                       device_remove_file(&css[i]->device,
+                       device_remove_file(&css->device,
                                           &dev_attr_cm_enable);
-               device_unregister(&css[i]->device);
+               device_unregister(&css->device);
        }
 out_bus:
        bus_unregister(&css_bus_type);
index 5d65e83ca66e818428ccf003b2f2a4ddc4e5b365..81215ef3243575bfa451218c96be4c0506772310 100644 (file)
@@ -167,7 +167,7 @@ struct channel_subsystem {
 #define to_css(dev) container_of(dev, struct channel_subsystem, device)
 
 extern struct bus_type css_bus_type;
-extern struct channel_subsystem *css[];
+extern struct channel_subsystem *channel_subsystems[];
 
 /* Some helper functions for disconnected state. */
 int device_is_disconnected(struct subchannel *);
@@ -191,6 +191,5 @@ int sch_is_pseudo_sch(struct subchannel *);
 
 extern struct workqueue_struct *slow_path_wq;
 
-int subchannel_add_files (struct device *);
 extern struct attribute_group *subch_attr_groups[];
 #endif
index e44d92eac8e9e8f80fb0f4c57f05b096bb3c494d..7ee57f084a89cd79c6f7afcd2caea817633f5877 100644 (file)
@@ -21,6 +21,7 @@
 #include <asm/ccwdev.h>
 #include <asm/cio.h>
 #include <asm/param.h>         /* HZ */
+#include <asm/cmb.h>
 
 #include "cio.h"
 #include "cio_debug.h"
@@ -78,49 +79,38 @@ static int snprint_alias(char *buf, size_t size,
 
 /* Set up environment variables for ccw device uevent. Return 0 on success,
  * non-zero otherwise. */
-static int ccw_uevent(struct device *dev, char **envp, int num_envp,
-                     char *buffer, int buffer_size)
+static int ccw_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        struct ccw_device *cdev = to_ccwdev(dev);
        struct ccw_device_id *id = &(cdev->id);
-       int i = 0;
-       int len = 0;
        int ret;
        char modalias_buf[30];
 
        /* CU_TYPE= */
-       ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
-                            "CU_TYPE=%04X", id->cu_type);
+       ret = add_uevent_var(env, "CU_TYPE=%04X", id->cu_type);
        if (ret)
                return ret;
 
        /* CU_MODEL= */
-       ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
-                            "CU_MODEL=%02X", id->cu_model);
+       ret = add_uevent_var(env, "CU_MODEL=%02X", id->cu_model);
        if (ret)
                return ret;
 
        /* The next two can be zero, that's ok for us */
        /* DEV_TYPE= */
-       ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
-                            "DEV_TYPE=%04X", id->dev_type);
+       ret = add_uevent_var(env, "DEV_TYPE=%04X", id->dev_type);
        if (ret)
                return ret;
 
        /* DEV_MODEL= */
-       ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
-                            "DEV_MODEL=%02X", id->dev_model);
+       ret = add_uevent_var(env, "DEV_MODEL=%02X", id->dev_model);
        if (ret)
                return ret;
 
        /* MODALIAS=  */
        snprint_alias(modalias_buf, sizeof(modalias_buf), id, "");
-       ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
-                            "MODALIAS=%s", modalias_buf);
-       if (ret)
-               return ret;
-       envp[i] = NULL;
-       return 0;
+       ret = add_uevent_var(env, "MODALIAS=%s", modalias_buf);
+       return ret;
 }
 
 struct bus_type ccw_bus_type;
@@ -357,8 +347,18 @@ ccw_device_remove_disconnected(struct ccw_device *cdev)
                              cdev->private->dev_id.devno);
 }
 
-int
-ccw_device_set_offline(struct ccw_device *cdev)
+/**
+ * ccw_device_set_offline() - disable a ccw device for I/O
+ * @cdev: target ccw device
+ *
+ * This function calls the driver's set_offline() function for @cdev, if
+ * given, and then disables @cdev.
+ * Returns:
+ *   %0 on success and a negative error value on failure.
+ * Context:
+ *  enabled, ccw device lock not held
+ */
+int ccw_device_set_offline(struct ccw_device *cdev)
 {
        int ret;
 
@@ -396,8 +396,19 @@ ccw_device_set_offline(struct ccw_device *cdev)
        return ret;
 }
 
-int
-ccw_device_set_online(struct ccw_device *cdev)
+/**
+ * ccw_device_set_online() - enable a ccw device for I/O
+ * @cdev: target ccw device
+ *
+ * This function first enables @cdev and then calls the driver's set_online()
+ * function for @cdev, if given. If set_online() returns an error, @cdev is
+ * disabled again.
+ * Returns:
+ *   %0 on success and a negative error value on failure.
+ * Context:
+ *  enabled, ccw device lock not held
+ */
+int ccw_device_set_online(struct ccw_device *cdev)
 {
        int ret;
 
@@ -947,8 +958,7 @@ out:
                wake_up(&ccw_device_init_wq);
 }
 
-void
-ccw_device_call_sch_unregister(struct work_struct *work)
+static void ccw_device_call_sch_unregister(struct work_struct *work)
 {
        struct ccw_device_private *priv;
        struct ccw_device *cdev;
@@ -1101,6 +1111,7 @@ io_subchannel_probe (struct subchannel *sch)
                 * device, e.g. the console.
                 */
                cdev = sch->dev.driver_data;
+               cdev->dev.groups = ccwdev_attr_groups;
                device_initialize(&cdev->dev);
                ccw_device_register(cdev);
                /*
@@ -1326,8 +1337,19 @@ __ccwdev_check_busid(struct device *dev, void *id)
 }
 
 
-struct ccw_device *
-get_ccwdev_by_busid(struct ccw_driver *cdrv, const char *bus_id)
+/**
+ * get_ccwdev_by_busid() - obtain device from a bus id
+ * @cdrv: driver the device is owned by
+ * @bus_id: bus id of the device to be searched
+ *
+ * This function searches all devices owned by @cdrv for a device with a bus
+ * id matching @bus_id.
+ * Returns:
+ *  If a match is found, its reference count of the found device is increased
+ *  and it is returned; else %NULL is returned.
+ */
+struct ccw_device *get_ccwdev_by_busid(struct ccw_driver *cdrv,
+                                      const char *bus_id)
 {
        struct device *dev;
        struct device_driver *drv;
@@ -1401,16 +1423,34 @@ ccw_device_remove (struct device *dev)
        return 0;
 }
 
+static void ccw_device_shutdown(struct device *dev)
+{
+       struct ccw_device *cdev;
+
+       cdev = to_ccwdev(dev);
+       if (cdev->drv && cdev->drv->shutdown)
+               cdev->drv->shutdown(cdev);
+       disable_cmf(cdev);
+}
+
 struct bus_type ccw_bus_type = {
        .name   = "ccw",
        .match  = ccw_bus_match,
        .uevent = ccw_uevent,
        .probe  = ccw_device_probe,
        .remove = ccw_device_remove,
+       .shutdown = ccw_device_shutdown,
 };
 
-int
-ccw_driver_register (struct ccw_driver *cdriver)
+/**
+ * ccw_driver_register() - register a ccw driver
+ * @cdriver: driver to be registered
+ *
+ * This function is mainly a wrapper around driver_register().
+ * Returns:
+ *   %0 on success and a negative error value on failure.
+ */
+int ccw_driver_register(struct ccw_driver *cdriver)
 {
        struct device_driver *drv = &cdriver->driver;
 
@@ -1420,8 +1460,13 @@ ccw_driver_register (struct ccw_driver *cdriver)
        return driver_register(drv);
 }
 
-void
-ccw_driver_unregister (struct ccw_driver *cdriver)
+/**
+ * ccw_driver_unregister() - deregister a ccw driver
+ * @cdriver: driver to be deregistered
+ *
+ * This function is mainly a wrapper around driver_unregister().
+ */
+void ccw_driver_unregister(struct ccw_driver *cdriver)
 {
        driver_unregister(&cdriver->driver);
 }
index b66338b7657936d7de03780537637f81f559ad4f..0d4089600439263c65c4ddb05479d636e8eae67b 100644 (file)
@@ -80,7 +80,6 @@ void io_subchannel_recog_done(struct ccw_device *cdev);
 int ccw_device_cancel_halt_clear(struct ccw_device *);
 
 void ccw_device_do_unreg_rereg(struct work_struct *);
-void ccw_device_call_sch_unregister(struct work_struct *);
 void ccw_device_move_to_orphanage(struct work_struct *);
 int ccw_device_is_orphan(struct ccw_device *);
 
index 8633dc537695db3a99a03d35e462133fca0fa829..8867443b806049e9b3a7ac19a076b3147fdb6b71 100644 (file)
@@ -446,7 +446,8 @@ static void __ccw_device_get_common_pgid(struct ccw_device *cdev)
        if (cdev->private->pgid[last].inf.ps.state1 ==
            SNID_STATE1_RESET)
                /* No previous pgid found */
-               memcpy(&cdev->private->pgid[0], &css[0]->global_pgid,
+               memcpy(&cdev->private->pgid[0],
+                      &channel_subsystems[0]->global_pgid,
                       sizeof(struct pgid));
        else
                /* Use existing pgid */
@@ -543,51 +544,6 @@ ccw_device_recog_timeout(struct ccw_device *cdev, enum dev_event dev_event)
 }
 
 
-static void
-ccw_device_nopath_notify(struct work_struct *work)
-{
-       struct ccw_device_private *priv;
-       struct ccw_device *cdev;
-       struct subchannel *sch;
-       int ret;
-       unsigned long flags;
-
-       priv = container_of(work, struct ccw_device_private, kick_work);
-       cdev = priv->cdev;
-       spin_lock_irqsave(cdev->ccwlock, flags);
-       sch = to_subchannel(cdev->dev.parent);
-       /* Extra sanity. */
-       if (sch->lpm)
-               goto out_unlock;
-       if (sch->driver && sch->driver->notify) {
-               spin_unlock_irqrestore(cdev->ccwlock, flags);
-               ret = sch->driver->notify(&sch->dev, CIO_NO_PATH);
-               spin_lock_irqsave(cdev->ccwlock, flags);
-       } else
-               ret = 0;
-       if (!ret) {
-               if (get_device(&sch->dev)) {
-                       /* Driver doesn't want to keep device. */
-                       cio_disable_subchannel(sch);
-                       if (get_device(&cdev->dev)) {
-                               PREPARE_WORK(&cdev->private->kick_work,
-                                            ccw_device_call_sch_unregister);
-                               queue_work(ccw_device_work,
-                                          &cdev->private->kick_work);
-                       } else
-                               put_device(&sch->dev);
-               }
-       } else {
-               cio_disable_subchannel(sch);
-               ccw_device_set_timeout(cdev, 0);
-               cdev->private->flags.fake_irb = 0;
-               cdev->private->state = DEV_STATE_DISCONNECTED;
-               wake_up(&cdev->private->wait_q);
-       }
-out_unlock:
-       spin_unlock_irqrestore(cdev->ccwlock, flags);
-}
-
 void
 ccw_device_verify_done(struct ccw_device *cdev, int err)
 {
@@ -631,12 +587,9 @@ ccw_device_verify_done(struct ccw_device *cdev, int err)
        default:
                /* Reset oper notify indication after verify error. */
                cdev->private->flags.donotify = 0;
-               if (cdev->online) {
-                       PREPARE_WORK(&cdev->private->kick_work,
-                                    ccw_device_nopath_notify);
-                       queue_work(ccw_device_notify_work,
-                                  &cdev->private->kick_work);
-               } else
+               if (cdev->online)
+                       dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
+               else
                        ccw_device_done(cdev, DEV_STATE_NOT_OPER);
                break;
        }
@@ -690,11 +643,7 @@ ccw_device_disband_done(struct ccw_device *cdev, int err)
                break;
        default:
                cdev->private->flags.donotify = 0;
-               if (get_device(&cdev->dev)) {
-                       PREPARE_WORK(&cdev->private->kick_work,
-                                    ccw_device_call_sch_unregister);
-                       queue_work(ccw_device_work, &cdev->private->kick_work);
-               }
+               dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
                ccw_device_done(cdev, DEV_STATE_NOT_OPER);
                break;
        }
@@ -765,59 +714,16 @@ ccw_device_recog_notoper(struct ccw_device *cdev, enum dev_event dev_event)
 }
 
 /*
- * Handle not operational event while offline.
+ * Handle not operational event in non-special state.
  */
-static void
-ccw_device_offline_notoper(struct ccw_device *cdev, enum dev_event dev_event)
+static void ccw_device_generic_notoper(struct ccw_device *cdev,
+                                      enum dev_event dev_event)
 {
        struct subchannel *sch;
 
        cdev->private->state = DEV_STATE_NOT_OPER;
        sch = to_subchannel(cdev->dev.parent);
-       if (get_device(&cdev->dev)) {
-               PREPARE_WORK(&cdev->private->kick_work,
-                            ccw_device_call_sch_unregister);
-               queue_work(ccw_device_work, &cdev->private->kick_work);
-       }
-       wake_up(&cdev->private->wait_q);
-}
-
-/*
- * Handle not operational event while online.
- */
-static void
-ccw_device_online_notoper(struct ccw_device *cdev, enum dev_event dev_event)
-{
-       struct subchannel *sch;
-       int ret;
-
-       sch = to_subchannel(cdev->dev.parent);
-       if (sch->driver->notify) {
-               spin_unlock_irq(cdev->ccwlock);
-               ret = sch->driver->notify(&sch->dev,
-                                         sch->lpm ? CIO_GONE : CIO_NO_PATH);
-               spin_lock_irq(cdev->ccwlock);
-       } else
-               ret = 0;
-       if (ret) {
-               ccw_device_set_timeout(cdev, 0);
-               cdev->private->flags.fake_irb = 0;
-               cdev->private->state = DEV_STATE_DISCONNECTED;
-               wake_up(&cdev->private->wait_q);
-               return;
-       }
-       cdev->private->state = DEV_STATE_NOT_OPER;
-       cio_disable_subchannel(sch);
-       if (sch->schib.scsw.actl != 0) {
-               // FIXME: not-oper indication to device driver ?
-               ccw_device_call_handler(cdev);
-       }
-       if (get_device(&cdev->dev)) {
-               PREPARE_WORK(&cdev->private->kick_work,
-                            ccw_device_call_sch_unregister);
-               queue_work(ccw_device_work, &cdev->private->kick_work);
-       }
-       wake_up(&cdev->private->wait_q);
+       css_schedule_eval(sch->schid);
 }
 
 /*
@@ -915,18 +821,9 @@ ccw_device_online_timeout(struct ccw_device *cdev, enum dev_event dev_event)
                cdev->private->state = DEV_STATE_TIMEOUT_KILL;
                return;
        }
-       if (ret == -ENODEV) {
-               struct subchannel *sch;
-
-               sch = to_subchannel(cdev->dev.parent);
-               if (!sch->lpm) {
-                       PREPARE_WORK(&cdev->private->kick_work,
-                                    ccw_device_nopath_notify);
-                       queue_work(ccw_device_notify_work,
-                                  &cdev->private->kick_work);
-               } else
-                       dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
-       } else if (cdev->handler)
+       if (ret == -ENODEV)
+               dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
+       else if (cdev->handler)
                cdev->handler(cdev, cdev->private->intparm,
                              ERR_PTR(-ETIMEDOUT));
 }
@@ -1233,7 +1130,7 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
                [DEV_EVENT_VERIFY]      = ccw_device_nop,
        },
        [DEV_STATE_SENSE_PGID] = {
-               [DEV_EVENT_NOTOPER]     = ccw_device_online_notoper,
+               [DEV_EVENT_NOTOPER]     = ccw_device_generic_notoper,
                [DEV_EVENT_INTERRUPT]   = ccw_device_sense_pgid_irq,
                [DEV_EVENT_TIMEOUT]     = ccw_device_onoff_timeout,
                [DEV_EVENT_VERIFY]      = ccw_device_nop,
@@ -1245,50 +1142,50 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
                [DEV_EVENT_VERIFY]      = ccw_device_nop,
        },
        [DEV_STATE_OFFLINE] = {
-               [DEV_EVENT_NOTOPER]     = ccw_device_offline_notoper,
+               [DEV_EVENT_NOTOPER]     = ccw_device_generic_notoper,
                [DEV_EVENT_INTERRUPT]   = ccw_device_offline_irq,
                [DEV_EVENT_TIMEOUT]     = ccw_device_nop,
                [DEV_EVENT_VERIFY]      = ccw_device_nop,
        },
        [DEV_STATE_VERIFY] = {
-               [DEV_EVENT_NOTOPER]     = ccw_device_online_notoper,
+               [DEV_EVENT_NOTOPER]     = ccw_device_generic_notoper,
                [DEV_EVENT_INTERRUPT]   = ccw_device_verify_irq,
                [DEV_EVENT_TIMEOUT]     = ccw_device_onoff_timeout,
                [DEV_EVENT_VERIFY]      = ccw_device_delay_verify,
        },
        [DEV_STATE_ONLINE] = {
-               [DEV_EVENT_NOTOPER]     = ccw_device_online_notoper,
+               [DEV_EVENT_NOTOPER]     = ccw_device_generic_notoper,
                [DEV_EVENT_INTERRUPT]   = ccw_device_irq,
                [DEV_EVENT_TIMEOUT]     = ccw_device_online_timeout,
                [DEV_EVENT_VERIFY]      = ccw_device_online_verify,
        },
        [DEV_STATE_W4SENSE] = {
-               [DEV_EVENT_NOTOPER]     = ccw_device_online_notoper,
+               [DEV_EVENT_NOTOPER]     = ccw_device_generic_notoper,
                [DEV_EVENT_INTERRUPT]   = ccw_device_w4sense,
                [DEV_EVENT_TIMEOUT]     = ccw_device_nop,
                [DEV_EVENT_VERIFY]      = ccw_device_online_verify,
        },
        [DEV_STATE_DISBAND_PGID] = {
-               [DEV_EVENT_NOTOPER]     = ccw_device_online_notoper,
+               [DEV_EVENT_NOTOPER]     = ccw_device_generic_notoper,
                [DEV_EVENT_INTERRUPT]   = ccw_device_disband_irq,
                [DEV_EVENT_TIMEOUT]     = ccw_device_onoff_timeout,
                [DEV_EVENT_VERIFY]      = ccw_device_nop,
        },
        [DEV_STATE_BOXED] = {
-               [DEV_EVENT_NOTOPER]     = ccw_device_offline_notoper,
+               [DEV_EVENT_NOTOPER]     = ccw_device_generic_notoper,
                [DEV_EVENT_INTERRUPT]   = ccw_device_stlck_done,
                [DEV_EVENT_TIMEOUT]     = ccw_device_stlck_done,
                [DEV_EVENT_VERIFY]      = ccw_device_nop,
        },
        /* states to wait for i/o completion before doing something */
        [DEV_STATE_CLEAR_VERIFY] = {
-               [DEV_EVENT_NOTOPER]     = ccw_device_online_notoper,
+               [DEV_EVENT_NOTOPER]     = ccw_device_generic_notoper,
                [DEV_EVENT_INTERRUPT]   = ccw_device_clear_verify,
                [DEV_EVENT_TIMEOUT]     = ccw_device_nop,
                [DEV_EVENT_VERIFY]      = ccw_device_nop,
        },
        [DEV_STATE_TIMEOUT_KILL] = {
-               [DEV_EVENT_NOTOPER]     = ccw_device_online_notoper,
+               [DEV_EVENT_NOTOPER]     = ccw_device_generic_notoper,
                [DEV_EVENT_INTERRUPT]   = ccw_device_killing_irq,
                [DEV_EVENT_TIMEOUT]     = ccw_device_killing_timeout,
                [DEV_EVENT_VERIFY]      = ccw_device_nop, //FIXME
index 14eba854b1556e8bad206828105ea8c5974aeb24..7fd2dadc32979272ad77fc16c1112e423e1e48e2 100644 (file)
 #include "device.h"
 #include "chp.h"
 
+/**
+ * ccw_device_set_options_mask() - set some options and unset the rest
+ * @cdev: device for which the options are to be set
+ * @flags: options to be set
+ *
+ * All flags specified in @flags are set, all flags not specified in @flags
+ * are cleared.
+ * Returns:
+ *   %0 on success, -%EINVAL on an invalid flag combination.
+ */
 int ccw_device_set_options_mask(struct ccw_device *cdev, unsigned long flags)
 {
        /*
@@ -40,6 +50,15 @@ int ccw_device_set_options_mask(struct ccw_device *cdev, unsigned long flags)
        return 0;
 }
 
+/**
+ * ccw_device_set_options() - set some options
+ * @cdev: device for which the options are to be set
+ * @flags: options to be set
+ *
+ * All flags specified in @flags are set, the remainder is left untouched.
+ * Returns:
+ *   %0 on success, -%EINVAL if an invalid flag combination would ensue.
+ */
 int ccw_device_set_options(struct ccw_device *cdev, unsigned long flags)
 {
        /*
@@ -59,6 +78,13 @@ int ccw_device_set_options(struct ccw_device *cdev, unsigned long flags)
        return 0;
 }
 
+/**
+ * ccw_device_clear_options() - clear some options
+ * @cdev: device for which the options are to be cleared
+ * @flags: options to be cleared
+ *
+ * All flags specified in @flags are cleared, the remainder is left untouched.
+ */
 void ccw_device_clear_options(struct ccw_device *cdev, unsigned long flags)
 {
        cdev->private->options.fast &= (flags & CCWDEV_EARLY_NOTIFICATION) == 0;
@@ -67,8 +93,22 @@ void ccw_device_clear_options(struct ccw_device *cdev, unsigned long flags)
        cdev->private->options.force &= (flags & CCWDEV_ALLOW_FORCE) == 0;
 }
 
-int
-ccw_device_clear(struct ccw_device *cdev, unsigned long intparm)
+/**
+ * ccw_device_clear() - terminate I/O request processing
+ * @cdev: target ccw device
+ * @intparm: interruption parameter; value is only used if no I/O is
+ *          outstanding, otherwise the intparm associated with the I/O request
+ *          is returned
+ *
+ * ccw_device_clear() calls csch on @cdev's subchannel.
+ * Returns:
+ *  %0 on success,
+ *  -%ENODEV on device not operational,
+ *  -%EINVAL on invalid device state.
+ * Context:
+ *  Interrupts disabled, ccw device lock held
+ */
+int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm)
 {
        struct subchannel *sch;
        int ret;
@@ -89,10 +129,33 @@ ccw_device_clear(struct ccw_device *cdev, unsigned long intparm)
        return ret;
 }
 
-int
-ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
-                    unsigned long intparm, __u8 lpm, __u8 key,
-                    unsigned long flags)
+/**
+ * ccw_device_start_key() - start a s390 channel program with key
+ * @cdev: target ccw device
+ * @cpa: logical start address of channel program
+ * @intparm: user specific interruption parameter; will be presented back to
+ *          @cdev's interrupt handler. Allows a device driver to associate
+ *          the interrupt with a particular I/O request.
+ * @lpm: defines the channel path to be used for a specific I/O request. A
+ *      value of 0 will make cio use the opm.
+ * @key: storage key to be used for the I/O
+ * @flags: additional flags; defines the action to be performed for I/O
+ *        processing.
+ *
+ * Start a S/390 channel program. When the interrupt arrives, the
+ * IRQ handler is called, either immediately, delayed (dev-end missing,
+ * or sense required) or never (no IRQ handler registered).
+ * Returns:
+ *  %0, if the operation was successful;
+ *  -%EBUSY, if the device is busy, or status pending;
+ *  -%EACCES, if no path specified in @lpm is operational;
+ *  -%ENODEV, if the device is not operational.
+ * Context:
+ *  Interrupts disabled, ccw device lock held
+ */
+int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
+                        unsigned long intparm, __u8 lpm, __u8 key,
+                        unsigned long flags)
 {
        struct subchannel *sch;
        int ret;
@@ -135,11 +198,38 @@ ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
        return ret;
 }
 
-
-int
-ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa,
-                            unsigned long intparm, __u8 lpm, __u8 key,
-                            unsigned long flags, int expires)
+/**
+ * ccw_device_start_timeout_key() - start a s390 channel program with timeout and key
+ * @cdev: target ccw device
+ * @cpa: logical start address of channel program
+ * @intparm: user specific interruption parameter; will be presented back to
+ *          @cdev's interrupt handler. Allows a device driver to associate
+ *          the interrupt with a particular I/O request.
+ * @lpm: defines the channel path to be used for a specific I/O request. A
+ *      value of 0 will make cio use the opm.
+ * @key: storage key to be used for the I/O
+ * @flags: additional flags; defines the action to be performed for I/O
+ *        processing.
+ * @expires: timeout value in jiffies
+ *
+ * Start a S/390 channel program. When the interrupt arrives, the
+ * IRQ handler is called, either immediately, delayed (dev-end missing,
+ * or sense required) or never (no IRQ handler registered).
+ * This function notifies the device driver if the channel program has not
+ * completed during the time specified by @expires. If a timeout occurs, the
+ * channel program is terminated via xsch, hsch or csch, and the device's
+ * interrupt handler will be called with an irb containing ERR_PTR(-%ETIMEDOUT).
+ * Returns:
+ *  %0, if the operation was successful;
+ *  -%EBUSY, if the device is busy, or status pending;
+ *  -%EACCES, if no path specified in @lpm is operational;
+ *  -%ENODEV, if the device is not operational.
+ * Context:
+ *  Interrupts disabled, ccw device lock held
+ */
+int ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa,
+                                unsigned long intparm, __u8 lpm, __u8 key,
+                                unsigned long flags, int expires)
 {
        int ret;
 
@@ -152,18 +242,67 @@ ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa,
        return ret;
 }
 
-int
-ccw_device_start(struct ccw_device *cdev, struct ccw1 *cpa,
-                unsigned long intparm, __u8 lpm, unsigned long flags)
+/**
+ * ccw_device_start() - start a s390 channel program
+ * @cdev: target ccw device
+ * @cpa: logical start address of channel program
+ * @intparm: user specific interruption parameter; will be presented back to
+ *          @cdev's interrupt handler. Allows a device driver to associate
+ *          the interrupt with a particular I/O request.
+ * @lpm: defines the channel path to be used for a specific I/O request. A
+ *      value of 0 will make cio use the opm.
+ * @flags: additional flags; defines the action to be performed for I/O
+ *        processing.
+ *
+ * Start a S/390 channel program. When the interrupt arrives, the
+ * IRQ handler is called, either immediately, delayed (dev-end missing,
+ * or sense required) or never (no IRQ handler registered).
+ * Returns:
+ *  %0, if the operation was successful;
+ *  -%EBUSY, if the device is busy, or status pending;
+ *  -%EACCES, if no path specified in @lpm is operational;
+ *  -%ENODEV, if the device is not operational.
+ * Context:
+ *  Interrupts disabled, ccw device lock held
+ */
+int ccw_device_start(struct ccw_device *cdev, struct ccw1 *cpa,
+                    unsigned long intparm, __u8 lpm, unsigned long flags)
 {
        return ccw_device_start_key(cdev, cpa, intparm, lpm,
                                    PAGE_DEFAULT_KEY, flags);
 }
 
-int
-ccw_device_start_timeout(struct ccw_device *cdev, struct ccw1 *cpa,
-                        unsigned long intparm, __u8 lpm, unsigned long flags,
-                        int expires)
+/**
+ * ccw_device_start_timeout() - start a s390 channel program with timeout
+ * @cdev: target ccw device
+ * @cpa: logical start address of channel program
+ * @intparm: user specific interruption parameter; will be presented back to
+ *          @cdev's interrupt handler. Allows a device driver to associate
+ *          the interrupt with a particular I/O request.
+ * @lpm: defines the channel path to be used for a specific I/O request. A
+ *      value of 0 will make cio use the opm.
+ * @flags: additional flags; defines the action to be performed for I/O
+ *        processing.
+ * @expires: timeout value in jiffies
+ *
+ * Start a S/390 channel program. When the interrupt arrives, the
+ * IRQ handler is called, either immediately, delayed (dev-end missing,
+ * or sense required) or never (no IRQ handler registered).
+ * This function notifies the device driver if the channel program has not
+ * completed during the time specified by @expires. If a timeout occurs, the
+ * channel program is terminated via xsch, hsch or csch, and the device's
+ * interrupt handler will be called with an irb containing ERR_PTR(-%ETIMEDOUT).
+ * Returns:
+ *  %0, if the operation was successful;
+ *  -%EBUSY, if the device is busy, or status pending;
+ *  -%EACCES, if no path specified in @lpm is operational;
+ *  -%ENODEV, if the device is not operational.
+ * Context:
+ *  Interrupts disabled, ccw device lock held
+ */
+int ccw_device_start_timeout(struct ccw_device *cdev, struct ccw1 *cpa,
+                            unsigned long intparm, __u8 lpm,
+                            unsigned long flags, int expires)
 {
        return ccw_device_start_timeout_key(cdev, cpa, intparm, lpm,
                                            PAGE_DEFAULT_KEY, flags,
@@ -171,8 +310,23 @@ ccw_device_start_timeout(struct ccw_device *cdev, struct ccw1 *cpa,
 }
 
 
-int
-ccw_device_halt(struct ccw_device *cdev, unsigned long intparm)
+/**
+ * ccw_device_halt() - halt I/O request processing
+ * @cdev: target ccw device
+ * @intparm: interruption parameter; value is only used if no I/O is
+ *          outstanding, otherwise the intparm associated with the I/O request
+ *          is returned
+ *
+ * ccw_device_halt() calls hsch on @cdev's subchannel.
+ * Returns:
+ *  %0 on success,
+ *  -%ENODEV on device not operational,
+ *  -%EINVAL on invalid device state,
+ *  -%EBUSY on device busy or interrupt pending.
+ * Context:
+ *  Interrupts disabled, ccw device lock held
+ */
+int ccw_device_halt(struct ccw_device *cdev, unsigned long intparm)
 {
        struct subchannel *sch;
        int ret;
@@ -193,8 +347,20 @@ ccw_device_halt(struct ccw_device *cdev, unsigned long intparm)
        return ret;
 }
 
-int
-ccw_device_resume(struct ccw_device *cdev)
+/**
+ * ccw_device_resume() - resume channel program execution
+ * @cdev: target ccw device
+ *
+ * ccw_device_resume() calls rsch on @cdev's subchannel.
+ * Returns:
+ *  %0 on success,
+ *  -%ENODEV on device not operational,
+ *  -%EINVAL on invalid device state,
+ *  -%EBUSY on device busy or interrupt pending.
+ * Context:
+ *  Interrupts disabled, ccw device lock held
+ */
+int ccw_device_resume(struct ccw_device *cdev)
 {
        struct subchannel *sch;
 
@@ -260,11 +426,21 @@ ccw_device_call_handler(struct ccw_device *cdev)
        return 1;
 }
 
-/*
- * Search for CIW command in extended sense data.
+/**
+ * ccw_device_get_ciw() - Search for CIW command in extended sense data.
+ * @cdev: ccw device to inspect
+ * @ct: command type to look for
+ *
+ * During SenseID, command information words (CIWs) describing special
+ * commands available to the device may have been stored in the extended
+ * sense data. This function searches for CIWs of a specified command
+ * type in the extended sense data.
+ * Returns:
+ *  %NULL if no extended sense data has been stored or if no CIW of the
+ *  specified command type could be found,
+ *  else a pointer to the CIW of the specified command type.
  */
-struct ciw *
-ccw_device_get_ciw(struct ccw_device *cdev, __u32 ct)
+struct ciw *ccw_device_get_ciw(struct ccw_device *cdev, __u32 ct)
 {
        int ciw_cnt;
 
@@ -276,8 +452,14 @@ ccw_device_get_ciw(struct ccw_device *cdev, __u32 ct)
        return NULL;
 }
 
-__u8
-ccw_device_get_path_mask(struct ccw_device *cdev)
+/**
+ * ccw_device_get_path_mask() - get currently available paths
+ * @cdev: ccw device to be queried
+ * Returns:
+ *  %0 if no subchannel for the device is available,
+ *  else the mask of currently available paths for the ccw device's subchannel.
+ */
+__u8 ccw_device_get_path_mask(struct ccw_device *cdev)
 {
        struct subchannel *sch;
 
@@ -357,8 +539,7 @@ out_unlock:
        return ret;
 }
 
-void *
-ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no)
+void *ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no)
 {
        struct subchannel *sch;
        struct chp_id chpid;
index d8d479876ec7ad7de402ada7cb8cf079cd1a0583..40a3208c7cf3defbc2c47429a8a4654d32290630 100644 (file)
@@ -1024,9 +1024,9 @@ __qdio_outbound_processing(struct qdio_q *q)
 }
 
 static void
-qdio_outbound_processing(struct qdio_q *q)
+qdio_outbound_processing(unsigned long q)
 {
-       __qdio_outbound_processing(q);
+       __qdio_outbound_processing((struct qdio_q *) q);
 }
 
 /************************* INBOUND ROUTINES *******************************/
@@ -1449,9 +1449,10 @@ out:
 }
 
 static void
-tiqdio_inbound_processing(struct qdio_q *q)
+tiqdio_inbound_processing(unsigned long q)
 {
-       __tiqdio_inbound_processing(q, atomic_read(&spare_indicator_usecount));
+       __tiqdio_inbound_processing((struct qdio_q *) q,
+                                   atomic_read(&spare_indicator_usecount));
 }
 
 static void
@@ -1494,9 +1495,9 @@ again:
 }
 
 static void
-qdio_inbound_processing(struct qdio_q *q)
+qdio_inbound_processing(unsigned long q)
 {
-       __qdio_inbound_processing(q);
+       __qdio_inbound_processing((struct qdio_q *) q);
 }
 
 /************************* MAIN ROUTINES *******************************/
@@ -1760,12 +1761,15 @@ qdio_fill_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev,
                q->handler=input_handler;
                q->dev_st_chg_ind=irq_ptr->dev_st_chg_ind;
 
-               q->tasklet.data=(unsigned long)q;
                /* q->is_thinint_q isn't valid at this time, but
-                * irq_ptr->is_thinint_irq is */
-               q->tasklet.func=(void(*)(unsigned long))
-                       ((irq_ptr->is_thinint_irq)?&tiqdio_inbound_processing:
-                        &qdio_inbound_processing);
+                * irq_ptr->is_thinint_irq is
+                */
+               if (irq_ptr->is_thinint_irq)
+                       tasklet_init(&q->tasklet, tiqdio_inbound_processing,
+                                    (unsigned long) q);
+               else
+                       tasklet_init(&q->tasklet, qdio_inbound_processing,
+                                    (unsigned long) q);
 
                /* actually this is not used for inbound queues. yet. */
                atomic_set(&q->busy_siga_counter,0);
@@ -1836,13 +1840,10 @@ qdio_fill_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev,
                q->last_move_ftc=0;
                q->handler=output_handler;
 
-               q->tasklet.data=(unsigned long)q;
-               q->tasklet.func=(void(*)(unsigned long))
-                       &qdio_outbound_processing;
-               q->timer.function=(void(*)(unsigned long))
-                       &qdio_outbound_processing;
-               q->timer.data = (long)q;
-               init_timer(&q->timer);
+               tasklet_init(&q->tasklet, qdio_outbound_processing,
+                            (unsigned long) q);
+               setup_timer(&q->timer, qdio_outbound_processing,
+                           (unsigned long) q);
 
                atomic_set(&q->busy_siga_counter,0);
                q->timing.busy_start=0;
@@ -3726,7 +3727,7 @@ qdio_performance_stats_store(struct bus_type *bus, const char *buf, size_t count
 #endif /* CONFIG_64BIT */
                }
        } else {
-               QDIO_PRINT_WARN("QDIO performance_stats: write 0 or 1 to this file!\n");
+               QDIO_PRINT_ERR("QDIO performance_stats: write 0 or 1 to this file!\n");
                return -EINVAL;
        }
        return count;
index 90bd22014513e7c56d05b7dd7eefe586c982761a..67aaff3e668d8a3354c06ae23099e8611b921065 100644 (file)
@@ -458,28 +458,22 @@ static int ap_bus_match(struct device *dev, struct device_driver *drv)
  * uevent function for AP devices. It sets up a single environment
  * variable DEV_TYPE which contains the hardware device type.
  */
-static int ap_uevent (struct device *dev, char **envp, int num_envp,
-                      char *buffer, int buffer_size)
+static int ap_uevent (struct device *dev, struct kobj_uevent_env *env)
 {
        struct ap_device *ap_dev = to_ap_dev(dev);
-       int retval = 0, length = 0, i = 0;
+       int retval = 0;
 
        if (!ap_dev)
                return -ENODEV;
 
        /* Set up DEV_TYPE environment variable. */
-       retval = add_uevent_var(envp, num_envp, &i,
-                               buffer, buffer_size, &length,
-                               "DEV_TYPE=%04X", ap_dev->device_type);
+       retval = add_uevent_var(env, "DEV_TYPE=%04X", ap_dev->device_type);
        if (retval)
                return retval;
 
        /* Add MODALIAS= */
-       retval = add_uevent_var(envp, num_envp, &i,
-                               buffer, buffer_size, &length,
-                               "MODALIAS=ap:t%02X", ap_dev->device_type);
+       retval = add_uevent_var(env, "MODALIAS=ap:t%02X", ap_dev->device_type);
 
-       envp[i] = NULL;
        return retval;
 }
 
@@ -1231,8 +1225,9 @@ static void ap_reset_domain(void)
 {
        int i;
 
-       for (i = 0; i < AP_DEVICES; i++)
-               ap_reset_queue(AP_MKQID(i, ap_domain_index));
+       if (ap_domain_index != -1)
+               for (i = 0; i < AP_DEVICES; i++)
+                       ap_reset_queue(AP_MKQID(i, ap_domain_index));
 }
 
 static void ap_reset_all(void)
index 2a9349ad68b7e20848fc909582a5a08f8d842aba..44253fdd41364436a6057d1100bba3f0a93892fe 100644 (file)
@@ -45,7 +45,7 @@
 /**
  * The module initialization code.
  */
-int __init zcrypt_init(void)
+static int __init zcrypt_init(void)
 {
        int rc;
 
@@ -86,7 +86,7 @@ out:
 /**
  * The module termination code.
  */
-void __exit zcrypt_exit(void)
+static void __exit zcrypt_exit(void)
 {
        zcrypt_cex2a_exit();
        zcrypt_pcixcc_exit();
index 64948788d30157c7237d43a68a8d3cdac509509f..70b9ddc8cf9d6270db525c7a62e6d7c019aedccf 100644 (file)
@@ -277,7 +277,7 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev,
        };
        struct {
                struct type6_hdr hdr;
-               struct ica_CPRBX cprbx;
+               struct CPRBX cprbx;
        } __attribute__((packed)) *msg = ap_msg->message;
 
        int rcblen = CEIL4(xcRB->request_control_blk_length);
@@ -432,14 +432,17 @@ static int convert_type86_ica(struct zcrypt_device *zdev,
                }
                if (service_rc == 8 && service_rs == 770) {
                        PDEBUG("Invalid key length on PCIXCC/CEX2C\n");
-                       zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
-                       return -EAGAIN;
+                       return -EINVAL;
                }
                if (service_rc == 8 && service_rs == 783) {
                        PDEBUG("Extended bitlengths not enabled on PCIXCC/CEX2C\n");
                        zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
                        return -EAGAIN;
                }
+               if (service_rc == 12 && service_rs == 769) {
+                       PDEBUG("Invalid key on PCIXCC/CEX2C\n");
+                       return -EINVAL;
+               }
                PRINTK("Unknown service rc/rs (PCIXCC/CEX2C): %d/%d\n",
                       service_rc, service_rs);
                zdev->online = 0;
index a78ff307fd191d22a67ef9dc017f6b8af309d517..8cb7d7a6973b4e19c89f10a0d18fc9bb797f2cf0 100644 (file)
 #ifndef _ZCRYPT_PCIXCC_H_
 #define _ZCRYPT_PCIXCC_H_
 
-/**
- * CPRBX
- *       Note that all shorts and ints are big-endian.
- *       All pointer fields are 16 bytes long, and mean nothing.
- *
- *       A request CPRB is followed by a request_parameter_block.
- *
- *       The request (or reply) parameter block is organized thus:
- *         function code
- *         VUD block
- *         key block
- */
-struct CPRBX {
-       unsigned short cprb_len;        /* CPRB length        220        */
-       unsigned char  cprb_ver_id;     /* CPRB version id.   0x02       */
-       unsigned char  pad_000[3];      /* Alignment pad bytes           */
-       unsigned char  func_id[2];      /* function id        0x5432     */
-       unsigned char  cprb_flags[4];   /* Flags                         */
-       unsigned int   req_parml;       /* request parameter buffer len  */
-       unsigned int   req_datal;       /* request data buffer           */
-       unsigned int   rpl_msgbl;       /* reply  message block length   */
-       unsigned int   rpld_parml;      /* replied parameter block len   */
-       unsigned int   rpl_datal;       /* reply data block len          */
-       unsigned int   rpld_datal;      /* replied data block len        */
-       unsigned int   req_extbl;       /* request extension block len   */
-       unsigned char  pad_001[4];      /* reserved                      */
-       unsigned int   rpld_extbl;      /* replied extension block len   */
-       unsigned char  req_parmb[16];   /* request parm block 'address'  */
-       unsigned char  req_datab[16];   /* request data block 'address'  */
-       unsigned char  rpl_parmb[16];   /* reply parm block 'address'    */
-       unsigned char  rpl_datab[16];   /* reply data block 'address'    */
-       unsigned char  req_extb[16];    /* request extension block 'addr'*/
-       unsigned char  rpl_extb[16];    /* reply extension block 'addres'*/
-       unsigned short ccp_rtcode;      /* server return code            */
-       unsigned short ccp_rscode;      /* server reason code            */
-       unsigned int   mac_data_len;    /* Mac Data Length               */
-       unsigned char  logon_id[8];     /* Logon Identifier              */
-       unsigned char  mac_value[8];    /* Mac Value                     */
-       unsigned char  mac_content_flgs;/* Mac content flag byte         */
-       unsigned char  pad_002;         /* Alignment                     */
-       unsigned short domain;          /* Domain                        */
-       unsigned char  pad_003[12];     /* Domain masks                  */
-       unsigned char  pad_004[36];     /* reserved                      */
-} __attribute__((packed));
-
 int zcrypt_pcixcc_init(void);
 void zcrypt_pcixcc_exit(void);
 
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 1c8f71a59855b26b2123e611b3ce3978ee6d5dd2..e01cbf152a81d3622a5d4a607b103ab472e607d0 100644 (file)
@@ -28,7 +28,7 @@ static void zfcp_ccw_remove(struct ccw_device *);
 static int zfcp_ccw_set_online(struct ccw_device *);
 static int zfcp_ccw_set_offline(struct ccw_device *);
 static int zfcp_ccw_notify(struct ccw_device *, int);
-static void zfcp_ccw_shutdown(struct device *);
+static void zfcp_ccw_shutdown(struct ccw_device *);
 
 static struct ccw_device_id zfcp_ccw_device_id[] = {
        {CCW_DEVICE_DEVTYPE(ZFCP_CONTROL_UNIT_TYPE,
@@ -51,9 +51,7 @@ static struct ccw_driver zfcp_ccw_driver = {
        .set_online  = zfcp_ccw_set_online,
        .set_offline = zfcp_ccw_set_offline,
        .notify      = zfcp_ccw_notify,
-       .driver      = {
-               .shutdown = zfcp_ccw_shutdown,
-       },
+       .shutdown    = zfcp_ccw_shutdown,
 };
 
 MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id);
@@ -150,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);
@@ -177,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;
@@ -201,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;
 }
@@ -277,12 +269,12 @@ zfcp_ccw_register(void)
  * Makes sure that QDIO queues are down when the system gets stopped.
  */
 static void
-zfcp_ccw_shutdown(struct device *dev)
+zfcp_ccw_shutdown(struct ccw_device *cdev)
 {
        struct zfcp_adapter *adapter;
 
        down(&zfcp_data.config_sema);
-       adapter = dev_get_drvdata(dev);
+       adapter = dev_get_drvdata(&cdev->dev);
        zfcp_erp_adapter_shutdown(adapter, 0);
        zfcp_erp_wait(adapter);
        up(&zfcp_data.config_sema);
index 5f3212440f68594b304e9c0b48074b1c3c0618bd..ffa3bf756943f6aa142c8bf66bc74e70de1c3fc5 100644 (file)
@@ -19,8 +19,8 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <asm/debug.h>
 #include <linux/ctype.h>
+#include <asm/debug.h>
 #include "zfcp_ext.h"
 
 static u32 dbfsize = 4;
@@ -35,17 +35,17 @@ static int
 zfcp_dbf_stck(char *out_buf, const char *label, unsigned long long stck)
 {
        unsigned long long sec;
-       struct timespec xtime;
+       struct timespec dbftime;
        int len = 0;
 
        stck -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096);
        sec = stck >> 12;
        do_div(sec, 1000000);
-       xtime.tv_sec = sec;
+       dbftime.tv_sec = sec;
        stck -= (sec * 1000000) << 12;
-       xtime.tv_nsec = ((stck * 1000) >> 12);
+       dbftime.tv_nsec = ((stck * 1000) >> 12);
        len += sprintf(out_buf + len, "%-24s%011lu:%06lu\n",
-                      label, xtime.tv_sec, xtime.tv_nsec);
+                      label, dbftime.tv_sec, dbftime.tv_nsec);
 
        return len;
 }
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 d8cd75ce2d9a37c1675d3c29af6fc9884dc00b66..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
@@ -54,7 +54,7 @@ static int zfcp_erp_strategy_check_adapter(struct zfcp_adapter *, int);
 static int zfcp_erp_strategy_statechange(int, u32, struct zfcp_adapter *,
                                         struct zfcp_port *,
                                         struct zfcp_unit *, int);
-static inline int zfcp_erp_strategy_statechange_detected(atomic_t *, u32);
+static int zfcp_erp_strategy_statechange_detected(atomic_t *, u32);
 static int zfcp_erp_strategy_followup_actions(int, struct zfcp_adapter *,
                                              struct zfcp_port *,
                                              struct zfcp_unit *, int);
@@ -106,8 +106,8 @@ static void zfcp_erp_action_cleanup(int, struct zfcp_adapter *,
 static void zfcp_erp_action_ready(struct zfcp_erp_action *);
 static int  zfcp_erp_action_exists(struct zfcp_erp_action *);
 
-static inline void zfcp_erp_action_to_ready(struct zfcp_erp_action *);
-static inline void zfcp_erp_action_to_running(struct zfcp_erp_action *);
+static void zfcp_erp_action_to_ready(struct zfcp_erp_action *);
+static void zfcp_erp_action_to_running(struct zfcp_erp_action *);
 
 static void zfcp_erp_memwait_handler(unsigned long);
 
@@ -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:
  *
@@ -952,7 +952,7 @@ zfcp_erp_memwait_handler(unsigned long data)
  *             action gets an appropriate flag and will be processed
  *             accordingly
  */
-void zfcp_erp_timeout_handler(unsigned long data)
+static void zfcp_erp_timeout_handler(unsigned long data)
 {
        struct zfcp_erp_action *erp_action = (struct zfcp_erp_action *) data;
        struct zfcp_adapter *adapter = erp_action->adapter;
@@ -967,7 +967,7 @@ 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
@@ -1491,7 +1491,7 @@ zfcp_erp_strategy_statechange(int action,
        return retval;
 }
 
-static inline int
+static int
 zfcp_erp_strategy_statechange_detected(atomic_t * target_status, u32 erp_status)
 {
        return
@@ -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)
@@ -2001,7 +2001,7 @@ zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *erp_action, int close)
  * returns:    0 - successful setup
  *             !0 - failed setup
  */
-int
+static int
 zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action)
 {
        int retval;
@@ -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,
@@ -3248,8 +3248,7 @@ static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *unit)
                zfcp_erp_action_dismiss(&unit->erp_action);
 }
 
-static inline void
-zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)
+static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)
 {
        struct zfcp_adapter *adapter = erp_action->adapter;
 
@@ -3258,8 +3257,7 @@ zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)
        list_move(&erp_action->list, &erp_action->adapter->erp_running_head);
 }
 
-static inline void
-zfcp_erp_action_to_ready(struct zfcp_erp_action *erp_action)
+static void zfcp_erp_action_to_ready(struct zfcp_erp_action *erp_action)
 {
        struct zfcp_adapter *adapter = erp_action->adapter;
 
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..e8010a702e73c6a0c33d0cadbe624b5c8d89947e 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"));
+
+       gdth_put_cmndinfo(cmndinfo);
+       scp->host_scribble = NULL;
 
-    if (scp->request)
-        complete((struct completion *)scp->request);
+       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", ha->hanum));
 
-    TRACE(("gdth_set_sema0() hanum %d\n",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
-{
-    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)
+static const char *gdth_ctr_name(gdth_ha_str *ha)
 {
-    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,536 @@ 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));
+#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 f142eafb6fc748ab5d7aa8c2c99ad38aa77a6c33..b41dfb5390212ddade69f1ff80bbe1930389b36f 100644 (file)
@@ -3829,18 +3829,18 @@ static int ipr_device_reset(struct ipr_ioa_cfg *ioa_cfg,
 
 /**
  * ipr_sata_reset - Reset the SATA port
- * @ap:                SATA port to reset
+ * @link:      SATA link to reset
  * @classes:   class of the attached device
  *
- * This function issues a SATA phy reset to the affected ATA port.
+ * This function issues a SATA phy reset to the affected ATA link.
  *
  * Return value:
  *     0 on success / non-zero on failure
  **/
-static int ipr_sata_reset(struct ata_port *ap, unsigned int *classes,
+static int ipr_sata_reset(struct ata_link *link, unsigned int *classes,
                                unsigned long deadline)
 {
-       struct ipr_sata_port *sata_port = ap->private_data;
+       struct ipr_sata_port *sata_port = link->ap->private_data;
        struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg;
        struct ipr_resource_entry *res;
        unsigned long lock_flags = 0;
@@ -4981,22 +4981,22 @@ static void ipr_ata_phy_reset(struct ata_port *ap)
        rc = ipr_device_reset(ioa_cfg, res);
 
        if (rc) {
-               ap->ops->port_disable(ap);
+               ata_port_disable(ap);
                goto out_unlock;
        }
 
        switch(res->cfgte.proto) {
        case IPR_PROTO_SATA:
        case IPR_PROTO_SAS_STP:
-               ap->device[0].class = ATA_DEV_ATA;
+               ap->link.device[0].class = ATA_DEV_ATA;
                break;
        case IPR_PROTO_SATA_ATAPI:
        case IPR_PROTO_SAS_STP_ATAPI:
-               ap->device[0].class = ATA_DEV_ATAPI;
+               ap->link.device[0].class = ATA_DEV_ATAPI;
                break;
        default:
-               ap->device[0].class = ATA_DEV_UNKNOWN;
-               ap->ops->port_disable(ap);
+               ap->link.device[0].class = ATA_DEV_UNKNOWN;
+               ata_port_disable(ap);
                break;
        };
 
@@ -5262,7 +5262,6 @@ static u8 ipr_ata_check_altstatus(struct ata_port *ap)
 }
 
 static struct ata_port_operations ipr_sata_ops = {
-       .port_disable = ata_port_disable,
        .check_status = ipr_ata_check_status,
        .check_altstatus = ipr_ata_check_altstatus,
        .dev_select = ata_noop_dev_select,
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 5e573efcf0a70f90232ac916aa8897f85c5f713b..0829b55c64d23c90cf70b025a566447eed8635f0 100644 (file)
@@ -249,17 +249,17 @@ static void sas_ata_phy_reset(struct ata_port *ap)
        switch (dev->sata_dev.command_set) {
                case ATA_COMMAND_SET:
                        SAS_DPRINTK("%s: Found ATA device.\n", __FUNCTION__);
-                       ap->device[0].class = ATA_DEV_ATA;
+                       ap->link.device[0].class = ATA_DEV_ATA;
                        break;
                case ATAPI_COMMAND_SET:
                        SAS_DPRINTK("%s: Found ATAPI device.\n", __FUNCTION__);
-                       ap->device[0].class = ATA_DEV_ATAPI;
+                       ap->link.device[0].class = ATA_DEV_ATAPI;
                        break;
                default:
                        SAS_DPRINTK("%s: Unknown SATA command set: %d.\n",
                                    __FUNCTION__,
                                    dev->sata_dev.command_set);
-                       ap->device[0].class = ATA_DEV_UNKNOWN;
+                       ap->link.device[0].class = ATA_DEV_UNKNOWN;
                        break;
        }
 
@@ -317,7 +317,7 @@ static int sas_ata_scr_write(struct ata_port *ap, unsigned int sc_reg_in,
                        dev->sata_dev.serror = val;
                        break;
                case SCR_ACTIVE:
-                       dev->sata_dev.ap->sactive = val;
+                       dev->sata_dev.ap->link.sactive = val;
                        break;
                default:
                        return -EINVAL;
@@ -342,7 +342,7 @@ static int sas_ata_scr_read(struct ata_port *ap, unsigned int sc_reg_in,
                        *val = dev->sata_dev.serror;
                        return 0;
                case SCR_ACTIVE:
-                       *val = dev->sata_dev.ap->sactive;
+                       *val = dev->sata_dev.ap->link.sactive;
                        return 0;
                default:
                        return -EINVAL;
@@ -350,7 +350,6 @@ static int sas_ata_scr_read(struct ata_port *ap, unsigned int sc_reg_in,
 }
 
 static struct ata_port_operations sas_sata_ops = {
-       .port_disable           = ata_port_disable,
        .check_status           = sas_ata_check_status,
        .check_altstatus        = sas_ata_check_status,
        .dev_select             = ata_noop_dev_select,
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 34cdce6738a6c3fe4fab28a739b7ea926788babd..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
 };
 
@@ -277,16 +319,11 @@ static int scsi_bus_match(struct device *dev, struct device_driver *gendrv)
        return (sdp->inq_periph_qual == SCSI_INQ_PQ_CON)? 1: 0;
 }
 
-static int scsi_bus_uevent(struct device *dev, char **envp, int num_envp,
-                          char *buffer, int buffer_size)
+static int scsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        struct scsi_device *sdev = to_scsi_device(dev);
-       int i = 0;
-       int length = 0;
 
-       add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
-                      "MODALIAS=" SCSI_DEVICE_MODALIAS_FMT, sdev->type);
-       envp[i] = NULL;
+       add_uevent_var(env, "MODALIAS=" SCSI_DEVICE_MODALIAS_FMT, sdev->type);
        return 0;
 }
 
@@ -576,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
 };
 
@@ -655,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
@@ -736,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)
@@ -746,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);
@@ -756,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:
@@ -956,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;
@@ -964,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);
@@ -985,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 e84d21597943d85d1752270526f43232221f1e7c..bcb8dd5fb0b48f745e13b5a9430d432360d5c2c8 100644 (file)
@@ -67,14 +67,11 @@ static int spi_match_device(struct device *dev, struct device_driver *drv)
        return strncmp(spi->modalias, drv->name, BUS_ID_SIZE) == 0;
 }
 
-static int spi_uevent(struct device *dev, char **envp, int num_envp,
-               char *buffer, int buffer_size)
+static int spi_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        const struct spi_device         *spi = to_spi_device(dev);
 
-       envp[0] = buffer;
-       snprintf(buffer, buffer_size, "MODALIAS=%s", spi->modalias);
-       envp[1] = NULL;
+       add_uevent_var(env, "MODALIAS=%s", spi->modalias);
        return 0;
 }
 
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 ac49b15fa76840ba74c986ee9d44c8ed7b17bf43..516a6400db432eb0ccb6e96d7af7d0a0a3d0bb82 100644 (file)
@@ -28,27 +28,7 @@ obj-$(CONFIG_USB_MICROTEK)   += image/
 
 obj-$(CONFIG_USB_SERIAL)       += serial/
 
-obj-$(CONFIG_USB_ADUTUX)       += misc/
-obj-$(CONFIG_USB_APPLEDISPLAY) += misc/
-obj-$(CONFIG_USB_AUERSWALD)    += misc/
-obj-$(CONFIG_USB_BERRY_CHARGE) += misc/
-obj-$(CONFIG_USB_CYPRESS_CY7C63)+= misc/
-obj-$(CONFIG_USB_CYTHERM)      += misc/
-obj-$(CONFIG_USB_EMI26)                += misc/
-obj-$(CONFIG_USB_EMI62)                += misc/
-obj-$(CONFIG_USB_FTDI_ELAN)    += misc/
-obj-$(CONFIG_USB_IDMOUSE)      += misc/
-obj-$(CONFIG_USB_LCD)          += misc/
-obj-$(CONFIG_USB_LD)           += misc/
-obj-$(CONFIG_USB_LED)          += misc/
-obj-$(CONFIG_USB_LEGOTOWER)    += misc/
-obj-$(CONFIG_USB_PHIDGETSERVO) += misc/
-obj-$(CONFIG_USB_RIO500)       += misc/
-obj-$(CONFIG_USB_SISUSBVGA)    += misc/
-obj-$(CONFIG_USB_TEST)         += misc/
-obj-$(CONFIG_USB_TRANCEVIBRATOR)+= misc/
-obj-$(CONFIG_USB_USS720)       += misc/
-obj-$(CONFIG_USB_IOWARRIOR)    += misc/
+obj-$(CONFIG_USB)              += misc/
 
 obj-$(CONFIG_USB_ATM)          += atm/
 obj-$(CONFIG_USB_SPEEDTOUCH)   += atm/
index a73e714288e51fa11dbfb86cc71e71039e3f4ae1..a51eeedc18d4860f83814948e0c5150c6d9aab26 100644 (file)
@@ -482,7 +482,9 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
        int rbuflen = ((rsize - 1) / stride + 1) * CMD_PACKET_SIZE;
 
        if (wbuflen > PAGE_SIZE || rbuflen > PAGE_SIZE) {
-               dbg("too big transfer requested");
+               if (printk_ratelimit())
+                       usb_err(instance->usbatm, "requested transfer size too large (%d, %d)\n",
+                               wbuflen, rbuflen);
                ret = -ENOMEM;
                goto fail;
        }
@@ -493,8 +495,9 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
        init_completion(&instance->rcv_done);
        ret = usb_submit_urb(instance->rcv_urb, GFP_KERNEL);
        if (ret < 0) {
-               dbg("submitting read urb for cm %#x failed", cm);
-               ret = ret;
+               if (printk_ratelimit())
+                       usb_err(instance->usbatm, "submit of read urb for cm %#x failed (%d)\n",
+                               cm, ret);
                goto fail;
        }
 
@@ -510,27 +513,29 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
        init_completion(&instance->snd_done);
        ret = usb_submit_urb(instance->snd_urb, GFP_KERNEL);
        if (ret < 0) {
-               dbg("submitting write urb for cm %#x failed", cm);
-               ret = ret;
+               if (printk_ratelimit())
+                       usb_err(instance->usbatm, "submit of write urb for cm %#x failed (%d)\n",
+                               cm, ret);
                goto fail;
        }
 
        ret = cxacru_start_wait_urb(instance->snd_urb, &instance->snd_done, NULL);
        if (ret < 0) {
-               dbg("sending cm %#x failed", cm);
-               ret = ret;
+               if (printk_ratelimit())
+                       usb_err(instance->usbatm, "send of cm %#x failed (%d)\n", cm, ret);
                goto fail;
        }
 
        ret = cxacru_start_wait_urb(instance->rcv_urb, &instance->rcv_done, &actlen);
        if (ret < 0) {
-               dbg("receiving cm %#x failed", cm);
-               ret = ret;
+               if (printk_ratelimit())
+                       usb_err(instance->usbatm, "receive of cm %#x failed (%d)\n", cm, ret);
                goto fail;
        }
        if (actlen % CMD_PACKET_SIZE || !actlen) {
-               dbg("response is not a positive multiple of %d: %#x",
-                               CMD_PACKET_SIZE, actlen);
+               if (printk_ratelimit())
+                       usb_err(instance->usbatm, "invalid response length to cm %#x: %d\n",
+                               cm, actlen);
                ret = -EIO;
                goto fail;
        }
@@ -538,12 +543,16 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
        /* check the return status and copy the data to the output buffer, if needed */
        for (offb = offd = 0; offd < rsize && offb < actlen; offb += CMD_PACKET_SIZE) {
                if (rbuf[offb] != cm) {
-                       dbg("wrong cm %#x in response", rbuf[offb]);
+                       if (printk_ratelimit())
+                               usb_err(instance->usbatm, "wrong cm %#x in response to cm %#x\n",
+                                       rbuf[offb], cm);
                        ret = -EIO;
                        goto fail;
                }
                if (rbuf[offb + 1] != CM_STATUS_SUCCESS) {
-                       dbg("response failed: %#x", rbuf[offb + 1]);
+                       if (printk_ratelimit())
+                               usb_err(instance->usbatm, "response to cm %#x failed: %#x\n",
+                                       cm, rbuf[offb + 1]);
                        ret = -EIO;
                        goto fail;
                }
@@ -582,14 +591,18 @@ static int cxacru_cm_get_array(struct cxacru_data *instance, enum cxacru_cm_requ
        for (offb = 0; offb < len; ) {
                int l = le32_to_cpu(buf[offb++]);
                if (l > stride || l > (len - offb) / 2) {
-                       dbg("wrong data length %#x in response", l);
+                       if (printk_ratelimit())
+                               usb_err(instance->usbatm, "invalid data length from cm %#x: %d\n",
+                                       cm, l);
                        ret = -EIO;
                        goto cleanup;
                }
                while (l--) {
                        offd = le32_to_cpu(buf[offb++]);
                        if (offd >= size) {
-                               dbg("wrong index %#x in response", offd);
+                               if (printk_ratelimit())
+                                       usb_err(instance->usbatm, "wrong index #%x in response to cm #%x\n",
+                                               offd, cm);
                                ret = -EIO;
                                goto cleanup;
                        }
index eb0615abff68a819f4dae10ff2a0010a637dbaaa..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,
@@ -251,7 +251,6 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance,
 {
        unsigned char *buffer;
        struct usbatm_data *usbatm = instance->usbatm;
-       struct usb_interface *intf;
        struct usb_device *usb_dev = usbatm->usb_dev;
        int actual_length;
        int ret = 0;
@@ -265,7 +264,7 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance,
                goto out;
        }
 
-       if (!(intf = usb_ifnum_to_if(usb_dev, 2))) {
+       if (!usb_ifnum_to_if(usb_dev, 2)) {
                ret = -ENODEV;
                usb_dbg(usbatm, "%s: interface not found!\n", __func__);
                goto out_free;
index 29807d048b0413ee0c83b2654dbdda560cf3a741..389c5b164eb2557a89775fbd9785540647c0af21 100644 (file)
@@ -2,7 +2,8 @@
  * Copyright (c) 2003, 2004
  *     Damien Bergamini <damien.bergamini@free.fr>. All rights reserved.
  *
- * Copyright (c) 2005 Matthieu Castet <castet.matthieu@free.fr>
+ * Copyright (c) 2005-2007 Matthieu Castet <castet.matthieu@free.fr>
+ * Copyright (c) 2005-2007 Stanislaw Gruszka <stf_xl@wp.pl>
  *
  * 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
 #define uea_info(usb_dev, format,args...) \
        dev_info(&(usb_dev)->dev ,"[ueagle-atm] " format, ##args)
 
-struct uea_cmvs {
+struct intr_pkt;
+
+/* cmv's from firmware */
+struct uea_cmvs_v1 {
        u32 address;
        u16 offset;
        u32 data;
 } __attribute__ ((packed));
 
+struct uea_cmvs_v2 {
+       u32 group;
+       u32 address;
+       u32 offset;
+       u32 data;
+} __attribute__ ((packed));
+
+/* information about currently processed cmv */
+struct cmv_dsc_e1 {
+       u8 function;
+       u16 idx;
+       u32 address;
+       u16 offset;
+};
+
+struct cmv_dsc_e4 {
+       u16 function;
+       u16 offset;
+       u16 address;
+       u16 group;
+};
+
+union cmv_dsc {
+       struct cmv_dsc_e1 e1;
+       struct cmv_dsc_e4 e4;
+};
+
 struct uea_softc {
        struct usb_device *usb_dev;
        struct usbatm_data *usbatm;
 
        int modem_index;
        unsigned int driver_info;
+       int annex;
+#define ANNEXA 0
+#define ANNEXB 1
 
        int booting;
        int reset;
@@ -127,20 +161,23 @@ struct uea_softc {
 
        struct task_struct *kthread;
        u32 data;
-       wait_queue_head_t cmv_ack_wait;
+       u32 data1;
+
        int cmv_ack;
+       union cmv_dsc cmv_dsc;
 
        struct work_struct task;
+       struct workqueue_struct *work_q;
        u16 pageno;
        u16 ovl;
 
        const struct firmware *dsp_firm;
        struct urb *urb_int;
 
-       u8 cmv_function;
-       u16 cmv_idx;
-       u32 cmv_address;
-       u16 cmv_offset;
+       void (*dispatch_cmv) (struct uea_softc *, struct intr_pkt *);
+       void (*schedule_load_page) (struct uea_softc *, struct intr_pkt *);
+       int (*stat) (struct uea_softc *);
+       int (*send_cmvs) (struct uea_softc *);
 
        /* keep in sync with eaglectl */
        struct uea_stats {
@@ -174,10 +211,34 @@ struct uea_softc {
 #define ELSA_PID_PSTFIRM       0x3350
 #define ELSA_PID_PREFIRM       0x3351
 
+#define ELSA_PID_A_PREFIRM     0x3352
+#define ELSA_PID_A_PSTFIRM     0x3353
+#define ELSA_PID_B_PREFIRM     0x3362
+#define ELSA_PID_B_PSTFIRM     0x3363
+
 /*
- * Sagem USB IDs
+ * Devolo IDs : pots if (pid & 0x10)
  */
-#define EAGLE_VID              0x1110
+#define DEVOLO_VID                     0x1039
+#define DEVOLO_EAGLE_I_A_PID_PSTFIRM   0x2110
+#define DEVOLO_EAGLE_I_A_PID_PREFIRM   0x2111
+
+#define DEVOLO_EAGLE_I_B_PID_PSTFIRM   0x2100
+#define DEVOLO_EAGLE_I_B_PID_PREFIRM   0x2101
+
+#define DEVOLO_EAGLE_II_A_PID_PSTFIRM  0x2130
+#define DEVOLO_EAGLE_II_A_PID_PREFIRM  0x2131
+
+#define DEVOLO_EAGLE_II_B_PID_PSTFIRM  0x2120
+#define DEVOLO_EAGLE_II_B_PID_PREFIRM  0x2121
+
+/*
+ * Reference design USB IDs
+ */
+#define ANALOG_VID             0x1110
+#define ADI930_PID_PREFIRM     0x9001
+#define ADI930_PID_PSTFIRM     0x9000
+
 #define EAGLE_I_PID_PREFIRM    0x9010  /* Eagle I */
 #define EAGLE_I_PID_PSTFIRM    0x900F  /* Eagle I */
 
@@ -187,12 +248,12 @@ struct uea_softc {
 #define EAGLE_II_PID_PREFIRM   0x9022  /* Eagle II */
 #define EAGLE_II_PID_PSTFIRM   0x9021  /* Eagle II */
 
-/*
- *  Eagle III Pid
- */
 #define EAGLE_III_PID_PREFIRM  0x9032  /* Eagle III */
 #define EAGLE_III_PID_PSTFIRM  0x9031  /* Eagle III */
 
+#define EAGLE_IV_PID_PREFIRM   0x9042  /* Eagle IV */
+#define EAGLE_IV_PID_PSTFIRM   0x9041  /* Eagle IV */
+
 /*
  * USR USB IDs
  */
@@ -208,11 +269,15 @@ struct uea_softc {
 
 #define PREFIRM 0
 #define PSTFIRM (1<<7)
+#define AUTO_ANNEX_A (1<<8)
+#define AUTO_ANNEX_B (1<<9)
+
 enum {
        ADI930 = 0,
        EAGLE_I,
        EAGLE_II,
-       EAGLE_III
+       EAGLE_III,
+       EAGLE_IV
 };
 
 /* macros for both struct usb_device_id and struct uea_softc */
@@ -221,15 +286,18 @@ enum {
 #define UEA_CHIP_VERSION(x) \
        ((x)->driver_info & 0xf)
 
-#define IS_ISDN(usb_dev) \
-       (le16_to_cpu((usb_dev)->descriptor.bcdDevice) & 0x80)
+#define IS_ISDN(x) \
+       ((x)->annex & ANNEXB)
 
 #define INS_TO_USBDEV(ins) ins->usb_dev
 
 #define GET_STATUS(data) \
        ((data >> 8) & 0xf)
+
 #define IS_OPERATIONAL(sc) \
-       (GET_STATUS(sc->stats.phy.state) == 2)
+       ((UEA_CHIP_VERSION(sc) != EAGLE_IV) ? \
+       (GET_STATUS(sc->stats.phy.state) == 2) : \
+       (sc->stats.phy.state == 7))
 
 /*
  * Set of macros to handle unaligned data in the firmware blob.
@@ -259,7 +327,8 @@ enum {
 #define UEA_INTR_PIPE          0x04
 #define UEA_ISO_DATA_PIPE      0x08
 
-#define UEA_SET_BLOCK          0x0001
+#define UEA_E1_SET_BLOCK       0x0001
+#define UEA_E4_SET_BLOCK       0x002c
 #define UEA_SET_MODE           0x0003
 #define UEA_SET_2183_DATA      0x0004
 #define UEA_SET_TIMEOUT                0x0011
@@ -275,71 +344,179 @@ enum {
 #define UEA_MPTX_MAILBOX       (0x3fd6 | 0x4000)
 #define UEA_MPRX_MAILBOX       (0x3fdf | 0x4000)
 
-/* structure describing a block within a DSP page */
-struct block_info {
+/* block information in eagle4 dsp firmware  */
+struct block_index {
+       __le32 PageOffset;
+       __le32 NotLastBlock;
+       __le32 dummy;
+       __le32 PageSize;
+       __le32 PageAddress;
+       __le16 dummy1;
+       __le16 PageNumber;
+} __attribute__ ((packed));
+
+#define E4_IS_BOOT_PAGE(PageSize) ((le32_to_cpu(PageSize)) & 0x80000000)
+#define E4_PAGE_BYTES(PageSize) ((le32_to_cpu(PageSize) & 0x7fffffff) * 4)
+
+#define E4_L1_STRING_HEADER 0x10
+#define E4_MAX_PAGE_NUMBER 0x58
+#define E4_NO_SWAPPAGE_HEADERS 0x31
+
+/* l1_code is eagle4 dsp firmware format */
+struct l1_code {
+       u8 string_header[E4_L1_STRING_HEADER];
+       u8 page_number_to_block_index[E4_MAX_PAGE_NUMBER];
+       struct block_index page_header[E4_NO_SWAPPAGE_HEADERS];
+       u8 code [0];
+} __attribute__ ((packed));
+
+/* structures describing a block within a DSP page */
+struct block_info_e1 {
        __le16 wHdr;
-#define UEA_BIHDR 0xabcd
        __le16 wAddress;
        __le16 wSize;
        __le16 wOvlOffset;
        __le16 wOvl;            /* overlay */
        __le16 wLast;
 } __attribute__ ((packed));
-#define BLOCK_INFO_SIZE 12
+#define E1_BLOCK_INFO_SIZE 12
+
+struct block_info_e4 {
+       __be16 wHdr;
+       __u8 bBootPage;
+       __u8 bPageNumber;
+       __be32 dwSize;
+       __be32 dwAddress;
+       __be16 wReserved;
+} __attribute__ ((packed));
+#define E4_BLOCK_INFO_SIZE 14
 
-/* structure representing a CMV (Configuration and Management Variable) */
-struct cmv {
-       __le16 wPreamble;
-#define PREAMBLE 0x535c
-       __u8 bDirection;
-#define MODEMTOHOST 0x01
-#define HOSTTOMODEM 0x10
-       __u8 bFunction;
-#define FUNCTION_TYPE(f)    ((f) >> 4)
-#define MEMACCESS      0x1
-#define ADSLDIRECTIVE  0x7
+#define UEA_BIHDR 0xabcd
+#define UEA_RESERVED 0xffff
+
+/* constants describing cmv type */
+#define E1_PREAMBLE 0x535c
+#define E1_MODEMTOHOST 0x01
+#define E1_HOSTTOMODEM 0x10
+
+#define E1_MEMACCESS 0x1
+#define E1_ADSLDIRECTIVE 0x7
+#define E1_FUNCTION_TYPE(f) ((f) >> 4)
+#define E1_FUNCTION_SUBTYPE(f) ((f) & 0x0f)
+
+#define E4_MEMACCESS 0
+#define E4_ADSLDIRECTIVE 0xf
+#define E4_FUNCTION_TYPE(f) ((f) >> 8)
+#define E4_FUNCTION_SIZE(f) ((f) & 0x0f)
+#define E4_FUNCTION_SUBTYPE(f) (((f) >> 4) & 0x0f)
 
-#define FUNCTION_SUBTYPE(f) ((f) & 0x0f)
 /* for MEMACCESS */
-#define REQUESTREAD    0x0
-#define REQUESTWRITE   0x1
-#define REPLYREAD      0x2
-#define REPLYWRITE     0x3
+#define E1_REQUESTREAD 0x0
+#define E1_REQUESTWRITE        0x1
+#define E1_REPLYREAD   0x2
+#define E1_REPLYWRITE  0x3
+
+#define E4_REQUESTREAD 0x0
+#define E4_REQUESTWRITE        0x4
+#define E4_REPLYREAD   (E4_REQUESTREAD | 1)
+#define E4_REPLYWRITE  (E4_REQUESTWRITE | 1)
+
 /* for ADSLDIRECTIVE */
-#define KERNELREADY    0x0
-#define MODEMREADY     0x1
+#define E1_KERNELREADY 0x0
+#define E1_MODEMREADY  0x1
 
-#define MAKEFUNCTION(t, s) (((t) & 0xf) << 4 | ((s) & 0xf))
-       __le16 wIndex;
-       __le32 dwSymbolicAddress;
-#define MAKESA(a, b, c, d)                                             \
+#define E4_KERNELREADY 0x0
+#define E4_MODEMREADY  0x1
+
+#define E1_MAKEFUNCTION(t, s) (((t) & 0xf) << 4 | ((s) & 0xf))
+#define E4_MAKEFUNCTION(t, st, s) (((t) & 0xf) << 8 | ((st) & 0xf) << 4 | ((s) & 0xf))
+
+#define E1_MAKESA(a, b, c, d)                                          \
        (((c) & 0xff) << 24 |                                           \
         ((d) & 0xff) << 16 |                                           \
         ((a) & 0xff) << 8  |                                           \
         ((b) & 0xff))
-#define GETSA1(a) ((a >> 8) & 0xff)
-#define GETSA2(a) (a & 0xff)
-#define GETSA3(a) ((a >> 24) & 0xff)
-#define GETSA4(a) ((a >> 16) & 0xff)
-
-#define SA_CNTL MAKESA('C', 'N', 'T', 'L')
-#define SA_DIAG MAKESA('D', 'I', 'A', 'G')
-#define SA_INFO MAKESA('I', 'N', 'F', 'O')
-#define SA_OPTN MAKESA('O', 'P', 'T', 'N')
-#define SA_RATE MAKESA('R', 'A', 'T', 'E')
-#define SA_STAT MAKESA('S', 'T', 'A', 'T')
+
+#define E1_GETSA1(a) ((a >> 8) & 0xff)
+#define E1_GETSA2(a) (a & 0xff)
+#define E1_GETSA3(a) ((a >> 24) & 0xff)
+#define E1_GETSA4(a) ((a >> 16) & 0xff)
+
+#define E1_SA_CNTL E1_MAKESA('C', 'N', 'T', 'L')
+#define E1_SA_DIAG E1_MAKESA('D', 'I', 'A', 'G')
+#define E1_SA_INFO E1_MAKESA('I', 'N', 'F', 'O')
+#define E1_SA_OPTN E1_MAKESA('O', 'P', 'T', 'N')
+#define E1_SA_RATE E1_MAKESA('R', 'A', 'T', 'E')
+#define E1_SA_STAT E1_MAKESA('S', 'T', 'A', 'T')
+
+#define E4_SA_CNTL 1
+#define E4_SA_STAT 2
+#define E4_SA_INFO 3
+#define E4_SA_TEST 4
+#define E4_SA_OPTN 5
+#define E4_SA_RATE 6
+#define E4_SA_DIAG 7
+#define E4_SA_CNFG 8
+
+/* structures representing a CMV (Configuration and Management Variable) */
+struct cmv_e1 {
+       __le16 wPreamble;
+       __u8 bDirection;
+       __u8 bFunction;
+       __le16 wIndex;
+       __le32 dwSymbolicAddress;
        __le16 wOffsetAddress;
        __le32 dwData;
 } __attribute__ ((packed));
-#define CMV_SIZE 16
 
-/* structure representing swap information */
-struct swap_info {
+struct cmv_e4 {
+       __be16 wGroup;
+       __be16 wFunction;
+       __be16 wOffset;
+       __be16 wAddress;
+       __be32 dwData [6];
+} __attribute__ ((packed));
+
+/* structures representing swap information */
+struct swap_info_e1 {
        __u8 bSwapPageNo;
        __u8 bOvl;              /* overlay */
 } __attribute__ ((packed));
 
-/* structure representing interrupt data */
+struct swap_info_e4 {
+       __u8 bSwapPageNo;
+} __attribute__ ((packed));
+
+/* structures representing interrupt data */
+#define e1_bSwapPageNo u.e1.s1.swapinfo.bSwapPageNo
+#define e1_bOvl                u.e1.s1.swapinfo.bOvl
+#define e4_bSwapPageNo  u.e4.s1.swapinfo.bSwapPageNo
+
+#define INT_LOADSWAPPAGE 0x0001
+#define INT_INCOMINGCMV  0x0002
+
+union intr_data_e1 {
+       struct {
+               struct swap_info_e1 swapinfo;
+               __le16 wDataSize;
+       } __attribute__ ((packed)) s1;
+       struct {
+               struct cmv_e1 cmv;
+               __le16 wDataSize;
+       } __attribute__ ((packed)) s2;
+} __attribute__ ((packed));
+
+union intr_data_e4 {
+       struct {
+               struct swap_info_e4 swapinfo;
+               __le16 wDataSize;
+       } __attribute__ ((packed)) s1;
+       struct {
+               struct cmv_e4 cmv;
+               __le16 wDataSize;
+       } __attribute__ ((packed)) s2;
+} __attribute__ ((packed));
+
 struct intr_pkt {
        __u8 bType;
        __u8 bNotification;
@@ -347,43 +524,48 @@ struct intr_pkt {
        __le16 wIndex;
        __le16 wLength;
        __le16 wInterrupt;
-#define INT_LOADSWAPPAGE 0x0001
-#define INT_INCOMINGCMV  0x0002
        union {
-               struct {
-                       struct swap_info swapinfo;
-                       __le16 wDataSize;
-               } __attribute__ ((packed)) s1;
-
-               struct {
-                       struct cmv cmv;
-                       __le16 wDataSize;
-               } __attribute__ ((packed)) s2;
-       } __attribute__ ((packed)) u;
-#define bSwapPageNo    u.s1.swapinfo.bSwapPageNo
-#define bOvl           u.s1.swapinfo.bOvl
+               union intr_data_e1 e1;
+               union intr_data_e4 e4;
+       } u;
 } __attribute__ ((packed));
-#define INTR_PKT_SIZE 28
+
+#define E1_INTR_PKT_SIZE 28
+#define E4_INTR_PKT_SIZE 64
 
 static struct usb_driver uea_driver;
 static DEFINE_MUTEX(uea_mutex);
-static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III"};
+static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III", "Eagle IV"};
 
 static int modem_index;
 static unsigned int debug;
-static int use_iso[NB_MODEM] = {[0 ... (NB_MODEM - 1)] = 1};
+static unsigned int altsetting[NB_MODEM] = {[0 ... (NB_MODEM - 1)] = FASTEST_ISO_INTF};
 static int sync_wait[NB_MODEM];
 static char *cmv_file[NB_MODEM];
+static int annex[NB_MODEM];
 
 module_param(debug, uint, 0644);
 MODULE_PARM_DESC(debug, "module debug level (0=off,1=on,2=verbose)");
-module_param_array(use_iso, bool, NULL, 0644);
-MODULE_PARM_DESC(use_iso, "use isochronous usb pipe for incoming traffic");
+module_param_array(altsetting, uint, NULL, 0644);
+MODULE_PARM_DESC(altsetting, "alternate setting for incoming traffic: 0=bulk, "
+                            "1=isoc slowest, ... , 8=isoc fastest (default)");
 module_param_array(sync_wait, bool, NULL, 0644);
 MODULE_PARM_DESC(sync_wait, "wait the synchronisation before starting ATM");
 module_param_array(cmv_file, charp, NULL, 0644);
 MODULE_PARM_DESC(cmv_file,
                "file name with configuration and management variables");
+module_param_array(annex, uint, NULL, 0644);
+MODULE_PARM_DESC(annex,
+                 "manually set annex a/b (0=auto, 1=annex a, 2=annex b)");
+
+#define uea_wait(sc, cond, timeo) \
+({ \
+       int _r = wait_event_interruptible_timeout(sc->sync_q, \
+                       (cond) || kthread_should_stop(), timeo); \
+       if (kthread_should_stop()) \
+               _r = -ENODEV; \
+       _r; \
+})
 
 #define UPDATE_ATM_STAT(type, val) \
        do { \
@@ -519,6 +701,9 @@ static int uea_load_firmware(struct usb_device *usb, unsigned int ver)
        case EAGLE_III:
                fw_name = FW_DIR "eagleIII.fw";
                break;
+       case EAGLE_IV:
+               fw_name = FW_DIR "eagleIV.fw";
+               break;
        }
 
        ret = request_firmware_nowait(THIS_MODULE, 1, fw_name, &usb->dev, usb, uea_upload_pre_firmware);
@@ -537,7 +722,7 @@ static int uea_load_firmware(struct usb_device *usb, unsigned int ver)
 /*
  * Make sure that the DSP code provided is safe to use.
  */
-static int check_dsp(u8 *dsp, unsigned int len)
+static int check_dsp_e1(u8 *dsp, unsigned int len)
 {
        u8 pagecount, blockcount;
        u16 blocksize;
@@ -588,6 +773,51 @@ static int check_dsp(u8 *dsp, unsigned int len)
        return 0;
 }
 
+static int check_dsp_e4(u8 *dsp, int len)
+{
+       int i;
+       struct l1_code *p = (struct l1_code *) dsp;
+       unsigned int sum = p->code - dsp;
+
+       if (len < sum)
+               return 1;
+
+       if (strcmp("STRATIPHY ANEXA", p->string_header) != 0 &&
+           strcmp("STRATIPHY ANEXB", p->string_header) != 0)
+               return 1;
+
+       for (i = 0; i < E4_MAX_PAGE_NUMBER; i++) {
+               struct block_index *blockidx;
+               u8 blockno = p->page_number_to_block_index[i];
+               if (blockno >= E4_NO_SWAPPAGE_HEADERS)
+                       continue;
+
+               do {
+                       u64 l;
+
+                       if (blockno >= E4_NO_SWAPPAGE_HEADERS)
+                               return 1;
+
+                       blockidx = &p->page_header[blockno++];
+                       if ((u8 *)(blockidx + 1) - dsp  >= len)
+                               return 1;
+
+                       if (le16_to_cpu(blockidx->PageNumber) != i)
+                               return 1;
+
+                       l = E4_PAGE_BYTES(blockidx->PageSize);
+                       sum += l;
+                       l += le32_to_cpu(blockidx->PageOffset);
+                       if (l > len)
+                               return 1;
+
+               /* zero is zero regardless endianes */
+               } while (blockidx->NotLastBlock);
+       }
+
+       return (sum == len) ? 0 : 1;
+}
+
 /*
  * send data to the idma pipe
  * */
@@ -624,13 +854,18 @@ static int request_dsp(struct uea_softc *sc)
        int ret;
        char *dsp_name;
 
-       if (UEA_CHIP_VERSION(sc) == ADI930) {
-               if (IS_ISDN(sc->usb_dev))
+       if (UEA_CHIP_VERSION(sc) == EAGLE_IV) {
+               if (IS_ISDN(sc))
+                       dsp_name = FW_DIR "DSP4i.bin";
+               else
+                       dsp_name = FW_DIR "DSP4p.bin";
+       } else if (UEA_CHIP_VERSION(sc) == ADI930) {
+               if (IS_ISDN(sc))
                        dsp_name = FW_DIR "DSP9i.bin";
                else
                        dsp_name = FW_DIR "DSP9p.bin";
        } else {
-               if (IS_ISDN(sc->usb_dev))
+               if (IS_ISDN(sc))
                        dsp_name = FW_DIR "DSPei.bin";
                else
                        dsp_name = FW_DIR "DSPep.bin";
@@ -640,11 +875,16 @@ static int request_dsp(struct uea_softc *sc)
        if (ret < 0) {
                uea_err(INS_TO_USBDEV(sc),
                       "requesting firmware %s failed with error %d\n",
-                      dsp_name, ret);
+                       dsp_name, ret);
                return ret;
        }
 
-       if (check_dsp(sc->dsp_firm->data, sc->dsp_firm->size)) {
+       if (UEA_CHIP_VERSION(sc) == EAGLE_IV)
+               ret = check_dsp_e4(sc->dsp_firm->data, sc->dsp_firm->size);
+       else
+               ret = check_dsp_e1(sc->dsp_firm->data, sc->dsp_firm->size);
+
+       if (ret) {
                uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n",
                       dsp_name);
                release_firmware(sc->dsp_firm);
@@ -658,12 +898,12 @@ static int request_dsp(struct uea_softc *sc)
 /*
  * The uea_load_page() function must be called within a process context
  */
-static void uea_load_page(struct work_struct *work)
+static void uea_load_page_e1(struct work_struct *work)
 {
        struct uea_softc *sc = container_of(work, struct uea_softc, task);
        u16 pageno = sc->pageno;
        u16 ovl = sc->ovl;
-       struct block_info bi;
+       struct block_info_e1 bi;
 
        u8 *p;
        u8 pagecount, blockcount;
@@ -716,7 +956,7 @@ static void uea_load_page(struct work_struct *work)
                bi.wLast = cpu_to_le16((i == blockcount - 1) ? 1 : 0);
 
                /* send block info through the IDMA pipe */
-               if (uea_idma_write(sc, &bi, BLOCK_INFO_SIZE))
+               if (uea_idma_write(sc, &bi, E1_BLOCK_INFO_SIZE))
                        goto bad2;
 
                /* send block data through the IDMA pipe */
@@ -735,17 +975,114 @@ bad1:
        uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n", pageno);
 }
 
+static void __uea_load_page_e4(struct uea_softc *sc, u8 pageno, int boot)
+{
+       struct block_info_e4 bi;
+       struct block_index *blockidx;
+       struct l1_code *p = (struct l1_code *) sc->dsp_firm->data;
+       u8 blockno = p->page_number_to_block_index[pageno];
+
+       bi.wHdr = cpu_to_be16(UEA_BIHDR);
+       bi.bBootPage = boot;
+       bi.bPageNumber = pageno;
+       bi.wReserved = cpu_to_be16(UEA_RESERVED);
+
+       do {
+               u8 *blockoffset;
+               unsigned int blocksize;
+
+               blockidx = &p->page_header[blockno];
+               blocksize = E4_PAGE_BYTES(blockidx->PageSize);
+               blockoffset = sc->dsp_firm->data + le32_to_cpu(blockidx->PageOffset);
+
+               bi.dwSize = cpu_to_be32(blocksize);
+               bi.dwAddress = swab32(blockidx->PageAddress);
+
+               uea_dbg(INS_TO_USBDEV(sc),
+                      "sending block %u for DSP page %u size %u adress %x\n",
+                      blockno, pageno, blocksize, le32_to_cpu(blockidx->PageAddress));
+
+               /* send block info through the IDMA pipe */
+               if (uea_idma_write(sc, &bi, E4_BLOCK_INFO_SIZE))
+                       goto bad;
+
+               /* send block data through the IDMA pipe */
+               if (uea_idma_write(sc, blockoffset, blocksize))
+                       goto bad;
+
+               blockno++;
+       } while (blockidx->NotLastBlock);
+
+       return;
+
+bad:
+       uea_err(INS_TO_USBDEV(sc), "sending DSP block %u failed\n", blockno);
+       return;
+}
+
+static void uea_load_page_e4(struct work_struct *work)
+{
+       struct uea_softc *sc = container_of(work, struct uea_softc, task);
+       u8 pageno = sc->pageno;
+       int i;
+       struct block_info_e4 bi;
+       struct l1_code *p;
+
+       uea_dbg(INS_TO_USBDEV(sc), "sending DSP page %u\n", pageno);
+
+       /* reload firmware when reboot start and it's loaded already */
+       if (pageno == 0 && sc->dsp_firm) {
+               release_firmware(sc->dsp_firm);
+               sc->dsp_firm = NULL;
+       }
+
+       if (sc->dsp_firm == NULL && request_dsp(sc) < 0)
+               return;
+
+       p = (struct l1_code *) sc->dsp_firm->data;
+       if (pageno >= p->page_header[0].PageNumber) {
+               uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n", pageno);
+               return;
+       }
+
+       if (pageno != 0) {
+               __uea_load_page_e4(sc, pageno, 0);
+               return;
+       }
+
+       uea_dbg(INS_TO_USBDEV(sc),
+              "sending Main DSP page %u\n", p->page_header[0].PageNumber);
+
+       for (i = 0; i < le16_to_cpu(p->page_header[0].PageNumber); i++) {
+               if (E4_IS_BOOT_PAGE(p->page_header[i].PageSize))
+                       __uea_load_page_e4(sc, i, 1);
+       }
+
+       uea_dbg(INS_TO_USBDEV(sc),"sending start bi\n");
+
+       bi.wHdr = cpu_to_be16(UEA_BIHDR);
+       bi.bBootPage = 0;
+       bi.bPageNumber = 0xff;
+       bi.wReserved = cpu_to_be16(UEA_RESERVED);
+       bi.dwSize = cpu_to_be32(E4_PAGE_BYTES(p->page_header[0].PageSize));
+       bi.dwAddress = swab32(p->page_header[0].PageAddress);
+
+       /* send block info through the IDMA pipe */
+       if (uea_idma_write(sc, &bi, E4_BLOCK_INFO_SIZE))
+               uea_err(INS_TO_USBDEV(sc), "sending DSP start bi failed\n");
+}
+
 static inline void wake_up_cmv_ack(struct uea_softc *sc)
 {
        BUG_ON(sc->cmv_ack);
        sc->cmv_ack = 1;
-       wake_up(&sc->cmv_ack_wait);
+       wake_up(&sc->sync_q);
 }
 
 static inline int wait_cmv_ack(struct uea_softc *sc)
 {
-       int ret = wait_event_interruptible_timeout(sc->cmv_ack_wait,
-                                                  sc->cmv_ack, ACK_TIMEOUT);
+       int ret = uea_wait(sc, sc->cmv_ack , ACK_TIMEOUT);
+
        sc->cmv_ack = 0;
 
        uea_dbg(INS_TO_USBDEV(sc), "wait_event_timeout : %d ms\n",
@@ -792,33 +1129,68 @@ static int uea_request(struct uea_softc *sc,
        return 0;
 }
 
-static int uea_cmv(struct uea_softc *sc,
+static int uea_cmv_e1(struct uea_softc *sc,
                u8 function, u32 address, u16 offset, u32 data)
 {
-       struct cmv cmv;
+       struct cmv_e1 cmv;
        int ret;
 
        uea_enters(INS_TO_USBDEV(sc));
        uea_vdbg(INS_TO_USBDEV(sc), "Function : %d-%d, Address : %c%c%c%c, "
                        "offset : 0x%04x, data : 0x%08x\n",
-                       FUNCTION_TYPE(function), FUNCTION_SUBTYPE(function),
-                       GETSA1(address), GETSA2(address), GETSA3(address),
-                       GETSA4(address), offset, data);
+                       E1_FUNCTION_TYPE(function), E1_FUNCTION_SUBTYPE(function),
+                       E1_GETSA1(address), E1_GETSA2(address), E1_GETSA3(address),
+                       E1_GETSA4(address), offset, data);
+
        /* we send a request, but we expect a reply */
-       sc->cmv_function = function | 0x2;
-       sc->cmv_idx++;
-       sc->cmv_address = address;
-       sc->cmv_offset = offset;
+       sc->cmv_dsc.e1.function = function | 0x2;
+       sc->cmv_dsc.e1.idx++;
+       sc->cmv_dsc.e1.address = address;
+       sc->cmv_dsc.e1.offset = offset;
 
-       cmv.wPreamble = cpu_to_le16(PREAMBLE);
-       cmv.bDirection = HOSTTOMODEM;
+       cmv.wPreamble = cpu_to_le16(E1_PREAMBLE);
+       cmv.bDirection = E1_HOSTTOMODEM;
        cmv.bFunction = function;
-       cmv.wIndex = cpu_to_le16(sc->cmv_idx);
+       cmv.wIndex = cpu_to_le16(sc->cmv_dsc.e1.idx);
        put_unaligned(cpu_to_le32(address), &cmv.dwSymbolicAddress);
        cmv.wOffsetAddress = cpu_to_le16(offset);
        put_unaligned(cpu_to_le32(data >> 16 | data << 16), &cmv.dwData);
 
-       ret = uea_request(sc, UEA_SET_BLOCK, UEA_MPTX_START, CMV_SIZE, &cmv);
+       ret = uea_request(sc, UEA_E1_SET_BLOCK, UEA_MPTX_START, sizeof(cmv), &cmv);
+       if (ret < 0)
+               return ret;
+       ret = wait_cmv_ack(sc);
+       uea_leaves(INS_TO_USBDEV(sc));
+       return ret;
+}
+
+static int uea_cmv_e4(struct uea_softc *sc,
+               u16 function, u16 group, u16 address, u16 offset, u32 data)
+{
+       struct cmv_e4 cmv;
+       int ret;
+
+       uea_enters(INS_TO_USBDEV(sc));
+       memset(&cmv, 0, sizeof(cmv));
+
+       uea_vdbg(INS_TO_USBDEV(sc), "Function : %d-%d, Group : 0x%04x, "
+                "Address : 0x%04x, offset : 0x%04x, data : 0x%08x\n",
+                E4_FUNCTION_TYPE(function), E4_FUNCTION_SUBTYPE(function),
+                group, address, offset, data);
+
+       /* we send a request, but we expect a reply */
+       sc->cmv_dsc.e4.function = function | (0x1 << 4);
+       sc->cmv_dsc.e4.offset = offset;
+       sc->cmv_dsc.e4.address = address;
+       sc->cmv_dsc.e4.group = group;
+
+       cmv.wFunction = cpu_to_be16(function);
+       cmv.wGroup = cpu_to_be16(group);
+       cmv.wAddress = cpu_to_be16(address);
+       cmv.wOffset = cpu_to_be16(offset);
+       cmv.dwData[0] = cpu_to_be32(data);
+
+       ret = uea_request(sc, UEA_E4_SET_BLOCK, UEA_MPTX_START, sizeof(cmv), &cmv);
        if (ret < 0)
                return ret;
        ret = wait_cmv_ack(sc);
@@ -826,10 +1198,10 @@ static int uea_cmv(struct uea_softc *sc,
        return ret;
 }
 
-static inline int uea_read_cmv(struct uea_softc *sc,
+static inline int uea_read_cmv_e1(struct uea_softc *sc,
                u32 address, u16 offset, u32 *data)
 {
-       int ret = uea_cmv(sc, MAKEFUNCTION(MEMACCESS, REQUESTREAD),
+       int ret = uea_cmv_e1(sc, E1_MAKEFUNCTION(E1_MEMACCESS, E1_REQUESTREAD),
                          address, offset, 0);
        if (ret < 0)
                uea_err(INS_TO_USBDEV(sc),
@@ -840,10 +1212,27 @@ static inline int uea_read_cmv(struct uea_softc *sc,
        return ret;
 }
 
-static inline int uea_write_cmv(struct uea_softc *sc,
+static inline int uea_read_cmv_e4(struct uea_softc *sc,
+               u8 size, u16 group, u16 address, u16 offset, u32 *data)
+{
+       int ret = uea_cmv_e4(sc, E4_MAKEFUNCTION(E4_MEMACCESS, E4_REQUESTREAD, size),
+                         group, address, offset, 0);
+       if (ret < 0)
+               uea_err(INS_TO_USBDEV(sc),
+                       "reading cmv failed with error %d\n", ret);
+       else {
+               *data = sc->data;
+               /* size is in 16-bit word quantities */
+               if (size > 2)
+                       *(data + 1) = sc->data1;
+       }
+       return ret;
+}
+
+static inline int uea_write_cmv_e1(struct uea_softc *sc,
                u32 address, u16 offset, u32 data)
 {
-       int ret = uea_cmv(sc, MAKEFUNCTION(MEMACCESS, REQUESTWRITE),
+       int ret = uea_cmv_e1(sc, E1_MAKEFUNCTION(E1_MEMACCESS, E1_REQUESTWRITE),
                          address, offset, data);
        if (ret < 0)
                uea_err(INS_TO_USBDEV(sc),
@@ -852,12 +1241,48 @@ static inline int uea_write_cmv(struct uea_softc *sc,
        return ret;
 }
 
+static inline int uea_write_cmv_e4(struct uea_softc *sc,
+               u8 size, u16 group, u16 address, u16 offset, u32 data)
+{
+       int ret = uea_cmv_e4(sc, E4_MAKEFUNCTION(E4_MEMACCESS, E4_REQUESTWRITE, size),
+                         group, address, offset, data);
+       if (ret < 0)
+               uea_err(INS_TO_USBDEV(sc),
+                       "writing cmv failed with error %d\n", ret);
+
+       return ret;
+}
+
+static void uea_set_bulk_timeout(struct uea_softc *sc, u32 dsrate)
+{
+       int ret;
+       u16 timeout;
+
+       /* in bulk mode the modem have problem with high rate
+        * changing internal timing could improve things, but the
+        * value is misterious.
+        * ADI930 don't support it (-EPIPE error).
+        */
+
+       if (UEA_CHIP_VERSION(sc) == ADI930 ||
+           altsetting[sc->modem_index] > 0 ||
+           sc->stats.phy.dsrate == dsrate)
+               return;
+
+       /* Original timming (1Mbit/s) from ADI (used in windows driver) */
+       timeout = (dsrate <= 1024*1024) ? 0 : 1;
+       ret = uea_request(sc, UEA_SET_TIMEOUT, timeout, 0, NULL);
+       uea_info(INS_TO_USBDEV(sc), "setting new timeout %d%s\n",
+                timeout,  ret < 0 ? " failed" : "");
+
+}
+
 /*
  * Monitor the modem and update the stat
  * return 0 if everything is ok
  * return < 0 if an error occurs (-EAGAIN reboot needed)
  */
-static int uea_stat(struct uea_softc *sc)
+static int uea_stat_e1(struct uea_softc *sc)
 {
        u32 data;
        int ret;
@@ -865,7 +1290,7 @@ static int uea_stat(struct uea_softc *sc)
        uea_enters(INS_TO_USBDEV(sc));
        data = sc->stats.phy.state;
 
-       ret = uea_read_cmv(sc, SA_STAT, 0, &sc->stats.phy.state);
+       ret = uea_read_cmv_e1(sc, E1_SA_STAT, 0, &sc->stats.phy.state);
        if (ret < 0)
                return ret;
 
@@ -885,7 +1310,7 @@ static int uea_stat(struct uea_softc *sc)
 
        case 3:         /* fail ... */
                uea_info(INS_TO_USBDEV(sc), "modem synchronization failed"
-                               " (may be try other cmv/dsp)\n");
+                                       " (may be try other cmv/dsp)\n");
                return -EAGAIN;
 
        case 4 ... 6:   /* test state */
@@ -923,7 +1348,7 @@ static int uea_stat(struct uea_softc *sc)
        /* wake up processes waiting for synchronization */
        wake_up(&sc->sync_q);
 
-       ret = uea_read_cmv(sc, SA_DIAG, 2, &sc->stats.phy.flags);
+       ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 2, &sc->stats.phy.flags);
        if (ret < 0)
                return ret;
        sc->stats.phy.mflags |= sc->stats.phy.flags;
@@ -937,105 +1362,223 @@ static int uea_stat(struct uea_softc *sc)
                return 0;
        }
 
-       ret = uea_read_cmv(sc, SA_RATE, 0, &data);
+       ret = uea_read_cmv_e1(sc, E1_SA_RATE, 0, &data);
        if (ret < 0)
                return ret;
 
-       /* in bulk mode the modem have problem with high rate
-        * changing internal timing could improve things, but the
-        * value is misterious.
-        * ADI930 don't support it (-EPIPE error).
-        */
-       if (UEA_CHIP_VERSION(sc) != ADI930
-                   && !use_iso[sc->modem_index]
-                   && sc->stats.phy.dsrate != (data >> 16) * 32) {
-               /* Original timming from ADI(used in windows driver)
-                * 0x20ffff>>16 * 32 = 32 * 32 = 1Mbits
-                */
-               u16 timeout = (data <= 0x20ffff) ? 0 : 1;
-               ret = uea_request(sc, UEA_SET_TIMEOUT, timeout, 0, NULL);
-               uea_info(INS_TO_USBDEV(sc),
-                               "setting new timeout %d%s\n", timeout,
-                               ret < 0?" failed":"");
-       }
+       uea_set_bulk_timeout(sc, (data >> 16) * 32);
        sc->stats.phy.dsrate = (data >> 16) * 32;
        sc->stats.phy.usrate = (data & 0xffff) * 32;
        UPDATE_ATM_STAT(link_rate, sc->stats.phy.dsrate * 1000 / 424);
 
-       ret = uea_read_cmv(sc, SA_DIAG, 23, &data);
+       ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 23, &data);
        if (ret < 0)
                return ret;
        sc->stats.phy.dsattenuation = (data & 0xff) / 2;
 
-       ret = uea_read_cmv(sc, SA_DIAG, 47, &data);
+       ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 47, &data);
        if (ret < 0)
                return ret;
        sc->stats.phy.usattenuation = (data & 0xff) / 2;
 
-       ret = uea_read_cmv(sc, SA_DIAG, 25, &sc->stats.phy.dsmargin);
+       ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 25, &sc->stats.phy.dsmargin);
        if (ret < 0)
                return ret;
 
-       ret = uea_read_cmv(sc, SA_DIAG, 49, &sc->stats.phy.usmargin);
+       ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 49, &sc->stats.phy.usmargin);
        if (ret < 0)
                return ret;
 
-       ret = uea_read_cmv(sc, SA_DIAG, 51, &sc->stats.phy.rxflow);
+       ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 51, &sc->stats.phy.rxflow);
        if (ret < 0)
                return ret;
 
-       ret = uea_read_cmv(sc, SA_DIAG, 52, &sc->stats.phy.txflow);
+       ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 52, &sc->stats.phy.txflow);
        if (ret < 0)
                return ret;
 
-       ret = uea_read_cmv(sc, SA_DIAG, 54, &sc->stats.phy.dsunc);
+       ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 54, &sc->stats.phy.dsunc);
        if (ret < 0)
                return ret;
 
        /* only for atu-c */
-       ret = uea_read_cmv(sc, SA_DIAG, 58, &sc->stats.phy.usunc);
+       ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 58, &sc->stats.phy.usunc);
        if (ret < 0)
                return ret;
 
-       ret = uea_read_cmv(sc, SA_DIAG, 53, &sc->stats.phy.dscorr);
+       ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 53, &sc->stats.phy.dscorr);
        if (ret < 0)
                return ret;
 
        /* only for atu-c */
-       ret = uea_read_cmv(sc, SA_DIAG, 57, &sc->stats.phy.uscorr);
+       ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 57, &sc->stats.phy.uscorr);
        if (ret < 0)
                return ret;
 
-       ret = uea_read_cmv(sc, SA_INFO, 8, &sc->stats.phy.vidco);
+       ret = uea_read_cmv_e1(sc, E1_SA_INFO, 8, &sc->stats.phy.vidco);
        if (ret < 0)
                return ret;
 
-       ret = uea_read_cmv(sc, SA_INFO, 13, &sc->stats.phy.vidcpe);
+       ret = uea_read_cmv_e1(sc, E1_SA_INFO, 13, &sc->stats.phy.vidcpe);
        if (ret < 0)
                return ret;
 
        return 0;
 }
 
-static int request_cmvs(struct uea_softc *sc,
-                struct uea_cmvs **cmvs, const struct firmware **fw)
+static int uea_stat_e4(struct uea_softc *sc)
 {
-       int ret, size;
-       u8 *data;
+       u32 data;
+       u32 tmp_arr[2];
+       int ret;
+
+       uea_enters(INS_TO_USBDEV(sc));
+       data = sc->stats.phy.state;
+
+       /* XXX only need to be done before operationnal... */
+       ret = uea_read_cmv_e4(sc, 1, E4_SA_STAT, 0, 0, &sc->stats.phy.state);
+       if (ret < 0)
+               return ret;
+
+       switch (sc->stats.phy.state) {
+               case 0x0:       /* not yet synchronized */
+               case 0x1:
+               case 0x3:
+               case 0x4:
+                       uea_dbg(INS_TO_USBDEV(sc), "modem not yet synchronized\n");
+                       return 0;
+               case 0x5:       /* initialization */
+               case 0x6:
+               case 0x9:
+               case 0xa:
+                       uea_dbg(INS_TO_USBDEV(sc), "modem initializing\n");
+                       return 0;
+               case 0x2:       /* fail ... */
+                       uea_info(INS_TO_USBDEV(sc), "modem synchronization failed"
+                                       " (may be try other cmv/dsp)\n");
+                       return -EAGAIN;
+               case 0x7:       /* operational */
+                       break;
+               default:
+                       uea_warn(INS_TO_USBDEV(sc), "unknown state: %x\n", sc->stats.phy.state);
+                       return 0;
+       }
+
+       if (data != 7) {
+               uea_request(sc, UEA_SET_MODE, UEA_LOOPBACK_OFF, 0, NULL);
+               uea_info(INS_TO_USBDEV(sc), "modem operational\n");
+
+               /* release the dsp firmware as it is not needed until
+                * the next failure
+                */
+               if (sc->dsp_firm) {
+                       release_firmware(sc->dsp_firm);
+                       sc->dsp_firm = NULL;
+               }
+       }
+
+       /* always update it as atm layer could not be init when we switch to
+        * operational state
+        */
+       UPDATE_ATM_STAT(signal, ATM_PHY_SIG_FOUND);
+
+       /* wake up processes waiting for synchronization */
+       wake_up(&sc->sync_q);
+
+       /* TODO improve this state machine :
+        * we need some CMV info : what they do and their unit
+        * we should find the equivalent of eagle3- CMV
+        */
+       /* check flags */
+       ret = uea_read_cmv_e4(sc, 1, E4_SA_DIAG, 0, 0, &sc->stats.phy.flags);
+       if (ret < 0)
+               return ret;
+       sc->stats.phy.mflags |= sc->stats.phy.flags;
+
+       /* in case of a flags ( for example delineation LOSS (& 0x10)),
+        * we check the status again in order to detect the failure earlier
+        */
+       if (sc->stats.phy.flags) {
+               uea_dbg(INS_TO_USBDEV(sc), "Stat flag = 0x%x\n",
+                      sc->stats.phy.flags);
+               if (sc->stats.phy.flags & 1) //delineation LOSS
+                       return -EAGAIN;
+               if (sc->stats.phy.flags & 0x4000) //Reset Flag
+                       return -EAGAIN;
+               return 0;
+       }
+
+       /* rate data may be in upper or lower half of 64 bit word, strange */
+       ret = uea_read_cmv_e4(sc, 4, E4_SA_RATE, 0, 0, tmp_arr);
+       if (ret < 0)
+               return ret;
+       data = (tmp_arr[0]) ? tmp_arr[0] : tmp_arr[1];
+       sc->stats.phy.usrate = data / 1000;
+
+       ret = uea_read_cmv_e4(sc, 4, E4_SA_RATE, 1, 0, tmp_arr);
+       if (ret < 0)
+               return ret;
+       data = (tmp_arr[0]) ? tmp_arr[0] : tmp_arr[1];
+       uea_set_bulk_timeout(sc, data / 1000);
+       sc->stats.phy.dsrate = data / 1000;
+       UPDATE_ATM_STAT(link_rate, sc->stats.phy.dsrate * 1000 / 424);
+
+       ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 68, 1, &data);
+       if (ret < 0)
+               return ret;
+       sc->stats.phy.dsattenuation = data / 10;
+
+       ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 69, 1, &data);
+       if (ret < 0)
+               return ret;
+       sc->stats.phy.usattenuation = data / 10;
+
+       ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 68, 3, &data);
+       if (ret < 0)
+               return ret;
+       sc->stats.phy.dsmargin = data / 2;
+
+       ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 69, 3, &data);
+       if (ret < 0)
+               return ret;
+       sc->stats.phy.usmargin = data / 10;
+
+       return 0;
+}
+
+static void cmvs_file_name(struct uea_softc *sc, char *const cmv_name, int ver)
+{
+       char file_arr[] = "CMVxy.bin";
        char *file;
-       char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */
 
+       /* set proper name corresponding modem version and line type */
        if (cmv_file[sc->modem_index] == NULL) {
                if (UEA_CHIP_VERSION(sc) == ADI930)
-                       file = (IS_ISDN(sc->usb_dev)) ? "CMV9i.bin" : "CMV9p.bin";
+                       file_arr[3] = '9';
+               else if (UEA_CHIP_VERSION(sc) == EAGLE_IV)
+                       file_arr[3] = '4';
                else
-                       file = (IS_ISDN(sc->usb_dev)) ? "CMVei.bin" : "CMVep.bin";
+                       file_arr[3] = 'e';
+
+               file_arr[4] = IS_ISDN(sc) ? 'i' : 'p';
+               file = file_arr;
        } else
                file = cmv_file[sc->modem_index];
 
        strcpy(cmv_name, FW_DIR);
-       strlcat(cmv_name, file, sizeof(cmv_name));
+       strlcat(cmv_name, file, FIRMWARE_NAME_MAX);
+       if (ver == 2)
+               strlcat(cmv_name, ".v2", FIRMWARE_NAME_MAX);
+}
+
+static int request_cmvs_old(struct uea_softc *sc,
+                void **cmvs, const struct firmware **fw)
+{
+       int ret, size;
+       u8 *data;
+       char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */
 
+       cmvs_file_name(sc, cmv_name, 1);
        ret = request_firmware(fw, cmv_name, &sc->usb_dev->dev);
        if (ret < 0) {
                uea_err(INS_TO_USBDEV(sc),
@@ -1045,16 +1588,197 @@ static int request_cmvs(struct uea_softc *sc,
        }
 
        data = (u8 *) (*fw)->data;
-       size = *data * sizeof(struct uea_cmvs) + 1;
-       if (size != (*fw)->size) {
-               uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n",
-                      cmv_name);
-               release_firmware(*fw);
-               return -EILSEQ;
+       size = (*fw)->size;
+       if (size < 1)
+               goto err_fw_corrupted;
+
+       if (size != *data * sizeof(struct uea_cmvs_v1) + 1)
+               goto err_fw_corrupted;
+
+       *cmvs = (void *)(data + 1);
+       return *data;
+
+err_fw_corrupted:
+       uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", cmv_name);
+       release_firmware(*fw);
+       return -EILSEQ;
+}
+
+static int request_cmvs(struct uea_softc *sc,
+                void **cmvs, const struct firmware **fw, int *ver)
+{
+       int ret, size;
+       u32 crc;
+       u8 *data;
+       char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */
+
+       cmvs_file_name(sc, cmv_name, 2);
+       ret = request_firmware(fw, cmv_name, &sc->usb_dev->dev);
+       if (ret < 0) {
+               /* if caller can handle old version, try to provide it */
+               if (*ver == 1) {
+                       uea_warn(INS_TO_USBDEV(sc), "requesting firmware %s failed, "
+                               "try to get older cmvs\n", cmv_name);
+                       return request_cmvs_old(sc, cmvs, fw);
+               }
+               uea_err(INS_TO_USBDEV(sc),
+                      "requesting firmware %s failed with error %d\n",
+                      cmv_name, ret);
+               return ret;
+       }
+
+       size = (*fw)->size;
+       data = (u8 *) (*fw)->data;
+       if (size < 4 || strncmp(data, "cmv2", 4) != 0) {
+               if (*ver == 1) {
+                       uea_warn(INS_TO_USBDEV(sc), "firmware %s is corrupted, "
+                               "try to get older cmvs\n", cmv_name);
+                       release_firmware(*fw);
+                       return request_cmvs_old(sc, cmvs, fw);
+               }
+               goto err_fw_corrupted;
        }
 
-       *cmvs = (struct uea_cmvs *)(data + 1);
+       *ver = 2;
+
+       data += 4;
+       size -= 4;
+       if (size < 5)
+               goto err_fw_corrupted;
+
+       crc = FW_GET_LONG(data);
+       data += 4;
+       size -= 4;
+       if (crc32_be(0, data, size) != crc)
+               goto err_fw_corrupted;
+
+       if (size != *data * sizeof(struct uea_cmvs_v2) + 1)
+               goto err_fw_corrupted;
+
+       *cmvs = (void *) (data + 1);
        return *data;
+
+err_fw_corrupted:
+       uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", cmv_name);
+       release_firmware(*fw);
+       return -EILSEQ;
+}
+
+static int uea_send_cmvs_e1(struct uea_softc *sc)
+{
+       int i, ret, len;
+       void *cmvs_ptr;
+       const struct firmware *cmvs_fw;
+       int ver = 1; // we can handle v1 cmv firmware version;
+
+       /* Enter in R-IDLE (cmv) until instructed otherwise */
+       ret = uea_write_cmv_e1(sc, E1_SA_CNTL, 0, 1);
+       if (ret < 0)
+               return ret;
+
+       /* Dump firmware version */
+       ret = uea_read_cmv_e1(sc, E1_SA_INFO, 10, &sc->stats.phy.firmid);
+       if (ret < 0)
+               return ret;
+       uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n",
+                       sc->stats.phy.firmid);
+
+       /* get options */
+       ret = len = request_cmvs(sc, &cmvs_ptr, &cmvs_fw, &ver);
+       if (ret < 0)
+               return ret;
+
+       /* send options */
+       if (ver == 1) {
+               struct uea_cmvs_v1 *cmvs_v1 = cmvs_ptr;
+
+               uea_warn(INS_TO_USBDEV(sc), "use deprecated cmvs version, "
+                       "please update your firmware\n");
+
+               for (i = 0; i < len; i++) {
+                       ret = uea_write_cmv_e1(sc, FW_GET_LONG(&cmvs_v1[i].address),
+                                               FW_GET_WORD(&cmvs_v1[i].offset),
+                                               FW_GET_LONG(&cmvs_v1[i].data));
+                       if (ret < 0)
+                               goto out;
+               }
+       } else if (ver == 2) {
+               struct uea_cmvs_v2 *cmvs_v2 = cmvs_ptr;
+
+               for (i = 0; i < len; i++) {
+                       ret = uea_write_cmv_e1(sc, FW_GET_LONG(&cmvs_v2[i].address),
+                                               (u16) FW_GET_LONG(&cmvs_v2[i].offset),
+                                               FW_GET_LONG(&cmvs_v2[i].data));
+                       if (ret < 0)
+                               goto out;
+               }
+       } else {
+               /* This realy should not happen */
+               uea_err(INS_TO_USBDEV(sc), "bad cmvs version %d\n", ver);
+               goto out;
+       }
+
+       /* Enter in R-ACT-REQ */
+       ret = uea_write_cmv_e1(sc, E1_SA_CNTL, 0, 2);
+       uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n");
+       uea_info(INS_TO_USBDEV(sc), "modem started, waiting synchronization...\n");
+out:
+       release_firmware(cmvs_fw);
+       return ret;
+}
+
+static int uea_send_cmvs_e4(struct uea_softc *sc)
+{
+       int i, ret, len;
+       void *cmvs_ptr;
+       const struct firmware *cmvs_fw;
+       int ver = 2; // we can only handle v2 cmv firmware version;
+
+       /* Enter in R-IDLE (cmv) until instructed otherwise */
+       ret = uea_write_cmv_e4(sc, 1, E4_SA_CNTL, 0, 0, 1);
+       if (ret < 0)
+               return ret;
+
+       /* Dump firmware version */
+       /* XXX don't read the 3th byte as it is always 6 */
+       ret = uea_read_cmv_e4(sc, 2, E4_SA_INFO, 55, 0, &sc->stats.phy.firmid);
+       if (ret < 0)
+               return ret;
+       uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n",
+                       sc->stats.phy.firmid);
+
+
+       /* get options */
+       ret = len = request_cmvs(sc, &cmvs_ptr, &cmvs_fw, &ver);
+       if (ret < 0)
+               return ret;
+
+       /* send options */
+       if (ver == 2) {
+               struct uea_cmvs_v2 *cmvs_v2 = cmvs_ptr;
+
+               for (i = 0; i < len; i++) {
+                       ret = uea_write_cmv_e4(sc, 1,
+                                               FW_GET_LONG(&cmvs_v2[i].group),
+                                               FW_GET_LONG(&cmvs_v2[i].address),
+                                               FW_GET_LONG(&cmvs_v2[i].offset),
+                                               FW_GET_LONG(&cmvs_v2[i].data));
+                       if (ret < 0)
+                               goto out;
+               }
+       } else {
+               /* This realy should not happen */
+               uea_err(INS_TO_USBDEV(sc), "bad cmvs version %d\n", ver);
+               goto out;
+       }
+
+       /* Enter in R-ACT-REQ */
+       ret = uea_write_cmv_e4(sc, 1, E4_SA_CNTL, 0, 0, 2);
+       uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n");
+       uea_info(INS_TO_USBDEV(sc), "modem started, waiting synchronization...\n");
+out:
+       release_firmware(cmvs_fw);
+       return ret;
 }
 
 /* Start boot post firmware modem:
@@ -1066,9 +1790,7 @@ static int request_cmvs(struct uea_softc *sc,
 static int uea_start_reset(struct uea_softc *sc)
 {
        u16 zero = 0;   /* ;-) */
-       int i, len, ret;
-       struct uea_cmvs *cmvs;
-       const struct firmware *cmvs_fw;
+       int ret;
 
        uea_enters(INS_TO_USBDEV(sc));
        uea_info(INS_TO_USBDEV(sc), "(re)booting started\n");
@@ -1093,25 +1815,36 @@ static int uea_start_reset(struct uea_softc *sc)
        uea_request(sc, UEA_SET_MODE, UEA_START_RESET, 0, NULL);
 
        /* original driver use 200ms, but windows driver use 100ms */
-       msleep(100);
+       ret = uea_wait(sc, 0, msecs_to_jiffies(100));
+       if (ret < 0)
+               return ret;
 
        /* leave reset mode */
        uea_request(sc, UEA_SET_MODE, UEA_END_RESET, 0, NULL);
 
-       /* clear tx and rx mailboxes */
-       uea_request(sc, UEA_SET_2183_DATA, UEA_MPTX_MAILBOX, 2, &zero);
-       uea_request(sc, UEA_SET_2183_DATA, UEA_MPRX_MAILBOX, 2, &zero);
-       uea_request(sc, UEA_SET_2183_DATA, UEA_SWAP_MAILBOX, 2, &zero);
+       if (UEA_CHIP_VERSION(sc) != EAGLE_IV) {
+               /* clear tx and rx mailboxes */
+               uea_request(sc, UEA_SET_2183_DATA, UEA_MPTX_MAILBOX, 2, &zero);
+               uea_request(sc, UEA_SET_2183_DATA, UEA_MPRX_MAILBOX, 2, &zero);
+               uea_request(sc, UEA_SET_2183_DATA, UEA_SWAP_MAILBOX, 2, &zero);
+       }
+
+       ret = uea_wait(sc, 0, msecs_to_jiffies(1000));
+       if (ret < 0)
+               return ret;
+
+       if (UEA_CHIP_VERSION(sc) == EAGLE_IV)
+               sc->cmv_dsc.e4.function = E4_MAKEFUNCTION(E4_ADSLDIRECTIVE, E4_MODEMREADY, 1);
+       else
+               sc->cmv_dsc.e1.function = E1_MAKEFUNCTION(E1_ADSLDIRECTIVE, E1_MODEMREADY);
 
-       msleep(1000);
-       sc->cmv_function = MAKEFUNCTION(ADSLDIRECTIVE, MODEMREADY);
        /* demask interrupt */
        sc->booting = 0;
 
        /* start loading DSP */
        sc->pageno = 0;
        sc->ovl = 0;
-       schedule_work(&sc->task);
+       queue_work(sc->work_q, &sc->task);
 
        /* wait for modem ready CMV */
        ret = wait_cmv_ack(sc);
@@ -1120,38 +1853,10 @@ static int uea_start_reset(struct uea_softc *sc)
 
        uea_vdbg(INS_TO_USBDEV(sc), "Ready CMV received\n");
 
-       /* Enter in R-IDLE (cmv) until instructed otherwise */
-       ret = uea_write_cmv(sc, SA_CNTL, 0, 1);
-       if (ret < 0)
-               return ret;
-
-       /* Dump firmware version */
-       ret = uea_read_cmv(sc, SA_INFO, 10, &sc->stats.phy.firmid);
+       ret = sc->send_cmvs(sc);
        if (ret < 0)
                return ret;
-       uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n",
-                       sc->stats.phy.firmid);
 
-       /* get options */
-       ret = len = request_cmvs(sc, &cmvs, &cmvs_fw);
-       if (ret < 0)
-               return ret;
-
-       /* send options */
-       for (i = 0; i < len; i++) {
-               ret = uea_write_cmv(sc, FW_GET_LONG(&cmvs[i].address),
-                                       FW_GET_WORD(&cmvs[i].offset),
-                                       FW_GET_LONG(&cmvs[i].data));
-               if (ret < 0)
-                       goto out;
-       }
-       /* Enter in R-ACT-REQ */
-       ret = uea_write_cmv(sc, SA_CNTL, 0, 2);
-       uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n");
-       uea_info(INS_TO_USBDEV(sc), "Modem started, "
-               "waiting synchronization\n");
-out:
-       release_firmware(cmvs_fw);
        sc->reset = 0;
        uea_leaves(INS_TO_USBDEV(sc));
        return ret;
@@ -1174,12 +1879,10 @@ static int uea_kthread(void *data)
                if (ret < 0 || sc->reset)
                        ret = uea_start_reset(sc);
                if (!ret)
-                       ret = uea_stat(sc);
+                       ret = sc->stat(sc);
                if (ret != -EAGAIN)
-                       msleep_interruptible(1000);
-               if (try_to_freeze())
-                       uea_err(INS_TO_USBDEV(sc), "suspend/resume not supported, "
-                               "please unplug/replug your modem\n");
+                       uea_wait(sc, 0, msecs_to_jiffies(1000));
+               try_to_freeze();
        }
        uea_leaves(INS_TO_USBDEV(sc));
        return ret;
@@ -1234,7 +1937,6 @@ static int load_XILINX_firmware(struct uea_softc *sc)
        if (ret < 0)
                uea_err(sc->usb_dev, "elsa de-assert failed with error %d\n", ret);
 
-
 err1:
        release_firmware(fw_entry);
 err0:
@@ -1243,40 +1945,41 @@ err0:
 }
 
 /* The modem send us an ack. First with check if it right */
-static void uea_dispatch_cmv(struct uea_softc *sc, struct cmv* cmv)
+static void uea_dispatch_cmv_e1(struct uea_softc *sc, struct intr_pkt *intr)
 {
+       struct cmv_dsc_e1 *dsc = &sc->cmv_dsc.e1;
+       struct cmv_e1 *cmv = &intr->u.e1.s2.cmv;
+
        uea_enters(INS_TO_USBDEV(sc));
-       if (le16_to_cpu(cmv->wPreamble) != PREAMBLE)
+       if (le16_to_cpu(cmv->wPreamble) != E1_PREAMBLE)
                goto bad1;
 
-       if (cmv->bDirection != MODEMTOHOST)
+       if (cmv->bDirection != E1_MODEMTOHOST)
                goto bad1;
 
        /* FIXME : ADI930 reply wrong preambule (func = 2, sub = 2) to
         * the first MEMACESS cmv. Ignore it...
         */
-       if (cmv->bFunction != sc->cmv_function) {
+       if (cmv->bFunction != dsc->function) {
                if (UEA_CHIP_VERSION(sc) == ADI930
-                               && cmv->bFunction ==  MAKEFUNCTION(2, 2)) {
-                       cmv->wIndex = cpu_to_le16(sc->cmv_idx);
-                       put_unaligned(cpu_to_le32(sc->cmv_address), &cmv->dwSymbolicAddress);
-                       cmv->wOffsetAddress = cpu_to_le16(sc->cmv_offset);
-               }
-               else
+                               && cmv->bFunction ==  E1_MAKEFUNCTION(2, 2)) {
+                       cmv->wIndex = cpu_to_le16(dsc->idx);
+                       put_unaligned(cpu_to_le32(dsc->address), &cmv->dwSymbolicAddress);
+                       cmv->wOffsetAddress = cpu_to_le16(dsc->offset);
+               } else
                        goto bad2;
        }
 
-       if (cmv->bFunction == MAKEFUNCTION(ADSLDIRECTIVE, MODEMREADY)) {
+       if (cmv->bFunction == E1_MAKEFUNCTION(E1_ADSLDIRECTIVE, E1_MODEMREADY)) {
                wake_up_cmv_ack(sc);
                uea_leaves(INS_TO_USBDEV(sc));
                return;
        }
 
        /* in case of MEMACCESS */
-       if (le16_to_cpu(cmv->wIndex) != sc->cmv_idx ||
-           le32_to_cpu(get_unaligned(&cmv->dwSymbolicAddress)) !=
-           sc->cmv_address
-           || le16_to_cpu(cmv->wOffsetAddress) != sc->cmv_offset)
+       if (le16_to_cpu(cmv->wIndex) != dsc->idx ||
+           le32_to_cpu(get_unaligned(&cmv->dwSymbolicAddress)) != dsc->address ||
+           le16_to_cpu(cmv->wOffsetAddress) != dsc->offset)
                goto bad2;
 
        sc->data = le32_to_cpu(get_unaligned(&cmv->dwData));
@@ -1289,8 +1992,8 @@ static void uea_dispatch_cmv(struct uea_softc *sc, struct cmv* cmv)
 bad2:
        uea_err(INS_TO_USBDEV(sc), "unexpected cmv received,"
                        "Function : %d, Subfunction : %d\n",
-                       FUNCTION_TYPE(cmv->bFunction),
-                       FUNCTION_SUBTYPE(cmv->bFunction));
+                       E1_FUNCTION_TYPE(cmv->bFunction),
+                       E1_FUNCTION_SUBTYPE(cmv->bFunction));
        uea_leaves(INS_TO_USBDEV(sc));
        return;
 
@@ -1301,6 +2004,61 @@ bad1:
        uea_leaves(INS_TO_USBDEV(sc));
 }
 
+/* The modem send us an ack. First with check if it right */
+static void uea_dispatch_cmv_e4(struct uea_softc *sc, struct intr_pkt *intr)
+{
+       struct cmv_dsc_e4 *dsc = &sc->cmv_dsc.e4;
+       struct cmv_e4 *cmv = &intr->u.e4.s2.cmv;
+
+       uea_enters(INS_TO_USBDEV(sc));
+       uea_dbg(INS_TO_USBDEV(sc), "cmv %x %x %x %x %x %x\n",
+               be16_to_cpu(cmv->wGroup), be16_to_cpu(cmv->wFunction),
+               be16_to_cpu(cmv->wOffset), be16_to_cpu(cmv->wAddress),
+               be32_to_cpu(cmv->dwData[0]), be32_to_cpu(cmv->dwData[1]));
+
+       if (be16_to_cpu(cmv->wFunction) != dsc->function)
+               goto bad2;
+
+       if (be16_to_cpu(cmv->wFunction) == E4_MAKEFUNCTION(E4_ADSLDIRECTIVE, E4_MODEMREADY, 1)) {
+               wake_up_cmv_ack(sc);
+               uea_leaves(INS_TO_USBDEV(sc));
+               return;
+       }
+
+       /* in case of MEMACCESS */
+       if (be16_to_cpu(cmv->wOffset) != dsc->offset ||
+           be16_to_cpu(cmv->wGroup) != dsc->group ||
+           be16_to_cpu(cmv->wAddress) != dsc->address)
+               goto bad2;
+
+       sc->data = be32_to_cpu(cmv->dwData[0]);
+       sc->data1 = be32_to_cpu(cmv->dwData[1]);
+       wake_up_cmv_ack(sc);
+       uea_leaves(INS_TO_USBDEV(sc));
+       return;
+
+bad2:
+       uea_err(INS_TO_USBDEV(sc), "unexpected cmv received,"
+                       "Function : %d, Subfunction : %d\n",
+                       E4_FUNCTION_TYPE(cmv->wFunction),
+                       E4_FUNCTION_SUBTYPE(cmv->wFunction));
+       uea_leaves(INS_TO_USBDEV(sc));
+       return;
+}
+
+static void uea_schedule_load_page_e1(struct uea_softc *sc, struct intr_pkt *intr)
+{
+       sc->pageno = intr->e1_bSwapPageNo;
+       sc->ovl = intr->e1_bOvl >> 4 | intr->e1_bOvl << 4;
+       queue_work(sc->work_q, &sc->task);
+}
+
+static void uea_schedule_load_page_e4(struct uea_softc *sc, struct intr_pkt *intr)
+{
+       sc->pageno = intr->e4_bSwapPageNo;
+       queue_work(sc->work_q, &sc->task);
+}
+
 /*
  * interrupt handler
  */
@@ -1326,13 +2084,11 @@ static void uea_intr(struct urb *urb)
 
        switch (le16_to_cpu(intr->wInterrupt)) {
        case INT_LOADSWAPPAGE:
-               sc->pageno = intr->bSwapPageNo;
-               sc->ovl = intr->bOvl >> 4 | intr->bOvl << 4;
-               schedule_work(&sc->task);
+               sc->schedule_load_page(sc, intr);
                break;
 
        case INT_INCOMINGCMV:
-               uea_dispatch_cmv(sc, &intr->u.s2.cmv);
+               sc->dispatch_cmv(sc, intr);
                break;
 
        default:
@@ -1349,35 +2105,55 @@ resubmit:
  */
 static int uea_boot(struct uea_softc *sc)
 {
-       int ret;
+       int ret, size;
        struct intr_pkt *intr;
 
        uea_enters(INS_TO_USBDEV(sc));
 
-       INIT_WORK(&sc->task, uea_load_page);
+       if (UEA_CHIP_VERSION(sc) == EAGLE_IV) {
+               size = E4_INTR_PKT_SIZE;
+               sc->dispatch_cmv = uea_dispatch_cmv_e4;
+               sc->schedule_load_page = uea_schedule_load_page_e4;
+               sc->stat = uea_stat_e4;
+               sc->send_cmvs = uea_send_cmvs_e4;
+               INIT_WORK(&sc->task, uea_load_page_e4);
+       } else {
+               size = E1_INTR_PKT_SIZE;
+               sc->dispatch_cmv = uea_dispatch_cmv_e1;
+               sc->schedule_load_page = uea_schedule_load_page_e1;
+               sc->stat = uea_stat_e1;
+               sc->send_cmvs = uea_send_cmvs_e1;
+               INIT_WORK(&sc->task, uea_load_page_e1);
+       }
+
        init_waitqueue_head(&sc->sync_q);
-       init_waitqueue_head(&sc->cmv_ack_wait);
+
+       sc->work_q = create_workqueue("ueagle-dsp");
+       if (!sc->work_q) {
+               uea_err(INS_TO_USBDEV(sc), "cannot allocate workqueue\n");
+               uea_leaves(INS_TO_USBDEV(sc));
+               return -ENOMEM;
+       }
 
        if (UEA_CHIP_VERSION(sc) == ADI930)
                load_XILINX_firmware(sc);
 
-       intr = kmalloc(INTR_PKT_SIZE, GFP_KERNEL);
+       intr = kmalloc(size, GFP_KERNEL);
        if (!intr) {
                uea_err(INS_TO_USBDEV(sc),
                       "cannot allocate interrupt package\n");
-               uea_leaves(INS_TO_USBDEV(sc));
-               return -ENOMEM;
+               goto err0;
        }
 
        sc->urb_int = usb_alloc_urb(0, GFP_KERNEL);
        if (!sc->urb_int) {
                uea_err(INS_TO_USBDEV(sc), "cannot allocate interrupt URB\n");
-               goto err;
+               goto err1;
        }
 
        usb_fill_int_urb(sc->urb_int, sc->usb_dev,
                         usb_rcvintpipe(sc->usb_dev, UEA_INTR_PIPE),
-                        intr, INTR_PKT_SIZE, uea_intr, sc,
+                        intr, size, uea_intr, sc,
                         sc->usb_dev->actconfig->interface[0]->altsetting[0].
                         endpoint[0].desc.bInterval);
 
@@ -1385,7 +2161,7 @@ static int uea_boot(struct uea_softc *sc)
        if (ret < 0) {
                uea_err(INS_TO_USBDEV(sc),
                       "urb submition failed with error %d\n", ret);
-               goto err;
+               goto err1;
        }
 
        sc->kthread = kthread_run(uea_kthread, sc, "ueagle-atm");
@@ -1399,10 +2175,12 @@ static int uea_boot(struct uea_softc *sc)
 
 err2:
        usb_kill_urb(sc->urb_int);
-err:
+err1:
        usb_free_urb(sc->urb_int);
        sc->urb_int = NULL;
        kfree(intr);
+err0:
+       destroy_workqueue(sc->work_q);
        uea_leaves(INS_TO_USBDEV(sc));
        return -ENOMEM;
 }
@@ -1417,15 +2195,15 @@ static void uea_stop(struct uea_softc *sc)
        ret = kthread_stop(sc->kthread);
        uea_dbg(INS_TO_USBDEV(sc), "kthread finish with status %d\n", ret);
 
-       /* stop any pending boot process */
-       flush_scheduled_work();
-
        uea_request(sc, UEA_SET_MODE, UEA_LOOPBACK_ON, 0, NULL);
 
        usb_kill_urb(sc->urb_int);
        kfree(sc->urb_int->transfer_buffer);
        usb_free_urb(sc->urb_int);
 
+       /* stop any pending boot process, when no one can schedule work */
+       destroy_workqueue(sc->work_q);
+
        if (sc->dsp_firm)
                release_firmware(sc->dsp_firm);
        uea_leaves(INS_TO_USBDEV(sc));
@@ -1487,6 +2265,7 @@ static ssize_t read_human_status(struct device *dev, struct device_attribute *at
                char *buf)
 {
        int ret = -ENODEV;
+       int modem_state;
        struct uea_softc *sc;
 
        mutex_lock(&uea_mutex);
@@ -1494,7 +2273,34 @@ static ssize_t read_human_status(struct device *dev, struct device_attribute *at
        if (!sc)
                goto out;
 
-       switch (GET_STATUS(sc->stats.phy.state)) {
+       if (UEA_CHIP_VERSION(sc) == EAGLE_IV) {
+               switch (sc->stats.phy.state) {
+               case 0x0:       /* not yet synchronized */
+               case 0x1:
+               case 0x3:
+               case 0x4:
+                       modem_state = 0;
+                       break;
+               case 0x5:       /* initialization */
+               case 0x6:
+               case 0x9:
+               case 0xa:
+                       modem_state = 1;
+                       break;
+               case 0x7:       /* operational */
+                       modem_state = 2;
+                       break;
+               case 0x2:       /* fail ... */
+                       modem_state = 3;
+                       break;
+               default:        /* unknown */
+                       modem_state = 4;
+                       break;
+               }
+       } else
+               modem_state = GET_STATUS(sc->stats.phy.state);
+
+       switch (modem_state) {
        case 0:
                ret = sprintf(buf, "Modem is booting\n");
                break;
@@ -1504,9 +2310,12 @@ static ssize_t read_human_status(struct device *dev, struct device_attribute *at
        case 2:
                ret = sprintf(buf, "Modem is operational\n");
                break;
-       default:
+       case 3:
                ret = sprintf(buf, "Modem synchronization failed\n");
                break;
+       default:
+               ret = sprintf(buf, "Modem state is unknown\n");
+               break;
        }
 out:
        mutex_unlock(&uea_mutex);
@@ -1520,18 +2329,26 @@ static ssize_t read_delin(struct device *dev, struct device_attribute *attr,
 {
        int ret = -ENODEV;
        struct uea_softc *sc;
+       char *delin = "GOOD";
 
        mutex_lock(&uea_mutex);
        sc = dev_to_uea(dev);
        if (!sc)
                goto out;
 
-       if (sc->stats.phy.flags & 0x0C00)
-               ret = sprintf(buf, "ERROR\n");
-       else if (sc->stats.phy.flags & 0x0030)
-               ret = sprintf(buf, "LOSS\n");
-       else
-               ret = sprintf(buf, "GOOD\n");
+       if (UEA_CHIP_VERSION(sc) == EAGLE_IV) {
+               if (sc->stats.phy.flags & 0x4000)
+                       delin = "RESET";
+               else if (sc->stats.phy.flags & 0x0001)
+                       delin = "LOSS";
+       } else {
+               if (sc->stats.phy.flags & 0x0C00)
+                       delin = "ERROR";
+               else if (sc->stats.phy.flags & 0x0030)
+                       delin = "LOSS";
+       }
+
+       ret = sprintf(buf, "%s\n", delin);
 out:
        mutex_unlock(&uea_mutex);
        return ret;
@@ -1662,6 +2479,7 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf,
        struct usb_device *usb = interface_to_usbdev(intf);
        struct uea_softc *sc;
        int ret, ifnum = intf->altsetting->desc.bInterfaceNumber;
+       unsigned int alt;
 
        uea_enters(usb);
 
@@ -1696,22 +2514,29 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf,
        sc->modem_index = (modem_index < NB_MODEM) ? modem_index++ : 0;
        sc->driver_info = id->driver_info;
 
-       /* ADI930 don't support iso */
-       if (UEA_CHIP_VERSION(id) != ADI930 && use_iso[sc->modem_index]) {
-               int i;
-
-               /* try set fastest alternate for inbound traffic interface */
-               for (i = FASTEST_ISO_INTF; i > 0; i--)
-                       if (usb_set_interface(usb, UEA_DS_IFACE_NO, i) == 0)
-                               break;
+       /* first try to use module parameter */
+       if (annex[sc->modem_index] == 1)
+               sc->annex = ANNEXA;
+       else if (annex[sc->modem_index] == 2)
+               sc->annex = ANNEXB;
+       /* try to autodetect annex */
+       else if (sc->driver_info & AUTO_ANNEX_A)
+               sc->annex = ANNEXA;
+       else if (sc->driver_info & AUTO_ANNEX_B)
+               sc->annex = ANNEXB;
+       else
+               sc->annex = (le16_to_cpu(sc->usb_dev->descriptor.bcdDevice) & 0x80)?ANNEXB:ANNEXA;
 
-               if (i > 0) {
-                       uea_dbg(usb, "set alternate %d for 2 interface\n", i);
+       alt = altsetting[sc->modem_index];
+       /* ADI930 don't support iso */
+       if (UEA_CHIP_VERSION(id) != ADI930 && alt > 0) {
+               if (alt <= 8 && usb_set_interface(usb, UEA_DS_IFACE_NO, alt) == 0) {
+                       uea_dbg(usb, "set alternate %u for 2 interface\n", alt);
                        uea_info(usb, "using iso mode\n");
                        usbatm->flags |= UDSL_USE_ISOC | UDSL_IGNORE_EILSEQ;
                } else {
-                       uea_err(usb, "setting any alternate failed for "
-                                       "2 interface, using bulk mode\n");
+                       uea_err(usb, "setting alternate %u failed for "
+                                       "2 interface, using bulk mode\n", alt);
                }
        }
 
@@ -1757,10 +2582,11 @@ static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id)
        struct usb_device *usb = interface_to_usbdev(intf);
 
        uea_enters(usb);
-       uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) : %s %s\n",
-              le16_to_cpu(usb->descriptor.idVendor),
-              le16_to_cpu(usb->descriptor.idProduct),
-              chip_name[UEA_CHIP_VERSION(id)], IS_ISDN(usb)?"isdn":"pots");
+       uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) Rev (%#X): %s\n",
+               le16_to_cpu(usb->descriptor.idVendor),
+               le16_to_cpu(usb->descriptor.idProduct),
+               le16_to_cpu(usb->descriptor.bcdDevice),
+               chip_name[UEA_CHIP_VERSION(id)]);
 
        usb_reset_device(usb);
 
@@ -1793,24 +2619,40 @@ static void uea_disconnect(struct usb_interface *intf)
  * List of supported VID/PID
  */
 static const struct usb_device_id uea_ids[] = {
+       {USB_DEVICE(ANALOG_VID, ADI930_PID_PREFIRM),    .driver_info = ADI930 | PREFIRM},
+       {USB_DEVICE(ANALOG_VID, ADI930_PID_PSTFIRM),    .driver_info = ADI930 | PSTFIRM},
+       {USB_DEVICE(ANALOG_VID, EAGLE_I_PID_PREFIRM),   .driver_info = EAGLE_I | PREFIRM},
+       {USB_DEVICE(ANALOG_VID, EAGLE_I_PID_PSTFIRM),   .driver_info = EAGLE_I | PSTFIRM},
+       {USB_DEVICE(ANALOG_VID, EAGLE_II_PID_PREFIRM),  .driver_info = EAGLE_II | PREFIRM},
+       {USB_DEVICE(ANALOG_VID, EAGLE_II_PID_PSTFIRM),  .driver_info = EAGLE_II | PSTFIRM},
+       {USB_DEVICE(ANALOG_VID, EAGLE_IIC_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM},
+       {USB_DEVICE(ANALOG_VID, EAGLE_IIC_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM},
+       {USB_DEVICE(ANALOG_VID, EAGLE_III_PID_PREFIRM), .driver_info = EAGLE_III | PREFIRM},
+       {USB_DEVICE(ANALOG_VID, EAGLE_III_PID_PSTFIRM), .driver_info = EAGLE_III | PSTFIRM},
+       {USB_DEVICE(ANALOG_VID, EAGLE_IV_PID_PREFIRM),  .driver_info = EAGLE_IV | PREFIRM},
+       {USB_DEVICE(ANALOG_VID, EAGLE_IV_PID_PSTFIRM),  .driver_info = EAGLE_IV | PSTFIRM},
+       {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_A_PID_PREFIRM),  .driver_info = EAGLE_I | PREFIRM},
+       {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_A_PID_PSTFIRM),  .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A},
+       {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_B_PID_PREFIRM),  .driver_info = EAGLE_I | PREFIRM},
+       {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_B_PID_PSTFIRM),  .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B},
+       {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_A_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM},
+       {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_A_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM | AUTO_ANNEX_A},
+       {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_B_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM},
+       {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_B_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM | AUTO_ANNEX_B},
        {USB_DEVICE(ELSA_VID,   ELSA_PID_PREFIRM),      .driver_info = ADI930 | PREFIRM},
        {USB_DEVICE(ELSA_VID,   ELSA_PID_PSTFIRM),      .driver_info = ADI930 | PSTFIRM},
-       {USB_DEVICE(EAGLE_VID,  EAGLE_I_PID_PREFIRM),   .driver_info = EAGLE_I | PREFIRM},
-       {USB_DEVICE(EAGLE_VID,  EAGLE_I_PID_PSTFIRM),   .driver_info = EAGLE_I | PSTFIRM},
-       {USB_DEVICE(EAGLE_VID,  EAGLE_II_PID_PREFIRM),  .driver_info = EAGLE_II | PREFIRM},
-       {USB_DEVICE(EAGLE_VID,  EAGLE_II_PID_PSTFIRM),  .driver_info = EAGLE_II | PSTFIRM},
-       {USB_DEVICE(EAGLE_VID,  EAGLE_IIC_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM},
-       {USB_DEVICE(EAGLE_VID,  EAGLE_IIC_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM},
-       {USB_DEVICE(EAGLE_VID,  EAGLE_III_PID_PREFIRM), .driver_info = EAGLE_III | PREFIRM},
-       {USB_DEVICE(EAGLE_VID,  EAGLE_III_PID_PSTFIRM), .driver_info = EAGLE_III | PSTFIRM},
+       {USB_DEVICE(ELSA_VID,   ELSA_PID_A_PREFIRM),    .driver_info = ADI930 | PREFIRM},
+       {USB_DEVICE(ELSA_VID,   ELSA_PID_A_PSTFIRM),    .driver_info = ADI930 | PSTFIRM | AUTO_ANNEX_A},
+       {USB_DEVICE(ELSA_VID,   ELSA_PID_B_PREFIRM),    .driver_info = ADI930 | PREFIRM},
+       {USB_DEVICE(ELSA_VID,   ELSA_PID_B_PSTFIRM),    .driver_info = ADI930 | PSTFIRM | AUTO_ANNEX_B},
        {USB_DEVICE(USR_VID,    MILLER_A_PID_PREFIRM),  .driver_info = EAGLE_I | PREFIRM},
-       {USB_DEVICE(USR_VID,    MILLER_A_PID_PSTFIRM),  .driver_info = EAGLE_I | PSTFIRM},
+       {USB_DEVICE(USR_VID,    MILLER_A_PID_PSTFIRM),  .driver_info = EAGLE_I | PSTFIRM  | AUTO_ANNEX_A},
        {USB_DEVICE(USR_VID,    MILLER_B_PID_PREFIRM),  .driver_info = EAGLE_I | PREFIRM},
-       {USB_DEVICE(USR_VID,    MILLER_B_PID_PSTFIRM),  .driver_info = EAGLE_I | PSTFIRM},
+       {USB_DEVICE(USR_VID,    MILLER_B_PID_PSTFIRM),  .driver_info = EAGLE_I | PSTFIRM  | AUTO_ANNEX_B},
        {USB_DEVICE(USR_VID,    HEINEKEN_A_PID_PREFIRM),.driver_info = EAGLE_I | PREFIRM},
-       {USB_DEVICE(USR_VID,    HEINEKEN_A_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM},
+       {USB_DEVICE(USR_VID,    HEINEKEN_A_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A},
        {USB_DEVICE(USR_VID,    HEINEKEN_B_PID_PREFIRM),.driver_info = EAGLE_I | PREFIRM},
-       {USB_DEVICE(USR_VID,    HEINEKEN_B_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM},
+       {USB_DEVICE(USR_VID,    HEINEKEN_B_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B},
        {}
 };
 
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 5192cd9356def4c3b23fb58783ca0ab379e75f14..ad632f2d6f94534e61a5ff6241a9671f517b1eea 100644 (file)
@@ -28,6 +28,7 @@
  *     v0.12 - add hpoj.sourceforge.net ioctls (David Paschal)
  *     v0.13 - alloc space for statusbuf (<status> not on stack);
  *             use usb_buffer_alloc() for read buf & write buf;
+ *      none  - Maintained in Linux kernel after v0.13
  */
 
 /*
@@ -69,7 +70,6 @@
 #define USBLP_DEVICE_ID_SIZE   1024
 
 /* ioctls: */
-#define LPGETSTATUS            0x060b          /* same as in drivers/char/lp.c */
 #define IOCNR_GET_DEVICE_ID            1
 #define IOCNR_GET_PROTOCOLS            2
 #define IOCNR_SET_PROTOCOL             3
@@ -115,7 +115,7 @@ MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:H
 #define USBLP_MINORS           16
 #define USBLP_MINOR_BASE       0
 
-#define USBLP_WRITE_TIMEOUT    (5000)                  /* 5 seconds */
+#define USBLP_CTL_TIMEOUT      5000                    /* 5 seconds */
 
 #define USBLP_FIRST_PROTOCOL   1
 #define USBLP_LAST_PROTOCOL    3
@@ -159,10 +159,12 @@ struct usblp {
        int                     wstatus;        /* bytes written or error */
        int                     rstatus;        /* bytes ready or error */
        unsigned int            quirks;                 /* quirks flags */
+       unsigned int            flags;                  /* mode flags */
        unsigned char           used;                   /* True if open */
        unsigned char           present;                /* True if not disconnected */
        unsigned char           bidir;                  /* interface is bidirectional */
        unsigned char           sleeping;               /* interface is suspended */
+       unsigned char           no_paper;               /* Paper Out happened */
        unsigned char           *device_id_string;      /* IEEE 1284 DEVICE ID string (ptr) */
                                                        /* first 2 bytes are (big-endian) length */
 };
@@ -259,7 +261,7 @@ static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, i
 
        retval = usb_control_msg(usblp->dev,
                dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0),
-               request, type | dir | recip, value, index, buf, len, USBLP_WRITE_TIMEOUT);
+               request, type | dir | recip, value, index, buf, len, USBLP_CTL_TIMEOUT);
        dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d idx: %d len: %#x result: %d",
                request, !!dir, recip, value, index, len, retval);
        return retval < 0 ? retval : 0;
@@ -325,13 +327,11 @@ static void usblp_bulk_write(struct urb *urb)
                usblp->wstatus = status;
        else
                usblp->wstatus = urb->actual_length;
+       usblp->no_paper = 0;
        usblp->wcomplete = 1;
        wake_up(&usblp->wwait);
        spin_unlock(&usblp->lock);
 
-       /* XXX Use usb_setup_bulk_urb when available. Talk to Marcel. */
-       kfree(urb->transfer_buffer);
-       urb->transfer_buffer = NULL;    /* Not refcounted, so to be safe... */
        usb_free_urb(urb);
 }
 
@@ -346,16 +346,17 @@ static int usblp_check_status(struct usblp *usblp, int err)
        unsigned char status, newerr = 0;
        int error;
 
-       error = usblp_read_status (usblp, usblp->statusbuf);
-       if (error < 0) {
+       mutex_lock(&usblp->mut);
+       if ((error = usblp_read_status(usblp, usblp->statusbuf)) < 0) {
+               mutex_unlock(&usblp->mut);
                if (printk_ratelimit())
                        printk(KERN_ERR
                                "usblp%d: error %d reading printer status\n",
                                usblp->minor, error);
                return 0;
        }
-
        status = *usblp->statusbuf;
+       mutex_unlock(&usblp->mut);
 
        if (~status & LP_PERRORP)
                newerr = 3;
@@ -411,18 +412,10 @@ static int usblp_open(struct inode *inode, struct file *file)
                goto out;
 
        /*
-        * TODO: need to implement LP_ABORTOPEN + O_NONBLOCK as in drivers/char/lp.c ???
-        * This is #if 0-ed because we *don't* want to fail an open
-        * just because the printer is off-line.
+        * We do not implement LP_ABORTOPEN/LPABORTOPEN for two reasons:
+        *  - We do not want persistent state which close(2) does not clear
+        *  - It is not used anyway, according to CUPS people
         */
-#if 0
-       if ((retval = usblp_check_status(usblp, 0))) {
-               retval = retval > 1 ? -EIO : -ENOSPC;
-               goto out;
-       }
-#else
-       retval = 0;
-#endif
 
        retval = usb_autopm_get_interface(intf);
        if (retval < 0)
@@ -463,6 +456,8 @@ static int usblp_release(struct inode *inode, struct file *file)
 {
        struct usblp *usblp = file->private_data;
 
+       usblp->flags &= ~LP_ABORT;
+
        mutex_lock (&usblp_mutex);
        usblp->used = 0;
        if (usblp->present) {
@@ -485,8 +480,8 @@ static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait
        poll_wait(file, &usblp->rwait, wait);
        poll_wait(file, &usblp->wwait, wait);
        spin_lock_irqsave(&usblp->lock, flags);
-       ret = ((!usblp->bidir || !usblp->rcomplete) ? 0 : POLLIN  | POLLRDNORM)
-                              | (!usblp->wcomplete ? 0 : POLLOUT | POLLWRNORM);
+       ret = ((usblp->bidir && usblp->rcomplete) ? POLLIN  | POLLRDNORM : 0) |
+          ((usblp->no_paper || usblp->wcomplete) ? POLLOUT | POLLWRNORM : 0);
        spin_unlock_irqrestore(&usblp->lock, flags);
        return ret;
 }
@@ -675,6 +670,13 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                                        retval = -EFAULT;
                                break;
 
+                       case LPABORT:
+                               if (arg)
+                                       usblp->flags |= LP_ABORT;
+                               else
+                                       usblp->flags &= ~LP_ABORT;
+                               break;
+
                        default:
                                retval = -ENOTTY;
                }
@@ -684,10 +686,30 @@ done:
        return retval;
 }
 
+static struct urb *usblp_new_writeurb(struct usblp *usblp, int transfer_length)
+{
+       struct urb *urb;
+       char *writebuf;
+
+       if ((writebuf = kmalloc(transfer_length, GFP_KERNEL)) == NULL)
+               return NULL;
+       if ((urb = usb_alloc_urb(0, GFP_KERNEL)) == NULL) {
+               kfree(writebuf);
+               return NULL;
+       }
+
+       usb_fill_bulk_urb(urb, usblp->dev,
+               usb_sndbulkpipe(usblp->dev,
+                usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress),
+               writebuf, transfer_length, usblp_bulk_write, usblp);
+       urb->transfer_flags |= URB_FREE_BUFFER;
+
+       return urb;
+}
+
 static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
 {
        struct usblp *usblp = file->private_data;
-       char *writebuf;
        struct urb *writeurb;
        int rv;
        int transfer_length;
@@ -708,17 +730,11 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
                        transfer_length = USBLP_BUF_SIZE;
 
                rv = -ENOMEM;
-               if ((writebuf = kmalloc(USBLP_BUF_SIZE, GFP_KERNEL)) == NULL)
-                       goto raise_buf;
-               if ((writeurb = usb_alloc_urb(0, GFP_KERNEL)) == NULL)
+               if ((writeurb = usblp_new_writeurb(usblp, transfer_length)) == NULL)
                        goto raise_urb;
-               usb_fill_bulk_urb(writeurb, usblp->dev,
-                       usb_sndbulkpipe(usblp->dev,
-                         usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress),
-                       writebuf, transfer_length, usblp_bulk_write, usblp);
                usb_anchor_urb(writeurb, &usblp->urbs);
 
-               if (copy_from_user(writebuf,
+               if (copy_from_user(writeurb->transfer_buffer,
                                   buffer + writecount, transfer_length)) {
                        rv = -EFAULT;
                        goto raise_badaddr;
@@ -730,6 +746,7 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
                if ((rv = usb_submit_urb(writeurb, GFP_KERNEL)) < 0) {
                        usblp->wstatus = 0;
                        spin_lock_irq(&usblp->lock);
+                       usblp->no_paper = 0;
                        usblp->wcomplete = 1;
                        wake_up(&usblp->wwait);
                        spin_unlock_irq(&usblp->lock);
@@ -747,12 +764,17 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
                                /* Presume that it's going to complete well. */
                                writecount += transfer_length;
                        }
+                       if (rv == -ENOSPC) {
+                               spin_lock_irq(&usblp->lock);
+                               usblp->no_paper = 1;    /* Mark for poll(2) */
+                               spin_unlock_irq(&usblp->lock);
+                               writecount += transfer_length;
+                       }
                        /* Leave URB dangling, to be cleaned on close. */
                        goto collect_error;
                }
 
                if (usblp->wstatus < 0) {
-                       usblp_check_status(usblp, 0);
                        rv = -EIO;
                        goto collect_error;
                }
@@ -771,8 +793,6 @@ raise_badaddr:
        usb_unanchor_urb(writeurb);
        usb_free_urb(writeurb);
 raise_urb:
-       kfree(writebuf);
-raise_buf:
 raise_wait:
 collect_error:         /* Out of raise sequence */
        mutex_unlock(&usblp->wmut);
@@ -838,32 +858,36 @@ done:
  * when O_NONBLOCK is set. So, applications setting O_NONBLOCK must use
  * select(2) or poll(2) to wait for the buffer to drain before closing.
  * Alternatively, set blocking mode with fcntl and issue a zero-size write.
- *
- * Old v0.13 code had a non-functional timeout for wait_event(). Someone forgot
- * to check the return code for timeout expiration, so it had no effect.
- * Apparently, it was intended to check for error conditons, such as out
- * of paper. It is going to return when we settle things with CUPS. XXX
  */
 static int usblp_wwait(struct usblp *usblp, int nonblock)
 {
        DECLARE_WAITQUEUE(waita, current);
        int rc;
+       int err = 0;
 
        add_wait_queue(&usblp->wwait, &waita);
        for (;;) {
+               set_current_state(TASK_INTERRUPTIBLE);
                if (mutex_lock_interruptible(&usblp->mut)) {
                        rc = -EINTR;
                        break;
                }
-               set_current_state(TASK_INTERRUPTIBLE);
-               if ((rc = usblp_wtest(usblp, nonblock)) < 0) {
-                       mutex_unlock(&usblp->mut);
-                       break;
-               }
+               rc = usblp_wtest(usblp, nonblock);
                mutex_unlock(&usblp->mut);
-               if (rc == 0)
+               if (rc <= 0)
                        break;
-               schedule();
+
+               if (usblp->flags & LP_ABORT) {
+                       if (schedule_timeout(msecs_to_jiffies(5000)) == 0) {
+                               err = usblp_check_status(usblp, err);
+                               if (err == 1) { /* Paper out */
+                                       rc = -ENOSPC;
+                                       break;
+                               }
+                       }
+               } else {
+                       schedule();
+               }
        }
        set_current_state(TASK_RUNNING);
        remove_wait_queue(&usblp->wwait, &waita);
index cb69aa1e02e8762913e1d68901fb64495b68d8d0..1a8edcee7f303af3d1f3a5c6931ca5f9a7620dc0 100644 (file)
@@ -507,18 +507,30 @@ void usb_destroy_configuration(struct usb_device *dev)
 }
 
 
-// hub-only!! ... and only in reset path, or usb_new_device()
-// (used by real hubs and virtual root hubs)
+/*
+ * Get the USB config descriptors, cache and parse'em
+ *
+ * hub-only!! ... and only in reset path, or usb_new_device()
+ * (used by real hubs and virtual root hubs)
+ *
+ * NOTE: if this is a WUSB device and is not authorized, we skip the
+ *       whole thing. A non-authorized USB device has no
+ *       configurations.
+ */
 int usb_get_configuration(struct usb_device *dev)
 {
        struct device *ddev = &dev->dev;
        int ncfg = dev->descriptor.bNumConfigurations;
-       int result = -ENOMEM;
+       int result = 0;
        unsigned int cfgno, length;
        unsigned char *buffer;
        unsigned char *bigbuffer;
        struct usb_config_descriptor *desc;
 
+       cfgno = 0;
+       if (dev->authorized == 0)       /* Not really an error */
+               goto out_not_authorized;
+       result = -ENOMEM;
        if (ncfg > USB_MAXCONFIG) {
                dev_warn(ddev, "too many configurations: %d, "
                    "using maximum allowed: %d\n", ncfg, USB_MAXCONFIG);
@@ -545,14 +557,15 @@ int usb_get_configuration(struct usb_device *dev)
                goto err2;
        desc = (struct usb_config_descriptor *)buffer;
 
-       for (cfgno = 0; cfgno < ncfg; cfgno++) {
+       result = 0;
+       for (; cfgno < ncfg; cfgno++) {
                /* We grab just the first descriptor so we know how long
                 * the whole configuration is */
                result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
                    buffer, USB_DT_CONFIG_SIZE);
                if (result < 0) {
                        dev_err(ddev, "unable to read config index %d "
-                           "descriptor/%s\n", cfgno, "start");
+                           "descriptor/%s: %d\n", cfgno, "start", result);
                        dev_err(ddev, "chopping to %d config(s)\n", cfgno);
                        dev->descriptor.bNumConfigurations = cfgno;
                        break;
@@ -599,6 +612,7 @@ int usb_get_configuration(struct usb_device *dev)
 
 err:
        kfree(buffer);
+out_not_authorized:
        dev->descriptor.bNumConfigurations = cfgno;
 err2:
        if (result == -ENOMEM)
index 927a181120a9123311313abaa6c58a1f34484048..f013b4012c9a18a4199f0764d0a8218233fdb577 100644 (file)
@@ -71,6 +71,7 @@ struct async {
        void __user *userbuffer;
        void __user *userurb;
        struct urb *urb;
+       int status;
        u32 secid;
 };
 
@@ -289,10 +290,8 @@ static void snoop_urb(struct urb *urb, void __user *userurb)
        if (!usbfs_snoop)
                return;
 
-       if (urb->pipe & USB_DIR_IN)
-               dev_info(&urb->dev->dev, "direction=IN\n");
-       else
-               dev_info(&urb->dev->dev, "direction=OUT\n");
+       dev_info(&urb->dev->dev, "direction=%s\n",
+                       usb_urb_dir_in(urb) ? "IN" : "OUT");
        dev_info(&urb->dev->dev, "userurb=%p\n", userurb);
        dev_info(&urb->dev->dev, "transfer_buffer_length=%d\n",
                 urb->transfer_buffer_length);
@@ -312,9 +311,10 @@ static void async_completed(struct urb *urb)
         spin_lock(&ps->lock);
         list_move_tail(&as->asynclist, &ps->async_completed);
         spin_unlock(&ps->lock);
+       as->status = urb->status;
        if (as->signr) {
                sinfo.si_signo = as->signr;
-               sinfo.si_errno = as->urb->status;
+               sinfo.si_errno = as->status;
                sinfo.si_code = SI_ASYNCIO;
                sinfo.si_addr = as->userurb;
                kill_pid_info_as_uid(as->signr, &sinfo, as->pid, as->uid,
@@ -910,6 +910,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
        struct usb_ctrlrequest *dr = NULL;
        unsigned int u, totlen, isofrmlen;
        int ret, ifnum = -1;
+       int is_in;
 
        if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_SHORT_NOT_OK|
                           URB_NO_FSBR|URB_ZERO_PACKET))
@@ -924,16 +925,18 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                if ((ret = checkintf(ps, ifnum)))
                        return ret;
        }
-       if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0)
-               ep = ps->dev->ep_in [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
-       else
-               ep = ps->dev->ep_out [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
+       if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0) {
+               is_in = 1;
+               ep = ps->dev->ep_in[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
+       } else {
+               is_in = 0;
+               ep = ps->dev->ep_out[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
+       }
        if (!ep)
                return -ENOENT;
        switch(uurb->type) {
        case USBDEVFS_URB_TYPE_CONTROL:
-               if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-                               != USB_ENDPOINT_XFER_CONTROL)
+               if (!usb_endpoint_xfer_control(&ep->desc))
                        return -EINVAL;
                /* min 8 byte setup packet, max 8 byte setup plus an arbitrary data stage */
                if (uurb->buffer_length < 8 || uurb->buffer_length > (8 + MAX_USBFS_BUFFER_SIZE))
@@ -952,23 +955,32 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                        kfree(dr);
                        return ret;
                }
-               uurb->endpoint = (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) | (dr->bRequestType & USB_ENDPOINT_DIR_MASK);
                uurb->number_of_packets = 0;
                uurb->buffer_length = le16_to_cpup(&dr->wLength);
                uurb->buffer += 8;
-               if (!access_ok((uurb->endpoint & USB_DIR_IN) ?  VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) {
+               if ((dr->bRequestType & USB_DIR_IN) && uurb->buffer_length) {
+                       is_in = 1;
+                       uurb->endpoint |= USB_DIR_IN;
+               } else {
+                       is_in = 0;
+                       uurb->endpoint &= ~USB_DIR_IN;
+               }
+               if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
+                               uurb->buffer, uurb->buffer_length)) {
                        kfree(dr);
                        return -EFAULT;
                }
                snoop(&ps->dev->dev, "control urb: bRequest=%02x "
                        "bRrequestType=%02x wValue=%04x "
                        "wIndex=%04x wLength=%04x\n",
-                       dr->bRequest, dr->bRequestType, dr->wValue,
-                       dr->wIndex, dr->wLength);
+                       dr->bRequest, dr->bRequestType,
+                       __le16_to_cpup(&dr->wValue),
+                       __le16_to_cpup(&dr->wIndex),
+                       __le16_to_cpup(&dr->wLength));
                break;
 
        case USBDEVFS_URB_TYPE_BULK:
-               switch (ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+               switch (usb_endpoint_type(&ep->desc)) {
                case USB_ENDPOINT_XFER_CONTROL:
                case USB_ENDPOINT_XFER_ISOC:
                        return -EINVAL;
@@ -977,7 +989,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                uurb->number_of_packets = 0;
                if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
                        return -EINVAL;
-               if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length))
+               if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
+                               uurb->buffer, uurb->buffer_length))
                        return -EFAULT;
                snoop(&ps->dev->dev, "bulk urb\n");
                break;
@@ -986,8 +999,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                /* arbitrary limit */
                if (uurb->number_of_packets < 1 || uurb->number_of_packets > 128)
                        return -EINVAL;
-               if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-                               != USB_ENDPOINT_XFER_ISOC)
+               if (!usb_endpoint_xfer_isoc(&ep->desc))
                        return -EINVAL;
                isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb->number_of_packets;
                if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL)))
@@ -1014,12 +1026,12 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
 
        case USBDEVFS_URB_TYPE_INTERRUPT:
                uurb->number_of_packets = 0;
-               if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-                               != USB_ENDPOINT_XFER_INT)
+               if (!usb_endpoint_xfer_int(&ep->desc))
                        return -EINVAL;
                if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
                        return -EINVAL;
-               if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length))
+               if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
+                               uurb->buffer, uurb->buffer_length))
                        return -EFAULT;
                snoop(&ps->dev->dev, "interrupt urb\n");
                break;
@@ -1039,8 +1051,11 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                return -ENOMEM;
        }
         as->urb->dev = ps->dev;
-        as->urb->pipe = (uurb->type << 30) | __create_pipe(ps->dev, uurb->endpoint & 0xf) | (uurb->endpoint & USB_DIR_IN);
-        as->urb->transfer_flags = uurb->flags;
+        as->urb->pipe = (uurb->type << 30) |
+                       __create_pipe(ps->dev, uurb->endpoint & 0xf) |
+                       (uurb->endpoint & USB_DIR_IN);
+        as->urb->transfer_flags = uurb->flags |
+                       (is_in ? URB_DIR_IN : URB_DIR_OUT);
        as->urb->transfer_buffer_length = uurb->buffer_length;
        as->urb->setup_packet = (unsigned char*)dr;
        as->urb->start_frame = uurb->start_frame;
@@ -1070,13 +1085,13 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
        as->uid = current->uid;
        as->euid = current->euid;
        security_task_getsecid(current, &as->secid);
-       if (!(uurb->endpoint & USB_DIR_IN)) {
-               if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, as->urb->transfer_buffer_length)) {
+       if (!is_in) {
+               if (copy_from_user(as->urb->transfer_buffer, uurb->buffer,
+                               as->urb->transfer_buffer_length)) {
                        free_async(as);
                        return -EFAULT;
                }
        }
-       snoop(&as->urb->dev->dev, "submit urb\n");
        snoop_urb(as->urb, as->userurb);
         async_newpending(as);
         if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) {
@@ -1119,14 +1134,14 @@ static int processcompl(struct async *as, void __user * __user *arg)
        if (as->userbuffer)
                if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length))
                        return -EFAULT;
-       if (put_user(urb->status, &userurb->status))
+       if (put_user(as->status, &userurb->status))
                return -EFAULT;
        if (put_user(urb->actual_length, &userurb->actual_length))
                return -EFAULT;
        if (put_user(urb->error_count, &userurb->error_count))
                return -EFAULT;
 
-       if (usb_pipeisoc(urb->pipe)) {
+       if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
                for (i = 0; i < urb->number_of_packets; i++) {
                        if (put_user(urb->iso_frame_desc[i].actual_length,
                                     &userurb->iso_frame_desc[i].actual_length))
@@ -1233,14 +1248,14 @@ static int processcompl_compat(struct async *as, void __user * __user *arg)
        if (as->userbuffer)
                if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length))
                        return -EFAULT;
-       if (put_user(urb->status, &userurb->status))
+       if (put_user(as->status, &userurb->status))
                return -EFAULT;
        if (put_user(urb->actual_length, &userurb->actual_length))
                return -EFAULT;
        if (put_user(urb->error_count, &userurb->error_count))
                return -EFAULT;
 
-       if (usb_pipeisoc(urb->pipe)) {
+       if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
                for (i = 0; i < urb->number_of_packets; i++) {
                        if (put_user(urb->iso_frame_desc[i].actual_length,
                                     &userurb->iso_frame_desc[i].actual_length))
@@ -1576,6 +1591,7 @@ static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wai
 }
 
 const struct file_operations usbdev_file_operations = {
+       .owner =        THIS_MODULE,
        .llseek =       usbdev_lseek,
        .read =         usbdev_read,
        .poll =         usbdev_poll,
@@ -1625,10 +1641,7 @@ static struct notifier_block usbdev_nb = {
 };
 #endif
 
-static struct cdev usb_device_cdev = {
-       .kobj   = {.name = "usb_device", },
-       .owner  = THIS_MODULE,
-};
+static struct cdev usb_device_cdev;
 
 int __init usb_devio_init(void)
 {
index 63b1243a9139d7071a221255bdacde5e524b5996..8586817698ad8db8f9abbee331075eef2c884077 100644 (file)
@@ -202,6 +202,11 @@ static int usb_probe_interface(struct device *dev)
        intf = to_usb_interface(dev);
        udev = interface_to_usbdev(intf);
 
+       if (udev->authorized == 0) {
+               dev_err(&intf->dev, "Device is not authorized for usage\n");
+               return -ENODEV;
+       }
+
        id = usb_match_id(intf, driver->id_table);
        if (!id)
                id = usb_match_dynamic_id(intf, driver);
@@ -576,12 +581,9 @@ static int usb_device_match(struct device *dev, struct device_driver *drv)
 }
 
 #ifdef CONFIG_HOTPLUG
-static int usb_uevent(struct device *dev, char **envp, int num_envp,
-                     char *buffer, int buffer_size)
+static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        struct usb_device *usb_dev;
-       int i = 0;
-       int length = 0;
 
        if (!dev)
                return -ENODEV;
@@ -610,51 +612,39 @@ static int usb_uevent(struct device *dev, char **envp, int num_envp,
         * all the device descriptors we don't tell them about.  Or
         * act as usermode drivers.
         */
-       if (add_uevent_var(envp, num_envp, &i,
-                          buffer, buffer_size, &length,
-                          "DEVICE=/proc/bus/usb/%03d/%03d",
+       if (add_uevent_var(env, "DEVICE=/proc/bus/usb/%03d/%03d",
                           usb_dev->bus->busnum, usb_dev->devnum))
                return -ENOMEM;
 #endif
 
        /* per-device configurations are common */
-       if (add_uevent_var(envp, num_envp, &i,
-                          buffer, buffer_size, &length,
-                          "PRODUCT=%x/%x/%x",
+       if (add_uevent_var(env, "PRODUCT=%x/%x/%x",
                           le16_to_cpu(usb_dev->descriptor.idVendor),
                           le16_to_cpu(usb_dev->descriptor.idProduct),
                           le16_to_cpu(usb_dev->descriptor.bcdDevice)))
                return -ENOMEM;
 
        /* class-based driver binding models */
-       if (add_uevent_var(envp, num_envp, &i,
-                          buffer, buffer_size, &length,
-                          "TYPE=%d/%d/%d",
+       if (add_uevent_var(env, "TYPE=%d/%d/%d",
                           usb_dev->descriptor.bDeviceClass,
                           usb_dev->descriptor.bDeviceSubClass,
                           usb_dev->descriptor.bDeviceProtocol))
                return -ENOMEM;
 
-       if (add_uevent_var(envp, num_envp, &i,
-                          buffer, buffer_size, &length,
-                          "BUSNUM=%03d",
+       if (add_uevent_var(env, "BUSNUM=%03d",
                           usb_dev->bus->busnum))
                return -ENOMEM;
 
-       if (add_uevent_var(envp, num_envp, &i,
-                          buffer, buffer_size, &length,
-                          "DEVNUM=%03d",
+       if (add_uevent_var(env, "DEVNUM=%03d",
                           usb_dev->devnum))
                return -ENOMEM;
 
-       envp[i] = NULL;
        return 0;
 }
 
 #else
 
-static int usb_uevent(struct device *dev, char **envp,
-                     int num_envp, char *buffer, int buffer_size)
+static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        return -ENODEV;
 }
@@ -945,11 +935,11 @@ done:
 #ifdef CONFIG_USB_SUSPEND
 
 /* Internal routine to check whether we may autosuspend a device. */
-static int autosuspend_check(struct usb_device *udev)
+static int autosuspend_check(struct usb_device *udev, int reschedule)
 {
        int                     i;
        struct usb_interface    *intf;
-       unsigned long           suspend_time;
+       unsigned long           suspend_time, j;
 
        /* For autosuspend, fail fast if anything is in use or autosuspend
         * is disabled.  Also fail if any interfaces require remote wakeup
@@ -991,20 +981,20 @@ static int autosuspend_check(struct usb_device *udev)
        }
 
        /* If everything is okay but the device hasn't been idle for long
-        * enough, queue a delayed autosuspend request.
+        * enough, queue a delayed autosuspend request.  If the device
+        * _has_ been idle for long enough and the reschedule flag is set,
+        * likewise queue a delayed (1 second) autosuspend request.
         */
-       if (time_after(suspend_time, jiffies)) {
+       j = jiffies;
+       if (time_before(j, suspend_time))
+               reschedule = 1;
+       else
+               suspend_time = j + HZ;
+       if (reschedule) {
                if (!timer_pending(&udev->autosuspend.timer)) {
-
-                       /* The value of jiffies may change between the
-                        * time_after() comparison above and the subtraction
-                        * below.  That's okay; the system behaves sanely
-                        * when a timer is registered for the present moment
-                        * or for the past.
-                        */
                        queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
-                               round_jiffies_relative(suspend_time - jiffies));
-                       }
+                               round_jiffies_relative(suspend_time - j));
+               }
                return -EAGAIN;
        }
        return 0;
@@ -1012,7 +1002,7 @@ static int autosuspend_check(struct usb_device *udev)
 
 #else
 
-static inline int autosuspend_check(struct usb_device *udev)
+static inline int autosuspend_check(struct usb_device *udev, int reschedule)
 {
        return 0;
 }
@@ -1069,7 +1059,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
        udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
 
        if (udev->auto_pm) {
-               status = autosuspend_check(udev);
+               status = autosuspend_check(udev, 0);
                if (status < 0)
                        goto done;
        }
@@ -1083,15 +1073,8 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
                                break;
                }
        }
-       if (status == 0) {
-
-               /* Non-root devices don't need to do anything for FREEZE
-                * or PRETHAW. */
-               if (udev->parent && (msg.event == PM_EVENT_FREEZE ||
-                               msg.event == PM_EVENT_PRETHAW))
-                       goto done;
+       if (status == 0)
                status = usb_suspend_device(udev, msg);
-       }
 
        /* If the suspend failed, resume interfaces that did get suspended */
        if (status != 0) {
@@ -1102,12 +1085,24 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
 
                /* Try another autosuspend when the interfaces aren't busy */
                if (udev->auto_pm)
-                       autosuspend_check(udev);
+                       autosuspend_check(udev, status == -EBUSY);
 
-       /* If the suspend succeeded, propagate it up the tree */
+       /* If the suspend succeeded then prevent any more URB submissions,
+        * flush any outstanding URBs, and propagate the suspend up the tree.
+        */
        } else {
                cancel_delayed_work(&udev->autosuspend);
-               if (parent)
+               udev->can_submit = 0;
+               for (i = 0; i < 16; ++i) {
+                       usb_hcd_flush_endpoint(udev, udev->ep_out[i]);
+                       usb_hcd_flush_endpoint(udev, udev->ep_in[i]);
+               }
+
+               /* If this is just a FREEZE or a PRETHAW, udev might
+                * not really be suspended.  Only true suspends get
+                * propagated up the device tree.
+                */
+               if (parent && udev->state == USB_STATE_SUSPENDED)
                        usb_autosuspend_device(parent);
        }
 
@@ -1156,6 +1151,7 @@ static int usb_resume_both(struct usb_device *udev)
                status = -ENODEV;
                goto done;
        }
+       udev->can_submit = 1;
 
        /* Propagate the resume up the tree, if necessary */
        if (udev->state == USB_STATE_SUSPENDED) {
@@ -1529,9 +1525,21 @@ int usb_external_resume_device(struct usb_device *udev)
 
 static int usb_suspend(struct device *dev, pm_message_t message)
 {
+       struct usb_device       *udev;
+
        if (!is_usb_device(dev))        /* Ignore PM for interfaces */
                return 0;
-       return usb_external_suspend_device(to_usb_device(dev), message);
+       udev = to_usb_device(dev);
+
+       /* If udev is already suspended, we can skip this suspend and
+        * we should also skip the upcoming system resume. */
+       if (udev->state == USB_STATE_SUSPENDED) {
+               udev->skip_sys_resume = 1;
+               return 0;
+       }
+
+       udev->skip_sys_resume = 0;
+       return usb_external_suspend_device(udev, message);
 }
 
 static int usb_resume(struct device *dev)
@@ -1542,13 +1550,14 @@ static int usb_resume(struct device *dev)
                return 0;
        udev = to_usb_device(dev);
 
-       /* If autoresume is disabled then we also want to prevent resume
-        * during system wakeup.  However, a "persistent-device" reset-resume
-        * after power loss counts as a wakeup event.  So allow a
-        * reset-resume to occur if remote wakeup is enabled. */
-       if (udev->autoresume_disabled) {
+       /* If udev->skip_sys_resume is set then udev was already suspended
+        * when the system suspend started, so we don't want to resume
+        * udev during this system wakeup.  However a reset-resume counts
+        * as a wakeup event, so allow a reset-resume to occur if remote
+        * wakeup is enabled. */
+       if (udev->skip_sys_resume) {
                if (!(udev->reset_resume && udev->do_remote_wakeup))
-                       return -EPERM;
+                       return -EHOSTUNREACH;
        }
        return usb_external_resume_device(udev);
 }
index e0ec7045e865d93772edc95bd6ccc6e1e0176786..7dc123d6b2d0e2893f9ddac031da0d3fe71ede35 100644 (file)
@@ -267,7 +267,6 @@ static void ep_device_release(struct device *dev)
 {
        struct ep_device *ep_dev = to_ep_device(dev);
 
-       dev_dbg(dev, "%s called for %s\n", __FUNCTION__, dev->bus_id);
        endpoint_free_minor(ep_dev);
        kfree(ep_dev);
 }
index b2fc2b115256633a2f19bfd2a013ffaffedcaf28..c1cb94e9f242a7fe2806e179b05122577b03b62f 100644 (file)
@@ -40,7 +40,7 @@ static int is_activesync(struct usb_interface_descriptor *desc)
                && desc->bInterfaceProtocol == 1;
 }
 
-static int choose_configuration(struct usb_device *udev)
+int usb_choose_configuration(struct usb_device *udev)
 {
        int i;
        int num_configs;
@@ -161,17 +161,20 @@ static int generic_probe(struct usb_device *udev)
        /* Choose and set the configuration.  This registers the interfaces
         * with the driver core and lets interface drivers bind to them.
         */
-       c = choose_configuration(udev);
-       if (c >= 0) {
-               err = usb_set_configuration(udev, c);
-               if (err) {
-                       dev_err(&udev->dev, "can't set config #%d, error %d\n",
+       if (udev->authorized == 0)
+               dev_err(&udev->dev, "Device is not authorized for usage\n");
+       else {
+               c = usb_choose_configuration(udev);
+               if (c >= 0) {
+                       err = usb_set_configuration(udev, c);
+                       if (err) {
+                               dev_err(&udev->dev, "can't set config #%d, error %d\n",
                                        c, err);
-                       /* This need not be fatal.  The user can try to
-                        * set other configurations. */
+                               /* This need not be fatal.  The user can try to
+                                * set other configurations. */
+                       }
                }
        }
-
        /* USB device state == configured ... usable */
        usb_notify_add_device(udev);
 
@@ -203,8 +206,13 @@ static int generic_suspend(struct usb_device *udev, pm_message_t msg)
         */
        if (!udev->parent)
                rc = hcd_bus_suspend(udev);
+
+       /* Non-root devices don't need to do anything for FREEZE or PRETHAW */
+       else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW)
+               rc = 0;
        else
                rc = usb_port_suspend(udev);
+
        return rc;
 }
 
index 42ef1d5f6c8ad07c78416bdbaa2c3e9c60e7516e..3dd997df8505bf3b2f64c7210f71b466b7101746 100644 (file)
@@ -356,10 +356,18 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
        const u8        *bufp = tbuf;
        int             len = 0;
        int             patch_wakeup = 0;
-       unsigned long   flags;
-       int             status = 0;
+       int             status;
        int             n;
 
+       might_sleep();
+
+       spin_lock_irq(&hcd_root_hub_lock);
+       status = usb_hcd_link_urb_to_ep(hcd, urb);
+       spin_unlock_irq(&hcd_root_hub_lock);
+       if (status)
+               return status;
+       urb->hcpriv = hcd;      /* Indicate it's queued */
+
        cmd = (struct usb_ctrlrequest *) urb->setup_packet;
        typeReq  = (cmd->bRequestType << 8) | cmd->bRequest;
        wValue   = le16_to_cpu (cmd->wValue);
@@ -523,13 +531,18 @@ error:
        }
 
        /* any errors get returned through the urb completion */
-       local_irq_save (flags);
-       spin_lock (&urb->lock);
-       if (urb->status == -EINPROGRESS)
-               urb->status = status;
-       spin_unlock (&urb->lock);
-       usb_hcd_giveback_urb (hcd, urb);
-       local_irq_restore (flags);
+       spin_lock_irq(&hcd_root_hub_lock);
+       usb_hcd_unlink_urb_from_ep(hcd, urb);
+
+       /* This peculiar use of spinlocks echoes what real HC drivers do.
+        * Avoiding calls to local_irq_disable/enable makes the code
+        * RT-friendly.
+        */
+       spin_unlock(&hcd_root_hub_lock);
+       usb_hcd_giveback_urb(hcd, urb, status);
+       spin_lock(&hcd_root_hub_lock);
+
+       spin_unlock_irq(&hcd_root_hub_lock);
        return 0;
 }
 
@@ -559,31 +572,23 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
        if (length > 0) {
 
                /* try to complete the status urb */
-               local_irq_save (flags);
-               spin_lock(&hcd_root_hub_lock);
+               spin_lock_irqsave(&hcd_root_hub_lock, flags);
                urb = hcd->status_urb;
                if (urb) {
-                       spin_lock(&urb->lock);
-                       if (urb->status == -EINPROGRESS) {
-                               hcd->poll_pending = 0;
-                               hcd->status_urb = NULL;
-                               urb->status = 0;
-                               urb->hcpriv = NULL;
-                               urb->actual_length = length;
-                               memcpy(urb->transfer_buffer, buffer, length);
-                       } else          /* urb has been unlinked */
-                               length = 0;
-                       spin_unlock(&urb->lock);
-               } else
-                       length = 0;
-               spin_unlock(&hcd_root_hub_lock);
+                       hcd->poll_pending = 0;
+                       hcd->status_urb = NULL;
+                       urb->actual_length = length;
+                       memcpy(urb->transfer_buffer, buffer, length);
 
-               /* local irqs are always blocked in completions */
-               if (length > 0)
-                       usb_hcd_giveback_urb (hcd, urb);
-               else
+                       usb_hcd_unlink_urb_from_ep(hcd, urb);
+                       spin_unlock(&hcd_root_hub_lock);
+                       usb_hcd_giveback_urb(hcd, urb, 0);
+                       spin_lock(&hcd_root_hub_lock);
+               } else {
+                       length = 0;
                        hcd->poll_pending = 1;
-               local_irq_restore (flags);
+               }
+               spin_unlock_irqrestore(&hcd_root_hub_lock, flags);
        }
 
        /* The USB 2.0 spec says 256 ms.  This is close enough and won't
@@ -611,33 +616,35 @@ static int rh_queue_status (struct usb_hcd *hcd, struct urb *urb)
        int             len = 1 + (urb->dev->maxchild / 8);
 
        spin_lock_irqsave (&hcd_root_hub_lock, flags);
-       if (urb->status != -EINPROGRESS)        /* already unlinked */
-               retval = urb->status;
-       else if (hcd->status_urb || urb->transfer_buffer_length < len) {
+       if (hcd->status_urb || urb->transfer_buffer_length < len) {
                dev_dbg (hcd->self.controller, "not queuing rh status urb\n");
                retval = -EINVAL;
-       } else {
-               hcd->status_urb = urb;
-               urb->hcpriv = hcd;      /* indicate it's queued */
+               goto done;
+       }
 
-               if (!hcd->uses_new_polling)
-                       mod_timer (&hcd->rh_timer,
-                               (jiffies/(HZ/4) + 1) * (HZ/4));
+       retval = usb_hcd_link_urb_to_ep(hcd, urb);
+       if (retval)
+               goto done;
 
-               /* If a status change has already occurred, report it ASAP */
-               else if (hcd->poll_pending)
-                       mod_timer (&hcd->rh_timer, jiffies);
-               retval = 0;
-       }
+       hcd->status_urb = urb;
+       urb->hcpriv = hcd;      /* indicate it's queued */
+       if (!hcd->uses_new_polling)
+               mod_timer(&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4));
+
+       /* If a status change has already occurred, report it ASAP */
+       else if (hcd->poll_pending)
+               mod_timer(&hcd->rh_timer, jiffies);
+       retval = 0;
+ done:
        spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
        return retval;
 }
 
 static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)
 {
-       if (usb_pipeint (urb->pipe))
+       if (usb_endpoint_xfer_int(&urb->ep->desc))
                return rh_queue_status (hcd, urb);
-       if (usb_pipecontrol (urb->pipe))
+       if (usb_endpoint_xfer_control(&urb->ep->desc))
                return rh_call_control (hcd, urb);
        return -EINVAL;
 }
@@ -647,32 +654,96 @@ static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)
 /* Unlinks of root-hub control URBs are legal, but they don't do anything
  * since these URBs always execute synchronously.
  */
-static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+static int usb_rh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
        unsigned long   flags;
+       int             rc;
+
+       spin_lock_irqsave(&hcd_root_hub_lock, flags);
+       rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+       if (rc)
+               goto done;
 
-       if (usb_pipeendpoint(urb->pipe) == 0) { /* Control URB */
+       if (usb_endpoint_num(&urb->ep->desc) == 0) {    /* Control URB */
                ;       /* Do nothing */
 
        } else {                                /* Status URB */
                if (!hcd->uses_new_polling)
                        del_timer (&hcd->rh_timer);
-               local_irq_save (flags);
-               spin_lock (&hcd_root_hub_lock);
                if (urb == hcd->status_urb) {
                        hcd->status_urb = NULL;
-                       urb->hcpriv = NULL;
-               } else
-                       urb = NULL;             /* wasn't fully queued */
-               spin_unlock (&hcd_root_hub_lock);
-               if (urb)
-                       usb_hcd_giveback_urb (hcd, urb);
-               local_irq_restore (flags);
+                       usb_hcd_unlink_urb_from_ep(hcd, urb);
+
+                       spin_unlock(&hcd_root_hub_lock);
+                       usb_hcd_giveback_urb(hcd, urb, status);
+                       spin_lock(&hcd_root_hub_lock);
+               }
        }
+ done:
+       spin_unlock_irqrestore(&hcd_root_hub_lock, flags);
+       return rc;
+}
 
-       return 0;
+
+
+/*
+ * Show & store the current value of authorized_default
+ */
+static ssize_t usb_host_authorized_default_show(struct device *dev,
+                                               struct device_attribute *attr,
+                                               char *buf)
+{
+       struct usb_device *rh_usb_dev = to_usb_device(dev);
+       struct usb_bus *usb_bus = rh_usb_dev->bus;
+       struct usb_hcd *usb_hcd;
+
+       if (usb_bus == NULL)    /* FIXME: not sure if this case is possible */
+               return -ENODEV;
+       usb_hcd = bus_to_hcd(usb_bus);
+       return snprintf(buf, PAGE_SIZE, "%u\n", usb_hcd->authorized_default);
+}
+
+static ssize_t usb_host_authorized_default_store(struct device *dev,
+                                                struct device_attribute *attr,
+                                                const char *buf, size_t size)
+{
+       ssize_t result;
+       unsigned val;
+       struct usb_device *rh_usb_dev = to_usb_device(dev);
+       struct usb_bus *usb_bus = rh_usb_dev->bus;
+       struct usb_hcd *usb_hcd;
+
+       if (usb_bus == NULL)    /* FIXME: not sure if this case is possible */
+               return -ENODEV;
+       usb_hcd = bus_to_hcd(usb_bus);
+       result = sscanf(buf, "%u\n", &val);
+       if (result == 1) {
+               usb_hcd->authorized_default = val? 1 : 0;
+               result = size;
+       }
+       else
+               result = -EINVAL;
+       return result;
 }
 
+static DEVICE_ATTR(authorized_default, 0644,
+           usb_host_authorized_default_show,
+           usb_host_authorized_default_store);
+
+
+/* Group all the USB bus attributes */
+static struct attribute *usb_bus_attrs[] = {
+               &dev_attr_authorized_default.attr,
+               NULL,
+};
+
+static struct attribute_group usb_bus_attr_group = {
+       .name = NULL,   /* we want them in the same directory */
+       .attrs = usb_bus_attrs,
+};
+
+
+
 /*-------------------------------------------------------------------------*/
 
 static struct class *usb_host_class;
@@ -726,27 +797,23 @@ static void usb_bus_init (struct usb_bus *bus)
  */
 static int usb_register_bus(struct usb_bus *bus)
 {
+       int result = -E2BIG;
        int busnum;
 
        mutex_lock(&usb_bus_list_lock);
        busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1);
-       if (busnum < USB_MAXBUS) {
-               set_bit (busnum, busmap.busmap);
-               bus->busnum = busnum;
-       } else {
+       if (busnum >= USB_MAXBUS) {
                printk (KERN_ERR "%s: too many buses\n", usbcore_name);
-               mutex_unlock(&usb_bus_list_lock);
-               return -E2BIG;
+               goto error_find_busnum;
        }
-
+       set_bit (busnum, busmap.busmap);
+       bus->busnum = busnum;
        bus->class_dev = class_device_create(usb_host_class, NULL, MKDEV(0,0),
-                                            bus->controller, "usb_host%d", busnum);
-       if (IS_ERR(bus->class_dev)) {
-               clear_bit(busnum, busmap.busmap);
-               mutex_unlock(&usb_bus_list_lock);
-               return PTR_ERR(bus->class_dev);
-       }
-
+                                            bus->controller, "usb_host%d",
+                                            busnum);
+       result = PTR_ERR(bus->class_dev);
+       if (IS_ERR(bus->class_dev))
+               goto error_create_class_dev;
        class_set_devdata(bus->class_dev, bus);
 
        /* Add it to the local list of buses */
@@ -755,8 +822,15 @@ static int usb_register_bus(struct usb_bus *bus)
 
        usb_notify_add_bus(bus);
 
-       dev_info (bus->controller, "new USB bus registered, assigned bus number %d\n", bus->busnum);
+       dev_info (bus->controller, "new USB bus registered, assigned bus "
+                 "number %d\n", bus->busnum);
        return 0;
+
+error_create_class_dev:
+       clear_bit(busnum, busmap.busmap);
+error_find_busnum:
+       mutex_unlock(&usb_bus_list_lock);
+       return result;
 }
 
 /**
@@ -908,103 +982,145 @@ EXPORT_SYMBOL (usb_calc_bus_time);
 
 /*-------------------------------------------------------------------------*/
 
-static void urb_unlink(struct usb_hcd *hcd, struct urb *urb)
+/**
+ * usb_hcd_link_urb_to_ep - add an URB to its endpoint queue
+ * @hcd: host controller to which @urb was submitted
+ * @urb: URB being submitted
+ *
+ * Host controller drivers should call this routine in their enqueue()
+ * method.  The HCD's private spinlock must be held and interrupts must
+ * be disabled.  The actions carried out here are required for URB
+ * submission, as well as for endpoint shutdown and for usb_kill_urb.
+ *
+ * Returns 0 for no error, otherwise a negative error code (in which case
+ * the enqueue() method must fail).  If no error occurs but enqueue() fails
+ * anyway, it must call usb_hcd_unlink_urb_from_ep() before releasing
+ * the private spinlock and returning.
+ */
+int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb)
 {
-       unsigned long           flags;
+       int             rc = 0;
 
-       /* clear all state linking urb to this dev (and hcd) */
-       spin_lock_irqsave(&hcd_urb_list_lock, flags);
-       list_del_init (&urb->urb_list);
-       spin_unlock_irqrestore(&hcd_urb_list_lock, flags);
+       spin_lock(&hcd_urb_list_lock);
 
-       if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
-               if (usb_pipecontrol (urb->pipe)
-                       && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
-                       dma_unmap_single (hcd->self.controller, urb->setup_dma,
-                                       sizeof (struct usb_ctrlrequest),
-                                       DMA_TO_DEVICE);
-               if (urb->transfer_buffer_length != 0
-                       && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
-                       dma_unmap_single (hcd->self.controller,
-                                       urb->transfer_dma,
-                                       urb->transfer_buffer_length,
-                                       usb_pipein (urb->pipe)
-                                           ? DMA_FROM_DEVICE
-                                           : DMA_TO_DEVICE);
+       /* Check that the URB isn't being killed */
+       if (unlikely(urb->reject)) {
+               rc = -EPERM;
+               goto done;
        }
-}
-
-/* may be called in any context with a valid urb->dev usecount
- * caller surrenders "ownership" of urb
- * expects usb_submit_urb() to have sanity checked and conditioned all
- * inputs in the urb
- */
-int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
-{
-       int                     status;
-       struct usb_hcd          *hcd = bus_to_hcd(urb->dev->bus);
-       struct usb_host_endpoint *ep;
-       unsigned long           flags;
 
-       if (!hcd)
-               return -ENODEV;
+       if (unlikely(!urb->ep->enabled)) {
+               rc = -ENOENT;
+               goto done;
+       }
 
-       usbmon_urb_submit(&hcd->self, urb);
+       if (unlikely(!urb->dev->can_submit)) {
+               rc = -EHOSTUNREACH;
+               goto done;
+       }
 
        /*
-        * Atomically queue the urb,  first to our records, then to the HCD.
-        * Access to urb->status is controlled by urb->lock ... changes on
-        * i/o completion (normal or fault) or unlinking.
+        * Check the host controller's state and add the URB to the
+        * endpoint's queue.
         */
-
-       // FIXME:  verify that quiescing hc works right (RH cleans up)
-
-       spin_lock_irqsave(&hcd_urb_list_lock, flags);
-       ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out)
-                       [usb_pipeendpoint(urb->pipe)];
-       if (unlikely (!ep))
-               status = -ENOENT;
-       else if (unlikely (urb->reject))
-               status = -EPERM;
-       else switch (hcd->state) {
+       switch (hcd->state) {
        case HC_STATE_RUNNING:
        case HC_STATE_RESUMING:
-               list_add_tail (&urb->urb_list, &ep->urb_list);
-               status = 0;
+               urb->unlinked = 0;
+               list_add_tail(&urb->urb_list, &urb->ep->urb_list);
                break;
        default:
-               status = -ESHUTDOWN;
-               break;
+               rc = -ESHUTDOWN;
+               goto done;
        }
-       spin_unlock_irqrestore(&hcd_urb_list_lock, flags);
-       if (status) {
-               INIT_LIST_HEAD (&urb->urb_list);
-               usbmon_urb_submit_error(&hcd->self, urb, status);
-               return status;
+ done:
+       spin_unlock(&hcd_urb_list_lock);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(usb_hcd_link_urb_to_ep);
+
+/**
+ * usb_hcd_check_unlink_urb - check whether an URB may be unlinked
+ * @hcd: host controller to which @urb was submitted
+ * @urb: URB being checked for unlinkability
+ * @status: error code to store in @urb if the unlink succeeds
+ *
+ * Host controller drivers should call this routine in their dequeue()
+ * method.  The HCD's private spinlock must be held and interrupts must
+ * be disabled.  The actions carried out here are required for making
+ * sure than an unlink is valid.
+ *
+ * Returns 0 for no error, otherwise a negative error code (in which case
+ * the dequeue() method must fail).  The possible error codes are:
+ *
+ *     -EIDRM: @urb was not submitted or has already completed.
+ *             The completion function may not have been called yet.
+ *
+ *     -EBUSY: @urb has already been unlinked.
+ */
+int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
+               int status)
+{
+       struct list_head        *tmp;
+
+       /* insist the urb is still queued */
+       list_for_each(tmp, &urb->ep->urb_list) {
+               if (tmp == &urb->urb_list)
+                       break;
        }
+       if (tmp != &urb->urb_list)
+               return -EIDRM;
 
-       /* increment urb's reference count as part of giving it to the HCD
-        * (which now controls it).  HCD guarantees that it either returns
-        * an error or calls giveback(), but not both.
+       /* Any status except -EINPROGRESS means something already started to
+        * unlink this URB from the hardware.  So there's no more work to do.
         */
-       urb = usb_get_urb (urb);
-       atomic_inc (&urb->use_count);
-
-       if (is_root_hub(urb->dev)) {
-               /* NOTE:  requirement on hub callers (usbfs and the hub
-                * driver, for now) that URBs' urb->transfer_buffer be
-                * valid and usb_buffer_{sync,unmap}() not be needed, since
-                * they could clobber root hub response data.
-                */
-               status = rh_urb_enqueue (hcd, urb);
-               goto done;
+       if (urb->unlinked)
+               return -EBUSY;
+       urb->unlinked = status;
+
+       /* IRQ setup can easily be broken so that USB controllers
+        * never get completion IRQs ... maybe even the ones we need to
+        * finish unlinking the initial failed usb_set_address()
+        * or device descriptor fetch.
+        */
+       if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) &&
+                       !is_root_hub(urb->dev)) {
+               dev_warn(hcd->self.controller, "Unlink after no-IRQ?  "
+                       "Controller is probably using the wrong IRQ.\n");
+               set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
        }
 
-       /* lower level hcd code should use *_dma exclusively,
+       return 0;
+}
+EXPORT_SYMBOL_GPL(usb_hcd_check_unlink_urb);
+
+/**
+ * usb_hcd_unlink_urb_from_ep - remove an URB from its endpoint queue
+ * @hcd: host controller to which @urb was submitted
+ * @urb: URB being unlinked
+ *
+ * Host controller drivers should call this routine before calling
+ * usb_hcd_giveback_urb().  The HCD's private spinlock must be held and
+ * interrupts must be disabled.  The actions carried out here are required
+ * for URB completion.
+ */
+void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb)
+{
+       /* clear all state linking urb to this dev (and hcd) */
+       spin_lock(&hcd_urb_list_lock);
+       list_del_init(&urb->urb_list);
+       spin_unlock(&hcd_urb_list_lock);
+}
+EXPORT_SYMBOL_GPL(usb_hcd_unlink_urb_from_ep);
+
+static void map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
+{
+       /* Map the URB's buffers for DMA access.
+        * Lower level HCD code should use *_dma exclusively,
         * unless it uses pio or talks to another transport.
         */
-       if (hcd->self.uses_dma) {
-               if (usb_pipecontrol (urb->pipe)
+       if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
+               if (usb_endpoint_xfer_control(&urb->ep->desc)
                        && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
                        urb->setup_dma = dma_map_single (
                                        hcd->self.controller,
@@ -1017,20 +1133,75 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
                                        hcd->self.controller,
                                        urb->transfer_buffer,
                                        urb->transfer_buffer_length,
-                                       usb_pipein (urb->pipe)
+                                       usb_urb_dir_in(urb)
                                            ? DMA_FROM_DEVICE
                                            : DMA_TO_DEVICE);
        }
+}
 
-       status = hcd->driver->urb_enqueue (hcd, ep, urb, mem_flags);
-done:
-       if (unlikely (status)) {
-               urb_unlink(hcd, urb);
-               atomic_dec (&urb->use_count);
-               if (urb->reject)
-                       wake_up (&usb_kill_urb_queue);
+static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
+{
+       if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
+               if (usb_endpoint_xfer_control(&urb->ep->desc)
+                       && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
+                       dma_unmap_single(hcd->self.controller, urb->setup_dma,
+                                       sizeof(struct usb_ctrlrequest),
+                                       DMA_TO_DEVICE);
+               if (urb->transfer_buffer_length != 0
+                       && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
+                       dma_unmap_single(hcd->self.controller,
+                                       urb->transfer_dma,
+                                       urb->transfer_buffer_length,
+                                       usb_urb_dir_in(urb)
+                                           ? DMA_FROM_DEVICE
+                                           : DMA_TO_DEVICE);
+       }
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* may be called in any context with a valid urb->dev usecount
+ * caller surrenders "ownership" of urb
+ * expects usb_submit_urb() to have sanity checked and conditioned all
+ * inputs in the urb
+ */
+int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
+{
+       int                     status;
+       struct usb_hcd          *hcd = bus_to_hcd(urb->dev->bus);
+
+       /* increment urb's reference count as part of giving it to the HCD
+        * (which will control it).  HCD guarantees that it either returns
+        * an error or calls giveback(), but not both.
+        */
+       usb_get_urb(urb);
+       atomic_inc(&urb->use_count);
+       atomic_inc(&urb->dev->urbnum);
+       usbmon_urb_submit(&hcd->self, urb);
+
+       /* NOTE requirements on root-hub callers (usbfs and the hub
+        * driver, for now):  URBs' urb->transfer_buffer must be
+        * valid and usb_buffer_{sync,unmap}() not be needed, since
+        * they could clobber root hub response data.  Also, control
+        * URBs must be submitted in process context with interrupts
+        * enabled.
+        */
+       map_urb_for_dma(hcd, urb);
+       if (is_root_hub(urb->dev))
+               status = rh_urb_enqueue(hcd, urb);
+       else
+               status = hcd->driver->urb_enqueue(hcd, urb, mem_flags);
+
+       if (unlikely(status)) {
                usbmon_urb_submit_error(&hcd->self, urb, status);
-               usb_put_urb (urb);
+               unmap_urb_for_dma(hcd, urb);
+               urb->hcpriv = NULL;
+               INIT_LIST_HEAD(&urb->urb_list);
+               atomic_dec(&urb->use_count);
+               atomic_dec(&urb->dev->urbnum);
+               if (urb->reject)
+                       wake_up(&usb_kill_urb_queue);
+               usb_put_urb(urb);
        }
        return status;
 }
@@ -1042,24 +1213,19 @@ done:
  * soon as practical.  we've already set up the urb's return status,
  * but we can't know if the callback completed already.
  */
-static int
-unlink1 (struct usb_hcd *hcd, struct urb *urb)
+static int unlink1(struct usb_hcd *hcd, struct urb *urb, int status)
 {
        int             value;
 
        if (is_root_hub(urb->dev))
-               value = usb_rh_urb_dequeue (hcd, urb);
+               value = usb_rh_urb_dequeue(hcd, urb, status);
        else {
 
                /* The only reason an HCD might fail this call is if
                 * it has not yet fully queued the urb to begin with.
                 * Such failures should be harmless. */
-               value = hcd->driver->urb_dequeue (hcd, urb);
+               value = hcd->driver->urb_dequeue(hcd, urb, status);
        }
-
-       if (value != 0)
-               dev_dbg (hcd->self.controller, "dequeue %p --> %d\n",
-                               urb, value);
        return value;
 }
 
@@ -1071,88 +1237,17 @@ unlink1 (struct usb_hcd *hcd, struct urb *urb)
  */
 int usb_hcd_unlink_urb (struct urb *urb, int status)
 {
-       struct usb_host_endpoint        *ep;
-       struct usb_hcd                  *hcd = NULL;
-       struct device                   *sys = NULL;
-       unsigned long                   flags;
-       struct list_head                *tmp;
-       int                             retval;
-
-       if (!urb)
-               return -EINVAL;
-       if (!urb->dev || !urb->dev->bus)
-               return -ENODEV;
-       ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out)
-                       [usb_pipeendpoint(urb->pipe)];
-       if (!ep)
-               return -ENODEV;
-
-       /*
-        * we contend for urb->status with the hcd core,
-        * which changes it while returning the urb.
-        *
-        * Caller guaranteed that the urb pointer hasn't been freed, and
-        * that it was submitted.  But as a rule it can't know whether or
-        * not it's already been unlinked ... so we respect the reversed
-        * lock sequence needed for the usb_hcd_giveback_urb() code paths
-        * (urb lock, then hcd_urb_list_lock) in case some other CPU is now
-        * unlinking it.
-        */
-       spin_lock_irqsave (&urb->lock, flags);
-       spin_lock(&hcd_urb_list_lock);
+       struct usb_hcd          *hcd;
+       int                     retval;
 
-       sys = &urb->dev->dev;
        hcd = bus_to_hcd(urb->dev->bus);
-       if (hcd == NULL) {
-               retval = -ENODEV;
-               goto done;
-       }
+       retval = unlink1(hcd, urb, status);
 
-       /* insist the urb is still queued */
-       list_for_each(tmp, &ep->urb_list) {
-               if (tmp == &urb->urb_list)
-                       break;
-       }
-       if (tmp != &urb->urb_list) {
-               retval = -EIDRM;
-               goto done;
-       }
-
-       /* Any status except -EINPROGRESS means something already started to
-        * unlink this URB from the hardware.  So there's no more work to do.
-        */
-       if (urb->status != -EINPROGRESS) {
-               retval = -EBUSY;
-               goto done;
-       }
-
-       /* IRQ setup can easily be broken so that USB controllers
-        * never get completion IRQs ... maybe even the ones we need to
-        * finish unlinking the initial failed usb_set_address()
-        * or device descriptor fetch.
-        */
-       if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) &&
-                       !is_root_hub(urb->dev)) {
-               dev_warn (hcd->self.controller, "Unlink after no-IRQ?  "
-                       "Controller is probably using the wrong IRQ.\n");
-               set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
-       }
-
-       urb->status = status;
-
-       spin_unlock(&hcd_urb_list_lock);
-       spin_unlock_irqrestore (&urb->lock, flags);
-
-       retval = unlink1 (hcd, urb);
        if (retval == 0)
                retval = -EINPROGRESS;
-       return retval;
-
-done:
-       spin_unlock(&hcd_urb_list_lock);
-       spin_unlock_irqrestore (&urb->lock, flags);
-       if (retval != -EIDRM && sys && sys->driver)
-               dev_dbg (sys, "hcd_unlink_urb %p fail %d\n", urb, retval);
+       else if (retval != -EIDRM && retval != -EBUSY)
+               dev_dbg(&urb->dev->dev, "hcd_unlink_urb %p fail %d\n",
+                               urb, retval);
        return retval;
 }
 
@@ -1162,6 +1257,7 @@ done:
  * usb_hcd_giveback_urb - return URB from HCD to device driver
  * @hcd: host controller returning the URB
  * @urb: urb being returned to the USB device driver.
+ * @status: completion status code for the URB.
  * Context: in_interrupt()
  *
  * This hands the URB from HCD to its USB device driver, using its
@@ -1169,14 +1265,27 @@ done:
  * (and is done using urb->hcpriv).  It also released all HCD locks;
  * the device driver won't cause problems if it frees, modifies,
  * or resubmits this URB.
+ *
+ * If @urb was unlinked, the value of @status will be overridden by
+ * @urb->unlinked.  Erroneous short transfers are detected in case
+ * the HCD hasn't checked for them.
  */
-void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
+void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status)
 {
-       urb_unlink(hcd, urb);
-       usbmon_urb_complete (&hcd->self, urb);
+       urb->hcpriv = NULL;
+       if (unlikely(urb->unlinked))
+               status = urb->unlinked;
+       else if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
+                       urb->actual_length < urb->transfer_buffer_length &&
+                       !status))
+               status = -EREMOTEIO;
+
+       unmap_urb_for_dma(hcd, urb);
+       usbmon_urb_complete(&hcd->self, urb, status);
        usb_unanchor_urb(urb);
 
        /* pass ownership to the completion handler */
+       urb->status = status;
        urb->complete (urb);
        atomic_dec (&urb->use_count);
        if (unlikely (urb->reject))
@@ -1187,78 +1296,61 @@ EXPORT_SYMBOL (usb_hcd_giveback_urb);
 
 /*-------------------------------------------------------------------------*/
 
-/* disables the endpoint: cancels any pending urbs, then synchronizes with
- * the hcd to make sure all endpoint state is gone from hardware, and then
- * waits until the endpoint's queue is completely drained. use for
- * set_configuration, set_interface, driver removal, physical disconnect.
- *
- * example:  a qh stored in ep->hcpriv, holding state related to endpoint
- * type, maxpacket size, toggle, halt status, and scheduling.
+/* Cancel all URBs pending on this endpoint and wait for the endpoint's
+ * queue to drain completely.  The caller must first insure that no more
+ * URBs can be submitted for this endpoint.
  */
-void usb_hcd_endpoint_disable (struct usb_device *udev,
+void usb_hcd_flush_endpoint(struct usb_device *udev,
                struct usb_host_endpoint *ep)
 {
        struct usb_hcd          *hcd;
        struct urb              *urb;
 
+       if (!ep)
+               return;
+       might_sleep();
        hcd = bus_to_hcd(udev->bus);
-       local_irq_disable ();
 
-       /* ep is already gone from udev->ep_{in,out}[]; no more submits */
+       /* No more submits can occur */
 rescan:
-       spin_lock(&hcd_urb_list_lock);
+       spin_lock_irq(&hcd_urb_list_lock);
        list_for_each_entry (urb, &ep->urb_list, urb_list) {
-               int     tmp;
+               int     is_in;
 
-               /* the urb may already have been unlinked */
-               if (urb->status != -EINPROGRESS)
+               if (urb->unlinked)
                        continue;
                usb_get_urb (urb);
+               is_in = usb_urb_dir_in(urb);
                spin_unlock(&hcd_urb_list_lock);
 
-               spin_lock (&urb->lock);
-               tmp = urb->status;
-               if (tmp == -EINPROGRESS)
-                       urb->status = -ESHUTDOWN;
-               spin_unlock (&urb->lock);
-
-               /* kick hcd unless it's already returning this */
-               if (tmp == -EINPROGRESS) {
-                       tmp = urb->pipe;
-                       unlink1 (hcd, urb);
-                       dev_dbg (hcd->self.controller,
-                               "shutdown urb %p pipe %08x ep%d%s%s\n",
-                               urb, tmp, usb_pipeendpoint (tmp),
-                               (tmp & USB_DIR_IN) ? "in" : "out",
-                               ({ char *s; \
-                                switch (usb_pipetype (tmp)) { \
-                                case PIPE_CONTROL:     s = ""; break; \
-                                case PIPE_BULK:        s = "-bulk"; break; \
-                                case PIPE_INTERRUPT:   s = "-intr"; break; \
-                                default:               s = "-iso"; break; \
-                               }; s;}));
-               }
+               /* kick hcd */
+               unlink1(hcd, urb, -ESHUTDOWN);
+               dev_dbg (hcd->self.controller,
+                       "shutdown urb %p ep%d%s%s\n",
+                       urb, usb_endpoint_num(&ep->desc),
+                       is_in ? "in" : "out",
+                       ({      char *s;
+
+                                switch (usb_endpoint_type(&ep->desc)) {
+                                case USB_ENDPOINT_XFER_CONTROL:
+                                       s = ""; break;
+                                case USB_ENDPOINT_XFER_BULK:
+                                       s = "-bulk"; break;
+                                case USB_ENDPOINT_XFER_INT:
+                                       s = "-intr"; break;
+                                default:
+                                       s = "-iso"; break;
+                               };
+                               s;
+                       }));
                usb_put_urb (urb);
 
                /* list contents may have changed */
                goto rescan;
        }
-       spin_unlock(&hcd_urb_list_lock);
-       local_irq_enable ();
-
-       /* synchronize with the hardware, so old configuration state
-        * clears out immediately (and will be freed).
-        */
-       might_sleep ();
-       if (hcd->driver->endpoint_disable)
-               hcd->driver->endpoint_disable (hcd, ep);
+       spin_unlock_irq(&hcd_urb_list_lock);
 
-       /* Wait until the endpoint queue is completely empty.  Most HCDs
-        * will have done this already in their endpoint_disable method,
-        * but some might not.  And there could be root-hub control URBs
-        * still pending since they aren't affected by the HCDs'
-        * endpoint_disable methods.
-        */
+       /* Wait until the endpoint queue is completely empty */
        while (!list_empty (&ep->urb_list)) {
                spin_lock_irq(&hcd_urb_list_lock);
 
@@ -1278,6 +1370,25 @@ rescan:
        }
 }
 
+/* Disables the endpoint: synchronizes with the hcd to make sure all
+ * endpoint state is gone from hardware.  usb_hcd_flush_endpoint() must
+ * have been called previously.  Use for set_configuration, set_interface,
+ * driver removal, physical disconnect.
+ *
+ * example:  a qh stored in ep->hcpriv, holding state related to endpoint
+ * type, maxpacket size, toggle, halt status, and scheduling.
+ */
+void usb_hcd_disable_endpoint(struct usb_device *udev,
+               struct usb_host_endpoint *ep)
+{
+       struct usb_hcd          *hcd;
+
+       might_sleep();
+       hcd = bus_to_hcd(udev->bus);
+       if (hcd->driver->endpoint_disable)
+               hcd->driver->endpoint_disable(hcd, ep);
+}
+
 /*-------------------------------------------------------------------------*/
 
 /* called in any context */
@@ -1525,7 +1636,6 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
        hcd->driver = driver;
        hcd->product_desc = (driver->product_desc) ? driver->product_desc :
                        "USB Host Controller";
-
        return hcd;
 }
 EXPORT_SYMBOL (usb_create_hcd);
@@ -1570,6 +1680,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
 
        dev_info(hcd->self.controller, "%s\n", hcd->product_desc);
 
+       hcd->authorized_default = hcd->wireless? 0 : 1;
        set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
 
        /* HC is in reset state, but accessible.  Now do the one-time init,
@@ -1646,10 +1757,20 @@ int usb_add_hcd(struct usb_hcd *hcd,
        if ((retval = register_root_hub(hcd)) != 0)
                goto err_register_root_hub;
 
+       retval = sysfs_create_group(&rhdev->dev.kobj, &usb_bus_attr_group);
+       if (retval < 0) {
+               printk(KERN_ERR "Cannot register USB bus sysfs attributes: %d\n",
+                      retval);
+               goto error_create_attr_group;
+       }
        if (hcd->uses_new_polling && hcd->poll_rh)
                usb_hcd_poll_rh_status(hcd);
        return retval;
 
+error_create_attr_group:
+       mutex_lock(&usb_bus_list_lock);
+       usb_disconnect(&hcd->self.root_hub);
+       mutex_unlock(&usb_bus_list_lock);
 err_register_root_hub:
        hcd->driver->stop(hcd);
 err_hcd_driver_start:
@@ -1691,6 +1812,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)
        cancel_work_sync(&hcd->wakeup_work);
 #endif
 
+       sysfs_remove_group(&hcd->self.root_hub->dev.kobj, &usb_bus_attr_group);
        mutex_lock(&usb_bus_list_lock);
        usb_disconnect(&hcd->self.root_hub);
        mutex_unlock(&usb_bus_list_lock);
index b5ebb73c23328cd5e65292f542d3d946e5ea9459..98e24194a4ab61f3be641fd38d9eeb6283bca289 100644 (file)
@@ -19,6 +19,8 @@
 
 #ifdef __KERNEL__
 
+#include <linux/rwsem.h>
+
 /* This file contains declarations of usbcore internals that are mostly
  * used or exposed by Host Controller Drivers.
  */
  *
  * Since "struct usb_bus" is so thin, you can't share much code in it.
  * This framework is a layer over that, and should be more sharable.
+ *
+ * @authorized_default: Specifies if new devices are authorized to
+ *                      connect by default or they require explicit
+ *                      user space authorization; this bit is settable
+ *                      through /sys/class/usb_host/X/authorized_default.
+ *                      For the rest is RO, so we don't lock to r/w it.
  */
 
 /*-------------------------------------------------------------------------*/
@@ -90,6 +98,7 @@ struct usb_hcd {
        unsigned                poll_rh:1;      /* poll for rh status? */
        unsigned                poll_pending:1; /* status has changed? */
        unsigned                wireless:1;     /* Wireless USB HCD */
+       unsigned                authorized_default:1;
 
        int                     irq;            /* irq allocated */
        void __iomem            *regs;          /* device memory/io */
@@ -182,11 +191,10 @@ struct hc_driver {
        int     (*get_frame_number) (struct usb_hcd *hcd);
 
        /* manage i/o requests, device state */
-       int     (*urb_enqueue) (struct usb_hcd *hcd,
-                                       struct usb_host_endpoint *ep,
-                                       struct urb *urb,
-                                       gfp_t mem_flags);
-       int     (*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb);
+       int     (*urb_enqueue)(struct usb_hcd *hcd,
+                               struct urb *urb, gfp_t mem_flags);
+       int     (*urb_dequeue)(struct usb_hcd *hcd,
+                               struct urb *urb, int status);
 
        /* hw synch, freeing endpoint resources that urb_dequeue can't */
        void    (*endpoint_disable)(struct usb_hcd *hcd,
@@ -204,10 +212,18 @@ struct hc_driver {
                /* Needed only if port-change IRQs are level-triggered */
 };
 
+extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
+extern int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
+               int status);
+extern void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb);
+
 extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags);
 extern int usb_hcd_unlink_urb (struct urb *urb, int status);
-extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb);
-extern void usb_hcd_endpoint_disable (struct usb_device *udev,
+extern void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb,
+               int status);
+extern void usb_hcd_flush_endpoint(struct usb_device *udev,
+               struct usb_host_endpoint *ep);
+extern void usb_hcd_disable_endpoint(struct usb_device *udev,
                struct usb_host_endpoint *ep);
 extern int usb_hcd_get_frame_number (struct usb_device *udev);
 
@@ -402,7 +418,7 @@ static inline void usbfs_cleanup(void) { }
 struct usb_mon_operations {
        void (*urb_submit)(struct usb_bus *bus, struct urb *urb);
        void (*urb_submit_error)(struct usb_bus *bus, struct urb *urb, int err);
-       void (*urb_complete)(struct usb_bus *bus, struct urb *urb);
+       void (*urb_complete)(struct usb_bus *bus, struct urb *urb, int status);
        /* void (*urb_unlink)(struct usb_bus *bus, struct urb *urb); */
 };
 
@@ -421,10 +437,11 @@ static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb,
                (*mon_ops->urb_submit_error)(bus, urb, error);
 }
 
-static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb)
+static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb,
+               int status)
 {
        if (bus->monitored)
-               (*mon_ops->urb_complete)(bus, urb);
+               (*mon_ops->urb_complete)(bus, urb, status);
 }
 
 int usb_mon_register(struct usb_mon_operations *ops);
@@ -435,7 +452,8 @@ void usb_mon_deregister(void);
 static inline void usbmon_urb_submit(struct usb_bus *bus, struct urb *urb) {}
 static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb,
     int error) {}
-static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) {}
+static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb,
+               int status) {}
 
 #endif /* CONFIG_USB_MON */
 
@@ -454,5 +472,9 @@ static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) {}
                : (in_interrupt () ? "in_interrupt" : "can sleep"))
 
 
-#endif /* __KERNEL__ */
+/* This rwsem is for use only by the hub driver and ehci-hcd.
+ * Nobody else should touch it.
+ */
+extern struct rw_semaphore ehci_cf_port_reset_rwsem;
 
+#endif /* __KERNEL__ */
index f7b337feb3eac28ddcc997069b81fe16243fde8a..d20cb545a6e4fd0bbc67634251f666d4a0eedfe9 100644 (file)
@@ -125,6 +125,12 @@ MODULE_PARM_DESC(use_both_schemes,
                "try the other device initialization scheme if the "
                "first one fails");
 
+/* Mutual exclusion for EHCI CF initialization.  This interferes with
+ * port reset on some companion controllers.
+ */
+DECLARE_RWSEM(ehci_cf_port_reset_rwsem);
+EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem);
+
 
 static inline char *portspeed(int portstatus)
 {
@@ -347,11 +353,11 @@ void usb_kick_khubd(struct usb_device *hdev)
 static void hub_irq(struct urb *urb)
 {
        struct usb_hub *hub = urb->context;
-       int status;
+       int status = urb->status;
        int i;
        unsigned long bits;
 
-       switch (urb->status) {
+       switch (status) {
        case -ENOENT:           /* synchronous unlink */
        case -ECONNRESET:       /* async unlink */
        case -ESHUTDOWN:        /* hardware going away */
@@ -359,10 +365,10 @@ static void hub_irq(struct urb *urb)
 
        default:                /* presumably an error */
                /* Cause a hub reset after 10 consecutive errors */
-               dev_dbg (hub->intfdev, "transfer --> %d\n", urb->status);
+               dev_dbg (hub->intfdev, "transfer --> %d\n", status);
                if ((++hub->nerrors < 10) || hub->error)
                        goto resubmit;
-               hub->error = urb->status;
+               hub->error = status;
                /* FALL THROUGH */
 
        /* let khubd handle things */
@@ -1220,54 +1226,14 @@ static inline void show_string(struct usb_device *udev, char *id, char *string)
 #endif
 
 /**
- * usb_new_device - perform initial device setup (usbcore-internal)
+ * usb_configure_device_otg - FIXME (usbcore-internal)
  * @udev: newly addressed device (in ADDRESS state)
  *
- * This is called with devices which have been enumerated, but not yet
- * configured.  The device descriptor is available, but not descriptors
- * for any device configuration.  The caller must have locked either
- * the parent hub (if udev is a normal device) or else the
- * usb_bus_list_lock (if udev is a root hub).  The parent's pointer to
- * udev has already been installed, but udev is not yet visible through
- * sysfs or other filesystem code.
- *
- * It will return if the device is configured properly or not.  Zero if
- * the interface was registered with the driver core; else a negative
- * errno value.
- *
- * This call is synchronous, and may not be used in an interrupt context.
- *
- * Only the hub driver or root-hub registrar should ever call this.
+ * Do configuration for On-The-Go devices
  */
-int usb_new_device(struct usb_device *udev)
+static int usb_configure_device_otg(struct usb_device *udev)
 {
-       int err;
-
-       /* Determine quirks */
-       usb_detect_quirks(udev);
-
-       err = usb_get_configuration(udev);
-       if (err < 0) {
-               dev_err(&udev->dev, "can't read configurations, error %d\n",
-                       err);
-               goto fail;
-       }
-
-       /* read the standard strings and cache them if present */
-       udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
-       udev->manufacturer = usb_cache_string(udev,
-                       udev->descriptor.iManufacturer);
-       udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
-
-       /* Tell the world! */
-       dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, "
-                       "SerialNumber=%d\n",
-                       udev->descriptor.iManufacturer,
-                       udev->descriptor.iProduct,
-                       udev->descriptor.iSerialNumber);
-       show_string(udev, "Product", udev->product);
-       show_string(udev, "Manufacturer", udev->manufacturer);
-       show_string(udev, "SerialNumber", udev->serial);
+       int err = 0;
 
 #ifdef CONFIG_USB_OTG
        /*
@@ -1329,8 +1295,82 @@ int usb_new_device(struct usb_device *udev)
                err = -ENOTSUPP;
                goto fail;
        }
+fail:
 #endif
+       return err;
+}
+
+
+/**
+ * usb_configure_device - Detect and probe device intfs/otg (usbcore-internal)
+ * @udev: newly addressed device (in ADDRESS state)
+ *
+ * This is only called by usb_new_device() and usb_authorize_device()
+ * and FIXME -- all comments that apply to them apply here wrt to
+ * environment.
+ *
+ * If the device is WUSB and not authorized, we don't attempt to read
+ * the string descriptors, as they will be errored out by the device
+ * until it has been authorized.
+ */
+static int usb_configure_device(struct usb_device *udev)
+{
+       int err;
 
+       if (udev->config == NULL) {
+               err = usb_get_configuration(udev);
+               if (err < 0) {
+                       dev_err(&udev->dev, "can't read configurations, error %d\n",
+                               err);
+                       goto fail;
+               }
+       }
+       if (udev->wusb == 1 && udev->authorized == 0) {
+               udev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+               udev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+               udev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+       }
+       else {
+               /* read the standard strings and cache them if present */
+               udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
+               udev->manufacturer = usb_cache_string(udev,
+                                                     udev->descriptor.iManufacturer);
+               udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
+       }
+       err = usb_configure_device_otg(udev);
+fail:
+       return err;
+}
+
+
+/**
+ * usb_new_device - perform initial device setup (usbcore-internal)
+ * @udev: newly addressed device (in ADDRESS state)
+ *
+ * This is called with devices which have been enumerated, but not yet
+ * configured.  The device descriptor is available, but not descriptors
+ * for any device configuration.  The caller must have locked either
+ * the parent hub (if udev is a normal device) or else the
+ * usb_bus_list_lock (if udev is a root hub).  The parent's pointer to
+ * udev has already been installed, but udev is not yet visible through
+ * sysfs or other filesystem code.
+ *
+ * It will return if the device is configured properly or not.  Zero if
+ * the interface was registered with the driver core; else a negative
+ * errno value.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ *
+ * Only the hub driver or root-hub registrar should ever call this.
+ */
+int usb_new_device(struct usb_device *udev)
+{
+       int err;
+
+       usb_detect_quirks(udev);                /* Determine quirks */
+       err = usb_configure_device(udev);       /* detect & probe dev/intfs */
+       if (err < 0)
+               goto fail;
        /* export the usbdev device-node for libusb */
        udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
                        (((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
@@ -1346,19 +1386,106 @@ int usb_new_device(struct usb_device *udev)
        err = device_add(&udev->dev);
        if (err) {
                dev_err(&udev->dev, "can't device_add, error %d\n", err);
-               if (udev->parent)
-                       usb_autosuspend_device(udev->parent);
                goto fail;
        }
 
-exit:
+       /* Tell the world! */
+       dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, "
+               "SerialNumber=%d\n",
+               udev->descriptor.iManufacturer,
+               udev->descriptor.iProduct,
+               udev->descriptor.iSerialNumber);
+       show_string(udev, "Product", udev->product);
+       show_string(udev, "Manufacturer", udev->manufacturer);
+       show_string(udev, "SerialNumber", udev->serial);
        return err;
 
 fail:
        usb_set_device_state(udev, USB_STATE_NOTATTACHED);
-       goto exit;
+       return err;
 }
 
+
+/**
+ * Similar to usb_disconnect()
+ *
+ * We share a lock (that we have) with device_del(), so we need to
+ * defer its call.
+ */
+int usb_deauthorize_device(struct usb_device *usb_dev)
+{
+       unsigned cnt;
+       usb_lock_device(usb_dev);
+       if (usb_dev->authorized == 0)
+               goto out_unauthorized;
+       usb_dev->authorized = 0;
+       usb_set_configuration(usb_dev, -1);
+       usb_dev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+       usb_dev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+       usb_dev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+       kfree(usb_dev->config);
+       usb_dev->config = NULL;
+       for (cnt = 0; cnt < usb_dev->descriptor.bNumConfigurations; cnt++)
+               kfree(usb_dev->rawdescriptors[cnt]);
+       usb_dev->descriptor.bNumConfigurations = 0;
+       kfree(usb_dev->rawdescriptors);
+out_unauthorized:
+       usb_unlock_device(usb_dev);
+       return 0;
+}
+
+
+int usb_authorize_device(struct usb_device *usb_dev)
+{
+       int result = 0, c;
+       usb_lock_device(usb_dev);
+       if (usb_dev->authorized == 1)
+               goto out_authorized;
+       kfree(usb_dev->product);
+       usb_dev->product = NULL;
+       kfree(usb_dev->manufacturer);
+       usb_dev->manufacturer = NULL;
+       kfree(usb_dev->serial);
+       usb_dev->serial = NULL;
+       result = usb_autoresume_device(usb_dev);
+       if (result < 0) {
+               dev_err(&usb_dev->dev,
+                       "can't autoresume for authorization: %d\n", result);
+               goto error_autoresume;
+       }
+       result = usb_get_device_descriptor(usb_dev, sizeof(usb_dev->descriptor));
+       if (result < 0) {
+               dev_err(&usb_dev->dev, "can't re-read device descriptor for "
+                       "authorization: %d\n", result);
+               goto error_device_descriptor;
+       }
+       usb_dev->authorized = 1;
+       result = usb_configure_device(usb_dev);
+       if (result < 0)
+               goto error_configure;
+       /* Choose and set the configuration.  This registers the interfaces
+        * with the driver core and lets interface drivers bind to them.
+        */
+       c = usb_choose_configuration(usb_dev);
+       if (c >= 0) {
+               result = usb_set_configuration(usb_dev, c);
+               if (result) {
+                       dev_err(&usb_dev->dev,
+                               "can't set config #%d, error %d\n", c, result);
+                       /* This need not be fatal.  The user can try to
+                        * set other configurations. */
+               }
+       }
+       dev_info(&usb_dev->dev, "authorized to connect\n");
+error_configure:
+error_device_descriptor:
+error_autoresume:
+out_authorized:
+       usb_unlock_device(usb_dev);     // complements locktree
+       return result;
+}
+
+
 static int hub_port_status(struct usb_hub *hub, int port1,
                               u16 *status, u16 *change)
 {
@@ -1460,6 +1587,11 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
 {
        int i, status;
 
+       /* Block EHCI CF initialization during the port reset.
+        * Some companion controllers don't like it when they mix.
+        */
+       down_read(&ehci_cf_port_reset_rwsem);
+
        /* Reset the port */
        for (i = 0; i < PORT_RESET_TRIES; i++) {
                status = set_port_feature(hub->hdev,
@@ -1481,6 +1613,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
                case 0:
                        /* TRSTRCY = 10 ms; plus some extra */
                        msleep(10 + 40);
+                       udev->devnum = 0;       /* Device now at address 0 */
                        /* FALL THROUGH */
                case -ENOTCONN:
                case -ENODEV:
@@ -1490,7 +1623,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
                        usb_set_device_state(udev, status
                                        ? USB_STATE_NOTATTACHED
                                        : USB_STATE_DEFAULT);
-                       return status;
+                       goto done;
                }
 
                dev_dbg (hub->intfdev,
@@ -1503,6 +1636,8 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
                "Cannot enable port %i.  Maybe the USB cable is bad?\n",
                port1);
 
+ done:
+       up_read(&ehci_cf_port_reset_rwsem);
        return status;
 }
 
@@ -1833,14 +1968,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
                struct usb_device       *udev;
 
                udev = hdev->children [port1-1];
-               if (udev && msg.event == PM_EVENT_SUSPEND &&
-#ifdef CONFIG_USB_SUSPEND
-                               udev->state != USB_STATE_SUSPENDED
-#else
-                               udev->dev.power.power_state.event
-                                       == PM_EVENT_ON
-#endif
-                               ) {
+               if (udev && udev->can_submit) {
                        if (!hdev->auto_pm)
                                dev_dbg(&intf->dev, "port %d nyet suspended\n",
                                                port1);
@@ -1999,26 +2127,27 @@ static void ep0_reinit(struct usb_device *udev)
 {
        usb_disable_endpoint(udev, 0 + USB_DIR_IN);
        usb_disable_endpoint(udev, 0 + USB_DIR_OUT);
-       udev->ep_in[0] = udev->ep_out[0] = &udev->ep0;
+       usb_enable_endpoint(udev, &udev->ep0);
 }
 
 #define usb_sndaddr0pipe()     (PIPE_CONTROL << 30)
 #define usb_rcvaddr0pipe()     ((PIPE_CONTROL << 30) | USB_DIR_IN)
 
-static int hub_set_address(struct usb_device *udev)
+static int hub_set_address(struct usb_device *udev, int devnum)
 {
        int retval;
 
-       if (udev->devnum == 0)
+       if (devnum <= 1)
                return -EINVAL;
        if (udev->state == USB_STATE_ADDRESS)
                return 0;
        if (udev->state != USB_STATE_DEFAULT)
                return -EINVAL;
        retval = usb_control_msg(udev, usb_sndaddr0pipe(),
-               USB_REQ_SET_ADDRESS, 0, udev->devnum, 0,
+               USB_REQ_SET_ADDRESS, 0, devnum, 0,
                NULL, 0, USB_CTRL_SET_TIMEOUT);
        if (retval == 0) {
+               udev->devnum = devnum;  /* Device now using proper address */
                usb_set_device_state(udev, USB_STATE_ADDRESS);
                ep0_reinit(udev);
        }
@@ -2045,6 +2174,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
        unsigned                delay = HUB_SHORT_RESET_TIME;
        enum usb_device_speed   oldspeed = udev->speed;
        char                    *speed, *type;
+       int                     devnum = udev->devnum;
 
        /* root hub ports have a slightly longer reset period
         * (from USB 2.0 spec, section 7.1.7.5)
@@ -2074,7 +2204,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
                goto fail;
        }
        oldspeed = udev->speed;
-  
+
        /* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
         * it's fixed size except for full speed devices.
         * For Wireless USB devices, ep0 max packet is always 512 (tho
@@ -2115,7 +2245,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
        dev_info (&udev->dev,
                  "%s %s speed %sUSB device using %s and address %d\n",
                  (udev->config) ? "reset" : "new", speed, type,
-                 udev->bus->controller->driver->name, udev->devnum);
+                 udev->bus->controller->driver->name, devnum);
 
        /* Set up TT records, if needed  */
        if (hdev->tt) {
@@ -2202,7 +2332,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
                }
 
                for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
-                       retval = hub_set_address(udev);
+                       retval = hub_set_address(udev, devnum);
                        if (retval >= 0)
                                break;
                        msleep(200);
@@ -2210,7 +2340,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
                if (retval < 0) {
                        dev_err(&udev->dev,
                                "device not accepting address %d, error %d\n",
-                               udev->devnum, retval);
+                               devnum, retval);
                        goto fail;
                }
  
@@ -2263,8 +2393,10 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
        retval = 0;
 
 fail:
-       if (retval)
+       if (retval) {
                hub_port_disable(hub, port1, 0);
+               udev->devnum = devnum;  /* for disconnect processing */
+       }
        mutex_unlock(&usb_address0_mutex);
        return retval;
 }
@@ -2699,9 +2831,9 @@ static void hub_events(void)
                                clear_hub_feature(hdev, C_HUB_LOCAL_POWER);
                                if (hubstatus & HUB_STATUS_LOCAL_POWER)
                                        /* FIXME: Is this always true? */
-                                       hub->limited_power = 0;
-                               else
                                        hub->limited_power = 1;
+                               else
+                                       hub->limited_power = 0;
                        }
                        if (hubchange & HUB_CHANGE_OVERCURRENT) {
                                dev_dbg (hub_dev, "overcurrent change\n");
index d8f7b089a8f0ad243f3218cbb50c78deed02301b..c021af3903723b3d27db15f2cc904cd80ed4bd36 100644 (file)
@@ -59,8 +59,8 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
                dev_dbg(&urb->dev->dev,
                        "%s timed out on ep%d%s len=%d/%d\n",
                        current->comm,
-                       usb_pipeendpoint(urb->pipe),
-                       usb_pipein(urb->pipe) ? "in" : "out",
+                       usb_endpoint_num(&urb->ep->desc),
+                       usb_urb_dir_in(urb) ? "in" : "out",
                        urb->actual_length,
                        urb->transfer_buffer_length);
        } else
@@ -250,7 +250,8 @@ static void sg_clean (struct usb_sg_request *io)
                io->urbs = NULL;
        }
        if (io->dev->dev.dma_mask != NULL)
-               usb_buffer_unmap_sg (io->dev, io->pipe, io->sg, io->nents);
+               usb_buffer_unmap_sg (io->dev, usb_pipein(io->pipe),
+                               io->sg, io->nents);
        io->dev = NULL;
 }
 
@@ -278,8 +279,8 @@ static void sg_complete (struct urb *urb)
                dev_err (io->dev->bus->controller,
                        "dev %s ep%d%s scatterlist error %d/%d\n",
                        io->dev->devpath,
-                       usb_pipeendpoint (urb->pipe),
-                       usb_pipein (urb->pipe) ? "in" : "out",
+                       usb_endpoint_num(&urb->ep->desc),
+                       usb_urb_dir_in(urb) ? "in" : "out",
                        status, io->status);
                // BUG ();
        }
@@ -379,7 +380,8 @@ int usb_sg_init (
         */
        dma = (dev->dev.dma_mask != NULL);
        if (dma)
-               io->entries = usb_buffer_map_sg (dev, pipe, sg, nents);
+               io->entries = usb_buffer_map_sg(dev, usb_pipein(pipe),
+                               sg, nents);
        else
                io->entries = nents;
 
@@ -1013,8 +1015,11 @@ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr)
                ep = dev->ep_in[epnum];
                dev->ep_in[epnum] = NULL;
        }
-       if (ep && dev->bus)
-               usb_hcd_endpoint_disable(dev, ep);
+       if (ep) {
+               ep->enabled = 0;
+               usb_hcd_flush_endpoint(dev, ep);
+               usb_hcd_disable_endpoint(dev, ep);
+       }
 }
 
 /**
@@ -1096,23 +1101,21 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
  * Resets the endpoint toggle, and sets dev->ep_{in,out} pointers.
  * For control endpoints, both the input and output sides are handled.
  */
-static void
-usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep)
+void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep)
 {
-       unsigned int epaddr = ep->desc.bEndpointAddress;
-       unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK;
-       int is_control;
+       int epnum = usb_endpoint_num(&ep->desc);
+       int is_out = usb_endpoint_dir_out(&ep->desc);
+       int is_control = usb_endpoint_xfer_control(&ep->desc);
 
-       is_control = ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-                       == USB_ENDPOINT_XFER_CONTROL);
-       if (usb_endpoint_out(epaddr) || is_control) {
+       if (is_out || is_control) {
                usb_settoggle(dev, epnum, 1, 0);
                dev->ep_out[epnum] = ep;
        }
-       if (!usb_endpoint_out(epaddr) || is_control) {
+       if (!is_out || is_control) {
                usb_settoggle(dev, epnum, 0, 0);
                dev->ep_in[epnum] = ep;
        }
+       ep->enabled = 1;
 }
 
 /*
@@ -1171,6 +1174,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
        struct usb_host_interface *alt;
        int ret;
        int manual = 0;
+       int changed;
 
        if (dev->state == USB_STATE_SUSPENDED)
                return -EHOSTUNREACH;
@@ -1210,7 +1214,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
         */
 
        /* prevent submissions using previous endpoint settings */
-       if (device_is_registered(&iface->dev))
+       changed = (iface->cur_altsetting != alt);
+       if (changed && device_is_registered(&iface->dev))
                usb_remove_sysfs_intf_files(iface);
        usb_disable_interface(dev, iface);
 
@@ -1247,7 +1252,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
         * (Likewise, EP0 never "halts" on well designed devices.)
         */
        usb_enable_interface(dev, iface);
-       if (device_is_registered(&iface->dev))
+       if (changed && device_is_registered(&iface->dev))
                usb_create_sysfs_intf_files(iface);
 
        return 0;
@@ -1328,7 +1333,7 @@ int usb_reset_configuration(struct usb_device *dev)
        return 0;
 }
 
-void usb_release_interface(struct device *dev)
+static void usb_release_interface(struct device *dev)
 {
        struct usb_interface *intf = to_usb_interface(dev);
        struct usb_interface_cache *intfc =
@@ -1339,14 +1344,11 @@ void usb_release_interface(struct device *dev)
 }
 
 #ifdef CONFIG_HOTPLUG
-static int usb_if_uevent(struct device *dev, char **envp, int num_envp,
-                char *buffer, int buffer_size)
+static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        struct usb_device *usb_dev;
        struct usb_interface *intf;
        struct usb_host_interface *alt;
-       int i = 0;
-       int length = 0;
 
        if (!dev)
                return -ENODEV;
@@ -1359,39 +1361,30 @@ static int usb_if_uevent(struct device *dev, char **envp, int num_envp,
        alt = intf->cur_altsetting;
 
 #ifdef CONFIG_USB_DEVICEFS
-       if (add_uevent_var(envp, num_envp, &i,
-                          buffer, buffer_size, &length,
-                          "DEVICE=/proc/bus/usb/%03d/%03d",
+       if (add_uevent_var(env, "DEVICE=/proc/bus/usb/%03d/%03d",
                           usb_dev->bus->busnum, usb_dev->devnum))
                return -ENOMEM;
 #endif
 
-       if (add_uevent_var(envp, num_envp, &i,
-                          buffer, buffer_size, &length,
-                          "PRODUCT=%x/%x/%x",
+       if (add_uevent_var(env, "PRODUCT=%x/%x/%x",
                           le16_to_cpu(usb_dev->descriptor.idVendor),
                           le16_to_cpu(usb_dev->descriptor.idProduct),
                           le16_to_cpu(usb_dev->descriptor.bcdDevice)))
                return -ENOMEM;
 
-       if (add_uevent_var(envp, num_envp, &i,
-                          buffer, buffer_size, &length,
-                          "TYPE=%d/%d/%d",
+       if (add_uevent_var(env, "TYPE=%d/%d/%d",
                           usb_dev->descriptor.bDeviceClass,
                           usb_dev->descriptor.bDeviceSubClass,
                           usb_dev->descriptor.bDeviceProtocol))
                return -ENOMEM;
 
-       if (add_uevent_var(envp, num_envp, &i,
-                  buffer, buffer_size, &length,
-                  "INTERFACE=%d/%d/%d",
+       if (add_uevent_var(env, "INTERFACE=%d/%d/%d",
                   alt->desc.bInterfaceClass,
                   alt->desc.bInterfaceSubClass,
                   alt->desc.bInterfaceProtocol))
                return -ENOMEM;
 
-       if (add_uevent_var(envp, num_envp, &i,
-                  buffer, buffer_size, &length,
+       if (add_uevent_var(env,
                   "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",
                   le16_to_cpu(usb_dev->descriptor.idVendor),
                   le16_to_cpu(usb_dev->descriptor.idProduct),
@@ -1404,14 +1397,12 @@ static int usb_if_uevent(struct device *dev, char **envp, int num_envp,
                   alt->desc.bInterfaceProtocol))
                return -ENOMEM;
 
-       envp[i] = NULL;
        return 0;
 }
 
 #else
 
-static int usb_if_uevent(struct device *dev, char **envp,
-                        int num_envp, char *buffer, int buffer_size)
+static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        return -ENODEV;
 }
@@ -1481,6 +1472,9 @@ static struct usb_interface_assoc_descriptor *find_iad(struct usb_device *dev,
  * channels are available independently; and choosing between open
  * standard device protocols (like CDC) or proprietary ones.
  *
+ * Note that a non-authorized device (dev->authorized == 0) will only
+ * be put in unconfigured mode.
+ *
  * Note that USB has an additional level of device configurability,
  * associated with interfaces.  That configurability is accessed using
  * usb_set_interface().
@@ -1502,7 +1496,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
        struct usb_interface **new_interfaces = NULL;
        int n, nintf;
 
-       if (configuration == -1)
+       if (dev->authorized == 0 || configuration == -1)
                configuration = 0;
        else {
                for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
index ebf3dc20110af96c4bdbcbac963c0d3c2a8ac313..d42c561c75f1fb5743e0fb98d9cb2cecc9ea930b 100644 (file)
@@ -32,52 +32,6 @@ static const struct usb_device_id usb_quirk_list[] = {
        { USB_DEVICE(0x0204, 0x6025), .driver_info = USB_QUIRK_RESET_RESUME },
        /* HP 5300/5370C scanner */
        { USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 },
-       /* Hewlett-Packard PhotoSmart 720 / PhotoSmart 935 (storage) */
-       { USB_DEVICE(0x03f0, 0x4002), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
-       /* SGS Thomson Microelectronics 4in1 card reader */
-       { USB_DEVICE(0x0483, 0x0321), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
-       /* Acer Peripherals Inc. (now BenQ Corp.) Prisa 640BU */
-       { USB_DEVICE(0x04a5, 0x207e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       /* Benq S2W 3300U */
-       { USB_DEVICE(0x04a5, 0x20b0), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       /* Canon, Inc. CanoScan N1240U/LiDE30 */
-       { USB_DEVICE(0x04a9, 0x220e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       /* Canon, Inc. CanoScan N650U/N656U */
-       { USB_DEVICE(0x04a9, 0x2206), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       /* Canon, Inc. CanoScan 1220U */
-       { USB_DEVICE(0x04a9, 0x2207), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       /* Canon, Inc. CanoScan N670U/N676U/LiDE 20 */
-       { USB_DEVICE(0x04a9, 0x220d), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       /* old Cannon scanner */
-       { USB_DEVICE(0x04a9, 0x2220), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       /* Seiko Epson Corp. Perfection 1200 */
-       { USB_DEVICE(0x04b8, 0x0104), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       /* Seiko Epson Corp. Perfection 660 */
-       { USB_DEVICE(0x04b8, 0x0114), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       /* Epson Perfection 1260 Photo */
-       { USB_DEVICE(0x04b8, 0x011d), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       /* Seiko Epson Corp - Perfection 1670 */
-       { USB_DEVICE(0x04b8, 0x011f), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       /* EPSON Perfection 2480 */
-       { USB_DEVICE(0x04b8, 0x0121), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       /* Seiko Epson Corp.*/
-       { USB_DEVICE(0x04b8, 0x0122), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       /* Samsung ML-2010 printer */
-       { USB_DEVICE(0x04e8, 0x326c), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       /* Samsung ML-2510 Series printer */
-       { USB_DEVICE(0x04e8, 0x327e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       /* Elsa MicroLink 56k (V.250) */
-       { USB_DEVICE(0x05cc, 0x2267), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       /* Ultima Electronics Corp.*/
-       { USB_DEVICE(0x05d8, 0x4005), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
-       /* Genesys USB-to-IDE */
-       { USB_DEVICE(0x0503, 0x0702), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
-       /* USB Graphical LCD - EEH Datalink GmbH */
-       { USB_DEVICE(0x060c, 0x04eb), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
 
        /* INTEL VALUE SSD */
        { USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME },
@@ -85,44 +39,15 @@ static const struct usb_device_id usb_quirk_list[] = {
        /* M-Systems Flash Disk Pioneers */
        { USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME },
 
-       /* Agfa Snapscan1212u */
-       { USB_DEVICE(0x06bd, 0x2061), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       /* Seagate RSS LLC */
-       { USB_DEVICE(0x0bc2, 0x3000), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       /* Umax [hex] Astra 3400U */
-       { USB_DEVICE(0x1606, 0x0060), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
        /* Philips PSC805 audio device */
        { USB_DEVICE(0x0471, 0x0155), .driver_info = USB_QUIRK_RESET_RESUME },
 
-       /* Alcor multi-card reader */
-       { USB_DEVICE(0x058f, 0x6366), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
-       /* Canon EOS 5D in PC Connection mode */
-       { USB_DEVICE(0x04a9, 0x3101), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
-       /* RIM Blackberry */
-       { USB_DEVICE(0x0fca, 0x0001), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       { USB_DEVICE(0x0fca, 0x0004), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       { USB_DEVICE(0x0fca, 0x0006), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
-       /* Apple iPhone */
-       { USB_DEVICE(0x05ac, 0x1290), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
        /* SKYMEDI USB_DRIVE */
        { USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME },
 
        { }  /* terminating entry must be last */
 };
 
-static void usb_autosuspend_quirk(struct usb_device *udev)
-{
-#ifdef CONFIG_USB_SUSPEND
-       /* disable autosuspend, but allow the user to re-enable it via sysfs */
-       udev->autosuspend_disabled = 1;
-#endif
-}
-
 static const struct usb_device_id *find_id(struct usb_device *udev)
 {
        const struct usb_device_id *id = usb_quirk_list;
@@ -149,13 +74,9 @@ void usb_detect_quirks(struct usb_device *udev)
                dev_dbg(&udev->dev, "USB quirks for this device: %x\n",
                                udev->quirks);
 
-       /* do any special quirk handling here if needed */
-       if (udev->quirks & USB_QUIRK_NO_AUTOSUSPEND)
-               usb_autosuspend_quirk(udev);
-
        /* By default, disable autosuspend for all non-hubs */
 #ifdef CONFIG_USB_SUSPEND
        if (udev->descriptor.bDeviceClass != USB_CLASS_HUB)
-               udev->autosuspend_delay = -1;
+               udev->autosuspend_disabled = 1;
 #endif
 }
index 2ab222be8fd164f58bff7245005ab4f621433a1d..b04afd06e502131f97024360fd5e1ad3279af9f4 100644 (file)
@@ -169,6 +169,16 @@ show_quirks(struct device *dev, struct device_attribute *attr, char *buf)
 }
 static DEVICE_ATTR(quirks, S_IRUGO, show_quirks, NULL);
 
+static ssize_t
+show_urbnum(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct usb_device *udev;
+
+       udev = to_usb_device(dev);
+       return sprintf(buf, "%d\n", atomic_read(&udev->urbnum));
+}
+static DEVICE_ATTR(urbnum, S_IRUGO, show_urbnum, NULL);
+
 
 #if defined(CONFIG_USB_PERSIST) || defined(CONFIG_USB_SUSPEND)
 static const char power_group[] = "power";
@@ -413,6 +423,44 @@ usb_descriptor_attr(bDeviceProtocol, "%02x\n")
 usb_descriptor_attr(bNumConfigurations, "%d\n")
 usb_descriptor_attr(bMaxPacketSize0, "%d\n")
 
+
+
+/* show if the device is authorized (1) or not (0) */
+static ssize_t usb_dev_authorized_show(struct device *dev,
+                                      struct device_attribute *attr,
+                                      char *buf)
+{
+       struct usb_device *usb_dev = to_usb_device(dev);
+       return snprintf(buf, PAGE_SIZE, "%u\n", usb_dev->authorized);
+}
+
+
+/*
+ * Authorize a device to be used in the system
+ *
+ * Writing a 0 deauthorizes the device, writing a 1 authorizes it.
+ */
+static ssize_t usb_dev_authorized_store(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t size)
+{
+       ssize_t result;
+       struct usb_device *usb_dev = to_usb_device(dev);
+       unsigned val;
+       result = sscanf(buf, "%u\n", &val);
+       if (result != 1)
+               result = -EINVAL;
+       else if (val == 0)
+               result = usb_deauthorize_device(usb_dev);
+       else
+               result = usb_authorize_device(usb_dev);
+       return result < 0? result : size;
+}
+
+static DEVICE_ATTR(authorized, 0644,
+           usb_dev_authorized_show, usb_dev_authorized_store);
+
+
 static struct attribute *dev_attrs[] = {
        /* current configuration's attributes */
        &dev_attr_configuration.attr,
@@ -420,6 +468,7 @@ static struct attribute *dev_attrs[] = {
        &dev_attr_bConfigurationValue.attr,
        &dev_attr_bmAttributes.attr,
        &dev_attr_bMaxPower.attr,
+       &dev_attr_urbnum.attr,
        /* device attributes */
        &dev_attr_idVendor.attr,
        &dev_attr_idProduct.attr,
@@ -435,6 +484,7 @@ static struct attribute *dev_attrs[] = {
        &dev_attr_version.attr,
        &dev_attr_maxchild.attr,
        &dev_attr_quirks.attr,
+       &dev_attr_authorized.attr,
        NULL,
 };
 static struct attribute_group dev_attr_grp = {
index be630228461c046d06fe5232ea91466ad75e861d..c20c03aaf01283bba746523ad5724f6e00a298d2 100644 (file)
@@ -3,6 +3,7 @@
 #include <linux/bitops.h>
 #include <linux/slab.h>
 #include <linux/init.h>
+#include <linux/log2.h>
 #include <linux/usb.h>
 #include <linux/wait.h>
 #include "hcd.h"
@@ -38,7 +39,6 @@ void usb_init_urb(struct urb *urb)
        if (urb) {
                memset(urb, 0, sizeof(*urb));
                kref_init(&urb->kref);
-               spin_lock_init(&urb->lock);
                INIT_LIST_HEAD(&urb->anchor_list);
        }
 }
@@ -277,44 +277,58 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb);
  */
 int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
 {
-       int                     pipe, temp, max;
-       struct usb_device       *dev;
-       int                     is_out;
+       int                             xfertype, max;
+       struct usb_device               *dev;
+       struct usb_host_endpoint        *ep;
+       int                             is_out;
 
        if (!urb || urb->hcpriv || !urb->complete)
                return -EINVAL;
-       if (!(dev = urb->dev) ||
-           (dev->state < USB_STATE_DEFAULT) ||
-           (!dev->bus) || (dev->devnum <= 0))
+       if (!(dev = urb->dev) || dev->state < USB_STATE_DEFAULT)
                return -ENODEV;
-       if (dev->bus->controller->power.power_state.event != PM_EVENT_ON
-                       || dev->state == USB_STATE_SUSPENDED)
-               return -EHOSTUNREACH;
 
+       /* For now, get the endpoint from the pipe.  Eventually drivers
+        * will be required to set urb->ep directly and we will eliminate
+        * urb->pipe.
+        */
+       ep = (usb_pipein(urb->pipe) ? dev->ep_in : dev->ep_out)
+                       [usb_pipeendpoint(urb->pipe)];
+       if (!ep)
+               return -ENOENT;
+
+       urb->ep = ep;
        urb->status = -EINPROGRESS;
        urb->actual_length = 0;
 
        /* Lots of sanity checks, so HCDs can rely on clean data
         * and don't need to duplicate tests
         */
-       pipe = urb->pipe;
-       temp = usb_pipetype(pipe);
-       is_out = usb_pipeout(pipe);
+       xfertype = usb_endpoint_type(&ep->desc);
+       if (xfertype == USB_ENDPOINT_XFER_CONTROL) {
+               struct usb_ctrlrequest *setup =
+                               (struct usb_ctrlrequest *) urb->setup_packet;
+
+               if (!setup)
+                       return -ENOEXEC;
+               is_out = !(setup->bRequestType & USB_DIR_IN) ||
+                               !setup->wLength;
+       } else {
+               is_out = usb_endpoint_dir_out(&ep->desc);
+       }
 
-       if (!usb_pipecontrol(pipe) && dev->state < USB_STATE_CONFIGURED)
-               return -ENODEV;
+       /* Cache the direction for later use */
+       urb->transfer_flags = (urb->transfer_flags & ~URB_DIR_MASK) |
+                       (is_out ? URB_DIR_OUT : URB_DIR_IN);
 
-       /* FIXME there should be a sharable lock protecting us against
-        * config/altsetting changes and disconnects, kicking in here.
-        * (here == before maxpacket, and eventually endpoint type,
-        * checks get made.)
-        */
+       if (xfertype != USB_ENDPOINT_XFER_CONTROL &&
+                       dev->state < USB_STATE_CONFIGURED)
+               return -ENODEV;
 
-       max = usb_maxpacket(dev, pipe, is_out);
+       max = le16_to_cpu(ep->desc.wMaxPacketSize);
        if (max <= 0) {
                dev_dbg(&dev->dev,
                        "bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",
-                       usb_pipeendpoint(pipe), is_out ? "out" : "in",
+                       usb_endpoint_num(&ep->desc), is_out ? "out" : "in",
                        __FUNCTION__, max);
                return -EMSGSIZE;
        }
@@ -323,7 +337,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
         * but drivers only control those sizes for ISO.
         * while we're checking, initialize return status.
         */
-       if (temp == PIPE_ISOCHRONOUS) {
+       if (xfertype == USB_ENDPOINT_XFER_ISOC) {
                int     n, len;
 
                /* "high bandwidth" mode, 1-3 packets/uframe? */
@@ -358,20 +372,20 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
 
        /* enforce simple/standard policy */
        allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP |
-                       URB_NO_INTERRUPT);
-       switch (temp) {
-       case PIPE_BULK:
+                       URB_NO_INTERRUPT | URB_DIR_MASK);
+       switch (xfertype) {
+       case USB_ENDPOINT_XFER_BULK:
                if (is_out)
                        allowed |= URB_ZERO_PACKET;
                /* FALLTHROUGH */
-       case PIPE_CONTROL:
+       case USB_ENDPOINT_XFER_CONTROL:
                allowed |= URB_NO_FSBR; /* only affects UHCI */
                /* FALLTHROUGH */
        default:                        /* all non-iso endpoints */
                if (!is_out)
                        allowed |= URB_SHORT_NOT_OK;
                break;
-       case PIPE_ISOCHRONOUS:
+       case USB_ENDPOINT_XFER_ISOC:
                allowed |= URB_ISO_ASAP;
                break;
        }
@@ -393,9 +407,9 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
         * supports different values... this uses EHCI/UHCI defaults (and
         * EHCI can use smaller non-default values).
         */
-       switch (temp) {
-       case PIPE_ISOCHRONOUS:
-       case PIPE_INTERRUPT:
+       switch (xfertype) {
+       case USB_ENDPOINT_XFER_ISOC:
+       case USB_ENDPOINT_XFER_INT:
                /* too small? */
                if (urb->interval <= 0)
                        return -EINVAL;
@@ -405,29 +419,27 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
                        // NOTE usb handles 2^15
                        if (urb->interval > (1024 * 8))
                                urb->interval = 1024 * 8;
-                       temp = 1024 * 8;
+                       max = 1024 * 8;
                        break;
                case USB_SPEED_FULL:    /* units are frames/msec */
                case USB_SPEED_LOW:
-                       if (temp == PIPE_INTERRUPT) {
+                       if (xfertype == USB_ENDPOINT_XFER_INT) {
                                if (urb->interval > 255)
                                        return -EINVAL;
                                // NOTE ohci only handles up to 32
-                               temp = 128;
+                               max = 128;
                        } else {
                                if (urb->interval > 1024)
                                        urb->interval = 1024;
                                // NOTE usb and ohci handle up to 2^15
-                               temp = 1024;
+                               max = 1024;
                        }
                        break;
                default:
                        return -EINVAL;
                }
-               /* power of two? */
-               while (temp > urb->interval)
-                       temp >>= 1;
-               urb->interval = temp;
+               /* Round down to a power of 2, no more than max */
+               urb->interval = min(max, 1 << ilog2(urb->interval));
        }
 
        return usb_hcd_submit_urb(urb, mem_flags);
@@ -496,8 +508,10 @@ int usb_unlink_urb(struct urb *urb)
 {
        if (!urb)
                return -EINVAL;
-       if (!(urb->dev && urb->dev->bus))
+       if (!urb->dev)
                return -ENODEV;
+       if (!urb->ep)
+               return -EIDRM;
        return usb_hcd_unlink_urb(urb, -ECONNRESET);
 }
 
@@ -523,19 +537,21 @@ int usb_unlink_urb(struct urb *urb)
  */
 void usb_kill_urb(struct urb *urb)
 {
+       static DEFINE_MUTEX(reject_mutex);
+
        might_sleep();
-       if (!(urb && urb->dev && urb->dev->bus))
+       if (!(urb && urb->dev && urb->ep))
                return;
-       spin_lock_irq(&urb->lock);
+       mutex_lock(&reject_mutex);
        ++urb->reject;
-       spin_unlock_irq(&urb->lock);
+       mutex_unlock(&reject_mutex);
 
        usb_hcd_unlink_urb(urb, -ENOENT);
        wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0);
 
-       spin_lock_irq(&urb->lock);
+       mutex_lock(&reject_mutex);
        --urb->reject;
-       spin_unlock_irq(&urb->lock);
+       mutex_unlock(&reject_mutex);
 }
 
 /**
index 0fee5c66fd64ea44ef0531453b1b0bfb60cc7614..c99938d5f78e6299ffacf7c732e20959c94ffc47 100644 (file)
@@ -223,6 +223,15 @@ static void ksuspend_usb_cleanup(void)
 
 #endif /* CONFIG_PM */
 
+
+/* Returns 1 if @usb_bus is WUSB, 0 otherwise */
+static unsigned usb_bus_is_wusb(struct usb_bus *bus)
+{
+       struct usb_hcd *hcd = container_of(bus, struct usb_hcd, self);
+       return hcd->wireless;
+}
+
+
 /**
  * usb_alloc_dev - usb device constructor (usbcore-internal)
  * @parent: hub to which device is connected; null to allocate a root hub
@@ -239,6 +248,8 @@ struct usb_device *
 usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
 {
        struct usb_device *dev;
+       struct usb_hcd *usb_hcd = container_of(bus, struct usb_hcd, self);
+       unsigned root_hub = 0;
 
        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
        if (!dev)
@@ -255,12 +266,14 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
        dev->dev.dma_mask = bus->controller->dma_mask;
        set_dev_node(&dev->dev, dev_to_node(bus->controller));
        dev->state = USB_STATE_ATTACHED;
+       atomic_set(&dev->urbnum, 0);
 
        INIT_LIST_HEAD(&dev->ep0.urb_list);
        dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;
        dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;
        /* ep0 maxpacket comes later, from device descriptor */
-       dev->ep_in[0] = dev->ep_out[0] = &dev->ep0;
+       usb_enable_endpoint(dev, &dev->ep0);
+       dev->can_submit = 1;
 
        /* Save readable and stable topology id, distinguishing devices
         * by location for diagnostics, tools, driver model, etc.  The
@@ -275,6 +288,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
 
                dev->dev.parent = bus->controller;
                sprintf(&dev->dev.bus_id[0], "usb%d", bus->busnum);
+               root_hub = 1;
        } else {
                /* match any labeling on the hubs; it's one-based */
                if (parent->devpath[0] == '0')
@@ -301,6 +315,12 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
        INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work);
        dev->autosuspend_delay = usb_autosuspend_delay * HZ;
 #endif
+       if (root_hub)   /* Root hub always ok [and always wired] */
+               dev->authorized = 1;
+       else {
+               dev->authorized = usb_hcd->authorized_default;
+               dev->wusb = usb_bus_is_wusb(bus)? 1 : 0;
+       }
        return dev;
 }
 
@@ -748,7 +768,7 @@ void usb_buffer_unmap(struct urb *urb)
 /**
  * usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint
  * @dev: device to which the scatterlist will be mapped
- * @pipe: endpoint defining the mapping direction
+ * @is_in: mapping transfer direction
  * @sg: the scatterlist to map
  * @nents: the number of entries in the scatterlist
  *
@@ -771,14 +791,13 @@ void usb_buffer_unmap(struct urb *urb)
  *
  * Reverse the effect of this call with usb_buffer_unmap_sg().
  */
-int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
+int usb_buffer_map_sg(const struct usb_device *dev, int is_in,
                      struct scatterlist *sg, int nents)
 {
        struct usb_bus          *bus;
        struct device           *controller;
 
        if (!dev
-                       || usb_pipecontrol(pipe)
                        || !(bus = dev->bus)
                        || !(controller = bus->controller)
                        || !controller->dma_mask)
@@ -786,7 +805,7 @@ int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
 
        // FIXME generic api broken like pci, can't report errors
        return dma_map_sg(controller, sg, nents,
-                       usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+                       is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 
 /* XXX DISABLED, no users currently.  If you wish to re-enable this
@@ -799,14 +818,14 @@ int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
 /**
  * usb_buffer_dmasync_sg - synchronize DMA and CPU view of scatterlist buffer(s)
  * @dev: device to which the scatterlist will be mapped
- * @pipe: endpoint defining the mapping direction
+ * @is_in: mapping transfer direction
  * @sg: the scatterlist to synchronize
  * @n_hw_ents: the positive return value from usb_buffer_map_sg
  *
  * Use this when you are re-using a scatterlist's data buffers for
  * another USB request.
  */
-void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe,
+void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in,
                           struct scatterlist *sg, int n_hw_ents)
 {
        struct usb_bus          *bus;
@@ -819,20 +838,20 @@ void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe,
                return;
 
        dma_sync_sg(controller, sg, n_hw_ents,
-                       usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+                       is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 #endif
 
 /**
  * usb_buffer_unmap_sg - free DMA mapping(s) for a scatterlist
  * @dev: device to which the scatterlist will be mapped
- * @pipe: endpoint defining the mapping direction
+ * @is_in: mapping transfer direction
  * @sg: the scatterlist to unmap
  * @n_hw_ents: the positive return value from usb_buffer_map_sg
  *
  * Reverses the effect of usb_buffer_map_sg().
  */
-void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe,
+void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in,
                         struct scatterlist *sg, int n_hw_ents)
 {
        struct usb_bus          *bus;
@@ -845,7 +864,7 @@ void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe,
                return;
 
        dma_unmap_sg(controller, sg, n_hw_ents,
-                       usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+                       is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 
 /* format to disable USB on kernel command line is: nousb */
index ad5fa0338f498631ca71350b198830b3f80ac3fb..c52626c51f70bd99859c170739eb20b7695937bb 100644 (file)
@@ -8,17 +8,22 @@ extern int usb_create_ep_files(struct device *parent, struct usb_host_endpoint *
                                struct usb_device *udev);
 extern void usb_remove_ep_files(struct usb_host_endpoint *endpoint);
 
+extern void usb_enable_endpoint(struct usb_device *dev,
+               struct usb_host_endpoint *ep);
 extern void usb_disable_endpoint (struct usb_device *dev, unsigned int epaddr);
 extern void usb_disable_interface (struct usb_device *dev,
                struct usb_interface *intf);
 extern void usb_release_interface_cache(struct kref *ref);
 extern void usb_disable_device (struct usb_device *dev, int skip_ep0);
+extern int usb_deauthorize_device (struct usb_device *);
+extern int usb_authorize_device (struct usb_device *);
 extern void usb_detect_quirks(struct usb_device *udev);
 
 extern int usb_get_device_descriptor(struct usb_device *dev,
                unsigned int size);
 extern char *usb_cache_string(struct usb_device *udev, int index);
 extern int usb_set_configuration(struct usb_device *dev, int configuration);
+extern int usb_choose_configuration(struct usb_device *udev);
 
 extern void usb_kick_khubd(struct usb_device *dev);
 extern int usb_match_device(struct usb_device *dev,
index 767aed5b4bea015938d7d8164c0c1e121942c994..f81d08d6538b6d34ce9d112a18de3dec909d096f 100644 (file)
@@ -67,6 +67,17 @@ config USB_GADGET_DEBUG_FILES
           driver on a new board.   Enable these files by choosing "Y"
           here.  If in doubt, or to conserve kernel memory, say "N".
 
+config USB_GADGET_DEBUG_FS
+       boolean "Debugging information files in debugfs"
+       depends on USB_GADGET && DEBUG_FS
+       help
+          Some of the drivers in the "gadget" framework can expose
+          debugging information in files under /sys/kernel/debug/.
+          The information in these files may help when you're
+          troubleshooting or bringing up a driver on a new board.
+          Enable these files by choosing "Y" here.  If in doubt, or
+          to conserve kernel memory, say "N".
+
 config USB_GADGET_SELECTED
        boolean
 
@@ -103,6 +114,20 @@ config USB_AMD5536UDC
        default USB_GADGET
        select USB_GADGET_SELECTED
 
+config USB_GADGET_ATMEL_USBA
+       boolean "Atmel USBA"
+       select USB_GADGET_DUALSPEED
+       depends on AVR32
+       help
+         USBA is the integrated high-speed USB Device controller on
+         the AT32AP700x processors from Atmel.
+
+config USB_ATMEL_USBA
+       tristate
+       depends on USB_GADGET_ATMEL_USBA
+       default USB_GADGET
+       select USB_GADGET_SELECTED
+
 config USB_GADGET_FSL_USB2
        boolean "Freescale Highspeed USB DR Peripheral Controller"
        depends on MPC834x || PPC_MPC831x
@@ -228,7 +253,6 @@ config USB_LH7A40X
        default USB_GADGET
        select USB_GADGET_SELECTED
 
-
 config USB_GADGET_OMAP
        boolean "OMAP USB Device Controller"
        depends on ARCH_OMAP
index 1bc0f03550cea0df21f0f21e3c6cd7fdf7fdff7d..904e57bf61124e8bb2e996df679a35a3d628c743 100644 (file)
@@ -14,6 +14,7 @@ obj-$(CONFIG_USB_OMAP)                += omap_udc.o
 obj-$(CONFIG_USB_LH7A40X)      += lh7a40x_udc.o
 obj-$(CONFIG_USB_S3C2410)      += s3c2410_udc.o
 obj-$(CONFIG_USB_AT91)         += at91_udc.o
+obj-$(CONFIG_USB_ATMEL_USBA)   += atmel_usba_udc.o
 obj-$(CONFIG_USB_FSL_USB2)     += fsl_usb2_udc.o
 obj-$(CONFIG_USB_M66592)       += m66592-udc.o
 
index 714156ca8fe470ac4b59210d09d21da4fffb288f..1c80406025252ed4f8b8a258f2a6d1f9ee8bbf4f 100644 (file)
@@ -69,7 +69,7 @@
 
 /* gadget stack */
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 /* udc specific */
 #include "amd5536udc.h"
@@ -3244,7 +3244,6 @@ static int udc_pci_probe(
                retval = -ENOMEM;
                goto finished;
        }
-       memset(dev, 0, sizeof(struct udc));
 
        /* pci setup */
        if (pci_enable_device(pdev) < 0) {
@@ -3286,14 +3285,12 @@ static int udc_pci_probe(
 
        pci_set_drvdata(pdev, dev);
 
-       /* chip revision */
-       dev->chiprev = 0;
+       /* chip revision for Hs AMD5536 */
+       dev->chiprev = pdev->revision;
 
        pci_set_master(pdev);
        pci_set_mwi(pdev);
 
-       /* chip rev for Hs AMD5536 */
-       pci_read_config_byte(pdev, PCI_REVISION_ID, (u8 *) &dev->chiprev);
        /* init dma pools */
        if (use_dma) {
                retval = init_dma_pools(dev);
index 63d7d6568699e28fad912c05c3fc4f7c601bf39d..a6adf7e0f6f8de4cc49595211dc5de7e6d4e779e 100644 (file)
@@ -38,7 +38,7 @@
 #include <linux/proc_fs.h>
 #include <linux/clk.h>
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include <asm/byteorder.h>
 #include <asm/hardware.h>
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
new file mode 100644 (file)
index 0000000..4fb5ff4
--- /dev/null
@@ -0,0 +1,2077 @@
+/*
+ * Driver for the Atmel USBA high speed USB device controller
+ *
+ * Copyright (C) 2005-2007 Atmel Corporation
+ *
+ * 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/clk.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/delay.h>
+
+#include <asm/gpio.h>
+#include <asm/arch/board.h>
+
+#include "atmel_usba_udc.h"
+
+
+static struct usba_udc the_udc;
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+
+static int queue_dbg_open(struct inode *inode, struct file *file)
+{
+       struct usba_ep *ep = inode->i_private;
+       struct usba_request *req, *req_copy;
+       struct list_head *queue_data;
+
+       queue_data = kmalloc(sizeof(*queue_data), GFP_KERNEL);
+       if (!queue_data)
+               return -ENOMEM;
+       INIT_LIST_HEAD(queue_data);
+
+       spin_lock_irq(&ep->udc->lock);
+       list_for_each_entry(req, &ep->queue, queue) {
+               req_copy = kmalloc(sizeof(*req_copy), GFP_ATOMIC);
+               if (!req_copy)
+                       goto fail;
+               memcpy(req_copy, req, sizeof(*req_copy));
+               list_add_tail(&req_copy->queue, queue_data);
+       }
+       spin_unlock_irq(&ep->udc->lock);
+
+       file->private_data = queue_data;
+       return 0;
+
+fail:
+       spin_unlock_irq(&ep->udc->lock);
+       list_for_each_entry_safe(req, req_copy, queue_data, queue) {
+               list_del(&req->queue);
+               kfree(req);
+       }
+       kfree(queue_data);
+       return -ENOMEM;
+}
+
+/*
+ * bbbbbbbb llllllll IZS sssss nnnn FDL\n\0
+ *
+ * b: buffer address
+ * l: buffer length
+ * I/i: interrupt/no interrupt
+ * Z/z: zero/no zero
+ * S/s: short ok/short not ok
+ * s: status
+ * n: nr_packets
+ * F/f: submitted/not submitted to FIFO
+ * D/d: using/not using DMA
+ * L/l: last transaction/not last transaction
+ */
+static ssize_t queue_dbg_read(struct file *file, char __user *buf,
+               size_t nbytes, loff_t *ppos)
+{
+       struct list_head *queue = file->private_data;
+       struct usba_request *req, *tmp_req;
+       size_t len, remaining, actual = 0;
+       char tmpbuf[38];
+
+       if (!access_ok(VERIFY_WRITE, buf, nbytes))
+               return -EFAULT;
+
+       mutex_lock(&file->f_dentry->d_inode->i_mutex);
+       list_for_each_entry_safe(req, tmp_req, queue, queue) {
+               len = snprintf(tmpbuf, sizeof(tmpbuf),
+                               "%8p %08x %c%c%c %5d %c%c%c\n",
+                               req->req.buf, req->req.length,
+                               req->req.no_interrupt ? 'i' : 'I',
+                               req->req.zero ? 'Z' : 'z',
+                               req->req.short_not_ok ? 's' : 'S',
+                               req->req.status,
+                               req->submitted ? 'F' : 'f',
+                               req->using_dma ? 'D' : 'd',
+                               req->last_transaction ? 'L' : 'l');
+               len = min(len, sizeof(tmpbuf));
+               if (len > nbytes)
+                       break;
+
+               list_del(&req->queue);
+               kfree(req);
+
+               remaining = __copy_to_user(buf, tmpbuf, len);
+               actual += len - remaining;
+               if (remaining)
+                       break;
+
+               nbytes -= len;
+               buf += len;
+       }
+       mutex_unlock(&file->f_dentry->d_inode->i_mutex);
+
+       return actual;
+}
+
+static int queue_dbg_release(struct inode *inode, struct file *file)
+{
+       struct list_head *queue_data = file->private_data;
+       struct usba_request *req, *tmp_req;
+
+       list_for_each_entry_safe(req, tmp_req, queue_data, queue) {
+               list_del(&req->queue);
+               kfree(req);
+       }
+       kfree(queue_data);
+       return 0;
+}
+
+static int regs_dbg_open(struct inode *inode, struct file *file)
+{
+       struct usba_udc *udc;
+       unsigned int i;
+       u32 *data;
+       int ret = -ENOMEM;
+
+       mutex_lock(&inode->i_mutex);
+       udc = inode->i_private;
+       data = kmalloc(inode->i_size, GFP_KERNEL);
+       if (!data)
+               goto out;
+
+       spin_lock_irq(&udc->lock);
+       for (i = 0; i < inode->i_size / 4; i++)
+               data[i] = __raw_readl(udc->regs + i * 4);
+       spin_unlock_irq(&udc->lock);
+
+       file->private_data = data;
+       ret = 0;
+
+out:
+       mutex_unlock(&inode->i_mutex);
+
+       return ret;
+}
+
+static ssize_t regs_dbg_read(struct file *file, char __user *buf,
+               size_t nbytes, loff_t *ppos)
+{
+       struct inode *inode = file->f_dentry->d_inode;
+       int ret;
+
+       mutex_lock(&inode->i_mutex);
+       ret = simple_read_from_buffer(buf, nbytes, ppos,
+                       file->private_data,
+                       file->f_dentry->d_inode->i_size);
+       mutex_unlock(&inode->i_mutex);
+
+       return ret;
+}
+
+static int regs_dbg_release(struct inode *inode, struct file *file)
+{
+       kfree(file->private_data);
+       return 0;
+}
+
+const struct file_operations queue_dbg_fops = {
+       .owner          = THIS_MODULE,
+       .open           = queue_dbg_open,
+       .llseek         = no_llseek,
+       .read           = queue_dbg_read,
+       .release        = queue_dbg_release,
+};
+
+const struct file_operations regs_dbg_fops = {
+       .owner          = THIS_MODULE,
+       .open           = regs_dbg_open,
+       .llseek         = generic_file_llseek,
+       .read           = regs_dbg_read,
+       .release        = regs_dbg_release,
+};
+
+static void usba_ep_init_debugfs(struct usba_udc *udc,
+               struct usba_ep *ep)
+{
+       struct dentry *ep_root;
+
+       ep_root = debugfs_create_dir(ep->ep.name, udc->debugfs_root);
+       if (!ep_root)
+               goto err_root;
+       ep->debugfs_dir = ep_root;
+
+       ep->debugfs_queue = debugfs_create_file("queue", 0400, ep_root,
+                                               ep, &queue_dbg_fops);
+       if (!ep->debugfs_queue)
+               goto err_queue;
+
+       if (ep->can_dma) {
+               ep->debugfs_dma_status
+                       = debugfs_create_u32("dma_status", 0400, ep_root,
+                                       &ep->last_dma_status);
+               if (!ep->debugfs_dma_status)
+                       goto err_dma_status;
+       }
+       if (ep_is_control(ep)) {
+               ep->debugfs_state
+                       = debugfs_create_u32("state", 0400, ep_root,
+                                       &ep->state);
+               if (!ep->debugfs_state)
+                       goto err_state;
+       }
+
+       return;
+
+err_state:
+       if (ep->can_dma)
+               debugfs_remove(ep->debugfs_dma_status);
+err_dma_status:
+       debugfs_remove(ep->debugfs_queue);
+err_queue:
+       debugfs_remove(ep_root);
+err_root:
+       dev_err(&ep->udc->pdev->dev,
+               "failed to create debugfs directory for %s\n", ep->ep.name);
+}
+
+static void usba_ep_cleanup_debugfs(struct usba_ep *ep)
+{
+       debugfs_remove(ep->debugfs_queue);
+       debugfs_remove(ep->debugfs_dma_status);
+       debugfs_remove(ep->debugfs_state);
+       debugfs_remove(ep->debugfs_dir);
+       ep->debugfs_dma_status = NULL;
+       ep->debugfs_dir = NULL;
+}
+
+static void usba_init_debugfs(struct usba_udc *udc)
+{
+       struct dentry *root, *regs;
+       struct resource *regs_resource;
+
+       root = debugfs_create_dir(udc->gadget.name, NULL);
+       if (IS_ERR(root) || !root)
+               goto err_root;
+       udc->debugfs_root = root;
+
+       regs = debugfs_create_file("regs", 0400, root, udc, &regs_dbg_fops);
+       if (!regs)
+               goto err_regs;
+
+       regs_resource = platform_get_resource(udc->pdev, IORESOURCE_MEM,
+                               CTRL_IOMEM_ID);
+       regs->d_inode->i_size = regs_resource->end - regs_resource->start + 1;
+       udc->debugfs_regs = regs;
+
+       usba_ep_init_debugfs(udc, to_usba_ep(udc->gadget.ep0));
+
+       return;
+
+err_regs:
+       debugfs_remove(root);
+err_root:
+       udc->debugfs_root = NULL;
+       dev_err(&udc->pdev->dev, "debugfs is not available\n");
+}
+
+static void usba_cleanup_debugfs(struct usba_udc *udc)
+{
+       usba_ep_cleanup_debugfs(to_usba_ep(udc->gadget.ep0));
+       debugfs_remove(udc->debugfs_regs);
+       debugfs_remove(udc->debugfs_root);
+       udc->debugfs_regs = NULL;
+       udc->debugfs_root = NULL;
+}
+#else
+static inline void usba_ep_init_debugfs(struct usba_udc *udc,
+                                        struct usba_ep *ep)
+{
+
+}
+
+static inline void usba_ep_cleanup_debugfs(struct usba_ep *ep)
+{
+
+}
+
+static inline void usba_init_debugfs(struct usba_udc *udc)
+{
+
+}
+
+static inline void usba_cleanup_debugfs(struct usba_udc *udc)
+{
+
+}
+#endif
+
+static int vbus_is_present(struct usba_udc *udc)
+{
+       if (udc->vbus_pin != -1)
+               return gpio_get_value(udc->vbus_pin);
+
+       /* No Vbus detection: Assume always present */
+       return 1;
+}
+
+static void copy_to_fifo(void __iomem *fifo, const void *buf, int len)
+{
+       unsigned long tmp;
+
+       DBG(DBG_FIFO, "copy to FIFO (len %d):\n", len);
+       for (; len > 0; len -= 4, buf += 4, fifo += 4) {
+               tmp = *(unsigned long *)buf;
+               if (len >= 4) {
+                       DBG(DBG_FIFO, "  -> %08lx\n", tmp);
+                       __raw_writel(tmp, fifo);
+               } else {
+                       do {
+                               DBG(DBG_FIFO, "  -> %02lx\n", tmp >> 24);
+                               __raw_writeb(tmp >> 24, fifo);
+                               fifo++;
+                               tmp <<= 8;
+                       } while (--len);
+                       break;
+               }
+       }
+}
+
+static void copy_from_fifo(void *buf, void __iomem *fifo, int len)
+{
+       union {
+               unsigned long *w;
+               unsigned char *b;
+       } p;
+       unsigned long tmp;
+
+       DBG(DBG_FIFO, "copy from FIFO (len %d):\n", len);
+       for (p.w = buf; len > 0; len -= 4, p.w++, fifo += 4) {
+               if (len >= 4) {
+                       tmp = __raw_readl(fifo);
+                       *p.w = tmp;
+                       DBG(DBG_FIFO, "  -> %08lx\n", tmp);
+               } else {
+                       do {
+                               tmp = __raw_readb(fifo);
+                               *p.b = tmp;
+                               DBG(DBG_FIFO, " -> %02lx\n", tmp);
+                               fifo++, p.b++;
+                       } while (--len);
+               }
+       }
+}
+
+static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req)
+{
+       unsigned int transaction_len;
+
+       transaction_len = req->req.length - req->req.actual;
+       req->last_transaction = 1;
+       if (transaction_len > ep->ep.maxpacket) {
+               transaction_len = ep->ep.maxpacket;
+               req->last_transaction = 0;
+       } else if (transaction_len == ep->ep.maxpacket && req->req.zero)
+               req->last_transaction = 0;
+
+       DBG(DBG_QUEUE, "%s: submit_transaction, req %p (length %d)%s\n",
+               ep->ep.name, req, transaction_len,
+               req->last_transaction ? ", done" : "");
+
+       copy_to_fifo(ep->fifo, req->req.buf + req->req.actual, transaction_len);
+       usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+       req->req.actual += transaction_len;
+}
+
+static void submit_request(struct usba_ep *ep, struct usba_request *req)
+{
+       DBG(DBG_QUEUE, "%s: submit_request: req %p (length %d)\n",
+               ep->ep.name, req, req->req.length);
+
+       req->req.actual = 0;
+       req->submitted = 1;
+
+       if (req->using_dma) {
+               if (req->req.length == 0) {
+                       usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
+                       return;
+               }
+
+               if (req->req.zero)
+                       usba_ep_writel(ep, CTL_ENB, USBA_SHORT_PACKET);
+               else
+                       usba_ep_writel(ep, CTL_DIS, USBA_SHORT_PACKET);
+
+               usba_dma_writel(ep, ADDRESS, req->req.dma);
+               usba_dma_writel(ep, CONTROL, req->ctrl);
+       } else {
+               next_fifo_transaction(ep, req);
+               if (req->last_transaction) {
+                       usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
+                       usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
+               } else {
+                       usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+                       usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
+               }
+       }
+}
+
+static void submit_next_request(struct usba_ep *ep)
+{
+       struct usba_request *req;
+
+       if (list_empty(&ep->queue)) {
+               usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY | USBA_RX_BK_RDY);
+               return;
+       }
+
+       req = list_entry(ep->queue.next, struct usba_request, queue);
+       if (!req->submitted)
+               submit_request(ep, req);
+}
+
+static void send_status(struct usba_udc *udc, struct usba_ep *ep)
+{
+       ep->state = STATUS_STAGE_IN;
+       usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+       usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
+}
+
+static void receive_data(struct usba_ep *ep)
+{
+       struct usba_udc *udc = ep->udc;
+       struct usba_request *req;
+       unsigned long status;
+       unsigned int bytecount, nr_busy;
+       int is_complete = 0;
+
+       status = usba_ep_readl(ep, STA);
+       nr_busy = USBA_BFEXT(BUSY_BANKS, status);
+
+       DBG(DBG_QUEUE, "receive data: nr_busy=%u\n", nr_busy);
+
+       while (nr_busy > 0) {
+               if (list_empty(&ep->queue)) {
+                       usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+                       break;
+               }
+               req = list_entry(ep->queue.next,
+                                struct usba_request, queue);
+
+               bytecount = USBA_BFEXT(BYTE_COUNT, status);
+
+               if (status & (1 << 31))
+                       is_complete = 1;
+               if (req->req.actual + bytecount >= req->req.length) {
+                       is_complete = 1;
+                       bytecount = req->req.length - req->req.actual;
+               }
+
+               copy_from_fifo(req->req.buf + req->req.actual,
+                               ep->fifo, bytecount);
+               req->req.actual += bytecount;
+
+               usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+
+               if (is_complete) {
+                       DBG(DBG_QUEUE, "%s: request done\n", ep->ep.name);
+                       req->req.status = 0;
+                       list_del_init(&req->queue);
+                       usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+                       spin_unlock(&udc->lock);
+                       req->req.complete(&ep->ep, &req->req);
+                       spin_lock(&udc->lock);
+               }
+
+               status = usba_ep_readl(ep, STA);
+               nr_busy = USBA_BFEXT(BUSY_BANKS, status);
+
+               if (is_complete && ep_is_control(ep)) {
+                       send_status(udc, ep);
+                       break;
+               }
+       }
+}
+
+static void
+request_complete(struct usba_ep *ep, struct usba_request *req, int status)
+{
+       struct usba_udc *udc = ep->udc;
+
+       WARN_ON(!list_empty(&req->queue));
+
+       if (req->req.status == -EINPROGRESS)
+               req->req.status = status;
+
+       if (req->mapped) {
+               dma_unmap_single(
+                       &udc->pdev->dev, req->req.dma, req->req.length,
+                       ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+               req->req.dma = DMA_ADDR_INVALID;
+               req->mapped = 0;
+       }
+
+       DBG(DBG_GADGET | DBG_REQ,
+               "%s: req %p complete: status %d, actual %u\n",
+               ep->ep.name, req, req->req.status, req->req.actual);
+
+       spin_unlock(&udc->lock);
+       req->req.complete(&ep->ep, &req->req);
+       spin_lock(&udc->lock);
+}
+
+static void
+request_complete_list(struct usba_ep *ep, struct list_head *list, int status)
+{
+       struct usba_request *req, *tmp_req;
+
+       list_for_each_entry_safe(req, tmp_req, list, queue) {
+               list_del_init(&req->queue);
+               request_complete(ep, req, status);
+       }
+}
+
+static int
+usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
+{
+       struct usba_ep *ep = to_usba_ep(_ep);
+       struct usba_udc *udc = ep->udc;
+       unsigned long flags, ept_cfg, maxpacket;
+       unsigned int nr_trans;
+
+       DBG(DBG_GADGET, "%s: ep_enable: desc=%p\n", ep->ep.name, desc);
+
+       maxpacket = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff;
+
+       if (((desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) != ep->index)
+                       || ep->index == 0
+                       || desc->bDescriptorType != USB_DT_ENDPOINT
+                       || maxpacket == 0
+                       || maxpacket > ep->fifo_size) {
+               DBG(DBG_ERR, "ep_enable: Invalid argument");
+               return -EINVAL;
+       }
+
+       ep->is_isoc = 0;
+       ep->is_in = 0;
+
+       if (maxpacket <= 8)
+               ept_cfg = USBA_BF(EPT_SIZE, USBA_EPT_SIZE_8);
+       else
+               /* LSB is bit 1, not 0 */
+               ept_cfg = USBA_BF(EPT_SIZE, fls(maxpacket - 1) - 3);
+
+       DBG(DBG_HW, "%s: EPT_SIZE = %lu (maxpacket = %lu)\n",
+                       ep->ep.name, ept_cfg, maxpacket);
+
+       if ((desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
+               ep->is_in = 1;
+               ept_cfg |= USBA_EPT_DIR_IN;
+       }
+
+       switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+       case USB_ENDPOINT_XFER_CONTROL:
+               ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL);
+               ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE);
+               break;
+       case USB_ENDPOINT_XFER_ISOC:
+               if (!ep->can_isoc) {
+                       DBG(DBG_ERR, "ep_enable: %s is not isoc capable\n",
+                                       ep->ep.name);
+                       return -EINVAL;
+               }
+
+               /*
+                * Bits 11:12 specify number of _additional_
+                * transactions per microframe.
+                */
+               nr_trans = ((le16_to_cpu(desc->wMaxPacketSize) >> 11) & 3) + 1;
+               if (nr_trans > 3)
+                       return -EINVAL;
+
+               ep->is_isoc = 1;
+               ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_ISO);
+
+               /*
+                * Do triple-buffering on high-bandwidth iso endpoints.
+                */
+               if (nr_trans > 1 && ep->nr_banks == 3)
+                       ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_TRIPLE);
+               else
+                       ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE);
+               ept_cfg |= USBA_BF(NB_TRANS, nr_trans);
+               break;
+       case USB_ENDPOINT_XFER_BULK:
+               ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK);
+               ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE);
+               break;
+       case USB_ENDPOINT_XFER_INT:
+               ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_INT);
+               ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE);
+               break;
+       }
+
+       spin_lock_irqsave(&ep->udc->lock, flags);
+
+       if (ep->desc) {
+               spin_unlock_irqrestore(&ep->udc->lock, flags);
+               DBG(DBG_ERR, "ep%d already enabled\n", ep->index);
+               return -EBUSY;
+       }
+
+       ep->desc = desc;
+       ep->ep.maxpacket = maxpacket;
+
+       usba_ep_writel(ep, CFG, ept_cfg);
+       usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE);
+
+       if (ep->can_dma) {
+               u32 ctrl;
+
+               usba_writel(udc, INT_ENB,
+                               (usba_readl(udc, INT_ENB)
+                                       | USBA_BF(EPT_INT, 1 << ep->index)
+                                       | USBA_BF(DMA_INT, 1 << ep->index)));
+               ctrl = USBA_AUTO_VALID | USBA_INTDIS_DMA;
+               usba_ep_writel(ep, CTL_ENB, ctrl);
+       } else {
+               usba_writel(udc, INT_ENB,
+                               (usba_readl(udc, INT_ENB)
+                                       | USBA_BF(EPT_INT, 1 << ep->index)));
+       }
+
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       DBG(DBG_HW, "EPT_CFG%d after init: %#08lx\n", ep->index,
+                       (unsigned long)usba_ep_readl(ep, CFG));
+       DBG(DBG_HW, "INT_ENB after init: %#08lx\n",
+                       (unsigned long)usba_readl(udc, INT_ENB));
+
+       return 0;
+}
+
+static int usba_ep_disable(struct usb_ep *_ep)
+{
+       struct usba_ep *ep = to_usba_ep(_ep);
+       struct usba_udc *udc = ep->udc;
+       LIST_HEAD(req_list);
+       unsigned long flags;
+
+       DBG(DBG_GADGET, "ep_disable: %s\n", ep->ep.name);
+
+       spin_lock_irqsave(&udc->lock, flags);
+
+       if (!ep->desc) {
+               spin_unlock_irqrestore(&udc->lock, flags);
+               DBG(DBG_ERR, "ep_disable: %s not enabled\n", ep->ep.name);
+               return -EINVAL;
+       }
+       ep->desc = NULL;
+
+       list_splice_init(&ep->queue, &req_list);
+       if (ep->can_dma) {
+               usba_dma_writel(ep, CONTROL, 0);
+               usba_dma_writel(ep, ADDRESS, 0);
+               usba_dma_readl(ep, STATUS);
+       }
+       usba_ep_writel(ep, CTL_DIS, USBA_EPT_ENABLE);
+       usba_writel(udc, INT_ENB,
+                       usba_readl(udc, INT_ENB)
+                       & ~USBA_BF(EPT_INT, 1 << ep->index));
+
+       request_complete_list(ep, &req_list, -ESHUTDOWN);
+
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       return 0;
+}
+
+static struct usb_request *
+usba_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
+{
+       struct usba_request *req;
+
+       DBG(DBG_GADGET, "ep_alloc_request: %p, 0x%x\n", _ep, gfp_flags);
+
+       req = kzalloc(sizeof(*req), gfp_flags);
+       if (!req)
+               return NULL;
+
+       INIT_LIST_HEAD(&req->queue);
+       req->req.dma = DMA_ADDR_INVALID;
+
+       return &req->req;
+}
+
+static void
+usba_ep_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+       struct usba_request *req = to_usba_req(_req);
+
+       DBG(DBG_GADGET, "ep_free_request: %p, %p\n", _ep, _req);
+
+       kfree(req);
+}
+
+static int queue_dma(struct usba_udc *udc, struct usba_ep *ep,
+               struct usba_request *req, gfp_t gfp_flags)
+{
+       unsigned long flags;
+       int ret;
+
+       DBG(DBG_DMA, "%s: req l/%u d/%08x %c%c%c\n",
+               ep->ep.name, req->req.length, req->req.dma,
+               req->req.zero ? 'Z' : 'z',
+               req->req.short_not_ok ? 'S' : 's',
+               req->req.no_interrupt ? 'I' : 'i');
+
+       if (req->req.length > 0x10000) {
+               /* Lengths from 0 to 65536 (inclusive) are supported */
+               DBG(DBG_ERR, "invalid request length %u\n", req->req.length);
+               return -EINVAL;
+       }
+
+       req->using_dma = 1;
+
+       if (req->req.dma == DMA_ADDR_INVALID) {
+               req->req.dma = dma_map_single(
+                       &udc->pdev->dev, req->req.buf, req->req.length,
+                       ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+               req->mapped = 1;
+       } else {
+               dma_sync_single_for_device(
+                       &udc->pdev->dev, req->req.dma, req->req.length,
+                       ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+               req->mapped = 0;
+       }
+
+       req->ctrl = USBA_BF(DMA_BUF_LEN, req->req.length)
+                       | USBA_DMA_CH_EN | USBA_DMA_END_BUF_IE
+                       | USBA_DMA_END_TR_EN | USBA_DMA_END_TR_IE;
+
+       if (ep->is_in)
+               req->ctrl |= USBA_DMA_END_BUF_EN;
+
+       /*
+        * Add this request to the queue and submit for DMA if
+        * possible. Check if we're still alive first -- we may have
+        * received a reset since last time we checked.
+        */
+       ret = -ESHUTDOWN;
+       spin_lock_irqsave(&udc->lock, flags);
+       if (ep->desc) {
+               if (list_empty(&ep->queue))
+                       submit_request(ep, req);
+
+               list_add_tail(&req->queue, &ep->queue);
+               ret = 0;
+       }
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       return ret;
+}
+
+static int
+usba_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+{
+       struct usba_request *req = to_usba_req(_req);
+       struct usba_ep *ep = to_usba_ep(_ep);
+       struct usba_udc *udc = ep->udc;
+       unsigned long flags;
+       int ret;
+
+       DBG(DBG_GADGET | DBG_QUEUE | DBG_REQ, "%s: queue req %p, len %u\n",
+                       ep->ep.name, req, _req->length);
+
+       if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN || !ep->desc)
+               return -ESHUTDOWN;
+
+       req->submitted = 0;
+       req->using_dma = 0;
+       req->last_transaction = 0;
+
+       _req->status = -EINPROGRESS;
+       _req->actual = 0;
+
+       if (ep->can_dma)
+               return queue_dma(udc, ep, req, gfp_flags);
+
+       /* May have received a reset since last time we checked */
+       ret = -ESHUTDOWN;
+       spin_lock_irqsave(&udc->lock, flags);
+       if (ep->desc) {
+               list_add_tail(&req->queue, &ep->queue);
+
+               if (ep->is_in || (ep_is_control(ep)
+                               && (ep->state == DATA_STAGE_IN
+                                       || ep->state == STATUS_STAGE_IN)))
+                       usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
+               else
+                       usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY);
+               ret = 0;
+       }
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       return ret;
+}
+
+static void
+usba_update_req(struct usba_ep *ep, struct usba_request *req, u32 status)
+{
+       req->req.actual = req->req.length - USBA_BFEXT(DMA_BUF_LEN, status);
+}
+
+static int stop_dma(struct usba_ep *ep, u32 *pstatus)
+{
+       unsigned int timeout;
+       u32 status;
+
+       /*
+        * Stop the DMA controller. When writing both CH_EN
+        * and LINK to 0, the other bits are not affected.
+        */
+       usba_dma_writel(ep, CONTROL, 0);
+
+       /* Wait for the FIFO to empty */
+       for (timeout = 40; timeout; --timeout) {
+               status = usba_dma_readl(ep, STATUS);
+               if (!(status & USBA_DMA_CH_EN))
+                       break;
+               udelay(1);
+       }
+
+       if (pstatus)
+               *pstatus = status;
+
+       if (timeout == 0) {
+               dev_err(&ep->udc->pdev->dev,
+                       "%s: timed out waiting for DMA FIFO to empty\n",
+                       ep->ep.name);
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+static int usba_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+       struct usba_ep *ep = to_usba_ep(_ep);
+       struct usba_udc *udc = ep->udc;
+       struct usba_request *req = to_usba_req(_req);
+       unsigned long flags;
+       u32 status;
+
+       DBG(DBG_GADGET | DBG_QUEUE, "ep_dequeue: %s, req %p\n",
+                       ep->ep.name, req);
+
+       spin_lock_irqsave(&udc->lock, flags);
+
+       if (req->using_dma) {
+               /*
+                * If this request is currently being transferred,
+                * stop the DMA controller and reset the FIFO.
+                */
+               if (ep->queue.next == &req->queue) {
+                       status = usba_dma_readl(ep, STATUS);
+                       if (status & USBA_DMA_CH_EN)
+                               stop_dma(ep, &status);
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+                       ep->last_dma_status = status;
+#endif
+
+                       usba_writel(udc, EPT_RST, 1 << ep->index);
+
+                       usba_update_req(ep, req, status);
+               }
+       }
+
+       /*
+        * Errors should stop the queue from advancing until the
+        * completion function returns.
+        */
+       list_del_init(&req->queue);
+
+       request_complete(ep, req, -ECONNRESET);
+
+       /* Process the next request if any */
+       submit_next_request(ep);
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       return 0;
+}
+
+static int usba_ep_set_halt(struct usb_ep *_ep, int value)
+{
+       struct usba_ep *ep = to_usba_ep(_ep);
+       struct usba_udc *udc = ep->udc;
+       unsigned long flags;
+       int ret = 0;
+
+       DBG(DBG_GADGET, "endpoint %s: %s HALT\n", ep->ep.name,
+                       value ? "set" : "clear");
+
+       if (!ep->desc) {
+               DBG(DBG_ERR, "Attempted to halt uninitialized ep %s\n",
+                               ep->ep.name);
+               return -ENODEV;
+       }
+       if (ep->is_isoc) {
+               DBG(DBG_ERR, "Attempted to halt isochronous ep %s\n",
+                               ep->ep.name);
+               return -ENOTTY;
+       }
+
+       spin_lock_irqsave(&udc->lock, flags);
+
+       /*
+        * We can't halt IN endpoints while there are still data to be
+        * transferred
+        */
+       if (!list_empty(&ep->queue)
+                       || ((value && ep->is_in && (usba_ep_readl(ep, STA)
+                                       & USBA_BF(BUSY_BANKS, -1L))))) {
+               ret = -EAGAIN;
+       } else {
+               if (value)
+                       usba_ep_writel(ep, SET_STA, USBA_FORCE_STALL);
+               else
+                       usba_ep_writel(ep, CLR_STA,
+                                       USBA_FORCE_STALL | USBA_TOGGLE_CLR);
+               usba_ep_readl(ep, STA);
+       }
+
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       return ret;
+}
+
+static int usba_ep_fifo_status(struct usb_ep *_ep)
+{
+       struct usba_ep *ep = to_usba_ep(_ep);
+
+       return USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA));
+}
+
+static void usba_ep_fifo_flush(struct usb_ep *_ep)
+{
+       struct usba_ep *ep = to_usba_ep(_ep);
+       struct usba_udc *udc = ep->udc;
+
+       usba_writel(udc, EPT_RST, 1 << ep->index);
+}
+
+static const struct usb_ep_ops usba_ep_ops = {
+       .enable         = usba_ep_enable,
+       .disable        = usba_ep_disable,
+       .alloc_request  = usba_ep_alloc_request,
+       .free_request   = usba_ep_free_request,
+       .queue          = usba_ep_queue,
+       .dequeue        = usba_ep_dequeue,
+       .set_halt       = usba_ep_set_halt,
+       .fifo_status    = usba_ep_fifo_status,
+       .fifo_flush     = usba_ep_fifo_flush,
+};
+
+static int usba_udc_get_frame(struct usb_gadget *gadget)
+{
+       struct usba_udc *udc = to_usba_udc(gadget);
+
+       return USBA_BFEXT(FRAME_NUMBER, usba_readl(udc, FNUM));
+}
+
+static int usba_udc_wakeup(struct usb_gadget *gadget)
+{
+       struct usba_udc *udc = to_usba_udc(gadget);
+       unsigned long flags;
+       u32 ctrl;
+       int ret = -EINVAL;
+
+       spin_lock_irqsave(&udc->lock, flags);
+       if (udc->devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) {
+               ctrl = usba_readl(udc, CTRL);
+               usba_writel(udc, CTRL, ctrl | USBA_REMOTE_WAKE_UP);
+               ret = 0;
+       }
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       return ret;
+}
+
+static int
+usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered)
+{
+       struct usba_udc *udc = to_usba_udc(gadget);
+       unsigned long flags;
+
+       spin_lock_irqsave(&udc->lock, flags);
+       if (is_selfpowered)
+               udc->devstatus |= 1 << USB_DEVICE_SELF_POWERED;
+       else
+               udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       return 0;
+}
+
+static const struct usb_gadget_ops usba_udc_ops = {
+       .get_frame              = usba_udc_get_frame,
+       .wakeup                 = usba_udc_wakeup,
+       .set_selfpowered        = usba_udc_set_selfpowered,
+};
+
+#define EP(nam, idx, maxpkt, maxbk, dma, isoc)                 \
+{                                                              \
+       .ep     = {                                             \
+               .ops            = &usba_ep_ops,                 \
+               .name           = nam,                          \
+               .maxpacket      = maxpkt,                       \
+       },                                                      \
+       .udc            = &the_udc,                             \
+       .queue          = LIST_HEAD_INIT(usba_ep[idx].queue),   \
+       .fifo_size      = maxpkt,                               \
+       .nr_banks       = maxbk,                                \
+       .index          = idx,                                  \
+       .can_dma        = dma,                                  \
+       .can_isoc       = isoc,                                 \
+}
+
+static struct usba_ep usba_ep[] = {
+       EP("ep0", 0, 64, 1, 0, 0),
+       EP("ep1in-bulk", 1, 512, 2, 1, 1),
+       EP("ep2out-bulk", 2, 512, 2, 1, 1),
+       EP("ep3in-int", 3, 64, 3, 1, 0),
+       EP("ep4out-int", 4, 64, 3, 1, 0),
+       EP("ep5in-iso", 5, 1024, 3, 1, 1),
+       EP("ep6out-iso", 6, 1024, 3, 1, 1),
+};
+#undef EP
+
+static struct usb_endpoint_descriptor usba_ep0_desc = {
+       .bLength = USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType = USB_DT_ENDPOINT,
+       .bEndpointAddress = 0,
+       .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+       .wMaxPacketSize = __constant_cpu_to_le16(64),
+       /* FIXME: I have no idea what to put here */
+       .bInterval = 1,
+};
+
+static void nop_release(struct device *dev)
+{
+
+}
+
+static struct usba_udc the_udc = {
+       .gadget = {
+               .ops            = &usba_udc_ops,
+               .ep0            = &usba_ep[0].ep,
+               .ep_list        = LIST_HEAD_INIT(the_udc.gadget.ep_list),
+               .is_dualspeed   = 1,
+               .name           = "atmel_usba_udc",
+               .dev    = {
+                       .bus_id         = "gadget",
+                       .release        = nop_release,
+               },
+       },
+
+       .lock   = SPIN_LOCK_UNLOCKED,
+};
+
+/*
+ * Called with interrupts disabled and udc->lock held.
+ */
+static void reset_all_endpoints(struct usba_udc *udc)
+{
+       struct usba_ep *ep;
+       struct usba_request *req, *tmp_req;
+
+       usba_writel(udc, EPT_RST, ~0UL);
+
+       ep = to_usba_ep(udc->gadget.ep0);
+       list_for_each_entry_safe(req, tmp_req, &ep->queue, queue) {
+               list_del_init(&req->queue);
+               request_complete(ep, req, -ECONNRESET);
+       }
+
+       list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
+               if (ep->desc) {
+                       spin_unlock(&udc->lock);
+                       usba_ep_disable(&ep->ep);
+                       spin_lock(&udc->lock);
+               }
+       }
+}
+
+static struct usba_ep *get_ep_by_addr(struct usba_udc *udc, u16 wIndex)
+{
+       struct usba_ep *ep;
+
+       if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0)
+               return to_usba_ep(udc->gadget.ep0);
+
+       list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) {
+               u8 bEndpointAddress;
+
+               if (!ep->desc)
+                       continue;
+               bEndpointAddress = ep->desc->bEndpointAddress;
+               if ((wIndex ^ bEndpointAddress) & USB_DIR_IN)
+                       continue;
+               if ((bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)
+                               == (wIndex & USB_ENDPOINT_NUMBER_MASK))
+                       return ep;
+       }
+
+       return NULL;
+}
+
+/* Called with interrupts disabled and udc->lock held */
+static inline void set_protocol_stall(struct usba_udc *udc, struct usba_ep *ep)
+{
+       usba_ep_writel(ep, SET_STA, USBA_FORCE_STALL);
+       ep->state = WAIT_FOR_SETUP;
+}
+
+static inline int is_stalled(struct usba_udc *udc, struct usba_ep *ep)
+{
+       if (usba_ep_readl(ep, STA) & USBA_FORCE_STALL)
+               return 1;
+       return 0;
+}
+
+static inline void set_address(struct usba_udc *udc, unsigned int addr)
+{
+       u32 regval;
+
+       DBG(DBG_BUS, "setting address %u...\n", addr);
+       regval = usba_readl(udc, CTRL);
+       regval = USBA_BFINS(DEV_ADDR, addr, regval);
+       usba_writel(udc, CTRL, regval);
+}
+
+static int do_test_mode(struct usba_udc *udc)
+{
+       static const char test_packet_buffer[] = {
+               /* JKJKJKJK * 9 */
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               /* JJKKJJKK * 8 */
+               0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+               /* JJKKJJKK * 8 */
+               0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE,
+               /* JJJJJJJKKKKKKK * 8 */
+               0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+               0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+               /* JJJJJJJK * 8 */
+               0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD,
+               /* {JKKKKKKK * 10}, JK */
+               0xFC, 0x7E, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0x7E
+       };
+       struct usba_ep *ep;
+       struct device *dev = &udc->pdev->dev;
+       int test_mode;
+
+       test_mode = udc->test_mode;
+
+       /* Start from a clean slate */
+       reset_all_endpoints(udc);
+
+       switch (test_mode) {
+       case 0x0100:
+               /* Test_J */
+               usba_writel(udc, TST, USBA_TST_J_MODE);
+               dev_info(dev, "Entering Test_J mode...\n");
+               break;
+       case 0x0200:
+               /* Test_K */
+               usba_writel(udc, TST, USBA_TST_K_MODE);
+               dev_info(dev, "Entering Test_K mode...\n");
+               break;
+       case 0x0300:
+               /*
+                * Test_SE0_NAK: Force high-speed mode and set up ep0
+                * for Bulk IN transfers
+                */
+               ep = &usba_ep[0];
+               usba_writel(udc, TST,
+                               USBA_BF(SPEED_CFG, USBA_SPEED_CFG_FORCE_HIGH));
+               usba_ep_writel(ep, CFG,
+                               USBA_BF(EPT_SIZE, USBA_EPT_SIZE_64)
+                               | USBA_EPT_DIR_IN
+                               | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK)
+                               | USBA_BF(BK_NUMBER, 1));
+               if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED)) {
+                       set_protocol_stall(udc, ep);
+                       dev_err(dev, "Test_SE0_NAK: ep0 not mapped\n");
+               } else {
+                       usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE);
+                       dev_info(dev, "Entering Test_SE0_NAK mode...\n");
+               }
+               break;
+       case 0x0400:
+               /* Test_Packet */
+               ep = &usba_ep[0];
+               usba_ep_writel(ep, CFG,
+                               USBA_BF(EPT_SIZE, USBA_EPT_SIZE_64)
+                               | USBA_EPT_DIR_IN
+                               | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK)
+                               | USBA_BF(BK_NUMBER, 1));
+               if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED)) {
+                       set_protocol_stall(udc, ep);
+                       dev_err(dev, "Test_Packet: ep0 not mapped\n");
+               } else {
+                       usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE);
+                       usba_writel(udc, TST, USBA_TST_PKT_MODE);
+                       copy_to_fifo(ep->fifo, test_packet_buffer,
+                                       sizeof(test_packet_buffer));
+                       usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+                       dev_info(dev, "Entering Test_Packet mode...\n");
+               }
+               break;
+       default:
+               dev_err(dev, "Invalid test mode: 0x%04x\n", test_mode);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* Avoid overly long expressions */
+static inline bool feature_is_dev_remote_wakeup(struct usb_ctrlrequest *crq)
+{
+       if (crq->wValue == __constant_cpu_to_le16(USB_DEVICE_REMOTE_WAKEUP))
+               return true;
+       return false;
+}
+
+static inline bool feature_is_dev_test_mode(struct usb_ctrlrequest *crq)
+{
+       if (crq->wValue == __constant_cpu_to_le16(USB_DEVICE_TEST_MODE))
+               return true;
+       return false;
+}
+
+static inline bool feature_is_ep_halt(struct usb_ctrlrequest *crq)
+{
+       if (crq->wValue == __constant_cpu_to_le16(USB_ENDPOINT_HALT))
+               return true;
+       return false;
+}
+
+static int handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep,
+               struct usb_ctrlrequest *crq)
+{
+       int retval = 0;;
+
+       switch (crq->bRequest) {
+       case USB_REQ_GET_STATUS: {
+               u16 status;
+
+               if (crq->bRequestType == (USB_DIR_IN | USB_RECIP_DEVICE)) {
+                       status = cpu_to_le16(udc->devstatus);
+               } else if (crq->bRequestType
+                               == (USB_DIR_IN | USB_RECIP_INTERFACE)) {
+                       status = __constant_cpu_to_le16(0);
+               } else if (crq->bRequestType
+                               == (USB_DIR_IN | USB_RECIP_ENDPOINT)) {
+                       struct usba_ep *target;
+
+                       target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex));
+                       if (!target)
+                               goto stall;
+
+                       status = 0;
+                       if (is_stalled(udc, target))
+                               status |= __constant_cpu_to_le16(1);
+               } else
+                       goto delegate;
+
+               /* Write directly to the FIFO. No queueing is done. */
+               if (crq->wLength != __constant_cpu_to_le16(sizeof(status)))
+                       goto stall;
+               ep->state = DATA_STAGE_IN;
+               __raw_writew(status, ep->fifo);
+               usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+               break;
+       }
+
+       case USB_REQ_CLEAR_FEATURE: {
+               if (crq->bRequestType == USB_RECIP_DEVICE) {
+                       if (feature_is_dev_remote_wakeup(crq))
+                               udc->devstatus
+                                       &= ~(1 << USB_DEVICE_REMOTE_WAKEUP);
+                       else
+                               /* Can't CLEAR_FEATURE TEST_MODE */
+                               goto stall;
+               } else if (crq->bRequestType == USB_RECIP_ENDPOINT) {
+                       struct usba_ep *target;
+
+                       if (crq->wLength != __constant_cpu_to_le16(0)
+                                       || !feature_is_ep_halt(crq))
+                               goto stall;
+                       target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex));
+                       if (!target)
+                               goto stall;
+
+                       usba_ep_writel(target, CLR_STA, USBA_FORCE_STALL);
+                       if (target->index != 0)
+                               usba_ep_writel(target, CLR_STA,
+                                               USBA_TOGGLE_CLR);
+               } else {
+                       goto delegate;
+               }
+
+               send_status(udc, ep);
+               break;
+       }
+
+       case USB_REQ_SET_FEATURE: {
+               if (crq->bRequestType == USB_RECIP_DEVICE) {
+                       if (feature_is_dev_test_mode(crq)) {
+                               send_status(udc, ep);
+                               ep->state = STATUS_STAGE_TEST;
+                               udc->test_mode = le16_to_cpu(crq->wIndex);
+                               return 0;
+                       } else if (feature_is_dev_remote_wakeup(crq)) {
+                               udc->devstatus |= 1 << USB_DEVICE_REMOTE_WAKEUP;
+                       } else {
+                               goto stall;
+                       }
+               } else if (crq->bRequestType == USB_RECIP_ENDPOINT) {
+                       struct usba_ep *target;
+
+                       if (crq->wLength != __constant_cpu_to_le16(0)
+                                       || !feature_is_ep_halt(crq))
+                               goto stall;
+
+                       target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex));
+                       if (!target)
+                               goto stall;
+
+                       usba_ep_writel(target, SET_STA, USBA_FORCE_STALL);
+               } else
+                       goto delegate;
+
+               send_status(udc, ep);
+               break;
+       }
+
+       case USB_REQ_SET_ADDRESS:
+               if (crq->bRequestType != (USB_DIR_OUT | USB_RECIP_DEVICE))
+                       goto delegate;
+
+               set_address(udc, le16_to_cpu(crq->wValue));
+               send_status(udc, ep);
+               ep->state = STATUS_STAGE_ADDR;
+               break;
+
+       default:
+delegate:
+               spin_unlock(&udc->lock);
+               retval = udc->driver->setup(&udc->gadget, crq);
+               spin_lock(&udc->lock);
+       }
+
+       return retval;
+
+stall:
+       printk(KERN_ERR
+               "udc: %s: Invalid setup request: %02x.%02x v%04x i%04x l%d, "
+               "halting endpoint...\n",
+               ep->ep.name, crq->bRequestType, crq->bRequest,
+               le16_to_cpu(crq->wValue), le16_to_cpu(crq->wIndex),
+               le16_to_cpu(crq->wLength));
+       set_protocol_stall(udc, ep);
+       return -1;
+}
+
+static void usba_control_irq(struct usba_udc *udc, struct usba_ep *ep)
+{
+       struct usba_request *req;
+       u32 epstatus;
+       u32 epctrl;
+
+restart:
+       epstatus = usba_ep_readl(ep, STA);
+       epctrl = usba_ep_readl(ep, CTL);
+
+       DBG(DBG_INT, "%s [%d]: s/%08x c/%08x\n",
+                       ep->ep.name, ep->state, epstatus, epctrl);
+
+       req = NULL;
+       if (!list_empty(&ep->queue))
+               req = list_entry(ep->queue.next,
+                                struct usba_request, queue);
+
+       if ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) {
+               if (req->submitted)
+                       next_fifo_transaction(ep, req);
+               else
+                       submit_request(ep, req);
+
+               if (req->last_transaction) {
+                       usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
+                       usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
+               }
+               goto restart;
+       }
+       if ((epstatus & epctrl) & USBA_TX_COMPLETE) {
+               usba_ep_writel(ep, CLR_STA, USBA_TX_COMPLETE);
+
+               switch (ep->state) {
+               case DATA_STAGE_IN:
+                       usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY);
+                       usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+                       ep->state = STATUS_STAGE_OUT;
+                       break;
+               case STATUS_STAGE_ADDR:
+                       /* Activate our new address */
+                       usba_writel(udc, CTRL, (usba_readl(udc, CTRL)
+                                               | USBA_FADDR_EN));
+                       usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+                       ep->state = WAIT_FOR_SETUP;
+                       break;
+               case STATUS_STAGE_IN:
+                       if (req) {
+                               list_del_init(&req->queue);
+                               request_complete(ep, req, 0);
+                               submit_next_request(ep);
+                       }
+                       usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+                       ep->state = WAIT_FOR_SETUP;
+                       break;
+               case STATUS_STAGE_TEST:
+                       usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+                       ep->state = WAIT_FOR_SETUP;
+                       if (do_test_mode(udc))
+                               set_protocol_stall(udc, ep);
+                       break;
+               default:
+                       printk(KERN_ERR
+                               "udc: %s: TXCOMP: Invalid endpoint state %d, "
+                               "halting endpoint...\n",
+                               ep->ep.name, ep->state);
+                       set_protocol_stall(udc, ep);
+                       break;
+               }
+
+               goto restart;
+       }
+       if ((epstatus & epctrl) & USBA_RX_BK_RDY) {
+               switch (ep->state) {
+               case STATUS_STAGE_OUT:
+                       usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+                       usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+
+                       if (req) {
+                               list_del_init(&req->queue);
+                               request_complete(ep, req, 0);
+                       }
+                       ep->state = WAIT_FOR_SETUP;
+                       break;
+
+               case DATA_STAGE_OUT:
+                       receive_data(ep);
+                       break;
+
+               default:
+                       usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+                       usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+                       printk(KERN_ERR
+                               "udc: %s: RXRDY: Invalid endpoint state %d, "
+                               "halting endpoint...\n",
+                               ep->ep.name, ep->state);
+                       set_protocol_stall(udc, ep);
+                       break;
+               }
+
+               goto restart;
+       }
+       if (epstatus & USBA_RX_SETUP) {
+               union {
+                       struct usb_ctrlrequest crq;
+                       unsigned long data[2];
+               } crq;
+               unsigned int pkt_len;
+               int ret;
+
+               if (ep->state != WAIT_FOR_SETUP) {
+                       /*
+                        * Didn't expect a SETUP packet at this
+                        * point. Clean up any pending requests (which
+                        * may be successful).
+                        */
+                       int status = -EPROTO;
+
+                       /*
+                        * RXRDY and TXCOMP are dropped when SETUP
+                        * packets arrive.  Just pretend we received
+                        * the status packet.
+                        */
+                       if (ep->state == STATUS_STAGE_OUT
+                                       || ep->state == STATUS_STAGE_IN) {
+                               usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+                               status = 0;
+                       }
+
+                       if (req) {
+                               list_del_init(&req->queue);
+                               request_complete(ep, req, status);
+                       }
+               }
+
+               pkt_len = USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA));
+               DBG(DBG_HW, "Packet length: %u\n", pkt_len);
+               if (pkt_len != sizeof(crq)) {
+                       printk(KERN_WARNING "udc: Invalid packet length %u "
+                               "(expected %lu)\n", pkt_len, sizeof(crq));
+                       set_protocol_stall(udc, ep);
+                       return;
+               }
+
+               DBG(DBG_FIFO, "Copying ctrl request from 0x%p:\n", ep->fifo);
+               copy_from_fifo(crq.data, ep->fifo, sizeof(crq));
+
+               /* Free up one bank in the FIFO so that we can
+                * generate or receive a reply right away. */
+               usba_ep_writel(ep, CLR_STA, USBA_RX_SETUP);
+
+               /* printk(KERN_DEBUG "setup: %d: %02x.%02x\n",
+                       ep->state, crq.crq.bRequestType,
+                       crq.crq.bRequest); */
+
+               if (crq.crq.bRequestType & USB_DIR_IN) {
+                       /*
+                        * The USB 2.0 spec states that "if wLength is
+                        * zero, there is no data transfer phase."
+                        * However, testusb #14 seems to actually
+                        * expect a data phase even if wLength = 0...
+                        */
+                       ep->state = DATA_STAGE_IN;
+               } else {
+                       if (crq.crq.wLength != __constant_cpu_to_le16(0))
+                               ep->state = DATA_STAGE_OUT;
+                       else
+                               ep->state = STATUS_STAGE_IN;
+               }
+
+               ret = -1;
+               if (ep->index == 0)
+                       ret = handle_ep0_setup(udc, ep, &crq.crq);
+               else {
+                       spin_unlock(&udc->lock);
+                       ret = udc->driver->setup(&udc->gadget, &crq.crq);
+                       spin_lock(&udc->lock);
+               }
+
+               DBG(DBG_BUS, "req %02x.%02x, length %d, state %d, ret %d\n",
+                       crq.crq.bRequestType, crq.crq.bRequest,
+                       le16_to_cpu(crq.crq.wLength), ep->state, ret);
+
+               if (ret < 0) {
+                       /* Let the host know that we failed */
+                       set_protocol_stall(udc, ep);
+               }
+       }
+}
+
+static void usba_ep_irq(struct usba_udc *udc, struct usba_ep *ep)
+{
+       struct usba_request *req;
+       u32 epstatus;
+       u32 epctrl;
+
+       epstatus = usba_ep_readl(ep, STA);
+       epctrl = usba_ep_readl(ep, CTL);
+
+       DBG(DBG_INT, "%s: interrupt, status: 0x%08x\n", ep->ep.name, epstatus);
+
+       while ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) {
+               DBG(DBG_BUS, "%s: TX PK ready\n", ep->ep.name);
+
+               if (list_empty(&ep->queue)) {
+                       dev_warn(&udc->pdev->dev, "ep_irq: queue empty\n");
+                       usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
+                       return;
+               }
+
+               req = list_entry(ep->queue.next, struct usba_request, queue);
+
+               if (req->using_dma) {
+                       /* Send a zero-length packet */
+                       usba_ep_writel(ep, SET_STA,
+                                       USBA_TX_PK_RDY);
+                       usba_ep_writel(ep, CTL_DIS,
+                                       USBA_TX_PK_RDY);
+                       list_del_init(&req->queue);
+                       submit_next_request(ep);
+                       request_complete(ep, req, 0);
+               } else {
+                       if (req->submitted)
+                               next_fifo_transaction(ep, req);
+                       else
+                               submit_request(ep, req);
+
+                       if (req->last_transaction) {
+                               list_del_init(&req->queue);
+                               submit_next_request(ep);
+                               request_complete(ep, req, 0);
+                       }
+               }
+
+               epstatus = usba_ep_readl(ep, STA);
+               epctrl = usba_ep_readl(ep, CTL);
+       }
+       if ((epstatus & epctrl) & USBA_RX_BK_RDY) {
+               DBG(DBG_BUS, "%s: RX data ready\n", ep->ep.name);
+               receive_data(ep);
+               usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+       }
+}
+
+static void usba_dma_irq(struct usba_udc *udc, struct usba_ep *ep)
+{
+       struct usba_request *req;
+       u32 status, control, pending;
+
+       status = usba_dma_readl(ep, STATUS);
+       control = usba_dma_readl(ep, CONTROL);
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+       ep->last_dma_status = status;
+#endif
+       pending = status & control;
+       DBG(DBG_INT | DBG_DMA, "dma irq, s/%#08x, c/%#08x\n", status, control);
+
+       if (status & USBA_DMA_CH_EN) {
+               dev_err(&udc->pdev->dev,
+                       "DMA_CH_EN is set after transfer is finished!\n");
+               dev_err(&udc->pdev->dev,
+                       "status=%#08x, pending=%#08x, control=%#08x\n",
+                       status, pending, control);
+
+               /*
+                * try to pretend nothing happened. We might have to
+                * do something here...
+                */
+       }
+
+       if (list_empty(&ep->queue))
+               /* Might happen if a reset comes along at the right moment */
+               return;
+
+       if (pending & (USBA_DMA_END_TR_ST | USBA_DMA_END_BUF_ST)) {
+               req = list_entry(ep->queue.next, struct usba_request, queue);
+               usba_update_req(ep, req, status);
+
+               list_del_init(&req->queue);
+               submit_next_request(ep);
+               request_complete(ep, req, 0);
+       }
+}
+
+static irqreturn_t usba_udc_irq(int irq, void *devid)
+{
+       struct usba_udc *udc = devid;
+       u32 status;
+       u32 dma_status;
+       u32 ep_status;
+
+       spin_lock(&udc->lock);
+
+       status = usba_readl(udc, INT_STA);
+       DBG(DBG_INT, "irq, status=%#08x\n", status);
+
+       if (status & USBA_DET_SUSPEND) {
+               usba_writel(udc, INT_CLR, USBA_DET_SUSPEND);
+               DBG(DBG_BUS, "Suspend detected\n");
+               if (udc->gadget.speed != USB_SPEED_UNKNOWN
+                               && udc->driver && udc->driver->suspend) {
+                       spin_unlock(&udc->lock);
+                       udc->driver->suspend(&udc->gadget);
+                       spin_lock(&udc->lock);
+               }
+       }
+
+       if (status & USBA_WAKE_UP) {
+               usba_writel(udc, INT_CLR, USBA_WAKE_UP);
+               DBG(DBG_BUS, "Wake Up CPU detected\n");
+       }
+
+       if (status & USBA_END_OF_RESUME) {
+               usba_writel(udc, INT_CLR, USBA_END_OF_RESUME);
+               DBG(DBG_BUS, "Resume detected\n");
+               if (udc->gadget.speed != USB_SPEED_UNKNOWN
+                               && udc->driver && udc->driver->resume) {
+                       spin_unlock(&udc->lock);
+                       udc->driver->resume(&udc->gadget);
+                       spin_lock(&udc->lock);
+               }
+       }
+
+       dma_status = USBA_BFEXT(DMA_INT, status);
+       if (dma_status) {
+               int i;
+
+               for (i = 1; i < USBA_NR_ENDPOINTS; i++)
+                       if (dma_status & (1 << i))
+                               usba_dma_irq(udc, &usba_ep[i]);
+       }
+
+       ep_status = USBA_BFEXT(EPT_INT, status);
+       if (ep_status) {
+               int i;
+
+               for (i = 0; i < USBA_NR_ENDPOINTS; i++)
+                       if (ep_status & (1 << i)) {
+                               if (ep_is_control(&usba_ep[i]))
+                                       usba_control_irq(udc, &usba_ep[i]);
+                               else
+                                       usba_ep_irq(udc, &usba_ep[i]);
+                       }
+       }
+
+       if (status & USBA_END_OF_RESET) {
+               struct usba_ep *ep0;
+
+               usba_writel(udc, INT_CLR, USBA_END_OF_RESET);
+               reset_all_endpoints(udc);
+
+               if (status & USBA_HIGH_SPEED) {
+                       DBG(DBG_BUS, "High-speed bus reset detected\n");
+                       udc->gadget.speed = USB_SPEED_HIGH;
+               } else {
+                       DBG(DBG_BUS, "Full-speed bus reset detected\n");
+                       udc->gadget.speed = USB_SPEED_FULL;
+               }
+
+               ep0 = &usba_ep[0];
+               ep0->desc = &usba_ep0_desc;
+               ep0->state = WAIT_FOR_SETUP;
+               usba_ep_writel(ep0, CFG,
+                               (USBA_BF(EPT_SIZE, EP0_EPT_SIZE)
+                               | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL)
+                               | USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE)));
+               usba_ep_writel(ep0, CTL_ENB,
+                               USBA_EPT_ENABLE | USBA_RX_SETUP);
+               usba_writel(udc, INT_ENB,
+                               (usba_readl(udc, INT_ENB)
+                               | USBA_BF(EPT_INT, 1)
+                               | USBA_DET_SUSPEND
+                               | USBA_END_OF_RESUME));
+
+               if (!(usba_ep_readl(ep0, CFG) & USBA_EPT_MAPPED))
+                       dev_warn(&udc->pdev->dev,
+                                "WARNING: EP0 configuration is invalid!\n");
+       }
+
+       spin_unlock(&udc->lock);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t usba_vbus_irq(int irq, void *devid)
+{
+       struct usba_udc *udc = devid;
+       int vbus;
+
+       /* debounce */
+       udelay(10);
+
+       spin_lock(&udc->lock);
+
+       /* May happen if Vbus pin toggles during probe() */
+       if (!udc->driver)
+               goto out;
+
+       vbus = gpio_get_value(udc->vbus_pin);
+       if (vbus != udc->vbus_prev) {
+               if (vbus) {
+                       usba_writel(udc, CTRL, USBA_EN_USBA);
+                       usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
+               } else {
+                       udc->gadget.speed = USB_SPEED_UNKNOWN;
+                       reset_all_endpoints(udc);
+                       usba_writel(udc, CTRL, 0);
+                       spin_unlock(&udc->lock);
+                       udc->driver->disconnect(&udc->gadget);
+                       spin_lock(&udc->lock);
+               }
+               udc->vbus_prev = vbus;
+       }
+
+out:
+       spin_unlock(&udc->lock);
+
+       return IRQ_HANDLED;
+}
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+       struct usba_udc *udc = &the_udc;
+       unsigned long flags;
+       int ret;
+
+       if (!udc->pdev)
+               return -ENODEV;
+
+       spin_lock_irqsave(&udc->lock, flags);
+       if (udc->driver) {
+               spin_unlock_irqrestore(&udc->lock, flags);
+               return -EBUSY;
+       }
+
+       udc->devstatus = 1 << USB_DEVICE_SELF_POWERED;
+       udc->driver = driver;
+       udc->gadget.dev.driver = &driver->driver;
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       clk_enable(udc->pclk);
+       clk_enable(udc->hclk);
+
+       ret = driver->bind(&udc->gadget);
+       if (ret) {
+               DBG(DBG_ERR, "Could not bind to driver %s: error %d\n",
+                       driver->driver.name, ret);
+               goto err_driver_bind;
+       }
+
+       DBG(DBG_GADGET, "registered driver `%s'\n", driver->driver.name);
+
+       udc->vbus_prev = 0;
+       if (udc->vbus_pin != -1)
+               enable_irq(gpio_to_irq(udc->vbus_pin));
+
+       /* If Vbus is present, enable the controller and wait for reset */
+       spin_lock_irqsave(&udc->lock, flags);
+       if (vbus_is_present(udc) && udc->vbus_prev == 0) {
+               usba_writel(udc, CTRL, USBA_EN_USBA);
+               usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
+       }
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       return 0;
+
+err_driver_bind:
+       udc->driver = NULL;
+       udc->gadget.dev.driver = NULL;
+       return ret;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+       struct usba_udc *udc = &the_udc;
+       unsigned long flags;
+
+       if (!udc->pdev)
+               return -ENODEV;
+       if (driver != udc->driver)
+               return -EINVAL;
+
+       if (udc->vbus_pin != -1)
+               disable_irq(gpio_to_irq(udc->vbus_pin));
+
+       spin_lock_irqsave(&udc->lock, flags);
+       udc->gadget.speed = USB_SPEED_UNKNOWN;
+       reset_all_endpoints(udc);
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       /* This will also disable the DP pullup */
+       usba_writel(udc, CTRL, 0);
+
+       driver->unbind(&udc->gadget);
+       udc->gadget.dev.driver = NULL;
+       udc->driver = NULL;
+
+       clk_disable(udc->hclk);
+       clk_disable(udc->pclk);
+
+       DBG(DBG_GADGET, "unregistered driver `%s'\n", driver->driver.name);
+
+       return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+static int __init usba_udc_probe(struct platform_device *pdev)
+{
+       struct usba_platform_data *pdata = pdev->dev.platform_data;
+       struct resource *regs, *fifo;
+       struct clk *pclk, *hclk;
+       struct usba_udc *udc = &the_udc;
+       int irq, ret, i;
+
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, CTRL_IOMEM_ID);
+       fifo = platform_get_resource(pdev, IORESOURCE_MEM, FIFO_IOMEM_ID);
+       if (!regs || !fifo)
+               return -ENXIO;
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0)
+               return irq;
+
+       pclk = clk_get(&pdev->dev, "pclk");
+       if (IS_ERR(pclk))
+               return PTR_ERR(pclk);
+       hclk = clk_get(&pdev->dev, "hclk");
+       if (IS_ERR(hclk)) {
+               ret = PTR_ERR(hclk);
+               goto err_get_hclk;
+       }
+
+       udc->pdev = pdev;
+       udc->pclk = pclk;
+       udc->hclk = hclk;
+       udc->vbus_pin = -1;
+
+       ret = -ENOMEM;
+       udc->regs = ioremap(regs->start, regs->end - regs->start + 1);
+       if (!udc->regs) {
+               dev_err(&pdev->dev, "Unable to map I/O memory, aborting.\n");
+               goto err_map_regs;
+       }
+       dev_info(&pdev->dev, "MMIO registers at 0x%08lx mapped at %p\n",
+                (unsigned long)regs->start, udc->regs);
+       udc->fifo = ioremap(fifo->start, fifo->end - fifo->start + 1);
+       if (!udc->fifo) {
+               dev_err(&pdev->dev, "Unable to map FIFO, aborting.\n");
+               goto err_map_fifo;
+       }
+       dev_info(&pdev->dev, "FIFO at 0x%08lx mapped at %p\n",
+                (unsigned long)fifo->start, udc->fifo);
+
+       device_initialize(&udc->gadget.dev);
+       udc->gadget.dev.parent = &pdev->dev;
+       udc->gadget.dev.dma_mask = pdev->dev.dma_mask;
+
+       platform_set_drvdata(pdev, udc);
+
+       /* Make sure we start from a clean slate */
+       clk_enable(pclk);
+       usba_writel(udc, CTRL, 0);
+       clk_disable(pclk);
+
+       INIT_LIST_HEAD(&usba_ep[0].ep.ep_list);
+       usba_ep[0].ep_regs = udc->regs + USBA_EPT_BASE(0);
+       usba_ep[0].dma_regs = udc->regs + USBA_DMA_BASE(0);
+       usba_ep[0].fifo = udc->fifo + USBA_FIFO_BASE(0);
+       for (i = 1; i < ARRAY_SIZE(usba_ep); i++) {
+               struct usba_ep *ep = &usba_ep[i];
+
+               ep->ep_regs = udc->regs + USBA_EPT_BASE(i);
+               ep->dma_regs = udc->regs + USBA_DMA_BASE(i);
+               ep->fifo = udc->fifo + USBA_FIFO_BASE(i);
+
+               list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+       }
+
+       ret = request_irq(irq, usba_udc_irq, 0, "atmel_usba_udc", udc);
+       if (ret) {
+               dev_err(&pdev->dev, "Cannot request irq %d (error %d)\n",
+                       irq, ret);
+               goto err_request_irq;
+       }
+       udc->irq = irq;
+
+       ret = device_add(&udc->gadget.dev);
+       if (ret) {
+               dev_dbg(&pdev->dev, "Could not add gadget: %d\n", ret);
+               goto err_device_add;
+       }
+
+       if (pdata && pdata->vbus_pin != GPIO_PIN_NONE) {
+               if (!gpio_request(pdata->vbus_pin, "atmel_usba_udc")) {
+                       udc->vbus_pin = pdata->vbus_pin;
+
+                       ret = request_irq(gpio_to_irq(udc->vbus_pin),
+                                       usba_vbus_irq, 0,
+                                       "atmel_usba_udc", udc);
+                       if (ret) {
+                               gpio_free(udc->vbus_pin);
+                               udc->vbus_pin = -1;
+                               dev_warn(&udc->pdev->dev,
+                                        "failed to request vbus irq; "
+                                        "assuming always on\n");
+                       } else {
+                               disable_irq(gpio_to_irq(udc->vbus_pin));
+                       }
+               }
+       }
+
+       usba_init_debugfs(udc);
+       for (i = 1; i < ARRAY_SIZE(usba_ep); i++)
+               usba_ep_init_debugfs(udc, &usba_ep[i]);
+
+       return 0;
+
+err_device_add:
+       free_irq(irq, udc);
+err_request_irq:
+       iounmap(udc->fifo);
+err_map_fifo:
+       iounmap(udc->regs);
+err_map_regs:
+       clk_put(hclk);
+err_get_hclk:
+       clk_put(pclk);
+
+       platform_set_drvdata(pdev, NULL);
+
+       return ret;
+}
+
+static int __exit usba_udc_remove(struct platform_device *pdev)
+{
+       struct usba_udc *udc;
+       int i;
+
+       udc = platform_get_drvdata(pdev);
+
+       for (i = 1; i < ARRAY_SIZE(usba_ep); i++)
+               usba_ep_cleanup_debugfs(&usba_ep[i]);
+       usba_cleanup_debugfs(udc);
+
+       if (udc->vbus_pin != -1)
+               gpio_free(udc->vbus_pin);
+
+       free_irq(udc->irq, udc);
+       iounmap(udc->fifo);
+       iounmap(udc->regs);
+       clk_put(udc->hclk);
+       clk_put(udc->pclk);
+
+       device_unregister(&udc->gadget.dev);
+
+       return 0;
+}
+
+static struct platform_driver udc_driver = {
+       .remove         = __exit_p(usba_udc_remove),
+       .driver         = {
+               .name           = "atmel_usba_udc",
+       },
+};
+
+static int __init udc_init(void)
+{
+       return platform_driver_probe(&udc_driver, usba_udc_probe);
+}
+module_init(udc_init);
+
+static void __exit udc_exit(void)
+{
+       platform_driver_unregister(&udc_driver);
+}
+module_exit(udc_exit);
+
+MODULE_DESCRIPTION("Atmel USBA UDC driver");
+MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/atmel_usba_udc.h b/drivers/usb/gadget/atmel_usba_udc.h
new file mode 100644 (file)
index 0000000..a68304e
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ * Driver for the Atmel USBA high speed USB device controller
+ *
+ * Copyright (C) 2005-2007 Atmel Corporation
+ *
+ * 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.
+ */
+#ifndef __LINUX_USB_GADGET_USBA_UDC_H__
+#define __LINUX_USB_GADGET_USBA_UDC_H__
+
+/* USB register offsets */
+#define USBA_CTRL                              0x0000
+#define USBA_FNUM                              0x0004
+#define USBA_INT_ENB                           0x0010
+#define USBA_INT_STA                           0x0014
+#define USBA_INT_CLR                           0x0018
+#define USBA_EPT_RST                           0x001c
+#define USBA_TST                               0x00e0
+
+/* USB endpoint register offsets */
+#define USBA_EPT_CFG                           0x0000
+#define USBA_EPT_CTL_ENB                       0x0004
+#define USBA_EPT_CTL_DIS                       0x0008
+#define USBA_EPT_CTL                           0x000c
+#define USBA_EPT_SET_STA                       0x0014
+#define USBA_EPT_CLR_STA                       0x0018
+#define USBA_EPT_STA                           0x001c
+
+/* USB DMA register offsets */
+#define USBA_DMA_NXT_DSC                       0x0000
+#define USBA_DMA_ADDRESS                       0x0004
+#define USBA_DMA_CONTROL                       0x0008
+#define USBA_DMA_STATUS                                0x000c
+
+/* Bitfields in CTRL */
+#define USBA_DEV_ADDR_OFFSET                   0
+#define USBA_DEV_ADDR_SIZE                     7
+#define USBA_FADDR_EN                          (1 <<  7)
+#define USBA_EN_USBA                           (1 <<  8)
+#define USBA_DETACH                            (1 <<  9)
+#define USBA_REMOTE_WAKE_UP                    (1 << 10)
+
+/* Bitfields in FNUM */
+#define USBA_MICRO_FRAME_NUM_OFFSET            0
+#define USBA_MICRO_FRAME_NUM_SIZE              3
+#define USBA_FRAME_NUMBER_OFFSET               3
+#define USBA_FRAME_NUMBER_SIZE                 11
+#define USBA_FRAME_NUM_ERROR                   (1 << 31)
+
+/* Bitfields in INT_ENB/INT_STA/INT_CLR */
+#define USBA_HIGH_SPEED                                (1 <<  0)
+#define USBA_DET_SUSPEND                       (1 <<  1)
+#define USBA_MICRO_SOF                         (1 <<  2)
+#define USBA_SOF                               (1 <<  3)
+#define USBA_END_OF_RESET                      (1 <<  4)
+#define USBA_WAKE_UP                           (1 <<  5)
+#define USBA_END_OF_RESUME                     (1 <<  6)
+#define USBA_UPSTREAM_RESUME                   (1 <<  7)
+#define USBA_EPT_INT_OFFSET                    8
+#define USBA_EPT_INT_SIZE                      16
+#define USBA_DMA_INT_OFFSET                    24
+#define USBA_DMA_INT_SIZE                      8
+
+/* Bitfields in EPT_RST */
+#define USBA_RST_OFFSET                                0
+#define USBA_RST_SIZE                          16
+
+/* Bitfields in USBA_TST */
+#define USBA_SPEED_CFG_OFFSET                  0
+#define USBA_SPEED_CFG_SIZE                    2
+#define USBA_TST_J_MODE                                (1 <<  2)
+#define USBA_TST_K_MODE                                (1 <<  3)
+#define USBA_TST_PKT_MODE                      (1 <<  4)
+#define USBA_OPMODE2                           (1 <<  5)
+
+/* Bitfields in EPT_CFG */
+#define USBA_EPT_SIZE_OFFSET                   0
+#define USBA_EPT_SIZE_SIZE                     3
+#define USBA_EPT_DIR_IN                                (1 <<  3)
+#define USBA_EPT_TYPE_OFFSET                   4
+#define USBA_EPT_TYPE_SIZE                     2
+#define USBA_BK_NUMBER_OFFSET                  6
+#define USBA_BK_NUMBER_SIZE                    2
+#define USBA_NB_TRANS_OFFSET                   8
+#define USBA_NB_TRANS_SIZE                     2
+#define USBA_EPT_MAPPED                                (1 << 31)
+
+/* Bitfields in EPT_CTL/EPT_CTL_ENB/EPT_CTL_DIS */
+#define USBA_EPT_ENABLE                                (1 <<  0)
+#define USBA_AUTO_VALID                                (1 <<  1)
+#define USBA_INTDIS_DMA                                (1 <<  3)
+#define USBA_NYET_DIS                          (1 <<  4)
+#define USBA_DATAX_RX                          (1 <<  6)
+#define USBA_MDATA_RX                          (1 <<  7)
+/* Bits 8-15 and 31 enable interrupts for respective bits in EPT_STA */
+#define USBA_BUSY_BANK_IE                      (1 << 18)
+
+/* Bitfields in EPT_SET_STA/EPT_CLR_STA/EPT_STA */
+#define USBA_FORCE_STALL                       (1 <<  5)
+#define USBA_TOGGLE_CLR                                (1 <<  6)
+#define USBA_TOGGLE_SEQ_OFFSET                 6
+#define USBA_TOGGLE_SEQ_SIZE                   2
+#define USBA_ERR_OVFLW                         (1 <<  8)
+#define USBA_RX_BK_RDY                         (1 <<  9)
+#define USBA_KILL_BANK                         (1 <<  9)
+#define USBA_TX_COMPLETE                       (1 << 10)
+#define USBA_TX_PK_RDY                         (1 << 11)
+#define USBA_ISO_ERR_TRANS                     (1 << 11)
+#define USBA_RX_SETUP                          (1 << 12)
+#define USBA_ISO_ERR_FLOW                      (1 << 12)
+#define USBA_STALL_SENT                                (1 << 13)
+#define USBA_ISO_ERR_CRC                       (1 << 13)
+#define USBA_ISO_ERR_NBTRANS                   (1 << 13)
+#define USBA_NAK_IN                            (1 << 14)
+#define USBA_ISO_ERR_FLUSH                     (1 << 14)
+#define USBA_NAK_OUT                           (1 << 15)
+#define USBA_CURRENT_BANK_OFFSET               16
+#define USBA_CURRENT_BANK_SIZE                 2
+#define USBA_BUSY_BANKS_OFFSET                 18
+#define USBA_BUSY_BANKS_SIZE                   2
+#define USBA_BYTE_COUNT_OFFSET                 20
+#define USBA_BYTE_COUNT_SIZE                   11
+#define USBA_SHORT_PACKET                      (1 << 31)
+
+/* Bitfields in DMA_CONTROL */
+#define USBA_DMA_CH_EN                         (1 <<  0)
+#define USBA_DMA_LINK                          (1 <<  1)
+#define USBA_DMA_END_TR_EN                     (1 <<  2)
+#define USBA_DMA_END_BUF_EN                    (1 <<  3)
+#define USBA_DMA_END_TR_IE                     (1 <<  4)
+#define USBA_DMA_END_BUF_IE                    (1 <<  5)
+#define USBA_DMA_DESC_LOAD_IE                  (1 <<  6)
+#define USBA_DMA_BURST_LOCK                    (1 <<  7)
+#define USBA_DMA_BUF_LEN_OFFSET                        16
+#define USBA_DMA_BUF_LEN_SIZE                  16
+
+/* Bitfields in DMA_STATUS */
+#define USBA_DMA_CH_ACTIVE                     (1 <<  1)
+#define USBA_DMA_END_TR_ST                     (1 <<  4)
+#define USBA_DMA_END_BUF_ST                    (1 <<  5)
+#define USBA_DMA_DESC_LOAD_ST                  (1 <<  6)
+
+/* Constants for SPEED_CFG */
+#define USBA_SPEED_CFG_NORMAL                  0
+#define USBA_SPEED_CFG_FORCE_HIGH              2
+#define USBA_SPEED_CFG_FORCE_FULL              3
+
+/* Constants for EPT_SIZE */
+#define USBA_EPT_SIZE_8                                0
+#define USBA_EPT_SIZE_16                       1
+#define USBA_EPT_SIZE_32                       2
+#define USBA_EPT_SIZE_64                       3
+#define USBA_EPT_SIZE_128                      4
+#define USBA_EPT_SIZE_256                      5
+#define USBA_EPT_SIZE_512                      6
+#define USBA_EPT_SIZE_1024                     7
+
+/* Constants for EPT_TYPE */
+#define USBA_EPT_TYPE_CONTROL                  0
+#define USBA_EPT_TYPE_ISO                      1
+#define USBA_EPT_TYPE_BULK                     2
+#define USBA_EPT_TYPE_INT                      3
+
+/* Constants for BK_NUMBER */
+#define USBA_BK_NUMBER_ZERO                    0
+#define USBA_BK_NUMBER_ONE                     1
+#define USBA_BK_NUMBER_DOUBLE                  2
+#define USBA_BK_NUMBER_TRIPLE                  3
+
+/* Bit manipulation macros */
+#define USBA_BF(name, value)                                   \
+       (((value) & ((1 << USBA_##name##_SIZE) - 1))            \
+        << USBA_##name##_OFFSET)
+#define USBA_BFEXT(name, value)                                        \
+       (((value) >> USBA_##name##_OFFSET)                      \
+        & ((1 << USBA_##name##_SIZE) - 1))
+#define USBA_BFINS(name, value, old)                           \
+       (((old) & ~(((1 << USBA_##name##_SIZE) - 1)             \
+                   << USBA_##name##_OFFSET))                   \
+        | USBA_BF(name, value))
+
+/* Register access macros */
+#define usba_readl(udc, reg)                                   \
+       __raw_readl((udc)->regs + USBA_##reg)
+#define usba_writel(udc, reg, value)                           \
+       __raw_writel((value), (udc)->regs + USBA_##reg)
+#define usba_ep_readl(ep, reg)                                 \
+       __raw_readl((ep)->ep_regs + USBA_EPT_##reg)
+#define usba_ep_writel(ep, reg, value)                         \
+       __raw_writel((value), (ep)->ep_regs + USBA_EPT_##reg)
+#define usba_dma_readl(ep, reg)                                        \
+       __raw_readl((ep)->dma_regs + USBA_DMA_##reg)
+#define usba_dma_writel(ep, reg, value)                                \
+       __raw_writel((value), (ep)->dma_regs + USBA_DMA_##reg)
+
+/* Calculate base address for a given endpoint or DMA controller */
+#define USBA_EPT_BASE(x)       (0x100 + (x) * 0x20)
+#define USBA_DMA_BASE(x)       (0x300 + (x) * 0x10)
+#define USBA_FIFO_BASE(x)      ((x) << 16)
+
+/* Synth parameters */
+#define USBA_NR_ENDPOINTS      7
+
+#define EP0_FIFO_SIZE          64
+#define EP0_EPT_SIZE           USBA_EPT_SIZE_64
+#define EP0_NR_BANKS           1
+
+/*
+ * REVISIT: Try to eliminate this value. Can we rely on req->mapped to
+ * provide this information?
+ */
+#define DMA_ADDR_INVALID (~(dma_addr_t)0)
+
+#define FIFO_IOMEM_ID  0
+#define CTRL_IOMEM_ID  1
+
+#ifdef DEBUG
+#define DBG_ERR                0x0001  /* report all error returns */
+#define DBG_HW         0x0002  /* debug hardware initialization */
+#define DBG_GADGET     0x0004  /* calls to/from gadget driver */
+#define DBG_INT                0x0008  /* interrupts */
+#define DBG_BUS                0x0010  /* report changes in bus state */
+#define DBG_QUEUE      0x0020  /* debug request queue processing */
+#define DBG_FIFO       0x0040  /* debug FIFO contents */
+#define DBG_DMA                0x0080  /* debug DMA handling */
+#define DBG_REQ                0x0100  /* print out queued request length */
+#define DBG_ALL                0xffff
+#define DBG_NONE       0x0000
+
+#define DEBUG_LEVEL    (DBG_ERR)
+#define DBG(level, fmt, ...)                                   \
+       do {                                                    \
+               if ((level) & DEBUG_LEVEL)                      \
+                       printk(KERN_DEBUG "udc: " fmt, ## __VA_ARGS__); \
+       } while (0)
+#else
+#define DBG(level, fmt...)
+#endif
+
+enum usba_ctrl_state {
+       WAIT_FOR_SETUP,
+       DATA_STAGE_IN,
+       DATA_STAGE_OUT,
+       STATUS_STAGE_IN,
+       STATUS_STAGE_OUT,
+       STATUS_STAGE_ADDR,
+       STATUS_STAGE_TEST,
+};
+/*
+  EP_STATE_IDLE,
+  EP_STATE_SETUP,
+  EP_STATE_IN_DATA,
+  EP_STATE_OUT_DATA,
+  EP_STATE_SET_ADDR_STATUS,
+  EP_STATE_RX_STATUS,
+  EP_STATE_TX_STATUS,
+  EP_STATE_HALT,
+*/
+
+struct usba_dma_desc {
+       dma_addr_t next;
+       dma_addr_t addr;
+       u32 ctrl;
+};
+
+struct usba_ep {
+       int                                     state;
+       void __iomem                            *ep_regs;
+       void __iomem                            *dma_regs;
+       void __iomem                            *fifo;
+       struct usb_ep                           ep;
+       struct usba_udc                         *udc;
+
+       struct list_head                        queue;
+       const struct usb_endpoint_descriptor    *desc;
+
+       u16                                     fifo_size;
+       u8                                      nr_banks;
+       u8                                      index;
+       unsigned int                            can_dma:1;
+       unsigned int                            can_isoc:1;
+       unsigned int                            is_isoc:1;
+       unsigned int                            is_in:1;
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+       u32                                     last_dma_status;
+       struct dentry                           *debugfs_dir;
+       struct dentry                           *debugfs_queue;
+       struct dentry                           *debugfs_dma_status;
+       struct dentry                           *debugfs_state;
+#endif
+};
+
+struct usba_request {
+       struct usb_request                      req;
+       struct list_head                        queue;
+
+       u32                                     ctrl;
+
+       unsigned int                            submitted:1;
+       unsigned int                            last_transaction:1;
+       unsigned int                            using_dma:1;
+       unsigned int                            mapped:1;
+};
+
+struct usba_udc {
+       /* Protect hw registers from concurrent modifications */
+       spinlock_t lock;
+
+       void __iomem *regs;
+       void __iomem *fifo;
+
+       struct usb_gadget gadget;
+       struct usb_gadget_driver *driver;
+       struct platform_device *pdev;
+       int irq;
+       int vbus_pin;
+       struct clk *pclk;
+       struct clk *hclk;
+
+       u16 devstatus;
+
+       u16 test_mode;
+       int vbus_prev;
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+       struct dentry *debugfs_root;
+       struct dentry *debugfs_regs;
+#endif
+};
+
+static inline struct usba_ep *to_usba_ep(struct usb_ep *ep)
+{
+       return container_of(ep, struct usba_ep, ep);
+}
+
+static inline struct usba_request *to_usba_req(struct usb_request *req)
+{
+       return container_of(req, struct usba_request, req);
+}
+
+static inline struct usba_udc *to_usba_udc(struct usb_gadget *gadget)
+{
+       return container_of(gadget, struct usba_udc, gadget);
+}
+
+#define ep_is_control(ep)      ((ep)->index == 0)
+#define ep_is_idle(ep)         ((ep)->state == EP_STATE_IDLE)
+
+#endif /* __LINUX_USB_GADGET_USBA_UDC_H */
index c6760aee1e5c0e7e4449c1e66515e0ff7c109d63..a4e54b2743f008e4368b551db63d87ef88bee11d 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/device.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 
 /**
index d008d1360a7aea6abf391da60a9a8eb0d5c8f5f2..9db2482bdfa2c5c46618697ba09d8ecc901d1f45 100644 (file)
@@ -46,7 +46,7 @@
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/usb.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
@@ -962,13 +962,13 @@ static struct platform_driver dummy_udc_driver = {
 
 static int dummy_urb_enqueue (
        struct usb_hcd                  *hcd,
-       struct usb_host_endpoint        *ep,
        struct urb                      *urb,
        gfp_t                           mem_flags
 ) {
        struct dummy    *dum;
        struct urbp     *urbp;
        unsigned long   flags;
+       int             rc;
 
        if (!urb->transfer_buffer && urb->transfer_buffer_length)
                return -EINVAL;
@@ -980,6 +980,11 @@ static int dummy_urb_enqueue (
 
        dum = hcd_to_dummy (hcd);
        spin_lock_irqsave (&dum->lock, flags);
+       rc = usb_hcd_link_urb_to_ep(hcd, urb);
+       if (rc) {
+               kfree(urbp);
+               goto done;
+       }
 
        if (!dum->udev) {
                dum->udev = urb->dev;
@@ -996,36 +1001,35 @@ static int dummy_urb_enqueue (
        if (!timer_pending (&dum->timer))
                mod_timer (&dum->timer, jiffies + 1);
 
-       spin_unlock_irqrestore (&dum->lock, flags);
-       return 0;
+ done:
+       spin_unlock_irqrestore(&dum->lock, flags);
+       return rc;
 }
 
-static int dummy_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
        struct dummy    *dum;
        unsigned long   flags;
+       int             rc;
 
        /* giveback happens automatically in timer callback,
         * so make sure the callback happens */
        dum = hcd_to_dummy (hcd);
        spin_lock_irqsave (&dum->lock, flags);
-       if (dum->rh_state != DUMMY_RH_RUNNING && !list_empty(&dum->urbp_list))
+
+       rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+       if (!rc && dum->rh_state != DUMMY_RH_RUNNING &&
+                       !list_empty(&dum->urbp_list))
                mod_timer (&dum->timer, jiffies);
-       spin_unlock_irqrestore (&dum->lock, flags);
-       return 0;
-}
 
-static void maybe_set_status (struct urb *urb, int status)
-{
-       spin_lock (&urb->lock);
-       if (urb->status == -EINPROGRESS)
-               urb->status = status;
-       spin_unlock (&urb->lock);
+       spin_unlock_irqrestore (&dum->lock, flags);
+       return rc;
 }
 
 /* transfer up to a frame's worth; caller must own lock */
 static int
-transfer (struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit)
+transfer(struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit,
+               int *status)
 {
        struct dummy_request    *req;
 
@@ -1088,24 +1092,20 @@ top:
                 *
                 * partially filling a buffer optionally blocks queue advances
                 * (so completion handlers can clean up the queue) but we don't
-                * need to emulate such data-in-flight.  so we only show part
-                * of the URB_SHORT_NOT_OK effect: completion status.
+                * need to emulate such data-in-flight.
                 */
                if (is_short) {
                        if (host_len == dev_len) {
                                req->req.status = 0;
-                               maybe_set_status (urb, 0);
+                               *status = 0;
                        } else if (to_host) {
                                req->req.status = 0;
                                if (dev_len > host_len)
-                                       maybe_set_status (urb, -EOVERFLOW);
+                                       *status = -EOVERFLOW;
                                else
-                                       maybe_set_status (urb,
-                                               (urb->transfer_flags
-                                                       & URB_SHORT_NOT_OK)
-                                               ? -EREMOTEIO : 0);
+                                       *status = 0;
                        } else if (!to_host) {
-                               maybe_set_status (urb, 0);
+                               *status = 0;
                                if (host_len > dev_len)
                                        req->req.status = -EOVERFLOW;
                                else
@@ -1119,9 +1119,8 @@ top:
                                req->req.status = 0;
                        if (urb->transfer_buffer_length == urb->actual_length
                                        && !(urb->transfer_flags
-                                               & URB_ZERO_PACKET)) {
-                               maybe_set_status (urb, 0);
-                       }
+                                               & URB_ZERO_PACKET))
+                               *status = 0;
                }
 
                /* device side completion --> continuable */
@@ -1137,7 +1136,7 @@ top:
                }
 
                /* host side completion --> terminate */
-               if (urb->status != -EINPROGRESS)
+               if (*status != -EINPROGRESS)
                        break;
 
                /* rescan to continue with any other queued i/o */
@@ -1248,12 +1247,12 @@ restart:
                u8                      address;
                struct dummy_ep         *ep = NULL;
                int                     type;
+               int                     status = -EINPROGRESS;
 
                urb = urbp->urb;
-               if (urb->status != -EINPROGRESS) {
-                       /* likely it was just unlinked */
+               if (urb->unlinked)
                        goto return_urb;
-               else if (dum->rh_state != DUMMY_RH_RUNNING)
+               else if (dum->rh_state != DUMMY_RH_RUNNING)
                        continue;
                type = usb_pipetype (urb->pipe);
 
@@ -1274,7 +1273,7 @@ restart:
                        dev_dbg (dummy_dev(dum),
                                "no ep configured for urb %p\n",
                                urb);
-                       maybe_set_status (urb, -EPROTO);
+                       status = -EPROTO;
                        goto return_urb;
                }
 
@@ -1289,7 +1288,7 @@ restart:
                        /* NOTE: must not be iso! */
                        dev_dbg (dummy_dev(dum), "ep %s halted, urb %p\n",
                                        ep->ep.name, urb);
-                       maybe_set_status (urb, -EPIPE);
+                       status = -EPIPE;
                        goto return_urb;
                }
                /* FIXME make sure both ends agree on maxpacket */
@@ -1307,7 +1306,7 @@ restart:
                        w_value = le16_to_cpu(setup.wValue);
                        if (le16_to_cpu(setup.wLength) !=
                                        urb->transfer_buffer_length) {
-                               maybe_set_status (urb, -EOVERFLOW);
+                               status = -EOVERFLOW;
                                goto return_urb;
                        }
 
@@ -1337,7 +1336,7 @@ restart:
                                if (setup.bRequestType != Dev_Request)
                                        break;
                                dum->address = w_value;
-                               maybe_set_status (urb, 0);
+                               status = 0;
                                dev_dbg (udc_dev(dum), "set_address = %d\n",
                                                w_value);
                                value = 0;
@@ -1364,7 +1363,7 @@ restart:
                                        if (value == 0) {
                                                dum->devstatus |=
                                                        (1 << w_value);
-                                               maybe_set_status (urb, 0);
+                                               status = 0;
                                        }
 
                                } else if (setup.bRequestType == Ep_Request) {
@@ -1376,7 +1375,7 @@ restart:
                                        }
                                        ep2->halted = 1;
                                        value = 0;
-                                       maybe_set_status (urb, 0);
+                                       status = 0;
                                }
                                break;
                        case USB_REQ_CLEAR_FEATURE:
@@ -1386,7 +1385,7 @@ restart:
                                                dum->devstatus &= ~(1 <<
                                                        USB_DEVICE_REMOTE_WAKEUP);
                                                value = 0;
-                                               maybe_set_status (urb, 0);
+                                               status = 0;
                                                break;
                                        default:
                                                value = -EOPNOTSUPP;
@@ -1401,7 +1400,7 @@ restart:
                                        }
                                        ep2->halted = 0;
                                        value = 0;
-                                       maybe_set_status (urb, 0);
+                                       status = 0;
                                }
                                break;
                        case USB_REQ_GET_STATUS:
@@ -1438,7 +1437,7 @@ restart:
                                        urb->actual_length = min (2,
                                                urb->transfer_buffer_length);
                                        value = 0;
-                                       maybe_set_status (urb, 0);
+                                       status = 0;
                                }
                                break;
                        }
@@ -1465,7 +1464,7 @@ restart:
                                        dev_dbg (udc_dev(dum),
                                                "setup --> %d\n",
                                                value);
-                               maybe_set_status (urb, -EPIPE);
+                               status = -EPIPE;
                                urb->actual_length = 0;
                        }
 
@@ -1482,7 +1481,7 @@ restart:
                         * report random errors, to debug drivers.
                         */
                        limit = max (limit, periodic_bytes (dum, ep));
-                       maybe_set_status (urb, -ENOSYS);
+                       status = -ENOSYS;
                        break;
 
                case PIPE_INTERRUPT:
@@ -1496,23 +1495,23 @@ restart:
                default:
                treat_control_like_bulk:
                        ep->last_io = jiffies;
-                       total = transfer (dum, urb, ep, limit);
+                       total = transfer(dum, urb, ep, limit, &status);
                        break;
                }
 
                /* incomplete transfer? */
-               if (urb->status == -EINPROGRESS)
+               if (status == -EINPROGRESS)
                        continue;
 
 return_urb:
-               urb->hcpriv = NULL;
                list_del (&urbp->urbp_list);
                kfree (urbp);
                if (ep)
                        ep->already_seen = ep->setup_stage = 0;
 
+               usb_hcd_unlink_urb_from_ep(dummy_to_hcd(dum), urb);
                spin_unlock (&dum->lock);
-               usb_hcd_giveback_urb (dummy_to_hcd(dum), urb);
+               usb_hcd_giveback_urb(dummy_to_hcd(dum), urb, status);
                spin_lock (&dum->lock);
 
                goto restart;
index 3aa46cfa66bae3fdae225ad3fd4e862514903e9e..f9d07108bc3048c721efbd11a0a46ff0dceb3b4f 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/string.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include "gadget_chips.h"
 
index f70055473a00b25b4b83cf873de8301d7264449b..9e732bff9df0608670dcf88b5db1f6d2f5b95ce2 100644 (file)
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+/* #define VERBOSE_DEBUG */
 
-// #define DEBUG 1
-// #define VERBOSE
-
-#include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
 #include <linux/utsname.h>
 #include <linux/device.h>
-#include <linux/moduleparam.h>
 #include <linux/ctype.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/unaligned.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/cdc.h>
-#include <linux/usb_gadget.h>
-
-#include <linux/random.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/ethtool.h>
+#include <linux/usb/gadget.h>
 
 #include "gadget_chips.h"
 
@@ -356,15 +334,15 @@ module_param (qmult, uint, S_IRUGO|S_IWUSR);
 #define qlen(gadget) \
        (DEFAULT_QLEN*((gadget->speed == USB_SPEED_HIGH) ? qmult : 1))
 
-/* also defer IRQs on highspeed TX */
-#define TX_DELAY       qmult
-
 static inline int BITRATE(struct usb_gadget *g)
 {
        return (g->speed == USB_SPEED_HIGH) ? HS_BPS : FS_BPS;
 }
 
 #else  /* full speed (low speed doesn't do bulk) */
+
+#define qmult          1
+
 #define        DEVSPEED        USB_SPEED_FULL
 
 #define qlen(gadget) DEFAULT_QLEN
@@ -390,7 +368,7 @@ static inline int BITRATE(struct usb_gadget *g)
        do { } while (0)
 #endif /* DEBUG */
 
-#ifdef VERBOSE
+#ifdef VERBOSE_DEBUG
 #define VDEBUG DEBUG
 #else
 #define VDEBUG(dev,fmt,args...) \
@@ -830,8 +808,6 @@ static const struct usb_descriptor_header *fs_rndis_function [] = {
 };
 #endif
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-
 /*
  * usb 2.0 devices need to expose both high speed and full speed
  * descriptors, unless they only run at full speed.
@@ -934,18 +910,15 @@ static const struct usb_descriptor_header *hs_rndis_function [] = {
 
 
 /* maxpacket and other transfer characteristics vary by speed. */
-#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
-
-#else
-
-/* if there's no high speed support, maxpacket doesn't change. */
-#define ep_desc(g,hs,fs) (((void)(g)), (fs))
-
-static inline void __init hs_subset_descriptors(void)
+static inline struct usb_endpoint_descriptor *
+ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
+               struct usb_endpoint_descriptor *fs)
 {
+       if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+               return hs;
+       return fs;
 }
 
-#endif /* !CONFIG_USB_GADGET_DUALSPEED */
 
 /*-------------------------------------------------------------------------*/
 
@@ -989,22 +962,19 @@ static struct usb_gadget_strings  stringtab = {
  * complications: class descriptors, and an altsetting.
  */
 static int
-config_buf (enum usb_device_speed speed,
-       u8 *buf, u8 type,
-       unsigned index, int is_otg)
+config_buf(struct usb_gadget *g, u8 *buf, u8 type, unsigned index, int is_otg)
 {
        int                                     len;
        const struct usb_config_descriptor      *config;
        const struct usb_descriptor_header      **function;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-       int                             hs = (speed == USB_SPEED_HIGH);
+       int                                     hs = 0;
 
-       if (type == USB_DT_OTHER_SPEED_CONFIG)
-               hs = !hs;
+       if (gadget_is_dualspeed(g)) {
+               hs = (g->speed == USB_SPEED_HIGH);
+               if (type == USB_DT_OTHER_SPEED_CONFIG)
+                       hs = !hs;
+       }
 #define which_fn(t)    (hs ? hs_ ## t ## _function : fs_ ## t ## _function)
-#else
-#define        which_fn(t)     (fs_ ## t ## _function)
-#endif
 
        if (index >= device_desc.bNumConfigurations)
                return -EINVAL;
@@ -1217,7 +1187,7 @@ eth_set_config (struct eth_dev *dev, unsigned number, gfp_t gfp_flags)
                if (number)
                        eth_reset_config (dev);
                usb_gadget_vbus_draw(dev->gadget,
-                               dev->gadget->is_otg ? 8 : 100);
+                               gadget_is_otg(dev->gadget) ? 8 : 100);
        } else {
                char *speed;
                unsigned power;
@@ -1399,24 +1369,22 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                        value = min (wLength, (u16) sizeof device_desc);
                        memcpy (req->buf, &device_desc, value);
                        break;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
                case USB_DT_DEVICE_QUALIFIER:
-                       if (!gadget->is_dualspeed)
+                       if (!gadget_is_dualspeed(gadget))
                                break;
                        value = min (wLength, (u16) sizeof dev_qualifier);
                        memcpy (req->buf, &dev_qualifier, value);
                        break;
 
                case USB_DT_OTHER_SPEED_CONFIG:
-                       if (!gadget->is_dualspeed)
+                       if (!gadget_is_dualspeed(gadget))
                                break;
                        // FALLTHROUGH
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
                case USB_DT_CONFIG:
-                       value = config_buf (gadget->speed, req->buf,
+                       value = config_buf(gadget, req->buf,
                                        wValue >> 8,
                                        wValue & 0xff,
-                                       gadget->is_otg);
+                                       gadget_is_otg(gadget));
                        if (value >= 0)
                                value = min (wLength, (u16) value);
                        break;
@@ -1585,12 +1553,12 @@ done_set_intf:
                                && rndis_control_intf.bInterfaceNumber
                                        == wIndex) {
                        u8 *buf;
+                       u32 n;
 
                        /* return the result */
-                       buf = rndis_get_next_response (dev->rndis_config,
-                                                      &value);
+                       buf = rndis_get_next_response(dev->rndis_config, &n);
                        if (buf) {
-                               memcpy (req->buf, buf, value);
+                               memcpy(req->buf, buf, n);
                                req->complete = rndis_response_complete;
                                rndis_free_response(dev->rndis_config, buf);
                        }
@@ -1989,8 +1957,20 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
        }
 
        spin_lock_irqsave(&dev->req_lock, flags);
+       /*
+        * this freelist can be empty if an interrupt triggered disconnect()
+        * and reconfigured the gadget (shutting down this queue) after the
+        * network stack decided to xmit but before we got the spinlock.
+        */
+       if (list_empty(&dev->tx_reqs)) {
+               spin_unlock_irqrestore(&dev->req_lock, flags);
+               return 1;
+       }
+
        req = container_of (dev->tx_reqs.next, struct usb_request, list);
        list_del (&req->list);
+
+       /* temporarily stop TX queue when the freelist empties */
        if (list_empty (&dev->tx_reqs))
                netif_stop_queue (net);
        spin_unlock_irqrestore(&dev->req_lock, flags);
@@ -2026,12 +2006,11 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
 
        req->length = length;
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
        /* throttle highspeed IRQ rate back slightly */
-       req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH)
-               ? ((atomic_read (&dev->tx_qlen) % TX_DELAY) != 0)
-               : 0;
-#endif
+       if (gadget_is_dualspeed(dev->gadget))
+               req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH)
+                       ? ((atomic_read(&dev->tx_qlen) % qmult) != 0)
+                       : 0;
 
        retval = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC);
        switch (retval) {
@@ -2188,8 +2167,7 @@ static int eth_stop (struct net_device *net)
        }
 
        if (rndis_active(dev)) {
-               rndis_set_param_medium (dev->rndis_config,
-                                       NDIS_MEDIUM_802_3, 0);
+               rndis_set_param_medium(dev->rndis_config, NDIS_MEDIUM_802_3, 0);
                (void) rndis_signal_disconnect (dev->rndis_config);
        }
 
@@ -2443,26 +2421,28 @@ autoconf_fail:
        if (rndis)
                device_desc.bNumConfigurations = 2;
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-       if (rndis)
-               dev_qualifier.bNumConfigurations = 2;
-       else if (!cdc)
-               dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC;
+       if (gadget_is_dualspeed(gadget)) {
+               if (rndis)
+                       dev_qualifier.bNumConfigurations = 2;
+               else if (!cdc)
+                       dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC;
 
-       /* assumes ep0 uses the same value for both speeds ... */
-       dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
+               /* assumes ep0 uses the same value for both speeds ... */
+               dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
 
-       /* and that all endpoints are dual-speed */
-       hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
-       hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
+               /* and that all endpoints are dual-speed */
+               hs_source_desc.bEndpointAddress =
+                               fs_source_desc.bEndpointAddress;
+               hs_sink_desc.bEndpointAddress =
+                               fs_sink_desc.bEndpointAddress;
 #if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
-       if (status_ep)
-               hs_status_desc.bEndpointAddress =
-                               fs_status_desc.bEndpointAddress;
+               if (status_ep)
+                       hs_status_desc.bEndpointAddress =
+                                       fs_status_desc.bEndpointAddress;
 #endif
-#endif /* DUALSPEED */
+       }
 
-       if (gadget->is_otg) {
+       if (gadget_is_otg(gadget)) {
                otg_descriptor.bmAttributes |= USB_OTG_HNP,
                eth_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
                eth_config.bMaxPower = 4;
@@ -2598,12 +2578,11 @@ fail0:
                if (rndis_set_param_dev (dev->rndis_config, dev->net,
                                         &dev->stats, &dev->cdc_filter))
                        goto fail0;
-               if (rndis_set_param_vendor (dev->rndis_config, vendorID,
-                                           manufacturer))
+               if (rndis_set_param_vendor(dev->rndis_config, vendorID,
+                                       manufacturer))
                        goto fail0;
-               if (rndis_set_param_medium (dev->rndis_config,
-                                           NDIS_MEDIUM_802_3,
-                                           0))
+               if (rndis_set_param_medium(dev->rndis_config,
+                                       NDIS_MEDIUM_802_3, 0))
                        goto fail0;
                INFO (dev, "RNDIS ready\n");
        }
index 965ad7bec7b7a2f19b3e9ad9757aae2ff5b8a9c3..73726c570a6eeb01cc41d91cb5230a256e57729e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * file_storage.c -- File-backed USB Storage Gadget, for USB development
  *
- * Copyright (C) 2003-2005 Alan Stern
+ * Copyright (C) 2003-2007 Alan Stern
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  */
 
 
-#undef DEBUG
-#undef VERBOSE
-#undef DUMP_MSGS
-
+/* #define VERBOSE_DEBUG */
+/* #define DUMP_MSGS */
 
-#include <asm/system.h>
-#include <asm/uaccess.h>
 
-#include <linux/bitops.h>
 #include <linux/blkdev.h>
-#include <linux/compiler.h>
 #include <linux/completion.h>
 #include <linux/dcache.h>
 #include <linux/delay.h>
 #include <linux/fcntl.h>
 #include <linux/file.h>
 #include <linux/fs.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
 #include <linux/kref.h>
 #include <linux/kthread.h>
 #include <linux/limits.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/pagemap.h>
 #include <linux/rwsem.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/string.h>
 #include <linux/utsname.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include "gadget_chips.h"
 
 
 #define DRIVER_DESC            "File-backed Storage Gadget"
 #define DRIVER_NAME            "g_file_storage"
-#define DRIVER_VERSION         "28 November 2005"
+#define DRIVER_VERSION         "7 August 2007"
 
 static const char longname[] = DRIVER_DESC;
 static const char shortname[] = DRIVER_NAME;
@@ -289,57 +275,48 @@ MODULE_LICENSE("Dual BSD/GPL");
 
 /*-------------------------------------------------------------------------*/
 
-#define xprintk(f,level,fmt,args...) \
-       dev_printk(level , &(f)->gadget->dev , fmt , ## args)
-#define yprintk(l,level,fmt,args...) \
-       dev_printk(level , &(l)->dev , fmt , ## args)
-
 #ifdef DEBUG
-#define DBG(fsg,fmt,args...) \
-       xprintk(fsg , KERN_DEBUG , fmt , ## args)
 #define LDBG(lun,fmt,args...) \
-       yprintk(lun , KERN_DEBUG , fmt , ## args)
+       dev_dbg(&(lun)->dev , fmt , ## args)
 #define MDBG(fmt,args...) \
        printk(KERN_DEBUG DRIVER_NAME ": " fmt , ## args)
 #else
-#define DBG(fsg,fmt,args...) \
-       do { } while (0)
 #define LDBG(lun,fmt,args...) \
        do { } while (0)
 #define MDBG(fmt,args...) \
        do { } while (0)
-#undef VERBOSE
+#undef VERBOSE_DEBUG
 #undef DUMP_MSGS
 #endif /* DEBUG */
 
-#ifdef VERBOSE
-#define VDBG   DBG
+#ifdef VERBOSE_DEBUG
 #define VLDBG  LDBG
 #else
-#define VDBG(fsg,fmt,args...) \
-       do { } while (0)
 #define VLDBG(lun,fmt,args...) \
        do { } while (0)
-#endif /* VERBOSE */
+#endif /* VERBOSE_DEBUG */
 
-#define ERROR(fsg,fmt,args...) \
-       xprintk(fsg , KERN_ERR , fmt , ## args)
 #define LERROR(lun,fmt,args...) \
-       yprintk(lun , KERN_ERR , fmt , ## args)
-
-#define WARN(fsg,fmt,args...) \
-       xprintk(fsg , KERN_WARNING , fmt , ## args)
+       dev_err(&(lun)->dev , fmt , ## args)
 #define LWARN(lun,fmt,args...) \
-       yprintk(lun , KERN_WARNING , fmt , ## args)
-
-#define INFO(fsg,fmt,args...) \
-       xprintk(fsg , KERN_INFO , fmt , ## args)
+       dev_warn(&(lun)->dev , fmt , ## args)
 #define LINFO(lun,fmt,args...) \
-       yprintk(lun , KERN_INFO , fmt , ## args)
+       dev_info(&(lun)->dev , fmt , ## args)
 
 #define MINFO(fmt,args...) \
        printk(KERN_INFO DRIVER_NAME ": " fmt , ## args)
 
+#define DBG(d, fmt, args...) \
+       dev_dbg(&(d)->gadget->dev , fmt , ## args)
+#define VDBG(d, fmt, args...) \
+       dev_vdbg(&(d)->gadget->dev , fmt , ## args)
+#define ERROR(d, fmt, args...) \
+       dev_err(&(d)->gadget->dev , fmt , ## args)
+#define WARN(d, fmt, args...) \
+       dev_warn(&(d)->gadget->dev , fmt , ## args)
+#define INFO(d, fmt, args...) \
+       dev_info(&(d)->gadget->dev , fmt , ## args)
+
 
 /*-------------------------------------------------------------------------*/
 
@@ -350,8 +327,8 @@ MODULE_LICENSE("Dual BSD/GPL");
 static struct {
        char            *file[MAX_LUNS];
        int             ro[MAX_LUNS];
-       int             num_filenames;
-       int             num_ros;
+       unsigned int    num_filenames;
+       unsigned int    num_ros;
        unsigned int    nluns;
 
        int             removable;
@@ -578,7 +555,7 @@ struct lun {
 
 #define backing_file_is_open(curlun)   ((curlun)->filp != NULL)
 
-static inline struct lun *dev_to_lun(struct device *dev)
+static struct lun *dev_to_lun(struct device *dev)
 {
        return container_of(dev, struct lun, dev);
 }
@@ -711,13 +688,13 @@ struct fsg_dev {
 
 typedef void (*fsg_routine_t)(struct fsg_dev *);
 
-static int inline exception_in_progress(struct fsg_dev *fsg)
+static int exception_in_progress(struct fsg_dev *fsg)
 {
        return (fsg->state > FSG_STATE_IDLE);
 }
 
 /* Make bulk-out requests be divisible by the maxpacket size */
-static void inline set_bulk_out_req_length(struct fsg_dev *fsg,
+static void set_bulk_out_req_length(struct fsg_dev *fsg,
                struct fsg_buffhd *bh, unsigned int length)
 {
        unsigned int    rem;
@@ -743,50 +720,36 @@ static void       close_all_backing_files(struct fsg_dev *fsg);
 static void dump_msg(struct fsg_dev *fsg, const char *label,
                const u8 *buf, unsigned int length)
 {
-       unsigned int    start, num, i;
-       char            line[52], *p;
-
-       if (length >= 512)
-               return;
-       DBG(fsg, "%s, length %u:\n", label, length);
-
-       start = 0;
-       while (length > 0) {
-               num = min(length, 16u);
-               p = line;
-               for (i = 0; i < num; ++i) {
-                       if (i == 8)
-                               *p++ = ' ';
-                       sprintf(p, " %02x", buf[i]);
-                       p += 3;
-               }
-               *p = 0;
-               printk(KERN_DEBUG "%6x: %s\n", start, line);
-               buf += num;
-               start += num;
-               length -= num;
+       if (length < 512) {
+               DBG(fsg, "%s, length %u:\n", label, length);
+               print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET,
+                               16, 1, buf, length, 0);
        }
 }
 
-static void inline dump_cdb(struct fsg_dev *fsg)
+static void dump_cdb(struct fsg_dev *fsg)
 {}
 
 #else
 
-static void inline dump_msg(struct fsg_dev *fsg, const char *label,
+static void dump_msg(struct fsg_dev *fsg, const char *label,
                const u8 *buf, unsigned int length)
 {}
 
-static void inline dump_cdb(struct fsg_dev *fsg)
-{
-       int     i;
-       char    cmdbuf[3*MAX_COMMAND_SIZE + 1];
+#ifdef VERBOSE_DEBUG
 
-       for (i = 0; i < fsg->cmnd_size; ++i)
-               sprintf(cmdbuf + i*3, " %02x", fsg->cmnd[i]);
-       VDBG(fsg, "SCSI CDB: %s\n", cmdbuf);
+static void dump_cdb(struct fsg_dev *fsg)
+{
+       print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE,
+                       16, 1, fsg->cmnd, fsg->cmnd_size, 0);
 }
 
+#else
+
+static void dump_cdb(struct fsg_dev *fsg)
+{}
+
+#endif /* VERBOSE_DEBUG */
 #endif /* DUMP_MSGS */
 
 
@@ -809,24 +772,24 @@ static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep)
 
 /* Routines for unaligned data access */
 
-static u16 inline get_be16(u8 *buf)
+static u16 get_be16(u8 *buf)
 {
        return ((u16) buf[0] << 8) | ((u16) buf[1]);
 }
 
-static u32 inline get_be32(u8 *buf)
+static u32 get_be32(u8 *buf)
 {
        return ((u32) buf[0] << 24) | ((u32) buf[1] << 16) |
                        ((u32) buf[2] << 8) | ((u32) buf[3]);
 }
 
-static void inline put_be16(u8 *buf, u16 val)
+static void put_be16(u8 *buf, u16 val)
 {
        buf[0] = val >> 8;
        buf[1] = val;
 }
 
-static void inline put_be32(u8 *buf, u32 val)
+static void put_be32(u8 *buf, u32 val)
 {
        buf[0] = val >> 24;
        buf[1] = val >> 16;
@@ -950,8 +913,6 @@ static const struct usb_descriptor_header *fs_function[] = {
 #define FS_FUNCTION_PRE_EP_ENTRIES     2
 
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-
 /*
  * USB 2.0 devices need to expose both high speed and full speed
  * descriptors, unless they only run at full speed.
@@ -1014,14 +975,14 @@ static const struct usb_descriptor_header *hs_function[] = {
 #define HS_FUNCTION_PRE_EP_ENTRIES     2
 
 /* Maxpacket and other transfer characteristics vary by speed. */
-#define ep_desc(g,fs,hs)       (((g)->speed==USB_SPEED_HIGH) ? (hs) : (fs))
-
-#else
-
-/* If there's no high speed support, always use the full-speed descriptor. */
-#define ep_desc(g,fs,hs)       fs
-
-#endif /* !CONFIG_USB_GADGET_DUALSPEED */
+static struct usb_endpoint_descriptor *
+ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
+               struct usb_endpoint_descriptor *hs)
+{
+       if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+               return hs;
+       return fs;
+}
 
 
 /* The CBI specification limits the serial string to 12 uppercase hexadecimal
@@ -1053,26 +1014,22 @@ static struct usb_gadget_strings        stringtab = {
 static int populate_config_buf(struct usb_gadget *gadget,
                u8 *buf, u8 type, unsigned index)
 {
-#ifdef CONFIG_USB_GADGET_DUALSPEED
        enum usb_device_speed                   speed = gadget->speed;
-#endif
        int                                     len;
        const struct usb_descriptor_header      **function;
 
        if (index > 0)
                return -EINVAL;
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-       if (type == USB_DT_OTHER_SPEED_CONFIG)
+       if (gadget_is_dualspeed(gadget) && type == USB_DT_OTHER_SPEED_CONFIG)
                speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed;
-       if (speed == USB_SPEED_HIGH)
+       if (gadget_is_dualspeed(gadget) && speed == USB_SPEED_HIGH)
                function = hs_function;
        else
-#endif
                function = fs_function;
 
        /* for now, don't advertise srp-only devices */
-       if (!gadget->is_otg)
+       if (!gadget_is_otg(gadget))
                function++;
 
        len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function);
@@ -1394,10 +1351,9 @@ static int standard_setup_req(struct fsg_dev *fsg,
                        value = sizeof device_desc;
                        memcpy(req->buf, &device_desc, value);
                        break;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
                case USB_DT_DEVICE_QUALIFIER:
                        VDBG(fsg, "get device qualifier\n");
-                       if (!fsg->gadget->is_dualspeed)
+                       if (!gadget_is_dualspeed(fsg->gadget))
                                break;
                        value = sizeof dev_qualifier;
                        memcpy(req->buf, &dev_qualifier, value);
@@ -1405,15 +1361,12 @@ static int standard_setup_req(struct fsg_dev *fsg,
 
                case USB_DT_OTHER_SPEED_CONFIG:
                        VDBG(fsg, "get other-speed config descriptor\n");
-                       if (!fsg->gadget->is_dualspeed)
+                       if (!gadget_is_dualspeed(fsg->gadget))
                                break;
                        goto get_config;
-#endif
                case USB_DT_CONFIG:
                        VDBG(fsg, "get configuration descriptor\n");
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-               get_config:
-#endif
+get_config:
                        value = populate_config_buf(fsg->gadget,
                                        req->buf,
                                        w_value >> 8,
@@ -1646,7 +1599,8 @@ static int do_read(struct fsg_dev *fsg)
                /* Wait for the next buffer to become available */
                bh = fsg->next_buffhd_to_fill;
                while (bh->state != BUF_STATE_EMPTY) {
-                       if ((rc = sleep_thread(fsg)) != 0)
+                       rc = sleep_thread(fsg);
+                       if (rc)
                                return rc;
                }
 
@@ -1885,7 +1839,8 @@ static int do_write(struct fsg_dev *fsg)
                }
 
                /* Wait for something to happen */
-               if ((rc = sleep_thread(fsg)) != 0)
+               rc = sleep_thread(fsg);
+               if (rc)
                        return rc;
        }
 
@@ -2369,7 +2324,8 @@ static int pad_with_zeros(struct fsg_dev *fsg)
 
                /* Wait for the next buffer to be free */
                while (bh->state != BUF_STATE_EMPTY) {
-                       if ((rc = sleep_thread(fsg)) != 0)
+                       rc = sleep_thread(fsg);
+                       if (rc)
                                return rc;
                }
 
@@ -2429,7 +2385,8 @@ static int throw_away_data(struct fsg_dev *fsg)
                }
 
                /* Otherwise wait for something to happen */
-               if ((rc = sleep_thread(fsg)) != 0)
+               rc = sleep_thread(fsg);
+               if (rc)
                        return rc;
        }
        return 0;
@@ -2551,7 +2508,8 @@ static int send_status(struct fsg_dev *fsg)
        /* Wait for the next buffer to become available */
        bh = fsg->next_buffhd_to_fill;
        while (bh->state != BUF_STATE_EMPTY) {
-               if ((rc = sleep_thread(fsg)) != 0)
+               rc = sleep_thread(fsg);
+               if (rc)
                        return rc;
        }
 
@@ -2771,9 +2729,10 @@ static int do_scsi_command(struct fsg_dev *fsg)
        /* Wait for the next buffer to become available for data or status */
        bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill;
        while (bh->state != BUF_STATE_EMPTY) {
-               if ((rc = sleep_thread(fsg)) != 0)
+               rc = sleep_thread(fsg);
+               if (rc)
                        return rc;
-               }
+       }
        fsg->phase_error = 0;
        fsg->short_packet_received = 0;
 
@@ -3005,7 +2964,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
 
        /* Is the CBW meaningful? */
        if (cbw->Lun >= MAX_LUNS || cbw->Flags & ~USB_BULK_IN_FLAG ||
-                       cbw->Length < 6 || cbw->Length > MAX_COMMAND_SIZE) {
+                       cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) {
                DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, "
                                "cmdlen %u\n",
                                cbw->Lun, cbw->Flags, cbw->Length);
@@ -3045,9 +3004,10 @@ static int get_next_command(struct fsg_dev *fsg)
                /* Wait for the next buffer to become available */
                bh = fsg->next_buffhd_to_fill;
                while (bh->state != BUF_STATE_EMPTY) {
-                       if ((rc = sleep_thread(fsg)) != 0)
+                       rc = sleep_thread(fsg);
+                       if (rc)
                                return rc;
-                       }
+               }
 
                /* Queue a request to read a Bulk-only CBW */
                set_bulk_out_req_length(fsg, bh, USB_BULK_CB_WRAP_LEN);
@@ -3061,9 +3021,10 @@ static int get_next_command(struct fsg_dev *fsg)
 
                /* Wait for the CBW to arrive */
                while (bh->state != BUF_STATE_FULL) {
-                       if ((rc = sleep_thread(fsg)) != 0)
+                       rc = sleep_thread(fsg);
+                       if (rc)
                                return rc;
-                       }
+               }
                smp_rmb();
                rc = received_cbw(fsg, bh);
                bh->state = BUF_STATE_EMPTY;
@@ -3072,9 +3033,10 @@ static int get_next_command(struct fsg_dev *fsg)
 
                /* Wait for the next command to arrive */
                while (fsg->cbbuf_cmnd_size == 0) {
-                       if ((rc = sleep_thread(fsg)) != 0)
+                       rc = sleep_thread(fsg);
+                       if (rc)
                                return rc;
-                       }
+               }
 
                /* Is the previous status interrupt request still busy?
                 * The host is allowed to skip reading the status,
@@ -3595,7 +3557,8 @@ static ssize_t show_ro(struct device *dev, struct device_attribute *attr, char *
        return sprintf(buf, "%d\n", curlun->ro);
 }
 
-static ssize_t show_file(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_file(struct device *dev, struct device_attribute *attr,
+               char *buf)
 {
        struct lun      *curlun = dev_to_lun(dev);
        struct fsg_dev  *fsg = dev_get_drvdata(dev);
@@ -3604,8 +3567,8 @@ static ssize_t show_file(struct device *dev, struct device_attribute *attr, char
 
        down_read(&fsg->filesem);
        if (backing_file_is_open(curlun)) {     // Get the complete pathname
-               p = d_path(curlun->filp->f_path.dentry, curlun->filp->f_path.mnt,
-                               buf, PAGE_SIZE - 1);
+               p = d_path(curlun->filp->f_path.dentry,
+                               curlun->filp->f_path.mnt, buf, PAGE_SIZE - 1);
                if (IS_ERR(p))
                        rc = PTR_ERR(p);
                else {
@@ -3623,7 +3586,8 @@ static ssize_t show_file(struct device *dev, struct device_attribute *attr, char
 }
 
 
-static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t store_ro(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
 {
        ssize_t         rc = count;
        struct lun      *curlun = dev_to_lun(dev);
@@ -3647,7 +3611,8 @@ static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const
        return rc;
 }
 
-static ssize_t store_file(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t store_file(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
 {
        struct lun      *curlun = dev_to_lun(dev);
        struct fsg_dev  *fsg = dev_get_drvdata(dev);
@@ -3859,7 +3824,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
        /* Find out how many LUNs there should be */
        i = mod_data.nluns;
        if (i == 0)
-               i = max(mod_data.num_filenames, 1);
+               i = max(mod_data.num_filenames, 1u);
        if (i > MAX_LUNS) {
                ERROR(fsg, "invalid number of LUNs: %d\n", i);
                rc = -EINVAL;
@@ -3944,21 +3909,23 @@ static int __init fsg_bind(struct usb_gadget *gadget)
        intf_desc.bInterfaceProtocol = mod_data.transport_type;
        fs_function[i + FS_FUNCTION_PRE_EP_ENTRIES] = NULL;
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-       hs_function[i + HS_FUNCTION_PRE_EP_ENTRIES] = NULL;
+       if (gadget_is_dualspeed(gadget)) {
+               hs_function[i + HS_FUNCTION_PRE_EP_ENTRIES] = NULL;
 
-       /* Assume ep0 uses the same maxpacket value for both speeds */
-       dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
+               /* Assume ep0 uses the same maxpacket value for both speeds */
+               dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
 
-       /* Assume that all endpoint addresses are the same for both speeds */
-       hs_bulk_in_desc.bEndpointAddress = fs_bulk_in_desc.bEndpointAddress;
-       hs_bulk_out_desc.bEndpointAddress = fs_bulk_out_desc.bEndpointAddress;
-       hs_intr_in_desc.bEndpointAddress = fs_intr_in_desc.bEndpointAddress;
-#endif
+               /* Assume endpoint addresses are the same for both speeds */
+               hs_bulk_in_desc.bEndpointAddress =
+                               fs_bulk_in_desc.bEndpointAddress;
+               hs_bulk_out_desc.bEndpointAddress =
+                               fs_bulk_out_desc.bEndpointAddress;
+               hs_intr_in_desc.bEndpointAddress =
+                               fs_intr_in_desc.bEndpointAddress;
+       }
 
-       if (gadget->is_otg) {
+       if (gadget_is_otg(gadget))
                otg_desc.bmAttributes |= USB_OTG_HNP;
-       }
 
        rc = -ENOMEM;
 
index d57bcfbc08a530b31cdb5e6c75871057c6a794ae..9bb7f64a85cdb9b0e5041f00162b3f89d0b957dd 100644 (file)
@@ -35,7 +35,7 @@
 #include <linux/moduleparam.h>
 #include <linux/device.h>
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 #include <linux/usb/otg.h>
 #include <linux/dma-mapping.h>
 #include <linux/platform_device.h>
@@ -1090,14 +1090,11 @@ static int fsl_vbus_session(struct usb_gadget *gadget, int is_active)
  */
 static int fsl_vbus_draw(struct usb_gadget *gadget, unsigned mA)
 {
-#ifdef CONFIG_USB_OTG
        struct fsl_udc *udc;
 
        udc = container_of(gadget, struct fsl_udc, gadget);
-
        if (udc->transceiver)
                return otg_set_power(udc->transceiver, mA);
-#endif
        return -ENOTSUPP;
 }
 
@@ -1120,7 +1117,7 @@ static int fsl_pullup(struct usb_gadget *gadget, int is_on)
        return 0;
 }
 
-/* defined in usb_gadget.h */
+/* defined in gadget.h */
 static struct usb_gadget_ops fsl_gadget_ops = {
        .get_frame = fsl_get_frame,
        .wakeup = fsl_wakeup,
@@ -1321,7 +1318,7 @@ static void setup_received_irq(struct fsl_udc *udc,
                                | USB_TYPE_STANDARD)) {
                        /* Note: The driver has not include OTG support yet.
                         * This will be set when OTG support is added */
-                       if (!udc->gadget.is_otg)
+                       if (!gadget_is_otg(udc->gadget))
                                break;
                        else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE)
                                udc->gadget.b_hnp_enable = 1;
@@ -1330,6 +1327,8 @@ static void setup_received_irq(struct fsl_udc *udc,
                        else if (setup->bRequest ==
                                        USB_DEVICE_A_ALT_HNP_SUPPORT)
                                udc->gadget.a_alt_hnp_support = 1;
+                       else
+                               break;
                        rc = 0;
                } else
                        break;
@@ -1840,10 +1839,8 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
        if (!driver || driver != udc_controller->driver || !driver->unbind)
                return -EINVAL;
 
-#ifdef CONFIG_USB_OTG
        if (udc_controller->transceiver)
                (void)otg_set_peripheral(udc_controller->transceiver, 0);
-#endif
 
        /* stop DR, disable intr */
        dr_controller_stop(udc_controller);
index 1c5aa49d74327ddff868671d50466d7931c83b30..0689189550bce6cab8b1800c4c161fdc14416e77 100644 (file)
  * http://www.usb.org/developers/devclass_docs/midi10.pdf
  */
 
-#define DEBUG 1
-// #define VERBOSE
+/* #define VERBOSE_DEBUG */
 
-#include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/init.h>
 #include <linux/utsname.h>
 #include <linux/device.h>
-#include <linux/moduleparam.h>
 
 #include <sound/driver.h>
 #include <sound/core.h>
@@ -36,7 +30,7 @@
 #include <sound/rawmidi.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 #include <linux/usb/audio.h>
 #include <linux/usb/midi.h>
 
@@ -139,30 +133,16 @@ struct gmidi_device {
 static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req);
 
 
-#define xprintk(d,level,fmt,args...) \
-       dev_printk(level , &(d)->gadget->dev , fmt , ## args)
-
-#ifdef DEBUG
-#define DBG(dev,fmt,args...) \
-       xprintk(dev , KERN_DEBUG , fmt , ## args)
-#else
-#define DBG(dev,fmt,args...) \
-       do { } while (0)
-#endif /* DEBUG */
-
-#ifdef VERBOSE
-#define VDBG   DBG
-#else
-#define VDBG(dev,fmt,args...) \
-       do { } while (0)
-#endif /* VERBOSE */
-
-#define ERROR(dev,fmt,args...) \
-       xprintk(dev , KERN_ERR , fmt , ## args)
-#define WARN(dev,fmt,args...) \
-       xprintk(dev , KERN_WARNING , fmt , ## args)
-#define INFO(dev,fmt,args...) \
-       xprintk(dev , KERN_INFO , fmt , ## args)
+#define DBG(d, fmt, args...) \
+       dev_dbg(&(d)->gadget->dev , fmt , ## args)
+#define VDBG(d, fmt, args...) \
+       dev_vdbg(&(d)->gadget->dev , fmt , ## args)
+#define ERROR(d, fmt, args...) \
+       dev_err(&(d)->gadget->dev , fmt , ## args)
+#define WARN(d, fmt, args...) \
+       dev_warn(&(d)->gadget->dev , fmt , ## args)
+#define INFO(d, fmt, args...) \
+       dev_info(&(d)->gadget->dev , fmt , ## args)
 
 
 static unsigned buflen = 256;
@@ -425,7 +405,7 @@ static int config_buf(struct usb_gadget *gadget,
        return len;
 }
 
-static struct usb_requestalloc_ep_req(struct usb_ep *ep, unsigned length)
+static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length)
 {
        struct usb_request      *req;
 
@@ -455,7 +435,7 @@ static const uint8_t gmidi_cin_length[] = {
  * Receives a chunk of MIDI data.
  */
 static void gmidi_read_data(struct usb_ep *ep, int cable,
-                                  uint8_tdata, int length)
+                                  uint8_t *data, int length)
 {
        struct gmidi_device *dev = ep->driver_data;
        /* cable is ignored, because for now we only have one. */
@@ -541,7 +521,7 @@ static int set_gmidi_config(struct gmidi_device *dev, gfp_t gfp_flags)
 {
        int err = 0;
        struct usb_request *req;
-       struct usb_epep;
+       struct usb_ep *ep;
        unsigned i;
 
        err = usb_ep_enable(dev->in_ep, &bulk_in_desc);
@@ -628,7 +608,7 @@ gmidi_set_config(struct gmidi_device *dev, unsigned number, gfp_t gfp_flags)
 
        if (gadget_is_sa1100(gadget) && dev->config) {
                /* tx fifo is full, but we can't clear it...*/
-               INFO(dev, "can't change configurations\n");
+               ERROR(dev, "can't change configurations\n");
                return -ESPIPE;
        }
        gmidi_reset_config(dev);
@@ -843,7 +823,7 @@ static void gmidi_disconnect(struct usb_gadget *gadget)
 static void /* __init_or_exit */ gmidi_unbind(struct usb_gadget *gadget)
 {
        struct gmidi_device *dev = get_gadget_data(gadget);
-       struct snd_cardcard;
+       struct snd_card *card;
 
        DBG(dev, "unbind\n");
 
@@ -867,12 +847,12 @@ static int gmidi_snd_free(struct snd_device *device)
        return 0;
 }
 
-static void gmidi_transmit_packet(struct usb_requestreq, uint8_t p0,
+static void gmidi_transmit_packet(struct usb_request *req, uint8_t p0,
                                        uint8_t p1, uint8_t p2, uint8_t p3)
 {
        unsigned length = req->length;
+       u8 *buf = (u8 *)req->buf + length;
 
-       uint8_t* buf = (uint8_t*)req->buf + length;
        buf[0] = p0;
        buf[1] = p1;
        buf[2] = p2;
@@ -883,8 +863,8 @@ static void gmidi_transmit_packet(struct usb_request* req, uint8_t p0,
 /*
  * Converts MIDI commands to USB MIDI packets.
  */
-static void gmidi_transmit_byte(struct usb_requestreq,
-                               struct gmidi_in_portport, uint8_t b)
+static void gmidi_transmit_byte(struct usb_request *req,
+                               struct gmidi_in_port *port, uint8_t b)
 {
        uint8_t p0 = port->cable;
 
@@ -981,10 +961,10 @@ static void gmidi_transmit_byte(struct usb_request* req,
        }
 }
 
-static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req)
+static void gmidi_transmit(struct gmidi_device *dev, struct usb_request *req)
 {
-       struct usb_epep = dev->in_ep;
-       struct gmidi_in_portport = &dev->in_port;
+       struct usb_ep *ep = dev->in_ep;
+       struct gmidi_in_port *port = &dev->in_port;
 
        if (!ep) {
                return;
@@ -1020,14 +1000,14 @@ static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req)
 
 static void gmidi_in_tasklet(unsigned long data)
 {
-       struct gmidi_device* dev = (struct gmidi_device*)data;
+       struct gmidi_device *dev = (struct gmidi_device *)data;
 
        gmidi_transmit(dev, NULL);
 }
 
 static int gmidi_in_open(struct snd_rawmidi_substream *substream)
 {
-       struct gmidi_devicedev = substream->rmidi->private_data;
+       struct gmidi_device *dev = substream->rmidi->private_data;
 
        VDBG(dev, "gmidi_in_open\n");
        dev->in_substream = substream;
@@ -1037,13 +1017,15 @@ static int gmidi_in_open(struct snd_rawmidi_substream *substream)
 
 static int gmidi_in_close(struct snd_rawmidi_substream *substream)
 {
+       struct gmidi_device *dev = substream->rmidi->private_data;
+
        VDBG(dev, "gmidi_in_close\n");
        return 0;
 }
 
 static void gmidi_in_trigger(struct snd_rawmidi_substream *substream, int up)
 {
-       struct gmidi_devicedev = substream->rmidi->private_data;
+       struct gmidi_device *dev = substream->rmidi->private_data;
 
        VDBG(dev, "gmidi_in_trigger %d\n", up);
        dev->in_port.active = up;
@@ -1054,7 +1036,7 @@ static void gmidi_in_trigger(struct snd_rawmidi_substream *substream, int up)
 
 static int gmidi_out_open(struct snd_rawmidi_substream *substream)
 {
-       struct gmidi_devicedev = substream->rmidi->private_data;
+       struct gmidi_device *dev = substream->rmidi->private_data;
 
        VDBG(dev, "gmidi_out_open\n");
        dev->out_substream = substream;
@@ -1063,13 +1045,15 @@ static int gmidi_out_open(struct snd_rawmidi_substream *substream)
 
 static int gmidi_out_close(struct snd_rawmidi_substream *substream)
 {
+       struct gmidi_device *dev = substream->rmidi->private_data;
+
        VDBG(dev, "gmidi_out_close\n");
        return 0;
 }
 
 static void gmidi_out_trigger(struct snd_rawmidi_substream *substream, int up)
 {
-       struct gmidi_devicedev = substream->rmidi->private_data;
+       struct gmidi_device *dev = substream->rmidi->private_data;
 
        VDBG(dev, "gmidi_out_trigger %d\n", up);
        if (up) {
index 349b8166f34acafd6ad8cc599f4cc31931b4f1ce..2ec9d196a8cfdc798232d2d51f1d4aad6686338f 100644 (file)
@@ -37,7 +37,7 @@
 #include <linux/proc_fs.h>
 #include <linux/device.h>
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
index 173004f60feaca1a74b395bbb109141d9ec0d781..47ef8bd58a00c1f99f9ef8a937801bbd12e0095d 100644 (file)
@@ -20,8 +20,7 @@
  */
 
 
-// #define     DEBUG                   /* data to help fault diagnosis */
-// #define     VERBOSE         /* extra debug messages (success too) */
+/* #define VERBOSE_DEBUG */
 
 #include <linux/init.h>
 #include <linux/module.h>
@@ -38,7 +37,7 @@
 #include <linux/moduleparam.h>
 
 #include <linux/usb/gadgetfs.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 
 /*
@@ -253,7 +252,7 @@ static const char *CHIP;
        do { } while (0)
 #endif /* DEBUG */
 
-#ifdef VERBOSE
+#ifdef VERBOSE_DEBUG
 #define VDEBUG DBG
 #else
 #define VDEBUG(dev,fmt,args...) \
@@ -1010,11 +1009,12 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
                        /* assume that was SET_CONFIGURATION */
                        if (dev->current_config) {
                                unsigned power;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-                               if (dev->gadget->speed == USB_SPEED_HIGH)
+
+                               if (gadget_is_dualspeed(dev->gadget)
+                                               && (dev->gadget->speed
+                                                       == USB_SPEED_HIGH))
                                        power = dev->hs_config->bMaxPower;
                                else
-#endif
                                        power = dev->config->bMaxPower;
                                usb_gadget_vbus_draw(dev->gadget, 2 * power);
                        }
@@ -1355,24 +1355,21 @@ static int
 config_buf (struct dev_data *dev, u8 type, unsigned index)
 {
        int             len;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-       int             hs;
-#endif
+       int             hs = 0;
 
        /* only one configuration */
        if (index > 0)
                return -EINVAL;
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-       hs = (dev->gadget->speed == USB_SPEED_HIGH);
-       if (type == USB_DT_OTHER_SPEED_CONFIG)
-               hs = !hs;
+       if (gadget_is_dualspeed(dev->gadget)) {
+               hs = (dev->gadget->speed == USB_SPEED_HIGH);
+               if (type == USB_DT_OTHER_SPEED_CONFIG)
+                       hs = !hs;
+       }
        if (hs) {
                dev->req->buf = dev->hs_config;
                len = le16_to_cpu(dev->hs_config->wTotalLength);
-       } else
-#endif
-       {
+       } else {
                dev->req->buf = dev->config;
                len = le16_to_cpu(dev->config->wTotalLength);
        }
@@ -1393,13 +1390,13 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
        spin_lock (&dev->lock);
        dev->setup_abort = 0;
        if (dev->state == STATE_DEV_UNCONNECTED) {
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-               if (gadget->speed == USB_SPEED_HIGH && dev->hs_config == NULL) {
+               if (gadget_is_dualspeed(gadget)
+                               && gadget->speed == USB_SPEED_HIGH
+                               && dev->hs_config == NULL) {
                        spin_unlock(&dev->lock);
                        ERROR (dev, "no high speed config??\n");
                        return -EINVAL;
                }
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
 
                dev->state = STATE_DEV_CONNECTED;
                dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket;
@@ -1469,13 +1466,12 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                        // user mode expected to disable endpoints
                } else {
                        u8      config, power;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-                       if (gadget->speed == USB_SPEED_HIGH) {
+
+                       if (gadget_is_dualspeed(gadget)
+                                       && gadget->speed == USB_SPEED_HIGH) {
                                config = dev->hs_config->bConfigurationValue;
                                power = dev->hs_config->bMaxPower;
-                       } else
-#endif
-                       {
+                       } else {
                                config = dev->config->bConfigurationValue;
                                power = dev->config->bMaxPower;
                        }
index b3fe197e1eeb1047a77fb306e9dbdfee7b21917c..1ecfd6366b9ab0b8d7b4afb05c540117c700d37b 100644 (file)
@@ -50,7 +50,7 @@
 #include <asm/hardware.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 /*
  * Memory map
index 4b27d12f049db022b7ca8287d5a8f816d4f4cdf0..ebc5536aa271d8ad78b76dcf701670ee76b1982c 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/platform_device.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include "m66592-udc.h"
 
index c3d364ecd4f8e48dbd6f3236bf2eb520f2906272..d5d473f8144b5332a550f07a9ece5df1ab4cc946 100644 (file)
@@ -62,7 +62,7 @@
 #include <linux/moduleparam.h>
 #include <linux/device.h>
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
index 9b0f0925dddf644259865cb9f54ac1a8a2c534cc..87c4f50dfb61b6af50d929efa52cd10ce9db9dc2 100644 (file)
@@ -38,7 +38,7 @@
 #include <linux/moduleparam.h>
 #include <linux/platform_device.h>
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 #include <linux/usb/otg.h>
 #include <linux/dma-mapping.h>
 #include <linux/clk.h>
@@ -1241,19 +1241,15 @@ static void pullup_enable(struct omap_udc *udc)
        udc->gadget.dev.parent->power.power_state = PMSG_ON;
        udc->gadget.dev.power.power_state = PMSG_ON;
        UDC_SYSCON1_REG |= UDC_PULLUP_EN;
-#ifndef CONFIG_USB_OTG
-       if (!cpu_is_omap15xx())
+       if (!gadget_is_otg(udc->gadget) && !cpu_is_omap15xx())
                OTG_CTRL_REG |= OTG_BSESSVLD;
-#endif
        UDC_IRQ_EN_REG = UDC_DS_CHG_IE;
 }
 
 static void pullup_disable(struct omap_udc *udc)
 {
-#ifndef CONFIG_USB_OTG
-       if (!cpu_is_omap15xx())
+       if (!gadget_is_otg(udc->gadget) && !cpu_is_omap15xx())
                OTG_CTRL_REG &= ~OTG_BSESSVLD;
-#endif
        UDC_IRQ_EN_REG = UDC_DS_CHG_IE;
        UDC_SYSCON1_REG &= ~UDC_PULLUP_EN;
 }
@@ -1390,7 +1386,7 @@ static void update_otg(struct omap_udc *udc)
 {
        u16     devstat;
 
-       if (!udc->gadget.is_otg)
+       if (!gadget_is_otg(udc->gadget))
                return;
 
        if (OTG_CTRL_REG & OTG_ID)
index 1407ad1c81288bdfa1343e871bcd5be36d4622bf..3e715082de36fe9789ded4f272184034ca41877f 100644 (file)
@@ -54,7 +54,7 @@
 #include <asm/hardware.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include <asm/mach/udc_pxa2xx.h>
 
index 0be80c635c484c0f9e12ee7e00d9fd7fdbedd29b..e3e90f8a75e7ffca404685058654e3d90df70336 100644 (file)
@@ -42,7 +42,7 @@
 #include <linux/seq_file.h>
 
 #include <linux/usb.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
index ce4d2e09633da520da7188bca1dbd8ad97196784..f5738eb8e76522ae43c12c3c9a8b56f3732a2fe3 100644 (file)
  *
  */
 
-#include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
 #include <linux/utsname.h>
-#include <linux/wait.h>
-#include <linux/proc_fs.h>
 #include <linux/device.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
-#include <linux/mutex.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/unaligned.h>
-#include <asm/uaccess.h>
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/cdc.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include "gadget_chips.h"
 
 #define GS_DEFAULT_PARITY              USB_CDC_NO_PARITY
 #define GS_DEFAULT_CHAR_FORMAT         USB_CDC_1_STOP_BITS
 
-/* select highspeed/fullspeed, hiding highspeed if not configured */
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-#define GS_SPEED_SELECT(is_hs,hs,fs) ((is_hs) ? (hs) : (fs))
-#else
-#define GS_SPEED_SELECT(is_hs,hs,fs) (fs)
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
+/* maxpacket and other transfer characteristics vary by speed. */
+static inline struct usb_endpoint_descriptor *
+choose_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
+               struct usb_endpoint_descriptor *fs)
+{
+       if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+               return hs;
+       return fs;
+}
+
 
 /* debug settings */
-#ifdef GS_DEBUG
+#ifdef DEBUG
 static int debug = 1;
+#else
+#define        debug 0
+#endif
 
 #define gs_debug(format, arg...) \
        do { if (debug) printk(KERN_DEBUG format, ## arg); } while(0)
 #define gs_debug_level(level, format, arg...) \
        do { if (debug>=level) printk(KERN_DEBUG format, ## arg); } while(0)
 
-#else
-
-#define gs_debug(format, arg...) \
-       do { } while(0)
-#define gs_debug_level(level, format, arg...) \
-       do { } while(0)
-
-#endif /* GS_DEBUG */
 
 /* Thanks to NetChip Technologies for donating this product ID.
  *
@@ -147,10 +127,10 @@ struct gs_req_entry {
 
 /* the port structure holds info for each port, one for each minor number */
 struct gs_port {
-       struct gs_dev           *port_dev;      /* pointer to device struct */
+       struct gs_dev           *port_dev;      /* pointer to device struct */
        struct tty_struct       *port_tty;      /* pointer to tty struct */
        spinlock_t              port_lock;
-       int                     port_num;
+       int                     port_num;
        int                     port_open_count;
        int                     port_in_use;    /* open/close in progress */
        wait_queue_head_t       port_write_wait;/* waiting to write */
@@ -188,7 +168,7 @@ static void __exit gs_module_exit(void);
 /* tty driver */
 static int gs_open(struct tty_struct *tty, struct file *file);
 static void gs_close(struct tty_struct *tty, struct file *file);
-static int gs_write(struct tty_struct *tty, 
+static int gs_write(struct tty_struct *tty,
        const unsigned char *buf, int count);
 static void gs_put_char(struct tty_struct *tty, unsigned char ch);
 static void gs_flush_chars(struct tty_struct *tty);
@@ -222,7 +202,7 @@ static void gs_setup_complete(struct usb_ep *ep, struct usb_request *req);
 static void gs_disconnect(struct usb_gadget *gadget);
 static int gs_set_config(struct gs_dev *dev, unsigned config);
 static void gs_reset_config(struct gs_dev *dev);
-static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed,
+static int gs_build_config_buf(u8 *buf, struct usb_gadget *g,
                u8 type, unsigned int index, int is_otg);
 
 static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len,
@@ -415,18 +395,18 @@ static const struct usb_cdc_header_desc gs_header_desc = {
 };
 
 static const struct usb_cdc_call_mgmt_descriptor gs_call_mgmt_descriptor = {
-       .bLength =              sizeof(gs_call_mgmt_descriptor),
-       .bDescriptorType =      USB_DT_CS_INTERFACE,
-       .bDescriptorSubType =   USB_CDC_CALL_MANAGEMENT_TYPE,
-       .bmCapabilities =       0,
-       .bDataInterface =       1,      /* index of data interface */
+       .bLength =              sizeof(gs_call_mgmt_descriptor),
+       .bDescriptorType =      USB_DT_CS_INTERFACE,
+       .bDescriptorSubType =   USB_CDC_CALL_MANAGEMENT_TYPE,
+       .bmCapabilities =       0,
+       .bDataInterface =       1,      /* index of data interface */
 };
 
 static struct usb_cdc_acm_descriptor gs_acm_descriptor = {
-       .bLength =              sizeof(gs_acm_descriptor),
-       .bDescriptorType =      USB_DT_CS_INTERFACE,
-       .bDescriptorSubType =   USB_CDC_ACM_TYPE,
-       .bmCapabilities =       0,
+       .bLength =              sizeof(gs_acm_descriptor),
+       .bDescriptorType =      USB_DT_CS_INTERFACE,
+       .bDescriptorSubType =   USB_CDC_ACM_TYPE,
+       .bmCapabilities =       0,
 };
 
 static const struct usb_cdc_union_desc gs_union_desc = {
@@ -436,7 +416,7 @@ static const struct usb_cdc_union_desc gs_union_desc = {
        .bMasterInterface0 =    0,      /* index of control interface */
        .bSlaveInterface0 =     1,      /* index of data interface */
 };
+
 static struct usb_endpoint_descriptor gs_fullspeed_notify_desc = {
        .bLength =              USB_DT_ENDPOINT_SIZE,
        .bDescriptorType =      USB_DT_ENDPOINT,
@@ -482,7 +462,6 @@ static const struct usb_descriptor_header *gs_acm_fullspeed_function[] = {
        NULL,
 };
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
 static struct usb_endpoint_descriptor gs_highspeed_notify_desc = {
        .bLength =              USB_DT_ENDPOINT_SIZE,
        .bDescriptorType =      USB_DT_ENDPOINT,
@@ -536,15 +515,13 @@ static const struct usb_descriptor_header *gs_acm_highspeed_function[] = {
        NULL,
 };
 
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
-
 
 /* Module */
 MODULE_DESCRIPTION(GS_LONG_NAME);
 MODULE_AUTHOR("Al Borchers");
 MODULE_LICENSE("GPL");
 
-#ifdef GS_DEBUG
+#ifdef DEBUG
 module_param(debug, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on");
 #endif
@@ -915,7 +892,8 @@ static void gs_put_char(struct tty_struct *tty, unsigned char ch)
                return;
        }
 
-       gs_debug("gs_put_char: (%d,%p) char=0x%x, called from %p, %p, %p\n", port->port_num, tty, ch, __builtin_return_address(0), __builtin_return_address(1), __builtin_return_address(2));
+       gs_debug("gs_put_char: (%d,%p) char=0x%x, called from %p\n",
+               port->port_num, tty, ch, __builtin_return_address(0));
 
        spin_lock_irqsave(&port->port_lock, flags);
 
@@ -1116,7 +1094,11 @@ static int gs_send(struct gs_dev *dev)
                len = gs_send_packet(dev, req->buf, ep->maxpacket);
 
                if (len > 0) {
-gs_debug_level(3, "gs_send: len=%d, 0x%2.2x 0x%2.2x 0x%2.2x ...\n", len, *((unsigned char *)req->buf), *((unsigned char *)req->buf+1), *((unsigned char *)req->buf+2));
+                       gs_debug_level(3, "gs_send: len=%d, 0x%2.2x "
+                                       "0x%2.2x 0x%2.2x ...\n", len,
+                                       *((unsigned char *)req->buf),
+                                       *((unsigned char *)req->buf+1),
+                                       *((unsigned char *)req->buf+2));
                        list_del(&req_entry->re_entry);
                        req->length = len;
                        spin_unlock_irqrestore(&dev->dev_lock, flags);
@@ -1269,7 +1251,7 @@ static void gs_read_complete(struct usb_ep *ep, struct usb_request *req)
 
        switch(req->status) {
        case 0:
-               /* normal completion */
+               /* normal completion */
                gs_recv_packet(dev, req->buf, req->actual);
 requeue:
                req->length = ep->maxpacket;
@@ -1406,23 +1388,24 @@ static int __init gs_bind(struct usb_gadget *gadget)
                ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
        gs_device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-       gs_qualifier_desc.bDeviceClass = use_acm
-               ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
-       /* assume ep0 uses the same packet size for both speeds */
-       gs_qualifier_desc.bMaxPacketSize0 = gs_device_desc.bMaxPacketSize0;
-       /* assume endpoints are dual-speed */
-       gs_highspeed_notify_desc.bEndpointAddress =
-               gs_fullspeed_notify_desc.bEndpointAddress;
-       gs_highspeed_in_desc.bEndpointAddress =
-               gs_fullspeed_in_desc.bEndpointAddress;
-       gs_highspeed_out_desc.bEndpointAddress =
-               gs_fullspeed_out_desc.bEndpointAddress;
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
+       if (gadget_is_dualspeed(gadget)) {
+               gs_qualifier_desc.bDeviceClass = use_acm
+                       ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
+               /* assume ep0 uses the same packet size for both speeds */
+               gs_qualifier_desc.bMaxPacketSize0 =
+                       gs_device_desc.bMaxPacketSize0;
+               /* assume endpoints are dual-speed */
+               gs_highspeed_notify_desc.bEndpointAddress =
+                       gs_fullspeed_notify_desc.bEndpointAddress;
+               gs_highspeed_in_desc.bEndpointAddress =
+                       gs_fullspeed_in_desc.bEndpointAddress;
+               gs_highspeed_out_desc.bEndpointAddress =
+                       gs_fullspeed_out_desc.bEndpointAddress;
+       }
 
        usb_gadget_set_selfpowered(gadget);
 
-       if (gadget->is_otg) {
+       if (gadget_is_otg(gadget)) {
                gs_otg_descriptor.bmAttributes |= USB_OTG_HNP,
                gs_bulk_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
                gs_acm_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
@@ -1487,6 +1470,12 @@ static void /* __init_or_exit */ gs_unbind(struct usb_gadget *gadget)
                        dev->dev_ctrl_req = NULL;
                }
                gs_free_ports(dev);
+               if (dev->dev_notify_ep)
+                       usb_ep_disable(dev->dev_notify_ep);
+               if (dev->dev_in_ep)
+                       usb_ep_disable(dev->dev_in_ep);
+               if (dev->dev_out_ep)
+                       usb_ep_disable(dev->dev_out_ep);
                kfree(dev);
                set_gadget_data(gadget, NULL);
        }
@@ -1570,9 +1559,8 @@ static int gs_setup_standard(struct usb_gadget *gadget,
                        memcpy(req->buf, &gs_device_desc, ret);
                        break;
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
                case USB_DT_DEVICE_QUALIFIER:
-                       if (!gadget->is_dualspeed)
+                       if (!gadget_is_dualspeed(gadget))
                                break;
                        ret = min(wLength,
                                (u16)sizeof(struct usb_qualifier_descriptor));
@@ -1580,14 +1568,13 @@ static int gs_setup_standard(struct usb_gadget *gadget,
                        break;
 
                case USB_DT_OTHER_SPEED_CONFIG:
-                       if (!gadget->is_dualspeed)
+                       if (!gadget_is_dualspeed(gadget))
                                break;
                        /* fall through */
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
                case USB_DT_CONFIG:
-                       ret = gs_build_config_buf(req->buf, gadget->speed,
+                       ret = gs_build_config_buf(req->buf, gadget,
                                wValue >> 8, wValue & 0xff,
-                               gadget->is_otg);
+                               gadget_is_otg(gadget));
                        if (ret >= 0)
                                ret = min(wLength, (u16)ret);
                        break;
@@ -1827,8 +1814,7 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
 
                if (EP_NOTIFY_NAME
                && strcmp(ep->name, EP_NOTIFY_NAME) == 0) {
-                       ep_desc = GS_SPEED_SELECT(
-                               gadget->speed == USB_SPEED_HIGH,
+                       ep_desc = choose_ep_desc(gadget,
                                &gs_highspeed_notify_desc,
                                &gs_fullspeed_notify_desc);
                        ret = usb_ep_enable(ep,ep_desc);
@@ -1844,9 +1830,8 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
                }
 
                else if (strcmp(ep->name, EP_IN_NAME) == 0) {
-                       ep_desc = GS_SPEED_SELECT(
-                               gadget->speed == USB_SPEED_HIGH,
-                               &gs_highspeed_in_desc,
+                       ep_desc = choose_ep_desc(gadget,
+                               &gs_highspeed_in_desc,
                                &gs_fullspeed_in_desc);
                        ret = usb_ep_enable(ep,ep_desc);
                        if (ret == 0) {
@@ -1861,8 +1846,7 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
                }
 
                else if (strcmp(ep->name, EP_OUT_NAME) == 0) {
-                       ep_desc = GS_SPEED_SELECT(
-                               gadget->speed == USB_SPEED_HIGH,
+                       ep_desc = choose_ep_desc(gadget,
                                &gs_highspeed_out_desc,
                                &gs_fullspeed_out_desc);
                        ret = usb_ep_enable(ep,ep_desc);
@@ -1981,11 +1965,11 @@ static void gs_reset_config(struct gs_dev *dev)
  * Builds the config descriptors in the given buffer and returns the
  * length, or a negative error number.
  */
-static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed,
+static int gs_build_config_buf(u8 *buf, struct usb_gadget *g,
        u8 type, unsigned int index, int is_otg)
 {
        int len;
-       int high_speed;
+       int high_speed = 0;
        const struct usb_config_descriptor *config_desc;
        const struct usb_descriptor_header **function;
 
@@ -1993,20 +1977,22 @@ static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed,
                return -EINVAL;
 
        /* other speed switches high and full speed */
-       high_speed = (speed == USB_SPEED_HIGH);
-       if (type == USB_DT_OTHER_SPEED_CONFIG)
-               high_speed = !high_speed;
+       if (gadget_is_dualspeed(g)) {
+               high_speed = (g->speed == USB_SPEED_HIGH);
+               if (type == USB_DT_OTHER_SPEED_CONFIG)
+                       high_speed = !high_speed;
+       }
 
        if (use_acm) {
                config_desc = &gs_acm_config_desc;
-               function = GS_SPEED_SELECT(high_speed,
-                       gs_acm_highspeed_function,
-                       gs_acm_fullspeed_function);
+               function = high_speed
+                       ? gs_acm_highspeed_function
+                       : gs_acm_fullspeed_function;
        } else {
                config_desc = &gs_bulk_config_desc;
-               function = GS_SPEED_SELECT(high_speed,
-                       gs_bulk_highspeed_function,
-                       gs_bulk_fullspeed_function);
+               function = high_speed
+                       ? gs_bulk_highspeed_function
+                       : gs_bulk_fullspeed_function;
        }
 
        /* for now, don't advertise srp-only devices */
index 3459ea6c6c0b4d7bac7bfbd50dbf1153db0ca27d..878e428a0ec12b3fd45c9298b40fa058220f5881 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/init.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include <asm/unaligned.h>
 
index fcfe869acb942bb36dcb742666d285f7de0cd931..fcde5d9c87df11eb6d867f7ff4a3bee075c96bc4 100644 (file)
@@ -1,38 +1,22 @@
 /*
  * zero.c -- Gadget Zero, for USB development
  *
- * Copyright (C) 2003-2004 David Brownell
+ * Copyright (C) 2003-2007 David Brownell
  * All rights reserved.
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
+ * 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.
  *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") as published by the Free Software
- * Foundation, either version 2 of that 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.
  *
- * 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.
+ * 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
  */
 
 
  * Many drivers will only have one configuration, letting them be much
  * simpler if they also don't support high speed operation (like this
  * driver does).
+ *
+ * Why is *this* driver using two configurations, rather than setting up
+ * two interfaces with different functions?  To help verify that multiple
+ * configuration infrastucture is working correctly; also, so that it can
+ * work with low capability USB controllers without four bulk endpoints.
  */
 
-#define DEBUG 1
-// #define VERBOSE
+/* #define VERBOSE_DEBUG */
 
-#include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
 #include <linux/utsname.h>
 #include <linux/device.h>
-#include <linux/moduleparam.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/unaligned.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include "gadget_chips.h"
 
 
 /*-------------------------------------------------------------------------*/
 
-#define DRIVER_VERSION         "St Patrick's Day 2004"
+#define DRIVER_VERSION         "Lughnasadh, 2007"
 
 static const char shortname [] = "zero";
 static const char longname [] = "Gadget Zero";
@@ -131,30 +103,16 @@ struct zero_dev {
        struct timer_list       resume;
 };
 
-#define xprintk(d,level,fmt,args...) \
-       dev_printk(level , &(d)->gadget->dev , fmt , ## args)
-
-#ifdef DEBUG
-#define DBG(dev,fmt,args...) \
-       xprintk(dev , KERN_DEBUG , fmt , ## args)
-#else
-#define DBG(dev,fmt,args...) \
-       do { } while (0)
-#endif /* DEBUG */
-
-#ifdef VERBOSE
-#define VDBG   DBG
-#else
-#define VDBG(dev,fmt,args...) \
-       do { } while (0)
-#endif /* VERBOSE */
-
-#define ERROR(dev,fmt,args...) \
-       xprintk(dev , KERN_ERR , fmt , ## args)
-#define WARN(dev,fmt,args...) \
-       xprintk(dev , KERN_WARNING , fmt , ## args)
-#define INFO(dev,fmt,args...) \
-       xprintk(dev , KERN_INFO , fmt , ## args)
+#define DBG(d, fmt, args...) \
+       dev_dbg(&(d)->gadget->dev , fmt , ## args)
+#define VDBG(d, fmt, args...) \
+       dev_vdbg(&(d)->gadget->dev , fmt , ## args)
+#define ERROR(d, fmt, args...) \
+       dev_err(&(d)->gadget->dev , fmt , ## args)
+#define WARN(d, fmt, args...) \
+       dev_warn(&(d)->gadget->dev , fmt , ## args)
+#define INFO(d, fmt, args...) \
+       dev_info(&(d)->gadget->dev , fmt , ## args)
 
 /*-------------------------------------------------------------------------*/
 
@@ -326,8 +284,6 @@ static const struct usb_descriptor_header *fs_loopback_function [] = {
        NULL,
 };
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-
 /*
  * usb 2.0 devices need to expose both high speed and full speed
  * descriptors, unless they only run at full speed.
@@ -383,17 +339,20 @@ static const struct usb_descriptor_header *hs_loopback_function [] = {
 };
 
 /* maxpacket and other transfer characteristics vary by speed. */
-#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
-
-#else
+static inline struct usb_endpoint_descriptor *
+ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
+               struct usb_endpoint_descriptor *fs)
+{
+       if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+               return hs;
+       return fs;
+}
 
-/* if there's no high speed support, maxpacket doesn't change. */
-#define ep_desc(g,hs,fs) fs
+static char manufacturer[50];
 
-#endif /* !CONFIG_USB_GADGET_DUALSPEED */
+/* default serial number takes at least two packets */
+static char serial[] = "0123456789.0123456789.0123456789";
 
-static char                            manufacturer [50];
-static char                            serial [40];
 
 /* static strings, in UTF-8 */
 static struct usb_string               strings [] = {
@@ -435,30 +394,29 @@ config_buf (struct usb_gadget *gadget,
        int                             is_source_sink;
        int                             len;
        const struct usb_descriptor_header **function;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-       int                             hs = (gadget->speed == USB_SPEED_HIGH);
-#endif
+       int                             hs = 0;
 
        /* two configurations will always be index 0 and index 1 */
        if (index > 1)
                return -EINVAL;
        is_source_sink = loopdefault ? (index == 1) : (index == 0);
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-       if (type == USB_DT_OTHER_SPEED_CONFIG)
-               hs = !hs;
+       if (gadget_is_dualspeed(gadget)) {
+               hs = (gadget->speed == USB_SPEED_HIGH);
+               if (type == USB_DT_OTHER_SPEED_CONFIG)
+                       hs = !hs;
+       }
        if (hs)
                function = is_source_sink
                        ? hs_source_sink_function
                        : hs_loopback_function;
        else
-#endif
                function = is_source_sink
                        ? fs_source_sink_function
                        : fs_loopback_function;
 
        /* for now, don't advertise srp-only devices */
-       if (!gadget->is_otg)
+       if (!gadget_is_otg(gadget))
                function++;
 
        len = usb_gadget_config_buf (is_source_sink
@@ -498,6 +456,19 @@ static void free_ep_req (struct usb_ep *ep, struct usb_request *req)
 
 /*-------------------------------------------------------------------------*/
 
+/*
+ * SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripherals,
+ * this just sinks bulk packets OUT to the peripheral and sources them IN
+ * to the host, optionally with specific data patterns.
+ *
+ * In terms of control messaging, this supports all the standard requests
+ * plus two that support control-OUT tests.
+ *
+ * Note that because this doesn't queue more than one request at a time,
+ * some other function must be used to test queueing logic.  The network
+ * link (g_ether) is probably the best option for that.
+ */
+
 /* optionally require specific source/sink data patterns  */
 
 static int
@@ -534,12 +505,7 @@ check_read_data (
        return 0;
 }
 
-static void
-reinit_write_data (
-       struct zero_dev         *dev,
-       struct usb_ep           *ep,
-       struct usb_request      *req
-)
+static void reinit_write_data(struct usb_ep *ep, struct usb_request *req)
 {
        unsigned        i;
        u8              *buf = req->buf;
@@ -566,16 +532,16 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
 
        switch (status) {
 
-       case 0:                         /* normal completion? */
+       case 0:                         /* normal completion? */
                if (ep == dev->out_ep) {
                        check_read_data (dev, ep, req);
                        memset (req->buf, 0x55, req->length);
                } else
-                       reinit_write_data (dev, ep, req);
+                       reinit_write_data(ep, req);
                break;
 
        /* this endpoint is normally active while we're configured */
-       case -ECONNABORTED:             /* hardware forced ep reset */
+       case -ECONNABORTED:             /* hardware forced ep reset */
        case -ECONNRESET:               /* request dequeued */
        case -ESHUTDOWN:                /* disconnect from host */
                VDBG (dev, "%s gone (%d), %d/%d\n", ep->name, status,
@@ -607,8 +573,7 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
        }
 }
 
-static struct usb_request *
-source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags)
+static struct usb_request *source_sink_start_ep(struct usb_ep *ep)
 {
        struct usb_request      *req;
        int                     status;
@@ -621,11 +586,11 @@ source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags)
        req->complete = source_sink_complete;
 
        if (strcmp (ep->name, EP_IN_NAME) == 0)
-               reinit_write_data (ep->driver_data, ep, req);
+               reinit_write_data(ep, req);
        else
                memset (req->buf, 0x55, req->length);
 
-       status = usb_ep_queue (ep, req, gfp_flags);
+       status = usb_ep_queue(ep, req, GFP_ATOMIC);
        if (status) {
                struct zero_dev *dev = ep->driver_data;
 
@@ -637,8 +602,7 @@ source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags)
        return req;
 }
 
-static int
-set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags)
+static int set_source_sink_config(struct zero_dev *dev)
 {
        int                     result = 0;
        struct usb_ep           *ep;
@@ -653,8 +617,7 @@ set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags)
                        result = usb_ep_enable (ep, d);
                        if (result == 0) {
                                ep->driver_data = dev;
-                               if (source_sink_start_ep(ep, gfp_flags)
-                                               != NULL) {
+                               if (source_sink_start_ep(ep) != NULL) {
                                        dev->in_ep = ep;
                                        continue;
                                }
@@ -668,8 +631,7 @@ set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags)
                        result = usb_ep_enable (ep, d);
                        if (result == 0) {
                                ep->driver_data = dev;
-                               if (source_sink_start_ep(ep, gfp_flags)
-                                               != NULL) {
+                               if (source_sink_start_ep(ep) != NULL) {
                                        dev->out_ep = ep;
                                        continue;
                                }
@@ -701,7 +663,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
 
        switch (status) {
 
-       case 0:                         /* normal completion? */
+       case 0:                         /* normal completion? */
                if (ep == dev->out_ep) {
                        /* loop this OUT packet back IN to the host */
                        req->zero = (req->actual < req->length);
@@ -735,7 +697,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
         * rely on the hardware driver to clean up on disconnect or
         * endpoint disable.
         */
-       case -ECONNABORTED:             /* hardware forced ep reset */
+       case -ECONNABORTED:             /* hardware forced ep reset */
        case -ECONNRESET:               /* request dequeued */
        case -ESHUTDOWN:                /* disconnect from host */
                free_ep_req (ep, req);
@@ -743,8 +705,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
        }
 }
 
-static int
-set_loopback_config (struct zero_dev *dev, gfp_t gfp_flags)
+static int set_loopback_config(struct zero_dev *dev)
 {
        int                     result = 0;
        struct usb_ep           *ep;
@@ -844,8 +805,7 @@ static void zero_reset_config (struct zero_dev *dev)
  * code can do, perhaps by disallowing more than one configuration or
  * by limiting configuration choices (like the pxa2xx).
  */
-static int
-zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags)
+static int zero_set_config(struct zero_dev *dev, unsigned number)
 {
        int                     result = 0;
        struct usb_gadget       *gadget = dev->gadget;
@@ -855,17 +815,17 @@ zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags)
 
        if (gadget_is_sa1100 (gadget) && dev->config) {
                /* tx fifo is full, but we can't clear it...*/
-               INFO (dev, "can't change configurations\n");
+               ERROR(dev, "can't change configurations\n");
                return -ESPIPE;
        }
        zero_reset_config (dev);
 
        switch (number) {
        case CONFIG_SOURCE_SINK:
-               result = set_source_sink_config (dev, gfp_flags);
+               result = set_source_sink_config(dev);
                break;
        case CONFIG_LOOPBACK:
-               result = set_loopback_config (dev, gfp_flags);
+               result = set_loopback_config(dev);
                break;
        default:
                result = -EINVAL;
@@ -885,7 +845,7 @@ zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags)
                case USB_SPEED_LOW:     speed = "low"; break;
                case USB_SPEED_FULL:    speed = "full"; break;
                case USB_SPEED_HIGH:    speed = "high"; break;
-               default:                speed = "?"; break;
+               default:                speed = "?"; break;
                }
 
                dev->config = number;
@@ -938,19 +898,17 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                        value = min (w_length, (u16) sizeof device_desc);
                        memcpy (req->buf, &device_desc, value);
                        break;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
                case USB_DT_DEVICE_QUALIFIER:
-                       if (!gadget->is_dualspeed)
+                       if (!gadget_is_dualspeed(gadget))
                                break;
                        value = min (w_length, (u16) sizeof dev_qualifier);
                        memcpy (req->buf, &dev_qualifier, value);
                        break;
 
                case USB_DT_OTHER_SPEED_CONFIG:
-                       if (!gadget->is_dualspeed)
+                       if (!gadget_is_dualspeed(gadget))
                                break;
                        // FALLTHROUGH
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
                case USB_DT_CONFIG:
                        value = config_buf (gadget, req->buf,
                                        w_value >> 8,
@@ -984,7 +942,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                else
                        VDBG (dev, "HNP inactive\n");
                spin_lock (&dev->lock);
-               value = zero_set_config (dev, w_value, GFP_ATOMIC);
+               value = zero_set_config(dev, w_value);
                spin_unlock (&dev->lock);
                break;
        case USB_REQ_GET_CONFIGURATION:
@@ -1013,7 +971,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                         * use this "reset the config" shortcut.
                         */
                        zero_reset_config (dev);
-                       zero_set_config (dev, config, GFP_ATOMIC);
+                       zero_set_config(dev, config);
                        value = 0;
                }
                spin_unlock (&dev->lock);
@@ -1163,7 +1121,7 @@ autoconf_fail:
        }
        EP_IN_NAME = ep->name;
        ep->driver_data = ep;   /* claim */
-       
+
        ep = usb_ep_autoconfig (gadget, &fs_sink_desc);
        if (!ep)
                goto autoconf_fail;
@@ -1207,16 +1165,18 @@ autoconf_fail:
 
        device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-       /* assume ep0 uses the same value for both speeds ... */
-       dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
+       if (gadget_is_dualspeed(gadget)) {
+               /* assume ep0 uses the same value for both speeds ... */
+               dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
 
-       /* and that all endpoints are dual-speed */
-       hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
-       hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
-#endif
+               /* and that all endpoints are dual-speed */
+               hs_source_desc.bEndpointAddress =
+                               fs_source_desc.bEndpointAddress;
+               hs_sink_desc.bEndpointAddress =
+                               fs_sink_desc.bEndpointAddress;
+       }
 
-       if (gadget->is_otg) {
+       if (gadget_is_otg(gadget)) {
                otg_descriptor.bmAttributes |= USB_OTG_HNP,
                source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
                loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
@@ -1294,23 +1254,18 @@ static struct usb_gadget_driver zero_driver = {
        .suspend        = zero_suspend,
        .resume         = zero_resume,
 
-       .driver         = {
+       .driver         = {
                .name           = (char *) shortname,
                .owner          = THIS_MODULE,
        },
 };
 
-MODULE_AUTHOR ("David Brownell");
-MODULE_LICENSE ("Dual BSD/GPL");
+MODULE_AUTHOR("David Brownell");
+MODULE_LICENSE("GPL");
 
 
 static int __init init (void)
 {
-       /* a real value would likely come through some id prom
-        * or module option.  this one takes at least two packets.
-        */
-       strlcpy (serial, "0123456789.0123456789.0123456789", sizeof serial);
-
        return usb_gadget_register_driver (&zero_driver);
 }
 module_init (init);
index 565d6ef4c4cf5befc157aba3639c83cafa4adabe..c978d622fa8aaa168488550cc479cb17a5aad070 100644 (file)
@@ -154,6 +154,19 @@ config USB_OHCI_HCD_PCI
          Enables support for PCI-bus plug-in USB controller cards.
          If unsure, say Y.
 
+config USB_OHCI_HCD_SSB
+       bool "OHCI support for Broadcom SSB OHCI core"
+       depends on USB_OHCI_HCD && SSB && EXPERIMENTAL
+       default n
+       ---help---
+         Support for the Sonics Silicon Backplane (SSB) attached
+         Broadcom USB OHCI core.
+
+         This device is present in some embedded devices with
+         Broadcom based SSB bus.
+
+         If unsure, say N.
+
 config USB_OHCI_BIG_ENDIAN_DESC
        bool
        depends on USB_OHCI_HCD
index b1d19268cb23df9688be260794ef475bddbe0340..766ef68a0b43a98d81168ec781a9b01623a337f1 100644 (file)
@@ -220,10 +220,8 @@ static const struct hc_driver ehci_au1xxx_hc_driver = {
         */
        .hub_status_data = ehci_hub_status_data,
        .hub_control = ehci_hub_control,
-#ifdef CONFIG_PM
-       .hub_suspend = ehci_hub_suspend,
-       .hub_resume = ehci_hub_resume,
-#endif
+       .bus_suspend = ehci_bus_suspend,
+       .bus_resume = ehci_bus_resume,
 };
 
 /*-------------------------------------------------------------------------*/
index 35cdba10411b3c09bf7a3e72b697cc0f0fef6931..c1514442883e4a4fecd2ff3d3fae3a18c80e8785 100644 (file)
@@ -570,10 +570,18 @@ static int ehci_run (struct usb_hcd *hcd)
         * are explicitly handed to companion controller(s), so no TT is
         * involved with the root hub.  (Except where one is integrated,
         * and there's no companion controller unless maybe for USB OTG.)
+        *
+        * Turning on the CF flag will transfer ownership of all ports
+        * from the companions to the EHCI controller.  If any of the
+        * companions are in the middle of a port reset at the time, it
+        * could cause trouble.  Write-locking ehci_cf_port_reset_rwsem
+        * guarantees that no resets are in progress.
         */
+       down_write(&ehci_cf_port_reset_rwsem);
        hcd->state = HC_STATE_RUNNING;
        ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
        ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
+       up_write(&ehci_cf_port_reset_rwsem);
 
        temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
        ehci_info (ehci,
@@ -719,7 +727,6 @@ dead:
  */
 static int ehci_urb_enqueue (
        struct usb_hcd  *hcd,
-       struct usb_host_endpoint *ep,
        struct urb      *urb,
        gfp_t           mem_flags
 ) {
@@ -734,12 +741,12 @@ static int ehci_urb_enqueue (
        default:
                if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
                        return -ENOMEM;
-               return submit_async (ehci, ep, urb, &qtd_list, mem_flags);
+               return submit_async(ehci, urb, &qtd_list, mem_flags);
 
        case PIPE_INTERRUPT:
                if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
                        return -ENOMEM;
-               return intr_submit (ehci, ep, urb, &qtd_list, mem_flags);
+               return intr_submit(ehci, urb, &qtd_list, mem_flags);
 
        case PIPE_ISOCHRONOUS:
                if (urb->dev->speed == USB_SPEED_HIGH)
@@ -777,13 +784,18 @@ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
  * completions normally happen asynchronously
  */
 
-static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
        struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
        struct ehci_qh          *qh;
        unsigned long           flags;
+       int                     rc;
 
        spin_lock_irqsave (&ehci->lock, flags);
+       rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+       if (rc)
+               goto done;
+
        switch (usb_pipetype (urb->pipe)) {
        // case PIPE_CONTROL:
        // case PIPE_BULK:
@@ -838,7 +850,7 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
        }
 done:
        spin_unlock_irqrestore (&ehci->lock, flags);
-       return 0;
+       return rc;
 }
 
 /*-------------------------------------------------------------------------*/
index a7816e392a8520fb264ee961aafbf4ba14b993eb..ad0d4965f2fb5df834cc54d0f5b6eed29d1e5e3b 100644 (file)
@@ -58,8 +58,6 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)
        if (!retval)
                ehci_dbg(ehci, "MWI active\n");
 
-       ehci_port_power(ehci, 0);
-
        return 0;
 }
 
@@ -156,8 +154,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
                break;
        }
 
-       if (ehci_is_TDI(ehci))
-               ehci_reset(ehci);
+       ehci_reset(ehci);
 
        /* at least the Genesys GL880S needs fixup here */
        temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params);
index 4f99b0eb27bc2bdaea9729897b46c44dae4c763b..452d4b1bc85927e4d21c3bb91caea7e14dc16d8a 100644 (file)
@@ -160,10 +160,8 @@ static const struct hc_driver ehci_ppc_soc_hc_driver = {
         */
        .hub_status_data = ehci_hub_status_data,
        .hub_control = ehci_hub_control,
-#ifdef CONFIG_PM
-       .hub_suspend = ehci_hub_suspend,
-       .hub_resume = ehci_hub_resume,
-#endif
+       .bus_suspend = ehci_bus_suspend,
+       .bus_resume = ehci_bus_resume,
 };
 
 static int ehci_hcd_ppc_soc_drv_probe(struct platform_device *pdev)
index 829fe649a981fdc03ad6f5cb64df4f9f0b8e4024..03a6b2f4e6ed81e722d855ee3bc76bdf6242648e 100644 (file)
@@ -47,7 +47,7 @@ static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
        if (result)
                return result;
 
-       ehci_port_power(ehci, 0);
+       ehci_reset(ehci);
 
        return result;
 }
index 140bfa423e07d39b18815221723b5181654ebd15..b10f39c047e944848f3ac2aa4067e820d2f5df90 100644 (file)
@@ -139,63 +139,65 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh)
 
 /*-------------------------------------------------------------------------*/
 
-static void qtd_copy_status (
+static int qtd_copy_status (
        struct ehci_hcd *ehci,
        struct urb *urb,
        size_t length,
        u32 token
 )
 {
+       int     status = -EINPROGRESS;
+
        /* count IN/OUT bytes, not SETUP (even short packets) */
        if (likely (QTD_PID (token) != 2))
                urb->actual_length += length - QTD_LENGTH (token);
 
        /* don't modify error codes */
-       if (unlikely (urb->status != -EINPROGRESS))
-               return;
+       if (unlikely(urb->unlinked))
+               return status;
 
        /* force cleanup after short read; not always an error */
        if (unlikely (IS_SHORT_READ (token)))
-               urb->status = -EREMOTEIO;
+               status = -EREMOTEIO;
 
        /* serious "can't proceed" faults reported by the hardware */
        if (token & QTD_STS_HALT) {
                if (token & QTD_STS_BABBLE) {
                        /* FIXME "must" disable babbling device's port too */
-                       urb->status = -EOVERFLOW;
+                       status = -EOVERFLOW;
                } else if (token & QTD_STS_MMF) {
                        /* fs/ls interrupt xfer missed the complete-split */
-                       urb->status = -EPROTO;
+                       status = -EPROTO;
                } else if (token & QTD_STS_DBE) {
-                       urb->status = (QTD_PID (token) == 1) /* IN ? */
+                       status = (QTD_PID (token) == 1) /* IN ? */
                                ? -ENOSR  /* hc couldn't read data */
                                : -ECOMM; /* hc couldn't write data */
                } else if (token & QTD_STS_XACT) {
                        /* timeout, bad crc, wrong PID, etc; retried */
                        if (QTD_CERR (token))
-                               urb->status = -EPIPE;
+                               status = -EPIPE;
                        else {
                                ehci_dbg (ehci, "devpath %s ep%d%s 3strikes\n",
                                        urb->dev->devpath,
                                        usb_pipeendpoint (urb->pipe),
                                        usb_pipein (urb->pipe) ? "in" : "out");
-                               urb->status = -EPROTO;
+                               status = -EPROTO;
                        }
                /* CERR nonzero + no errors + halt --> stall */
                } else if (QTD_CERR (token))
-                       urb->status = -EPIPE;
+                       status = -EPIPE;
                else    /* unknown */
-                       urb->status = -EPROTO;
+                       status = -EPROTO;
 
                ehci_vdbg (ehci,
                        "dev%d ep%d%s qtd token %08x --> status %d\n",
                        usb_pipedevice (urb->pipe),
                        usb_pipeendpoint (urb->pipe),
                        usb_pipein (urb->pipe) ? "in" : "out",
-                       token, urb->status);
+                       token, status);
 
                /* if async CSPLIT failed, try cleaning out the TT buffer */
-               if (urb->status != -EPIPE
+               if (status != -EPIPE
                                && urb->dev->tt && !usb_pipeint (urb->pipe)
                                && ((token & QTD_STS_MMF) != 0
                                        || QTD_CERR(token) == 0)
@@ -212,10 +214,12 @@ static void qtd_copy_status (
                        usb_hub_tt_clear_buffer (urb->dev, urb->pipe);
                }
        }
+
+       return status;
 }
 
 static void
-ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb)
+ehci_urb_done(struct ehci_hcd *ehci, struct urb *urb, int status)
 __releases(ehci->lock)
 __acquires(ehci->lock)
 {
@@ -231,25 +235,13 @@ __acquires(ehci->lock)
                qh_put (qh);
        }
 
-       spin_lock (&urb->lock);
-       urb->hcpriv = NULL;
-       switch (urb->status) {
-       case -EINPROGRESS:              /* success */
-               urb->status = 0;
-       default:                        /* fault */
-               COUNT (ehci->stats.complete);
-               break;
-       case -EREMOTEIO:                /* fault or normal */
-               if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
-                       urb->status = 0;
-               COUNT (ehci->stats.complete);
-               break;
-       case -ECONNRESET:               /* canceled */
-       case -ENOENT:
-               COUNT (ehci->stats.unlink);
-               break;
+       if (unlikely(urb->unlinked)) {
+               COUNT(ehci->stats.unlink);
+       } else {
+               if (likely(status == -EINPROGRESS))
+                       status = 0;
+               COUNT(ehci->stats.complete);
        }
-       spin_unlock (&urb->lock);
 
 #ifdef EHCI_URB_TRACE
        ehci_dbg (ehci,
@@ -257,13 +249,14 @@ __acquires(ehci->lock)
                __FUNCTION__, urb->dev->devpath, urb,
                usb_pipeendpoint (urb->pipe),
                usb_pipein (urb->pipe) ? "in" : "out",
-               urb->status,
+               status,
                urb->actual_length, urb->transfer_buffer_length);
 #endif
 
        /* complete() can reenter this HCD */
+       usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
        spin_unlock (&ehci->lock);
-       usb_hcd_giveback_urb (ehci_to_hcd(ehci), urb);
+       usb_hcd_giveback_urb(ehci_to_hcd(ehci), urb, status);
        spin_lock (&ehci->lock);
 }
 
@@ -283,6 +276,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
        struct ehci_qtd         *last = NULL, *end = qh->dummy;
        struct list_head        *entry, *tmp;
+       int                     last_status = -EINPROGRESS;
        int                     stopped;
        unsigned                count = 0;
        int                     do_status = 0;
@@ -311,6 +305,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
                struct ehci_qtd *qtd;
                struct urb      *urb;
                u32             token = 0;
+               int             qtd_status;
 
                qtd = list_entry (entry, struct ehci_qtd, qtd_list);
                urb = qtd->urb;
@@ -318,11 +313,12 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
                /* clean up any state from previous QTD ...*/
                if (last) {
                        if (likely (last->urb != urb)) {
-                               ehci_urb_done (ehci, last->urb);
+                               ehci_urb_done(ehci, last->urb, last_status);
                                count++;
                        }
                        ehci_qtd_free (ehci, last);
                        last = NULL;
+                       last_status = -EINPROGRESS;
                }
 
                /* ignore urbs submitted during completions we reported */
@@ -358,13 +354,14 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
                        stopped = 1;
 
                        if (unlikely (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)))
-                               urb->status = -ESHUTDOWN;
+                               last_status = -ESHUTDOWN;
 
                        /* ignore active urbs unless some previous qtd
                         * for the urb faulted (including short read) or
                         * its urb was canceled.  we may patch qh or qtds.
                         */
-                       if (likely (urb->status == -EINPROGRESS))
+                       if (likely(last_status == -EINPROGRESS &&
+                                       !urb->unlinked))
                                continue;
 
                        /* issue status after short control reads */
@@ -392,11 +389,14 @@ halt:
                }
 
                /* remove it from the queue */
-               spin_lock (&urb->lock);
-               qtd_copy_status (ehci, urb, qtd->length, token);
-               do_status = (urb->status == -EREMOTEIO)
-                               && usb_pipecontrol (urb->pipe);
-               spin_unlock (&urb->lock);
+               qtd_status = qtd_copy_status(ehci, urb, qtd->length, token);
+               if (unlikely(qtd_status == -EREMOTEIO)) {
+                       do_status = (!urb->unlinked &&
+                                       usb_pipecontrol(urb->pipe));
+                       qtd_status = 0;
+               }
+               if (likely(last_status == -EINPROGRESS))
+                       last_status = qtd_status;
 
                if (stopped && qtd->qtd_list.prev != &qh->qtd_list) {
                        last = list_entry (qtd->qtd_list.prev,
@@ -409,7 +409,7 @@ halt:
 
        /* last urb's completion might still need calling */
        if (likely (last != NULL)) {
-               ehci_urb_done (ehci, last->urb);
+               ehci_urb_done(ehci, last->urb, last_status);
                count++;
                ehci_qtd_free (ehci, last);
        }
@@ -913,7 +913,6 @@ static struct ehci_qh *qh_append_tds (
 static int
 submit_async (
        struct ehci_hcd         *ehci,
-       struct usb_host_endpoint *ep,
        struct urb              *urb,
        struct list_head        *qtd_list,
        gfp_t                   mem_flags
@@ -922,10 +921,10 @@ submit_async (
        int                     epnum;
        unsigned long           flags;
        struct ehci_qh          *qh = NULL;
-       int                     rc = 0;
+       int                     rc;
 
        qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
-       epnum = ep->desc.bEndpointAddress;
+       epnum = urb->ep->desc.bEndpointAddress;
 
 #ifdef EHCI_URB_TRACE
        ehci_dbg (ehci,
@@ -933,7 +932,7 @@ submit_async (
                __FUNCTION__, urb->dev->devpath, urb,
                epnum & 0x0f, (epnum & USB_DIR_IN) ? "in" : "out",
                urb->transfer_buffer_length,
-               qtd, ep->hcpriv);
+               qtd, urb->ep->hcpriv);
 #endif
 
        spin_lock_irqsave (&ehci->lock, flags);
@@ -942,9 +941,13 @@ submit_async (
                rc = -ESHUTDOWN;
                goto done;
        }
+       rc = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
+       if (unlikely(rc))
+               goto done;
 
-       qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv);
+       qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv);
        if (unlikely(qh == NULL)) {
+               usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
                rc = -ENOMEM;
                goto done;
        }
index e682f2342ef826693678262c0eb7009c72fcecbe..80d99bce2b38fb3d5a6459cdff8eeb5642fa0b06 100644 (file)
@@ -797,7 +797,6 @@ done:
 
 static int intr_submit (
        struct ehci_hcd         *ehci,
-       struct usb_host_endpoint *ep,
        struct urb              *urb,
        struct list_head        *qtd_list,
        gfp_t                   mem_flags
@@ -805,23 +804,26 @@ static int intr_submit (
        unsigned                epnum;
        unsigned long           flags;
        struct ehci_qh          *qh;
-       int                     status = 0;
+       int                     status;
        struct list_head        empty;
 
        /* get endpoint and transfer/schedule data */
-       epnum = ep->desc.bEndpointAddress;
+       epnum = urb->ep->desc.bEndpointAddress;
 
        spin_lock_irqsave (&ehci->lock, flags);
 
        if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
                        &ehci_to_hcd(ehci)->flags))) {
                status = -ESHUTDOWN;
-               goto done;
+               goto done_not_linked;
        }
+       status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
+       if (unlikely(status))
+               goto done_not_linked;
 
        /* get qh and force any scheduling errors */
        INIT_LIST_HEAD (&empty);
-       qh = qh_append_tds (ehci, urb, &empty, epnum, &ep->hcpriv);
+       qh = qh_append_tds(ehci, urb, &empty, epnum, &urb->ep->hcpriv);
        if (qh == NULL) {
                status = -ENOMEM;
                goto done;
@@ -832,13 +834,16 @@ static int intr_submit (
        }
 
        /* then queue the urb's tds to the qh */
-       qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv);
+       qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv);
        BUG_ON (qh == NULL);
 
        /* ... update usbfs periodic stats */
        ehci_to_hcd(ehci)->self.bandwidth_int_reqs++;
 
 done:
+       if (unlikely(status))
+               usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
+done_not_linked:
        spin_unlock_irqrestore (&ehci->lock, flags);
        if (status)
                qtd_list_free (ehci, urb, qtd_list);
@@ -1622,7 +1627,7 @@ itd_complete (
 
        /* give urb back to the driver ... can be out-of-order */
        dev = urb->dev;
-       ehci_urb_done (ehci, urb);
+       ehci_urb_done(ehci, urb, 0);
        urb = NULL;
 
        /* defer stopping schedule; completion can submit */
@@ -1686,12 +1691,19 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb,
        /* schedule ... need to lock */
        spin_lock_irqsave (&ehci->lock, flags);
        if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
-                              &ehci_to_hcd(ehci)->flags)))
+                              &ehci_to_hcd(ehci)->flags))) {
                status = -ESHUTDOWN;
-       else
-               status = iso_stream_schedule (ehci, urb, stream);
+               goto done_not_linked;
+       }
+       status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
+       if (unlikely(status))
+               goto done_not_linked;
+       status = iso_stream_schedule(ehci, urb, stream);
        if (likely (status == 0))
                itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
+       else
+               usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
+done_not_linked:
        spin_unlock_irqrestore (&ehci->lock, flags);
 
 done:
@@ -1988,7 +2000,7 @@ sitd_complete (
 
        /* give urb back to the driver */
        dev = urb->dev;
-       ehci_urb_done (ehci, urb);
+       ehci_urb_done(ehci, urb, 0);
        urb = NULL;
 
        /* defer stopping schedule; completion can submit */
@@ -2049,12 +2061,19 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb,
        /* schedule ... need to lock */
        spin_lock_irqsave (&ehci->lock, flags);
        if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
-                              &ehci_to_hcd(ehci)->flags)))
+                              &ehci_to_hcd(ehci)->flags))) {
                status = -ESHUTDOWN;
-       else
-               status = iso_stream_schedule (ehci, urb, stream);
+               goto done_not_linked;
+       }
+       status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
+       if (unlikely(status))
+               goto done_not_linked;
+       status = iso_stream_schedule(ehci, urb, stream);
        if (status == 0)
                sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
+       else
+               usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
+done_not_linked:
        spin_unlock_irqrestore (&ehci->lock, flags);
 
 done:
index 5c851a36de722e36d67fb65128219213d95d0235..c27417f5b9d8635320a491bd5fbdad1c8f4b366c 100644 (file)
@@ -277,12 +277,11 @@ static void preproc_atl_queue(struct isp116x *isp116x)
   processed urbs.
 */
 static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep,
-                          struct urb *urb)
+                          struct urb *urb, int status)
 __releases(isp116x->lock) __acquires(isp116x->lock)
 {
        unsigned i;
 
-       urb->hcpriv = NULL;
        ep->error_count = 0;
 
        if (usb_pipecontrol(urb->pipe))
@@ -290,8 +289,9 @@ __releases(isp116x->lock) __acquires(isp116x->lock)
 
        urb_dbg(urb, "Finish");
 
+       usb_hcd_unlink_urb_from_ep(isp116x_to_hcd(isp116x), urb);
        spin_unlock(&isp116x->lock);
-       usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb);
+       usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb, status);
        spin_lock(&isp116x->lock);
 
        /* take idle endpoints out of the schedule */
@@ -445,12 +445,7 @@ static void postproc_atl_queue(struct isp116x *isp116x)
                        if (PTD_GET_ACTIVE(ptd)
                            || (cc != TD_CC_NOERROR && cc < 0x0E))
                                break;
-                       if ((urb->transfer_flags & URB_SHORT_NOT_OK) &&
-                                       urb->actual_length <
-                                               urb->transfer_buffer_length)
-                               status = -EREMOTEIO;
-                       else
-                               status = 0;
+                       status = 0;
                        ep->nextpid = 0;
                        break;
                default:
@@ -458,14 +453,8 @@ static void postproc_atl_queue(struct isp116x *isp116x)
                }
 
  done:
-               if (status != -EINPROGRESS) {
-                       spin_lock(&urb->lock);
-                       if (urb->status == -EINPROGRESS)
-                               urb->status = status;
-                       spin_unlock(&urb->lock);
-               }
-               if (urb->status != -EINPROGRESS)
-                       finish_request(isp116x, ep, urb);
+               if (status != -EINPROGRESS || urb->unlinked)
+                       finish_request(isp116x, ep, urb, status);
        }
 }
 
@@ -673,7 +662,7 @@ static int balance(struct isp116x *isp116x, u16 period, u16 load)
 /*-----------------------------------------------------------------*/
 
 static int isp116x_urb_enqueue(struct usb_hcd *hcd,
-                              struct usb_host_endpoint *hep, struct urb *urb,
+                              struct urb *urb,
                               gfp_t mem_flags)
 {
        struct isp116x *isp116x = hcd_to_isp116x(hcd);
@@ -682,6 +671,7 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
        int is_out = !usb_pipein(pipe);
        int type = usb_pipetype(pipe);
        int epnum = usb_pipeendpoint(pipe);
+       struct usb_host_endpoint *hep = urb->ep;
        struct isp116x_ep *ep = NULL;
        unsigned long flags;
        int i;
@@ -705,7 +695,12 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
        if (!HC_IS_RUNNING(hcd->state)) {
                kfree(ep);
                ret = -ENODEV;
-               goto fail;
+               goto fail_not_linked;
+       }
+       ret = usb_hcd_link_urb_to_ep(hcd, urb);
+       if (ret) {
+               kfree(ep);
+               goto fail_not_linked;
        }
 
        if (hep->hcpriv)
@@ -808,16 +803,13 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
                }
        }
 
-       /* in case of unlink-during-submit */
-       if (urb->status != -EINPROGRESS) {
-               finish_request(isp116x, ep, urb);
-               ret = 0;
-               goto fail;
-       }
        urb->hcpriv = hep;
        start_atl_transfers(isp116x);
 
       fail:
+       if (ret)
+               usb_hcd_unlink_urb_from_ep(hcd, urb);
+      fail_not_linked:
        spin_unlock_irqrestore(&isp116x->lock, flags);
        return ret;
 }
@@ -825,20 +817,21 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
 /*
    Dequeue URBs.
 */
-static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
+               int status)
 {
        struct isp116x *isp116x = hcd_to_isp116x(hcd);
        struct usb_host_endpoint *hep;
        struct isp116x_ep *ep, *ep_act;
        unsigned long flags;
+       int rc;
 
        spin_lock_irqsave(&isp116x->lock, flags);
+       rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+       if (rc)
+               goto done;
+
        hep = urb->hcpriv;
-       /* URB already unlinked (or never linked)? */
-       if (!hep) {
-               spin_unlock_irqrestore(&isp116x->lock, flags);
-               return 0;
-       }
        ep = hep->hcpriv;
        WARN_ON(hep != ep->hep);
 
@@ -855,10 +848,10 @@ static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
                        }
 
        if (urb)
-               finish_request(isp116x, ep, urb);
-
+               finish_request(isp116x, ep, urb, status);
+ done:
        spin_unlock_irqrestore(&isp116x->lock, flags);
-       return 0;
+       return rc;
 }
 
 static void isp116x_endpoint_disable(struct usb_hcd *hcd,
index f61c6cdd06f2443ecbc0ed333df7a92cee618494..ebab5ce8f5ce7d760b48e9fb5e1df650c7ffded5 100644 (file)
@@ -24,7 +24,7 @@
  * small: 0) header + data packets 1) just header
  */
 static void __maybe_unused
-urb_print (struct urb * urb, char * str, int small)
+urb_print(struct urb * urb, char * str, int small, int status)
 {
        unsigned int pipe= urb->pipe;
 
@@ -34,7 +34,7 @@ urb_print (struct urb * urb, char * str, int small)
        }
 
 #ifndef        OHCI_VERBOSE_DEBUG
-       if (urb->status != 0)
+       if (status != 0)
 #endif
        dbg("%s %p dev=%d ep=%d%s-%s flags=%x len=%d/%d stat=%d",
                    str,
@@ -46,7 +46,7 @@ urb_print (struct urb * urb, char * str, int small)
                    urb->transfer_flags,
                    urb->actual_length,
                    urb->transfer_buffer_length,
-                   urb->status);
+                   status);
 
 #ifdef OHCI_VERBOSE_DEBUG
        if (!small) {
@@ -66,7 +66,7 @@ urb_print (struct urb * urb, char * str, int small)
                                                urb->transfer_buffer_length: urb->actual_length;
                        for (i = 0; i < 16 && i < len; i++)
                                printk (" %02x", ((__u8 *) urb->transfer_buffer) [i]);
-                       printk ("%s stat:%d\n", i < len? "...": "", urb->status);
+                       printk ("%s stat:%d\n", i < len? "...": "", status);
                }
        }
 #endif
index 6edf4097d2d25a2156bfcd67fbc7f4f0b7b02962..240c7f50754149e678bc1bf8b0fc4e890f776209 100644 (file)
@@ -81,7 +81,6 @@ static void ohci_dump (struct ohci_hcd *ohci, int verbose);
 static int ohci_init (struct ohci_hcd *ohci);
 static void ohci_stop (struct usb_hcd *hcd);
 static int ohci_restart (struct ohci_hcd *ohci);
-static void ohci_quirk_nec_worker (struct work_struct *work);
 
 #include "ohci-hub.c"
 #include "ohci-dbg.c"
@@ -118,7 +117,6 @@ MODULE_PARM_DESC (no_handshake, "true (not default) disables BIOS handshake");
  */
 static int ohci_urb_enqueue (
        struct usb_hcd  *hcd,
-       struct usb_host_endpoint *ep,
        struct urb      *urb,
        gfp_t           mem_flags
 ) {
@@ -131,11 +129,11 @@ static int ohci_urb_enqueue (
        int             retval = 0;
 
 #ifdef OHCI_VERBOSE_DEBUG
-       urb_print (urb, "SUB", usb_pipein (pipe));
+       urb_print(urb, "SUB", usb_pipein(pipe), -EINPROGRESS);
 #endif
 
        /* every endpoint has a ed, locate and maybe (re)initialize it */
-       if (! (ed = ed_get (ohci, ep, urb->dev, pipe, urb->interval)))
+       if (! (ed = ed_get (ohci, urb->ep, urb->dev, pipe, urb->interval)))
                return -ENOMEM;
 
        /* for the private part of the URB we need the number of TDs (size) */
@@ -200,22 +198,17 @@ static int ohci_urb_enqueue (
                retval = -ENODEV;
                goto fail;
        }
-
-       /* in case of unlink-during-submit */
-       spin_lock (&urb->lock);
-       if (urb->status != -EINPROGRESS) {
-               spin_unlock (&urb->lock);
-               urb->hcpriv = urb_priv;
-               finish_urb (ohci, urb);
-               retval = 0;
+       retval = usb_hcd_link_urb_to_ep(hcd, urb);
+       if (retval)
                goto fail;
-       }
 
        /* schedule the ed if needed */
        if (ed->state == ED_IDLE) {
                retval = ed_schedule (ohci, ed);
-               if (retval < 0)
-                       goto fail0;
+               if (retval < 0) {
+                       usb_hcd_unlink_urb_from_ep(hcd, urb);
+                       goto fail;
+               }
                if (ed->type == PIPE_ISOCHRONOUS) {
                        u16     frame = ohci_frame_no(ohci);
 
@@ -239,8 +232,6 @@ static int ohci_urb_enqueue (
        urb->hcpriv = urb_priv;
        td_submit_urb (ohci, urb);
 
-fail0:
-       spin_unlock (&urb->lock);
 fail:
        if (retval)
                urb_free_priv (ohci, urb_priv);
@@ -249,22 +240,26 @@ fail:
 }
 
 /*
- * decouple the URB from the HC queues (TDs, urb_priv); it's
- * already marked using urb->status.  reporting is always done
+ * decouple the URB from the HC queues (TDs, urb_priv).
+ * reporting is always done
  * asynchronously, and we might be dealing with an urb that's
  * partially transferred, or an ED with other urbs being unlinked.
  */
-static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+static int ohci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
        struct ohci_hcd         *ohci = hcd_to_ohci (hcd);
        unsigned long           flags;
+       int                     rc;
 
 #ifdef OHCI_VERBOSE_DEBUG
-       urb_print (urb, "UNLINK", 1);
+       urb_print(urb, "UNLINK", 1, status);
 #endif
 
        spin_lock_irqsave (&ohci->lock, flags);
-       if (HC_IS_RUNNING(hcd->state)) {
+       rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+       if (rc) {
+               ;       /* Do nothing */
+       } else if (HC_IS_RUNNING(hcd->state)) {
                urb_priv_t  *urb_priv;
 
                /* Unless an IRQ completed the unlink while it was being
@@ -282,10 +277,10 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
                 * any more ... just clean up every urb's memory.
                 */
                if (urb->hcpriv)
-                       finish_urb (ohci, urb);
+                       finish_urb(ohci, urb, status);
        }
        spin_unlock_irqrestore (&ohci->lock, flags);
-       return 0;
+       return rc;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -314,6 +309,8 @@ rescan:
        if (!HC_IS_RUNNING (hcd->state)) {
 sanitize:
                ed->state = ED_IDLE;
+               if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT)
+                       ohci->eds_scheduled--;
                finish_unlinks (ohci, 0);
        }
 
@@ -321,7 +318,12 @@ sanitize:
        case ED_UNLINK:         /* wait for hw to finish? */
                /* major IRQ delivery trouble loses INTR_SF too... */
                if (limit-- == 0) {
-                       ohci_warn (ohci, "IRQ INTR_SF lossage\n");
+                       ohci_warn(ohci, "ED unlink timeout\n");
+                       if (quirk_zfmicro(ohci)) {
+                               ohci_warn(ohci, "Attempting ZF TD recovery\n");
+                               ohci->ed_to_check = ed;
+                               ohci->zf_delay = 2;
+                       }
                        goto sanitize;
                }
                spin_unlock_irqrestore (&ohci->lock, flags);
@@ -379,6 +381,93 @@ ohci_shutdown (struct usb_hcd *hcd)
        (void) ohci_readl (ohci, &ohci->regs->control);
 }
 
+static int check_ed(struct ohci_hcd *ohci, struct ed *ed)
+{
+       return (hc32_to_cpu(ohci, ed->hwINFO) & ED_IN) != 0
+               && (hc32_to_cpu(ohci, ed->hwHeadP) & TD_MASK)
+                       == (hc32_to_cpu(ohci, ed->hwTailP) & TD_MASK)
+               && !list_empty(&ed->td_list);
+}
+
+/* ZF Micro watchdog timer callback. The ZF Micro chipset sometimes completes
+ * an interrupt TD but neglects to add it to the donelist.  On systems with
+ * this chipset, we need to periodically check the state of the queues to look
+ * for such "lost" TDs.
+ */
+static void unlink_watchdog_func(unsigned long _ohci)
+{
+       long            flags;
+       unsigned        max;
+       unsigned        seen_count = 0;
+       unsigned        i;
+       struct ed       **seen = NULL;
+       struct ohci_hcd *ohci = (struct ohci_hcd *) _ohci;
+
+       spin_lock_irqsave(&ohci->lock, flags);
+       max = ohci->eds_scheduled;
+       if (!max)
+               goto done;
+
+       if (ohci->ed_to_check)
+               goto out;
+
+       seen = kcalloc(max, sizeof *seen, GFP_ATOMIC);
+       if (!seen)
+               goto out;
+
+       for (i = 0; i < NUM_INTS; i++) {
+               struct ed       *ed = ohci->periodic[i];
+
+               while (ed) {
+                       unsigned        temp;
+
+                       /* scan this branch of the periodic schedule tree */
+                       for (temp = 0; temp < seen_count; temp++) {
+                               if (seen[temp] == ed) {
+                                       /* we've checked it and what's after */
+                                       ed = NULL;
+                                       break;
+                               }
+                       }
+                       if (!ed)
+                               break;
+                       seen[seen_count++] = ed;
+                       if (!check_ed(ohci, ed)) {
+                               ed = ed->ed_next;
+                               continue;
+                       }
+
+                       /* HC's TD list is empty, but HCD sees at least one
+                        * TD that's not been sent through the donelist.
+                        */
+                       ohci->ed_to_check = ed;
+                       ohci->zf_delay = 2;
+
+                       /* The HC may wait until the next frame to report the
+                        * TD as done through the donelist and INTR_WDH.  (We
+                        * just *assume* it's not a multi-TD interrupt URB;
+                        * those could defer the IRQ more than one frame, using
+                        * DI...)  Check again after the next INTR_SF.
+                        */
+                       ohci_writel(ohci, OHCI_INTR_SF,
+                                       &ohci->regs->intrstatus);
+                       ohci_writel(ohci, OHCI_INTR_SF,
+                                       &ohci->regs->intrenable);
+
+                       /* flush those writes */
+                       (void) ohci_readl(ohci, &ohci->regs->control);
+
+                       goto out;
+               }
+       }
+out:
+       kfree(seen);
+       if (ohci->eds_scheduled)
+               mod_timer(&ohci->unlink_watchdog, round_jiffies_relative(HZ));
+done:
+       spin_unlock_irqrestore(&ohci->lock, flags);
+}
+
 /*-------------------------------------------------------------------------*
  * HC functions
  *-------------------------------------------------------------------------*/
@@ -616,6 +705,15 @@ retry:
        mdelay ((temp >> 23) & 0x1fe);
        hcd->state = HC_STATE_RUNNING;
 
+       if (quirk_zfmicro(ohci)) {
+               /* Create timer to watch for bad queue state on ZF Micro */
+               setup_timer(&ohci->unlink_watchdog, unlink_watchdog_func,
+                               (unsigned long) ohci);
+
+               ohci->eds_scheduled = 0;
+               ohci->ed_to_check = NULL;
+       }
+
        ohci_dump (ohci, 1);
 
        return 0;
@@ -629,10 +727,11 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
 {
        struct ohci_hcd         *ohci = hcd_to_ohci (hcd);
        struct ohci_regs __iomem *regs = ohci->regs;
-       int                     ints; 
+       int                     ints;
 
        /* we can eliminate a (slow) ohci_readl()
-          if _only_ WDH caused this irq */
+        * if _only_ WDH caused this irq
+        */
        if ((ohci->hcca->done_head != 0)
                        && ! (hc32_to_cpup (ohci, &ohci->hcca->done_head)
                                & 0x01)) {
@@ -651,7 +750,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
 
        if (ints & OHCI_INTR_UE) {
                // e.g. due to PCI Master/Target Abort
-               if (ohci->flags & OHCI_QUIRK_NEC) {
+               if (quirk_nec(ohci)) {
                        /* Workaround for a silicon bug in some NEC chips used
                         * in Apple's PowerBooks. Adapted from Darwin code.
                         */
@@ -713,6 +812,31 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
                        ohci_writel (ohci, OHCI_INTR_WDH, &regs->intrenable);
        }
 
+       if (quirk_zfmicro(ohci) && (ints & OHCI_INTR_SF)) {
+               spin_lock(&ohci->lock);
+               if (ohci->ed_to_check) {
+                       struct ed *ed = ohci->ed_to_check;
+
+                       if (check_ed(ohci, ed)) {
+                               /* HC thinks the TD list is empty; HCD knows
+                                * at least one TD is outstanding
+                                */
+                               if (--ohci->zf_delay == 0) {
+                                       struct td *td = list_entry(
+                                               ed->td_list.next,
+                                               struct td, td_list);
+                                       ohci_warn(ohci,
+                                                 "Reclaiming orphan TD %p\n",
+                                                 td);
+                                       takeback_td(ohci, td);
+                                       ohci->ed_to_check = NULL;
+                               }
+                       } else
+                               ohci->ed_to_check = NULL;
+               }
+               spin_unlock(&ohci->lock);
+       }
+
        /* could track INTR_SO to reduce available PCI/... bandwidth */
 
        /* handle any pending URB/ED unlinks, leaving INTR_SF enabled
@@ -721,7 +845,9 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
        spin_lock (&ohci->lock);
        if (ohci->ed_rm_list)
                finish_unlinks (ohci, ohci_frame_no(ohci));
-       if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list
+       if ((ints & OHCI_INTR_SF) != 0
+                       && !ohci->ed_rm_list
+                       && !ohci->ed_to_check
                        && HC_IS_RUNNING(hcd->state))
                ohci_writel (ohci, OHCI_INTR_SF, &regs->intrdisable);
        spin_unlock (&ohci->lock);
@@ -751,6 +877,9 @@ static void ohci_stop (struct usb_hcd *hcd)
        free_irq(hcd->irq, hcd);
        hcd->irq = -1;
 
+       if (quirk_zfmicro(ohci))
+               del_timer(&ohci->unlink_watchdog);
+
        remove_debug_files (ohci);
        ohci_mem_cleanup (ohci);
        if (ohci->hcca) {
@@ -798,9 +927,8 @@ static int ohci_restart (struct ohci_hcd *ohci)
                                        ed, ed->state);
                }
 
-               spin_lock (&urb->lock);
-               urb->status = -ESHUTDOWN;
-               spin_unlock (&urb->lock);
+               if (!urb->unlinked)
+                       urb->unlinked = -ESHUTDOWN;
        }
        finish_unlinks (ohci, 0);
        spin_unlock_irq(&ohci->lock);
@@ -828,27 +956,6 @@ static int ohci_restart (struct ohci_hcd *ohci)
 
 /*-------------------------------------------------------------------------*/
 
-/* NEC workaround */
-static void ohci_quirk_nec_worker(struct work_struct *work)
-{
-       struct ohci_hcd *ohci = container_of(work, struct ohci_hcd, nec_work);
-       int status;
-
-       status = ohci_init(ohci);
-       if (status != 0) {
-               ohci_err(ohci, "Restarting NEC controller failed "
-                        "in ohci_init, %d\n", status);
-               return;
-       }
-
-       status = ohci_restart(ohci);
-       if (status != 0)
-               ohci_err(ohci, "Restarting NEC controller failed "
-                        "in ohci_restart, %d\n", status);
-}
-
-/*-------------------------------------------------------------------------*/
-
 #define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
 
 MODULE_AUTHOR (DRIVER_AUTHOR);
@@ -926,11 +1033,17 @@ MODULE_LICENSE ("GPL");
 #define PS3_SYSTEM_BUS_DRIVER  ps3_ohci_driver
 #endif
 
+#ifdef CONFIG_USB_OHCI_HCD_SSB
+#include "ohci-ssb.c"
+#define SSB_OHCI_DRIVER                ssb_ohci_driver
+#endif
+
 #if    !defined(PCI_DRIVER) &&         \
        !defined(PLATFORM_DRIVER) &&    \
        !defined(OF_PLATFORM_DRIVER) && \
        !defined(SA1111_DRIVER) &&      \
-       !defined(PS3_SYSTEM_BUS_DRIVER)
+       !defined(PS3_SYSTEM_BUS_DRIVER) && \
+       !defined(SSB_OHCI_DRIVER)
 #error "missing bus glue for ohci-hcd"
 #endif
 
@@ -975,10 +1088,20 @@ static int __init ohci_hcd_mod_init(void)
                goto error_pci;
 #endif
 
+#ifdef SSB_OHCI_DRIVER
+       retval = ssb_driver_register(&SSB_OHCI_DRIVER);
+       if (retval)
+               goto error_ssb;
+#endif
+
        return retval;
 
        /* Error path */
+#ifdef SSB_OHCI_DRIVER
+ error_ssb:
+#endif
 #ifdef PCI_DRIVER
+       pci_unregister_driver(&PCI_DRIVER);
  error_pci:
 #endif
 #ifdef SA1111_DRIVER
@@ -1003,6 +1126,9 @@ module_init(ohci_hcd_mod_init);
 
 static void __exit ohci_hcd_mod_exit(void)
 {
+#ifdef SSB_OHCI_DRIVER
+       ssb_driver_unregister(&SSB_OHCI_DRIVER);
+#endif
 #ifdef PCI_DRIVER
        pci_unregister_driver(&PCI_DRIVER);
 #endif
index 450c7b460c5ab092e62ab13828ec41874f483b95..2f20d3dc895b8b4a959459573f4089e2014f27f8 100644 (file)
@@ -28,7 +28,6 @@ static void ohci_hcd_init (struct ohci_hcd *ohci)
        ohci->next_statechange = jiffies;
        spin_lock_init (&ohci->lock);
        INIT_LIST_HEAD (&ohci->pending);
-       INIT_WORK (&ohci->nec_work, ohci_quirk_nec_worker);
 }
 
 /*-------------------------------------------------------------------------*/
index a5e2eb85d073bd69cb9e356cffc5f202e489d305..d0360f65ebd99951243d8d7cbd1cfe1683419c8a 100644 (file)
@@ -84,7 +84,7 @@ static int ohci_quirk_zfmicro(struct usb_hcd *hcd)
        struct ohci_hcd *ohci = hcd_to_ohci (hcd);
 
        ohci->flags |= OHCI_QUIRK_ZFMICRO;
-       ohci_dbg (ohci, "enabled Compaq ZFMicro chipset quirk\n");
+       ohci_dbg(ohci, "enabled Compaq ZFMicro chipset quirks\n");
 
        return 0;
 }
@@ -113,11 +113,31 @@ static int ohci_quirk_toshiba_scc(struct usb_hcd *hcd)
 
 /* Check for NEC chip and apply quirk for allegedly lost interrupts.
  */
+
+static void ohci_quirk_nec_worker(struct work_struct *work)
+{
+       struct ohci_hcd *ohci = container_of(work, struct ohci_hcd, nec_work);
+       int status;
+
+       status = ohci_init(ohci);
+       if (status != 0) {
+               ohci_err(ohci, "Restarting NEC controller failed in %s, %d\n",
+                        "ohci_init", status);
+               return;
+       }
+
+       status = ohci_restart(ohci);
+       if (status != 0)
+               ohci_err(ohci, "Restarting NEC controller failed in %s, %d\n",
+                        "ohci_restart", status);
+}
+
 static int ohci_quirk_nec(struct usb_hcd *hcd)
 {
        struct ohci_hcd *ohci = hcd_to_ohci (hcd);
 
        ohci->flags |= OHCI_QUIRK_NEC;
+       INIT_WORK(&ohci->nec_work, ohci_quirk_nec_worker);
        ohci_dbg (ohci, "enabled NEC chipset lost interrupt quirk\n");
 
        return 0;
index c43b66acd4d50ab99756138bd0656a0822b82399..0a74269201502e4381ecc609b6f039568d99b537 100644 (file)
@@ -134,8 +134,11 @@ ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
        }
 
        ohci = hcd_to_ohci(hcd);
-       if (is_bigendian)
+       if (is_bigendian) {
                ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
+               if (of_device_is_compatible(dn, "mpc5200-ohci"))
+                       ohci->flags |= OHCI_QUIRK_FRAME_NO;
+       }
 
        ohci_hcd_init(ohci);
 
index 1a2e1777ca61c54595992a06c36556eaa67d47ac..f95be1896b0d73ea93889617a4862e51c96bd5ad 100644 (file)
@@ -73,6 +73,11 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
 
        ohci = hcd_to_ohci(hcd);
        ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
+
+#ifdef CONFIG_PPC_MPC52xx
+       /* MPC52xx doesn't need frame_no shift */
+       ohci->flags |= OHCI_QUIRK_FRAME_NO;
+#endif
        ohci_hcd_init(ohci);
 
        retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
index 830a3fe8615e9e1d96008789dc7d817934c882a0..51817322232b453a5f6c881809d542e9315e0f76 100644 (file)
@@ -36,29 +36,15 @@ static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv)
  * PRECONDITION:  ohci lock held, irqs blocked.
  */
 static void
-finish_urb (struct ohci_hcd *ohci, struct urb *urb)
+finish_urb(struct ohci_hcd *ohci, struct urb *urb, int status)
 __releases(ohci->lock)
 __acquires(ohci->lock)
 {
        // ASSERT (urb->hcpriv != 0);
 
        urb_free_priv (ohci, urb->hcpriv);
-       urb->hcpriv = NULL;
-
-       spin_lock (&urb->lock);
-       if (likely (urb->status == -EINPROGRESS))
-               urb->status = 0;
-       /* report short control reads right even though the data TD always
-        * has TD_R set.  (much simpler, but creates the 1-td limit.)
-        */
-       if (unlikely (urb->transfer_flags & URB_SHORT_NOT_OK)
-                       && unlikely (usb_pipecontrol (urb->pipe))
-                       && urb->actual_length < urb->transfer_buffer_length
-                       && usb_pipein (urb->pipe)
-                       && urb->status == 0) {
-               urb->status = -EREMOTEIO;
-       }
-       spin_unlock (&urb->lock);
+       if (likely(status == -EINPROGRESS))
+               status = 0;
 
        switch (usb_pipetype (urb->pipe)) {
        case PIPE_ISOCHRONOUS:
@@ -70,12 +56,13 @@ __acquires(ohci->lock)
        }
 
 #ifdef OHCI_VERBOSE_DEBUG
-       urb_print (urb, "RET", usb_pipeout (urb->pipe));
+       urb_print(urb, "RET", usb_pipeout (urb->pipe), status);
 #endif
 
        /* urb->complete() can reenter this HCD */
+       usb_hcd_unlink_urb_from_ep(ohci_to_hcd(ohci), urb);
        spin_unlock (&ohci->lock);
-       usb_hcd_giveback_urb (ohci_to_hcd(ohci), urb);
+       usb_hcd_giveback_urb(ohci_to_hcd(ohci), urb, status);
        spin_lock (&ohci->lock);
 
        /* stop periodic dma if it's not needed */
@@ -179,6 +166,10 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed)
        ed->ed_prev = NULL;
        ed->ed_next = NULL;
        ed->hwNextED = 0;
+       if (quirk_zfmicro(ohci)
+                       && (ed->type == PIPE_INTERRUPT)
+                       && !(ohci->eds_scheduled++))
+               mod_timer(&ohci->unlink_watchdog, round_jiffies_relative(HZ));
        wmb ();
 
        /* we care about rm_list when setting CLE/BLE in case the HC was at
@@ -708,19 +699,18 @@ static void td_submit_urb (
  * Done List handling functions
  *-------------------------------------------------------------------------*/
 
-/* calculate transfer length/status and update the urb
- * PRECONDITION:  irqsafe (only for urb->status locking)
- */
-static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
+/* calculate transfer length/status and update the urb */
+static int td_done(struct ohci_hcd *ohci, struct urb *urb, struct td *td)
 {
        u32     tdINFO = hc32_to_cpup (ohci, &td->hwINFO);
        int     cc = 0;
+       int     status = -EINPROGRESS;
 
        list_del (&td->td_list);
 
        /* ISO ... drivers see per-TD length/status */
        if (tdINFO & TD_ISO) {
-               u16     tdPSW = ohci_hwPSW (ohci, td, 0);
+               u16     tdPSW = ohci_hwPSW(ohci, td, 0);
                int     dlen = 0;
 
                /* NOTE:  assumes FC in tdINFO == 0, and that
@@ -729,7 +719,7 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
 
                cc = (tdPSW >> 12) & 0xF;
                if (tdINFO & TD_CC)     /* hc didn't touch? */
-                       return;
+                       return status;
 
                if (usb_pipeout (urb->pipe))
                        dlen = urb->iso_frame_desc [td->index].length;
@@ -762,12 +752,8 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
                if (cc == TD_DATAUNDERRUN
                                && !(urb->transfer_flags & URB_SHORT_NOT_OK))
                        cc = TD_CC_NOERROR;
-               if (cc != TD_CC_NOERROR && cc < 0x0E) {
-                       spin_lock (&urb->lock);
-                       if (urb->status == -EINPROGRESS)
-                               urb->status = cc_to_error [cc];
-                       spin_unlock (&urb->lock);
-               }
+               if (cc != TD_CC_NOERROR && cc < 0x0E)
+                       status = cc_to_error[cc];
 
                /* count all non-empty packets except control SETUP packet */
                if ((type != PIPE_CONTROL || td->index != 0) && tdBE != 0) {
@@ -786,14 +772,15 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
                                urb->actual_length,
                                urb->transfer_buffer_length);
        }
+       return status;
 }
 
 /*-------------------------------------------------------------------------*/
 
-static inline struct td *
-ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
+static void ed_halted(struct ohci_hcd *ohci, struct td *td, int cc)
 {
        struct urb              *urb = td->urb;
+       urb_priv_t              *urb_priv = urb->hcpriv;
        struct ed               *ed = td->ed;
        struct list_head        *tmp = td->td_list.next;
        __hc32                  toggle = ed->hwHeadP & cpu_to_hc32 (ohci, ED_C);
@@ -805,13 +792,12 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
        wmb ();
        ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_H);
 
-       /* put any later tds from this urb onto the donelist, after 'td',
-        * order won't matter here: no errors, and nothing was transferred.
-        * also patch the ed so it looks as if those tds completed normally.
+       /* Get rid of all later tds from this urb.  We don't have
+        * to be careful: no errors and nothing was transferred.
+        * Also patch the ed so it looks as if those tds completed normally.
         */
        while (tmp != &ed->td_list) {
                struct td       *next;
-               __hc32          info;
 
                next = list_entry (tmp, struct td, td_list);
                tmp = next->td_list.next;
@@ -826,14 +812,9 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
                 * then we need to leave the control STATUS packet queued
                 * and clear ED_SKIP.
                 */
-               info = next->hwINFO;
-               info |= cpu_to_hc32 (ohci, TD_DONE);
-               info &= ~cpu_to_hc32 (ohci, TD_CC);
-               next->hwINFO = info;
-
-               next->next_dl_td = rev;
-               rev = next;
 
+               list_del(&next->td_list);
+               urb_priv->td_cnt++;
                ed->hwHeadP = next->hwNextTD | toggle;
        }
 
@@ -859,8 +840,6 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
                        hc32_to_cpu (ohci, td->hwINFO),
                        cc, cc_to_error [cc]);
        }
-
-       return rev;
 }
 
 /* replies to the request have to be on a FIFO basis so
@@ -897,7 +876,7 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
                 */
                if (cc != TD_CC_NOERROR
                                && (td->ed->hwHeadP & cpu_to_hc32 (ohci, ED_H)))
-                       td_rev = ed_halted (ohci, td, cc, td_rev);
+                       ed_halted(ohci, td, cc);
 
                td->next_dl_td = td_rev;
                td_rev = td;
@@ -940,8 +919,12 @@ skip_ed:
                                                                TD_MASK;
 
                                /* INTR_WDH may need to clean up first */
-                               if (td->td_dma != head)
-                                       goto skip_ed;
+                               if (td->td_dma != head) {
+                                       if (ed == ohci->ed_to_check)
+                                               ohci->ed_to_check = NULL;
+                                       else
+                                               goto skip_ed;
+                               }
                        }
                }
 
@@ -974,7 +957,7 @@ rescan_this:
                        urb = td->urb;
                        urb_priv = td->urb->hcpriv;
 
-                       if (urb->status == -EINPROGRESS) {
+                       if (!urb->unlinked) {
                                prev = &td->hwNextTD;
                                continue;
                        }
@@ -990,7 +973,7 @@ rescan_this:
                        /* if URB is done, clean up */
                        if (urb_priv->td_cnt == urb_priv->length) {
                                modified = completed = 1;
-                               finish_urb (ohci, urb);
+                               finish_urb(ohci, urb, 0);
                        }
                }
                if (completed && !list_empty (&ed->td_list))
@@ -998,6 +981,8 @@ rescan_this:
 
                /* ED's now officially unlinked, hc doesn't see */
                ed->state = ED_IDLE;
+               if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT)
+                       ohci->eds_scheduled--;
                ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_H);
                ed->hwNextED = 0;
                wmb ();
@@ -1021,7 +1006,7 @@ rescan_this:
 
                if (ohci->ed_controltail) {
                        command |= OHCI_CLF;
-                       if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+                       if (quirk_zfmicro(ohci))
                                mdelay(1);
                        if (!(ohci->hc_control & OHCI_CTRL_CLE)) {
                                control |= OHCI_CTRL_CLE;
@@ -1031,7 +1016,7 @@ rescan_this:
                }
                if (ohci->ed_bulktail) {
                        command |= OHCI_BLF;
-                       if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+                       if (quirk_zfmicro(ohci))
                                mdelay(1);
                        if (!(ohci->hc_control & OHCI_CTRL_BLE)) {
                                control |= OHCI_CTRL_BLE;
@@ -1043,13 +1028,13 @@ rescan_this:
                /* CLE/BLE to enable, CLF/BLF to (maybe) kickstart */
                if (control) {
                        ohci->hc_control |= control;
-                       if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+                       if (quirk_zfmicro(ohci))
                                mdelay(1);
                        ohci_writel (ohci, ohci->hc_control,
                                        &ohci->regs->control);
                }
                if (command) {
-                       if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+                       if (quirk_zfmicro(ohci))
                                mdelay(1);
                        ohci_writel (ohci, command, &ohci->regs->cmdstatus);
                }
@@ -1060,12 +1045,61 @@ rescan_this:
 
 /*-------------------------------------------------------------------------*/
 
+/*
+ * Used to take back a TD from the host controller. This would normally be
+ * called from within dl_done_list, however it may be called directly if the
+ * HC no longer sees the TD and it has not appeared on the donelist (after
+ * two frames).  This bug has been observed on ZF Micro systems.
+ */
+static void takeback_td(struct ohci_hcd *ohci, struct td *td)
+{
+       struct urb      *urb = td->urb;
+       urb_priv_t      *urb_priv = urb->hcpriv;
+       struct ed       *ed = td->ed;
+       int             status;
+
+       /* update URB's length and status from TD */
+       status = td_done(ohci, urb, td);
+       urb_priv->td_cnt++;
+
+       /* If all this urb's TDs are done, call complete() */
+       if (urb_priv->td_cnt == urb_priv->length)
+               finish_urb(ohci, urb, status);
+
+       /* clean schedule:  unlink EDs that are no longer busy */
+       if (list_empty(&ed->td_list)) {
+               if (ed->state == ED_OPER)
+                       start_ed_unlink(ohci, ed);
+
+       /* ... reenabling halted EDs only after fault cleanup */
+       } else if ((ed->hwINFO & cpu_to_hc32(ohci, ED_SKIP | ED_DEQUEUE))
+                       == cpu_to_hc32(ohci, ED_SKIP)) {
+               td = list_entry(ed->td_list.next, struct td, td_list);
+               if (!(td->hwINFO & cpu_to_hc32(ohci, TD_DONE))) {
+                       ed->hwINFO &= ~cpu_to_hc32(ohci, ED_SKIP);
+                       /* ... hc may need waking-up */
+                       switch (ed->type) {
+                       case PIPE_CONTROL:
+                               ohci_writel(ohci, OHCI_CLF,
+                                               &ohci->regs->cmdstatus);
+                               break;
+                       case PIPE_BULK:
+                               ohci_writel(ohci, OHCI_BLF,
+                                               &ohci->regs->cmdstatus);
+                               break;
+                       }
+               }
+       }
+}
+
 /*
  * Process normal completions (error or success) and clean the schedules.
  *
  * This is the main path for handing urbs back to drivers.  The only other
- * path is finish_unlinks(), which unlinks URBs using ed_rm_list, instead of
- * scanning the (re-reversed) donelist as this does.
+ * normal path is finish_unlinks(), which unlinks URBs using ed_rm_list,
+ * instead of scanning the (re-reversed) donelist as this does.  There's
+ * an abnormal path too, handling a quirk in some Compaq silicon:  URBs
+ * with TDs that appear to be orphaned are directly reclaimed.
  */
 static void
 dl_done_list (struct ohci_hcd *ohci)
@@ -1074,44 +1108,7 @@ dl_done_list (struct ohci_hcd *ohci)
 
        while (td) {
                struct td       *td_next = td->next_dl_td;
-               struct urb      *urb = td->urb;
-               urb_priv_t      *urb_priv = urb->hcpriv;
-               struct ed       *ed = td->ed;
-
-               /* update URB's length and status from TD */
-               td_done (ohci, urb, td);
-               urb_priv->td_cnt++;
-
-               /* If all this urb's TDs are done, call complete() */
-               if (urb_priv->td_cnt == urb_priv->length)
-                       finish_urb (ohci, urb);
-
-               /* clean schedule:  unlink EDs that are no longer busy */
-               if (list_empty (&ed->td_list)) {
-                       if (ed->state == ED_OPER)
-                               start_ed_unlink (ohci, ed);
-
-               /* ... reenabling halted EDs only after fault cleanup */
-               } else if ((ed->hwINFO & cpu_to_hc32 (ohci,
-                                               ED_SKIP | ED_DEQUEUE))
-                                       == cpu_to_hc32 (ohci, ED_SKIP)) {
-                       td = list_entry (ed->td_list.next, struct td, td_list);
-                       if (!(td->hwINFO & cpu_to_hc32 (ohci, TD_DONE))) {
-                               ed->hwINFO &= ~cpu_to_hc32 (ohci, ED_SKIP);
-                               /* ... hc may need waking-up */
-                               switch (ed->type) {
-                               case PIPE_CONTROL:
-                                       ohci_writel (ohci, OHCI_CLF,
-                                               &ohci->regs->cmdstatus);
-                                       break;
-                               case PIPE_BULK:
-                                       ohci_writel (ohci, OHCI_BLF,
-                                               &ohci->regs->cmdstatus);
-                                       break;
-                               }
-                       }
-               }
-
+               takeback_td(ohci, td);
                td = td_next;
        }
 }
diff --git a/drivers/usb/host/ohci-ssb.c b/drivers/usb/host/ohci-ssb.c
new file mode 100644 (file)
index 0000000..fe70e72
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * Sonics Silicon Backplane
+ * Broadcom USB-core OHCI driver
+ *
+ * Copyright 2007 Michael Buesch <mb@bu3sch.de>
+ *
+ * Derived from the OHCI-PCI driver
+ * Copyright 1999 Roman Weissgaerber
+ * Copyright 2000-2002 David Brownell
+ * Copyright 1999 Linus Torvalds
+ * Copyright 1999 Gregory P. Smith
+ *
+ * Derived from the USBcore related parts of Broadcom-SB
+ * Copyright 2005 Broadcom Corporation
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+#include <linux/ssb/ssb.h>
+
+
+#define SSB_OHCI_TMSLOW_HOSTMODE       (1 << 29)
+
+struct ssb_ohci_device {
+       struct ohci_hcd ohci; /* _must_ be at the beginning. */
+
+       u32 enable_flags;
+};
+
+static inline
+struct ssb_ohci_device *hcd_to_ssb_ohci(struct usb_hcd *hcd)
+{
+       return (struct ssb_ohci_device *)(hcd->hcd_priv);
+}
+
+
+static int ssb_ohci_reset(struct usb_hcd *hcd)
+{
+       struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
+       struct ohci_hcd *ohci = &ohcidev->ohci;
+       int err;
+
+       ohci_hcd_init(ohci);
+       err = ohci_init(ohci);
+
+       return err;
+}
+
+static int ssb_ohci_start(struct usb_hcd *hcd)
+{
+       struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
+       struct ohci_hcd *ohci = &ohcidev->ohci;
+       int err;
+
+       err = ohci_run(ohci);
+       if (err < 0) {
+               ohci_err(ohci, "can't start\n");
+               ohci_stop(hcd);
+       }
+
+       return err;
+}
+
+#ifdef CONFIG_PM
+static int ssb_ohci_hcd_suspend(struct usb_hcd *hcd, pm_message_t message)
+{
+       struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
+       struct ohci_hcd *ohci = &ohcidev->ohci;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ohci->lock, flags);
+
+       ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
+       ohci_readl(ohci, &ohci->regs->intrdisable); /* commit write */
+
+       /* make sure snapshot being resumed re-enumerates everything */
+       if (message.event == PM_EVENT_PRETHAW)
+               ohci_usb_reset(ohci);
+
+       clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+
+       spin_unlock_irqrestore(&ohci->lock, flags);
+       return 0;
+}
+
+static int ssb_ohci_hcd_resume(struct usb_hcd *hcd)
+{
+       set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+       usb_hcd_resume_root_hub(hcd);
+       return 0;
+}
+#endif /* CONFIG_PM */
+
+static const struct hc_driver ssb_ohci_hc_driver = {
+       .description            = "ssb-usb-ohci",
+       .product_desc           = "SSB OHCI Controller",
+       .hcd_priv_size          = sizeof(struct ssb_ohci_device),
+
+       .irq                    = ohci_irq,
+       .flags                  = HCD_MEMORY | HCD_USB11,
+
+       .reset                  = ssb_ohci_reset,
+       .start                  = ssb_ohci_start,
+       .stop                   = ohci_stop,
+       .shutdown               = ohci_shutdown,
+
+#ifdef CONFIG_PM
+       .suspend                = ssb_ohci_hcd_suspend,
+       .resume                 = ssb_ohci_hcd_resume,
+#endif
+
+       .urb_enqueue            = ohci_urb_enqueue,
+       .urb_dequeue            = ohci_urb_dequeue,
+       .endpoint_disable       = ohci_endpoint_disable,
+
+       .get_frame_number       = ohci_get_frame,
+
+       .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,
+};
+
+static void ssb_ohci_detach(struct ssb_device *dev)
+{
+       struct usb_hcd *hcd = ssb_get_drvdata(dev);
+
+       usb_remove_hcd(hcd);
+       iounmap(hcd->regs);
+       usb_put_hcd(hcd);
+       ssb_device_disable(dev, 0);
+}
+
+static int ssb_ohci_attach(struct ssb_device *dev)
+{
+       struct ssb_ohci_device *ohcidev;
+       struct usb_hcd *hcd;
+       int err = -ENOMEM;
+       u32 tmp, flags = 0;
+
+       if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV)
+               flags |= SSB_OHCI_TMSLOW_HOSTMODE;
+
+       ssb_device_enable(dev, flags);
+
+       hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev,
+                       dev->dev->bus_id);
+       if (!hcd)
+               goto err_dev_disable;
+       ohcidev = hcd_to_ssb_ohci(hcd);
+       ohcidev->enable_flags = flags;
+
+       tmp = ssb_read32(dev, SSB_ADMATCH0);
+       hcd->rsrc_start = ssb_admatch_base(tmp);
+       hcd->rsrc_len = ssb_admatch_size(tmp);
+       hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
+       if (!hcd->regs)
+               goto err_put_hcd;
+       err = usb_add_hcd(hcd, dev->irq, IRQF_SHARED);
+       if (err)
+               goto err_iounmap;
+
+       ssb_set_drvdata(dev, hcd);
+
+       return err;
+
+err_iounmap:
+       iounmap(hcd->regs);
+err_put_hcd:
+       usb_put_hcd(hcd);
+err_dev_disable:
+       ssb_device_disable(dev, flags);
+       return err;
+}
+
+static int ssb_ohci_probe(struct ssb_device *dev,
+               const struct ssb_device_id *id)
+{
+       int err;
+       u16 chipid_top;
+
+       /* USBcores are only connected on embedded devices. */
+       chipid_top = (dev->bus->chip_id & 0xFF00);
+       if (chipid_top != 0x4700 && chipid_top != 0x5300)
+               return -ENODEV;
+
+       /* TODO: Probably need checks here; is the core connected? */
+
+       if (usb_disabled())
+               return -ENODEV;
+
+       /* We currently always attach SSB_DEV_USB11_HOSTDEV
+        * as HOST OHCI. If we want to attach it as Client device,
+        * we must branch here and call into the (yet to
+        * be written) Client mode driver. Same for remove(). */
+
+       err = ssb_ohci_attach(dev);
+
+       return err;
+}
+
+static void ssb_ohci_remove(struct ssb_device *dev)
+{
+       ssb_ohci_detach(dev);
+}
+
+#ifdef CONFIG_PM
+
+static int ssb_ohci_suspend(struct ssb_device *dev, pm_message_t state)
+{
+       ssb_device_disable(dev, 0);
+
+       return 0;
+}
+
+static int ssb_ohci_resume(struct ssb_device *dev)
+{
+       struct usb_hcd *hcd = ssb_get_drvdata(dev);
+       struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
+
+       ssb_device_enable(dev, ohcidev->enable_flags);
+
+       return 0;
+}
+
+#else /* !CONFIG_PM */
+#define ssb_ohci_suspend       NULL
+#define ssb_ohci_resume        NULL
+#endif /* CONFIG_PM */
+
+static const struct ssb_device_id ssb_ohci_table[] = {
+       SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV),
+       SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV),
+       SSB_DEVTABLE_END
+};
+MODULE_DEVICE_TABLE(ssb, ssb_ohci_table);
+
+static struct ssb_driver ssb_ohci_driver = {
+       .name           = KBUILD_MODNAME,
+       .id_table       = ssb_ohci_table,
+       .probe          = ssb_ohci_probe,
+       .remove         = ssb_ohci_remove,
+       .suspend        = ssb_ohci_suspend,
+       .resume         = ssb_ohci_resume,
+};
index 4ada43cf1387db28fefe811f18f5e02ac098666c..47c5c66a282c55fdc24f0f6b654c39fb7137f9ee 100644 (file)
@@ -398,11 +398,38 @@ struct ohci_hcd {
 #define        OHCI_QUIRK_BE_MMIO      0x10                    /* BE registers */
 #define        OHCI_QUIRK_ZFMICRO      0x20                    /* Compaq ZFMicro chipset*/
 #define        OHCI_QUIRK_NEC          0x40                    /* lost interrupts */
+#define        OHCI_QUIRK_FRAME_NO     0x80                    /* no big endian frame_no shift */
        // there are also chip quirks/bugs in init logic
 
        struct work_struct      nec_work;       /* Worker for NEC quirk */
+
+       /* Needed for ZF Micro quirk */
+       struct timer_list       unlink_watchdog;
+       unsigned                eds_scheduled;
+       struct ed               *ed_to_check;
+       unsigned                zf_delay;
 };
 
+#ifdef CONFIG_PCI
+static inline int quirk_nec(struct ohci_hcd *ohci)
+{
+       return ohci->flags & OHCI_QUIRK_NEC;
+}
+static inline int quirk_zfmicro(struct ohci_hcd *ohci)
+{
+       return ohci->flags & OHCI_QUIRK_ZFMICRO;
+}
+#else
+static inline int quirk_nec(struct ohci_hcd *ohci)
+{
+       return 0;
+}
+static inline int quirk_zfmicro(struct ohci_hcd *ohci)
+{
+       return 0;
+}
+#endif
+
 /* convert between an hcd pointer and the corresponding ohci_hcd */
 static inline struct ohci_hcd *hcd_to_ohci (struct usb_hcd *hcd)
 {
@@ -607,15 +634,12 @@ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
 /* HCCA frame number is 16 bits, but is accessed as 32 bits since not all
  * hardware handles 16 bit reads.  That creates a different confusion on
  * some big-endian SOC implementations.  Same thing happens with PSW access.
- *
- * FIXME: Deal with that as a runtime quirk when STB03xxx is ported over
- * to arch/powerpc
  */
 
-#ifdef CONFIG_STB03xxx
-#define OHCI_BE_FRAME_NO_SHIFT 16
+#ifdef CONFIG_PPC_MPC52xx
+#define big_endian_frame_no_quirk(ohci)        (ohci->flags & OHCI_QUIRK_FRAME_NO)
 #else
-#define OHCI_BE_FRAME_NO_SHIFT 0
+#define big_endian_frame_no_quirk(ohci)        0
 #endif
 
 static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
@@ -623,7 +647,8 @@ static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
        u32 tmp;
        if (big_endian_desc(ohci)) {
                tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no);
-               tmp >>= OHCI_BE_FRAME_NO_SHIFT;
+               if (!big_endian_frame_no_quirk(ohci))
+                       tmp >>= 16;
        } else
                tmp = le32_to_cpup((__force __le32 *)&ohci->hcca->frame_no);
 
index 40a1de4c256efafabc5ca528d97b6f6361413def..ae8ec4474eb801a1a748d3480cbbcb3fed1ddfd8 100644 (file)
@@ -782,10 +782,12 @@ static void force_dequeue(struct r8a66597 *r8a66597, u16 pipenum, u16 address)
                kfree(td);
 
                if (urb) {
-                       urb->status = -ENODEV;
-                       urb->hcpriv = NULL;
+                       usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597),
+                                       urb);
+
                        spin_unlock(&r8a66597->lock);
-                       usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb);
+                       usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb,
+                                       -ENODEV);
                        spin_lock(&r8a66597->lock);
                }
                break;
@@ -832,7 +834,7 @@ static void init_pipe_info(struct r8a66597 *r8a66597, struct urb *urb,
        info.pipenum = get_empty_pipenum(r8a66597, ep);
        info.address = get_urb_to_r8a66597_addr(r8a66597, urb);
        info.epnum = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
-       info.maxpacket = ep->wMaxPacketSize;
+       info.maxpacket = le16_to_cpu(ep->wMaxPacketSize);
        info.type = get_r8a66597_type(ep->bmAttributes
                                      & USB_ENDPOINT_XFERTYPE_MASK);
        info.bufnum = get_bufnum(info.pipenum);
@@ -923,7 +925,7 @@ static void prepare_setup_packet(struct r8a66597 *r8a66597,
        r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1);
 
        for (i = 0; i < 4; i++) {
-               r8a66597_write(r8a66597, p[i], setup_addr);
+               r8a66597_write(r8a66597, cpu_to_le16(p[i]), setup_addr);
                setup_addr += 2;
        }
        r8a66597_write(r8a66597, SUREQ, DCPCTR);
@@ -1032,6 +1034,15 @@ static void prepare_status_packet(struct r8a66597 *r8a66597,
        pipe_start(r8a66597, td->pipe);
 }
 
+static int is_set_address(unsigned char *setup_packet)
+{
+       if (((setup_packet[0] & USB_TYPE_MASK) == USB_TYPE_STANDARD) &&
+                       setup_packet[1] == USB_REQ_SET_ADDRESS)
+               return 1;
+       else
+               return 0;
+}
+
 /* this function must be called with interrupt disabled */
 static int start_transfer(struct r8a66597 *r8a66597, struct r8a66597_td *td)
 {
@@ -1039,7 +1050,7 @@ static int start_transfer(struct r8a66597 *r8a66597, struct r8a66597_td *td)
 
        switch (td->type) {
        case USB_PID_SETUP:
-               if (td->urb->setup_packet[1] == USB_REQ_SET_ADDRESS) {
+               if (is_set_address(td->urb->setup_packet)) {
                        td->set_address = 1;
                        td->urb->setup_packet[2] = alloc_usb_address(r8a66597,
                                                                     td->urb);
@@ -1106,8 +1117,9 @@ static void set_td_timer(struct r8a66597 *r8a66597, struct r8a66597_td *td)
 }
 
 /* this function must be called with interrupt disabled */
-static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td,
-                u16 pipenum, struct urb *urb)
+static void finish_request(struct r8a66597 *r8a66597, struct r8a66597_td *td,
+               u16 pipenum, struct urb *urb, int status)
+__releases(r8a66597->lock) __acquires(r8a66597->lock)
 {
        int restart = 0;
        struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597);
@@ -1115,7 +1127,7 @@ static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td,
        r8a66597->timeout_map &= ~(1 << pipenum);
 
        if (likely(td)) {
-               if (td->set_address && urb->status != 0)
+               if (td->set_address && (status != 0 || urb->unlinked))
                        r8a66597->address_map &= ~(1 << urb->setup_packet[2]);
 
                pipe_toggle_save(r8a66597, td->pipe, urb);
@@ -1130,9 +1142,9 @@ static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td,
                if (usb_pipeisoc(urb->pipe))
                        urb->start_frame = r8a66597_get_frame(hcd);
 
-               urb->hcpriv = NULL;
+               usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), urb);
                spin_unlock(&r8a66597->lock);
-               usb_hcd_giveback_urb(hcd, urb);
+               usb_hcd_giveback_urb(hcd, urb, status);
                spin_lock(&r8a66597->lock);
        }
 
@@ -1146,14 +1158,6 @@ static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td,
        }
 }
 
-/* this function must be called with interrupt disabled */
-static void finish_request(struct r8a66597 *r8a66597, struct r8a66597_td *td,
-                          u16 pipenum, struct urb *urb)
-__releases(r8a66597->lock) __acquires(r8a66597->lock)
-{
-       done(r8a66597, td, pipenum, urb);
-}
-
 static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
 {
        u16 tmp;
@@ -1162,6 +1166,7 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
        struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum);
        struct urb *urb;
        int finish = 0;
+       int status = 0;
 
        if (unlikely(!td))
                return;
@@ -1170,17 +1175,15 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
        fifo_change_from_pipe(r8a66597, td->pipe);
        tmp = r8a66597_read(r8a66597, td->pipe->fifoctr);
        if (unlikely((tmp & FRDY) == 0)) {
-               urb->status = -EPIPE;
                pipe_stop(r8a66597, td->pipe);
                pipe_irq_disable(r8a66597, pipenum);
                err("in fifo not ready (%d)", pipenum);
-               finish_request(r8a66597, td, pipenum, td->urb);
+               finish_request(r8a66597, td, pipenum, td->urb, -EPIPE);
                return;
        }
 
        /* prepare parameters */
        rcv_len = tmp & DTLN;
-       bufsize = td->maxpacket;
        if (usb_pipeisoc(urb->pipe)) {
                buf = (u16 *)(urb->transfer_buffer +
                                urb->iso_frame_desc[td->iso_cnt].offset);
@@ -1189,29 +1192,31 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
                buf = (void *)urb->transfer_buffer + urb->actual_length;
                urb_len = urb->transfer_buffer_length - urb->actual_length;
        }
-       if (rcv_len < bufsize)
-               size = min(rcv_len, urb_len);
-       else
-               size = min(bufsize, urb_len);
+       bufsize = min(urb_len, (int) td->maxpacket);
+       if (rcv_len <= bufsize) {
+               size = rcv_len;
+       } else {
+               size = bufsize;
+               status = -EOVERFLOW;
+               finish = 1;
+       }
 
        /* update parameters */
        urb->actual_length += size;
        if (rcv_len == 0)
                td->zero_packet = 1;
-       if ((size % td->maxpacket) > 0) {
+       if (rcv_len < bufsize) {
                td->short_packet = 1;
-               if (urb->transfer_buffer_length != urb->actual_length &&
-                   urb->transfer_flags & URB_SHORT_NOT_OK)
-                       td->urb->status = -EREMOTEIO;
        }
        if (usb_pipeisoc(urb->pipe)) {
                urb->iso_frame_desc[td->iso_cnt].actual_length = size;
-               urb->iso_frame_desc[td->iso_cnt].status = 0;
+               urb->iso_frame_desc[td->iso_cnt].status = status;
                td->iso_cnt++;
+               finish = 0;
        }
 
        /* check transfer finish */
-       if (check_transfer_finish(td, urb)) {
+       if (finish || check_transfer_finish(td, urb)) {
                pipe_stop(r8a66597, td->pipe);
                pipe_irq_disable(r8a66597, pipenum);
                finish = 1;
@@ -1226,11 +1231,8 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
                                           buf, size);
        }
 
-       if (finish && pipenum != 0) {
-               if (td->urb->status == -EINPROGRESS)
-                       td->urb->status = 0;
-               finish_request(r8a66597, td, pipenum, urb);
-       }
+       if (finish && pipenum != 0)
+               finish_request(r8a66597, td, pipenum, urb, status);
 }
 
 static void packet_write(struct r8a66597 *r8a66597, u16 pipenum)
@@ -1248,11 +1250,10 @@ static void packet_write(struct r8a66597 *r8a66597, u16 pipenum)
        fifo_change_from_pipe(r8a66597, td->pipe);
        tmp = r8a66597_read(r8a66597, td->pipe->fifoctr);
        if (unlikely((tmp & FRDY) == 0)) {
-               urb->status = -EPIPE;
                pipe_stop(r8a66597, td->pipe);
                pipe_irq_disable(r8a66597, pipenum);
                err("out write fifo not ready. (%d)", pipenum);
-               finish_request(r8a66597, td, pipenum, td->urb);
+               finish_request(r8a66597, td, pipenum, urb, -EPIPE);
                return;
        }
 
@@ -1297,7 +1298,7 @@ static void packet_write(struct r8a66597 *r8a66597, u16 pipenum)
 }
 
 
-static void check_next_phase(struct r8a66597 *r8a66597)
+static void check_next_phase(struct r8a66597 *r8a66597, int status)
 {
        struct r8a66597_td *td = r8a66597_get_td(r8a66597, 0);
        struct urb *urb;
@@ -1310,49 +1311,41 @@ static void check_next_phase(struct r8a66597 *r8a66597)
        switch (td->type) {
        case USB_PID_IN:
        case USB_PID_OUT:
-               if (urb->status != -EINPROGRESS) {
-                       finish = 1;
-                       break;
-               }
                if (check_transfer_finish(td, urb))
                        td->type = USB_PID_ACK;
                break;
        case USB_PID_SETUP:
-               if (urb->status != -EINPROGRESS)
-                       finish = 1;
-               else if (urb->transfer_buffer_length == urb->actual_length) {
+               if (urb->transfer_buffer_length == urb->actual_length)
                        td->type = USB_PID_ACK;
-                       urb->status = 0;
-               } else if (usb_pipeout(urb->pipe))
+               else if (usb_pipeout(urb->pipe))
                        td->type = USB_PID_OUT;
                else
                        td->type = USB_PID_IN;
                break;
        case USB_PID_ACK:
                finish = 1;
-               if (urb->status == -EINPROGRESS)
-                       urb->status = 0;
                break;
        }
 
-       if (finish)
-               finish_request(r8a66597, td, 0, urb);
+       if (finish || status != 0 || urb->unlinked)
+               finish_request(r8a66597, td, 0, urb, status);
        else
                start_transfer(r8a66597, td);
 }
 
-static void set_urb_error(struct r8a66597 *r8a66597, u16 pipenum)
+static int get_urb_error(struct r8a66597 *r8a66597, u16 pipenum)
 {
        struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum);
 
-       if (td && td->urb) {
+       if (td) {
                u16 pid = r8a66597_read(r8a66597, td->pipe->pipectr) & PID;
 
                if (pid == PID_NAK)
-                       td->urb->status = -ECONNRESET;
+                       return -ECONNRESET;
                else
-                       td->urb->status = -EPIPE;
+                       return -EPIPE;
        }
+       return 0;
 }
 
 static void irq_pipe_ready(struct r8a66597 *r8a66597)
@@ -1371,7 +1364,7 @@ static void irq_pipe_ready(struct r8a66597 *r8a66597)
                        packet_read(r8a66597, 0);
                else
                        pipe_irq_disable(r8a66597, 0);
-               check_next_phase(r8a66597);
+               check_next_phase(r8a66597, 0);
        }
 
        for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
@@ -1405,7 +1398,7 @@ static void irq_pipe_empty(struct r8a66597 *r8a66597)
                td = r8a66597_get_td(r8a66597, 0);
                if (td && td->type != USB_PID_OUT)
                        disable_irq_empty(r8a66597, 0);
-               check_next_phase(r8a66597);
+               check_next_phase(r8a66597, 0);
        }
 
        for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
@@ -1420,9 +1413,8 @@ static void irq_pipe_empty(struct r8a66597 *r8a66597)
                        if ((tmp & INBUFM) == 0) {
                                disable_irq_empty(r8a66597, pipenum);
                                pipe_irq_disable(r8a66597, pipenum);
-                               if (td->urb->status == -EINPROGRESS)
-                                       td->urb->status = 0;
-                               finish_request(r8a66597, td, pipenum, td->urb);
+                               finish_request(r8a66597, td, pipenum, td->urb,
+                                               0);
                        }
                }
        }
@@ -1433,15 +1425,16 @@ static void irq_pipe_nrdy(struct r8a66597 *r8a66597)
        u16 check;
        u16 pipenum;
        u16 mask;
+       int status;
 
        mask = r8a66597_read(r8a66597, NRDYSTS)
               & r8a66597_read(r8a66597, NRDYENB);
        r8a66597_write(r8a66597, ~mask, NRDYSTS);
        if (mask & NRDY0) {
                cfifo_change(r8a66597, 0);
-               set_urb_error(r8a66597, 0);
+               status = get_urb_error(r8a66597, 0);
                pipe_irq_disable(r8a66597, 0);
-               check_next_phase(r8a66597);
+               check_next_phase(r8a66597, status);
        }
 
        for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
@@ -1452,10 +1445,10 @@ static void irq_pipe_nrdy(struct r8a66597 *r8a66597)
                        if (unlikely(!td))
                                continue;
 
-                       set_urb_error(r8a66597, pipenum);
+                       status = get_urb_error(r8a66597, pipenum);
                        pipe_irq_disable(r8a66597, pipenum);
                        pipe_stop(r8a66597, td->pipe);
-                       finish_request(r8a66597, td, pipenum, td->urb);
+                       finish_request(r8a66597, td, pipenum, td->urb, status);
                }
        }
 }
@@ -1475,6 +1468,7 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd)
        u16 intsts0, intsts1, intsts2;
        u16 intenb0, intenb1, intenb2;
        u16 mask0, mask1, mask2;
+       int status;
 
        spin_lock(&r8a66597->lock);
 
@@ -1518,12 +1512,12 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd)
                }
                if (mask1 & SIGN) {
                        r8a66597_write(r8a66597, ~SIGN, INTSTS1);
-                       set_urb_error(r8a66597, 0);
-                       check_next_phase(r8a66597);
+                       status = get_urb_error(r8a66597, 0);
+                       check_next_phase(r8a66597, status);
                }
                if (mask1 & SACK) {
                        r8a66597_write(r8a66597, ~SACK, INTSTS1);
-                       check_next_phase(r8a66597);
+                       check_next_phase(r8a66597, 0);
                }
        }
        if (mask0) {
@@ -1722,21 +1716,25 @@ static struct r8a66597_td *r8a66597_make_td(struct r8a66597 *r8a66597,
 }
 
 static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
-                               struct usb_host_endpoint *hep,
                                struct urb *urb,
                                gfp_t mem_flags)
 {
+       struct usb_host_endpoint *hep = urb->ep;
        struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
        struct r8a66597_td *td = NULL;
-       int ret = 0, request = 0;
+       int ret, request = 0;
        unsigned long flags;
 
        spin_lock_irqsave(&r8a66597->lock, flags);
        if (!get_urb_to_r8a66597_dev(r8a66597, urb)) {
                ret = -ENODEV;
-               goto error;
+               goto error_not_linked;
        }
 
+       ret = usb_hcd_link_urb_to_ep(hcd, urb);
+       if (ret)
+               goto error_not_linked;
+
        if (!hep->hcpriv) {
                hep->hcpriv = kzalloc(sizeof(struct r8a66597_pipe),
                                GFP_ATOMIC);
@@ -1761,15 +1759,7 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
        if (list_empty(&r8a66597->pipe_queue[td->pipenum]))
                request = 1;
        list_add_tail(&td->queue, &r8a66597->pipe_queue[td->pipenum]);
-
-       spin_lock(&urb->lock);
-       if (urb->status != -EINPROGRESS) {
-               spin_unlock(&urb->lock);
-               ret = -EPIPE;
-               goto error;
-       }
        urb->hcpriv = td;
-       spin_unlock(&urb->lock);
 
        if (request) {
                ret = start_transfer(r8a66597, td);
@@ -1781,26 +1771,36 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
                set_td_timer(r8a66597, td);
 
 error:
+       if (ret)
+               usb_hcd_unlink_urb_from_ep(hcd, urb);
+error_not_linked:
        spin_unlock_irqrestore(&r8a66597->lock, flags);
        return ret;
 }
 
-static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
+               int status)
 {
        struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
        struct r8a66597_td *td;
        unsigned long flags;
+       int rc;
 
        spin_lock_irqsave(&r8a66597->lock, flags);
+       rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+       if (rc)
+               goto done;
+
        if (urb->hcpriv) {
                td = urb->hcpriv;
                pipe_stop(r8a66597, td->pipe);
                pipe_irq_disable(r8a66597, td->pipenum);
                disable_irq_empty(r8a66597, td->pipenum);
-               done(r8a66597, td, td->pipenum, urb);
+               finish_request(r8a66597, td, td->pipenum, urb, status);
        }
+ done:
        spin_unlock_irqrestore(&r8a66597->lock, flags);
-       return 0;
+       return rc;
 }
 
 static void r8a66597_endpoint_disable(struct usb_hcd *hcd,
@@ -1830,7 +1830,7 @@ static void r8a66597_endpoint_disable(struct usb_hcd *hcd,
        td = r8a66597_get_td(r8a66597, pipenum);
        if (td)
                urb = td->urb;
-       done(r8a66597, td, pipenum, urb);
+       finish_request(r8a66597, td, pipenum, urb, -ESHUTDOWN);
        kfree(hep->hcpriv);
        hep->hcpriv = NULL;
        spin_unlock_irqrestore(&r8a66597->lock, flags);
@@ -2027,7 +2027,7 @@ static int r8a66597_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
        case GetPortStatus:
                if (wIndex > R8A66597_MAX_ROOT_HUB)
                        goto error;
-               *(u32 *)buf = rh->port;
+               *(u32 *)buf = cpu_to_le32(rh->port);
                break;
        case SetPortFeature:
                if (wIndex > R8A66597_MAX_ROOT_HUB)
@@ -2126,8 +2126,8 @@ static int __init_or_module r8a66597_remove(struct platform_device *pdev)
        struct usb_hcd          *hcd = r8a66597_to_hcd(r8a66597);
 
        del_timer_sync(&r8a66597->rh_timer);
-       iounmap((void *)r8a66597->reg);
        usb_remove_hcd(hcd);
+       iounmap((void *)r8a66597->reg);
        usb_put_hcd(hcd);
        return 0;
 }
index 4cfa3ff2c993249045d2c08dd570156e22c3ce87..94d859aa73f818bc389dc10db5e3c490b760581a 100644 (file)
@@ -435,14 +435,9 @@ static void finish_request(
        if (usb_pipecontrol(urb->pipe))
                ep->nextpid = USB_PID_SETUP;
 
-       spin_lock(&urb->lock);
-       if (urb->status == -EINPROGRESS)
-               urb->status = status;
-       urb->hcpriv = NULL;
-       spin_unlock(&urb->lock);
-
+       usb_hcd_unlink_urb_from_ep(sl811_to_hcd(sl811), urb);
        spin_unlock(&sl811->lock);
-       usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb);
+       usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb, status);
        spin_lock(&sl811->lock);
 
        /* leave active endpoints in the schedule */
@@ -538,35 +533,21 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank)
                                                bank + SL11H_XFERCNTREG);
                        if (len > ep->length) {
                                len = ep->length;
-                               urb->status = -EOVERFLOW;
+                               urbstat = -EOVERFLOW;
                        }
                        urb->actual_length += len;
                        sl811_read_buf(sl811, SL811HS_PACKET_BUF(bank == 0),
                                        buf, len);
                        usb_dotoggle(udev, ep->epnum, 0);
-                       if (urb->actual_length == urb->transfer_buffer_length)
-                               urbstat = 0;
-                       else if (len < ep->maxpacket) {
-                               if (urb->transfer_flags & URB_SHORT_NOT_OK)
-                                       urbstat = -EREMOTEIO;
+                       if (urbstat == -EINPROGRESS &&
+                                       (len < ep->maxpacket ||
+                                               urb->actual_length ==
+                                               urb->transfer_buffer_length)) {
+                               if (usb_pipecontrol(urb->pipe))
+                                       ep->nextpid = USB_PID_ACK;
                                else
                                        urbstat = 0;
                        }
-                       if (usb_pipecontrol(urb->pipe)
-                                       && (urbstat == -EREMOTEIO
-                                               || urbstat == 0)) {
-
-                               /* NOTE if the status stage STALLs (why?),
-                                * this reports the wrong urb status.
-                                */
-                               spin_lock(&urb->lock);
-                               if (urb->status == -EINPROGRESS)
-                                       urb->status = urbstat;
-                               spin_unlock(&urb->lock);
-
-                               urb = NULL;
-                               ep->nextpid = USB_PID_ACK;
-                       }
                        break;
                case USB_PID_SETUP:
                        // PACKET("...ACK/setup_%02x qh%p\n", bank, ep);
@@ -605,7 +586,7 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank)
                                bank, status, ep, urbstat);
        }
 
-       if (urb && (urbstat != -EINPROGRESS || urb->status != -EINPROGRESS))
+       if (urbstat != -EINPROGRESS || urb->unlinked)
                finish_request(sl811, ep, urb, urbstat);
 }
 
@@ -807,7 +788,6 @@ static int balance(struct sl811 *sl811, u16 period, u16 load)
 
 static int sl811h_urb_enqueue(
        struct usb_hcd          *hcd,
-       struct usb_host_endpoint *hep,
        struct urb              *urb,
        gfp_t                   mem_flags
 ) {
@@ -820,7 +800,8 @@ static int sl811h_urb_enqueue(
        struct sl811h_ep        *ep = NULL;
        unsigned long           flags;
        int                     i;
-       int                     retval = 0;
+       int                     retval;
+       struct usb_host_endpoint        *hep = urb->ep;
 
 #ifdef DISABLE_ISO
        if (type == PIPE_ISOCHRONOUS)
@@ -838,7 +819,12 @@ static int sl811h_urb_enqueue(
                        || !HC_IS_RUNNING(hcd->state)) {
                retval = -ENODEV;
                kfree(ep);
-               goto fail;
+               goto fail_not_linked;
+       }
+       retval = usb_hcd_link_urb_to_ep(hcd, urb);
+       if (retval) {
+               kfree(ep);
+               goto fail_not_linked;
        }
 
        if (hep->hcpriv) {
@@ -951,37 +937,31 @@ static int sl811h_urb_enqueue(
                sofirq_on(sl811);
        }
 
-       /* in case of unlink-during-submit */
-       spin_lock(&urb->lock);
-       if (urb->status != -EINPROGRESS) {
-               spin_unlock(&urb->lock);
-               finish_request(sl811, ep, urb, 0);
-               retval = 0;
-               goto fail;
-       }
        urb->hcpriv = hep;
-       spin_unlock(&urb->lock);
-
        start_transfer(sl811);
        sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable);
 fail:
+       if (retval)
+               usb_hcd_unlink_urb_from_ep(hcd, urb);
+fail_not_linked:
        spin_unlock_irqrestore(&sl811->lock, flags);
        return retval;
 }
 
-static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
        struct sl811            *sl811 = hcd_to_sl811(hcd);
        struct usb_host_endpoint *hep;
        unsigned long           flags;
        struct sl811h_ep        *ep;
-       int                     retval = 0;
+       int                     retval;
 
        spin_lock_irqsave(&sl811->lock, flags);
-       hep = urb->hcpriv;
-       if (!hep)
+       retval = usb_hcd_check_unlink_urb(hcd, urb, status);
+       if (retval)
                goto fail;
 
+       hep = urb->hcpriv;
        ep = hep->hcpriv;
        if (ep) {
                /* finish right away if this urb can't be active ...
@@ -1029,8 +1009,8 @@ static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
                        VDBG("dequeue, urb %p active %s; wait4irq\n", urb,
                                (sl811->active_a == ep) ? "A" : "B");
        } else
-fail:
                retval = -EINVAL;
+ fail:
        spin_unlock_irqrestore(&sl811->lock, flags);
        return retval;
 }
index b88eb3c62c0254b2358b693926b836bffa9d1df5..ac283b09a63f873c7d362f0305bdc957617a66c8 100644 (file)
@@ -51,7 +51,6 @@
 #include <linux/usb.h>
 #include <linux/workqueue.h>
 #include <linux/platform_device.h>
-#include <linux/pci_ids.h>
 #include <linux/mutex.h>
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -184,7 +183,7 @@ struct u132_ring {
 struct u132 {
         struct kref kref;
         struct list_head u132_list;
-        struct semaphore sw_lock;
+        struct mutex sw_lock;
         struct semaphore scheduler_lock;
         struct u132_platform_data *board;
         struct platform_device *platform_dev;
@@ -493,20 +492,20 @@ static void u132_hcd_monitor_work(struct work_struct *work)
                 return;
         } else {
                 int retval;
-                down(&u132->sw_lock);
+                mutex_lock(&u132->sw_lock);
                 retval = read_roothub_info(u132);
                 if (retval) {
                         struct usb_hcd *hcd = u132_to_hcd(u132);
                         u132_disable(u132);
                         u132->going = 1;
-                        up(&u132->sw_lock);
+                        mutex_unlock(&u132->sw_lock);
                         usb_hc_died(hcd);
                         ftdi_elan_gone_away(u132->platform_dev);
                         u132_monitor_put_kref(u132);
                         return;
                 } else {
                         u132_monitor_requeue_work(u132, 500);
-                        up(&u132->sw_lock);
+                        mutex_unlock(&u132->sw_lock);
                         return;
                 }
         }
@@ -519,9 +518,8 @@ static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp,
         unsigned long irqs;
         struct usb_hcd *hcd = u132_to_hcd(u132);
         urb->error_count = 0;
-        urb->status = status;
-        urb->hcpriv = NULL;
         spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+       usb_hcd_unlink_urb_from_ep(hcd, urb);
         endp->queue_next += 1;
         if (ENDP_QUEUE_SIZE > --endp->queue_size) {
                 endp->active = 0;
@@ -543,7 +541,7 @@ static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp,
         u132_ring_queue_work(u132, ring, 0);
         up(&u132->scheduler_lock);
         u132_endp_put_kref(u132, endp);
-        usb_hcd_giveback_urb(hcd, urb);
+       usb_hcd_giveback_urb(hcd, urb, status);
         return;
 }
 
@@ -559,9 +557,8 @@ static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp,
         unsigned long irqs;
         struct usb_hcd *hcd = u132_to_hcd(u132);
         urb->error_count = 0;
-        urb->status = status;
-        urb->hcpriv = NULL;
         spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+       usb_hcd_unlink_urb_from_ep(hcd, urb);
         endp->queue_next += 1;
         if (ENDP_QUEUE_SIZE > --endp->queue_size) {
                 endp->active = 0;
@@ -576,7 +573,7 @@ static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp,
                 endp->active = 0;
                 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
                 kfree(urbq);
-        } usb_hcd_giveback_urb(hcd, urb);
+       } usb_hcd_giveback_urb(hcd, urb, status);
         return;
 }
 
@@ -646,12 +643,12 @@ static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf,
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "device is being removed "
+                               "urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+       } else if (!urb->unlinked) {
                 struct u132_ring *ring = endp->ring;
                 u8 *u = urb->transfer_buffer + urb->actual_length;
                 u8 *b = buf;
@@ -717,10 +714,10 @@ static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf,
                         return;
                 }
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+                               "unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+               u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -745,12 +742,12 @@ static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf,
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "device is being removed "
+                               "urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+       } else if (!urb->unlinked) {
                 struct u132_ring *ring = endp->ring;
                 urb->actual_length += len;
                 endp->toggle_bits = toggle_bits;
@@ -769,10 +766,10 @@ static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf,
                         return;
                 }
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+                               "unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+               u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -798,12 +795,12 @@ static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf,
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "device is being removed "
+                               "urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+       } else if (!urb->unlinked) {
                 struct u132_ring *ring = endp->ring;
                 u8 *u = urb->transfer_buffer + urb->actual_length;
                 u8 *b = buf;
@@ -872,10 +869,10 @@ static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf,
                         return;
                 }
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+                               "unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+               u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -899,20 +896,20 @@ static void u132_hcd_configure_empty_sent(void *data, struct urb *urb, u8 *buf,
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "device is being removed "
+                               "urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+       } else if (!urb->unlinked) {
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+                               "unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+               u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -937,12 +934,12 @@ static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf,
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "device is being removed "
+                               "urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+       } else if (!urb->unlinked) {
                 struct u132_ring *ring = endp->ring;
                 u8 *u = urb->transfer_buffer;
                 u8 *b = buf;
@@ -981,10 +978,10 @@ static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf,
                         return;
                 }
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+                               "unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+               u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1008,20 +1005,20 @@ static void u132_hcd_configure_empty_recv(void *data, struct urb *urb, u8 *buf,
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "device is being removed "
+                               "urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+       } else if (!urb->unlinked) {
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+                               "unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+               u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1046,12 +1043,12 @@ static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf,
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "device is being removed "
+                               "urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+       } else if (!urb->unlinked) {
                 if (usb_pipein(urb->pipe)) {
                         int retval;
                         struct u132_ring *ring = endp->ring;
@@ -1078,10 +1075,10 @@ static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf,
                         return;
                 }
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+                               "unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+               u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1107,22 +1104,22 @@ static void u132_hcd_enumeration_empty_recv(void *data, struct urb *urb,
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "device is being removed "
+                               "urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+       } else if (!urb->unlinked) {
                 u132->addr[0].address = 0;
                 endp->usb_addr = udev->usb_addr;
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+                               "unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+               u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1146,12 +1143,12 @@ static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb,
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "device is being removed "
+                               "urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+       } else if (!urb->unlinked) {
                 int retval;
                 struct u132_ring *ring = endp->ring;
                 up(&u132->scheduler_lock);
@@ -1163,10 +1160,10 @@ static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb,
                         u132_hcd_giveback_urb(u132, endp, urb, retval);
                 return;
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+                               "unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+               u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1190,20 +1187,20 @@ static void u132_hcd_initial_empty_sent(void *data, struct urb *urb, u8 *buf,
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "device is being removed "
+                               "urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+       } else if (!urb->unlinked) {
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+                               "unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+               u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1228,12 +1225,12 @@ static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf,
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "device is being removed "
+                               "urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+       } else if (!urb->unlinked) {
                 int retval;
                 struct u132_ring *ring = endp->ring;
                 u8 *u = urb->transfer_buffer;
@@ -1252,10 +1249,10 @@ static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf,
                         u132_hcd_giveback_urb(u132, endp, urb, retval);
                 return;
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+                               "unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+               u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1280,12 +1277,12 @@ static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf,
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "device is being removed "
+                               "urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+       } else if (!urb->unlinked) {
                 int retval;
                 struct u132_ring *ring = endp->ring;
                 up(&u132->scheduler_lock);
@@ -1297,10 +1294,10 @@ static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf,
                         u132_hcd_giveback_urb(u132, endp, urb, retval);
                 return;
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+                               "unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+               u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1805,10 +1802,10 @@ static void u132_hcd_stop(struct usb_hcd *hcd)
                 dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov"
                         "ed\n", hcd);
         } else {
-                down(&u132->sw_lock);
+                mutex_lock(&u132->sw_lock);
                 msleep(100);
                 u132_power(u132, 0);
-                up(&u132->sw_lock);
+                mutex_unlock(&u132->sw_lock);
         }
 }
 
@@ -1830,7 +1827,7 @@ static int u132_hcd_start(struct usb_hcd *hcd)
                         (pdev->dev.platform_data))->vendor;
                 u16 device = ((struct u132_platform_data *)
                         (pdev->dev.platform_data))->device;
-                down(&u132->sw_lock);
+                mutex_lock(&u132->sw_lock);
                 msleep(10);
                 if (vendor == PCI_VENDOR_ID_AMD && device == 0x740c) {
                         u132->flags = OHCI_QUIRK_AMD756;
@@ -1845,7 +1842,7 @@ static int u132_hcd_start(struct usb_hcd *hcd)
                         u132->going = 1;
                 }
                 msleep(100);
-                up(&u132->sw_lock);
+                mutex_unlock(&u132->sw_lock);
                 return retval;
         } else {
                 dev_err(&u132->platform_dev->dev, "platform_device missing\n");
@@ -1865,32 +1862,44 @@ static int u132_hcd_reset(struct usb_hcd *hcd)
                 return -ESHUTDOWN;
         } else {
                 int retval;
-                down(&u132->sw_lock);
+                mutex_lock(&u132->sw_lock);
                 retval = u132_init(u132);
                 if (retval) {
                         u132_disable(u132);
                         u132->going = 1;
                 }
-                up(&u132->sw_lock);
+                mutex_unlock(&u132->sw_lock);
                 return retval;
         }
 }
 
 static int create_endpoint_and_queue_int(struct u132 *u132,
-        struct u132_udev *udev, struct usb_host_endpoint *hep, struct urb *urb,
+       struct u132_udev *udev, struct urb *urb,
         struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address,
         gfp_t mem_flags)
 {
         struct u132_ring *ring;
         unsigned long irqs;
-        u8 endp_number = ++u132->num_endpoints;
-        struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] =
-                kmalloc(sizeof(struct u132_endp), mem_flags);
+       int rc;
+       u8 endp_number;
+       struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
+
         if (!endp) {
                 return -ENOMEM;
         }
+
+       spin_lock_init(&endp->queue_lock.slock);
+       spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+       rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
+       if (rc) {
+               spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+               kfree(endp);
+               return rc;
+       }
+
+       endp_number = ++u132->num_endpoints;
+       urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
         INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
-        spin_lock_init(&endp->queue_lock.slock);
         INIT_LIST_HEAD(&endp->urb_more);
         ring = endp->ring = &u132->ring[0];
         if (ring->curr_endp) {
@@ -1906,7 +1915,7 @@ static int create_endpoint_and_queue_int(struct u132 *u132,
         endp->delayed = 0;
         endp->endp_number = endp_number;
         endp->u132 = u132;
-        endp->hep = hep;
+       endp->hep = urb->ep;
         endp->pipetype = usb_pipetype(urb->pipe);
         u132_endp_init_kref(u132, endp);
         if (usb_pipein(urb->pipe)) {
@@ -1925,7 +1934,6 @@ static int create_endpoint_and_queue_int(struct u132 *u132,
                 u132_udev_get_kref(u132, udev);
         }
         urb->hcpriv = u132;
-        spin_lock_irqsave(&endp->queue_lock.slock, irqs);
         endp->delayed = 1;
         endp->jiffies = jiffies + msecs_to_jiffies(urb->interval);
         endp->udev_number = address;
@@ -1940,8 +1948,8 @@ static int create_endpoint_and_queue_int(struct u132 *u132,
         return 0;
 }
 
-static int queue_int_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
-        struct usb_host_endpoint *hep, struct urb *urb,
+static int queue_int_on_old_endpoint(struct u132 *u132,
+       struct u132_udev *udev, struct urb *urb,
         struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
         u8 usb_endp, u8 address)
 {
@@ -1965,21 +1973,33 @@ static int queue_int_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
 }
 
 static int create_endpoint_and_queue_bulk(struct u132 *u132,
-        struct u132_udev *udev, struct usb_host_endpoint *hep, struct urb *urb,
+       struct u132_udev *udev, struct urb *urb,
         struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address,
         gfp_t mem_flags)
 {
         int ring_number;
         struct u132_ring *ring;
         unsigned long irqs;
-        u8 endp_number = ++u132->num_endpoints;
-        struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] =
-                kmalloc(sizeof(struct u132_endp), mem_flags);
+       int rc;
+       u8 endp_number;
+       struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
+
         if (!endp) {
                 return -ENOMEM;
         }
+
+       spin_lock_init(&endp->queue_lock.slock);
+       spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+       rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
+       if (rc) {
+               spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+               kfree(endp);
+               return rc;
+       }
+
+       endp_number = ++u132->num_endpoints;
+       urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
         INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
-        spin_lock_init(&endp->queue_lock.slock);
         INIT_LIST_HEAD(&endp->urb_more);
         endp->dequeueing = 0;
         endp->edset_flush = 0;
@@ -1987,7 +2007,7 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132,
         endp->delayed = 0;
         endp->endp_number = endp_number;
         endp->u132 = u132;
-        endp->hep = hep;
+       endp->hep = urb->ep;
         endp->pipetype = usb_pipetype(urb->pipe);
         u132_endp_init_kref(u132, endp);
         if (usb_pipein(urb->pipe)) {
@@ -2016,7 +2036,6 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132,
         }
         ring->length += 1;
         urb->hcpriv = u132;
-        spin_lock_irqsave(&endp->queue_lock.slock, irqs);
         endp->udev_number = address;
         endp->usb_addr = usb_addr;
         endp->usb_endp = usb_endp;
@@ -2030,7 +2049,7 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132,
 }
 
 static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
-         struct usb_host_endpoint *hep, struct urb *urb,
+       struct urb *urb,
         struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
         u8 usb_endp, u8 address)
 {
@@ -2052,19 +2071,32 @@ static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
 }
 
 static int create_endpoint_and_queue_control(struct u132 *u132,
-        struct usb_host_endpoint *hep, struct urb *urb,
+       struct urb *urb,
         struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp,
         gfp_t mem_flags)
 {
         struct u132_ring *ring;
-        u8 endp_number = ++u132->num_endpoints;
-        struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] =
-                kmalloc(sizeof(struct u132_endp), mem_flags);
+       unsigned long irqs;
+       int rc;
+       u8 endp_number;
+       struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
+
         if (!endp) {
                 return -ENOMEM;
         }
+
+       spin_lock_init(&endp->queue_lock.slock);
+       spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+       rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
+       if (rc) {
+               spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+               kfree(endp);
+               return rc;
+       }
+
+       endp_number = ++u132->num_endpoints;
+       urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
         INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
-        spin_lock_init(&endp->queue_lock.slock);
         INIT_LIST_HEAD(&endp->urb_more);
         ring = endp->ring = &u132->ring[0];
         if (ring->curr_endp) {
@@ -2080,11 +2112,10 @@ static int create_endpoint_and_queue_control(struct u132 *u132,
         endp->delayed = 0;
         endp->endp_number = endp_number;
         endp->u132 = u132;
-        endp->hep = hep;
+       endp->hep = urb->ep;
         u132_endp_init_kref(u132, endp);
         u132_endp_get_kref(u132, endp);
         if (usb_addr == 0) {
-                unsigned long irqs;
                 u8 address = u132->addr[usb_addr].address;
                 struct u132_udev *udev = &u132->udev[address];
                 endp->udev_number = address;
@@ -2098,7 +2129,6 @@ static int create_endpoint_and_queue_control(struct u132 *u132,
                 udev->endp_number_in[usb_endp] = endp_number;
                 udev->endp_number_out[usb_endp] = endp_number;
                 urb->hcpriv = u132;
-                spin_lock_irqsave(&endp->queue_lock.slock, irqs);
                 endp->queue_size = 1;
                 endp->queue_last = 0;
                 endp->queue_next = 0;
@@ -2107,7 +2137,6 @@ static int create_endpoint_and_queue_control(struct u132 *u132,
                 u132_endp_queue_work(u132, endp, 0);
                 return 0;
         } else {                /*(usb_addr > 0) */
-                unsigned long irqs;
                 u8 address = u132->addr[usb_addr].address;
                 struct u132_udev *udev = &u132->udev[address];
                 endp->udev_number = address;
@@ -2121,7 +2150,6 @@ static int create_endpoint_and_queue_control(struct u132 *u132,
                 udev->endp_number_in[usb_endp] = endp_number;
                 udev->endp_number_out[usb_endp] = endp_number;
                 urb->hcpriv = u132;
-                spin_lock_irqsave(&endp->queue_lock.slock, irqs);
                 endp->queue_size = 1;
                 endp->queue_last = 0;
                 endp->queue_next = 0;
@@ -2133,7 +2161,7 @@ static int create_endpoint_and_queue_control(struct u132 *u132,
 }
 
 static int queue_control_on_old_endpoint(struct u132 *u132,
-        struct usb_host_endpoint *hep, struct urb *urb,
+       struct urb *urb,
         struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
         u8 usb_endp)
 {
@@ -2233,8 +2261,8 @@ static int queue_control_on_old_endpoint(struct u132 *u132,
         }
 }
 
-static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
-        struct urb *urb, gfp_t mem_flags)
+static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
+               gfp_t mem_flags)
 {
         struct u132 *u132 = hcd_to_u132(hcd);
         if (irqs_disabled()) {
@@ -2249,8 +2277,8 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
                         , u132->going);
                 return -ENODEV;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "device is being removed "
+                               "urb=%p\n", urb);
                 return -ESHUTDOWN;
         } else {
                 u8 usb_addr = usb_pipedevice(urb->pipe);
@@ -2259,16 +2287,24 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
                 if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
                         u8 address = u132->addr[usb_addr].address;
                         struct u132_udev *udev = &u132->udev[address];
-                        struct u132_endp *endp = hep->hcpriv;
+                        struct u132_endp *endp = urb->ep->hcpriv;
                         urb->actual_length = 0;
                         if (endp) {
                                 unsigned long irqs;
                                 int retval;
                                 spin_lock_irqsave(&endp->queue_lock.slock,
                                         irqs);
-                                retval = queue_int_on_old_endpoint(u132, udev,
-                                        hep, urb, usb_dev, endp, usb_addr,
-                                        usb_endp, address);
+                               retval = usb_hcd_link_urb_to_ep(hcd, urb);
+                               if (retval == 0) {
+                                       retval = queue_int_on_old_endpoint(
+                                                       u132, udev, urb,
+                                                       usb_dev, endp,
+                                                       usb_addr, usb_endp,
+                                                       address);
+                                       if (retval)
+                                               usb_hcd_unlink_urb_from_ep(
+                                                               hcd, urb);
+                               }
                                 spin_unlock_irqrestore(&endp->queue_lock.slock,
                                         irqs);
                                 if (retval) {
@@ -2283,8 +2319,8 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
                                 return -EINVAL;
                         } else {        /*(endp == NULL) */
                                 return create_endpoint_and_queue_int(u132, udev,
-                                         hep, urb, usb_dev, usb_addr, usb_endp,
-                                        address, mem_flags);
+                                               urb, usb_dev, usb_addr,
+                                               usb_endp, address, mem_flags);
                         }
                 } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
                         dev_err(&u132->platform_dev->dev, "the hardware does no"
@@ -2293,16 +2329,24 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
                 } else if (usb_pipetype(urb->pipe) == PIPE_BULK) {
                         u8 address = u132->addr[usb_addr].address;
                         struct u132_udev *udev = &u132->udev[address];
-                        struct u132_endp *endp = hep->hcpriv;
+                        struct u132_endp *endp = urb->ep->hcpriv;
                         urb->actual_length = 0;
                         if (endp) {
                                 unsigned long irqs;
                                 int retval;
                                 spin_lock_irqsave(&endp->queue_lock.slock,
                                         irqs);
-                                retval = queue_bulk_on_old_endpoint(u132, udev,
-                                        hep, urb, usb_dev, endp, usb_addr,
-                                        usb_endp, address);
+                               retval = usb_hcd_link_urb_to_ep(hcd, urb);
+                               if (retval == 0) {
+                                       retval = queue_bulk_on_old_endpoint(
+                                                       u132, udev, urb,
+                                                       usb_dev, endp,
+                                                       usb_addr, usb_endp,
+                                                       address);
+                                       if (retval)
+                                               usb_hcd_unlink_urb_from_ep(
+                                                               hcd, urb);
+                               }
                                 spin_unlock_irqrestore(&endp->queue_lock.slock,
                                         irqs);
                                 if (retval) {
@@ -2315,10 +2359,10 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
                                 return -EINVAL;
                         } else
                                 return create_endpoint_and_queue_bulk(u132,
-                                        udev, hep, urb, usb_dev, usb_addr,
+                                       udev, urb, usb_dev, usb_addr,
                                         usb_endp, address, mem_flags);
                 } else {
-                        struct u132_endp *endp = hep->hcpriv;
+                        struct u132_endp *endp = urb->ep->hcpriv;
                         u16 urb_size = 8;
                         u8 *b = urb->setup_packet;
                         int i = 0;
@@ -2341,9 +2385,16 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
                                 int retval;
                                 spin_lock_irqsave(&endp->queue_lock.slock,
                                         irqs);
-                                retval = queue_control_on_old_endpoint(u132,
-                                        hep, urb, usb_dev, endp, usb_addr,
-                                        usb_endp);
+                               retval = usb_hcd_link_urb_to_ep(hcd, urb);
+                               if (retval == 0) {
+                                       retval = queue_control_on_old_endpoint(
+                                                       u132, urb, usb_dev,
+                                                       endp, usb_addr,
+                                                       usb_endp);
+                                       if (retval)
+                                               usb_hcd_unlink_urb_from_ep(
+                                                               hcd, urb);
+                               }
                                 spin_unlock_irqrestore(&endp->queue_lock.slock,
                                         irqs);
                                 if (retval) {
@@ -2356,7 +2407,7 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
                                 return -EINVAL;
                         } else
                                 return create_endpoint_and_queue_control(u132,
-                                        hep, urb, usb_dev, usb_addr, usb_endp,
+                                       urb, usb_dev, usb_addr, usb_endp,
                                         mem_flags);
                 }
         }
@@ -2375,8 +2426,7 @@ static int dequeue_from_overflow_chain(struct u132 *u132,
                         list_del(scan);
                         endp->queue_size -= 1;
                         urb->error_count = 0;
-                        urb->hcpriv = NULL;
-                        usb_hcd_giveback_urb(hcd, urb);
+                       usb_hcd_giveback_urb(hcd, urb, 0);
                         return 0;
                 } else
                         continue;
@@ -2391,10 +2441,17 @@ static int dequeue_from_overflow_chain(struct u132 *u132,
 }
 
 static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
-        struct urb *urb)
+               struct urb *urb, int status)
 {
         unsigned long irqs;
+       int rc;
+
         spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+       rc = usb_hcd_check_unlink_urb(u132_to_hcd(u132), urb, status);
+       if (rc) {
+               spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+               return rc;
+       }
         if (endp->queue_size == 0) {
                 dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]"
                         "=%p ring[%d] %c%c usb_endp=%d usb_addr=%d\n", urb,
@@ -2410,11 +2467,10 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
                         endp->edset_flush = 1;
                         u132_endp_queue_work(u132, endp, 0);
                         spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
-                        urb->hcpriv = NULL;
                         return 0;
                 } else {
                         spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
-                        u132_hcd_abandon_urb(u132, endp, urb, urb->status);
+                       u132_hcd_abandon_urb(u132, endp, urb, status);
                         return 0;
                 }
         } else {
@@ -2439,6 +2495,8 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
                 }
                 if (urb_slot) {
                         struct usb_hcd *hcd = u132_to_hcd(u132);
+
+                       usb_hcd_unlink_urb_from_ep(hcd, urb);
                         endp->queue_size -= 1;
                         if (list_empty(&endp->urb_more)) {
                                 spin_unlock_irqrestore(&endp->queue_lock.slock,
@@ -2453,8 +2511,7 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
                                         irqs);
                                 kfree(urbq);
                         } urb->error_count = 0;
-                        urb->hcpriv = NULL;
-                        usb_hcd_giveback_urb(hcd, urb);
+                       usb_hcd_giveback_urb(hcd, urb, status);
                         return 0;
                 } else if (list_empty(&endp->urb_more)) {
                         dev_err(&u132->platform_dev->dev, "urb=%p not found in "
@@ -2468,7 +2525,10 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
                         spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
                         return -EINVAL;
                 } else {
-                        int retval = dequeue_from_overflow_chain(u132, endp,
+                       int retval;
+
+                       usb_hcd_unlink_urb_from_ep(u132_to_hcd(u132), urb);
+                       retval = dequeue_from_overflow_chain(u132, endp,
                                 urb);
                         spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
                         return retval;
@@ -2476,7 +2536,7 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
         }
 }
 
-static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
         struct u132 *u132 = hcd_to_u132(hcd);
         if (u132->going > 2) {
@@ -2491,11 +2551,11 @@ static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
                 if (usb_pipein(urb->pipe)) {
                         u8 endp_number = udev->endp_number_in[usb_endp];
                         struct u132_endp *endp = u132->endp[endp_number - 1];
-                        return u132_endp_urb_dequeue(u132, endp, urb);
+                        return u132_endp_urb_dequeue(u132, endp, urb, status);
                 } else {
                         u8 endp_number = udev->endp_number_out[usb_endp];
                         struct u132_endp *endp = u132->endp[endp_number - 1];
-                        return u132_endp_urb_dequeue(u132, endp, urb);
+                        return u132_endp_urb_dequeue(u132, endp, urb, status);
                 }
         }
 }
@@ -2805,7 +2865,7 @@ static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                 return -ESHUTDOWN;
         } else {
                 int retval = 0;
-                down(&u132->sw_lock);
+                mutex_lock(&u132->sw_lock);
                 switch (typeReq) {
                 case ClearHubFeature:
                         switch (wValue) {
@@ -2868,7 +2928,7 @@ static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                       stall:retval = -EPIPE;
                         break;
                 }
-                up(&u132->sw_lock);
+                mutex_unlock(&u132->sw_lock);
                 return retval;
         }
 }
@@ -3004,7 +3064,7 @@ static int __devexit u132_remove(struct platform_device *pdev)
                         dev_err(&u132->platform_dev->dev, "removing device u132"
                                ".%d\n", u132->sequence_num);
                         msleep(100);
-                        down(&u132->sw_lock);
+                        mutex_lock(&u132->sw_lock);
                         u132_monitor_cancel_work(u132);
                         while (rings-- > 0) {
                                 struct u132_ring *ring = &u132->ring[rings];
@@ -3017,7 +3077,7 @@ static int __devexit u132_remove(struct platform_device *pdev)
                         u132->going += 1;
                         printk(KERN_INFO "removing device u132.%d\n",
                                 u132->sequence_num);
-                        up(&u132->sw_lock);
+                        mutex_unlock(&u132->sw_lock);
                         usb_remove_hcd(hcd);
                         u132_u132_put_kref(u132);
                         return 0;
@@ -3037,7 +3097,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev)
         u132->platform_dev = pdev;
         u132->power = 0;
         u132->reset = 0;
-        init_MUTEX(&u132->sw_lock);
+        mutex_init(&u132->sw_lock);
         init_MUTEX(&u132->scheduler_lock);
         while (rings-- > 0) {
                 struct u132_ring *ring = &u132->ring[rings];
@@ -3047,7 +3107,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev)
                 ring->curr_endp = NULL;
                 INIT_DELAYED_WORK(&ring->scheduler,
                                  u132_hcd_ring_work_scheduler);
-        } down(&u132->sw_lock);
+        } mutex_lock(&u132->sw_lock);
         INIT_DELAYED_WORK(&u132->monitor, u132_hcd_monitor_work);
         while (ports-- > 0) {
                 struct u132_port *port = &u132->port[ports];
@@ -3077,7 +3137,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev)
         while (endps-- > 0) {
                 u132->endp[endps] = NULL;
         }
-        up(&u132->sw_lock);
+        mutex_unlock(&u132->sw_lock);
         return;
 }
 
index 1497371583b983a212ca15db917a628d9ca5d8e6..20cc58b9780713c573f874c85e01968e15a5f947 100644 (file)
@@ -120,8 +120,8 @@ static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space)
        out += sprintf(out, "%s%s", ptype, (urbp->fsbr ? " FSBR" : ""));
        out += sprintf(out, " Actlen=%d", urbp->urb->actual_length);
 
-       if (urbp->urb->status != -EINPROGRESS)
-               out += sprintf(out, " Status=%d", urbp->urb->status);
+       if (urbp->urb->unlinked)
+               out += sprintf(out, " Unlinked=%d", urbp->urb->unlinked);
        out += sprintf(out, "\n");
 
        i = nactive = ninactive = 0;
index 1b3d23406ac414005636d93212d2783968f8d17a..340d6ed3e6e92006c858e80ee8bdcd5f0ef0b179 100644 (file)
@@ -146,7 +146,6 @@ struct uhci_qh {
        short phase;                    /* Between 0 and period-1 */
        short load;                     /* Periodic time requirement, in us */
        unsigned int iso_frame;         /* Frame # for iso_packet_desc */
-       int iso_status;                 /* Status for Isochronous URBs */
 
        int state;                      /* QH_STATE_xxx; see above */
        int type;                       /* Queue type (control, bulk, etc) */
@@ -457,21 +456,6 @@ struct urb_priv {
 };
 
 
-/*
- * Locking in uhci.c
- *
- * Almost everything relating to the hardware schedule and processing
- * of URBs is protected by uhci->lock.  urb->status is protected by
- * urb->lock; that's the one exception.
- *
- * To prevent deadlocks, never lock uhci->lock while holding urb->lock.
- * The safe order of locking is:
- *
- * #1 uhci->lock
- * #2 urb->lock
- */
-
-
 /* Some special IDs */
 
 #define PCI_VENDOR_ID_GENESYS          0x17a0
index 3bb908ca38e9c91ffd59df6e148608d23ab2d8f9..e5d60d5b105a8975979c731a401eee26b0effd62 100644 (file)
@@ -757,7 +757,6 @@ static void uhci_free_urb_priv(struct uhci_hcd *uhci,
                uhci_free_td(uhci, td);
        }
 
-       urbp->urb->hcpriv = NULL;
        kmem_cache_free(uhci_up_cachep, urbp);
 }
 
@@ -1324,7 +1323,6 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
        if (list_empty(&qh->queue)) {
                qh->iso_packet_desc = &urb->iso_frame_desc[0];
                qh->iso_frame = urb->start_frame;
-               qh->iso_status = 0;
        }
 
        qh->skel = SKEL_ISO;
@@ -1361,22 +1359,18 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb)
                        qh->iso_packet_desc->actual_length = actlength;
                        qh->iso_packet_desc->status = status;
                }
-
-               if (status) {
+               if (status)
                        urb->error_count++;
-                       qh->iso_status = status;
-               }
 
                uhci_remove_td_from_urbp(td);
                uhci_free_td(uhci, td);
                qh->iso_frame += qh->period;
                ++qh->iso_packet_desc;
        }
-       return qh->iso_status;
+       return 0;
 }
 
 static int uhci_urb_enqueue(struct usb_hcd *hcd,
-               struct usb_host_endpoint *hep,
                struct urb *urb, gfp_t mem_flags)
 {
        int ret;
@@ -1387,19 +1381,19 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
 
        spin_lock_irqsave(&uhci->lock, flags);
 
-       ret = urb->status;
-       if (ret != -EINPROGRESS)                /* URB already unlinked! */
-               goto done;
+       ret = usb_hcd_link_urb_to_ep(hcd, urb);
+       if (ret)
+               goto done_not_linked;
 
        ret = -ENOMEM;
        urbp = uhci_alloc_urb_priv(uhci, urb);
        if (!urbp)
                goto done;
 
-       if (hep->hcpriv)
-               qh = (struct uhci_qh *) hep->hcpriv;
+       if (urb->ep->hcpriv)
+               qh = urb->ep->hcpriv;
        else {
-               qh = uhci_alloc_qh(uhci, urb->dev, hep);
+               qh = uhci_alloc_qh(uhci, urb->dev, urb->ep);
                if (!qh)
                        goto err_no_qh;
        }
@@ -1440,27 +1434,29 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
 err_submit_failed:
        if (qh->state == QH_STATE_IDLE)
                uhci_make_qh_idle(uhci, qh);    /* Reclaim unused QH */
-
 err_no_qh:
        uhci_free_urb_priv(uhci, urbp);
-
 done:
+       if (ret)
+               usb_hcd_unlink_urb_from_ep(hcd, urb);
+done_not_linked:
        spin_unlock_irqrestore(&uhci->lock, flags);
        return ret;
 }
 
-static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
        struct uhci_hcd *uhci = hcd_to_uhci(hcd);
        unsigned long flags;
-       struct urb_priv *urbp;
        struct uhci_qh *qh;
+       int rc;
 
        spin_lock_irqsave(&uhci->lock, flags);
-       urbp = urb->hcpriv;
-       if (!urbp)                      /* URB was never linked! */
+       rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+       if (rc)
                goto done;
-       qh = urbp->qh;
+
+       qh = ((struct urb_priv *) urb->hcpriv)->qh;
 
        /* Remove Isochronous TDs from the frame list ASAP */
        if (qh->type == USB_ENDPOINT_XFER_ISOC) {
@@ -1477,14 +1473,14 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
 
 done:
        spin_unlock_irqrestore(&uhci->lock, flags);
-       return 0;
+       return rc;
 }
 
 /*
  * Finish unlinking an URB and give it back
  */
 static void uhci_giveback_urb(struct uhci_hcd *uhci, struct uhci_qh *qh,
-               struct urb *urb)
+               struct urb *urb, int status)
 __releases(uhci->lock)
 __acquires(uhci->lock)
 {
@@ -1497,13 +1493,6 @@ __acquires(uhci->lock)
                 * unlinked first.  Regardless, don't confuse people with a
                 * negative length. */
                urb->actual_length = max(urb->actual_length, 0);
-
-               /* Report erroneous short transfers */
-               if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
-                               urb->actual_length <
-                                       urb->transfer_buffer_length &&
-                               urb->status == 0))
-                       urb->status = -EREMOTEIO;
        }
 
        /* When giving back the first URB in an Isochronous queue,
@@ -1516,7 +1505,6 @@ __acquires(uhci->lock)
 
                qh->iso_packet_desc = &nurb->iso_frame_desc[0];
                qh->iso_frame = nurb->start_frame;
-               qh->iso_status = 0;
        }
 
        /* Take the URB off the QH's queue.  If the queue is now empty,
@@ -1529,9 +1517,10 @@ __acquires(uhci->lock)
        }
 
        uhci_free_urb_priv(uhci, urbp);
+       usb_hcd_unlink_urb_from_ep(uhci_to_hcd(uhci), urb);
 
        spin_unlock(&uhci->lock);
-       usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb);
+       usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb, status);
        spin_lock(&uhci->lock);
 
        /* If the queue is now empty, we can unlink the QH and give up its
@@ -1567,24 +1556,17 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
                if (status == -EINPROGRESS)
                        break;
 
-               spin_lock(&urb->lock);
-               if (urb->status == -EINPROGRESS)        /* Not dequeued */
-                       urb->status = status;
-               else
-                       status = ECONNRESET;            /* Not -ECONNRESET */
-               spin_unlock(&urb->lock);
-
                /* Dequeued but completed URBs can't be given back unless
                 * the QH is stopped or has finished unlinking. */
-               if (status == ECONNRESET) {
+               if (urb->unlinked) {
                        if (QH_FINISHED_UNLINKING(qh))
                                qh->is_stopped = 1;
                        else if (!qh->is_stopped)
                                return;
                }
 
-               uhci_giveback_urb(uhci, qh, urb);
-               if (status < 0 && qh->type != USB_ENDPOINT_XFER_ISOC)
+               uhci_giveback_urb(uhci, qh, urb, status);
+               if (status < 0)
                        break;
        }
 
@@ -1599,7 +1581,7 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
 restart:
        list_for_each_entry(urbp, &qh->queue, node) {
                urb = urbp->urb;
-               if (urb->status != -EINPROGRESS) {
+               if (urb->unlinked) {
 
                        /* Fix up the TD links and save the toggles for
                         * non-Isochronous queues.  For Isochronous queues,
@@ -1608,7 +1590,7 @@ restart:
                                qh->is_stopped = 0;
                                return;
                        }
-                       uhci_giveback_urb(uhci, qh, urb);
+                       uhci_giveback_urb(uhci, qh, urb, 0);
                        goto restart;
                }
        }
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 e9fdbc8997b32c2be588a3b52030448c4a689307..5131cbfb2f5230cec9c0c3cd9d5c95d5f5731538 100644 (file)
@@ -188,7 +188,8 @@ static void adu_interrupt_in_callback(struct urb *urb)
        spin_lock(&dev->buflock);
 
        if (status != 0) {
-               if ((status != -ENOENT) && (status != -ECONNRESET)) {
+               if ((status != -ENOENT) && (status != -ECONNRESET) &&
+                       (status != -ESHUTDOWN)) {
                        dbg(1," %s : nonzero status received: %d",
                            __FUNCTION__, status);
                }
index 92c1d2768df9680afb7050d74b09b30c10db1d65..24e2dc3148a492d6b1adaf40a484b21717ae72bd 100644 (file)
@@ -71,7 +71,7 @@ static int magic_charge(struct usb_device *udev)
        if (retval != 2) {
                dev_err(&udev->dev, "First magic command failed: %d.\n",
                        retval);
-               return retval;
+               goto exit;
        }
 
        dbg(&udev->dev, "Sending second magic command\n");
@@ -80,7 +80,7 @@ static int magic_charge(struct usb_device *udev)
        if (retval != 0) {
                dev_err(&udev->dev, "Second magic command failed: %d.\n",
                        retval);
-               return retval;
+               goto exit;
        }
 
        dbg(&udev->dev, "Calling set_configuration\n");
@@ -88,6 +88,8 @@ static int magic_charge(struct usb_device *udev)
        if (retval)
                dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval);
 
+exit:
+       kfree(dummy_buffer);
        return retval;
 }
 
@@ -112,6 +114,7 @@ static int magic_dual_mode(struct usb_device *udev)
        if (retval)
                dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval);
 
+       kfree(dummy_buffer);
        return retval;
 }
 
index 538b535e955ba0be89303c18a54076bfdc0f2743..d3d8cd6ff103b5d399b992be5dee264a652ae40f 100644 (file)
@@ -2777,12 +2777,14 @@ static int ftdi_elan_probe(struct usb_interface *interface,
         size_t buffer_size;
         int i;
         int retval = -ENOMEM;
-        struct usb_ftdi *ftdi = kmalloc(sizeof(struct usb_ftdi), GFP_KERNEL);
-        if (ftdi == NULL) {
+        struct usb_ftdi *ftdi;
+
+       ftdi = kzalloc(sizeof(struct usb_ftdi), GFP_KERNEL);
+       if (!ftdi) {
                 printk(KERN_ERR "Out of memory\n");
                 return -ENOMEM;
         }
-        memset(ftdi, 0x00, sizeof(struct usb_ftdi));
+
         mutex_lock(&ftdi_module_lock);
         list_add_tail(&ftdi->ftdi_list, &ftdi_static_list);
         ftdi->sequence_num = ++ftdi_instances;
index b64ca91d9b02353cb43fe51655f2dc7d78f73a6c..9244d067cec1d9e3232d3379bae6cf46fa998925 100644 (file)
@@ -32,7 +32,7 @@
  * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * Author:     Thomas Winischhofer <thomas@winischhofer.net>
+ * Author:     Thomas Winischhofer <thomas@winischhofer.net>
  *
  */
 
@@ -962,12 +962,12 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
                           packet.address = 0x00000194;
                           packet.data    = addr;
                           ret = sisusb_send_bridge_packet(sisusb, 10,
-                                                               &packet, 0);
+                                                               &packet, 0);
                           packet.header  = 0x001f;
                           packet.address = 0x00000190;
                           packet.data    = (length & ~3);
                           ret |= sisusb_send_bridge_packet(sisusb, 10,
-                                                               &packet, 0);
+                                                               &packet, 0);
                           if (sisusb->flagb0 != 0x16) {
                                packet.header  = 0x001f;
                                packet.address = 0x00000180;
@@ -1003,23 +1003,17 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
                        if (ret) {
                                msgcount++;
                                if (msgcount < 500)
-                                       printk(KERN_ERR
-                                               "sisusbvga[%d]: Wrote %zd of "
-                                               "%d bytes, error %d\n",
-                                               sisusb->minor, *bytes_written,
-                                               length, ret);
+                                       dev_err(&sisusb->sisusb_dev->dev, "Wrote %zd of %d bytes, error %d\n",
+                                               *bytes_written, length, ret);
                                else if (msgcount == 500)
-                                       printk(KERN_ERR
-                                               "sisusbvga[%d]: Too many errors"
-                                               ", logging stopped\n",
-                                               sisusb->minor);
+                                       dev_err(&sisusb->sisusb_dev->dev, "Too many errors, logging stopped\n");
                        }
                        addr += (*bytes_written);
                        length -= (*bytes_written);
            }
 
            if (ret)
-               break;
+               break;
 
        }
 
@@ -1261,51 +1255,10 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
                                addr += 4;
                                length -= 4;
                        }
-#if 0          /* That does not work, as EP 2 is an OUT EP! */
-               default:
-                       CLEARPACKET(&packet);
-                       packet.header  = 0x001f;
-                       packet.address = 0x000001a0;
-                       packet.data    = 0x00000006;
-                       ret |= sisusb_send_bridge_packet(sisusb, 10,
-                                                               &packet, 0);
-                       packet.header  = 0x001f;
-                       packet.address = 0x000001b0;
-                       packet.data    = (length & ~3) | 0x40000000;
-                       ret |= sisusb_send_bridge_packet(sisusb, 10,
-                                                               &packet, 0);
-                       packet.header  = 0x001f;
-                       packet.address = 0x000001b4;
-                       packet.data    = addr;
-                       ret |= sisusb_send_bridge_packet(sisusb, 10,
-                                                               &packet, 0);
-                       packet.header  = 0x001f;
-                       packet.address = 0x000001a4;
-                       packet.data    = 0x00000001;
-                       ret |= sisusb_send_bridge_packet(sisusb, 10,
-                                                               &packet, 0);
-                       if (userbuffer) {
-                               ret |= sisusb_recv_bulk_msg(sisusb,
-                                                       SISUSB_EP_GFX_BULK_IN,
-                                                       (length & ~3),
-                                                       NULL, userbuffer,
-                                                       bytes_read, 0);
-                               if (!ret) userbuffer += (*bytes_read);
-                       } else {
-                               ret |= sisusb_recv_bulk_msg(sisusb,
-                                                       SISUSB_EP_GFX_BULK_IN,
-                                                       (length & ~3),
-                                                       kernbuffer, NULL,
-                                                       bytes_read, 0);
-                               if (!ret) kernbuffer += (*bytes_read);
-                       }
-                       addr += (*bytes_read);
-                       length -= (*bytes_read);
-#endif
            }
 
            if (ret)
-               break;
+               break;
        }
 
        return ret;
@@ -1401,22 +1354,6 @@ sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data)
        return(sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data));
 }
 
-#if 0
-
-int
-sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data)
-{
-       return(sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data));
-}
-
-int
-sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data)
-{
-       return(sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data));
-}
-
-#endif  /*  0  */
-
 int
 sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
                        u32 dest, int length, size_t *bytes_written)
@@ -1446,10 +1383,10 @@ sisusb_testreadwrite(struct sisusb_usb_data *sisusb)
     sisusb_copy_memory(sisusb, srcbuffer, sisusb->vrambase, 7, &dummy);
 
     for(i = 1; i <= 7; i++) {
-        printk(KERN_DEBUG "sisusb: rwtest %d bytes\n", i);
+        dev_dbg(&sisusb->sisusb_dev->dev, "sisusb: rwtest %d bytes\n", i);
        sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase, i, &dummy);
        for(j = 0; j < i; j++) {
-            printk(KERN_DEBUG "sisusb: rwtest read[%d] = %x\n", j, destbuffer[j]);
+            dev_dbg(&sisusb->sisusb_dev->dev, "rwtest read[%d] = %x\n", j, destbuffer[j]);
        }
     }
 }
@@ -1533,9 +1470,9 @@ sisusb_clear_vram(struct sisusb_usb_data *sisusb, u32 address, int length)
 #define SETIREGAND(r,i,a)      sisusb_setidxregand(sisusb, r, i, a)
 #define SETIREGANDOR(r,i,a,o)  sisusb_setidxregandor(sisusb, r, i, a, o)
 #define READL(a,d)     sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
-#define WRITEL(a,d)    sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
+#define WRITEL(a,d)    sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
 #define READB(a,d)     sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
-#define WRITEB(a,d)    sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
+#define WRITEB(a,d)    sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
 
 static int
 sisusb_triggersr16(struct sisusb_usb_data *sisusb, u8 ramtype)
@@ -2008,7 +1945,7 @@ sisusb_set_default_mode(struct sisusb_usb_data *sisusb, int touchengines)
                SETIREG(SISSR, 0x26, 0x00);
        }
 
-       SETIREG(SISCR, 0x34, 0x44);     /* we just set std mode #44 */
+       SETIREG(SISCR, 0x34, 0x44);     /* we just set std mode #44 */
 
        return ret;
 }
@@ -2168,17 +2105,12 @@ sisusb_init_gfxcore(struct sisusb_usb_data *sisusb)
                if (ramtype <= 1) {
                        ret |= sisusb_get_sdram_size(sisusb, &iret, bw, chab);
                        if (iret) {
-                               printk(KERN_ERR "sisusbvga[%d]: RAM size "
-                                       "detection failed, "
-                                       "assuming 8MB video RAM\n",
-                                       sisusb->minor);
+                               dev_err(&sisusb->sisusb_dev->dev,"RAM size detection failed, assuming 8MB video RAM\n");
                                ret |= SETIREG(SISSR,0x14,0x31);
                                /* TODO */
                        }
                } else {
-                       printk(KERN_ERR "sisusbvga[%d]: DDR RAM device found, "
-                                       "assuming 8MB video RAM\n",
-                                       sisusb->minor);
+                       dev_err(&sisusb->sisusb_dev->dev, "DDR RAM device found, assuming 8MB video RAM\n");
                        ret |= SETIREG(SISSR,0x14,0x31);
                        /* *** TODO *** */
                }
@@ -2249,8 +2181,7 @@ sisusb_get_ramconfig(struct sisusb_usb_data *sisusb)
                break;
        }
 
-       printk(KERN_INFO "sisusbvga[%d]: %dMB %s %s, bus width %d\n",
-                       sisusb->minor, (sisusb->vramsize >> 20), ramtypetext1,
+       dev_info(&sisusb->sisusb_dev->dev, "%dMB %s %s, bus width %d\n", (sisusb->vramsize >> 20), ramtypetext1,
                        ramtypetext2[ramtype], bw);
 }
 
@@ -2509,11 +2440,8 @@ sisusb_open(struct inode *inode, struct file *file)
        struct usb_interface *interface;
        int subminor = iminor(inode);
 
-       if (!(interface = usb_find_interface(&sisusb_driver, subminor))) {
-               printk(KERN_ERR "sisusb[%d]: Failed to find interface\n",
-                               subminor);
+       if (!(interface = usb_find_interface(&sisusb_driver, subminor)))
                return -ENODEV;
-       }
 
        if (!(sisusb = usb_get_intfdata(interface)))
                return -ENODEV;
@@ -2534,18 +2462,12 @@ sisusb_open(struct inode *inode, struct file *file)
                if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) {
                        if (sisusb_init_gfxdevice(sisusb, 0)) {
                                mutex_unlock(&sisusb->lock);
-                               printk(KERN_ERR
-                                       "sisusbvga[%d]: Failed to initialize "
-                                       "device\n",
-                                       sisusb->minor);
+                               dev_err(&sisusb->sisusb_dev->dev, "Failed to initialize device\n");
                                return -EIO;
                        }
                } else {
                        mutex_unlock(&sisusb->lock);
-                       printk(KERN_ERR
-                               "sisusbvga[%d]: Device not attached to "
-                               "USB 2.0 hub\n",
-                               sisusb->minor);
+                       dev_err(&sisusb->sisusb_dev->dev, "Device not attached to USB 2.0 hub\n");
                        return -EIO;
                }
        }
@@ -2586,7 +2508,6 @@ static int
 sisusb_release(struct inode *inode, struct file *file)
 {
        struct sisusb_usb_data *sisusb;
-       int myminor;
 
        if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
                return -ENODEV;
@@ -2599,8 +2520,6 @@ sisusb_release(struct inode *inode, struct file *file)
                        sisusb_kill_all_busy(sisusb);
        }
 
-       myminor = sisusb->minor;
-
        sisusb->isopen = 0;
        file->private_data = NULL;
 
@@ -2942,7 +2861,7 @@ static int
 sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
                                                        unsigned long arg)
 {
-       int     retval, port, length;
+       int     retval, port, length;
        u32     address;
 
        /* All our commands require the device
@@ -3065,12 +2984,12 @@ sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
 
 static int
 sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-                                                       unsigned long arg)
+                                                       unsigned long arg)
 {
        struct sisusb_usb_data *sisusb;
        struct sisusb_info x;
        struct sisusb_command y;
-       int     retval = 0;
+       int     retval = 0;
        u32 __user *argp = (u32 __user *)arg;
 
        if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
@@ -3095,7 +3014,7 @@ sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
 
                case SISUSB_GET_CONFIG:
 
-                       x.sisusb_id         = SISUSB_ID;
+                       x.sisusb_id         = SISUSB_ID;
                        x.sisusb_version    = SISUSB_VERSION;
                        x.sisusb_revision   = SISUSB_REVISION;
                        x.sisusb_patchlevel = SISUSB_PATCHLEVEL;
@@ -3164,7 +3083,7 @@ static const struct file_operations usb_sisusb_fops = {
        .release =      sisusb_release,
        .read =         sisusb_read,
        .write =        sisusb_write,
-       .llseek =       sisusb_lseek,
+       .llseek =       sisusb_lseek,
 #ifdef SISUSB_NEW_CONFIG_COMPAT
        .compat_ioctl = sisusb_compat_ioctl,
 #endif
@@ -3183,17 +3102,13 @@ static int sisusb_probe(struct usb_interface *intf,
        struct usb_device *dev = interface_to_usbdev(intf);
        struct sisusb_usb_data *sisusb;
        int retval = 0, i;
-       const char *memfail =
-               KERN_ERR
-               "sisusbvga[%d]: Failed to allocate memory for %s buffer\n";
 
-       printk(KERN_INFO "sisusb: USB2VGA dongle found at address %d\n",
+       dev_info(&dev->dev, "USB2VGA dongle found at address %d\n",
                dev->devnum);
 
        /* Allocate memory for our private */
        if (!(sisusb = kzalloc(sizeof(*sisusb), GFP_KERNEL))) {
-               printk(KERN_ERR
-                       "sisusb: Failed to allocate memory for private data\n");
+               dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for private data\n");
                return -ENOMEM;
        }
        kref_init(&sisusb->kref);
@@ -3202,8 +3117,7 @@ static int sisusb_probe(struct usb_interface *intf,
 
        /* Register device */
        if ((retval = usb_register_dev(intf, &usb_sisusb_class))) {
-               printk(KERN_ERR
-                       "sisusb: Failed to get a minor for device %d\n",
+               dev_err(&sisusb->sisusb_dev->dev, "Failed to get a minor for device %d\n",
                        dev->devnum);
                retval = -ENODEV;
                goto error_1;
@@ -3221,7 +3135,7 @@ static int sisusb_probe(struct usb_interface *intf,
        sisusb->ibufsize = SISUSB_IBUF_SIZE;
        if (!(sisusb->ibuf = usb_buffer_alloc(dev, SISUSB_IBUF_SIZE,
                                        GFP_KERNEL, &sisusb->transfer_dma_in))) {
-               printk(memfail, "input", sisusb->minor);
+               dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for input buffer");
                retval = -ENOMEM;
                goto error_2;
        }
@@ -3233,7 +3147,7 @@ static int sisusb_probe(struct usb_interface *intf,
                                        GFP_KERNEL,
                                        &sisusb->transfer_dma_out[i]))) {
                        if (i == 0) {
-                               printk(memfail, "output", sisusb->minor);
+                               dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for output buffer\n");
                                retval = -ENOMEM;
                                goto error_3;
                        }
@@ -3245,9 +3159,7 @@ static int sisusb_probe(struct usb_interface *intf,
 
        /* Allocate URBs */
        if (!(sisusb->sisurbin = usb_alloc_urb(0, GFP_KERNEL))) {
-               printk(KERN_ERR
-                       "sisusbvga[%d]: Failed to allocate URBs\n",
-                       sisusb->minor);
+               dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate URBs\n");
                retval = -ENOMEM;
                goto error_3;
        }
@@ -3255,9 +3167,7 @@ static int sisusb_probe(struct usb_interface *intf,
 
        for (i = 0; i < sisusb->numobufs; i++) {
                if (!(sisusb->sisurbout[i] = usb_alloc_urb(0, GFP_KERNEL))) {
-                       printk(KERN_ERR
-                               "sisusbvga[%d]: Failed to allocate URBs\n",
-                               sisusb->minor);
+                       dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate URBs\n");
                        retval = -ENOMEM;
                        goto error_4;
                }
@@ -3266,15 +3176,12 @@ static int sisusb_probe(struct usb_interface *intf,
                sisusb->urbstatus[i] = 0;
        }
 
-       printk(KERN_INFO "sisusbvga[%d]: Allocated %d output buffers\n",
-                                       sisusb->minor, sisusb->numobufs);
+       dev_info(&sisusb->sisusb_dev->dev, "Allocated %d output buffers\n", sisusb->numobufs);
 
 #ifdef INCL_SISUSB_CON
        /* Allocate our SiS_Pr */
        if (!(sisusb->SiS_Pr = kmalloc(sizeof(struct SiS_Private), GFP_KERNEL))) {
-               printk(KERN_ERR
-                       "sisusbvga[%d]: Failed to allocate SiS_Pr\n",
-                       sisusb->minor);
+               dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate SiS_Pr\n");
        }
 #endif
 
@@ -3296,10 +3203,7 @@ static int sisusb_probe(struct usb_interface *intf,
        ret |= register_ioctl32_conversion(SISUSB_GET_CONFIG,      NULL);
        ret |= register_ioctl32_conversion(SISUSB_COMMAND,         NULL);
        if (ret)
-               printk(KERN_ERR
-                       "sisusbvga[%d]: Error registering ioctl32 "
-                       "translations\n",
-                       sisusb->minor);
+               dev_err(&sisusb->sisusb_dev->dev, "Error registering ioctl32 translations\n");
        else
                sisusb->ioctl32registered = 1;
        }
@@ -3315,23 +3219,17 @@ static int sisusb_probe(struct usb_interface *intf,
                        initscreen = 0;
 #endif
                if (sisusb_init_gfxdevice(sisusb, initscreen))
-                       printk(KERN_ERR
-                               "sisusbvga[%d]: Failed to early "
-                               "initialize device\n",
-                               sisusb->minor);
+                       dev_err(&sisusb->sisusb_dev->dev, "Failed to early initialize device\n");
 
        } else
-               printk(KERN_INFO
-                       "sisusbvga[%d]: Not attached to USB 2.0 hub, "
-                       "deferring init\n",
-                       sisusb->minor);
+               dev_info(&sisusb->sisusb_dev->dev, "Not attached to USB 2.0 hub, deferring init\n");
 
        sisusb->ready = 1;
 
 #ifdef SISUSBENDIANTEST
-       printk(KERN_DEBUG "sisusb: *** RWTEST ***\n");
+       dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST ***\n");
        sisusb_testreadwrite(sisusb);
-       printk(KERN_DEBUG "sisusb: *** RWTEST END ***\n");
+       dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST END ***\n");
 #endif
 
 #ifdef INCL_SISUSB_CON
@@ -3354,7 +3252,6 @@ error_1:
 static void sisusb_disconnect(struct usb_interface *intf)
 {
        struct sisusb_usb_data *sisusb;
-       int minor;
 
        /* This should *not* happen */
        if (!(sisusb = usb_get_intfdata(intf)))
@@ -3364,8 +3261,6 @@ static void sisusb_disconnect(struct usb_interface *intf)
        sisusb_console_exit(sisusb);
 #endif
 
-       minor = sisusb->minor;
-
        usb_deregister_dev(intf, &usb_sisusb_class);
 
        mutex_lock(&sisusb->lock);
@@ -3384,10 +3279,7 @@ static void sisusb_disconnect(struct usb_interface *intf)
                ret |= unregister_ioctl32_conversion(SISUSB_GET_CONFIG);
                ret |= unregister_ioctl32_conversion(SISUSB_COMMAND);
                if (ret) {
-                       printk(KERN_ERR
-                               "sisusbvga[%d]: Error unregistering "
-                               "ioctl32 translations\n",
-                               minor);
+                       dev_err(&sisusb->sisusb_dev->dev, "Error unregistering ioctl32 translations\n");
                }
        }
 #endif
@@ -3400,7 +3292,7 @@ static void sisusb_disconnect(struct usb_interface *intf)
        /* decrement our usage count */
        kref_put(&sisusb->kref, sisusb_delete);
 
-       printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor);
+       dev_info(&sisusb->sisusb_dev->dev, "Disconnected\n");
 }
 
 static struct usb_device_id sisusb_table [] = {
@@ -3424,22 +3316,12 @@ static struct usb_driver sisusb_driver = {
 
 static int __init usb_sisusb_init(void)
 {
-       int retval;
 
 #ifdef INCL_SISUSB_CON
        sisusb_init_concode();
 #endif
 
-       if (!(retval = usb_register(&sisusb_driver))) {
-
-               printk(KERN_INFO "sisusb: Driver version %d.%d.%d\n",
-                       SISUSB_VERSION, SISUSB_REVISION, SISUSB_PATCHLEVEL);
-               printk(KERN_INFO
-                       "sisusb: Copyright (C) 2005 Thomas Winischhofer\n");
-
-       }
-
-       return retval;
+       return usb_register(&sisusb_driver);
 }
 
 static void __exit usb_sisusb_exit(void)
index 8e1120a6480647b4d8d97803205d3ca2016a88a9..d2d7872cd0229622ba546f3fc3111b20bccc471e 100644 (file)
@@ -8,29 +8,29 @@
  *
  * Otherwise, the following license terms apply:
  *
- * * Redistribution and use in source and binary forms, with or without
- * * modification, are permitted provided that the following conditions
- * * are met:
- * * 1) Redistributions of source code must retain the above copyright
- * *    notice, this list of conditions and the following disclaimer.
- * * 2) Redistributions in binary form must reproduce the above copyright
- * *    notice, this list of conditions and the following disclaimer in the
- * *    documentation and/or other materials provided with the distribution.
- * * 3) The name of the author may not be used to endorse or promote products
- * *    derived from this software without specific prior written permission.
- * *
- * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED 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 AUTHOR 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.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1) Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2) Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3) The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
  *
- * Author:     Thomas Winischhofer <thomas@winischhofer.net>
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED 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 AUTHOR 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.
+ *
+ * Author:     Thomas Winischhofer <thomas@winischhofer.net>
  *
  */
 
 #include <linux/mutex.h>
 
 /* For older kernels, support for text consoles is by default
- * off. To ensable text console support, change the following:
+ * off. To enable text console support, change the following:
  */
-#if 0
-#define CONFIG_USB_SISUSBVGA_CON
-#endif
+/* #define CONFIG_USB_SISUSBVGA_CON */
 
 /* Version Information */
 
 #define SISUSB_VERSION         0
-#define SISUSB_REVISION        0
+#define SISUSB_REVISION                0
 #define SISUSB_PATCHLEVEL      8
 
 /* Include console and mode switching code? */
@@ -74,7 +72,7 @@
 #define SISUSB_IBUF_SIZE  0x01000
 #define SISUSB_OBUF_SIZE  0x10000      /* fixed */
 
-#define NUMOBUFS 8                     /* max number of output buffers/output URBs */
+#define NUMOBUFS 8             /* max number of output buffers/output URBs */
 
 /* About endianness:
  *
@@ -93,7 +91,7 @@
  */
 
 #ifdef __BIG_ENDIAN
-#define SISUSB_CORRECT_ENDIANNESS_PACKET(p)            \
+#define SISUSB_CORRECT_ENDIANNESS_PACKET(p)            \
        do {                                            \
                p->header  = cpu_to_le16(p->header);    \
                p->address = cpu_to_le32(p->address);   \
 
 struct sisusb_usb_data;
 
-struct sisusb_urb_context {            /* urb->context for outbound bulk URBs */
+struct sisusb_urb_context {    /* urb->context for outbound bulk URBs */
        struct sisusb_usb_data *sisusb;
        int urbindex;
        int *actual_length;
@@ -116,16 +114,16 @@ struct sisusb_usb_data {
        struct usb_interface *interface;
        struct kref kref;
        wait_queue_head_t wait_q;       /* for syncind and timeouts */
-       struct mutex lock;              /* general race avoidance */
-       unsigned int ifnum;             /* interface number of the USB device */
-       int minor;                      /* minor (for logging clarity) */
-       int isopen;                     /* !=0 if open */
-       int present;                    /* !=0 if device is present on the bus */
-       int ready;                      /* !=0 if device is ready for userland */
+       struct mutex lock;      /* general race avoidance */
+       unsigned int ifnum;     /* interface number of the USB device */
+       int minor;              /* minor (for logging clarity) */
+       int isopen;             /* !=0 if open */
+       int present;            /* !=0 if device is present on the bus */
+       int ready;              /* !=0 if device is ready for userland */
 #ifdef SISUSB_OLD_CONFIG_COMPAT
        int ioctl32registered;
 #endif
-       int numobufs;                   /* number of obufs = number of out urbs */
+       int numobufs;           /* number of obufs = number of out urbs */
        char *obuf[NUMOBUFS], *ibuf;    /* transfer buffers */
        int obufsize, ibufsize;
        dma_addr_t transfer_dma_out[NUMOBUFS];
@@ -136,13 +134,13 @@ struct sisusb_usb_data {
        unsigned char completein;
        struct sisusb_urb_context urbout_context[NUMOBUFS];
        unsigned long flagb0;
-       unsigned long vrambase;         /* framebuffer base */
-       unsigned int vramsize;          /* framebuffer size (bytes) */
+       unsigned long vrambase; /* framebuffer base */
+       unsigned int vramsize;  /* framebuffer size (bytes) */
        unsigned long mmiobase;
        unsigned int mmiosize;
        unsigned long ioportbase;
-       unsigned char devinit;          /* device initialized? */
-       unsigned char gfxinit;          /* graphics core initialized? */
+       unsigned char devinit;  /* device initialized? */
+       unsigned char gfxinit;  /* graphics core initialized? */
        unsigned short chipid, chipvendor;
        unsigned short chiprevision;
 #ifdef INCL_SISUSB_CON
@@ -152,7 +150,7 @@ struct sisusb_usb_data {
        int haveconsole, con_first, con_last;
        int havethisconsole[MAX_NR_CONSOLES];
        int textmodedestroyed;
-       unsigned int sisusb_num_columns; /* real number, not vt's idea */
+       unsigned int sisusb_num_columns;        /* real number, not vt's idea */
        int cur_start_addr, con_rolled_over;
        int sisusb_cursor_loc, bad_cursor_pos;
        int sisusb_cursor_size_from;
@@ -197,7 +195,7 @@ struct sisusb_packet {
        unsigned short header;
        u32 address;
        u32 data;
-} __attribute__((__packed__));
+} __attribute__ ((__packed__));
 
 #define CLEARPACKET(packet) memset(packet, 0, 10)
 
@@ -265,36 +263,36 @@ struct sisusb_packet {
 
 /* Structure argument for SISUSB_GET_INFO ioctl  */
 struct sisusb_info {
-       __u32   sisusb_id;              /* for identifying sisusb */
-#define SISUSB_ID  0x53495355          /* Identify myself with 'SISU' */
-       __u8    sisusb_version;
-       __u8    sisusb_revision;
-       __u8    sisusb_patchlevel;
-       __u8    sisusb_gfxinit;         /* graphics core initialized? */
+       __u32 sisusb_id;        /* for identifying sisusb */
+#define SISUSB_ID  0x53495355  /* Identify myself with 'SISU' */
+       __u8 sisusb_version;
+       __u8 sisusb_revision;
+       __u8 sisusb_patchlevel;
+       __u8 sisusb_gfxinit;    /* graphics core initialized? */
 
-       __u32   sisusb_vrambase;
-       __u32   sisusb_mmiobase;
-       __u32   sisusb_iobase;
-       __u32   sisusb_pcibase;
+       __u32 sisusb_vrambase;
+       __u32 sisusb_mmiobase;
+       __u32 sisusb_iobase;
+       __u32 sisusb_pcibase;
 
-       __u32   sisusb_vramsize;        /* framebuffer size in bytes */
+       __u32 sisusb_vramsize;  /* framebuffer size in bytes */
 
-       __u32   sisusb_minor;
+       __u32 sisusb_minor;
 
-       __u32   sisusb_fbdevactive;     /* != 0 if framebuffer device active */
+       __u32 sisusb_fbdevactive;       /* != 0 if framebuffer device active */
 
-       __u32   sisusb_conactive;       /* != 0 if console driver active */
+       __u32 sisusb_conactive; /* != 0 if console driver active */
 
-       __u8    sisusb_reserved[28];    /* for future use */
+       __u8 sisusb_reserved[28];       /* for future use */
 };
 
 struct sisusb_command {
-       __u8   operation;       /* see below */
-       __u8   data0;           /* operation dependent */
-       __u8   data1;           /* operation dependent */
-       __u8   data2;           /* operation dependent */
-       __u32  data3;           /* operation dependent */
-       __u32  data4;           /* for future use */
+       __u8 operation;         /* see below */
+       __u8 data0;             /* operation dependent */
+       __u8 data1;             /* operation dependent */
+       __u8 data2;             /* operation dependent */
+       __u32 data3;            /* operation dependent */
+       __u32 data4;            /* for future use */
 };
 
 #define SUCMD_GET      0x01    /* for all: data0 = index, data3 = port */
@@ -306,7 +304,7 @@ struct sisusb_command {
 
 #define SUCMD_CLRSCR   0x07    /* data0:1:2 = length, data3 = address */
 
-#define SUCMD_HANDLETEXTMODE 0x08 /* Reset/destroy text mode */
+#define SUCMD_HANDLETEXTMODE 0x08      /* Reset/destroy text mode */
 
 #define SUCMD_SETMODE  0x09    /* Set a display mode (data3 = SiS mode) */
 #define SUCMD_SETVESAMODE 0x0a /* Set a display mode (data3 = VESA mode) */
@@ -315,6 +313,4 @@ struct sisusb_command {
 #define SISUSB_GET_CONFIG_SIZE _IOR(0xF3,0x3E,__u32)
 #define SISUSB_GET_CONFIG      _IOR(0xF3,0x3F,struct sisusb_info)
 
-
 #endif /* SISUSB_H */
-
index 8d0edc867f3316b969106dfb468d9f8bf249388b..43722e5a49d13e93bf4671af5daea1f02765f67e 100644 (file)
@@ -52,6 +52,7 @@
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/fs.h>
+#include <linux/usb.h>
 #include <linux/tty.h>
 #include <linux/console.h>
 #include <linux/string.h>
@@ -373,14 +374,6 @@ sisusbcon_putc(struct vc_data *c, int ch, int y, int x)
                return;
 
        /* sisusb->lock is down */
-
-       /* Don't need to put the character into buffer ourselves,
-        * because the vt does this BEFORE calling us.
-        */
-#if 0
-       sisusbcon_writew(ch, SISUSB_VADDR(x, y));
-#endif
-
        if (sisusb_is_inactive(c, sisusb)) {
                mutex_unlock(&sisusb->lock);
                return;
@@ -490,10 +483,6 @@ sisusbcon_bmove(struct vc_data *c, int sy, int sx,
        struct sisusb_usb_data *sisusb;
        ssize_t written;
        int cols, length;
-#if 0
-       u16 *src, *dest;
-       int i;
-#endif
 
        if (width <= 0 || height <= 0)
                return;
@@ -505,41 +494,6 @@ sisusbcon_bmove(struct vc_data *c, int sy, int sx,
 
        cols = sisusb->sisusb_num_columns;
 
-       /* Don't need to move data outselves, because
-        * vt does this BEFORE calling us.
-        * This is only used by vt's insert/deletechar.
-        */
-#if 0
-       if (sx == 0 && dx == 0 && width >= c->vc_cols && width <= cols) {
-
-               sisusbcon_memmovew(SISUSB_VADDR(0, dy), SISUSB_VADDR(0, sy),
-                                       height * width * 2);
-
-       } else if (dy < sy || (dy == sy && dx < sx)) {
-
-               src  = SISUSB_VADDR(sx, sy);
-               dest = SISUSB_VADDR(dx, dy);
-
-               for (i = height; i > 0; i--) {
-                       sisusbcon_memmovew(dest, src, width * 2);
-                       src  += cols;
-                       dest += cols;
-               }
-
-       } else {
-
-               src  = SISUSB_VADDR(sx, sy + height - 1);
-               dest = SISUSB_VADDR(dx, dy + height - 1);
-
-               for (i = height; i > 0; i--) {
-                       sisusbcon_memmovew(dest, src, width * 2);
-                       src  -= cols;
-                       dest -= cols;
-               }
-
-       }
-#endif
-
        if (sisusb_is_inactive(c, sisusb)) {
                mutex_unlock(&sisusb->lock);
                return;
@@ -584,7 +538,7 @@ sisusbcon_switch(struct vc_data *c)
         */
        if (c->vc_origin == (unsigned long)c->vc_screenbuf) {
                mutex_unlock(&sisusb->lock);
-               printk(KERN_DEBUG "sisusb: ASSERT ORIGIN != SCREENBUF!\n");
+               dev_dbg(&sisusb->sisusb_dev->dev, "ASSERT ORIGIN != SCREENBUF!\n");
                return 0;
        }
 
@@ -1475,7 +1429,7 @@ static const struct consw sisusb_dummy_con = {
 int
 sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
 {
-       int i, ret, minor = sisusb->minor;
+       int i, ret;
 
        mutex_lock(&sisusb->lock);
 
@@ -1508,9 +1462,7 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
        /* Set up text mode (and upload  default font) */
        if (sisusb_reset_text_mode(sisusb, 1)) {
                mutex_unlock(&sisusb->lock);
-               printk(KERN_ERR
-                       "sisusbvga[%d]: Failed to set up text mode\n",
-                       minor);
+               dev_err(&sisusb->sisusb_dev->dev, "Failed to set up text mode\n");
                return 1;
        }
 
@@ -1531,9 +1483,7 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
        /* Allocate screen buffer */
        if (!(sisusb->scrbuf = (unsigned long)vmalloc(sisusb->scrbuf_size))) {
                mutex_unlock(&sisusb->lock);
-               printk(KERN_ERR
-                       "sisusbvga[%d]: Failed to allocate screen buffer\n",
-                       minor);
+               dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate screen buffer\n");
                return 1;
        }
 
index 9b30f896281471ab05656fb0c07e33c4040ee40a..273de5d0934e6d969a56eeb4d9761e6b443a5dfc 100644 (file)
@@ -32,7 +32,7 @@
  * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * Author:     Thomas Winischhofer <thomas@winischhofer.net>
+ * Author:     Thomas Winischhofer <thomas@winischhofer.net>
  *
  */
 
 /*         POINTER INITIALIZATION            */
 /*********************************************/
 
-static void
-SiSUSB_InitPtr(struct SiS_Private *SiS_Pr)
+static void SiSUSB_InitPtr(struct SiS_Private *SiS_Pr)
 {
-       SiS_Pr->SiS_ModeResInfo   = SiSUSB_ModeResInfo;
-       SiS_Pr->SiS_StandTable    = SiSUSB_StandTable;
-
-       SiS_Pr->SiS_SModeIDTable  = SiSUSB_SModeIDTable;
-       SiS_Pr->SiS_EModeIDTable  = SiSUSB_EModeIDTable;
-       SiS_Pr->SiS_RefIndex      = SiSUSB_RefIndex;
-       SiS_Pr->SiS_CRT1Table     = SiSUSB_CRT1Table;
-
-       SiS_Pr->SiS_VCLKData      = SiSUSB_VCLKData;
-}
-
-/*********************************************/
-/*            HELPER: Get ModeID             */
-/*********************************************/
+       SiS_Pr->SiS_ModeResInfo = SiSUSB_ModeResInfo;
+       SiS_Pr->SiS_StandTable = SiSUSB_StandTable;
 
-#if 0
-unsigned short
-SiSUSB_GetModeID(int HDisplay, int VDisplay, int Depth)
-{
-       unsigned short ModeIndex = 0;
-
-       switch (HDisplay)
-       {
-               case 320:
-                       if (VDisplay == 200)
-                               ModeIndex = ModeIndex_320x200[Depth];
-                       else if (VDisplay == 240)
-                               ModeIndex = ModeIndex_320x240[Depth];
-                       break;
-               case 400:
-                       if (VDisplay == 300)
-                               ModeIndex = ModeIndex_400x300[Depth];
-                       break;
-               case 512:
-                       if (VDisplay == 384)
-                               ModeIndex = ModeIndex_512x384[Depth];
-                       break;
-               case 640:
-                       if (VDisplay == 480)
-                               ModeIndex = ModeIndex_640x480[Depth];
-                       else if (VDisplay == 400)
-                               ModeIndex = ModeIndex_640x400[Depth];
-                       break;
-               case 720:
-                       if (VDisplay == 480)
-                               ModeIndex = ModeIndex_720x480[Depth];
-                       else if (VDisplay == 576)
-                               ModeIndex = ModeIndex_720x576[Depth];
-                       break;
-               case 768:
-                       if (VDisplay == 576)
-                               ModeIndex = ModeIndex_768x576[Depth];
-                       break;
-               case 800:
-                       if (VDisplay == 600)
-                               ModeIndex = ModeIndex_800x600[Depth];
-                       else if (VDisplay == 480)
-                               ModeIndex = ModeIndex_800x480[Depth];
-                       break;
-               case 848:
-                       if (VDisplay == 480)
-                               ModeIndex = ModeIndex_848x480[Depth];
-                       break;
-               case 856:
-                       if (VDisplay == 480)
-                               ModeIndex = ModeIndex_856x480[Depth];
-                       break;
-               case 960:
-                       if (VDisplay == 540)
-                               ModeIndex = ModeIndex_960x540[Depth];
-                       else if (VDisplay == 600)
-                               ModeIndex = ModeIndex_960x600[Depth];
-                       break;
-               case 1024:
-                       if (VDisplay == 576)
-                               ModeIndex = ModeIndex_1024x576[Depth];
-                       else if (VDisplay == 768)
-                               ModeIndex = ModeIndex_1024x768[Depth];
-                       break;
-               case 1152:
-                       if (VDisplay == 864)
-                               ModeIndex = ModeIndex_1152x864[Depth];
-                       break;
-               case 1280:
-                       switch (VDisplay) {
-                               case 720:
-                                       ModeIndex = ModeIndex_1280x720[Depth];
-                                       break;
-                               case 768:
-                                       ModeIndex = ModeIndex_1280x768[Depth];
-                                       break;
-                               case 1024:
-                                       ModeIndex = ModeIndex_1280x1024[Depth];
-                                       break;
-                       }
-       }
+       SiS_Pr->SiS_SModeIDTable = SiSUSB_SModeIDTable;
+       SiS_Pr->SiS_EModeIDTable = SiSUSB_EModeIDTable;
+       SiS_Pr->SiS_RefIndex = SiSUSB_RefIndex;
+       SiS_Pr->SiS_CRT1Table = SiSUSB_CRT1Table;
 
-       return ModeIndex;
+       SiS_Pr->SiS_VCLKData = SiSUSB_VCLKData;
 }
-#endif  /*  0  */
 
 /*********************************************/
 /*          HELPER: SetReg, GetReg           */
@@ -165,21 +74,20 @@ SiSUSB_GetModeID(int HDisplay, int VDisplay, int Depth)
 
 static void
 SiS_SetReg(struct SiS_Private *SiS_Pr, unsigned long port,
-                       unsigned short index, unsigned short data)
+          unsigned short index, unsigned short data)
 {
        sisusb_setidxreg(SiS_Pr->sisusb, port, index, data);
 }
 
 static void
 SiS_SetRegByte(struct SiS_Private *SiS_Pr, unsigned long port,
-                                               unsigned short data)
+              unsigned short data)
 {
        sisusb_setreg(SiS_Pr->sisusb, port, data);
 }
 
 static unsigned char
-SiS_GetReg(struct SiS_Private *SiS_Pr, unsigned long port,
-                                               unsigned short index)
+SiS_GetReg(struct SiS_Private *SiS_Pr, unsigned long port, unsigned short index)
 {
        u8 data;
 
@@ -200,22 +108,22 @@ SiS_GetRegByte(struct SiS_Private *SiS_Pr, unsigned long port)
 
 static void
 SiS_SetRegANDOR(struct SiS_Private *SiS_Pr, unsigned long port,
-                       unsigned short index, unsigned short DataAND,
-                                               unsigned short DataOR)
+               unsigned short index, unsigned short DataAND,
+               unsigned short DataOR)
 {
        sisusb_setidxregandor(SiS_Pr->sisusb, port, index, DataAND, DataOR);
 }
 
 static void
 SiS_SetRegAND(struct SiS_Private *SiS_Pr, unsigned long port,
-                       unsigned short index, unsigned short DataAND)
+             unsigned short index, unsigned short DataAND)
 {
        sisusb_setidxregand(SiS_Pr->sisusb, port, index, DataAND);
 }
 
 static void
-SiS_SetRegOR(struct SiS_Private *SiS_Pr,unsigned long port,
-                       unsigned short index, unsigned short DataOR)
+SiS_SetRegOR(struct SiS_Private *SiS_Pr, unsigned long port,
+            unsigned short index, unsigned short DataOR)
 {
        sisusb_setidxregor(SiS_Pr->sisusb, port, index, DataOR);
 }
@@ -224,8 +132,7 @@ SiS_SetRegOR(struct SiS_Private *SiS_Pr,unsigned long port,
 /*      HELPER: DisplayOn, DisplayOff        */
 /*********************************************/
 
-static void
-SiS_DisplayOn(struct SiS_Private *SiS_Pr)
+static void SiS_DisplayOn(struct SiS_Private *SiS_Pr)
 {
        SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, 0xDF);
 }
@@ -234,8 +141,7 @@ SiS_DisplayOn(struct SiS_Private *SiS_Pr)
 /*        HELPER: Init Port Addresses        */
 /*********************************************/
 
-static void
-SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr)
+static void SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr)
 {
        SiS_Pr->SiS_P3c4 = BaseAddr + 0x14;
        SiS_Pr->SiS_P3d4 = BaseAddr + 0x24;
@@ -258,8 +164,7 @@ SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr)
 /*             HELPER: GetSysFlags           */
 /*********************************************/
 
-static void
-SiS_GetSysFlags(struct SiS_Private *SiS_Pr)
+static void SiS_GetSysFlags(struct SiS_Private *SiS_Pr)
 {
        SiS_Pr->SiS_MyCR63 = 0x63;
 }
@@ -268,8 +173,7 @@ SiS_GetSysFlags(struct SiS_Private *SiS_Pr)
 /*         HELPER: Init PCI & Engines        */
 /*********************************************/
 
-static void
-SiSInitPCIetc(struct SiS_Private *SiS_Pr)
+static void SiSInitPCIetc(struct SiS_Private *SiS_Pr)
 {
        SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x20, 0xa1);
        /*  - Enable 2D (0x40)
@@ -285,8 +189,7 @@ SiSInitPCIetc(struct SiS_Private *SiS_Pr)
 /*        HELPER: SET SEGMENT REGISTERS      */
 /*********************************************/
 
-static void
-SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value)
+static void SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value)
 {
        unsigned short temp;
 
@@ -299,8 +202,7 @@ SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value)
        SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp);
 }
 
-static void
-SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value)
+static void SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value)
 {
        unsigned short temp;
 
@@ -313,15 +215,13 @@ SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value)
        SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp);
 }
 
-static void
-SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value)
+static void SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value)
 {
        SiS_SetSegRegLower(SiS_Pr, value);
        SiS_SetSegRegUpper(SiS_Pr, value);
 }
 
-static void
-SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr)
+static void SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr)
 {
        SiS_SetSegmentReg(SiS_Pr, 0);
 }
@@ -337,14 +237,12 @@ SiS_SetSegmentRegOver(struct SiS_Private *SiS_Pr, unsigned short value)
        SiS_SetSegmentReg(SiS_Pr, value);
 }
 
-static void
-SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr)
+static void SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr)
 {
        SiS_SetSegmentRegOver(SiS_Pr, 0);
 }
 
-static void
-SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr)
+static void SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr)
 {
        SiS_ResetSegmentReg(SiS_Pr);
        SiS_ResetSegmentRegOver(SiS_Pr);
@@ -356,7 +254,7 @@ SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr)
 
 static int
 SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
-                                               unsigned short *ModeIdIndex)
+                unsigned short *ModeIdIndex)
 {
        if ((*ModeNo) <= 0x13) {
 
@@ -367,12 +265,14 @@ SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
 
        } else {
 
-               for(*ModeIdIndex = 0; ;(*ModeIdIndex)++) {
+               for (*ModeIdIndex = 0;; (*ModeIdIndex)++) {
 
-                       if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == (*ModeNo))
+                       if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID ==
+                           (*ModeNo))
                                break;
 
-                       if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == 0xFF)
+                       if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID ==
+                           0xFF)
                                return 0;
                }
 
@@ -385,8 +285,7 @@ SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
 /*            HELPER: ENABLE CRT1            */
 /*********************************************/
 
-static void
-SiS_HandleCRT1(struct SiS_Private *SiS_Pr)
+static void SiS_HandleCRT1(struct SiS_Private *SiS_Pr)
 {
        /* Enable CRT1 gating */
        SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, SiS_Pr->SiS_MyCR63, 0xbf);
@@ -398,9 +297,9 @@ SiS_HandleCRT1(struct SiS_Private *SiS_Pr)
 
 static unsigned short
 SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-               unsigned short ModeIdIndex)
+                 unsigned short ModeIdIndex)
 {
-       static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8};
+       static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8 };
        unsigned short modeflag;
        short index;
 
@@ -411,7 +310,8 @@ SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
        }
 
        index = (modeflag & ModeTypeMask) - ModeEGA;
-       if (index < 0) index = 0;
+       if (index < 0)
+               index = 0;
        return ColorDepth[index];
 }
 
@@ -421,7 +321,7 @@ SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 
 static unsigned short
 SiS_GetOffset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-               unsigned short ModeIdIndex, unsigned short rrti)
+             unsigned short ModeIdIndex, unsigned short rrti)
 {
        unsigned short xres, temp, colordepth, infoflag;
 
@@ -458,8 +358,8 @@ SiS_SetSeqRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
        SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[0] | 0x20;
        SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, SRdata);
 
-       for(i = 2; i <= 4; i++) {
-               SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i-1];
+       for (i = 2; i <= 4; i++) {
+               SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i - 1];
                SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, SRdata);
        }
 }
@@ -488,7 +388,7 @@ SiS_SetCRTCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
 
        SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f);
 
-       for(i = 0; i <= 0x18; i++) {
+       for (i = 0; i <= 0x18; i++) {
                CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i];
                SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, i, CRTCdata);
        }
@@ -504,7 +404,7 @@ SiS_SetATTRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
        unsigned char ARdata;
        unsigned short i;
 
-       for(i = 0; i <= 0x13; i++) {
+       for (i = 0; i <= 0x13; i++) {
                ARdata = SiS_Pr->SiS_StandTable[StandTableIndex].ATTR[i];
                SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da);
                SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, i);
@@ -529,7 +429,7 @@ SiS_SetGRCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
        unsigned char GRdata;
        unsigned short i;
 
-       for(i = 0; i <= 0x08; i++) {
+       for (i = 0; i <= 0x08; i++) {
                GRdata = SiS_Pr->SiS_StandTable[StandTableIndex].GRC[i];
                SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3ce, i, GRdata);
        }
@@ -544,12 +444,11 @@ SiS_SetGRCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
 /*          CLEAR EXTENDED REGISTERS         */
 /*********************************************/
 
-static void
-SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
+static void SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
 {
        int i;
 
-       for(i = 0x0A; i <= 0x0E; i++) {
+       for (i = 0x0A; i <= 0x0E; i++) {
                SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, 0x00);
        }
 
@@ -562,15 +461,16 @@ SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
 
 static unsigned short
 SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-                                       unsigned short ModeIdIndex)
+              unsigned short ModeIdIndex)
 {
        unsigned short rrti, i, index, temp;
 
        if (ModeNo <= 0x13)
                return 0xFFFF;
 
-       index = SiS_GetReg(SiS_Pr,SiS_Pr->SiS_P3d4, 0x33) & 0x0F;
-       if (index > 0) index--;
+       index = SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x33) & 0x0F;
+       if (index > 0)
+               index--;
 
        rrti = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex;
        ModeNo = SiS_Pr->SiS_RefIndex[rrti].ModeID;
@@ -580,13 +480,14 @@ SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
                if (SiS_Pr->SiS_RefIndex[rrti + i].ModeID != ModeNo)
                        break;
 
-               temp = SiS_Pr->SiS_RefIndex[rrti + i].Ext_InfoFlag & ModeTypeMask;
+               temp =
+                   SiS_Pr->SiS_RefIndex[rrti + i].Ext_InfoFlag & ModeTypeMask;
                if (temp < SiS_Pr->SiS_ModeType)
                        break;
 
                i++;
                index--;
-       } while(index != 0xFFFF);
+       } while (index != 0xFFFF);
 
        i--;
 
@@ -597,8 +498,7 @@ SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 /*                  SYNC                     */
 /*********************************************/
 
-static void
-SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti)
+static void SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti)
 {
        unsigned short sync = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag >> 8;
        sync &= 0xC0;
@@ -612,39 +512,40 @@ SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti)
 
 static void
 SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-                       unsigned short ModeIdIndex, unsigned short rrti)
+               unsigned short ModeIdIndex, unsigned short rrti)
 {
-       unsigned char  index;
+       unsigned char index;
        unsigned short temp, i, j, modeflag;
 
-       SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4,0x11,0x7f);
+       SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f);
 
        modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
 
        index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRT1CRTC;
 
-       for(i = 0,j = 0; i <= 7; i++, j++) {
+       for (i = 0, j = 0; i <= 7; i++, j++) {
                SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
-                               SiS_Pr->SiS_CRT1Table[index].CR[i]);
+                          SiS_Pr->SiS_CRT1Table[index].CR[i]);
        }
-       for(j = 0x10; i <= 10; i++, j++) {
+       for (j = 0x10; i <= 10; i++, j++) {
                SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
-                               SiS_Pr->SiS_CRT1Table[index].CR[i]);
+                          SiS_Pr->SiS_CRT1Table[index].CR[i]);
        }
-       for(j = 0x15; i <= 12; i++, j++) {
+       for (j = 0x15; i <= 12; i++, j++) {
                SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
-                               SiS_Pr->SiS_CRT1Table[index].CR[i]);
+                          SiS_Pr->SiS_CRT1Table[index].CR[i]);
        }
-       for(j = 0x0A; i <= 15; i++, j++) {
+       for (j = 0x0A; i <= 15; i++, j++) {
                SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, j,
-                               SiS_Pr->SiS_CRT1Table[index].CR[i]);
+                          SiS_Pr->SiS_CRT1Table[index].CR[i]);
        }
 
        temp = SiS_Pr->SiS_CRT1Table[index].CR[16] & 0xE0;
-       SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4, 0x0E, temp);
+       SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0E, temp);
 
        temp = ((SiS_Pr->SiS_CRT1Table[index].CR[16]) & 0x01) << 5;
-       if (modeflag & DoubleScanMode)  temp |= 0x80;
+       if (modeflag & DoubleScanMode)
+               temp |= 0x80;
        SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3d4, 0x09, 0x5F, temp);
 
        if (SiS_Pr->SiS_ModeType > ModeVGA)
@@ -659,10 +560,10 @@ SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 
 static void
 SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-                       unsigned short ModeIdIndex, unsigned short rrti)
+                 unsigned short ModeIdIndex, unsigned short rrti)
 {
        unsigned short du = SiS_GetOffset(SiS_Pr, ModeNo, ModeIdIndex, rrti);
-       unsigned short infoflag =  SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag;
+       unsigned short infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag;
        unsigned short temp;
 
        temp = (du >> 8) & 0x0f;
@@ -670,11 +571,13 @@ SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 
        SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x13, (du & 0xFF));
 
-       if (infoflag & InterlaceMode) du >>= 1;
+       if (infoflag & InterlaceMode)
+               du >>= 1;
 
        du <<= 5;
        temp = (du >> 8) & 0xff;
-       if (du & 0xff) temp++;
+       if (du & 0xff)
+               temp++;
        temp++;
        SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x10, temp);
 }
@@ -685,17 +588,17 @@ SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 
 static void
 SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-                                               unsigned short rrti)
+               unsigned short rrti)
 {
        unsigned short index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRTVCLK;
        unsigned short clka = SiS_Pr->SiS_VCLKData[index].SR2B;
        unsigned short clkb = SiS_Pr->SiS_VCLKData[index].SR2C;
 
-       SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4,0x31,0xCF);
+       SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x31, 0xCF);
 
-       SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2B,clka);
-       SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2C,clkb);
-       SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2D,0x01);
+       SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2B, clka);
+       SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2C, clkb);
+       SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2D, 0x01);
 }
 
 /*********************************************/
@@ -704,7 +607,7 @@ SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 
 static void
 SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-                                                       unsigned short mi)
+                   unsigned short mi)
 {
        unsigned short modeflag = SiS_Pr->SiS_EModeIDTable[mi].Ext_ModeFlag;
 
@@ -729,7 +632,7 @@ SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 
 static void
 SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-                                                       unsigned short rrti)
+                unsigned short rrti)
 {
        unsigned short data = 0, VCLK = 0, index = 0;
 
@@ -738,7 +641,8 @@ SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
                VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;
        }
 
-       if (VCLK >= 166) data |= 0x0c;
+       if (VCLK >= 166)
+               data |= 0x0c;
        SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x32, 0xf3, data);
 
        if (VCLK >= 166)
@@ -758,7 +662,7 @@ SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 
 static void
 SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-                       unsigned short ModeIdIndex, unsigned short rrti)
+                   unsigned short ModeIdIndex, unsigned short rrti)
 {
        unsigned short data, infoflag = 0, modeflag;
 
@@ -778,17 +682,22 @@ SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
                        data |= 0x02;
                        data |= ((SiS_Pr->SiS_ModeType - ModeVGA) << 2);
                }
-               if (infoflag & InterlaceMode) data |= 0x20;
+               if (infoflag & InterlaceMode)
+                       data |= 0x20;
        }
        SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x06, 0xC0, data);
 
        data = 0;
        if (infoflag & InterlaceMode) {
                /* data = (Hsync / 8) - ((Htotal / 8) / 2) + 3 */
-               unsigned short hrs = (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x04) |
-                       ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0xc0) << 2)) - 3;
-               unsigned short hto = (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x00) |
-                       ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0x03) << 8)) + 5;
+               unsigned short hrs =
+                   (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x04) |
+                    ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0xc0) << 2))
+                   - 3;
+               unsigned short hto =
+                   (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x00) |
+                    ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0x03) << 8))
+                   + 5;
                data = hrs - (hto >> 1) + 3;
        }
        SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x19, (data & 0xFF));
@@ -829,20 +738,26 @@ SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 
 static void
 SiS_WriteDAC(struct SiS_Private *SiS_Pr, unsigned long DACData,
-               unsigned short shiftflag, unsigned short dl, unsigned short ah,
-               unsigned short al, unsigned short dh)
+            unsigned short shiftflag, unsigned short dl, unsigned short ah,
+            unsigned short al, unsigned short dh)
 {
        unsigned short d1, d2, d3;
 
        switch (dl) {
-               case  0:
-                       d1 = dh; d2 = ah; d3 = al;
-                       break;
-               case  1:
-                       d1 = ah; d2 = al; d3 = dh;
-                       break;
-               default:
-                       d1 = al; d2 = dh; d3 = ah;
+       case 0:
+               d1 = dh;
+               d2 = ah;
+               d3 = al;
+               break;
+       case 1:
+               d1 = ah;
+               d2 = al;
+               d3 = dh;
+               break;
+       default:
+               d1 = al;
+               d2 = dh;
+               d3 = ah;
        }
        SiS_SetRegByte(SiS_Pr, DACData, (d1 << shiftflag));
        SiS_SetRegByte(SiS_Pr, DACData, (d2 << shiftflag));
@@ -850,7 +765,8 @@ SiS_WriteDAC(struct SiS_Private *SiS_Pr, unsigned long DACData,
 }
 
 static void
-SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi)
+SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
+           unsigned short mi)
 {
        unsigned short data, data2, time, i, j, k, m, n, o;
        unsigned short si, di, bx, sf;
@@ -884,41 +800,45 @@ SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi
 
        SiS_SetRegByte(SiS_Pr, DACAddr, 0x00);
 
-       for(i = 0; i < j; i++) {
+       for (i = 0; i < j; i++) {
                data = table[i];
-               for(k = 0; k < 3; k++) {
+               for (k = 0; k < 3; k++) {
                        data2 = 0;
-                       if (data & 0x01) data2 += 0x2A;
-                       if (data & 0x02) data2 += 0x15;
+                       if (data & 0x01)
+                               data2 += 0x2A;
+                       if (data & 0x02)
+                               data2 += 0x15;
                        SiS_SetRegByte(SiS_Pr, DACData, (data2 << sf));
                        data >>= 2;
                }
        }
 
        if (time == 256) {
-               for(i = 16; i < 32; i++) {
+               for (i = 16; i < 32; i++) {
                        data = table[i] << sf;
-                       for(k = 0; k < 3; k++)
+                       for (k = 0; k < 3; k++)
                                SiS_SetRegByte(SiS_Pr, DACData, data);
                }
                si = 32;
-               for(m = 0; m < 9; m++) {
+               for (m = 0; m < 9; m++) {
                        di = si;
                        bx = si + 4;
-                       for(n = 0; n < 3; n++) {
-                               for(o = 0; o < 5; o++) {
+                       for (n = 0; n < 3; n++) {
+                               for (o = 0; o < 5; o++) {
                                        SiS_WriteDAC(SiS_Pr, DACData, sf, n,
-                                               table[di], table[bx], table[si]);
+                                                    table[di], table[bx],
+                                                    table[si]);
                                        si++;
                                }
                                si -= 2;
-                               for(o = 0; o < 3; o++) {
+                               for (o = 0; o < 3; o++) {
                                        SiS_WriteDAC(SiS_Pr, DACData, sf, n,
-                                               table[di], table[si], table[bx]);
+                                                    table[di], table[si],
+                                                    table[bx]);
                                        si--;
                                }
                        }
-               si += 5;
+                       si += 5;
                }
        }
 }
@@ -929,7 +849,7 @@ SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi
 
 static void
 SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-                                       unsigned short ModeIdIndex)
+                unsigned short ModeIdIndex)
 {
        unsigned short StandTableIndex, rrti;
 
@@ -970,11 +890,10 @@ SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 /*                 SiSSetMode()              */
 /*********************************************/
 
-int
-SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
+int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
 {
        unsigned short ModeIdIndex;
-       unsigned long  BaseAddr = SiS_Pr->IOAddress;
+       unsigned long BaseAddr = SiS_Pr->IOAddress;
 
        SiSUSB_InitPtr(SiS_Pr);
        SiSUSBRegInit(SiS_Pr, BaseAddr);
@@ -990,7 +909,7 @@ SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
        ModeNo &= 0x7f;
 
        SiS_Pr->SiS_ModeType =
-               SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag & ModeTypeMask;
+           SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag & ModeTypeMask;
 
        SiS_Pr->SiS_SetFlag = LowModeTests;
 
@@ -1008,8 +927,7 @@ SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
        return 1;
 }
 
-int
-SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo)
+int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo)
 {
        unsigned short ModeNo = 0;
        int i;
@@ -1041,7 +959,3 @@ SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo)
 }
 
 #endif /* INCL_SISUSB_CON */
-
-
-
-
index 864bc0e96591afcedfe351342964041c6fee833d..c46ce42d44892cb895f5d7f3a8d49a6083aa58f2 100644 (file)
@@ -46,7 +46,7 @@
  * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * Author:     Thomas Winischhofer <thomas@winischhofer.net>
+ * Author:     Thomas Winischhofer <thomas@winischhofer.net>
  *
  */
 
 #define CRT2Mode               0x0800
 #define HalfDCLK               0x1000
 #define NoSupportSimuTV                0x2000
-#define NoSupportLCDScale      0x4000 /* SiS bridge: No scaling possible (no matter what panel) */
+#define NoSupportLCDScale      0x4000  /* SiS bridge: No scaling possible (no matter what panel) */
 #define DoubleScanMode         0x8000
 
 /* Infoflag */
 #define SupportTV              0x0008
 #define SupportTV1024          0x0800
-#define SupportCHTV            0x0800
-#define Support64048060Hz      0x0800  /* Special for 640x480 LCD */
+#define SupportCHTV            0x0800
+#define Support64048060Hz      0x0800  /* Special for 640x480 LCD */
 #define SupportHiVision                0x0010
 #define SupportYPbPr750p       0x1000
 #define SupportLCD             0x0020
 #define SupportRAMDAC2         0x0040  /* All           (<= 100Mhz) */
-#define SupportRAMDAC2_135     0x0100  /* All except DH (<= 135Mhz) */
-#define SupportRAMDAC2_162     0x0200  /* B, C          (<= 162Mhz) */
-#define SupportRAMDAC2_202     0x0400  /* C             (<= 202Mhz) */
+#define SupportRAMDAC2_135     0x0100  /* All except DH (<= 135Mhz) */
+#define SupportRAMDAC2_162     0x0200  /* B, C          (<= 162Mhz) */
+#define SupportRAMDAC2_202     0x0400  /* C             (<= 202Mhz) */
 #define InterlaceMode          0x0080
 #define SyncPP                 0x0000
 #define SyncPN                 0x4000
 #define SIS_RI_856x480         19
 #define SIS_RI_1280x768                20
 #define SIS_RI_1400x1050       21
-#define SIS_RI_1152x864                22  /* Up to here SiS conforming */
+#define SIS_RI_1152x864                22      /* Up to here SiS conforming */
 #define SIS_RI_848x480         23
 #define SIS_RI_1360x768                24
 #define SIS_RI_1024x600                25
 #define SIS_CRT2_PORT_04       0x04 - 0x30
 
 /* Mode numbers */
-static const unsigned short ModeIndex_320x200[]   = {0x59, 0x41, 0x00, 0x4f};
-static const unsigned short ModeIndex_320x240[]   = {0x50, 0x56, 0x00, 0x53};
-static const unsigned short ModeIndex_400x300[]   = {0x51, 0x57, 0x00, 0x54};
-static const unsigned short ModeIndex_512x384[]   = {0x52, 0x58, 0x00, 0x5c};
-static const unsigned short ModeIndex_640x400[]   = {0x2f, 0x5d, 0x00, 0x5e};
-static const unsigned short ModeIndex_640x480[]   = {0x2e, 0x44, 0x00, 0x62};
-static const unsigned short ModeIndex_720x480[]   = {0x31, 0x33, 0x00, 0x35};
-static const unsigned short ModeIndex_720x576[]   = {0x32, 0x34, 0x00, 0x36};
-static const unsigned short ModeIndex_768x576[]   = {0x5f, 0x60, 0x00, 0x61};
-static const unsigned short ModeIndex_800x480[]   = {0x70, 0x7a, 0x00, 0x76};
-static const unsigned short ModeIndex_800x600[]   = {0x30, 0x47, 0x00, 0x63};
-static const unsigned short ModeIndex_848x480[]   = {0x39, 0x3b, 0x00, 0x3e};
-static const unsigned short ModeIndex_856x480[]   = {0x3f, 0x42, 0x00, 0x45};
-static const unsigned short ModeIndex_960x540[]   = {0x1d, 0x1e, 0x00, 0x1f};
-static const unsigned short ModeIndex_960x600[]   = {0x20, 0x21, 0x00, 0x22};
-static const unsigned short ModeIndex_1024x768[]  = {0x38, 0x4a, 0x00, 0x64};
-static const unsigned short ModeIndex_1024x576[]  = {0x71, 0x74, 0x00, 0x77};
-static const unsigned short ModeIndex_1152x864[]  = {0x29, 0x2a, 0x00, 0x2b};
-static const unsigned short ModeIndex_1280x720[]  = {0x79, 0x75, 0x00, 0x78};
-static const unsigned short ModeIndex_1280x768[]  = {0x23, 0x24, 0x00, 0x25};
-static const unsigned short ModeIndex_1280x1024[] = {0x3a, 0x4d, 0x00, 0x65};
+static const unsigned short ModeIndex_320x200[] = { 0x59, 0x41, 0x00, 0x4f };
+static const unsigned short ModeIndex_320x240[] = { 0x50, 0x56, 0x00, 0x53 };
+static const unsigned short ModeIndex_400x300[] = { 0x51, 0x57, 0x00, 0x54 };
+static const unsigned short ModeIndex_512x384[] = { 0x52, 0x58, 0x00, 0x5c };
+static const unsigned short ModeIndex_640x400[] = { 0x2f, 0x5d, 0x00, 0x5e };
+static const unsigned short ModeIndex_640x480[] = { 0x2e, 0x44, 0x00, 0x62 };
+static const unsigned short ModeIndex_720x480[] = { 0x31, 0x33, 0x00, 0x35 };
+static const unsigned short ModeIndex_720x576[] = { 0x32, 0x34, 0x00, 0x36 };
+static const unsigned short ModeIndex_768x576[] = { 0x5f, 0x60, 0x00, 0x61 };
+static const unsigned short ModeIndex_800x480[] = { 0x70, 0x7a, 0x00, 0x76 };
+static const unsigned short ModeIndex_800x600[] = { 0x30, 0x47, 0x00, 0x63 };
+static const unsigned short ModeIndex_848x480[] = { 0x39, 0x3b, 0x00, 0x3e };
+static const unsigned short ModeIndex_856x480[] = { 0x3f, 0x42, 0x00, 0x45 };
+static const unsigned short ModeIndex_960x540[] = { 0x1d, 0x1e, 0x00, 0x1f };
+static const unsigned short ModeIndex_960x600[] = { 0x20, 0x21, 0x00, 0x22 };
+static const unsigned short ModeIndex_1024x768[] = { 0x38, 0x4a, 0x00, 0x64 };
+static const unsigned short ModeIndex_1024x576[] = { 0x71, 0x74, 0x00, 0x77 };
+static const unsigned short ModeIndex_1152x864[] = { 0x29, 0x2a, 0x00, 0x2b };
+static const unsigned short ModeIndex_1280x720[] = { 0x79, 0x75, 0x00, 0x78 };
+static const unsigned short ModeIndex_1280x768[] = { 0x23, 0x24, 0x00, 0x25 };
+static const unsigned short ModeIndex_1280x1024[] = { 0x3a, 0x4d, 0x00, 0x65 };
 
-static const unsigned char SiS_MDA_DAC[] =
-{
-       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-        0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
-        0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
-        0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
-        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-        0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
-        0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
-        0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F
+static const unsigned char SiS_MDA_DAC[] = {
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+       0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+       0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+       0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+       0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F
 };
 
-static const unsigned char SiS_CGA_DAC[] =
-{
-        0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
-        0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
-        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
-        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
-        0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
-        0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
-        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
-        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F
+static const unsigned char SiS_CGA_DAC[] = {
+       0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+       0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+       0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
+       0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
+       0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+       0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+       0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
+       0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F
 };
 
-static const unsigned char SiS_EGA_DAC[] =
-{
-        0x00,0x10,0x04,0x14,0x01,0x11,0x05,0x15,
-        0x20,0x30,0x24,0x34,0x21,0x31,0x25,0x35,
-        0x08,0x18,0x0C,0x1C,0x09,0x19,0x0D,0x1D,
-        0x28,0x38,0x2C,0x3C,0x29,0x39,0x2D,0x3D,
-        0x02,0x12,0x06,0x16,0x03,0x13,0x07,0x17,
-        0x22,0x32,0x26,0x36,0x23,0x33,0x27,0x37,
-        0x0A,0x1A,0x0E,0x1E,0x0B,0x1B,0x0F,0x1F,
-        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F
+static const unsigned char SiS_EGA_DAC[] = {
+       0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x05, 0x15,
+       0x20, 0x30, 0x24, 0x34, 0x21, 0x31, 0x25, 0x35,
+       0x08, 0x18, 0x0C, 0x1C, 0x09, 0x19, 0x0D, 0x1D,
+       0x28, 0x38, 0x2C, 0x3C, 0x29, 0x39, 0x2D, 0x3D,
+       0x02, 0x12, 0x06, 0x16, 0x03, 0x13, 0x07, 0x17,
+       0x22, 0x32, 0x26, 0x36, 0x23, 0x33, 0x27, 0x37,
+       0x0A, 0x1A, 0x0E, 0x1E, 0x0B, 0x1B, 0x0F, 0x1F,
+       0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F
 };
 
-static const unsigned char SiS_VGA_DAC[] =
-{
-       0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
-       0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
-       0x00,0x05,0x08,0x0B,0x0E,0x11,0x14,0x18,
-       0x1C,0x20,0x24,0x28,0x2D,0x32,0x38,0x3F,
-       0x00,0x10,0x1F,0x2F,0x3F,0x1F,0x27,0x2F,
-       0x37,0x3F,0x2D,0x31,0x36,0x3A,0x3F,0x00,
-       0x07,0x0E,0x15,0x1C,0x0E,0x11,0x15,0x18,
-       0x1C,0x14,0x16,0x18,0x1A,0x1C,0x00,0x04,
-       0x08,0x0C,0x10,0x08,0x0A,0x0C,0x0E,0x10,
-       0x0B,0x0C,0x0D,0x0F,0x10
+static const unsigned char SiS_VGA_DAC[] = {
+       0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+       0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
+       0x00, 0x05, 0x08, 0x0B, 0x0E, 0x11, 0x14, 0x18,
+       0x1C, 0x20, 0x24, 0x28, 0x2D, 0x32, 0x38, 0x3F,
+       0x00, 0x10, 0x1F, 0x2F, 0x3F, 0x1F, 0x27, 0x2F,
+       0x37, 0x3F, 0x2D, 0x31, 0x36, 0x3A, 0x3F, 0x00,
+       0x07, 0x0E, 0x15, 0x1C, 0x0E, 0x11, 0x15, 0x18,
+       0x1C, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x00, 0x04,
+       0x08, 0x0C, 0x10, 0x08, 0x0A, 0x0C, 0x0E, 0x10,
+       0x0B, 0x0C, 0x0D, 0x0F, 0x10
 };
 
-static const struct SiS_St SiSUSB_SModeIDTable[] =
-{
-       {0x03,0x0010,0x18,0x02,0x02,0x00,0x01,0x03,0x40},
-       {0xff,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
+static const struct SiS_St SiSUSB_SModeIDTable[] = {
+       {0x03, 0x0010, 0x18, 0x02, 0x02, 0x00, 0x01, 0x03, 0x40},
+       {0xff, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
 };
 
-static const struct SiS_StResInfo_S SiSUSB_StResInfo[] =
-{
-       { 640,400},
-       { 640,350},
-       { 720,400},
-       { 720,350},
-       { 640,480}
+static const struct SiS_StResInfo_S SiSUSB_StResInfo[] = {
+       {640, 400},
+       {640, 350},
+       {720, 400},
+       {720, 350},
+       {640, 480}
 };
 
-static const struct SiS_ModeResInfo SiSUSB_ModeResInfo[] =
-{
-       {  320, 200, 8, 8},   /* 0x00 */
-       {  320, 240, 8, 8},   /* 0x01 */
-       {  320, 400, 8, 8},   /* 0x02 */
-       {  400, 300, 8, 8},   /* 0x03 */
-       {  512, 384, 8, 8},   /* 0x04 */
-       {  640, 400, 8,16},   /* 0x05 */
-       {  640, 480, 8,16},   /* 0x06 */
-       {  800, 600, 8,16},   /* 0x07 */
-       { 1024, 768, 8,16},   /* 0x08 */
-       { 1280,1024, 8,16},   /* 0x09 */
-       { 1600,1200, 8,16},   /* 0x0a */
-       { 1920,1440, 8,16},   /* 0x0b */
-       { 2048,1536, 8,16},   /* 0x0c */
-       {  720, 480, 8,16},   /* 0x0d */
-       {  720, 576, 8,16},   /* 0x0e */
-       { 1280, 960, 8,16},   /* 0x0f */
-       {  800, 480, 8,16},   /* 0x10 */
-       { 1024, 576, 8,16},   /* 0x11 */
-       { 1280, 720, 8,16},   /* 0x12 */
-       {  856, 480, 8,16},   /* 0x13 */
-       { 1280, 768, 8,16},   /* 0x14 */
-       { 1400,1050, 8,16},   /* 0x15 */
-       { 1152, 864, 8,16},   /* 0x16 */
-       {  848, 480, 8,16},   /* 0x17 */
-       { 1360, 768, 8,16},   /* 0x18 */
-       { 1024, 600, 8,16},   /* 0x19 */
-       { 1152, 768, 8,16},   /* 0x1a */
-       {  768, 576, 8,16},   /* 0x1b */
-       { 1360,1024, 8,16},   /* 0x1c */
-       { 1680,1050, 8,16},   /* 0x1d */
-       { 1280, 800, 8,16},   /* 0x1e */
-       { 1920,1080, 8,16},   /* 0x1f */
-       {  960, 540, 8,16},   /* 0x20 */
-       {  960, 600, 8,16}    /* 0x21 */
+static const struct SiS_ModeResInfo SiSUSB_ModeResInfo[] = {
+       {320, 200, 8, 8},       /* 0x00 */
+       {320, 240, 8, 8},       /* 0x01 */
+       {320, 400, 8, 8},       /* 0x02 */
+       {400, 300, 8, 8},       /* 0x03 */
+       {512, 384, 8, 8},       /* 0x04 */
+       {640, 400, 8, 16},      /* 0x05 */
+       {640, 480, 8, 16},      /* 0x06 */
+       {800, 600, 8, 16},      /* 0x07 */
+       {1024, 768, 8, 16},     /* 0x08 */
+       {1280, 1024, 8, 16},    /* 0x09 */
+       {1600, 1200, 8, 16},    /* 0x0a */
+       {1920, 1440, 8, 16},    /* 0x0b */
+       {2048, 1536, 8, 16},    /* 0x0c */
+       {720, 480, 8, 16},      /* 0x0d */
+       {720, 576, 8, 16},      /* 0x0e */
+       {1280, 960, 8, 16},     /* 0x0f */
+       {800, 480, 8, 16},      /* 0x10 */
+       {1024, 576, 8, 16},     /* 0x11 */
+       {1280, 720, 8, 16},     /* 0x12 */
+       {856, 480, 8, 16},      /* 0x13 */
+       {1280, 768, 8, 16},     /* 0x14 */
+       {1400, 1050, 8, 16},    /* 0x15 */
+       {1152, 864, 8, 16},     /* 0x16 */
+       {848, 480, 8, 16},      /* 0x17 */
+       {1360, 768, 8, 16},     /* 0x18 */
+       {1024, 600, 8, 16},     /* 0x19 */
+       {1152, 768, 8, 16},     /* 0x1a */
+       {768, 576, 8, 16},      /* 0x1b */
+       {1360, 1024, 8, 16},    /* 0x1c */
+       {1680, 1050, 8, 16},    /* 0x1d */
+       {1280, 800, 8, 16},     /* 0x1e */
+       {1920, 1080, 8, 16},    /* 0x1f */
+       {960, 540, 8, 16},      /* 0x20 */
+       {960, 600, 8, 16}       /* 0x21 */
 };
 
-static const struct SiS_StandTable SiSUSB_StandTable[] =
-{
+static const struct SiS_StandTable SiSUSB_StandTable[] = {
        /* MD_3_400 - mode 0x03 - 400 */
        {
-               0x50,0x18,0x10,0x1000,
-               { 0x00,0x03,0x00,0x02 },
-               0x67,
-               { 0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
-                 0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,
-                 0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,
-                 0xff },
-               { 0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
-                 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
-                 0x0c,0x00,0x0f,0x08 },
-               { 0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, 0xff }
-       },
+        0x50, 0x18, 0x10, 0x1000,
+        {0x00, 0x03, 0x00, 0x02},
+        0x67,
+        {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
+         0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
+         0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
+         0xff},
+        {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+         0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+         0x0c, 0x00, 0x0f, 0x08},
+        {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff}
+        },
        /* Generic for VGA and higher */
        {
-               0x00,0x00,0x00,0x0000,
-               { 0x01,0x0f,0x00,0x0e },
-               0x23,
-               { 0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
-                 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
-                 0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
-                 0xff },
-               { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
-                 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
-                 0x01,0x00,0x00,0x00 },
-               { 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f, 0xff }
-       }
+        0x00, 0x00, 0x00, 0x0000,
+        {0x01, 0x0f, 0x00, 0x0e},
+        0x23,
+        {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e,
+         0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+         0xea, 0x8c, 0xdf, 0x28, 0x40, 0xe7, 0x04, 0xa3,
+         0xff},
+        {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+         0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+         0x01, 0x00, 0x00, 0x00},
+        {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff}
+        }
 };
 
-static const struct SiS_Ext SiSUSB_EModeIDTable[] =
-{
-       {0x2e,0x0a1b,0x0101,SIS_RI_640x480,  0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x8 */
-       {0x2f,0x0a1b,0x0100,SIS_RI_640x400,  0x00,0x00,0x05,0x05,0x10, 0}, /* 640x400x8 */
-       {0x30,0x2a1b,0x0103,SIS_RI_800x600,  0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x8 */
-       {0x31,0x4a1b,0x0000,SIS_RI_720x480,  0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x8 */
-       {0x32,0x4a1b,0x0000,SIS_RI_720x576,  0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x8 */
-       {0x33,0x4a1d,0x0000,SIS_RI_720x480,  0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x16 */
-       {0x34,0x6a1d,0x0000,SIS_RI_720x576,  0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x16 */
-       {0x35,0x4a1f,0x0000,SIS_RI_720x480,  0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x32 */
-       {0x36,0x6a1f,0x0000,SIS_RI_720x576,  0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x32 */
-       {0x38,0x0a1b,0x0105,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x8 */
-       {0x3a,0x0e3b,0x0107,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x8 */
-       {0x41,0x9a1d,0x010e,SIS_RI_320x200,  0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x16 */
-       {0x44,0x0a1d,0x0111,SIS_RI_640x480,  0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x16 */
-       {0x47,0x2a1d,0x0114,SIS_RI_800x600,  0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x16 */
-       {0x4a,0x0a3d,0x0117,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x16 */
-       {0x4d,0x0e7d,0x011a,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x16 */
-       {0x50,0x9a1b,0x0132,SIS_RI_320x240,  0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x8  */
-       {0x51,0xba1b,0x0133,SIS_RI_400x300,  0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x8  */
-       {0x52,0xba1b,0x0134,SIS_RI_512x384,  0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x8  */
-       {0x56,0x9a1d,0x0135,SIS_RI_320x240,  0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x16 */
-       {0x57,0xba1d,0x0136,SIS_RI_400x300,  0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x16 */
-       {0x58,0xba1d,0x0137,SIS_RI_512x384,  0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x16 */
-       {0x59,0x9a1b,0x0138,SIS_RI_320x200,  0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x8  */
-       {0x5c,0xba1f,0x0000,SIS_RI_512x384,  0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x32 */
-       {0x5d,0x0a1d,0x0139,SIS_RI_640x400,  0x00,0x00,0x05,0x07,0x10, 0}, /* 640x400x16 */
-       {0x5e,0x0a1f,0x0000,SIS_RI_640x400,  0x00,0x00,0x05,0x07,0x10, 0}, /* 640x400x32 */
-       {0x62,0x0a3f,0x013a,SIS_RI_640x480,  0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x32 */
-       {0x63,0x2a3f,0x013b,SIS_RI_800x600,  0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x32 */
-       {0x64,0x0a7f,0x013c,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x32 */
-       {0x65,0x0eff,0x013d,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x32 */
-       {0x70,0x6a1b,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x8 */
-       {0x71,0x4a1b,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x8 */
-       {0x74,0x4a1d,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x16 */
-       {0x75,0x0a3d,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x16 */
-       {0x76,0x6a1f,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x32 */
-       {0x77,0x4a1f,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x32 */
-       {0x78,0x0a3f,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x32 */
-       {0x79,0x0a3b,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x8 */
-       {0x7a,0x6a1d,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x16 */
-       {0x23,0x0e3b,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x8 */
-       {0x24,0x0e7d,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x16 */
-       {0x25,0x0eff,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x32 */
-       {0x39,0x6a1b,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x00,0x28,-1}, /* 848x480 */
-       {0x3b,0x6a3d,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x00,0x28,-1},
-       {0x3e,0x6a7f,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x00,0x28,-1},
-       {0x3f,0x6a1b,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x00,0x2a,-1}, /* 856x480 */
-       {0x42,0x6a3d,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x00,0x2a,-1},
-       {0x45,0x6a7f,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x00,0x2a,-1},
-       {0x4f,0x9a1f,0x0000,SIS_RI_320x200,  0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x32 */
-       {0x53,0x9a1f,0x0000,SIS_RI_320x240,  0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x32 */
-       {0x54,0xba1f,0x0000,SIS_RI_400x300,  0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x32 */
-       {0x5f,0x6a1b,0x0000,SIS_RI_768x576,  0x00,0x00,0x06,0x06,0x2c,-1}, /* 768x576 */
-       {0x60,0x6a1d,0x0000,SIS_RI_768x576,  0x00,0x00,0x06,0x06,0x2c,-1},
-       {0x61,0x6a3f,0x0000,SIS_RI_768x576,  0x00,0x00,0x06,0x06,0x2c,-1},
-       {0x1d,0x6a1b,0x0000,SIS_RI_960x540,  0x00,0x00,0x00,0x00,0x2d,-1}, /* 960x540 */
-       {0x1e,0x6a3d,0x0000,SIS_RI_960x540,  0x00,0x00,0x00,0x00,0x2d,-1},
-       {0x1f,0x6a7f,0x0000,SIS_RI_960x540,  0x00,0x00,0x00,0x00,0x2d,-1},
-       {0x20,0x6a1b,0x0000,SIS_RI_960x600,  0x00,0x00,0x00,0x00,0x2e,-1}, /* 960x600 */
-       {0x21,0x6a3d,0x0000,SIS_RI_960x600,  0x00,0x00,0x00,0x00,0x2e,-1},
-       {0x22,0x6a7f,0x0000,SIS_RI_960x600,  0x00,0x00,0x00,0x00,0x2e,-1},
-       {0x29,0x4e1b,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1}, /* 1152x864 */
-       {0x2a,0x4e3d,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1},
-       {0x2b,0x4e7f,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1},
-       {0xff,0x0000,0x0000,0,               0x00,0x00,0x00,0x00,0x00,-1}
+static const struct SiS_Ext SiSUSB_EModeIDTable[] = {
+       {0x2e, 0x0a1b, 0x0101, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2},        /* 640x480x8 */
+       {0x2f, 0x0a1b, 0x0100, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x05, 0x10, 0},        /* 640x400x8 */
+       {0x30, 0x2a1b, 0x0103, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3},        /* 800x600x8 */
+       {0x31, 0x4a1b, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1},       /* 720x480x8 */
+       {0x32, 0x4a1b, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1},       /* 720x576x8 */
+       {0x33, 0x4a1d, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1},       /* 720x480x16 */
+       {0x34, 0x6a1d, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1},       /* 720x576x16 */
+       {0x35, 0x4a1f, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1},       /* 720x480x32 */
+       {0x36, 0x6a1f, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1},       /* 720x576x32 */
+       {0x38, 0x0a1b, 0x0105, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4},       /* 1024x768x8 */
+       {0x3a, 0x0e3b, 0x0107, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8},      /* 1280x1024x8 */
+       {0x41, 0x9a1d, 0x010e, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0},        /* 320x200x16 */
+       {0x44, 0x0a1d, 0x0111, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2},        /* 640x480x16 */
+       {0x47, 0x2a1d, 0x0114, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3},        /* 800x600x16 */
+       {0x4a, 0x0a3d, 0x0117, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4},       /* 1024x768x16 */
+       {0x4d, 0x0e7d, 0x011a, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8},      /* 1280x1024x16 */
+       {0x50, 0x9a1b, 0x0132, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2},        /* 320x240x8  */
+       {0x51, 0xba1b, 0x0133, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3},        /* 400x300x8  */
+       {0x52, 0xba1b, 0x0134, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4},        /* 512x384x8  */
+       {0x56, 0x9a1d, 0x0135, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2},        /* 320x240x16 */
+       {0x57, 0xba1d, 0x0136, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3},        /* 400x300x16 */
+       {0x58, 0xba1d, 0x0137, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4},        /* 512x384x16 */
+       {0x59, 0x9a1b, 0x0138, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0},        /* 320x200x8  */
+       {0x5c, 0xba1f, 0x0000, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4},        /* 512x384x32 */
+       {0x5d, 0x0a1d, 0x0139, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x07, 0x10, 0},        /* 640x400x16 */
+       {0x5e, 0x0a1f, 0x0000, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x07, 0x10, 0},        /* 640x400x32 */
+       {0x62, 0x0a3f, 0x013a, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2},        /* 640x480x32 */
+       {0x63, 0x2a3f, 0x013b, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3},        /* 800x600x32 */
+       {0x64, 0x0a7f, 0x013c, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4},       /* 1024x768x32 */
+       {0x65, 0x0eff, 0x013d, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8},      /* 1280x1024x32 */
+       {0x70, 0x6a1b, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1},       /* 800x480x8 */
+       {0x71, 0x4a1b, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1},      /* 1024x576x8 */
+       {0x74, 0x4a1d, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1},      /* 1024x576x16 */
+       {0x75, 0x0a3d, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5},       /* 1280x720x16 */
+       {0x76, 0x6a1f, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1},       /* 800x480x32 */
+       {0x77, 0x4a1f, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1},      /* 1024x576x32 */
+       {0x78, 0x0a3f, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5},       /* 1280x720x32 */
+       {0x79, 0x0a3b, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5},       /* 1280x720x8 */
+       {0x7a, 0x6a1d, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1},       /* 800x480x16 */
+       {0x23, 0x0e3b, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6},       /* 1280x768x8 */
+       {0x24, 0x0e7d, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6},       /* 1280x768x16 */
+       {0x25, 0x0eff, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6},       /* 1280x768x32 */
+       {0x39, 0x6a1b, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28, -1},       /* 848x480 */
+       {0x3b, 0x6a3d, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28,
+        -1},
+       {0x3e, 0x6a7f, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28,
+        -1},
+       {0x3f, 0x6a1b, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a, -1},       /* 856x480 */
+       {0x42, 0x6a3d, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a,
+        -1},
+       {0x45, 0x6a7f, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a,
+        -1},
+       {0x4f, 0x9a1f, 0x0000, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0},        /* 320x200x32 */
+       {0x53, 0x9a1f, 0x0000, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2},        /* 320x240x32 */
+       {0x54, 0xba1f, 0x0000, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3},        /* 400x300x32 */
+       {0x5f, 0x6a1b, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c, -1},       /* 768x576 */
+       {0x60, 0x6a1d, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c,
+        -1},
+       {0x61, 0x6a3f, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c,
+        -1},
+       {0x1d, 0x6a1b, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d, -1},       /* 960x540 */
+       {0x1e, 0x6a3d, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d,
+        -1},
+       {0x1f, 0x6a7f, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d,
+        -1},
+       {0x20, 0x6a1b, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e, -1},       /* 960x600 */
+       {0x21, 0x6a3d, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e,
+        -1},
+       {0x22, 0x6a7f, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e,
+        -1},
+       {0x29, 0x4e1b, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33, -1},      /* 1152x864 */
+       {0x2a, 0x4e3d, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33,
+        -1},
+       {0x2b, 0x4e7f, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33,
+        -1},
+       {0xff, 0x0000, 0x0000, 0, 0x00, 0x00, 0x00, 0x00, 0x00, -1}
 };
 
-static const struct SiS_Ext2 SiSUSB_RefIndex[] =
-{
-       {0x085f,0x0d,0x03,0x05,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x0 */
-       {0x0067,0x0e,0x04,0x05,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x1 */
-       {0x0067,0x0f,0x08,0x48,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x2 */
-       {0x0067,0x10,0x07,0x8b,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x3 */
-       {0x0047,0x11,0x0a,0x00,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x4 */
-       {0x0047,0x12,0x0d,0x00,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x5 */
-       {0x0047,0x13,0x13,0x00,0x05,0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x6 */
-       {0x0107,0x14,0x1c,0x00,0x05,0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x7 */
-       {0xc85f,0x05,0x00,0x04,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x8 */
-       {0xc067,0x06,0x02,0x04,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x9 */
-       {0xc067,0x07,0x02,0x47,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xa */
-       {0xc067,0x08,0x03,0x8a,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xb */
-       {0xc047,0x09,0x05,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xc */
-       {0xc047,0x0a,0x09,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xd */
-       {0xc047,0x0b,0x0e,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xe */
-       {0xc047,0x0c,0x15,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xf */
-       {0x487f,0x04,0x00,0x00,0x00,0x2f, 640, 400, 0x30, 0x55, 0x6e}, /* 0x10 */
-       {0xc06f,0x3c,0x01,0x06,0x13,0x31, 720, 480, 0x30, 0x00, 0x00}, /* 0x11 */
-       {0x006f,0x3d,0x6f,0x06,0x14,0x32, 720, 576, 0x30, 0x00, 0x00}, /* 0x12 (6f was 03) */
-       {0x0087,0x15,0x06,0x00,0x06,0x38,1024, 768, 0x30, 0x00, 0x00}, /* 0x13 */
-       {0xc877,0x16,0x0b,0x06,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x14 */
-       {0xc067,0x17,0x0f,0x49,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x15 */
-       {0x0067,0x18,0x11,0x00,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x16 */
-       {0x0047,0x19,0x16,0x8c,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x17 */
-       {0x0107,0x1a,0x1b,0x00,0x06,0x38,1024, 768, 0x10, 0x00, 0x00}, /* 0x18 */
-       {0x0107,0x1b,0x1f,0x00,0x06,0x38,1024, 768, 0x10, 0x00, 0x00}, /* 0x19 */
-       {0x407f,0x00,0x00,0x00,0x00,0x41, 320, 200, 0x30, 0x56, 0x4e}, /* 0x1a */
-       {0xc07f,0x01,0x00,0x04,0x04,0x50, 320, 240, 0x30, 0x00, 0x00}, /* 0x1b */
-       {0x007f,0x02,0x04,0x05,0x05,0x51, 400, 300, 0x30, 0x00, 0x00}, /* 0x1c */
-       {0xc077,0x03,0x0b,0x06,0x06,0x52, 512, 384, 0x30, 0x00, 0x00}, /* 0x1d */
-       {0x0077,0x32,0x40,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1e */
-       {0x0047,0x33,0x07,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1f */
-       {0x0047,0x34,0x0a,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x20 */
-       {0x0077,0x35,0x0b,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x21 */
-       {0x0047,0x36,0x11,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x22 */
-       {0x0047,0x37,0x16,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x23 */
-       {0x1137,0x38,0x19,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x24 */
-       {0x1107,0x39,0x1e,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x25 */
-       {0x1307,0x3a,0x20,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x26 */
-       {0x0077,0x42,0x5b,0x08,0x11,0x23,1280, 768, 0x30, 0x00, 0x00}, /* 0x27 */
-       {0x0087,0x45,0x57,0x00,0x16,0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x28 38Hzi  */
-       {0xc067,0x46,0x55,0x0b,0x16,0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x29 848x480-60Hz   */
-       {0x0087,0x47,0x57,0x00,0x17,0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2a 856x480-38Hzi  */
-       {0xc067,0x48,0x57,0x00,0x17,0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2b 856x480-60Hz   */
-       {0x006f,0x4d,0x71,0x06,0x15,0x5f, 768, 576, 0x30, 0x00, 0x00}, /* 0x2c 768x576-56Hz   */
-       {0x0067,0x52,0x6a,0x00,0x1c,0x1d, 960, 540, 0x30, 0x00, 0x00}, /* 0x2d 960x540 60Hz */
-       {0x0077,0x53,0x6b,0x0b,0x1d,0x20, 960, 600, 0x30, 0x00, 0x00}, /* 0x2e 960x600 60Hz */
-       {0x0087,0x1c,0x11,0x00,0x07,0x3a,1280,1024, 0x30, 0x00, 0x00}, /* 0x2f */
-       {0x0137,0x1d,0x19,0x07,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x30 */
-       {0x0107,0x1e,0x1e,0x00,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x31 */
-       {0x0207,0x1f,0x20,0x00,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x32 */
-       {0x0127,0x54,0x6d,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x33 1152x864-60Hz  */
-       {0x0127,0x44,0x19,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x34 1152x864-75Hz  */
-       {0x0127,0x4a,0x1e,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x35 1152x864-85Hz  */
-       {0xffff,0x00,0x00,0x00,0x00,0x00,   0,   0,    0, 0x00, 0x00}
+static const struct SiS_Ext2 SiSUSB_RefIndex[] = {
+       {0x085f, 0x0d, 0x03, 0x05, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00},     /* 0x0 */
+       {0x0067, 0x0e, 0x04, 0x05, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00},     /* 0x1 */
+       {0x0067, 0x0f, 0x08, 0x48, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00},     /* 0x2 */
+       {0x0067, 0x10, 0x07, 0x8b, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00},     /* 0x3 */
+       {0x0047, 0x11, 0x0a, 0x00, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00},     /* 0x4 */
+       {0x0047, 0x12, 0x0d, 0x00, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00},     /* 0x5 */
+       {0x0047, 0x13, 0x13, 0x00, 0x05, 0x30, 800, 600, 0x20, 0x00, 0x00},     /* 0x6 */
+       {0x0107, 0x14, 0x1c, 0x00, 0x05, 0x30, 800, 600, 0x20, 0x00, 0x00},     /* 0x7 */
+       {0xc85f, 0x05, 0x00, 0x04, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},     /* 0x8 */
+       {0xc067, 0x06, 0x02, 0x04, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},     /* 0x9 */
+       {0xc067, 0x07, 0x02, 0x47, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},     /* 0xa */
+       {0xc067, 0x08, 0x03, 0x8a, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},     /* 0xb */
+       {0xc047, 0x09, 0x05, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},     /* 0xc */
+       {0xc047, 0x0a, 0x09, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},     /* 0xd */
+       {0xc047, 0x0b, 0x0e, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},     /* 0xe */
+       {0xc047, 0x0c, 0x15, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},     /* 0xf */
+       {0x487f, 0x04, 0x00, 0x00, 0x00, 0x2f, 640, 400, 0x30, 0x55, 0x6e},     /* 0x10 */
+       {0xc06f, 0x3c, 0x01, 0x06, 0x13, 0x31, 720, 480, 0x30, 0x00, 0x00},     /* 0x11 */
+       {0x006f, 0x3d, 0x6f, 0x06, 0x14, 0x32, 720, 576, 0x30, 0x00, 0x00},     /* 0x12 (6f was 03) */
+       {0x0087, 0x15, 0x06, 0x00, 0x06, 0x38, 1024, 768, 0x30, 0x00, 0x00},    /* 0x13 */
+       {0xc877, 0x16, 0x0b, 0x06, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00},    /* 0x14 */
+       {0xc067, 0x17, 0x0f, 0x49, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00},    /* 0x15 */
+       {0x0067, 0x18, 0x11, 0x00, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00},    /* 0x16 */
+       {0x0047, 0x19, 0x16, 0x8c, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00},    /* 0x17 */
+       {0x0107, 0x1a, 0x1b, 0x00, 0x06, 0x38, 1024, 768, 0x10, 0x00, 0x00},    /* 0x18 */
+       {0x0107, 0x1b, 0x1f, 0x00, 0x06, 0x38, 1024, 768, 0x10, 0x00, 0x00},    /* 0x19 */
+       {0x407f, 0x00, 0x00, 0x00, 0x00, 0x41, 320, 200, 0x30, 0x56, 0x4e},     /* 0x1a */
+       {0xc07f, 0x01, 0x00, 0x04, 0x04, 0x50, 320, 240, 0x30, 0x00, 0x00},     /* 0x1b */
+       {0x007f, 0x02, 0x04, 0x05, 0x05, 0x51, 400, 300, 0x30, 0x00, 0x00},     /* 0x1c */
+       {0xc077, 0x03, 0x0b, 0x06, 0x06, 0x52, 512, 384, 0x30, 0x00, 0x00},     /* 0x1d */
+       {0x0077, 0x32, 0x40, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00},     /* 0x1e */
+       {0x0047, 0x33, 0x07, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00},     /* 0x1f */
+       {0x0047, 0x34, 0x0a, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00},     /* 0x20 */
+       {0x0077, 0x35, 0x0b, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00},    /* 0x21 */
+       {0x0047, 0x36, 0x11, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00},    /* 0x22 */
+       {0x0047, 0x37, 0x16, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00},    /* 0x23 */
+       {0x1137, 0x38, 0x19, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00},    /* 0x24 */
+       {0x1107, 0x39, 0x1e, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00},    /* 0x25 */
+       {0x1307, 0x3a, 0x20, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00},    /* 0x26 */
+       {0x0077, 0x42, 0x5b, 0x08, 0x11, 0x23, 1280, 768, 0x30, 0x00, 0x00},    /* 0x27 */
+       {0x0087, 0x45, 0x57, 0x00, 0x16, 0x39, 848, 480, 0x30, 0x00, 0x00},     /* 0x28 38Hzi  */
+       {0xc067, 0x46, 0x55, 0x0b, 0x16, 0x39, 848, 480, 0x30, 0x00, 0x00},     /* 0x29 848x480-60Hz   */
+       {0x0087, 0x47, 0x57, 0x00, 0x17, 0x3f, 856, 480, 0x30, 0x00, 0x00},     /* 0x2a 856x480-38Hzi  */
+       {0xc067, 0x48, 0x57, 0x00, 0x17, 0x3f, 856, 480, 0x30, 0x00, 0x00},     /* 0x2b 856x480-60Hz   */
+       {0x006f, 0x4d, 0x71, 0x06, 0x15, 0x5f, 768, 576, 0x30, 0x00, 0x00},     /* 0x2c 768x576-56Hz   */
+       {0x0067, 0x52, 0x6a, 0x00, 0x1c, 0x1d, 960, 540, 0x30, 0x00, 0x00},     /* 0x2d 960x540 60Hz */
+       {0x0077, 0x53, 0x6b, 0x0b, 0x1d, 0x20, 960, 600, 0x30, 0x00, 0x00},     /* 0x2e 960x600 60Hz */
+       {0x0087, 0x1c, 0x11, 0x00, 0x07, 0x3a, 1280, 1024, 0x30, 0x00, 0x00},   /* 0x2f */
+       {0x0137, 0x1d, 0x19, 0x07, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00},   /* 0x30 */
+       {0x0107, 0x1e, 0x1e, 0x00, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00},   /* 0x31 */
+       {0x0207, 0x1f, 0x20, 0x00, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00},   /* 0x32 */
+       {0x0127, 0x54, 0x6d, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00},    /* 0x33 1152x864-60Hz  */
+       {0x0127, 0x44, 0x19, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00},    /* 0x34 1152x864-75Hz  */
+       {0x0127, 0x4a, 0x1e, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00},    /* 0x35 1152x864-85Hz  */
+       {0xffff, 0x00, 0x00, 0x00, 0x00, 0x00, 0, 0, 0, 0x00, 0x00}
 };
 
-static const struct SiS_CRT1Table SiSUSB_CRT1Table[] =
-{
- {{0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f,
-   0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x00,
-   0x00}}, /* 0x0 */
- {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e,
-   0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00,
-   0x00}}, /* 0x1 */
- {{0x3d,0x31,0x31,0x81,0x37,0x1f,0x72,0xf0,
-   0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x05,
-   0x01}}, /* 0x2 */
- {{0x4f,0x3f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
-   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x01,
-   0x01}}, /* 0x3 */
- {{0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
-   0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x05,
-   0x00}}, /* 0x4 */
- {{0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e,
-   0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05,
-   0x00}}, /* 0x5 */
- {{0x63,0x4f,0x4f,0x87,0x56,0x9b,0x06,0x3e,
-   0xe8,0x8a,0xdf,0xe7,0x07,0x00,0x00,0x01,
-   0x00}}, /* 0x6 */
- {{0x64,0x4f,0x4f,0x88,0x55,0x9d,0xf2,0x1f,
-   0xe0,0x83,0xdf,0xdf,0xf3,0x10,0x00,0x01,
-   0x00}}, /* 0x7 */
- {{0x63,0x4f,0x4f,0x87,0x5a,0x81,0xfb,0x1f,
-   0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05,
-   0x00}}, /* 0x8 */
- {{0x65,0x4f,0x4f,0x89,0x58,0x80,0xfb,0x1f,
-   0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05,
-   0x61}}, /* 0x9 */
- {{0x65,0x4f,0x4f,0x89,0x58,0x80,0x01,0x3e,
-   0xe0,0x83,0xdf,0xdf,0x02,0x00,0x00,0x05,
-   0x61}}, /* 0xa */
- {{0x67,0x4f,0x4f,0x8b,0x58,0x81,0x0d,0x3e,
-   0xe0,0x83,0xdf,0xdf,0x0e,0x00,0x00,0x05,
-   0x61}}, /* 0xb */
- {{0x65,0x4f,0x4f,0x89,0x57,0x9f,0xfb,0x1f,
-   0xe6,0x8a,0xdf,0xdf,0xfc,0x10,0x00,0x01,
-   0x00}}, /* 0xc */
- {{0x7b,0x63,0x63,0x9f,0x6a,0x93,0x6f,0xf0,
-   0x58,0x8a,0x57,0x57,0x70,0x20,0x00,0x05,
-   0x01}}, /* 0xd */
- {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xf0,
-   0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x06,
-   0x01}}, /* 0xe */
- {{0x7d,0x63,0x63,0x81,0x6e,0x1d,0x98,0xf0,
-   0x7c,0x82,0x57,0x57,0x99,0x00,0x00,0x06,
-   0x01}}, /* 0xf */
- {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xf0,
-   0x58,0x8b,0x57,0x57,0x70,0x20,0x00,0x06,
-   0x01}}, /* 0x10 */
- {{0x7e,0x63,0x63,0x82,0x6b,0x13,0x75,0xf0,
-   0x58,0x8b,0x57,0x57,0x76,0x20,0x00,0x06,
-   0x01}}, /* 0x11 */
- {{0x81,0x63,0x63,0x85,0x6d,0x18,0x7a,0xf0,
-   0x58,0x8b,0x57,0x57,0x7b,0x20,0x00,0x06,
-   0x61}}, /* 0x12 */
- {{0x83,0x63,0x63,0x87,0x6e,0x19,0x81,0xf0,
-   0x58,0x8b,0x57,0x57,0x82,0x20,0x00,0x06,
-   0x61}}, /* 0x13 */
- {{0x85,0x63,0x63,0x89,0x6f,0x1a,0x91,0xf0,
-   0x58,0x8b,0x57,0x57,0x92,0x20,0x00,0x06,
-   0x61}}, /* 0x14 */
- {{0x99,0x7f,0x7f,0x9d,0x84,0x1a,0x96,0x1f,
-   0x7f,0x83,0x7f,0x7f,0x97,0x10,0x00,0x02,
-   0x00}}, /* 0x15 */
- {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,
-   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
-   0x01}}, /* 0x16 */
- {{0xa1,0x7f,0x7f,0x85,0x86,0x97,0x24,0xf5,
-   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
-   0x01}}, /* 0x17 */
- {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf5,
-   0x00,0x83,0xff,0xff,0x1f,0x10,0x00,0x02,
-   0x01}}, /* 0x18 */
- {{0xa7,0x7f,0x7f,0x8b,0x89,0x95,0x26,0xf5,
-   0x00,0x83,0xff,0xff,0x27,0x10,0x00,0x02,
-   0x01}}, /* 0x19 */
- {{0xa9,0x7f,0x7f,0x8d,0x8c,0x9a,0x2c,0xf5,
-   0x00,0x83,0xff,0xff,0x2d,0x14,0x00,0x02,
-   0x62}}, /* 0x1a */
- {{0xab,0x7f,0x7f,0x8f,0x8d,0x9b,0x35,0xf5,
-   0x00,0x83,0xff,0xff,0x36,0x14,0x00,0x02,
-   0x62}}, /* 0x1b */
- {{0xcf,0x9f,0x9f,0x93,0xb2,0x01,0x14,0xba,
-   0x00,0x83,0xff,0xff,0x15,0x00,0x00,0x03,
-   0x00}}, /* 0x1c */
- {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0x5a,
-   0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07,
-   0x01}}, /* 0x1d */
- {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0x5a,
-   0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07,
-   0x01}}, /* 0x1e */
- {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0x5a,
-   0x00,0x83,0xff,0xff,0x2f,0x09,0x00,0x07,
-   0x01}}, /* 0x1f */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-   0x00}}, /* 0x20 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-   0x00}}, /* 0x21 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-   0x00}}, /* 0x22 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-   0x00}}, /* 0x23 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-   0x00}}, /* 0x24 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-   0x00}}, /* 0x25 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-   0x00}}, /* 0x26 */
- {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
-   0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
-   0x00}}, /* 0x27 */
- {{0x43,0xef,0xef,0x87,0x06,0x00,0xd4,0x1f,
-   0xa0,0x83,0x9f,0x9f,0xd5,0x1f,0x41,0x05,
-   0x63}}, /* 0x28 */
- {{0x45,0xef,0xef,0x89,0x07,0x01,0xd9,0x1f,
-   0xa0,0x83,0x9f,0x9f,0xda,0x1f,0x41,0x05,
-   0x63}}, /* 0x29 */
- {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
-   0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
-   0x00}}, /* 0x2a */
- {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
-   0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
-   0x00}}, /* 0x2b */
- {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
-   0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
-   0x00}}, /* 0x2c */
- {{0x59,0xff,0xff,0x9d,0x17,0x13,0x33,0xba,
-   0x00,0x83,0xff,0xff,0x34,0x0f,0x41,0x05,
-   0x44}}, /* 0x2d */
- {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x38,0xba,
-   0x00,0x83,0xff,0xff,0x39,0x0f,0x41,0x05,
-   0x44}}, /* 0x2e */
- {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x3d,0xba,
-   0x00,0x83,0xff,0xff,0x3e,0x0f,0x41,0x05,
-   0x44}}, /* 0x2f */
- {{0x5d,0xff,0xff,0x81,0x19,0x95,0x41,0xba,
-   0x00,0x84,0xff,0xff,0x42,0x0f,0x41,0x05,
-   0x44}}, /* 0x30 */
- {{0x55,0xff,0xff,0x99,0x0d,0x0c,0x3e,0xba,
-   0x00,0x84,0xff,0xff,0x3f,0x0f,0x41,0x05,
-   0x00}}, /* 0x31 */
- {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xba,
-   0x27,0x8b,0xdf,0xdf,0x73,0x00,0x00,0x06,
-   0x01}}, /* 0x32 */
- {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xba,
-   0x26,0x89,0xdf,0xdf,0x6f,0x00,0x00,0x06,
-   0x01}}, /* 0x33 */
- {{0x7f,0x63,0x63,0x82,0x6b,0x13,0x75,0xba,
-   0x29,0x8c,0xdf,0xdf,0x75,0x00,0x00,0x06,
-   0x01}}, /* 0x34 */
- {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf1,
-   0xaf,0x85,0x3f,0x3f,0x25,0x30,0x00,0x02,
-   0x01}}, /* 0x35 */
- {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf1,
-   0xad,0x81,0x3f,0x3f,0x1f,0x30,0x00,0x02,
-   0x01}}, /* 0x36 */
- {{0xa7,0x7f,0x7f,0x88,0x89,0x95,0x26,0xf1,
-   0xb1,0x85,0x3f,0x3f,0x27,0x30,0x00,0x02,
-   0x01}}, /* 0x37 */
- {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0xc4,
-   0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07,
-   0x01}}, /* 0x38 */
- {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0xd4,
-   0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07,
-   0x01}}, /* 0x39 */
- {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0xd4,
-   0x7d,0x81,0xcf,0xcf,0x2f,0x21,0x00,0x07,
-   0x01}}, /* 0x3a */
- {{0xdc,0x9f,0x9f,0x80,0xaf,0x9d,0xe6,0xff,
-   0xc0,0x83,0xbf,0xbf,0xe7,0x10,0x00,0x07,
-   0x01}}, /* 0x3b */
- {{0x6b,0x59,0x59,0x8f,0x5e,0x8c,0x0b,0x3e,
-   0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05,
-   0x00}}, /* 0x3c */
- {{0x6d,0x59,0x59,0x91,0x60,0x89,0x53,0xf0,
-   0x41,0x84,0x3f,0x3f,0x54,0x00,0x00,0x05,
-   0x41}}, /* 0x3d */
- {{0x86,0x6a,0x6a,0x8a,0x74,0x06,0x8c,0x15,
-   0x4f,0x83,0xef,0xef,0x8d,0x30,0x00,0x02,
-   0x00}}, /* 0x3e */
- {{0x81,0x6a,0x6a,0x85,0x70,0x00,0x0f,0x3e,
-   0xeb,0x8e,0xdf,0xdf,0x10,0x00,0x00,0x02,
-   0x00}}, /* 0x3f */
- {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x1e,0xf1,
-   0xae,0x85,0x57,0x57,0x1f,0x30,0x00,0x02,
-   0x01}},  /* 0x40 */
- {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,
-   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
-   0x01}},  /* 0x41 */
- {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x20,0xf5,
-   0x03,0x88,0xff,0xff,0x21,0x10,0x00,0x07,
-   0x01}},  /* 0x42 */
- {{0xe6,0xae,0xae,0x8a,0xbd,0x90,0x3d,0x10,
-   0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x00,0x03,
-   0x00}},  /* 0x43 */
- {{0xc3,0x8f,0x8f,0x87,0x9b,0x0b,0x82,0xef,
-   0x60,0x83,0x5f,0x5f,0x83,0x10,0x00,0x07,
-   0x01}},  /* 0x44 */
- {{0x86,0x69,0x69,0x8A,0x74,0x06,0x8C,0x15,
-   0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02,
-   0x00}},  /* 0x45 */
- {{0x83,0x69,0x69,0x87,0x6f,0x1d,0x03,0x3E,
-   0xE5,0x8d,0xDF,0xe4,0x04,0x00,0x00,0x06,
-   0x00}},  /* 0x46 */
- {{0x86,0x6A,0x6A,0x8A,0x74,0x06,0x8C,0x15,
-   0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02,
-   0x00}},  /* 0x47 */
- {{0x81,0x6A,0x6A,0x85,0x70,0x00,0x0F,0x3E,
-   0xEB,0x8E,0xDF,0xDF,0x10,0x00,0x00,0x02,
-   0x00}},  /* 0x48 */
- {{0xdd,0xa9,0xa9,0x81,0xb4,0x97,0x26,0xfd,
-   0x01,0x8d,0xff,0x00,0x27,0x10,0x00,0x03,
-   0x01}},  /* 0x49 */
- {{0xd9,0x8f,0x8f,0x9d,0xba,0x0a,0x8a,0xff,
-   0x60,0x8b,0x5f,0x5f,0x8b,0x10,0x00,0x03,
-   0x01}},  /* 0x4a */
- {{0xea,0xae,0xae,0x8e,0xba,0x82,0x40,0x10,
-   0x1b,0x87,0x19,0x1a,0x41,0x0f,0x00,0x03,
-   0x00}},  /* 0x4b */
- {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0xf1,0xff,
-   0xc0,0x83,0xbf,0xbf,0xf2,0x10,0x00,0x07,
-   0x01}},  /* 0x4c */
- {{0x75,0x5f,0x5f,0x99,0x66,0x90,0x53,0xf0,
-   0x41,0x84,0x3f,0x3f,0x54,0x00,0x00,0x05,
-   0x41}},
- {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e,
-   0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00,
-   0x00}},  /* 0x4e */
- {{0xcd,0x9f,0x9f,0x91,0xab,0x1c,0x3a,0xff,
-   0x20,0x83,0x1f,0x1f,0x3b,0x10,0x00,0x07,
-   0x21}},  /* 0x4f */
- {{0x15,0xd1,0xd1,0x99,0xe2,0x19,0x3d,0x10,
-   0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x01,0x0c,
-   0x20}},  /* 0x50 */
- {{0x0e,0xef,0xef,0x92,0xfe,0x03,0x30,0xf0,
-   0x1e,0x83,0x1b,0x1c,0x31,0x00,0x01,0x00,
-   0x61}},  /* 0x51 */
- {{0x85,0x77,0x77,0x89,0x7d,0x01,0x31,0xf0,
-   0x1e,0x84,0x1b,0x1c,0x32,0x00,0x00,0x02,
-   0x41}},  /* 0x52 */
- {{0x87,0x77,0x77,0x8b,0x81,0x0b,0x68,0xf0,
-   0x5a,0x80,0x57,0x57,0x69,0x00,0x00,0x02,
-   0x01}},  /* 0x53 */
- {{0xcd,0x8f,0x8f,0x91,0x9b,0x1b,0x7a,0xff,
-   0x64,0x8c,0x5f,0x62,0x7b,0x10,0x00,0x07,
-   0x41}}   /* 0x54 */
+static const struct SiS_CRT1Table SiSUSB_CRT1Table[] = {
+       {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f,
+         0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x00,
+         0x00}},               /* 0x0 */
+       {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0x0b, 0x3e,
+         0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x00,
+         0x00}},               /* 0x1 */
+       {{0x3d, 0x31, 0x31, 0x81, 0x37, 0x1f, 0x72, 0xf0,
+         0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x05,
+         0x01}},               /* 0x2 */
+       {{0x4f, 0x3f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5,
+         0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x01,
+         0x01}},               /* 0x3 */
+       {{0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
+         0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x05,
+         0x00}},               /* 0x4 */
+       {{0x5f, 0x4f, 0x4f, 0x83, 0x55, 0x81, 0x0b, 0x3e,
+         0xe9, 0x8b, 0xdf, 0xe8, 0x0c, 0x00, 0x00, 0x05,
+         0x00}},               /* 0x5 */
+       {{0x63, 0x4f, 0x4f, 0x87, 0x56, 0x9b, 0x06, 0x3e,
+         0xe8, 0x8a, 0xdf, 0xe7, 0x07, 0x00, 0x00, 0x01,
+         0x00}},               /* 0x6 */
+       {{0x64, 0x4f, 0x4f, 0x88, 0x55, 0x9d, 0xf2, 0x1f,
+         0xe0, 0x83, 0xdf, 0xdf, 0xf3, 0x10, 0x00, 0x01,
+         0x00}},               /* 0x7 */
+       {{0x63, 0x4f, 0x4f, 0x87, 0x5a, 0x81, 0xfb, 0x1f,
+         0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x05,
+         0x00}},               /* 0x8 */
+       {{0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0xfb, 0x1f,
+         0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x05,
+         0x61}},               /* 0x9 */
+       {{0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0x01, 0x3e,
+         0xe0, 0x83, 0xdf, 0xdf, 0x02, 0x00, 0x00, 0x05,
+         0x61}},               /* 0xa */
+       {{0x67, 0x4f, 0x4f, 0x8b, 0x58, 0x81, 0x0d, 0x3e,
+         0xe0, 0x83, 0xdf, 0xdf, 0x0e, 0x00, 0x00, 0x05,
+         0x61}},               /* 0xb */
+       {{0x65, 0x4f, 0x4f, 0x89, 0x57, 0x9f, 0xfb, 0x1f,
+         0xe6, 0x8a, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x01,
+         0x00}},               /* 0xc */
+       {{0x7b, 0x63, 0x63, 0x9f, 0x6a, 0x93, 0x6f, 0xf0,
+         0x58, 0x8a, 0x57, 0x57, 0x70, 0x20, 0x00, 0x05,
+         0x01}},               /* 0xd */
+       {{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xf0,
+         0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x06,
+         0x01}},               /* 0xe */
+       {{0x7d, 0x63, 0x63, 0x81, 0x6e, 0x1d, 0x98, 0xf0,
+         0x7c, 0x82, 0x57, 0x57, 0x99, 0x00, 0x00, 0x06,
+         0x01}},               /* 0xf */
+       {{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xf0,
+         0x58, 0x8b, 0x57, 0x57, 0x70, 0x20, 0x00, 0x06,
+         0x01}},               /* 0x10 */
+       {{0x7e, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xf0,
+         0x58, 0x8b, 0x57, 0x57, 0x76, 0x20, 0x00, 0x06,
+         0x01}},               /* 0x11 */
+       {{0x81, 0x63, 0x63, 0x85, 0x6d, 0x18, 0x7a, 0xf0,
+         0x58, 0x8b, 0x57, 0x57, 0x7b, 0x20, 0x00, 0x06,
+         0x61}},               /* 0x12 */
+       {{0x83, 0x63, 0x63, 0x87, 0x6e, 0x19, 0x81, 0xf0,
+         0x58, 0x8b, 0x57, 0x57, 0x82, 0x20, 0x00, 0x06,
+         0x61}},               /* 0x13 */
+       {{0x85, 0x63, 0x63, 0x89, 0x6f, 0x1a, 0x91, 0xf0,
+         0x58, 0x8b, 0x57, 0x57, 0x92, 0x20, 0x00, 0x06,
+         0x61}},               /* 0x14 */
+       {{0x99, 0x7f, 0x7f, 0x9d, 0x84, 0x1a, 0x96, 0x1f,
+         0x7f, 0x83, 0x7f, 0x7f, 0x97, 0x10, 0x00, 0x02,
+         0x00}},               /* 0x15 */
+       {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5,
+         0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02,
+         0x01}},               /* 0x16 */
+       {{0xa1, 0x7f, 0x7f, 0x85, 0x86, 0x97, 0x24, 0xf5,
+         0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02,
+         0x01}},               /* 0x17 */
+       {{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf5,
+         0x00, 0x83, 0xff, 0xff, 0x1f, 0x10, 0x00, 0x02,
+         0x01}},               /* 0x18 */
+       {{0xa7, 0x7f, 0x7f, 0x8b, 0x89, 0x95, 0x26, 0xf5,
+         0x00, 0x83, 0xff, 0xff, 0x27, 0x10, 0x00, 0x02,
+         0x01}},               /* 0x19 */
+       {{0xa9, 0x7f, 0x7f, 0x8d, 0x8c, 0x9a, 0x2c, 0xf5,
+         0x00, 0x83, 0xff, 0xff, 0x2d, 0x14, 0x00, 0x02,
+         0x62}},               /* 0x1a */
+       {{0xab, 0x7f, 0x7f, 0x8f, 0x8d, 0x9b, 0x35, 0xf5,
+         0x00, 0x83, 0xff, 0xff, 0x36, 0x14, 0x00, 0x02,
+         0x62}},               /* 0x1b */
+       {{0xcf, 0x9f, 0x9f, 0x93, 0xb2, 0x01, 0x14, 0xba,
+         0x00, 0x83, 0xff, 0xff, 0x15, 0x00, 0x00, 0x03,
+         0x00}},               /* 0x1c */
+       {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0x5a,
+         0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07,
+         0x01}},               /* 0x1d */
+       {{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0x5a,
+         0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07,
+         0x01}},               /* 0x1e */
+       {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0x5a,
+         0x00, 0x83, 0xff, 0xff, 0x2f, 0x09, 0x00, 0x07,
+         0x01}},               /* 0x1f */
+       {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+         0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+         0x00}},               /* 0x20 */
+       {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+         0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+         0x00}},               /* 0x21 */
+       {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+         0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+         0x00}},               /* 0x22 */
+       {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+         0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+         0x00}},               /* 0x23 */
+       {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+         0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+         0x00}},               /* 0x24 */
+       {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+         0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+         0x00}},               /* 0x25 */
+       {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+         0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+         0x00}},               /* 0x26 */
+       {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f,
+         0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01,
+         0x00}},               /* 0x27 */
+       {{0x43, 0xef, 0xef, 0x87, 0x06, 0x00, 0xd4, 0x1f,
+         0xa0, 0x83, 0x9f, 0x9f, 0xd5, 0x1f, 0x41, 0x05,
+         0x63}},               /* 0x28 */
+       {{0x45, 0xef, 0xef, 0x89, 0x07, 0x01, 0xd9, 0x1f,
+         0xa0, 0x83, 0x9f, 0x9f, 0xda, 0x1f, 0x41, 0x05,
+         0x63}},               /* 0x29 */
+       {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f,
+         0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01,
+         0x00}},               /* 0x2a */
+       {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f,
+         0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01,
+         0x00}},               /* 0x2b */
+       {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f,
+         0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01,
+         0x00}},               /* 0x2c */
+       {{0x59, 0xff, 0xff, 0x9d, 0x17, 0x13, 0x33, 0xba,
+         0x00, 0x83, 0xff, 0xff, 0x34, 0x0f, 0x41, 0x05,
+         0x44}},               /* 0x2d */
+       {{0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x38, 0xba,
+         0x00, 0x83, 0xff, 0xff, 0x39, 0x0f, 0x41, 0x05,
+         0x44}},               /* 0x2e */
+       {{0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x3d, 0xba,
+         0x00, 0x83, 0xff, 0xff, 0x3e, 0x0f, 0x41, 0x05,
+         0x44}},               /* 0x2f */
+       {{0x5d, 0xff, 0xff, 0x81, 0x19, 0x95, 0x41, 0xba,
+         0x00, 0x84, 0xff, 0xff, 0x42, 0x0f, 0x41, 0x05,
+         0x44}},               /* 0x30 */
+       {{0x55, 0xff, 0xff, 0x99, 0x0d, 0x0c, 0x3e, 0xba,
+         0x00, 0x84, 0xff, 0xff, 0x3f, 0x0f, 0x41, 0x05,
+         0x00}},               /* 0x31 */
+       {{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xba,
+         0x27, 0x8b, 0xdf, 0xdf, 0x73, 0x00, 0x00, 0x06,
+         0x01}},               /* 0x32 */
+       {{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xba,
+         0x26, 0x89, 0xdf, 0xdf, 0x6f, 0x00, 0x00, 0x06,
+         0x01}},               /* 0x33 */
+       {{0x7f, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xba,
+         0x29, 0x8c, 0xdf, 0xdf, 0x75, 0x00, 0x00, 0x06,
+         0x01}},               /* 0x34 */
+       {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf1,
+         0xaf, 0x85, 0x3f, 0x3f, 0x25, 0x30, 0x00, 0x02,
+         0x01}},               /* 0x35 */
+       {{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf1,
+         0xad, 0x81, 0x3f, 0x3f, 0x1f, 0x30, 0x00, 0x02,
+         0x01}},               /* 0x36 */
+       {{0xa7, 0x7f, 0x7f, 0x88, 0x89, 0x95, 0x26, 0xf1,
+         0xb1, 0x85, 0x3f, 0x3f, 0x27, 0x30, 0x00, 0x02,
+         0x01}},               /* 0x37 */
+       {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0xc4,
+         0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07,
+         0x01}},               /* 0x38 */
+       {{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0xd4,
+         0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07,
+         0x01}},               /* 0x39 */
+       {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0xd4,
+         0x7d, 0x81, 0xcf, 0xcf, 0x2f, 0x21, 0x00, 0x07,
+         0x01}},               /* 0x3a */
+       {{0xdc, 0x9f, 0x9f, 0x80, 0xaf, 0x9d, 0xe6, 0xff,
+         0xc0, 0x83, 0xbf, 0xbf, 0xe7, 0x10, 0x00, 0x07,
+         0x01}},               /* 0x3b */
+       {{0x6b, 0x59, 0x59, 0x8f, 0x5e, 0x8c, 0x0b, 0x3e,
+         0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x05,
+         0x00}},               /* 0x3c */
+       {{0x6d, 0x59, 0x59, 0x91, 0x60, 0x89, 0x53, 0xf0,
+         0x41, 0x84, 0x3f, 0x3f, 0x54, 0x00, 0x00, 0x05,
+         0x41}},               /* 0x3d */
+       {{0x86, 0x6a, 0x6a, 0x8a, 0x74, 0x06, 0x8c, 0x15,
+         0x4f, 0x83, 0xef, 0xef, 0x8d, 0x30, 0x00, 0x02,
+         0x00}},               /* 0x3e */
+       {{0x81, 0x6a, 0x6a, 0x85, 0x70, 0x00, 0x0f, 0x3e,
+         0xeb, 0x8e, 0xdf, 0xdf, 0x10, 0x00, 0x00, 0x02,
+         0x00}},               /* 0x3f */
+       {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x1e, 0xf1,
+         0xae, 0x85, 0x57, 0x57, 0x1f, 0x30, 0x00, 0x02,
+         0x01}},               /* 0x40 */
+       {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5,
+         0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02,
+         0x01}},               /* 0x41 */
+       {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x20, 0xf5,
+         0x03, 0x88, 0xff, 0xff, 0x21, 0x10, 0x00, 0x07,
+         0x01}},               /* 0x42 */
+       {{0xe6, 0xae, 0xae, 0x8a, 0xbd, 0x90, 0x3d, 0x10,
+         0x1a, 0x8d, 0x19, 0x19, 0x3e, 0x2f, 0x00, 0x03,
+         0x00}},               /* 0x43 */
+       {{0xc3, 0x8f, 0x8f, 0x87, 0x9b, 0x0b, 0x82, 0xef,
+         0x60, 0x83, 0x5f, 0x5f, 0x83, 0x10, 0x00, 0x07,
+         0x01}},               /* 0x44 */
+       {{0x86, 0x69, 0x69, 0x8A, 0x74, 0x06, 0x8C, 0x15,
+         0x4F, 0x83, 0xEF, 0xEF, 0x8D, 0x30, 0x00, 0x02,
+         0x00}},               /* 0x45 */
+       {{0x83, 0x69, 0x69, 0x87, 0x6f, 0x1d, 0x03, 0x3E,
+         0xE5, 0x8d, 0xDF, 0xe4, 0x04, 0x00, 0x00, 0x06,
+         0x00}},               /* 0x46 */
+       {{0x86, 0x6A, 0x6A, 0x8A, 0x74, 0x06, 0x8C, 0x15,
+         0x4F, 0x83, 0xEF, 0xEF, 0x8D, 0x30, 0x00, 0x02,
+         0x00}},               /* 0x47 */
+       {{0x81, 0x6A, 0x6A, 0x85, 0x70, 0x00, 0x0F, 0x3E,
+         0xEB, 0x8E, 0xDF, 0xDF, 0x10, 0x00, 0x00, 0x02,
+         0x00}},               /* 0x48 */
+       {{0xdd, 0xa9, 0xa9, 0x81, 0xb4, 0x97, 0x26, 0xfd,
+         0x01, 0x8d, 0xff, 0x00, 0x27, 0x10, 0x00, 0x03,
+         0x01}},               /* 0x49 */
+       {{0xd9, 0x8f, 0x8f, 0x9d, 0xba, 0x0a, 0x8a, 0xff,
+         0x60, 0x8b, 0x5f, 0x5f, 0x8b, 0x10, 0x00, 0x03,
+         0x01}},               /* 0x4a */
+       {{0xea, 0xae, 0xae, 0x8e, 0xba, 0x82, 0x40, 0x10,
+         0x1b, 0x87, 0x19, 0x1a, 0x41, 0x0f, 0x00, 0x03,
+         0x00}},               /* 0x4b */
+       {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0xf1, 0xff,
+         0xc0, 0x83, 0xbf, 0xbf, 0xf2, 0x10, 0x00, 0x07,
+         0x01}},               /* 0x4c */
+       {{0x75, 0x5f, 0x5f, 0x99, 0x66, 0x90, 0x53, 0xf0,
+         0x41, 0x84, 0x3f, 0x3f, 0x54, 0x00, 0x00, 0x05,
+         0x41}},
+       {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0x0b, 0x3e,
+         0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x00,
+         0x00}},               /* 0x4e */
+       {{0xcd, 0x9f, 0x9f, 0x91, 0xab, 0x1c, 0x3a, 0xff,
+         0x20, 0x83, 0x1f, 0x1f, 0x3b, 0x10, 0x00, 0x07,
+         0x21}},               /* 0x4f */
+       {{0x15, 0xd1, 0xd1, 0x99, 0xe2, 0x19, 0x3d, 0x10,
+         0x1a, 0x8d, 0x19, 0x19, 0x3e, 0x2f, 0x01, 0x0c,
+         0x20}},               /* 0x50 */
+       {{0x0e, 0xef, 0xef, 0x92, 0xfe, 0x03, 0x30, 0xf0,
+         0x1e, 0x83, 0x1b, 0x1c, 0x31, 0x00, 0x01, 0x00,
+         0x61}},               /* 0x51 */
+       {{0x85, 0x77, 0x77, 0x89, 0x7d, 0x01, 0x31, 0xf0,
+         0x1e, 0x84, 0x1b, 0x1c, 0x32, 0x00, 0x00, 0x02,
+         0x41}},               /* 0x52 */
+       {{0x87, 0x77, 0x77, 0x8b, 0x81, 0x0b, 0x68, 0xf0,
+         0x5a, 0x80, 0x57, 0x57, 0x69, 0x00, 0x00, 0x02,
+         0x01}},               /* 0x53 */
+       {{0xcd, 0x8f, 0x8f, 0x91, 0x9b, 0x1b, 0x7a, 0xff,
+         0x64, 0x8c, 0x5f, 0x62, 0x7b, 0x10, 0x00, 0x07,
+         0x41}}                /* 0x54 */
 };
 
-static const struct SiS_VCLKData SiSUSB_VCLKData[] =
-{
-       { 0x1b,0xe1, 25}, /* 0x00 */
-       { 0x4e,0xe4, 28}, /* 0x01 */
-       { 0x57,0xe4, 31}, /* 0x02 */
-       { 0xc3,0xc8, 36}, /* 0x03 */
-       { 0x42,0xe2, 40}, /* 0x04 */
-       { 0xfe,0xcd, 43}, /* 0x05 */
-       { 0x5d,0xc4, 44}, /* 0x06 */
-       { 0x52,0xe2, 49}, /* 0x07 */
-       { 0x53,0xe2, 50}, /* 0x08 */
-       { 0x74,0x67, 52}, /* 0x09 */
-       { 0x6d,0x66, 56}, /* 0x0a */
-       { 0x5a,0x64, 65}, /* 0x0b */
-       { 0x46,0x44, 67}, /* 0x0c */
-       { 0xb1,0x46, 68}, /* 0x0d */
-       { 0xd3,0x4a, 72}, /* 0x0e */
-       { 0x29,0x61, 75}, /* 0x0f */
-       { 0x6e,0x46, 76}, /* 0x10 */
-       { 0x2b,0x61, 78}, /* 0x11 */
-       { 0x31,0x42, 79}, /* 0x12 */
-       { 0xab,0x44, 83}, /* 0x13 */
-       { 0x46,0x25, 84}, /* 0x14 */
-       { 0x78,0x29, 86}, /* 0x15 */
-       { 0x62,0x44, 94}, /* 0x16 */
-       { 0x2b,0x41,104}, /* 0x17 */
-       { 0x3a,0x23,105}, /* 0x18 */
-       { 0x70,0x44,108}, /* 0x19 */
-       { 0x3c,0x23,109}, /* 0x1a */
-       { 0x5e,0x43,113}, /* 0x1b */
-       { 0xbc,0x44,116}, /* 0x1c */
-       { 0xe0,0x46,132}, /* 0x1d */
-       { 0x54,0x42,135}, /* 0x1e */
-       { 0xea,0x2a,139}, /* 0x1f */
-       { 0x41,0x22,157}, /* 0x20 */
-       { 0x70,0x24,162}, /* 0x21 */
-       { 0x30,0x21,175}, /* 0x22 */
-       { 0x4e,0x22,189}, /* 0x23 */
-       { 0xde,0x26,194}, /* 0x24 */
-       { 0x62,0x06,202}, /* 0x25 */
-       { 0x3f,0x03,229}, /* 0x26 */
-       { 0xb8,0x06,234}, /* 0x27 */
-       { 0x34,0x02,253}, /* 0x28 */
-       { 0x58,0x04,255}, /* 0x29 */
-       { 0x24,0x01,265}, /* 0x2a */
-       { 0x9b,0x02,267}, /* 0x2b */
-       { 0x70,0x05,270}, /* 0x2c */
-       { 0x25,0x01,272}, /* 0x2d */
-       { 0x9c,0x02,277}, /* 0x2e */
-       { 0x27,0x01,286}, /* 0x2f */
-       { 0x3c,0x02,291}, /* 0x30 */
-       { 0xef,0x0a,292}, /* 0x31 */
-       { 0xf6,0x0a,310}, /* 0x32 */
-       { 0x95,0x01,315}, /* 0x33 */
-       { 0xf0,0x09,324}, /* 0x34 */
-       { 0xfe,0x0a,331}, /* 0x35 */
-       { 0xf3,0x09,332}, /* 0x36 */
-       { 0xea,0x08,340}, /* 0x37 */
-       { 0xe8,0x07,376}, /* 0x38 */
-       { 0xde,0x06,389}, /* 0x39 */
-       { 0x52,0x2a, 54}, /* 0x3a 301 TV */
-       { 0x52,0x6a, 27}, /* 0x3b 301 TV */
-       { 0x62,0x24, 70}, /* 0x3c 301 TV */
-       { 0x62,0x64, 70}, /* 0x3d 301 TV */
-       { 0xa8,0x4c, 30}, /* 0x3e 301 TV */
-       { 0x20,0x26, 33}, /* 0x3f 301 TV */
-       { 0x31,0xc2, 39}, /* 0x40 */
-       { 0x60,0x36, 30}, /* 0x41 Chrontel */
-       { 0x40,0x4a, 28}, /* 0x42 Chrontel */
-       { 0x9f,0x46, 44}, /* 0x43 Chrontel */
-       { 0x97,0x2c, 26}, /* 0x44 */
-       { 0x44,0xe4, 25}, /* 0x45 Chrontel */
-       { 0x7e,0x32, 47}, /* 0x46 Chrontel */
-       { 0x8a,0x24, 31}, /* 0x47 Chrontel */
-       { 0x97,0x2c, 26}, /* 0x48 Chrontel */
-       { 0xce,0x3c, 39}, /* 0x49 */
-       { 0x52,0x4a, 36}, /* 0x4a Chrontel */
-       { 0x34,0x61, 95}, /* 0x4b */
-       { 0x78,0x27,108}, /* 0x4c - was 102 */
-       { 0x66,0x43,123}, /* 0x4d Modes 0x26-0x28 (1400x1050) */
-       { 0x41,0x4e, 21}, /* 0x4e */
-       { 0xa1,0x4a, 29}, /* 0x4f Chrontel */
-       { 0x19,0x42, 42}, /* 0x50 */
-       { 0x54,0x46, 58}, /* 0x51 Chrontel */
-       { 0x25,0x42, 61}, /* 0x52 */
-       { 0x44,0x44, 66}, /* 0x53 Chrontel */
-       { 0x3a,0x62, 70}, /* 0x54 Chrontel */
-       { 0x62,0xc6, 34}, /* 0x55 848x480-60 */
-       { 0x6a,0xc6, 37}, /* 0x56 848x480-75 - TEMP */
-       { 0xbf,0xc8, 35}, /* 0x57 856x480-38i,60 */
-       { 0x30,0x23, 88}, /* 0x58 1360x768-62 (is 60Hz!) */
-       { 0x52,0x07,149}, /* 0x59 1280x960-85 */
-       { 0x56,0x07,156}, /* 0x5a 1400x1050-75 */
-       { 0x70,0x29, 81}, /* 0x5b 1280x768 LCD */
-       { 0x45,0x25, 83}, /* 0x5c 1280x800  */
-       { 0x70,0x0a,147}, /* 0x5d 1680x1050 */
-       { 0x70,0x24,162}, /* 0x5e 1600x1200 */
-       { 0x5a,0x64, 65}, /* 0x5f 1280x720 - temp */
-       { 0x63,0x46, 68}, /* 0x60 1280x768_2 */
-       { 0x31,0x42, 79}, /* 0x61 1280x768_3 - temp */
-       {    0,   0,  0}, /* 0x62 - custom (will be filled out at run-time) */
-       { 0x5a,0x64, 65}, /* 0x63 1280x720 (LCD LVDS) */
-       { 0x70,0x28, 90}, /* 0x64 1152x864@60 */
-       { 0x41,0xc4, 32}, /* 0x65 848x480@60 */
-       { 0x5c,0xc6, 32}, /* 0x66 856x480@60 */
-       { 0x76,0xe7, 27}, /* 0x67 720x480@60 */
-       { 0x5f,0xc6, 33}, /* 0x68 720/768x576@60 */
-       { 0x52,0x27, 75}, /* 0x69 1920x1080i 60Hz interlaced */
-       { 0x7c,0x6b, 38}, /* 0x6a 960x540@60 */
-       { 0xe3,0x56, 41}, /* 0x6b 960x600@60 */
-       { 0x45,0x25, 83}, /* 0x6c 1280x800 */
-       { 0x70,0x28, 90}, /* 0x6d 1152x864@60 */
-       { 0x15,0xe1, 20}, /* 0x6e 640x400@60 (fake, not actually used) */
-       { 0x5f,0xc6, 33}, /* 0x6f 720x576@60 */
-       { 0x37,0x5a, 10}, /* 0x70 320x200@60 (fake, not actually used) */
-       { 0x2b,0xc2, 35}  /* 0x71 768@576@60 */
+static const struct SiS_VCLKData SiSUSB_VCLKData[] = {
+       {0x1b, 0xe1, 25},       /* 0x00 */
+       {0x4e, 0xe4, 28},       /* 0x01 */
+       {0x57, 0xe4, 31},       /* 0x02 */
+       {0xc3, 0xc8, 36},       /* 0x03 */
+       {0x42, 0xe2, 40},       /* 0x04 */
+       {0xfe, 0xcd, 43},       /* 0x05 */
+       {0x5d, 0xc4, 44},       /* 0x06 */
+       {0x52, 0xe2, 49},       /* 0x07 */
+       {0x53, 0xe2, 50},       /* 0x08 */
+       {0x74, 0x67, 52},       /* 0x09 */
+       {0x6d, 0x66, 56},       /* 0x0a */
+       {0x5a, 0x64, 65},       /* 0x0b */
+       {0x46, 0x44, 67},       /* 0x0c */
+       {0xb1, 0x46, 68},       /* 0x0d */
+       {0xd3, 0x4a, 72},       /* 0x0e */
+       {0x29, 0x61, 75},       /* 0x0f */
+       {0x6e, 0x46, 76},       /* 0x10 */
+       {0x2b, 0x61, 78},       /* 0x11 */
+       {0x31, 0x42, 79},       /* 0x12 */
+       {0xab, 0x44, 83},       /* 0x13 */
+       {0x46, 0x25, 84},       /* 0x14 */
+       {0x78, 0x29, 86},       /* 0x15 */
+       {0x62, 0x44, 94},       /* 0x16 */
+       {0x2b, 0x41, 104},      /* 0x17 */
+       {0x3a, 0x23, 105},      /* 0x18 */
+       {0x70, 0x44, 108},      /* 0x19 */
+       {0x3c, 0x23, 109},      /* 0x1a */
+       {0x5e, 0x43, 113},      /* 0x1b */
+       {0xbc, 0x44, 116},      /* 0x1c */
+       {0xe0, 0x46, 132},      /* 0x1d */
+       {0x54, 0x42, 135},      /* 0x1e */
+       {0xea, 0x2a, 139},      /* 0x1f */
+       {0x41, 0x22, 157},      /* 0x20 */
+       {0x70, 0x24, 162},      /* 0x21 */
+       {0x30, 0x21, 175},      /* 0x22 */
+       {0x4e, 0x22, 189},      /* 0x23 */
+       {0xde, 0x26, 194},      /* 0x24 */
+       {0x62, 0x06, 202},      /* 0x25 */
+       {0x3f, 0x03, 229},      /* 0x26 */
+       {0xb8, 0x06, 234},      /* 0x27 */
+       {0x34, 0x02, 253},      /* 0x28 */
+       {0x58, 0x04, 255},      /* 0x29 */
+       {0x24, 0x01, 265},      /* 0x2a */
+       {0x9b, 0x02, 267},      /* 0x2b */
+       {0x70, 0x05, 270},      /* 0x2c */
+       {0x25, 0x01, 272},      /* 0x2d */
+       {0x9c, 0x02, 277},      /* 0x2e */
+       {0x27, 0x01, 286},      /* 0x2f */
+       {0x3c, 0x02, 291},      /* 0x30 */
+       {0xef, 0x0a, 292},      /* 0x31 */
+       {0xf6, 0x0a, 310},      /* 0x32 */
+       {0x95, 0x01, 315},      /* 0x33 */
+       {0xf0, 0x09, 324},      /* 0x34 */
+       {0xfe, 0x0a, 331},      /* 0x35 */
+       {0xf3, 0x09, 332},      /* 0x36 */
+       {0xea, 0x08, 340},      /* 0x37 */
+       {0xe8, 0x07, 376},      /* 0x38 */
+       {0xde, 0x06, 389},      /* 0x39 */
+       {0x52, 0x2a, 54},       /* 0x3a 301 TV */
+       {0x52, 0x6a, 27},       /* 0x3b 301 TV */
+       {0x62, 0x24, 70},       /* 0x3c 301 TV */
+       {0x62, 0x64, 70},       /* 0x3d 301 TV */
+       {0xa8, 0x4c, 30},       /* 0x3e 301 TV */
+       {0x20, 0x26, 33},       /* 0x3f 301 TV */
+       {0x31, 0xc2, 39},       /* 0x40 */
+       {0x60, 0x36, 30},       /* 0x41 Chrontel */
+       {0x40, 0x4a, 28},       /* 0x42 Chrontel */
+       {0x9f, 0x46, 44},       /* 0x43 Chrontel */
+       {0x97, 0x2c, 26},       /* 0x44 */
+       {0x44, 0xe4, 25},       /* 0x45 Chrontel */
+       {0x7e, 0x32, 47},       /* 0x46 Chrontel */
+       {0x8a, 0x24, 31},       /* 0x47 Chrontel */
+       {0x97, 0x2c, 26},       /* 0x48 Chrontel */
+       {0xce, 0x3c, 39},       /* 0x49 */
+       {0x52, 0x4a, 36},       /* 0x4a Chrontel */
+       {0x34, 0x61, 95},       /* 0x4b */
+       {0x78, 0x27, 108},      /* 0x4c - was 102 */
+       {0x66, 0x43, 123},      /* 0x4d Modes 0x26-0x28 (1400x1050) */
+       {0x41, 0x4e, 21},       /* 0x4e */
+       {0xa1, 0x4a, 29},       /* 0x4f Chrontel */
+       {0x19, 0x42, 42},       /* 0x50 */
+       {0x54, 0x46, 58},       /* 0x51 Chrontel */
+       {0x25, 0x42, 61},       /* 0x52 */
+       {0x44, 0x44, 66},       /* 0x53 Chrontel */
+       {0x3a, 0x62, 70},       /* 0x54 Chrontel */
+       {0x62, 0xc6, 34},       /* 0x55 848x480-60 */
+       {0x6a, 0xc6, 37},       /* 0x56 848x480-75 - TEMP */
+       {0xbf, 0xc8, 35},       /* 0x57 856x480-38i,60 */
+       {0x30, 0x23, 88},       /* 0x58 1360x768-62 (is 60Hz!) */
+       {0x52, 0x07, 149},      /* 0x59 1280x960-85 */
+       {0x56, 0x07, 156},      /* 0x5a 1400x1050-75 */
+       {0x70, 0x29, 81},       /* 0x5b 1280x768 LCD */
+       {0x45, 0x25, 83},       /* 0x5c 1280x800  */
+       {0x70, 0x0a, 147},      /* 0x5d 1680x1050 */
+       {0x70, 0x24, 162},      /* 0x5e 1600x1200 */
+       {0x5a, 0x64, 65},       /* 0x5f 1280x720 - temp */
+       {0x63, 0x46, 68},       /* 0x60 1280x768_2 */
+       {0x31, 0x42, 79},       /* 0x61 1280x768_3 - temp */
+       {0, 0, 0},              /* 0x62 - custom (will be filled out at run-time) */
+       {0x5a, 0x64, 65},       /* 0x63 1280x720 (LCD LVDS) */
+       {0x70, 0x28, 90},       /* 0x64 1152x864@60 */
+       {0x41, 0xc4, 32},       /* 0x65 848x480@60 */
+       {0x5c, 0xc6, 32},       /* 0x66 856x480@60 */
+       {0x76, 0xe7, 27},       /* 0x67 720x480@60 */
+       {0x5f, 0xc6, 33},       /* 0x68 720/768x576@60 */
+       {0x52, 0x27, 75},       /* 0x69 1920x1080i 60Hz interlaced */
+       {0x7c, 0x6b, 38},       /* 0x6a 960x540@60 */
+       {0xe3, 0x56, 41},       /* 0x6b 960x600@60 */
+       {0x45, 0x25, 83},       /* 0x6c 1280x800 */
+       {0x70, 0x28, 90},       /* 0x6d 1152x864@60 */
+       {0x15, 0xe1, 20},       /* 0x6e 640x400@60 (fake, not actually used) */
+       {0x5f, 0xc6, 33},       /* 0x6f 720x576@60 */
+       {0x37, 0x5a, 10},       /* 0x70 320x200@60 (fake, not actually used) */
+       {0x2b, 0xc2, 35}        /* 0x71 768@576@60 */
 };
 
-int            SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
-int            SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo);
+int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
+int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo);
 
-extern int     sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data);
-extern int     sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data);
-extern int     sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port,
-                                       u8 index, u8 data);
-extern int     sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port,
-                                       u8 index, u8 *data);
-extern int     sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port,
-                                       u8 idx, u8 myand, u8 myor);
-extern int     sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port,
-                                       u8 index, u8 myor);
-extern int     sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port,
-                                       u8 idx, u8 myand);
+extern int sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data);
+extern int sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 * data);
+extern int sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port,
+                           u8 index, u8 data);
+extern int sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port,
+                           u8 index, u8 * data);
+extern int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port,
+                                u8 idx, u8 myand, u8 myor);
+extern int sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port,
+                             u8 index, u8 myor);
+extern int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port,
+                              u8 idx, u8 myand);
 
 void sisusb_delete(struct kref *kref);
 int sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data);
-int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data);
+int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 * data);
 int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
-                      u32 dest, int length, size_t *bytes_written);
+                      u32 dest, int length, size_t * bytes_written);
 int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init);
 int sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot,
-                        u8 *arg, int cmapsz, int ch512, int dorecalc,
+                        u8 * arg, int cmapsz, int ch512, int dorecalc,
                         struct vc_data *c, int fh, int uplock);
 void sisusb_set_cursor(struct sisusb_usb_data *sisusb, unsigned int location);
 int sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last);
@@ -839,4 +839,3 @@ void sisusb_console_exit(struct sisusb_usb_data *sisusb);
 void sisusb_init_concode(void);
 
 #endif
-
index f325ecb29a61f9e9722063db9601ccb89df4cba2..1c4240e802c1984cb6ab0d0fa6456484c09fc799 100644 (file)
@@ -44,7 +44,7 @@
  * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * Author:     Thomas Winischhofer <thomas@winischhofer.net>
+ * Author:     Thomas Winischhofer <thomas@winischhofer.net>
  *
  */
 
 #define _SISUSB_STRUCT_H_
 
 struct SiS_St {
-       unsigned char   St_ModeID;
-       unsigned short  St_ModeFlag;
-       unsigned char   St_StTableIndex;
-       unsigned char   St_CRT2CRTC;
-       unsigned char   St_ResInfo;
-       unsigned char   VB_StTVFlickerIndex;
-       unsigned char   VB_StTVEdgeIndex;
-       unsigned char   VB_StTVYFilterIndex;
-       unsigned char   St_PDC;
+       unsigned char St_ModeID;
+       unsigned short St_ModeFlag;
+       unsigned char St_StTableIndex;
+       unsigned char St_CRT2CRTC;
+       unsigned char St_ResInfo;
+       unsigned char VB_StTVFlickerIndex;
+       unsigned char VB_StTVEdgeIndex;
+       unsigned char VB_StTVYFilterIndex;
+       unsigned char St_PDC;
 };
 
-struct SiS_StandTable
-{
-       unsigned char   CRT_COLS;
-       unsigned char   ROWS;
-       unsigned char   CHAR_HEIGHT;
-       unsigned short  CRT_LEN;
-       unsigned char   SR[4];
-       unsigned char   MISC;
-       unsigned char   CRTC[0x19];
-       unsigned char   ATTR[0x14];
-       unsigned char   GRC[9];
+struct SiS_StandTable {
+       unsigned char CRT_COLS;
+       unsigned char ROWS;
+       unsigned char CHAR_HEIGHT;
+       unsigned short CRT_LEN;
+       unsigned char SR[4];
+       unsigned char MISC;
+       unsigned char CRTC[0x19];
+       unsigned char ATTR[0x14];
+       unsigned char GRC[9];
 };
 
 struct SiS_StResInfo_S {
-       unsigned short  HTotal;
-       unsigned short  VTotal;
+       unsigned short HTotal;
+       unsigned short VTotal;
 };
 
-struct SiS_Ext
-{
-       unsigned char   Ext_ModeID;
-       unsigned short  Ext_ModeFlag;
-       unsigned short  Ext_VESAID;
-       unsigned char   Ext_RESINFO;
-       unsigned char   VB_ExtTVFlickerIndex;
-       unsigned char   VB_ExtTVEdgeIndex;
-       unsigned char   VB_ExtTVYFilterIndex;
-       unsigned char   VB_ExtTVYFilterIndexROM661;
-       unsigned char   REFindex;
-       char            ROMMODEIDX661;
+struct SiS_Ext {
+       unsigned char Ext_ModeID;
+       unsigned short Ext_ModeFlag;
+       unsigned short Ext_VESAID;
+       unsigned char Ext_RESINFO;
+       unsigned char VB_ExtTVFlickerIndex;
+       unsigned char VB_ExtTVEdgeIndex;
+       unsigned char VB_ExtTVYFilterIndex;
+       unsigned char VB_ExtTVYFilterIndexROM661;
+       unsigned char REFindex;
+       char ROMMODEIDX661;
 };
 
-struct SiS_Ext2
-{
-       unsigned short  Ext_InfoFlag;
-       unsigned char   Ext_CRT1CRTC;
-       unsigned char   Ext_CRTVCLK;
-       unsigned char   Ext_CRT2CRTC;
-       unsigned char   Ext_CRT2CRTC_NS;
-       unsigned char   ModeID;
-       unsigned short  XRes;
-       unsigned short  YRes;
-       unsigned char   Ext_PDC;
-       unsigned char   Ext_FakeCRT2CRTC;
-       unsigned char   Ext_FakeCRT2Clk;
+struct SiS_Ext2 {
+       unsigned short Ext_InfoFlag;
+       unsigned char Ext_CRT1CRTC;
+       unsigned char Ext_CRTVCLK;
+       unsigned char Ext_CRT2CRTC;
+       unsigned char Ext_CRT2CRTC_NS;
+       unsigned char ModeID;
+       unsigned short XRes;
+       unsigned short YRes;
+       unsigned char Ext_PDC;
+       unsigned char Ext_FakeCRT2CRTC;
+       unsigned char Ext_FakeCRT2Clk;
 };
 
-struct SiS_CRT1Table
-{
-       unsigned char   CR[17];
+struct SiS_CRT1Table {
+       unsigned char CR[17];
 };
 
-struct SiS_VCLKData
-{
-       unsigned char   SR2B,SR2C;
-       unsigned short  CLOCK;
+struct SiS_VCLKData {
+       unsigned char SR2B, SR2C;
+       unsigned short CLOCK;
 };
 
-struct SiS_ModeResInfo
-{
-       unsigned short  HTotal;
-       unsigned short  VTotal;
-       unsigned char   XChar;
-       unsigned char   YChar;
+struct SiS_ModeResInfo {
+       unsigned short HTotal;
+       unsigned short VTotal;
+       unsigned char XChar;
+       unsigned char YChar;
 };
 
-struct SiS_Private
-{
+struct SiS_Private {
        void *sisusb;
 
        unsigned long IOAddress;
@@ -151,19 +144,18 @@ struct SiS_Private
        unsigned long SiS_P3da;
        unsigned long SiS_Part1Port;
 
-       unsigned char   SiS_MyCR63;
-       unsigned short  SiS_CRT1Mode;
-       unsigned short  SiS_ModeType;
-       unsigned short  SiS_SetFlag;
-
-       const struct SiS_StandTable     *SiS_StandTable;
-       const struct SiS_St             *SiS_SModeIDTable;
-       const struct SiS_Ext            *SiS_EModeIDTable;
-       const struct SiS_Ext2           *SiS_RefIndex;
-       const struct SiS_CRT1Table      *SiS_CRT1Table;
-       const struct SiS_VCLKData       *SiS_VCLKData;
-       const struct SiS_ModeResInfo    *SiS_ModeResInfo;
+       unsigned char SiS_MyCR63;
+       unsigned short SiS_CRT1Mode;
+       unsigned short SiS_ModeType;
+       unsigned short SiS_SetFlag;
+
+       const struct SiS_StandTable *SiS_StandTable;
+       const struct SiS_St *SiS_SModeIDTable;
+       const struct SiS_Ext *SiS_EModeIDTable;
+       const struct SiS_Ext2 *SiS_RefIndex;
+       const struct SiS_CRT1Table *SiS_CRT1Table;
+       const struct SiS_VCLKData *SiS_VCLKData;
+       const struct SiS_ModeResInfo *SiS_ModeResInfo;
 };
 
 #endif
-
index c03dfd7a9d36f8fe460869158d78f2a599e1f28e..f06e4e2b49d3bdac755d8136077dcae352bcb19d 100644 (file)
@@ -172,6 +172,10 @@ static inline struct mon_bin_hdr *MON_OFF2HDR(const struct mon_reader_bin *rp,
 
 #define MON_RING_EMPTY(rp)     ((rp)->b_cnt == 0)
 
+static unsigned char xfer_to_pipe[4] = {
+       PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT
+};
+
 static struct class *mon_bin_class;
 static dev_t mon_bin_dev0;
 static struct cdev mon_bin_cdev;
@@ -354,13 +358,9 @@ static inline char mon_bin_get_setup(unsigned char *setupb,
     const struct urb *urb, char ev_type)
 {
 
-       if (!usb_pipecontrol(urb->pipe) || ev_type != 'S')
+       if (!usb_endpoint_xfer_control(&urb->ep->desc) || ev_type != 'S')
                return '-';
 
-       if (urb->dev->bus->uses_dma &&
-           (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
-               return mon_dmapeek(setupb, urb->setup_dma, SETUP_LEN);
-       }
        if (urb->setup_packet == NULL)
                return 'Z';
 
@@ -386,13 +386,15 @@ static char mon_bin_get_data(const struct mon_reader_bin *rp,
 }
 
 static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
-    char ev_type)
+    char ev_type, int status)
 {
+       const struct usb_endpoint_descriptor *epd = &urb->ep->desc;
        unsigned long flags;
        struct timeval ts;
        unsigned int urb_length;
        unsigned int offset;
        unsigned int length;
+       unsigned char dir;
        struct mon_bin_hdr *ep;
        char data_tag = 0;
 
@@ -410,16 +412,19 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
        if (length >= rp->b_size/5)
                length = rp->b_size/5;
 
-       if (usb_pipein(urb->pipe)) {
+       if (usb_urb_dir_in(urb)) {
                if (ev_type == 'S') {
                        length = 0;
                        data_tag = '<';
                }
+               /* Cannot rely on endpoint number in case of control ep.0 */
+               dir = USB_DIR_IN;
        } else {
                if (ev_type == 'C') {
                        length = 0;
                        data_tag = '>';
                }
+               dir = 0;
        }
 
        if (rp->mmap_active)
@@ -440,15 +445,14 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
         */
        memset(ep, 0, PKT_SIZE);
        ep->type = ev_type;
-       ep->xfer_type = usb_pipetype(urb->pipe);
-       /* We use the fact that usb_pipein() returns 0x80 */
-       ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe);
-       ep->devnum = usb_pipedevice(urb->pipe);
+       ep->xfer_type = xfer_to_pipe[usb_endpoint_type(epd)];
+       ep->epnum = dir | usb_endpoint_num(epd);
+       ep->devnum = urb->dev->devnum;
        ep->busnum = urb->dev->bus->busnum;
        ep->id = (unsigned long) urb;
        ep->ts_sec = ts.tv_sec;
        ep->ts_usec = ts.tv_usec;
-       ep->status = urb->status;
+       ep->status = status;
        ep->len_urb = urb_length;
        ep->len_cap = length;
 
@@ -471,13 +475,13 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
 static void mon_bin_submit(void *data, struct urb *urb)
 {
        struct mon_reader_bin *rp = data;
-       mon_bin_event(rp, urb, 'S');
+       mon_bin_event(rp, urb, 'S', -EINPROGRESS);
 }
 
-static void mon_bin_complete(void *data, struct urb *urb)
+static void mon_bin_complete(void *data, struct urb *urb, int status)
 {
        struct mon_reader_bin *rp = data;
-       mon_bin_event(rp, urb, 'C');
+       mon_bin_event(rp, urb, 'C', status);
 }
 
 static void mon_bin_error(void *data, struct urb *urb, int error)
@@ -500,10 +504,10 @@ static void mon_bin_error(void *data, struct urb *urb, int error)
 
        memset(ep, 0, PKT_SIZE);
        ep->type = 'E';
-       ep->xfer_type = usb_pipetype(urb->pipe);
-       /* We use the fact that usb_pipein() returns 0x80 */
-       ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe);
-       ep->devnum = usb_pipedevice(urb->pipe);
+       ep->xfer_type = xfer_to_pipe[usb_endpoint_type(&urb->ep->desc)];
+       ep->epnum = usb_urb_dir_in(urb) ? USB_DIR_IN : 0;
+       ep->epnum |= usb_endpoint_num(&urb->ep->desc);
+       ep->devnum = urb->dev->devnum;
        ep->busnum = urb->dev->bus->busnum;
        ep->id = (unsigned long) urb;
        ep->status = error;
index ce61d8b0fd866b4ea91346296d828667d30a9468..b371ffd39d369b8c34615bc250587aaef8d19790 100644 (file)
@@ -129,7 +129,8 @@ static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int error)
 
 /*
  */
-static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb)
+static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb,
+               int status)
 {
        unsigned long flags;
        struct list_head *pos;
@@ -139,28 +140,18 @@ static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb)
        mbus->cnt_events++;
        list_for_each (pos, &mbus->r_list) {
                r = list_entry(pos, struct mon_reader, r_link);
-               r->rnf_complete(r->r_data, urb);
+               r->rnf_complete(r->r_data, urb, status);
        }
        spin_unlock_irqrestore(&mbus->lock, flags);
 }
 
-static void mon_complete(struct usb_bus *ubus, struct urb *urb)
+static void mon_complete(struct usb_bus *ubus, struct urb *urb, int status)
 {
        struct mon_bus *mbus;
 
-       mbus = ubus->mon_bus;
-       if (mbus == NULL) {
-               /*
-                * This should not happen.
-                * At this point we do not even know the bus number...
-                */
-               printk(KERN_ERR TAG ": Null mon bus in URB, pipe 0x%x\n",
-                   urb->pipe);
-               return;
-       }
-
-       mon_bus_complete(mbus, urb);
-       mon_bus_complete(&mon_bus0, urb);
+       if ((mbus = ubus->mon_bus) != NULL)
+               mon_bus_complete(mbus, urb, status);
+       mon_bus_complete(&mon_bus0, urb, status);
 }
 
 /* int (*unlink_urb) (struct urb *urb, int status); */
@@ -170,7 +161,7 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb)
  */
 static void mon_stop(struct mon_bus *mbus)
 {
-       struct usb_bus *ubus = mbus->u_bus;
+       struct usb_bus *ubus;
        struct list_head *p;
 
        if (mbus == &mon_bus0) {
index 8f27a9e1c36ba7c0b38a5ca4b9acb5ced9ab7da3..ebb04ac4857b2019d234cedb37631a877a63dbc0 100644 (file)
@@ -50,10 +50,13 @@ struct mon_iso_desc {
 struct mon_event_text {
        struct list_head e_link;
        int type;               /* submit, complete, etc. */
-       unsigned int pipe;      /* Pipe */
        unsigned long id;       /* From pointer, most of the time */
        unsigned int tstamp;
        int busnum;
+       char devnum;
+       char epnum;
+       char is_in;
+       char xfertype;
        int length;             /* Depends on type: xfer length or act length */
        int status;
        int interval;
@@ -121,13 +124,9 @@ static inline char mon_text_get_setup(struct mon_event_text *ep,
     struct urb *urb, char ev_type, struct mon_bus *mbus)
 {
 
-       if (!usb_pipecontrol(urb->pipe) || ev_type != 'S')
+       if (ep->xfertype != USB_ENDPOINT_XFER_CONTROL || ev_type != 'S')
                return '-';
 
-       if (urb->dev->bus->uses_dma &&
-           (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
-               return mon_dmapeek(ep->setup, urb->setup_dma, SETUP_MAX);
-       }
        if (urb->setup_packet == NULL)
                return 'Z';     /* '0' would be not as pretty. */
 
@@ -138,14 +137,12 @@ static inline char mon_text_get_setup(struct mon_event_text *ep,
 static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb,
     int len, char ev_type, struct mon_bus *mbus)
 {
-       int pipe = urb->pipe;
-
        if (len <= 0)
                return 'L';
        if (len >= DATA_MAX)
                len = DATA_MAX;
 
-       if (usb_pipein(pipe)) {
+       if (ep->is_in) {
                if (ev_type != 'C')
                        return '<';
        } else {
@@ -186,7 +183,7 @@ static inline unsigned int mon_get_timestamp(void)
 }
 
 static void mon_text_event(struct mon_reader_text *rp, struct urb *urb,
-    char ev_type)
+    char ev_type, int status)
 {
        struct mon_event_text *ep;
        unsigned int stamp;
@@ -203,24 +200,28 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb,
        }
 
        ep->type = ev_type;
-       ep->pipe = urb->pipe;
        ep->id = (unsigned long) urb;
        ep->busnum = urb->dev->bus->busnum;
+       ep->devnum = urb->dev->devnum;
+       ep->epnum = usb_endpoint_num(&urb->ep->desc);
+       ep->xfertype = usb_endpoint_type(&urb->ep->desc);
+       ep->is_in = usb_urb_dir_in(urb);
        ep->tstamp = stamp;
        ep->length = (ev_type == 'S') ?
            urb->transfer_buffer_length : urb->actual_length;
        /* Collecting status makes debugging sense for submits, too */
-       ep->status = urb->status;
+       ep->status = status;
 
-       if (usb_pipeint(urb->pipe)) {
+       if (ep->xfertype == USB_ENDPOINT_XFER_INT) {
                ep->interval = urb->interval;
-       } else if (usb_pipeisoc(urb->pipe)) {
+       } else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) {
                ep->interval = urb->interval;
                ep->start_frame = urb->start_frame;
                ep->error_count = urb->error_count;
        }
        ep->numdesc = urb->number_of_packets;
-       if (usb_pipeisoc(urb->pipe) && urb->number_of_packets > 0) {
+       if (ep->xfertype == USB_ENDPOINT_XFER_ISOC &&
+                       urb->number_of_packets > 0) {
                if ((ndesc = urb->number_of_packets) > ISODESC_MAX)
                        ndesc = ISODESC_MAX;
                fp = urb->iso_frame_desc;
@@ -247,13 +248,13 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb,
 static void mon_text_submit(void *data, struct urb *urb)
 {
        struct mon_reader_text *rp = data;
-       mon_text_event(rp, urb, 'S');
+       mon_text_event(rp, urb, 'S', -EINPROGRESS);
 }
 
-static void mon_text_complete(void *data, struct urb *urb)
+static void mon_text_complete(void *data, struct urb *urb, int status)
 {
        struct mon_reader_text *rp = data;
-       mon_text_event(rp, urb, 'C');
+       mon_text_event(rp, urb, 'C', status);
 }
 
 static void mon_text_error(void *data, struct urb *urb, int error)
@@ -268,9 +269,12 @@ static void mon_text_error(void *data, struct urb *urb, int error)
        }
 
        ep->type = 'E';
-       ep->pipe = urb->pipe;
        ep->id = (unsigned long) urb;
        ep->busnum = 0;
+       ep->devnum = urb->dev->devnum;
+       ep->epnum = usb_endpoint_num(&urb->ep->desc);
+       ep->xfertype = usb_endpoint_type(&urb->ep->desc);
+       ep->is_in = usb_urb_dir_in(urb);
        ep->tstamp = 0;
        ep->length = 0;
        ep->status = error;
@@ -413,10 +417,10 @@ static ssize_t mon_text_read_u(struct file *file, char __user *buf,
        mon_text_read_head_u(rp, &ptr, ep);
        if (ep->type == 'E') {
                mon_text_read_statset(rp, &ptr, ep);
-       } else if (usb_pipeisoc(ep->pipe)) {
+       } else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) {
                mon_text_read_isostat(rp, &ptr, ep);
                mon_text_read_isodesc(rp, &ptr, ep);
-       } else if (usb_pipeint(ep->pipe)) {
+       } else if (ep->xfertype == USB_ENDPOINT_XFER_INT) {
                mon_text_read_intstat(rp, &ptr, ep);
        } else {
                mon_text_read_statset(rp, &ptr, ep);
@@ -468,18 +472,17 @@ static void mon_text_read_head_t(struct mon_reader_text *rp,
 {
        char udir, utype;
 
-       udir = usb_pipein(ep->pipe) ? 'i' : 'o';
-       switch (usb_pipetype(ep->pipe)) {
-       case PIPE_ISOCHRONOUS:  utype = 'Z'; break;
-       case PIPE_INTERRUPT:    utype = 'I'; break;
-       case PIPE_CONTROL:      utype = 'C'; break;
+       udir = (ep->is_in ? 'i' : 'o');
+       switch (ep->xfertype) {
+       case USB_ENDPOINT_XFER_ISOC:    utype = 'Z'; break;
+       case USB_ENDPOINT_XFER_INT:     utype = 'I'; break;
+       case USB_ENDPOINT_XFER_CONTROL: utype = 'C'; break;
        default: /* PIPE_BULK */  utype = 'B';
        }
        p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
            "%lx %u %c %c%c:%03u:%02u",
            ep->id, ep->tstamp, ep->type,
-           utype, udir,
-           usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe));
+           utype, udir, ep->devnum, ep->epnum);
 }
 
 static void mon_text_read_head_u(struct mon_reader_text *rp,
@@ -487,18 +490,17 @@ static void mon_text_read_head_u(struct mon_reader_text *rp,
 {
        char udir, utype;
 
-       udir = usb_pipein(ep->pipe) ? 'i' : 'o';
-       switch (usb_pipetype(ep->pipe)) {
-       case PIPE_ISOCHRONOUS:  utype = 'Z'; break;
-       case PIPE_INTERRUPT:    utype = 'I'; break;
-       case PIPE_CONTROL:      utype = 'C'; break;
+       udir = (ep->is_in ? 'i' : 'o');
+       switch (ep->xfertype) {
+       case USB_ENDPOINT_XFER_ISOC:    utype = 'Z'; break;
+       case USB_ENDPOINT_XFER_INT:     utype = 'I'; break;
+       case USB_ENDPOINT_XFER_CONTROL: utype = 'C'; break;
        default: /* PIPE_BULK */  utype = 'B';
        }
        p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
            "%lx %u %c %c%c:%d:%03u:%u",
            ep->id, ep->tstamp, ep->type,
-           utype, udir,
-           ep->busnum, usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe));
+           utype, udir, ep->busnum, ep->devnum, ep->epnum);
 }
 
 static void mon_text_read_statset(struct mon_reader_text *rp,
index f68ad6d99ad7563581919fb024c37a4c5259a6e7..f5d84ff8c101b2c783a5b3cca9307ffb600ed21c 100644 (file)
@@ -46,7 +46,7 @@ struct mon_reader {
 
        void (*rnf_submit)(void *data, struct urb *urb);
        void (*rnf_error)(void *data, struct urb *urb, int error);
-       void (*rnf_complete)(void *data, struct urb *urb);
+       void (*rnf_complete)(void *data, struct urb *urb, int status);
 };
 
 void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r);
index 43d6db696f905cc7361cee823ccb60d2ed99d4d6..99fefed77919de2dbd28af6de48faa1080181924 100644 (file)
@@ -92,6 +92,16 @@ config USB_SERIAL_BELKIN
          To compile this driver as a module, choose M here: the
          module will be called belkin_sa.
 
+config USB_SERIAL_CH341
+       tristate "USB Winchiphead CH341 Single Port Serial Driver"
+       depends on USB_SERIAL
+       help
+         Say Y here if you want to use a Winchiphead CH341 single port
+         USB to serial adapter.
+
+         To compile this driver as a module, choose M here: the
+         module will be called ch341.
+
 config USB_SERIAL_WHITEHEAT
        tristate "USB ConnectTech WhiteHEAT Serial Driver"
        depends on USB_SERIAL
index 07a976eca6b7eed0e2a81c6f6724c7db2c9a5544..d6fb384e52b24ab1dca674e1ceaa9bfd515595e0 100644 (file)
@@ -15,6 +15,7 @@ obj-$(CONFIG_USB_SERIAL_AIRCABLE)             += aircable.o
 obj-$(CONFIG_USB_SERIAL_AIRPRIME)              += airprime.o
 obj-$(CONFIG_USB_SERIAL_ARK3116)               += ark3116.o
 obj-$(CONFIG_USB_SERIAL_BELKIN)                        += belkin_sa.o
+obj-$(CONFIG_USB_SERIAL_CH341)                 += ch341.o
 obj-$(CONFIG_USB_SERIAL_CP2101)                        += cp2101.o
 obj-$(CONFIG_USB_SERIAL_CYBERJACK)             += cyberjack.o
 obj-$(CONFIG_USB_SERIAL_CYPRESS_M8)            += cypress_m8.o
index c9fd486c1c7d7a030b9d5b039caabe2a9f3f5c56..2a8e537cb046eb77a7bcc77a60679d7d716a96cf 100644 (file)
@@ -172,11 +172,6 @@ static void ark3116_set_termios(struct usb_serial_port *port,
 
        dbg("%s - port %d", __FUNCTION__, port->number);
 
-       if (!port->tty || !port->tty->termios) {
-               dbg("%s - no tty structures", __FUNCTION__);
-               return;
-       }
-
        spin_lock_irqsave(&priv->lock, flags);
        if (!priv->termios_initialized) {
                *(port->tty->termios) = tty_std_termios;
index a47a24f8820dce01ee6d949f3167fbeb15dd3b61..0b14aea8ebd52891015e32963784a048e7472ca1 100644 (file)
@@ -36,6 +36,16 @@ static int usb_serial_device_match (struct device *dev, struct device_driver *dr
        return 0;
 }
 
+static ssize_t show_port_number(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct usb_serial_port *port = to_usb_serial_port(dev);
+
+       return sprintf(buf, "%d\n", port->number - port->serial->minor);
+}
+
+static DEVICE_ATTR(port_number, S_IRUGO, show_port_number, NULL);
+
 static int usb_serial_device_probe (struct device *dev)
 {
        struct usb_serial_driver *driver;
@@ -62,6 +72,10 @@ static int usb_serial_device_probe (struct device *dev)
                        goto exit;
        }
 
+       retval = device_create_file(dev, &dev_attr_port_number);
+       if (retval)
+               goto exit;
+
        minor = port->number;
        tty_register_device (usb_serial_tty_driver, minor, dev);
        dev_info(&port->serial->dev->dev, 
@@ -84,6 +98,8 @@ static int usb_serial_device_remove (struct device *dev)
                return -ENODEV;
        }
 
+       device_remove_file(&port->dev, &dev_attr_port_number);
+
        driver = port->serial->type;
        if (driver->port_remove) {
                if (!try_module_get(driver->driver.owner)) {
diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c
new file mode 100644 (file)
index 0000000..6b252ce
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ * Copyright 2007, Frank A Kingswood <frank@kingswood-consulting.co.uk>
+ *
+ * ch341.c implements a serial port driver for the Winchiphead CH341.
+ *
+ * The CH341 device can be used to implement an RS232 asynchronous
+ * serial port, an IEEE-1284 parallel printer port or a memory-like
+ * interface. In all cases the CH341 supports an I2C interface as well.
+ * This driver only supports the asynchronous serial interface.
+ *
+ * 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/init.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+#include <linux/serial.h>
+
+#define DEFAULT_BAUD_RATE 2400
+#define DEFAULT_TIMEOUT   1000
+
+static int debug;
+
+static struct usb_device_id id_table [] = {
+       { USB_DEVICE(0x4348, 0x5523) },
+       { },
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+struct ch341_private {
+       unsigned baud_rate;
+       u8 dtr;
+       u8 rts;
+};
+
+static int ch341_control_out(struct usb_device *dev, u8 request,
+                            u16 value, u16 index)
+{
+       int r;
+       dbg("ch341_control_out(%02x,%02x,%04x,%04x)", USB_DIR_OUT|0x40,
+               (int)request, (int)value, (int)index);
+
+       r = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request,
+                           USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+                           value, index, NULL, 0, DEFAULT_TIMEOUT);
+
+       return r;
+}
+
+static int ch341_control_in(struct usb_device *dev,
+                           u8 request, u16 value, u16 index,
+                           char *buf, unsigned bufsize)
+{
+       int r;
+       dbg("ch341_control_in(%02x,%02x,%04x,%04x,%p,%u)", USB_DIR_IN|0x40,
+               (int)request, (int)value, (int)index, buf, (int)bufsize);
+
+       r = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request,
+                           USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+                           value, index, buf, bufsize, DEFAULT_TIMEOUT);
+       return r;
+}
+
+static int ch341_set_baudrate(struct usb_device *dev,
+                             struct ch341_private *priv)
+{
+       short a, b;
+       int r;
+
+       dbg("ch341_set_baudrate(%d)", priv->baud_rate);
+       switch (priv->baud_rate) {
+       case 2400:
+               a = 0xd901;
+               b = 0x0038;
+               break;
+       case 4800:
+               a = 0x6402;
+               b = 0x001f;
+               break;
+       case 9600:
+               a = 0xb202;
+               b = 0x0013;
+               break;
+       case 19200:
+               a = 0xd902;
+               b = 0x000d;
+               break;
+       case 38400:
+               a = 0x6403;
+               b = 0x000a;
+               break;
+       case 115200:
+               a = 0xcc03;
+               b = 0x0008;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       r = ch341_control_out(dev, 0x9a, 0x1312, a);
+       if (!r)
+               r = ch341_control_out(dev, 0x9a, 0x0f2c, b);
+
+       return r;
+}
+
+static int ch341_set_handshake(struct usb_device *dev,
+                              struct ch341_private *priv)
+{
+       dbg("ch341_set_handshake(%d,%d)", priv->dtr, priv->rts);
+       return ch341_control_out(dev, 0xa4,
+               ~((priv->dtr?1<<5:0)|(priv->rts?1<<6:0)), 0);
+}
+
+static int ch341_get_status(struct usb_device *dev)
+{
+       char *buffer;
+       int r;
+       const unsigned size = 8;
+
+       dbg("ch341_get_status()");
+
+       buffer = kmalloc(size, GFP_KERNEL);
+       if (!buffer)
+               return -ENOMEM;
+
+       r = ch341_control_in(dev, 0x95, 0x0706, 0, buffer, size);
+       if ( r < 0)
+               goto out;
+
+       /* Not having the datasheet for the CH341, we ignore the bytes returned
+        * from the device. Return error if the device did not respond in time.
+        */
+       r = 0;
+
+out:   kfree(buffer);
+       return r;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int ch341_configure(struct usb_device *dev, struct ch341_private *priv)
+{
+       char *buffer;
+       int r;
+       const unsigned size = 8;
+
+       dbg("ch341_configure()");
+
+       buffer = kmalloc(size, GFP_KERNEL);
+       if (!buffer)
+               return -ENOMEM;
+
+       /* expect two bytes 0x27 0x00 */
+       r = ch341_control_in(dev, 0x5f, 0, 0, buffer, size);
+       if (r < 0)
+               goto out;
+
+       r = ch341_control_out(dev, 0xa1, 0, 0);
+       if (r < 0)
+               goto out;
+
+       r = ch341_set_baudrate(dev, priv);
+       if (r < 0)
+               goto out;
+
+       /* expect two bytes 0x56 0x00 */
+       r = ch341_control_in(dev, 0x95, 0x2518, 0, buffer, size);
+       if (r < 0)
+               goto out;
+
+       r = ch341_control_out(dev, 0x9a, 0x2518, 0x0050);
+       if (r < 0)
+               goto out;
+
+       /* expect 0xff 0xee */
+       r = ch341_get_status(dev);
+       if (r < 0)
+               goto out;
+
+       r = ch341_control_out(dev, 0xa1, 0x501f, 0xd90a);
+       if (r < 0)
+               goto out;
+
+       r = ch341_set_baudrate(dev, priv);
+       if (r < 0)
+               goto out;
+
+       r = ch341_set_handshake(dev, priv);
+       if (r < 0)
+               goto out;
+
+       /* expect 0x9f 0xee */
+       r = ch341_get_status(dev);
+
+out:   kfree(buffer);
+       return r;
+}
+
+/* allocate private data */
+static int ch341_attach(struct usb_serial *serial)
+{
+       struct ch341_private *priv;
+       int r;
+
+       dbg("ch341_attach()");
+
+       /* private data */
+       priv = kzalloc(sizeof(struct ch341_private), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->baud_rate = DEFAULT_BAUD_RATE;
+       priv->dtr = 1;
+       priv->rts = 1;
+
+       r = ch341_configure(serial->dev, priv);
+       if (r < 0)
+               goto error;
+
+       usb_set_serial_port_data(serial->port[0], priv);
+       return 0;
+
+error: kfree(priv);
+       return r;
+}
+
+/* open this device, set default parameters */
+static int ch341_open(struct usb_serial_port *port, struct file *filp)
+{
+       struct usb_serial *serial = port->serial;
+       struct ch341_private *priv = usb_get_serial_port_data(serial->port[0]);
+       int r;
+
+       dbg("ch341_open()");
+
+       priv->baud_rate = DEFAULT_BAUD_RATE;
+       priv->dtr = 1;
+       priv->rts = 1;
+
+       r = ch341_configure(serial->dev, priv);
+       if (r)
+               goto out;
+
+       r = ch341_set_handshake(serial->dev, priv);
+       if (r)
+               goto out;
+
+       r = ch341_set_baudrate(serial->dev, priv);
+       if (r)
+               goto out;
+
+       r = usb_serial_generic_open(port, filp);
+
+out:   return r;
+}
+
+/* Old_termios contains the original termios settings and
+ * tty->termios contains the new setting to be used.
+ */
+static void ch341_set_termios(struct usb_serial_port *port,
+                             struct ktermios *old_termios)
+{
+       struct ch341_private *priv = usb_get_serial_port_data(port);
+       struct tty_struct *tty = port->tty;
+       unsigned baud_rate;
+
+       dbg("ch341_set_termios()");
+
+       if (!tty || !tty->termios)
+               return;
+
+       baud_rate = tty_get_baud_rate(tty);
+
+       switch (baud_rate) {
+       case 2400:
+       case 4800:
+       case 9600:
+       case 19200:
+       case 38400:
+       case 115200:
+               priv->baud_rate = baud_rate;
+               break;
+       default:
+               dbg("Rate %d not supported, using %d",
+                       baud_rate, DEFAULT_BAUD_RATE);
+               priv->baud_rate = DEFAULT_BAUD_RATE;
+       }
+
+       ch341_set_baudrate(port->serial->dev, priv);
+
+       /* Unimplemented:
+        * (cflag & CSIZE) : data bits [5, 8]
+        * (cflag & PARENB) : parity {NONE, EVEN, ODD}
+        * (cflag & CSTOPB) : stop bits [1, 2]
+        */
+}
+
+static struct usb_driver ch341_driver = {
+       .name           = "ch341",
+       .probe          = usb_serial_probe,
+       .disconnect     = usb_serial_disconnect,
+       .id_table       = id_table,
+       .no_dynamic_id  = 1,
+};
+
+static struct usb_serial_driver ch341_device = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "ch341-uart",
+       },
+       .id_table         = id_table,
+       .usb_driver       = &ch341_driver,
+       .num_interrupt_in = NUM_DONT_CARE,
+       .num_bulk_in      = 1,
+       .num_bulk_out     = 1,
+       .num_ports        = 1,
+       .open             = ch341_open,
+       .set_termios      = ch341_set_termios,
+       .attach           = ch341_attach,
+};
+
+static int __init ch341_init(void)
+{
+       int retval;
+
+       retval = usb_serial_register(&ch341_device);
+       if (retval)
+               return retval;
+       retval = usb_register(&ch341_driver);
+       if (retval)
+               usb_serial_deregister(&ch341_device);
+       return retval;
+}
+
+static void __exit ch341_exit(void)
+{
+       usb_deregister(&ch341_driver);
+       usb_serial_deregister(&ch341_device);
+}
+
+module_init(ch341_init);
+module_exit(ch341_exit);
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+/* EOF ch341.c */
index 33f6ee50b8d34b5c0ca5fc83d368d8325d11e235..eb7df1835c11a620462ce61f03cf03dd9c0fb460 100644 (file)
@@ -53,6 +53,7 @@ static void cp2101_shutdown(struct usb_serial*);
 static int debug;
 
 static struct usb_device_id id_table [] = {
+       { USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */
        { USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */
        { USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */
        { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
@@ -521,7 +522,7 @@ static void cp2101_set_termios (struct usb_serial_port *port,
 
        dbg("%s - port %d", __FUNCTION__, port->number);
 
-       if ((!port->tty) || (!port->tty->termios)) {
+       if (!port->tty || !port->tty->termios) {
                dbg("%s - no tty structures", __FUNCTION__);
                return;
        }
index 2d045857b18124bb81f85d4471152d5b4ff45f46..e4c248c98e8480faa45fbd72600f8fc81cd7c4af 100644 (file)
@@ -1169,7 +1169,9 @@ static void remove_sysfs_attrs(struct usb_serial_port *port)
        /* XXX see create_sysfs_attrs */
        if (priv->chip_type != SIO) {
                device_remove_file(&port->dev, &dev_attr_event_char);
-               if (priv->chip_type == FT232BM || priv->chip_type == FT2232C) {
+               if (priv->chip_type == FT232BM ||
+                   priv->chip_type == FT2232C ||
+                   priv->chip_type == FT232RL) {
                        device_remove_file(&port->dev, &dev_attr_latency_timer);
                }
        }
@@ -2102,6 +2104,7 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file)
        case FT8U232AM:
        case FT232BM:
        case FT2232C:
+       case FT232RL:
                /* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same
                   format as the data returned from the in point */
                if ((ret = usb_control_msg(port->serial->dev,
index 4092f6dc9efdf9a35f6ff1ac166d2de8ed583fb5..b5194dc7d3bba271e2066e539570e691f0fa0d93 100644 (file)
@@ -24,26 +24,6 @@ static struct usb_device_id id_table [] = {
 };
 MODULE_DEVICE_TABLE(usb, id_table);
 
-static int funsoft_ioctl(struct usb_serial_port *port, struct file *file,
-                        unsigned int cmd, unsigned long arg)
-{
-       struct ktermios t;
-
-       dbg("%s - port %d, cmd 0x%04x", __FUNCTION__, port->number, cmd);
-
-       if (cmd == TCSETSF) {
-               if (user_termios_to_kernel_termios(&t, (struct termios __user *)arg))
-                       return -EFAULT;
-
-               dbg("%s - iflag:%x oflag:%x cflag:%x lflag:%x", __FUNCTION__,
-                   t.c_iflag, t.c_oflag, t.c_cflag, t.c_lflag);
-
-               if (!(t.c_lflag & ICANON))
-                       return -EINVAL;
-       }
-       return -ENOIOCTLCMD;
-}
-
 static struct usb_driver funsoft_driver = {
        .name =         "funsoft",
        .probe =        usb_serial_probe,
@@ -63,7 +43,6 @@ static struct usb_serial_driver funsoft_device = {
        .num_bulk_in =          NUM_DONT_CARE,
        .num_bulk_out =         NUM_DONT_CARE,
        .num_ports =            1,
-       .ioctl =                funsoft_ioctl,
 };
 
 static int __init funsoft_init(void)
index 6a3a704b58498bff271b34351dd382049f7cbcd2..e836ad07fdb9e958c1380cf93d11076433adfa60 100644 (file)
@@ -256,6 +256,7 @@ static struct usb_device_id ipaq_id_table [] = {
        { USB_DEVICE(0x04DD, 0x9121) }, /* SHARP WS004SH USB Modem */
        { USB_DEVICE(0x04DD, 0x9123) }, /* SHARP WS007SH USB Modem */
        { USB_DEVICE(0x04DD, 0x9151) }, /* SHARP S01SH USB Modem */
+       { USB_DEVICE(0x04DD, 0x91AC) }, /* SHARP WS011SH USB Modem */
        { USB_DEVICE(0x04E8, 0x5F00) }, /* Samsung NEXiO USB Sync */
        { USB_DEVICE(0x04E8, 0x5F01) }, /* Samsung NEXiO USB Sync */
        { USB_DEVICE(0x04E8, 0x5F02) }, /* Samsung NEXiO USB Sync */
@@ -646,11 +647,13 @@ static int ipaq_open(struct usb_serial_port *port, struct file *filp)
        kfree(port->bulk_out_buffer);
        port->bulk_in_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
        if (port->bulk_in_buffer == NULL) {
+               port->bulk_out_buffer = NULL; /* prevent double free */
                goto enomem;
        }
        port->bulk_out_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
        if (port->bulk_out_buffer == NULL) {
                kfree(port->bulk_in_buffer);
+               port->bulk_in_buffer = NULL;
                goto enomem;
        }
        port->read_urb->transfer_buffer = port->bulk_in_buffer;
index 5a4127e62c4ad4f08089eafd3fa4d4e131cd578d..90e3216abd1f006800f0d2ed018a83c12a9b5cc0 100644 (file)
@@ -728,24 +728,32 @@ static void klsi_105_set_termios (struct usb_serial_port *port,
 #endif
                }
                
-               switch(cflag & CBAUD) {
-               case B0: /* handled below */
+               switch(tty_get_baud_rate(port->tty)) {
+               case 0: /* handled below */
                        break;
-               case B1200: priv->cfg.baudrate = kl5kusb105a_sio_b1200;
+               case 1200:
+                       priv->cfg.baudrate = kl5kusb105a_sio_b1200;
                        break;
-               case B2400: priv->cfg.baudrate = kl5kusb105a_sio_b2400;
+               case 2400:
+                       priv->cfg.baudrate = kl5kusb105a_sio_b2400;
                        break;
-               case B4800: priv->cfg.baudrate = kl5kusb105a_sio_b4800;
+               case 4800:
+                       priv->cfg.baudrate = kl5kusb105a_sio_b4800;
                        break;
-               case B9600: priv->cfg.baudrate = kl5kusb105a_sio_b9600;
+               case 9600:
+                       priv->cfg.baudrate = kl5kusb105a_sio_b9600;
                        break;
-               case B19200: priv->cfg.baudrate = kl5kusb105a_sio_b19200;
+               case 19200:
+                       priv->cfg.baudrate = kl5kusb105a_sio_b19200;
                        break;
-               case B38400: priv->cfg.baudrate = kl5kusb105a_sio_b38400;
+               case 38400:
+                       priv->cfg.baudrate = kl5kusb105a_sio_b38400;
                        break;
-               case B57600: priv->cfg.baudrate = kl5kusb105a_sio_b57600;
+               case 57600:
+                       priv->cfg.baudrate = kl5kusb105a_sio_b57600;
                        break;
-               case B115200: priv->cfg.baudrate = kl5kusb105a_sio_b115200;
+               case 115200:
+                       priv->cfg.baudrate = kl5kusb105a_sio_b115200;
                        break;
                default:
                        err("KLSI USB->Serial converter:"
index 02a86dbc0e9759673000eeb4521a8d0bafabc5ed..6f224195bd25a6048efc65cc26f9b197d6f87a70 100644 (file)
@@ -82,6 +82,7 @@ static int  kobil_tiocmset(struct usb_serial_port *port, struct file *file,
                           unsigned int set, unsigned int clear);
 static void kobil_read_int_callback( struct urb *urb );
 static void kobil_write_callback( struct urb *purb );
+static void kobil_set_termios(struct usb_serial_port *port, struct ktermios *old);
 
 
 static struct usb_device_id id_table [] = {
@@ -119,6 +120,7 @@ static struct usb_serial_driver kobil_device = {
        .attach =               kobil_startup,
        .shutdown =             kobil_shutdown,
        .ioctl =                kobil_ioctl,
+       .set_termios =          kobil_set_termios,
        .tiocmget =             kobil_tiocmget,
        .tiocmset =             kobil_tiocmset,
        .open =                 kobil_open,
@@ -137,7 +139,6 @@ struct kobil_private {
        int cur_pos; // index of the next char to send in buf
        __u16 device_type;
        int line_state;
-       struct ktermios internal_termios;
 };
 
 
@@ -216,7 +217,7 @@ static void kobil_shutdown (struct usb_serial *serial)
 
 static int kobil_open (struct usb_serial_port *port, struct file *filp)
 {
-       int i, result = 0;
+       int result = 0;
        struct kobil_private *priv;
        unsigned char *transfer_buffer;
        int transfer_buffer_length = 8;
@@ -242,16 +243,6 @@ static int kobil_open (struct usb_serial_port *port, struct file *filp)
        port->tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF;
        port->tty->termios->c_oflag &= ~ONLCR; // do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D)
        
-       // set up internal termios structure 
-       priv->internal_termios.c_iflag = port->tty->termios->c_iflag;
-       priv->internal_termios.c_oflag = port->tty->termios->c_oflag;
-       priv->internal_termios.c_cflag = port->tty->termios->c_cflag;
-       priv->internal_termios.c_lflag = port->tty->termios->c_lflag;
-
-       for (i=0; i<NCCS; i++) {
-               priv->internal_termios.c_cc[i] = port->tty->termios->c_cc[i];
-       }
-       
        // allocate memory for transfer buffer
        transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL);
        if (! transfer_buffer) {
@@ -607,102 +598,79 @@ static int  kobil_tiocmset(struct usb_serial_port *port, struct file *file,
        return (result < 0) ? result : 0;
 }
 
-
-static int  kobil_ioctl(struct usb_serial_port *port, struct file *file,
-                       unsigned int cmd, unsigned long arg)
+static void kobil_set_termios(struct usb_serial_port *port, struct ktermios *old)
 {
        struct kobil_private * priv;
        int result;
        unsigned short urb_val = 0;
-       unsigned char *transfer_buffer;
-       int transfer_buffer_length = 8;
-       char *settings;
-       void __user *user_arg = (void __user *)arg;
+       int c_cflag = port->tty->termios->c_cflag;
+       speed_t speed;
+       void * settings;
 
        priv = usb_get_serial_port_data(port);
-       if ((priv->device_type == KOBIL_USBTWIN_PRODUCT_ID) || (priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)) {
+       if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)
                // This device doesn't support ioctl calls
-               return 0;
-       }
-
-       switch (cmd) {
-       case TCGETS:   // 0x5401
-               if (!access_ok(VERIFY_WRITE, user_arg, sizeof(struct ktermios))) {
-                       dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number);
-                       return -EFAULT;
-               }
-               if (kernel_termios_to_user_termios((struct ktermios __user *)arg,
-                                                  &priv->internal_termios))
-                       return -EFAULT;
-               return 0;
-
-       case TCSETS:   // 0x5402
-               if (!(port->tty->termios)) {
-                       dbg("%s - port %d Error: port->tty->termios is NULL", __FUNCTION__, port->number);
-                       return -ENOTTY;
-               }
-               if (!access_ok(VERIFY_READ, user_arg, sizeof(struct ktermios))) {
-                       dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number);
-                       return -EFAULT;
-               }
-               if (user_termios_to_kernel_termios(&priv->internal_termios,
-                                                  (struct ktermios __user *)arg))
-                       return -EFAULT;
-               
-               settings = kzalloc(50, GFP_KERNEL);
-               if (! settings) {
-                       return -ENOBUFS;
-               }
+               return;
 
-               switch (priv->internal_termios.c_cflag & CBAUD) {
-               case B1200:
+       switch (speed = tty_get_baud_rate(port->tty)) {
+               case 1200:
                        urb_val = SUSBCR_SBR_1200;
-                       strcat(settings, "1200 ");
                        break;
-               case B9600:
+               case 9600:
                default:
                        urb_val = SUSBCR_SBR_9600;
-                       strcat(settings, "9600 ");
                        break;
-               }
+       }
+       urb_val |= (c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits : SUSBCR_SPASB_1StopBit;
+
+       settings = kzalloc(50, GFP_KERNEL);
+       if (! settings)
+               return;
 
-               urb_val |= (priv->internal_termios.c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits : SUSBCR_SPASB_1StopBit;
-               strcat(settings, (priv->internal_termios.c_cflag & CSTOPB) ? "2 StopBits " : "1 StopBit ");
+       sprintf(settings, "%d ", speed);
 
-               if (priv->internal_termios.c_cflag & PARENB) {
-                       if  (priv->internal_termios.c_cflag & PARODD) {
-                               urb_val |= SUSBCR_SPASB_OddParity;
-                               strcat(settings, "Odd Parity");
-                       } else {
-                               urb_val |= SUSBCR_SPASB_EvenParity;
-                               strcat(settings, "Even Parity");
-                       }
+       if (c_cflag & PARENB) {
+               if  (c_cflag & PARODD) {
+                       urb_val |= SUSBCR_SPASB_OddParity;
+                       strcat(settings, "Odd Parity");
                } else {
-                       urb_val |= SUSBCR_SPASB_NoParity;
-                       strcat(settings, "No Parity");
+                       urb_val |= SUSBCR_SPASB_EvenParity;
+                       strcat(settings, "Even Parity");
                }
-               dbg("%s - port %d setting port to: %s", __FUNCTION__, port->number, settings );
+       } else {
+               urb_val |= SUSBCR_SPASB_NoParity;
+               strcat(settings, "No Parity");
+       }
 
-               result = usb_control_msg( port->serial->dev, 
-                                         usb_rcvctrlpipe(port->serial->dev, 0 ), 
-                                         SUSBCRequest_SetBaudRateParityAndStopBits,
-                                         USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
-                                         urb_val,
-                                         0,
-                                         settings,
-                                         0,
-                                         KOBIL_TIMEOUT
-                       );
+       result = usb_control_msg( port->serial->dev,
+                                 usb_rcvctrlpipe(port->serial->dev, 0 ),
+                                 SUSBCRequest_SetBaudRateParityAndStopBits,
+                                 USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
+                                 urb_val,
+                                 0,
+                                 settings,
+                                 0,
+                                 KOBIL_TIMEOUT
+               );
+       kfree(settings);
+}
 
-               dbg("%s - port %d Send set_baudrate URB returns: %i", __FUNCTION__, port->number, result);
-               kfree(settings);
+static int kobil_ioctl(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
+{
+       struct kobil_private * priv = usb_get_serial_port_data(port);
+       unsigned char *transfer_buffer;
+       int transfer_buffer_length = 8;
+       int result;
+
+       if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)
+               // This device doesn't support ioctl calls
                return 0;
 
+       switch (cmd) {
        case TCFLSH:   // 0x540B
                transfer_buffer = kmalloc(transfer_buffer_length, GFP_KERNEL);
-               if (! transfer_buffer) {
+               if (! transfer_buffer)
                        return -ENOBUFS;
-               }
 
                result = usb_control_msg( port->serial->dev, 
                                          usb_rcvctrlpipe(port->serial->dev, 0 ), 
@@ -716,15 +684,13 @@ static int  kobil_ioctl(struct usb_serial_port *port, struct file *file,
                        );
                
                dbg("%s - port %d Send reset_all_queues (FLUSH) URB returns: %i", __FUNCTION__, port->number, result);
-
                kfree(transfer_buffer);
-               return ((result < 0) ? -EFAULT : 0);
-
+               return (result < 0) ? -EFAULT : 0;
+       default:
+               return -ENOIOCTLCMD;
        }
-       return -ENOIOCTLCMD;
 }
 
-
 static int __init kobil_init (void)
 {
        int retval;
index e08c9bb403d88544709108174ce610b51962a340..0dc99f75bb09d13ab67072e4703c81a80894eb21 100644 (file)
@@ -206,20 +206,20 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value
                }
        } else {
                switch (value) {
-                       case 300: break;
-                       case 600: break;
-                       case 1200: break;
-                       case 2400: break;
-                       case 4800: break;
-                       case 9600: break;
-                       case 19200: break;
-                       case 38400: break;
-                       case 57600: break;
-                       case 115200: break;
-                       default:
-                               err("MCT USB-RS232: unsupported baudrate request 0x%x,"
-                                   " using default of B9600", value);
-                               value = 9600;
+               case 300: break;
+               case 600: break;
+               case 1200: break;
+               case 2400: break;
+               case 4800: break;
+               case 9600: break;
+               case 19200: break;
+               case 38400: break;
+               case 57600: break;
+               case 115200: break;
+               default:
+                       err("MCT USB-RS232: unsupported baudrate request 0x%x,"
+                           " using default of B9600", value);
+                       value = 9600;
                }
                return 115200/value;
        }
index 64f3f66a7a353b8962ad9dffb4f3a7b752f7b6c1..d19861166b505cbca39a37f692d61fafd41cdf07 100644 (file)
@@ -1144,7 +1144,7 @@ static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
        if (size == 0)
                return NULL;
 
-       pb = (struct pl2303_buf *)kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
+       pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
        if (pb == NULL)
                return NULL;
 
index f9f85f56f0db48a0c3f67262be1f64a0e81ee6f2..1da57fd9ea236f65db6670c682a26838da959e3e 100644 (file)
@@ -73,6 +73,7 @@ static struct usb_device_id id_table [] = {
        { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) },
        { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },
        { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) },
+       { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) },
        { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
        { USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },
        { USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },
index f9a71d0c102e7c54cafd3edb7747dbf5ceea0eb9..c39bace5cbccb43b8a711ee5213a1b3b73b34221 100644 (file)
@@ -59,6 +59,7 @@
 #define SIEMENS_PRODUCT_ID_SX1 0x0001
 #define SIEMENS_PRODUCT_ID_X65 0x0003
 #define SIEMENS_PRODUCT_ID_X75 0x0004
+#define SIEMENS_PRODUCT_ID_EF81        0x0005
 
 #define SYNTECH_VENDOR_ID      0x0745
 #define SYNTECH_PRODUCT_ID     0x0001
index 51669b7622bb8fdeaf80bdfd29017603d58ec5cb..4e6dcc199be9a3119800dcf82845858b64d41ad9 100644 (file)
@@ -90,18 +90,12 @@ MODULE_AUTHOR (DRIVER_AUTHOR);
 MODULE_DESCRIPTION (DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
-#if defined(CONFIG_USBD_SAFE_SERIAL_VENDOR) && !defined(CONFIG_USBD_SAFE_SERIAL_PRODUCT)
-#error "SAFE_SERIAL_VENDOR defined without SAFE_SERIAL_PRODUCT"
-#endif
-
-#if ! defined(CONFIG_USBD_SAFE_SERIAL_VENDOR)
 static __u16 vendor;           // no default
 static __u16 product;          // no default
 module_param(vendor, ushort, 0);
 MODULE_PARM_DESC(vendor, "User specified USB idVendor (required)");
 module_param(product, ushort, 0);
 MODULE_PARM_DESC(product, "User specified USB idProduct (required)");
-#endif
 
 module_param(debug, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug enabled or not");
@@ -145,11 +139,6 @@ static struct usb_device_id id_table[] = {
        {MY_USB_DEVICE (0x4dd, 0x8003, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},  // Collie 
        {MY_USB_DEVICE (0x4dd, 0x8004, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},  // Collie 
        {MY_USB_DEVICE (0x5f9, 0xffff, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},  // Sharp tmp
-#if defined(CONFIG_USB_SAFE_SERIAL_VENDOR)
-       {MY_USB_DEVICE
-        (CONFIG_USB_SAFE_SERIAL_VENDOR, CONFIG_USB_SAFE_SERIAL_PRODUCT, CDC_DEVICE_CLASS,
-         LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},
-#endif
        // extra null entry for module 
        // vendor/produc parameters
        {MY_USB_DEVICE (0, 0, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},
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 9bf01a5efc84adaaec0145ca24076421b64db558..4b1bd7def4a5a32243753431ffd526952c017368 100644 (file)
@@ -578,6 +578,17 @@ static void kill_traffic(struct usb_serial_port *port)
 {
        usb_kill_urb(port->read_urb);
        usb_kill_urb(port->write_urb);
+       /*
+        * This is tricky.
+        * Some drivers submit the read_urb in the
+        * handler for the write_urb or vice versa
+        * this order determines the order in which
+        * usb_kill_urb() must be used to reliably
+        * kill the URBs. As it is unknown here,
+        * both orders must be used in turn.
+        * The call below is not redundant.
+        */
+       usb_kill_urb(port->read_urb);
        usb_kill_urb(port->interrupt_in_urb);
        usb_kill_urb(port->interrupt_out_urb);
 }
@@ -651,16 +662,14 @@ exit:
 
 static struct usb_serial_driver *search_serial_device(struct usb_interface *iface)
 {
-       struct list_head *p;
        const struct usb_device_id *id;
-       struct usb_serial_driver *t;
+       struct usb_serial_driver *drv;
 
        /* Check if the usb id matches a known device */
-       list_for_each(p, &usb_serial_driver_list) {
-               t = list_entry(p, struct usb_serial_driver, driver_list);
-               id = get_iface_id(t, iface);
+       list_for_each_entry(drv, &usb_serial_driver_list, driver_list) {
+               id = get_iface_id(drv, iface);
                if (id)
-                       return t;
+                       return drv;
        }
 
        return NULL;
@@ -800,9 +809,6 @@ int usb_serial_probe(struct usb_interface *interface,
        /* END HORRIBLE HACK FOR PL2303 */
 #endif
 
-       /* found all that we need */
-       dev_info(&interface->dev, "%s converter detected\n", type->description);
-
 #ifdef CONFIG_USB_SERIAL_GENERIC
        if (type == &usb_serial_generic_device) {
                num_ports = num_bulk_out;
@@ -836,6 +842,24 @@ int usb_serial_probe(struct usb_interface *interface,
        serial->num_interrupt_in = num_interrupt_in;
        serial->num_interrupt_out = num_interrupt_out;
 
+       /* check that the device meets the driver's requirements */
+       if ((type->num_interrupt_in != NUM_DONT_CARE &&
+                               type->num_interrupt_in != num_interrupt_in)
+                       || (type->num_interrupt_out != NUM_DONT_CARE &&
+                               type->num_interrupt_out != num_interrupt_out)
+                       || (type->num_bulk_in != NUM_DONT_CARE &&
+                               type->num_bulk_in != num_bulk_in)
+                       || (type->num_bulk_out != NUM_DONT_CARE &&
+                               type->num_bulk_out != num_bulk_out)) {
+               dbg("wrong number of endpoints");
+               kfree(serial);
+               return -EIO;
+       }
+
+       /* found all that we need */
+       dev_info(&interface->dev, "%s converter detected\n",
+                       type->description);
+
        /* create our ports, we need as many as the max endpoints */
        /* we don't use num_ports here cauz some devices have more endpoint pairs than ports */
        max_endpoints = max(num_bulk_in, num_bulk_out);
index 30e08c0bcdc2d3c26311f17f2088e45ed35b10a6..7ee087fed913fbeed34678caebbe15dc8a96567c 100644 (file)
@@ -46,7 +46,6 @@ static int  visor_probe               (struct usb_serial *serial, const struct usb_device_id
 static int  visor_calc_num_ports(struct usb_serial *serial);
 static void visor_shutdown     (struct usb_serial *serial);
 static int  visor_ioctl                (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
-static void visor_set_termios  (struct usb_serial_port *port, struct ktermios *old_termios);
 static void visor_write_bulk_callback  (struct urb *urb);
 static void visor_read_bulk_callback   (struct urb *urb);
 static void visor_read_int_callback    (struct urb *urb);
@@ -203,7 +202,6 @@ static struct usb_serial_driver handspring_device = {
        .calc_num_ports =       visor_calc_num_ports,
        .shutdown =             visor_shutdown,
        .ioctl =                visor_ioctl,
-       .set_termios =          visor_set_termios,
        .write =                visor_write,
        .write_room =           visor_write_room,
        .chars_in_buffer =      visor_chars_in_buffer,
@@ -234,7 +232,6 @@ static struct usb_serial_driver clie_5_device = {
        .calc_num_ports =       visor_calc_num_ports,
        .shutdown =             visor_shutdown,
        .ioctl =                visor_ioctl,
-       .set_termios =          visor_set_termios,
        .write =                visor_write,
        .write_room =           visor_write_room,
        .chars_in_buffer =      visor_chars_in_buffer,
@@ -262,7 +259,6 @@ static struct usb_serial_driver clie_3_5_device = {
        .unthrottle =           visor_unthrottle,
        .attach =               clie_3_5_startup,
        .ioctl =                visor_ioctl,
-       .set_termios =          visor_set_termios,
        .write =                visor_write,
        .write_room =           visor_write_room,
        .chars_in_buffer =      visor_chars_in_buffer,
@@ -936,66 +932,6 @@ static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsign
        return -ENOIOCTLCMD;
 }
 
-
-/* This function is all nice and good, but we don't change anything based on it :) */
-static void visor_set_termios (struct usb_serial_port *port, struct ktermios *old_termios)
-{
-       unsigned int cflag;
-
-       dbg("%s - port %d", __FUNCTION__, port->number);
-
-       if ((!port->tty) || (!port->tty->termios)) {
-               dbg("%s - no tty structures", __FUNCTION__);
-               return;
-       }
-
-       cflag = port->tty->termios->c_cflag;
-
-       /* get the byte size */
-       switch (cflag & CSIZE) {
-               case CS5:       dbg("%s - data bits = 5", __FUNCTION__);   break;
-               case CS6:       dbg("%s - data bits = 6", __FUNCTION__);   break;
-               case CS7:       dbg("%s - data bits = 7", __FUNCTION__);   break;
-               default:
-               case CS8:       dbg("%s - data bits = 8", __FUNCTION__);   break;
-       }
-       
-       /* determine the parity */
-       if (cflag & PARENB)
-               if (cflag & PARODD)
-                       dbg("%s - parity = odd", __FUNCTION__);
-               else
-                       dbg("%s - parity = even", __FUNCTION__);
-       else
-               dbg("%s - parity = none", __FUNCTION__);
-
-       /* figure out the stop bits requested */
-       if (cflag & CSTOPB)
-               dbg("%s - stop bits = 2", __FUNCTION__);
-       else
-               dbg("%s - stop bits = 1", __FUNCTION__);
-
-       
-       /* figure out the flow control settings */
-       if (cflag & CRTSCTS)
-               dbg("%s - RTS/CTS is enabled", __FUNCTION__);
-       else
-               dbg("%s - RTS/CTS is disabled", __FUNCTION__);
-       
-       /* determine software flow control */
-       if (I_IXOFF(port->tty))
-               dbg("%s - XON/XOFF is enabled, XON = %2x, XOFF = %2x",
-                   __FUNCTION__, START_CHAR(port->tty), STOP_CHAR(port->tty));
-       else
-               dbg("%s - XON/XOFF is disabled", __FUNCTION__);
-
-       /* get the baud rate wanted */
-       dbg("%s - baud rate = %d", __FUNCTION__, tty_get_baud_rate(port->tty));
-
-       return;
-}
-
-
 static int __init visor_init (void)
 {
        int i, retval;
index 3a41740cad97d38b6e04c385fd64dd82f9c85133..ee5b42aa53633b159b259d95bbf208e866a48492 100644 (file)
@@ -90,3 +90,17 @@ int usb_stor_ucr61s2b_init(struct us_data *us)
 
        return (res ? -1 : 0);
 }
+
+/* This places the HUAWEI E220 devices in multi-port mode */
+int usb_stor_huawei_e220_init(struct us_data *us)
+{
+       int result;
+
+       us->iobuf[0] = 0x1;
+       result = usb_stor_control_msg(us, us->send_ctrl_pipe,
+                                     USB_REQ_SET_FEATURE,
+                                     USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+                                     0x01, 0x0, us->iobuf, 0x1, 1000);
+       US_DEBUGP("usb_control_msg performing result is %d\n", result);
+       return (result ? 0 : -1);
+}
index e2967a4d48a2e30d0fa694f233d10941ec88121a..ad3ffd4236c2af961039f36e3943978ee07fd66a 100644 (file)
@@ -47,3 +47,6 @@ int usb_stor_euscsi_init(struct us_data *us);
 /* This function is required to activate all four slots on the UCR-61S2B
  * flash reader */
 int usb_stor_ucr61s2b_init(struct us_data *us);
+
+/* This places the HUAWEI E220 devices in multi-port mode */
+int usb_stor_huawei_e220_init(struct us_data *us);
index 5e27297c0175cb9017973b5e9e1c82de5c48056a..17ca4d73577b851fdf33eb91dfe2514c97c8ec46 100644 (file)
@@ -190,9 +190,6 @@ static int usbat_check_status(struct us_data *us)
        unsigned char *reply = us->iobuf;
        int rc;
 
-       if (!us)
-               return USB_STOR_TRANSPORT_ERROR;
-
        rc = usbat_get_status(us, reply);
        if (rc != USB_STOR_XFER_GOOD)
                return USB_STOR_TRANSPORT_FAILED;
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 c6b78ba815eaaa94dfd0f90f61690b4c59cb23ec..9b656ec427d0613ae388bce16eacbbc03cac62c5 100644 (file)
@@ -198,7 +198,7 @@ UNUSUAL_DEV(  0x0421, 0x044e, 0x0100, 0x0100,
                US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ),
 
 /* Reported by Bardur Arantsson <bardur@scientician.net> */
-UNUSUAL_DEV(  0x0421, 0x047c, 0x0370, 0x0370,
+UNUSUAL_DEV(  0x0421, 0x047c, 0x0370, 0x0610,
                "Nokia",
                "6131",
                US_SC_DEVICE, US_PR_DEVICE, NULL,
@@ -341,6 +341,13 @@ UNUSUAL_DEV(  0x04b0, 0x040d, 0x0100, 0x0100,
                US_SC_DEVICE, US_PR_DEVICE, NULL,
                US_FL_FIX_CAPACITY),
 
+/* Reported by Graber and Mike Pagano <mpagano-kernel@mpagano.com> */
+UNUSUAL_DEV(  0x04b0, 0x040f, 0x0200, 0x0200,
+       "NIKON",
+       "NIKON DSC D200",
+       US_SC_DEVICE, US_PR_DEVICE, NULL,
+       US_FL_FIX_CAPACITY),
+
 /* Reported by Emil Larsson <emil@swip.net> */
 UNUSUAL_DEV(  0x04b0, 0x0411, 0x0100, 0x0101,
                "NIKON",
@@ -355,6 +362,20 @@ UNUSUAL_DEV(  0x04b0, 0x0413, 0x0110, 0x0110,
                US_SC_DEVICE, US_PR_DEVICE, NULL,
                US_FL_FIX_CAPACITY),
 
+/* Reported by Paul Check <paul@openstreet.com> */
+UNUSUAL_DEV(  0x04b0, 0x0415, 0x0100, 0x0100,
+               "NIKON",
+               "NIKON DSC D2Xs",
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               US_FL_FIX_CAPACITY),
+
+/* Reported by Shan Destromp (shansan@gmail.com) */
+UNUSUAL_DEV(  0x04b0, 0x0417, 0x0100, 0x0100,
+               "NIKON",
+               "NIKON DSC D40X",
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               US_FL_FIX_CAPACITY),
+
 /* BENQ DC5330
  * Reported by Manuel Fombuena <mfombuena@ya.com> and
  * Frank Copeland <fjc@thingy.apana.org.au> */
@@ -1463,6 +1484,17 @@ UNUSUAL_DEV(  0x1210, 0x0003, 0x0100, 0x0100,
                US_SC_DEVICE, US_PR_DEVICE, NULL,
                US_FL_IGNORE_RESIDUE ),
 
+/* Reported by fangxiaozhi <fangxiaozhi60675@huawei.com>
+ * and by linlei <linlei83@huawei.com>
+ * Patch reworked by Johann Wilhelm <johann.wilhelm@student.tugraz.at>
+ * This brings the HUAWEI E220 devices into multi-port mode
+ */
+UNUSUAL_DEV( 0x12d1, 0x1003, 0x0000, 0x0000,
+               "HUAWEI MOBILE",
+               "Mass Storage",
+               US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+               0),
+
 /* Reported by Vilius Bilinkevicius <vilisas AT xxx DOT lt) */
 UNUSUAL_DEV(  0x132b, 0x000b, 0x0001, 0x0001,
                "Minolta",
index 59181667066ce7cfa9b382685c921fe3d0fb52fb..3451e8d03ab0e4653ff2f7208077f565f7294e19 100644 (file)
@@ -960,6 +960,10 @@ static int storage_probe(struct usb_interface *intf,
                return -ENOMEM;
        }
 
+       /*
+        * Allow 16-byte CDBs and thus > 2TB
+        */
+       host->max_cmd_len = 16;
        us = host_to_us(host);
        memset(us, 0, sizeof(struct us_data));
        mutex_init(&(us->dev_mutex));
index 8de11deb5d1429dffb16febcd1d834623b59d0c5..c815a40e167f33f7427f0c908514e0e93b685b7d 100644 (file)
@@ -125,6 +125,7 @@ static int skel_open(struct inode *inode, struct file *file)
 
        /* save our object in the file's private structure */
        file->private_data = dev;
+       mutex_unlock(&dev->io_mutex);
 
 exit:
        return retval;
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 1473f2c892d258b2b351c6f9fa777154b1595a88..f2df5519c9c455557bf039b899e0d45a123054c0 100644 (file)
@@ -31,7 +31,8 @@ MODULE_DESCRIPTION("Display Output Switcher Lowlevel Control Abstraction");
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Luming Yu <luming.yu@intel.com>");
 
-static ssize_t video_output_show_state(struct class_device *dev,char *buf)
+static ssize_t video_output_show_state(struct device *dev,
+                                      struct device_attribute *attr, char *buf)
 {
        ssize_t ret_size = 0;
        struct output_device *od = to_output_device(dev);
@@ -40,8 +41,9 @@ static ssize_t video_output_show_state(struct class_device *dev,char *buf)
        return ret_size;
 }
 
-static ssize_t video_output_store_state(struct class_device *dev,
-       const char *buf,size_t count)
+static ssize_t video_output_store_state(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf,size_t count)
 {
        char *endp;
        struct output_device *od = to_output_device(dev);
@@ -60,21 +62,22 @@ static ssize_t video_output_store_state(struct class_device *dev,
        return count;
 }
 
-static void video_output_class_release(struct class_device *dev)
+static void video_output_release(struct device *dev)
 {
        struct output_device *od = to_output_device(dev);
        kfree(od);
 }
 
-static struct class_device_attribute video_output_attributes[] = {
+static struct device_attribute video_output_attributes[] = {
        __ATTR(state, 0644, video_output_show_state, video_output_store_state),
        __ATTR_NULL,
 };
 
+
 static struct class video_output_class = {
        .name = "video_output",
-       .release = video_output_class_release,
-       .class_dev_attrs = video_output_attributes,
+       .dev_release = video_output_release,
+       .dev_attrs = video_output_attributes,
 };
 
 struct output_device *video_output_register(const char *name,
@@ -91,11 +94,11 @@ struct output_device *video_output_register(const char *name,
                goto error_return;
        }
        new_dev->props = op;
-       new_dev->class_dev.class = &video_output_class;
-       new_dev->class_dev.dev = dev;
-       strlcpy(new_dev->class_dev.class_id,name,KOBJ_NAME_LEN);
-       class_set_devdata(&new_dev->class_dev,devdata);
-       ret_code = class_device_register(&new_dev->class_dev);
+       new_dev->dev.class = &video_output_class;
+       new_dev->dev.parent = dev;
+       strlcpy(new_dev->dev.bus_id,name, BUS_ID_SIZE);
+       dev_set_drvdata(&new_dev->dev, devdata);
+       ret_code = device_register(&new_dev->dev);
        if (ret_code) {
                kfree(new_dev);
                goto error_return;
@@ -111,7 +114,7 @@ void video_output_unregister(struct output_device *dev)
 {
        if (!dev)
                return;
-       class_device_unregister(&dev->class_dev);
+       device_unregister(&dev->dev);
 }
 EXPORT_SYMBOL(video_output_unregister);
 
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 a593f900eff4ff1936f9e9504747592ab27e9b4d..070217322c9fb30e98b1db28c476bc68b5cdbbef 100644 (file)
@@ -197,7 +197,7 @@ static struct w1_family w1_default_family = {
        .fops = &w1_default_fops,
 };
 
-static int w1_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size);
+static int w1_uevent(struct device *dev, struct kobj_uevent_env *env);
 
 static struct bus_type w1_bus_type = {
        .name = "w1",
@@ -396,13 +396,12 @@ static void w1_destroy_master_attributes(struct w1_master *master)
 }
 
 #ifdef CONFIG_HOTPLUG
-static int w1_uevent(struct device *dev, char **envp, int num_envp,
-                       char *buffer, int buffer_size)
+static int w1_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        struct w1_master *md = NULL;
        struct w1_slave *sl = NULL;
        char *event_owner, *name;
-       int err, cur_index=0, cur_len=0;
+       int err;
 
        if (dev->driver == &w1_master_driver) {
                md = container_of(dev, struct w1_master, dev);
@@ -423,23 +422,19 @@ static int w1_uevent(struct device *dev, char **envp, int num_envp,
        if (dev->driver != &w1_slave_driver || !sl)
                return 0;
 
-       err = add_uevent_var(envp, num_envp, &cur_index, buffer, buffer_size,
-                       &cur_len, "W1_FID=%02X", sl->reg_num.family);
+       err = add_uevent_var(env, "W1_FID=%02X", sl->reg_num.family);
        if (err)
                return err;
 
-       err = add_uevent_var(envp, num_envp, &cur_index, buffer, buffer_size,
-                       &cur_len, "W1_SLAVE_ID=%024LX",
-                       (unsigned long long)sl->reg_num.id);
-       envp[cur_index] = NULL;
+       err = add_uevent_var(env, "W1_SLAVE_ID=%024LX",
+                            (unsigned long long)sl->reg_num.id);
        if (err)
                return err;
 
        return 0;
 };
 #else
-static int w1_uevent(struct device *dev, char **envp, int num_envp,
-                       char *buffer, int buffer_size)
+static int w1_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        return 0;
 }
index f9eed6d790669e003b71680af254d05c3eab9eee..bb02b39380a3b5bfd571a5d036d0cfd435c3c791 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.
+         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.
+
+         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
 
index 2e124e0075c5a3c2512af9626b03250c43e45cf3..a9b99c0dc2e7cb6d0575511918776e444cdd1059 100644 (file)
@@ -221,6 +221,42 @@ struct dentry *debugfs_create_u64(const char *name, mode_t mode,
 }
 EXPORT_SYMBOL_GPL(debugfs_create_u64);
 
+DEFINE_SIMPLE_ATTRIBUTE(fops_x8, debugfs_u8_get, debugfs_u8_set, "0x%02llx\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_x16, debugfs_u16_get, debugfs_u16_set, "0x%04llx\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_x32, debugfs_u32_get, debugfs_u32_set, "0x%08llx\n");
+
+/**
+ * debugfs_create_x8 - create a debugfs file that is used to read and write an unsigned 8-bit value
+ * debugfs_create_x16 - create a debugfs file that is used to read and write an unsigned 16-bit value
+ * debugfs_create_x32 - create a debugfs file that is used to read and write an unsigned 32-bit value
+ *
+ * These functions are exactly the same as the above functions, (but use a hex
+ * output for the decimal challenged) for details look at the above unsigned
+ * decimal functions.
+ */
+struct dentry *debugfs_create_x8(const char *name, mode_t mode,
+                                struct dentry *parent, u8 *value)
+{
+       return debugfs_create_file(name, mode, parent, value, &fops_x8);
+}
+EXPORT_SYMBOL_GPL(debugfs_create_x8);
+
+struct dentry *debugfs_create_x16(const char *name, mode_t mode,
+                                struct dentry *parent, u16 *value)
+{
+       return debugfs_create_file(name, mode, parent, value, &fops_x16);
+}
+EXPORT_SYMBOL_GPL(debugfs_create_x16);
+
+struct dentry *debugfs_create_x32(const char *name, mode_t mode,
+                                struct dentry *parent, u32 *value)
+{
+       return debugfs_create_file(name, mode, parent, value, &fops_x32);
+}
+EXPORT_SYMBOL_GPL(debugfs_create_x32);
+
 static ssize_t read_file_bool(struct file *file, char __user *user_buf,
                              size_t count, loff_t *ppos)
 {
index 74901e981e1089363bdc501fefc9c4ed106c70bb..d2fc2384c3bed34e32b83ed98804d01961eb7d5a 100644 (file)
@@ -491,6 +491,7 @@ struct dlm_ls {
        uint64_t                ls_recover_seq;
        struct dlm_recover      *ls_recover_args;
        struct rw_semaphore     ls_in_recovery; /* block local requests */
+       struct rw_semaphore     ls_recv_active; /* block dlm_recv */
        struct list_head        ls_requestqueue;/* queue remote requests */
        struct mutex            ls_requestqueue_mutex;
        char                    *ls_recover_buf;
index 2082daf083d86cdec3b3697e061f8f3ff703e867..3915b8e1414623db82bce20d0d4b4c41fc6b9fa3 100644 (file)
@@ -3638,55 +3638,8 @@ static void receive_lookup_reply(struct dlm_ls *ls, struct dlm_message *ms)
        dlm_put_lkb(lkb);
 }
 
-int dlm_receive_message(struct dlm_header *hd, int nodeid, int recovery)
+static void _receive_message(struct dlm_ls *ls, struct dlm_message *ms)
 {
-       struct dlm_message *ms = (struct dlm_message *) hd;
-       struct dlm_ls *ls;
-       int error = 0;
-
-       if (!recovery)
-               dlm_message_in(ms);
-
-       ls = dlm_find_lockspace_global(hd->h_lockspace);
-       if (!ls) {
-               log_print("drop message %d from %d for unknown lockspace %d",
-                         ms->m_type, nodeid, hd->h_lockspace);
-               return -EINVAL;
-       }
-
-       /* recovery may have just ended leaving a bunch of backed-up requests
-          in the requestqueue; wait while dlm_recoverd clears them */
-
-       if (!recovery)
-               dlm_wait_requestqueue(ls);
-
-       /* recovery may have just started while there were a bunch of
-          in-flight requests -- save them in requestqueue to be processed
-          after recovery.  we can't let dlm_recvd block on the recovery
-          lock.  if dlm_recoverd is calling this function to clear the
-          requestqueue, it needs to be interrupted (-EINTR) if another
-          recovery operation is starting. */
-
-       while (1) {
-               if (dlm_locking_stopped(ls)) {
-                       if (recovery) {
-                               error = -EINTR;
-                               goto out;
-                       }
-                       error = dlm_add_requestqueue(ls, nodeid, hd);
-                       if (error == -EAGAIN)
-                               continue;
-                       else {
-                               error = -EINTR;
-                               goto out;
-                       }
-               }
-
-               if (dlm_lock_recovery_try(ls))
-                       break;
-               schedule();
-       }
-
        switch (ms->m_type) {
 
        /* messages sent to a master node */
@@ -3761,17 +3714,90 @@ int dlm_receive_message(struct dlm_header *hd, int nodeid, int recovery)
                log_error(ls, "unknown message type %d", ms->m_type);
        }
 
-       dlm_unlock_recovery(ls);
- out:
-       dlm_put_lockspace(ls);
        dlm_astd_wake();
-       return error;
 }
 
+/* If the lockspace is in recovery mode (locking stopped), then normal
+   messages are saved on the requestqueue for processing after recovery is
+   done.  When not in recovery mode, we wait for dlm_recoverd to drain saved
+   messages off the requestqueue before we process new ones. This occurs right
+   after recovery completes when we transition from saving all messages on
+   requestqueue, to processing all the saved messages, to processing new
+   messages as they arrive. */
 
-/*
- * Recovery related
- */
+static void dlm_receive_message(struct dlm_ls *ls, struct dlm_message *ms,
+                               int nodeid)
+{
+       if (dlm_locking_stopped(ls)) {
+               dlm_add_requestqueue(ls, nodeid, (struct dlm_header *) ms);
+       } else {
+               dlm_wait_requestqueue(ls);
+               _receive_message(ls, ms);
+       }
+}
+
+/* This is called by dlm_recoverd to process messages that were saved on
+   the requestqueue. */
+
+void dlm_receive_message_saved(struct dlm_ls *ls, struct dlm_message *ms)
+{
+       _receive_message(ls, ms);
+}
+
+/* This is called by the midcomms layer when something is received for
+   the lockspace.  It could be either a MSG (normal message sent as part of
+   standard locking activity) or an RCOM (recovery message sent as part of
+   lockspace recovery). */
+
+void dlm_receive_buffer(struct dlm_header *hd, int nodeid)
+{
+       struct dlm_message *ms = (struct dlm_message *) hd;
+       struct dlm_rcom *rc = (struct dlm_rcom *) hd;
+       struct dlm_ls *ls;
+       int type = 0;
+
+       switch (hd->h_cmd) {
+       case DLM_MSG:
+               dlm_message_in(ms);
+               type = ms->m_type;
+               break;
+       case DLM_RCOM:
+               dlm_rcom_in(rc);
+               type = rc->rc_type;
+               break;
+       default:
+               log_print("invalid h_cmd %d from %u", hd->h_cmd, nodeid);
+               return;
+       }
+
+       if (hd->h_nodeid != nodeid) {
+               log_print("invalid h_nodeid %d from %d lockspace %x",
+                         hd->h_nodeid, nodeid, hd->h_lockspace);
+               return;
+       }
+
+       ls = dlm_find_lockspace_global(hd->h_lockspace);
+       if (!ls) {
+               log_print("invalid h_lockspace %x from %d cmd %d type %d",
+                         hd->h_lockspace, nodeid, hd->h_cmd, type);
+
+               if (hd->h_cmd == DLM_RCOM && type == DLM_RCOM_STATUS)
+                       dlm_send_ls_not_ready(nodeid, rc);
+               return;
+       }
+
+       /* this rwsem allows dlm_ls_stop() to wait for all dlm_recv threads to
+          be inactive (in this ls) before transitioning to recovery mode */
+
+       down_read(&ls->ls_recv_active);
+       if (hd->h_cmd == DLM_MSG)
+               dlm_receive_message(ls, ms, nodeid);
+       else
+               dlm_receive_rcom(ls, rc, nodeid);
+       up_read(&ls->ls_recv_active);
+
+       dlm_put_lockspace(ls);
+}
 
 static void recover_convert_waiter(struct dlm_ls *ls, struct dlm_lkb *lkb)
 {
@@ -4429,7 +4455,8 @@ int dlm_user_unlock(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
 
        if (lvb_in && ua->lksb.sb_lvbptr)
                memcpy(ua->lksb.sb_lvbptr, lvb_in, DLM_USER_LVB_LEN);
-       ua->castparam = ua_tmp->castparam;
+       if (ua_tmp->castparam)
+               ua->castparam = ua_tmp->castparam;
        ua->user_lksb = ua_tmp->user_lksb;
 
        error = set_unlock_args(flags, ua, &args);
@@ -4474,7 +4501,8 @@ int dlm_user_cancel(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
                goto out;
 
        ua = (struct dlm_user_args *)lkb->lkb_astparam;
-       ua->castparam = ua_tmp->castparam;
+       if (ua_tmp->castparam)
+               ua->castparam = ua_tmp->castparam;
        ua->user_lksb = ua_tmp->user_lksb;
 
        error = set_unlock_args(flags, ua, &args);
index 1720313c22dfc455fd6c25f47d94fc02db075a64..ada04680a1e5d9ff994aa82a35c899b6a975692b 100644 (file)
@@ -16,7 +16,8 @@
 void dlm_print_rsb(struct dlm_rsb *r);
 void dlm_dump_rsb(struct dlm_rsb *r);
 void dlm_print_lkb(struct dlm_lkb *lkb);
-int dlm_receive_message(struct dlm_header *hd, int nodeid, int recovery);
+void dlm_receive_message_saved(struct dlm_ls *ls, struct dlm_message *ms);
+void dlm_receive_buffer(struct dlm_header *hd, int nodeid);
 int dlm_modes_compat(int mode1, int mode2);
 int dlm_find_rsb(struct dlm_ls *ls, char *name, int namelen,
        unsigned int flags, struct dlm_rsb **r_ret);
index 1dc72105ab125171b4bb3356ea0a09577178ec77..6353a8384520f20190bc5039fc46e6c006ae5d77 100644 (file)
@@ -167,7 +167,6 @@ static struct kobj_type dlm_ktype = {
 };
 
 static struct kset dlm_kset = {
-       .kobj   = {.name = "dlm",},
        .ktype  = &dlm_ktype,
 };
 
@@ -228,6 +227,7 @@ int dlm_lockspace_init(void)
        INIT_LIST_HEAD(&lslist);
        spin_lock_init(&lslist_lock);
 
+       kobject_set_name(&dlm_kset.kobj, "dlm");
        kobj_set_kset_s(&dlm_kset, kernel_subsys);
        error = kset_register(&dlm_kset);
        if (error)
@@ -519,6 +519,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace,
        ls->ls_recover_seq = 0;
        ls->ls_recover_args = NULL;
        init_rwsem(&ls->ls_in_recovery);
+       init_rwsem(&ls->ls_recv_active);
        INIT_LIST_HEAD(&ls->ls_requestqueue);
        mutex_init(&ls->ls_requestqueue_mutex);
        mutex_init(&ls->ls_clear_proc_locks);
index 9e9d2e82f40fb36a62307e92b5ab48285a3c4654..58bf3f5cdbe25ac6cbd2c527be2df7c286d01ede 100644 (file)
@@ -334,18 +334,8 @@ static void close_connection(struct connection *con, bool and_other)
                con->rx_page = NULL;
        }
 
-       /* If we are an 'othercon' then NULL the pointer to us
-          from the parent and tidy ourself up */
-       if (test_bit(CF_IS_OTHERCON, &con->flags)) {
-               struct connection *parent = __nodeid2con(con->nodeid, 0);
-               parent->othercon = NULL;
-               kmem_cache_free(con_cache, con);
-       }
-       else {
-               /* Parent connections get reused */
-               con->retries = 0;
-               mutex_unlock(&con->sock_mutex);
-       }
+       con->retries = 0;
+       mutex_unlock(&con->sock_mutex);
 }
 
 /* We only send shutdown messages to nodes that are not part of the cluster */
@@ -731,6 +721,8 @@ static int tcp_accept_from_sock(struct connection *con)
                        INIT_WORK(&othercon->swork, process_send_sockets);
                        INIT_WORK(&othercon->rwork, process_recv_sockets);
                        set_bit(CF_IS_OTHERCON, &othercon->flags);
+               }
+               if (!othercon->sock) {
                        newcon->othercon = othercon;
                        othercon->sock = newsock;
                        newsock->sk->sk_user_data = othercon;
@@ -1272,14 +1264,15 @@ static void send_to_sock(struct connection *con)
                if (len) {
                        ret = sendpage(con->sock, e->page, offset, len,
                                       msg_flags);
-                       if (ret == -EAGAIN || ret == 0)
+                       if (ret == -EAGAIN || ret == 0) {
+                               cond_resched();
                                goto out;
+                       }
                        if (ret <= 0)
                                goto send_error;
-               } else {
+               }
                        /* Don't starve people filling buffers */
                        cond_resched();
-               }
 
                spin_lock(&con->writequeue_lock);
                e->offset += ret;
index d09977528f692c7e133a9d7702cae88411536e75..e9cdcab306e2a06037c4e0c32ac1c0e7be3097dc 100644 (file)
 #include "rcom.h"
 #include "config.h"
 
-/*
- * Following called by dlm_recoverd thread
- */
-
 static void add_ordered_member(struct dlm_ls *ls, struct dlm_member *new)
 {
        struct dlm_member *memb = NULL;
@@ -250,18 +246,30 @@ int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv, int *neg_out)
        return error;
 }
 
-/*
- * Following called from lockspace.c
- */
+/* Userspace guarantees that dlm_ls_stop() has completed on all nodes before
+   dlm_ls_start() is called on any of them to start the new recovery. */
 
 int dlm_ls_stop(struct dlm_ls *ls)
 {
        int new;
 
        /*
-        * A stop cancels any recovery that's in progress (see RECOVERY_STOP,
-        * dlm_recovery_stopped()) and prevents any new locks from being
-        * processed (see RUNNING, dlm_locking_stopped()).
+        * Prevent dlm_recv from being in the middle of something when we do
+        * the stop.  This includes ensuring dlm_recv isn't processing a
+        * recovery message (rcom), while dlm_recoverd is aborting and
+        * resetting things from an in-progress recovery.  i.e. we want
+        * dlm_recoverd to abort its recovery without worrying about dlm_recv
+        * processing an rcom at the same time.  Stopping dlm_recv also makes
+        * it easy for dlm_receive_message() to check locking stopped and add a
+        * message to the requestqueue without races.
+        */
+
+       down_write(&ls->ls_recv_active);
+
+       /*
+        * Abort any recovery that's in progress (see RECOVERY_STOP,
+        * dlm_recovery_stopped()) and tell any other threads running in the
+        * dlm to quit any processing (see RUNNING, dlm_locking_stopped()).
         */
 
        spin_lock(&ls->ls_recover_lock);
@@ -270,9 +278,15 @@ int dlm_ls_stop(struct dlm_ls *ls)
        ls->ls_recover_seq++;
        spin_unlock(&ls->ls_recover_lock);
 
+       /*
+        * Let dlm_recv run again, now any normal messages will be saved on the
+        * requestqueue for later.
+        */
+
+       up_write(&ls->ls_recv_active);
+
        /*
         * This in_recovery lock does two things:
-        *
         * 1) Keeps this function from returning until all threads are out
         *    of locking routines and locking is truely stopped.
         * 2) Keeps any new requests from being processed until it's unlocked
@@ -284,9 +298,8 @@ int dlm_ls_stop(struct dlm_ls *ls)
 
        /*
         * The recoverd suspend/resume makes sure that dlm_recoverd (if
-        * running) has noticed the clearing of RUNNING above and quit
-        * processing the previous recovery.  This will be true for all nodes
-        * before any nodes start the new recovery.
+        * running) has noticed RECOVERY_STOP above and quit processing the
+        * previous recovery.
         */
 
        dlm_recoverd_suspend(ls);
index a5126e0c68a69e6983e7d77833586bd928e7a3a7..f8c69dda16a080af8e960f2111772bed46d2c8c2 100644 (file)
@@ -2,7 +2,7 @@
 *******************************************************************************
 **
 **  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
-**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2004-2007 Red Hat, Inc.  All rights reserved.
 **
 **  This copyrighted material is made available to anyone wishing to use,
 **  modify, copy, or redistribute it subject to the terms and conditions
@@ -27,7 +27,6 @@
 #include "dlm_internal.h"
 #include "lowcomms.h"
 #include "config.h"
-#include "rcom.h"
 #include "lock.h"
 #include "midcomms.h"
 
@@ -117,19 +116,7 @@ int dlm_process_incoming_buffer(int nodeid, const void *base,
                offset &= (limit - 1);
                len -= msglen;
 
-               switch (msg->h_cmd) {
-               case DLM_MSG:
-                       dlm_receive_message(msg, nodeid, 0);
-                       break;
-
-               case DLM_RCOM:
-                       dlm_receive_rcom(msg, nodeid);
-                       break;
-
-               default:
-                       log_print("unknown msg type %x from %u: %u %u %u %u",
-                                 msg->h_cmd, nodeid, msglen, len, offset, ret);
-               }
+               dlm_receive_buffer(msg, nodeid);
        }
 
        if (msg != (struct dlm_header *) __tmp)
index 188b91c027e4b16a811c30b398654018ad63a771..ae2fd97fa4adc8392b720f1e455e4a53968c8d0c 100644 (file)
@@ -2,7 +2,7 @@
 *******************************************************************************
 **
 **  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
-**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2005-2007 Red Hat, Inc.  All rights reserved.
 **
 **  This copyrighted material is made available to anyone wishing to use,
 **  modify, copy, or redistribute it subject to the terms and conditions
@@ -386,7 +386,10 @@ static void receive_rcom_lock_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in)
        dlm_recover_process_copy(ls, rc_in);
 }
 
-static int send_ls_not_ready(int nodeid, struct dlm_rcom *rc_in)
+/* If the lockspace doesn't exist then still send a status message
+   back; it's possible that it just doesn't have its global_id yet. */
+
+int dlm_send_ls_not_ready(int nodeid, struct dlm_rcom *rc_in)
 {
        struct dlm_rcom *rc;
        struct rcom_config *rf;
@@ -446,28 +449,11 @@ static int is_old_reply(struct dlm_ls *ls, struct dlm_rcom *rc)
        return rv;
 }
 
-/* Called by dlm_recvd; corresponds to dlm_receive_message() but special
+/* Called by dlm_recv; corresponds to dlm_receive_message() but special
    recovery-only comms are sent through here. */
 
-void dlm_receive_rcom(struct dlm_header *hd, int nodeid)
+void dlm_receive_rcom(struct dlm_ls *ls, struct dlm_rcom *rc, int nodeid)
 {
-       struct dlm_rcom *rc = (struct dlm_rcom *) hd;
-       struct dlm_ls *ls;
-
-       dlm_rcom_in(rc);
-
-       /* If the lockspace doesn't exist then still send a status message
-          back; it's possible that it just doesn't have its global_id yet. */
-
-       ls = dlm_find_lockspace_global(hd->h_lockspace);
-       if (!ls) {
-               log_print("lockspace %x from %d type %x not found",
-                         hd->h_lockspace, nodeid, rc->rc_type);
-               if (rc->rc_type == DLM_RCOM_STATUS)
-                       send_ls_not_ready(nodeid, rc);
-               return;
-       }
-
        if (dlm_recovery_stopped(ls) && (rc->rc_type != DLM_RCOM_STATUS)) {
                log_debug(ls, "ignoring recovery message %x from %d",
                          rc->rc_type, nodeid);
@@ -477,12 +463,6 @@ void dlm_receive_rcom(struct dlm_header *hd, int nodeid)
        if (is_old_reply(ls, rc))
                goto out;
 
-       if (nodeid != rc->rc_header.h_nodeid) {
-               log_error(ls, "bad rcom nodeid %d from %d",
-                         rc->rc_header.h_nodeid, nodeid);
-               goto out;
-       }
-
        switch (rc->rc_type) {
        case DLM_RCOM_STATUS:
                receive_rcom_status(ls, rc);
@@ -520,6 +500,6 @@ void dlm_receive_rcom(struct dlm_header *hd, int nodeid)
                DLM_ASSERT(0, printk("rc_type=%x\n", rc->rc_type););
        }
  out:
-       dlm_put_lockspace(ls);
+       return;
 }
 
index d7984321ff4152d5030094f78b113e28a618f195..b09abd29ba38cfc3ff64dd2666f3945054520c62 100644 (file)
@@ -2,7 +2,7 @@
 *******************************************************************************
 **
 **  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
-**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2005-2007 Red Hat, Inc.  All rights reserved.
 **
 **  This copyrighted material is made available to anyone wishing to use,
 **  modify, copy, or redistribute it subject to the terms and conditions
@@ -18,7 +18,8 @@ int dlm_rcom_status(struct dlm_ls *ls, int nodeid);
 int dlm_rcom_names(struct dlm_ls *ls, int nodeid, char *last_name,int last_len);
 int dlm_send_rcom_lookup(struct dlm_rsb *r, int dir_nodeid);
 int dlm_send_rcom_lock(struct dlm_rsb *r, struct dlm_lkb *lkb);
-void dlm_receive_rcom(struct dlm_header *hd, int nodeid);
+void dlm_receive_rcom(struct dlm_ls *ls, struct dlm_rcom *rc, int nodeid);
+int dlm_send_ls_not_ready(int nodeid, struct dlm_rcom *rc_in);
 
 #endif
 
index 66575997861cad1da5e02e9528deaaf6240751b7..4b89e20eebe702f32a9214d2f377e1efc2768001 100644 (file)
 
 
 /* If the start for which we're re-enabling locking (seq) has been superseded
-   by a newer stop (ls_recover_seq), we need to leave locking disabled. */
+   by a newer stop (ls_recover_seq), we need to leave locking disabled.
+
+   We suspend dlm_recv threads here to avoid the race where dlm_recv a) sees
+   locking stopped and b) adds a message to the requestqueue, but dlm_recoverd
+   enables locking and clears the requestqueue between a and b. */
 
 static int enable_locking(struct dlm_ls *ls, uint64_t seq)
 {
        int error = -EINTR;
 
+       down_write(&ls->ls_recv_active);
+
        spin_lock(&ls->ls_recover_lock);
        if (ls->ls_recover_seq == seq) {
                set_bit(LSFL_RUNNING, &ls->ls_flags);
+               /* unblocks processes waiting to enter the dlm */
                up_write(&ls->ls_in_recovery);
                error = 0;
        }
        spin_unlock(&ls->ls_recover_lock);
+
+       up_write(&ls->ls_recv_active);
        return error;
 }
 
index 65008d79c96d2e651091dbd7bcbe47f1e17221ec..0de04f17cceaeec20383d5613e9fd17152e5df10 100644 (file)
@@ -1,7 +1,7 @@
 /******************************************************************************
 *******************************************************************************
 **
-**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2005-2007 Red Hat, Inc.  All rights reserved.
 **
 **  This copyrighted material is made available to anyone wishing to use,
 **  modify, copy, or redistribute it subject to the terms and conditions
@@ -20,7 +20,7 @@
 struct rq_entry {
        struct list_head list;
        int nodeid;
-       char request[1];
+       char request[0];
 };
 
 /*
@@ -30,42 +30,39 @@ struct rq_entry {
  * lockspace is enabled on some while still suspended on others.
  */
 
-int dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_header *hd)
+void dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_header *hd)
 {
        struct rq_entry *e;
        int length = hd->h_length;
-       int rv = 0;
 
        e = kmalloc(sizeof(struct rq_entry) + length, GFP_KERNEL);
        if (!e) {
-               log_print("dlm_add_requestqueue: out of memory\n");
-               return 0;
+               log_print("dlm_add_requestqueue: out of memory len %d", length);
+               return;
        }
 
        e->nodeid = nodeid;
        memcpy(e->request, hd, length);
 
-       /* We need to check dlm_locking_stopped() after taking the mutex to
-          avoid a race where dlm_recoverd enables locking and runs
-          process_requestqueue between our earlier dlm_locking_stopped check
-          and this addition to the requestqueue. */
-
        mutex_lock(&ls->ls_requestqueue_mutex);
-       if (dlm_locking_stopped(ls))
-               list_add_tail(&e->list, &ls->ls_requestqueue);
-       else {
-               log_debug(ls, "dlm_add_requestqueue skip from %d", nodeid);
-               kfree(e);
-               rv = -EAGAIN;
-       }
+       list_add_tail(&e->list, &ls->ls_requestqueue);
        mutex_unlock(&ls->ls_requestqueue_mutex);
-       return rv;
 }
 
+/*
+ * Called by dlm_recoverd to process normal messages saved while recovery was
+ * happening.  Normal locking has been enabled before this is called.  dlm_recv
+ * upon receiving a message, will wait for all saved messages to be drained
+ * here before processing the message it got.  If a new dlm_ls_stop() arrives
+ * while we're processing these saved messages, it may block trying to suspend
+ * dlm_recv if dlm_recv is waiting for us in dlm_wait_requestqueue.  In that
+ * case, we don't abort since locking_stopped is still 0.  If dlm_recv is not
+ * waiting for us, then this processing may be aborted due to locking_stopped.
+ */
+
 int dlm_process_requestqueue(struct dlm_ls *ls)
 {
        struct rq_entry *e;
-       struct dlm_header *hd;
        int error = 0;
 
        mutex_lock(&ls->ls_requestqueue_mutex);
@@ -79,14 +76,7 @@ int dlm_process_requestqueue(struct dlm_ls *ls)
                e = list_entry(ls->ls_requestqueue.next, struct rq_entry, list);
                mutex_unlock(&ls->ls_requestqueue_mutex);
 
-               hd = (struct dlm_header *) e->request;
-               error = dlm_receive_message(hd, e->nodeid, 1);
-
-               if (error == -EINTR) {
-                       /* entry is left on requestqueue */
-                       log_debug(ls, "process_requestqueue abort eintr");
-                       break;
-               }
+               dlm_receive_message_saved(ls, (struct dlm_message *)e->request);
 
                mutex_lock(&ls->ls_requestqueue_mutex);
                list_del(&e->list);
@@ -106,10 +96,12 @@ int dlm_process_requestqueue(struct dlm_ls *ls)
 
 /*
  * After recovery is done, locking is resumed and dlm_recoverd takes all the
- * saved requests and processes them as they would have been by dlm_recvd.  At
- * the same time, dlm_recvd will start receiving new requests from remote
- * nodes.  We want to delay dlm_recvd processing new requests until
- * dlm_recoverd has finished processing the old saved requests.
+ * saved requests and processes them as they would have been by dlm_recv.  At
+ * the same time, dlm_recv will start receiving new requests from remote nodes.
+ * We want to delay dlm_recv processing new requests until dlm_recoverd has
+ * finished processing the old saved requests.  We don't check for locking
+ * stopped here because dlm_ls_stop won't stop locking until it's suspended us
+ * (dlm_recv).
  */
 
 void dlm_wait_requestqueue(struct dlm_ls *ls)
@@ -118,8 +110,6 @@ void dlm_wait_requestqueue(struct dlm_ls *ls)
                mutex_lock(&ls->ls_requestqueue_mutex);
                if (list_empty(&ls->ls_requestqueue))
                        break;
-               if (dlm_locking_stopped(ls))
-                       break;
                mutex_unlock(&ls->ls_requestqueue_mutex);
                schedule();
        }
index 6a53ea03335dae50b9d22f1c0c156ff01dfd581d..aba34fc05ee442ba98eb47e14c87b5d3530d67a4 100644 (file)
@@ -1,7 +1,7 @@
 /******************************************************************************
 *******************************************************************************
 **
-**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2005-2007 Red Hat, Inc.  All rights reserved.
 **
 **  This copyrighted material is made available to anyone wishing to use,
 **  modify, copy, or redistribute it subject to the terms and conditions
@@ -13,7 +13,7 @@
 #ifndef __REQUESTQUEUE_DOT_H__
 #define __REQUESTQUEUE_DOT_H__
 
-int dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_header *hd);
+void dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_header *hd);
 int dlm_process_requestqueue(struct dlm_ls *ls);
 void dlm_wait_requestqueue(struct dlm_ls *ls);
 void dlm_purge_requestqueue(struct dlm_ls *ls);
index cd805a66880ddd3f24459be574bd868d29f2d801..93fa427bb5f501cee6da6ab88afbfd921f584295 100644 (file)
@@ -93,9 +93,10 @@ static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh,
                map_bh(bh, inode->i_sb, block);
 
        set_buffer_uptodate(bh);
+       if (!gfs2_is_jdata(ip))
+               mark_buffer_dirty(bh);
        if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip))
                gfs2_trans_add_bh(ip->i_gl, bh, 0);
-       mark_buffer_dirty(bh);
 
        if (release) {
                unlock_page(page);
@@ -1085,6 +1086,33 @@ static int do_shrink(struct gfs2_inode *ip, u64 size)
        return error;
 }
 
+static int do_touch(struct gfs2_inode *ip, u64 size)
+{
+       struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+       struct buffer_head *dibh;
+       int error;
+
+       error = gfs2_trans_begin(sdp, RES_DINODE, 0);
+       if (error)
+               return error;
+
+       down_write(&ip->i_rw_mutex);
+
+       error = gfs2_meta_inode_buffer(ip, &dibh);
+       if (error)
+               goto do_touch_out;
+
+       ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME;
+       gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+       gfs2_dinode_out(ip, dibh->b_data);
+       brelse(dibh);
+
+do_touch_out:
+       up_write(&ip->i_rw_mutex);
+       gfs2_trans_end(sdp);
+       return error;
+}
+
 /**
  * gfs2_truncatei - make a file a given size
  * @ip: the inode
@@ -1105,8 +1133,11 @@ int gfs2_truncatei(struct gfs2_inode *ip, u64 size)
 
        if (size > ip->i_di.di_size)
                error = do_grow(ip, size);
-       else
+       else if (size < ip->i_di.di_size)
                error = do_shrink(ip, size);
+       else
+               /* update time stamps */
+               error = do_touch(ip, size);
 
        return error;
 }
index 3548d9f31e0d5c6918d74115a5fd0f9f2b133f48..3731ab0771d511ada7a2e6fbfceecb174b4075ee 100644 (file)
 
    The kthread functions used to start these daemons block and flush signals. */
 
-/**
- * gfs2_scand - Look for cached glocks and inodes to toss from memory
- * @sdp: Pointer to GFS2 superblock
- *
- * One of these daemons runs, finding candidates to add to sd_reclaim_list.
- * See gfs2_glockd()
- */
-
-int gfs2_scand(void *data)
-{
-       struct gfs2_sbd *sdp = data;
-       unsigned long t;
-
-       while (!kthread_should_stop()) {
-               gfs2_scand_internal(sdp);
-               t = gfs2_tune_get(sdp, gt_scand_secs) * HZ;
-               if (freezing(current))
-                       refrigerator();
-               schedule_timeout_interruptible(t);
-       }
-
-       return 0;
-}
-
 /**
  * gfs2_glockd - Reclaim unused glock structures
  * @sdp: Pointer to GFS2 superblock
index 801007120fb266a6c7bd22bddedfe0743cb045e2..0de9b35579555dcaabf74378bd6ee7fc465d971b 100644 (file)
@@ -10,7 +10,6 @@
 #ifndef __DAEMON_DOT_H__
 #define __DAEMON_DOT_H__
 
-int gfs2_scand(void *data);
 int gfs2_glockd(void *data);
 int gfs2_recoverd(void *data);
 int gfs2_logd(void *data);
index 2beb2f401aa24a2b23cf511d813d21db06e521b7..9949bb746a52e2b0975c466e1b2bd9fe6b963766 100644 (file)
@@ -1043,6 +1043,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name)
 
        error = gfs2_meta_inode_buffer(dip, &dibh);
        if (!gfs2_assert_withdraw(GFS2_SB(&dip->i_inode), !error)) {
+               gfs2_trans_add_bh(dip->i_gl, dibh, 1);
                dip->i_di.di_blocks++;
                gfs2_set_inode_blocks(&dip->i_inode);
                gfs2_dinode_out(dip, dibh->b_data);
@@ -1501,7 +1502,7 @@ struct inode *gfs2_dir_search(struct inode *dir, const struct qstr *name)
                inode = gfs2_inode_lookup(dir->i_sb, 
                                be16_to_cpu(dent->de_type),
                                be64_to_cpu(dent->de_inum.no_addr),
-                               be64_to_cpu(dent->de_inum.no_formal_ino));
+                               be64_to_cpu(dent->de_inum.no_formal_ino), 0);
                brelse(bh);
                return inode;
        }
index 1ab3e9d73886b19ada397b91516e5d39cff1f5bd..aa8dbf303f6d57185c83f40dc270759390fd0642 100644 (file)
@@ -200,28 +200,28 @@ static int security_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er)
        return gfs2_ea_remove_i(ip, er);
 }
 
-static struct gfs2_eattr_operations gfs2_user_eaops = {
+static const struct gfs2_eattr_operations gfs2_user_eaops = {
        .eo_get = user_eo_get,
        .eo_set = user_eo_set,
        .eo_remove = user_eo_remove,
        .eo_name = "user",
 };
 
-struct gfs2_eattr_operations gfs2_system_eaops = {
+const struct gfs2_eattr_operations gfs2_system_eaops = {
        .eo_get = system_eo_get,
        .eo_set = system_eo_set,
        .eo_remove = system_eo_remove,
        .eo_name = "system",
 };
 
-static struct gfs2_eattr_operations gfs2_security_eaops = {
+static const struct gfs2_eattr_operations gfs2_security_eaops = {
        .eo_get = security_eo_get,
        .eo_set = security_eo_set,
        .eo_remove = security_eo_remove,
        .eo_name = "security",
 };
 
-struct gfs2_eattr_operations *gfs2_ea_ops[] = {
+const struct gfs2_eattr_operations *gfs2_ea_ops[] = {
        NULL,
        &gfs2_user_eaops,
        &gfs2_system_eaops,
index 508b4f7a24494deddf21f86205d7bb00d1f6f997..da2f7fbbb40d9fe2aaf96c429693ff52d5dbb67e 100644 (file)
@@ -22,9 +22,9 @@ struct gfs2_eattr_operations {
 
 unsigned int gfs2_ea_name2type(const char *name, const char **truncated_name);
 
-extern struct gfs2_eattr_operations gfs2_system_eaops;
+extern const struct gfs2_eattr_operations gfs2_system_eaops;
 
-extern struct gfs2_eattr_operations *gfs2_ea_ops[];
+extern const struct gfs2_eattr_operations *gfs2_ea_ops[];
 
 #endif /* __EAOPS_DOT_H__ */
 
index 3f0974e1afef8bbd2b706a418f616f38e2817f71..a37efe4aae6f37d4812be6490e3379e129658c31 100644 (file)
 #include <asm/uaccess.h>
 #include <linux/seq_file.h>
 #include <linux/debugfs.h>
-#include <linux/module.h>
-#include <linux/kallsyms.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/workqueue.h>
+#include <linux/jiffies.h>
 
 #include "gfs2.h"
 #include "incore.h"
@@ -48,7 +50,6 @@ struct glock_iter {
        int hash;                     /* hash bucket index         */
        struct gfs2_sbd *sdp;         /* incore superblock         */
        struct gfs2_glock *gl;        /* current glock struct      */
-       struct hlist_head *hb_list;   /* current hash bucket ptr   */
        struct seq_file *seq;         /* sequence file for debugfs */
        char string[512];             /* scratch space             */
 };
@@ -59,8 +60,13 @@ static int gfs2_dump_lockstate(struct gfs2_sbd *sdp);
 static int dump_glock(struct glock_iter *gi, struct gfs2_glock *gl);
 static void gfs2_glock_xmote_th(struct gfs2_glock *gl, struct gfs2_holder *gh);
 static void gfs2_glock_drop_th(struct gfs2_glock *gl);
+static void run_queue(struct gfs2_glock *gl);
+
 static DECLARE_RWSEM(gfs2_umount_flush_sem);
 static struct dentry *gfs2_root;
+static struct task_struct *scand_process;
+static unsigned int scand_secs = 5;
+static struct workqueue_struct *glock_workqueue;
 
 #define GFS2_GL_HASH_SHIFT      15
 #define GFS2_GL_HASH_SIZE       (1 << GFS2_GL_HASH_SHIFT)
@@ -276,6 +282,18 @@ static struct gfs2_glock *gfs2_glock_find(const struct gfs2_sbd *sdp,
        return gl;
 }
 
+static void glock_work_func(struct work_struct *work)
+{
+       struct gfs2_glock *gl = container_of(work, struct gfs2_glock, gl_work.work);
+
+       spin_lock(&gl->gl_spin);
+       if (test_and_clear_bit(GLF_PENDING_DEMOTE, &gl->gl_flags))
+               set_bit(GLF_DEMOTE, &gl->gl_flags);
+       run_queue(gl);
+       spin_unlock(&gl->gl_spin);
+       gfs2_glock_put(gl);
+}
+
 /**
  * gfs2_glock_get() - Get a glock, or create one if one doesn't exist
  * @sdp: The GFS2 superblock
@@ -315,6 +333,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
        gl->gl_name = name;
        atomic_set(&gl->gl_ref, 1);
        gl->gl_state = LM_ST_UNLOCKED;
+       gl->gl_demote_state = LM_ST_EXCLUSIVE;
        gl->gl_hash = hash;
        gl->gl_owner_pid = 0;
        gl->gl_ip = 0;
@@ -323,10 +342,12 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
        gl->gl_req_bh = NULL;
        gl->gl_vn = 0;
        gl->gl_stamp = jiffies;
+       gl->gl_tchange = jiffies;
        gl->gl_object = NULL;
        gl->gl_sbd = sdp;
        gl->gl_aspace = NULL;
        lops_init_le(&gl->gl_le, &gfs2_glock_lops);
+       INIT_DELAYED_WORK(&gl->gl_work, glock_work_func);
 
        /* If this glock protects actual on-disk data or metadata blocks,
           create a VFS inode to manage the pages/buffers holding them. */
@@ -440,6 +461,8 @@ static void wait_on_holder(struct gfs2_holder *gh)
 
 static void gfs2_demote_wake(struct gfs2_glock *gl)
 {
+       BUG_ON(!spin_is_locked(&gl->gl_spin));
+       gl->gl_demote_state = LM_ST_EXCLUSIVE;
         clear_bit(GLF_DEMOTE, &gl->gl_flags);
         smp_mb__after_clear_bit();
         wake_up_bit(&gl->gl_flags, GLF_DEMOTE);
@@ -545,12 +568,14 @@ static int rq_demote(struct gfs2_glock *gl)
                return 0;
        }
        set_bit(GLF_LOCK, &gl->gl_flags);
-       spin_unlock(&gl->gl_spin);
        if (gl->gl_demote_state == LM_ST_UNLOCKED ||
-           gl->gl_state != LM_ST_EXCLUSIVE)
+           gl->gl_state != LM_ST_EXCLUSIVE) {
+               spin_unlock(&gl->gl_spin);
                gfs2_glock_drop_th(gl);
-       else
+       } else {
+               spin_unlock(&gl->gl_spin);
                gfs2_glock_xmote_th(gl, NULL);
+       }
        spin_lock(&gl->gl_spin);
 
        return 0;
@@ -679,24 +704,25 @@ static void gfs2_glmutex_unlock(struct gfs2_glock *gl)
  * practise: LM_ST_SHARED and LM_ST_UNLOCKED
  */
 
-static void handle_callback(struct gfs2_glock *gl, unsigned int state, int remote)
+static void handle_callback(struct gfs2_glock *gl, unsigned int state,
+                           int remote, unsigned long delay)
 {
+       int bit = delay ? GLF_PENDING_DEMOTE : GLF_DEMOTE;
+
        spin_lock(&gl->gl_spin);
-       if (test_and_set_bit(GLF_DEMOTE, &gl->gl_flags) == 0) {
+       set_bit(bit, &gl->gl_flags);
+       if (gl->gl_demote_state == LM_ST_EXCLUSIVE) {
                gl->gl_demote_state = state;
                gl->gl_demote_time = jiffies;
                if (remote && gl->gl_ops->go_type == LM_TYPE_IOPEN &&
                    gl->gl_object) {
-                       struct inode *inode = igrab(gl->gl_object);
+                       gfs2_glock_schedule_for_reclaim(gl);
                        spin_unlock(&gl->gl_spin);
-                       if (inode) {
-                               d_prune_aliases(inode);
-                               iput(inode);
-                       }
                        return;
                }
-       } else if (gl->gl_demote_state != LM_ST_UNLOCKED) {
-               gl->gl_demote_state = state;
+       } else if (gl->gl_demote_state != LM_ST_UNLOCKED &&
+                       gl->gl_demote_state != state) {
+               gl->gl_demote_state = LM_ST_UNLOCKED;
        }
        spin_unlock(&gl->gl_spin);
 }
@@ -723,6 +749,7 @@ static void state_change(struct gfs2_glock *gl, unsigned int new_state)
        }
 
        gl->gl_state = new_state;
+       gl->gl_tchange = jiffies;
 }
 
 /**
@@ -760,10 +787,20 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret)
 
        if (!gh) {
                gl->gl_stamp = jiffies;
-               if (ret & LM_OUT_CANCELED)
+               if (ret & LM_OUT_CANCELED) {
                        op_done = 0;
-               else
+               } else {
+                       spin_lock(&gl->gl_spin);
+                       if (gl->gl_state != gl->gl_demote_state) {
+                               gl->gl_req_bh = NULL;
+                               spin_unlock(&gl->gl_spin);
+                               gfs2_glock_drop_th(gl);
+                               gfs2_glock_put(gl);
+                               return;
+                       }
                        gfs2_demote_wake(gl);
+                       spin_unlock(&gl->gl_spin);
+               }
        } else {
                spin_lock(&gl->gl_spin);
                list_del_init(&gh->gh_list);
@@ -799,7 +836,6 @@ out:
                gl->gl_req_gh = NULL;
                gl->gl_req_bh = NULL;
                clear_bit(GLF_LOCK, &gl->gl_flags);
-               run_queue(gl);
                spin_unlock(&gl->gl_spin);
        }
 
@@ -817,7 +853,7 @@ out:
  *
  */
 
-void gfs2_glock_xmote_th(struct gfs2_glock *gl, struct gfs2_holder *gh)
+static void gfs2_glock_xmote_th(struct gfs2_glock *gl, struct gfs2_holder *gh)
 {
        struct gfs2_sbd *sdp = gl->gl_sbd;
        int flags = gh ? gh->gh_flags : 0;
@@ -871,7 +907,6 @@ static void drop_bh(struct gfs2_glock *gl, unsigned int ret)
        gfs2_assert_warn(sdp, !ret);
 
        state_change(gl, LM_ST_UNLOCKED);
-       gfs2_demote_wake(gl);
 
        if (glops->go_inval)
                glops->go_inval(gl, DIO_METADATA);
@@ -884,10 +919,10 @@ static void drop_bh(struct gfs2_glock *gl, unsigned int ret)
        }
 
        spin_lock(&gl->gl_spin);
+       gfs2_demote_wake(gl);
        gl->gl_req_gh = NULL;
        gl->gl_req_bh = NULL;
        clear_bit(GLF_LOCK, &gl->gl_flags);
-       run_queue(gl);
        spin_unlock(&gl->gl_spin);
 
        gfs2_glock_put(gl);
@@ -1067,24 +1102,31 @@ static void add_to_queue(struct gfs2_holder *gh)
        if (test_and_set_bit(HIF_WAIT, &gh->gh_iflags))
                BUG();
 
-       existing = find_holder_by_owner(&gl->gl_holders, gh->gh_owner_pid);
-       if (existing) {
-               print_symbol(KERN_WARNING "original: %s\n", existing->gh_ip);
-               printk(KERN_INFO "pid : %d\n", existing->gh_owner_pid);
-               printk(KERN_INFO "lock type : %d lock state : %d\n",
-                               existing->gh_gl->gl_name.ln_type, existing->gh_gl->gl_state);
-               print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip);
-               printk(KERN_INFO "pid : %d\n", gh->gh_owner_pid);
-               printk(KERN_INFO "lock type : %d lock state : %d\n",
-                               gl->gl_name.ln_type, gl->gl_state);
-               BUG();
-       }
-
-       existing = find_holder_by_owner(&gl->gl_waiters3, gh->gh_owner_pid);
-       if (existing) {
-               print_symbol(KERN_WARNING "original: %s\n", existing->gh_ip);
-               print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip);
-               BUG();
+       if (!(gh->gh_flags & GL_FLOCK)) {
+               existing = find_holder_by_owner(&gl->gl_holders, 
+                                               gh->gh_owner_pid);
+               if (existing) {
+                       print_symbol(KERN_WARNING "original: %s\n", 
+                                    existing->gh_ip);
+                       printk(KERN_INFO "pid : %d\n", existing->gh_owner_pid);
+                       printk(KERN_INFO "lock type : %d lock state : %d\n",
+                              existing->gh_gl->gl_name.ln_type, 
+                              existing->gh_gl->gl_state);
+                       print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip);
+                       printk(KERN_INFO "pid : %d\n", gh->gh_owner_pid);
+                       printk(KERN_INFO "lock type : %d lock state : %d\n",
+                              gl->gl_name.ln_type, gl->gl_state);
+                       BUG();
+               }
+               
+               existing = find_holder_by_owner(&gl->gl_waiters3, 
+                                               gh->gh_owner_pid);
+               if (existing) {
+                       print_symbol(KERN_WARNING "original: %s\n", 
+                                    existing->gh_ip);
+                       print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip);
+                       BUG();
+               }
        }
 
        if (gh->gh_flags & LM_FLAG_PRIORITY)
@@ -1195,9 +1237,10 @@ void gfs2_glock_dq(struct gfs2_holder *gh)
 {
        struct gfs2_glock *gl = gh->gh_gl;
        const struct gfs2_glock_operations *glops = gl->gl_ops;
+       unsigned delay = 0;
 
        if (gh->gh_flags & GL_NOCACHE)
-               handle_callback(gl, LM_ST_UNLOCKED, 0);
+               handle_callback(gl, LM_ST_UNLOCKED, 0, 0);
 
        gfs2_glmutex_lock(gl);
 
@@ -1215,8 +1258,14 @@ void gfs2_glock_dq(struct gfs2_holder *gh)
        }
 
        clear_bit(GLF_LOCK, &gl->gl_flags);
-       run_queue(gl);
        spin_unlock(&gl->gl_spin);
+
+       gfs2_glock_hold(gl);
+       if (test_bit(GLF_PENDING_DEMOTE, &gl->gl_flags) &&
+           !test_bit(GLF_DEMOTE, &gl->gl_flags))
+               delay = gl->gl_ops->go_min_hold_time;
+       if (queue_delayed_work(glock_workqueue, &gl->gl_work, delay) == 0)
+               gfs2_glock_put(gl);
 }
 
 void gfs2_glock_dq_wait(struct gfs2_holder *gh)
@@ -1443,18 +1492,21 @@ static void blocking_cb(struct gfs2_sbd *sdp, struct lm_lockname *name,
                        unsigned int state)
 {
        struct gfs2_glock *gl;
+       unsigned long delay = 0;
+       unsigned long holdtime;
+       unsigned long now = jiffies;
 
        gl = gfs2_glock_find(sdp, name);
        if (!gl)
                return;
 
-       handle_callback(gl, state, 1);
-
-       spin_lock(&gl->gl_spin);
-       run_queue(gl);
-       spin_unlock(&gl->gl_spin);
+       holdtime = gl->gl_tchange + gl->gl_ops->go_min_hold_time;
+       if (time_before(now, holdtime))
+               delay = holdtime - now;
 
-       gfs2_glock_put(gl);
+       handle_callback(gl, state, 1, delay);
+       if (queue_delayed_work(glock_workqueue, &gl->gl_work, delay) == 0)
+               gfs2_glock_put(gl);
 }
 
 /**
@@ -1495,7 +1547,8 @@ void gfs2_glock_cb(void *cb_data, unsigned int type, void *data)
                        return;
                if (!gfs2_assert_warn(sdp, gl->gl_req_bh))
                        gl->gl_req_bh(gl, async->lc_ret);
-               gfs2_glock_put(gl);
+               if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0)
+                       gfs2_glock_put(gl);
                up_read(&gfs2_umount_flush_sem);
                return;
        }
@@ -1588,7 +1641,7 @@ void gfs2_reclaim_glock(struct gfs2_sbd *sdp)
        if (gfs2_glmutex_trylock(gl)) {
                if (list_empty(&gl->gl_holders) &&
                    gl->gl_state != LM_ST_UNLOCKED && demote_ok(gl))
-                       handle_callback(gl, LM_ST_UNLOCKED, 0);
+                       handle_callback(gl, LM_ST_UNLOCKED, 0, 0);
                gfs2_glmutex_unlock(gl);
        }
 
@@ -1617,7 +1670,7 @@ static int examine_bucket(glock_examiner examiner, struct gfs2_sbd *sdp,
                goto out;
        gl = list_entry(head->first, struct gfs2_glock, gl_list);
        while(1) {
-               if (gl->gl_sbd == sdp) {
+               if (!sdp || gl->gl_sbd == sdp) {
                        gfs2_glock_hold(gl);
                        read_unlock(gl_lock_addr(hash));
                        if (prev)
@@ -1635,6 +1688,7 @@ out:
        read_unlock(gl_lock_addr(hash));
        if (prev)
                gfs2_glock_put(prev);
+       cond_resched();
        return has_entries;
 }
 
@@ -1662,20 +1716,6 @@ out_schedule:
        gfs2_glock_schedule_for_reclaim(gl);
 }
 
-/**
- * gfs2_scand_internal - Look for glocks and inodes to toss from memory
- * @sdp: the filesystem
- *
- */
-
-void gfs2_scand_internal(struct gfs2_sbd *sdp)
-{
-       unsigned int x;
-
-       for (x = 0; x < GFS2_GL_HASH_SIZE; x++)
-               examine_bucket(scan_glock, sdp, x);
-}
-
 /**
  * clear_glock - look at a glock and see if we can free it from glock cache
  * @gl: the glock to look at
@@ -1701,7 +1741,7 @@ static void clear_glock(struct gfs2_glock *gl)
        if (gfs2_glmutex_trylock(gl)) {
                if (list_empty(&gl->gl_holders) &&
                    gl->gl_state != LM_ST_UNLOCKED)
-                       handle_callback(gl, LM_ST_UNLOCKED, 0);
+                       handle_callback(gl, LM_ST_UNLOCKED, 0, 0);
                gfs2_glmutex_unlock(gl);
        }
 }
@@ -1843,7 +1883,7 @@ static int dump_glock(struct glock_iter *gi, struct gfs2_glock *gl)
 
        spin_lock(&gl->gl_spin);
 
-       print_dbg(gi, "Glock 0x%p (%u, %llu)\n", gl, gl->gl_name.ln_type,
+       print_dbg(gi, "Glock 0x%p (%u, 0x%llx)\n", gl, gl->gl_name.ln_type,
                   (unsigned long long)gl->gl_name.ln_number);
        print_dbg(gi, "  gl_flags =");
        for (x = 0; x < 32; x++) {
@@ -1963,6 +2003,35 @@ static int gfs2_dump_lockstate(struct gfs2_sbd *sdp)
        return error;
 }
 
+/**
+ * gfs2_scand - Look for cached glocks and inodes to toss from memory
+ * @sdp: Pointer to GFS2 superblock
+ *
+ * One of these daemons runs, finding candidates to add to sd_reclaim_list.
+ * See gfs2_glockd()
+ */
+
+static int gfs2_scand(void *data)
+{
+       unsigned x;
+       unsigned delay;
+
+       while (!kthread_should_stop()) {
+               for (x = 0; x < GFS2_GL_HASH_SIZE; x++)
+                       examine_bucket(scan_glock, NULL, x);
+               if (freezing(current))
+                       refrigerator();
+               delay = scand_secs;
+               if (delay < 1)
+                       delay = 1;
+               schedule_timeout_interruptible(delay * HZ);
+       }
+
+       return 0;
+}
+
+
+
 int __init gfs2_glock_init(void)
 {
        unsigned i;
@@ -1974,52 +2043,69 @@ int __init gfs2_glock_init(void)
                rwlock_init(&gl_hash_locks[i]);
        }
 #endif
+
+       scand_process = kthread_run(gfs2_scand, NULL, "gfs2_scand");
+       if (IS_ERR(scand_process))
+               return PTR_ERR(scand_process);
+
+       glock_workqueue = create_workqueue("glock_workqueue");
+       if (IS_ERR(glock_workqueue)) {
+               kthread_stop(scand_process);
+               return PTR_ERR(glock_workqueue);
+       }
+
        return 0;
 }
 
+void gfs2_glock_exit(void)
+{
+       destroy_workqueue(glock_workqueue);
+       kthread_stop(scand_process);
+}
+
+module_param(scand_secs, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(scand_secs, "The number of seconds between scand runs");
+
 static int gfs2_glock_iter_next(struct glock_iter *gi)
 {
+       struct gfs2_glock *gl;
+
+restart:
        read_lock(gl_lock_addr(gi->hash));
-       while (1) {
-               if (!gi->hb_list) {  /* If we don't have a hash bucket yet */
-                       gi->hb_list = &gl_hash_table[gi->hash].hb_list;
-                       if (hlist_empty(gi->hb_list)) {
-                               read_unlock(gl_lock_addr(gi->hash));
-                               gi->hash++;
-                               read_lock(gl_lock_addr(gi->hash));
-                               gi->hb_list = NULL;
-                               if (gi->hash >= GFS2_GL_HASH_SIZE) {
-                                       read_unlock(gl_lock_addr(gi->hash));
-                                       return 1;
-                               }
-                               else
-                                       continue;
-                       }
-                       if (!hlist_empty(gi->hb_list)) {
-                               gi->gl = list_entry(gi->hb_list->first,
-                                                   struct gfs2_glock,
-                                                   gl_list);
-                       }
-               } else {
-                       if (gi->gl->gl_list.next == NULL) {
-                               read_unlock(gl_lock_addr(gi->hash));
-                               gi->hash++;
-                               read_lock(gl_lock_addr(gi->hash));
-                               gi->hb_list = NULL;
-                               continue;
-                       }
-                       gi->gl = list_entry(gi->gl->gl_list.next,
-                                           struct gfs2_glock, gl_list);
-               }
+       gl = gi->gl;
+       if (gl) {
+               gi->gl = hlist_entry(gl->gl_list.next,
+                                    struct gfs2_glock, gl_list);
                if (gi->gl)
-                       break;
+                       gfs2_glock_hold(gi->gl);
        }
        read_unlock(gl_lock_addr(gi->hash));
+       if (gl)
+               gfs2_glock_put(gl);
+       if (gl && gi->gl == NULL)
+               gi->hash++;
+       while(gi->gl == NULL) {
+               if (gi->hash >= GFS2_GL_HASH_SIZE)
+                       return 1;
+               read_lock(gl_lock_addr(gi->hash));
+               gi->gl = hlist_entry(gl_hash_table[gi->hash].hb_list.first,
+                                    struct gfs2_glock, gl_list);
+               if (gi->gl)
+                       gfs2_glock_hold(gi->gl);
+               read_unlock(gl_lock_addr(gi->hash));
+               gi->hash++;
+       }
+
+       if (gi->sdp != gi->gl->gl_sbd)
+               goto restart;
+
        return 0;
 }
 
 static void gfs2_glock_iter_free(struct glock_iter *gi)
 {
+       if (gi->gl)
+               gfs2_glock_put(gi->gl);
        kfree(gi);
 }
 
@@ -2033,9 +2119,8 @@ static struct glock_iter *gfs2_glock_iter_init(struct gfs2_sbd *sdp)
 
        gi->sdp = sdp;
        gi->hash = 0;
-       gi->gl = NULL;
-       gi->hb_list = NULL;
        gi->seq = NULL;
+       gi->gl = NULL;
        memset(gi->string, 0, sizeof(gi->string));
 
        if (gfs2_glock_iter_next(gi)) {
@@ -2055,7 +2140,7 @@ static void *gfs2_glock_seq_start(struct seq_file *file, loff_t *pos)
        if (!gi)
                return NULL;
 
-       while (n--) {
+       while(n--) {
                if (gfs2_glock_iter_next(gi)) {
                        gfs2_glock_iter_free(gi);
                        return NULL;
@@ -2082,7 +2167,9 @@ static void *gfs2_glock_seq_next(struct seq_file *file, void *iter_ptr,
 
 static void gfs2_glock_seq_stop(struct seq_file *file, void *iter_ptr)
 {
-       /* nothing for now */
+       struct glock_iter *gi = iter_ptr;
+       if (gi)
+               gfs2_glock_iter_free(gi);
 }
 
 static int gfs2_glock_seq_show(struct seq_file *file, void *iter_ptr)
@@ -2095,7 +2182,7 @@ static int gfs2_glock_seq_show(struct seq_file *file, void *iter_ptr)
        return 0;
 }
 
-static struct seq_operations gfs2_glock_seq_ops = {
+static const struct seq_operations gfs2_glock_seq_ops = {
        .start = gfs2_glock_seq_start,
        .next  = gfs2_glock_seq_next,
        .stop  = gfs2_glock_seq_stop,
index 7721ca3fff9eee2c4789d141f209949a819f21e2..b16f604eea9fd6e052ac29b17766f16ad2316adb 100644 (file)
@@ -26,6 +26,7 @@
 #define GL_SKIP                        0x00000100
 #define GL_ATIME               0x00000200
 #define GL_NOCACHE             0x00000400
+#define GL_FLOCK               0x00000800
 #define GL_NOCANCEL            0x00001000
 
 #define GLR_TRYFAILED          13
@@ -132,11 +133,11 @@ void gfs2_glock_cb(void *cb_data, unsigned int type, void *data);
 
 void gfs2_glock_schedule_for_reclaim(struct gfs2_glock *gl);
 void gfs2_reclaim_glock(struct gfs2_sbd *sdp);
-
-void gfs2_scand_internal(struct gfs2_sbd *sdp);
 void gfs2_gl_hash_clear(struct gfs2_sbd *sdp, int wait);
 
 int __init gfs2_glock_init(void);
+void gfs2_glock_exit(void);
+
 int gfs2_create_debugfs_file(struct gfs2_sbd *sdp);
 void gfs2_delete_debugfs_file(struct gfs2_sbd *sdp);
 int gfs2_register_debugfs(void);
index 777ca46010e875907a49d5972f937cf5f83cdba1..4670dcb2a87734b12643e11991b817de454693a4 100644 (file)
@@ -41,7 +41,6 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl)
        struct list_head *head = &gl->gl_ail_list;
        struct gfs2_bufdata *bd;
        struct buffer_head *bh;
-       u64 blkno;
        int error;
 
        blocks = atomic_read(&gl->gl_ail_count);
@@ -57,19 +56,12 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl)
                bd = list_entry(head->next, struct gfs2_bufdata,
                                bd_ail_gl_list);
                bh = bd->bd_bh;
-               blkno = bh->b_blocknr;
+               gfs2_remove_from_ail(NULL, bd);
+               bd->bd_bh = NULL;
+               bh->b_private = NULL;
+               bd->bd_blkno = bh->b_blocknr;
                gfs2_assert_withdraw(sdp, !buffer_busy(bh));
-
-               bd->bd_ail = NULL;
-               list_del(&bd->bd_ail_st_list);
-               list_del(&bd->bd_ail_gl_list);
-               atomic_dec(&gl->gl_ail_count);
-               brelse(bh);
-               gfs2_log_unlock(sdp);
-
-               gfs2_trans_add_revoke(sdp, blkno);
-
-               gfs2_log_lock(sdp);
+               gfs2_trans_add_revoke(sdp, bd);
        }
        gfs2_assert_withdraw(sdp, !atomic_read(&gl->gl_ail_count));
        gfs2_log_unlock(sdp);
@@ -156,9 +148,11 @@ static void inode_go_sync(struct gfs2_glock *gl)
                ip = NULL;
 
        if (test_bit(GLF_DIRTY, &gl->gl_flags)) {
-               if (ip)
+               if (ip && !gfs2_is_jdata(ip))
                        filemap_fdatawrite(ip->i_inode.i_mapping);
                gfs2_log_flush(gl->gl_sbd, gl);
+               if (ip && gfs2_is_jdata(ip))
+                       filemap_fdatawrite(ip->i_inode.i_mapping);
                gfs2_meta_sync(gl);
                if (ip) {
                        struct address_space *mapping = ip->i_inode.i_mapping;
@@ -452,6 +446,7 @@ const struct gfs2_glock_operations gfs2_inode_glops = {
        .go_lock = inode_go_lock,
        .go_unlock = inode_go_unlock,
        .go_type = LM_TYPE_INODE,
+       .go_min_hold_time = HZ / 10,
 };
 
 const struct gfs2_glock_operations gfs2_rgrp_glops = {
@@ -462,6 +457,7 @@ const struct gfs2_glock_operations gfs2_rgrp_glops = {
        .go_lock = rgrp_go_lock,
        .go_unlock = rgrp_go_unlock,
        .go_type = LM_TYPE_RGRP,
+       .go_min_hold_time = HZ / 10,
 };
 
 const struct gfs2_glock_operations gfs2_trans_glops = {
index 170ba93829c037881996c944fc8ae02adfcd2c52..eaddfb5a8e6fe103c792a1f8c0c0dee411a4421b 100644 (file)
@@ -11,6 +11,7 @@
 #define __INCORE_DOT_H__
 
 #include <linux/fs.h>
+#include <linux/workqueue.h>
 
 #define DIO_WAIT       0x00000010
 #define DIO_METADATA   0x00000020
@@ -113,7 +114,13 @@ struct gfs2_bufdata {
        struct buffer_head *bd_bh;
        struct gfs2_glock *bd_gl;
 
-       struct list_head bd_list_tr;
+       union {
+               struct list_head list_tr;
+               u64 blkno;
+       } u;
+#define bd_list_tr u.list_tr
+#define bd_blkno u.blkno
+
        struct gfs2_log_element bd_le;
 
        struct gfs2_ail *bd_ail;
@@ -130,6 +137,7 @@ struct gfs2_glock_operations {
        int (*go_lock) (struct gfs2_holder *gh);
        void (*go_unlock) (struct gfs2_holder *gh);
        const int go_type;
+       const unsigned long go_min_hold_time;
 };
 
 enum {
@@ -161,6 +169,7 @@ enum {
        GLF_LOCK                = 1,
        GLF_STICKY              = 2,
        GLF_DEMOTE              = 3,
+       GLF_PENDING_DEMOTE      = 4,
        GLF_DIRTY               = 5,
 };
 
@@ -193,6 +202,7 @@ struct gfs2_glock {
 
        u64 gl_vn;
        unsigned long gl_stamp;
+       unsigned long gl_tchange;
        void *gl_object;
 
        struct list_head gl_reclaim;
@@ -203,6 +213,7 @@ struct gfs2_glock {
        struct gfs2_log_element gl_le;
        struct list_head gl_ail_list;
        atomic_t gl_ail_count;
+       struct delayed_work gl_work;
 };
 
 struct gfs2_alloc {
@@ -293,11 +304,6 @@ struct gfs2_file {
        struct gfs2_holder f_fl_gh;
 };
 
-struct gfs2_revoke {
-       struct gfs2_log_element rv_le;
-       u64 rv_blkno;
-};
-
 struct gfs2_revoke_replay {
        struct list_head rr_list;
        u64 rr_blkno;
@@ -335,12 +341,6 @@ struct gfs2_quota_data {
        unsigned long qd_last_touched;
 };
 
-struct gfs2_log_buf {
-       struct list_head lb_list;
-       struct buffer_head *lb_bh;
-       struct buffer_head *lb_real;
-};
-
 struct gfs2_trans {
        unsigned long tr_ip;
 
@@ -429,7 +429,6 @@ struct gfs2_tune {
        unsigned int gt_log_flush_secs;
        unsigned int gt_jindex_refresh_secs; /* Check for new journal index */
 
-       unsigned int gt_scand_secs;
        unsigned int gt_recoverd_secs;
        unsigned int gt_logd_secs;
        unsigned int gt_quotad_secs;
@@ -574,7 +573,6 @@ struct gfs2_sbd {
 
        /* Daemon stuff */
 
-       struct task_struct *sd_scand_process;
        struct task_struct *sd_recoverd_process;
        struct task_struct *sd_logd_process;
        struct task_struct *sd_quotad_process;
@@ -609,13 +607,13 @@ struct gfs2_sbd {
        unsigned int sd_log_num_revoke;
        unsigned int sd_log_num_rg;
        unsigned int sd_log_num_databuf;
-       unsigned int sd_log_num_jdata;
 
        struct list_head sd_log_le_gl;
        struct list_head sd_log_le_buf;
        struct list_head sd_log_le_revoke;
        struct list_head sd_log_le_rg;
        struct list_head sd_log_le_databuf;
+       struct list_head sd_log_le_ordered;
 
        unsigned int sd_log_blks_free;
        struct mutex sd_log_reserve_mutex;
@@ -627,7 +625,8 @@ struct gfs2_sbd {
 
        unsigned long sd_log_flush_time;
        struct rw_semaphore sd_log_flush_lock;
-       struct list_head sd_log_flush_list;
+       atomic_t sd_log_in_flight;
+       wait_queue_head_t sd_log_flush_wait;
 
        unsigned int sd_log_flush_head;
        u64 sd_log_flush_wrapped;
index 34f7bcdea1e972e00187013eddd98272d65a40f0..5f6dc32946cd09c795ef5bf7226e6aadfe4942e8 100644 (file)
@@ -77,6 +77,49 @@ static struct inode *gfs2_iget(struct super_block *sb, u64 no_addr)
        return iget5_locked(sb, hash, iget_test, iget_set, &no_addr);
 }
 
+struct gfs2_skip_data {
+       u64     no_addr;
+       int     skipped;
+};
+
+static int iget_skip_test(struct inode *inode, void *opaque)
+{
+       struct gfs2_inode *ip = GFS2_I(inode);
+       struct gfs2_skip_data *data = opaque;
+
+       if (ip->i_no_addr == data->no_addr && inode->i_private != NULL){
+               if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE)){
+                       data->skipped = 1;
+                       return 0;
+               }
+               return 1;
+       }
+       return 0;
+}
+
+static int iget_skip_set(struct inode *inode, void *opaque)
+{
+       struct gfs2_inode *ip = GFS2_I(inode);
+       struct gfs2_skip_data *data = opaque;
+
+       if (data->skipped)
+               return 1;
+       inode->i_ino = (unsigned long)(data->no_addr);
+       ip->i_no_addr = data->no_addr;
+       return 0;
+}
+
+static struct inode *gfs2_iget_skip(struct super_block *sb,
+                                   u64 no_addr)
+{
+       struct gfs2_skip_data data;
+       unsigned long hash = (unsigned long)no_addr;
+
+       data.no_addr = no_addr;
+       data.skipped = 0;
+       return iget5_locked(sb, hash, iget_skip_test, iget_skip_set, &data);
+}
+
 /**
  * GFS2 lookup code fills in vfs inode contents based on info obtained
  * from directory entry inside gfs2_inode_lookup(). This has caused issues
@@ -112,6 +155,7 @@ void gfs2_set_iop(struct inode *inode)
  * @sb: The super block
  * @no_addr: The inode number
  * @type: The type of the inode
+ * @skip_freeing: set this not return an inode if it is currently being freed.
  *
  * Returns: A VFS inode, or an error
  */
@@ -119,13 +163,19 @@ void gfs2_set_iop(struct inode *inode)
 struct inode *gfs2_inode_lookup(struct super_block *sb, 
                                unsigned int type,
                                u64 no_addr,
-                               u64 no_formal_ino)
+                               u64 no_formal_ino, int skip_freeing)
 {
-       struct inode *inode = gfs2_iget(sb, no_addr);
-       struct gfs2_inode *ip = GFS2_I(inode);
+       struct inode *inode;
+       struct gfs2_inode *ip;
        struct gfs2_glock *io_gl;
        int error;
 
+       if (skip_freeing)
+               inode = gfs2_iget_skip(sb, no_addr);
+       else
+               inode = gfs2_iget(sb, no_addr);
+       ip = GFS2_I(inode);
+
        if (!inode)
                return ERR_PTR(-ENOBUFS);
 
@@ -244,6 +294,11 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
        return 0;
 }
 
+static void gfs2_inode_bh(struct gfs2_inode *ip, struct buffer_head *bh)
+{
+       ip->i_cache[0] = bh;
+}
+
 /**
  * gfs2_inode_refresh - Refresh the incore copy of the dinode
  * @ip: The GFS2 inode
@@ -688,7 +743,7 @@ out:
 static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl,
                        const struct gfs2_inum_host *inum, unsigned int mode,
                        unsigned int uid, unsigned int gid,
-                       const u64 *generation, dev_t dev)
+                       const u64 *generation, dev_t dev, struct buffer_head **bhp)
 {
        struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
        struct gfs2_dinode *di;
@@ -743,13 +798,15 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl,
        di->di_mtime_nsec = cpu_to_be32(tv.tv_nsec);
        di->di_ctime_nsec = cpu_to_be32(tv.tv_nsec);
        memset(&di->di_reserved, 0, sizeof(di->di_reserved));
+       
+       set_buffer_uptodate(dibh);
 
-       brelse(dibh);
+       *bhp = dibh;
 }
 
 static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl,
                       unsigned int mode, const struct gfs2_inum_host *inum,
-                      const u64 *generation, dev_t dev)
+                      const u64 *generation, dev_t dev, struct buffer_head **bhp)
 {
        struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
        unsigned int uid, gid;
@@ -770,7 +827,7 @@ static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl,
        if (error)
                goto out_quota;
 
-       init_dinode(dip, gl, inum, mode, uid, gid, generation, dev);
+       init_dinode(dip, gl, inum, mode, uid, gid, generation, dev, bhp);
        gfs2_quota_change(dip, +1, uid, gid);
        gfs2_trans_end(sdp);
 
@@ -909,6 +966,7 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,
        struct gfs2_inum_host inum = { .no_addr = 0, .no_formal_ino = 0 };
        int error;
        u64 generation;
+       struct buffer_head *bh=NULL;
 
        if (!name->len || name->len > GFS2_FNAMESIZE)
                return ERR_PTR(-ENAMETOOLONG);
@@ -935,16 +993,18 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,
        if (error)
                goto fail_gunlock;
 
-       error = make_dinode(dip, ghs[1].gh_gl, mode, &inum, &generation, dev);
+       error = make_dinode(dip, ghs[1].gh_gl, mode, &inum, &generation, dev, &bh);
        if (error)
                goto fail_gunlock2;
 
        inode = gfs2_inode_lookup(dir->i_sb, IF2DT(mode),
                                        inum.no_addr,
-                                       inum.no_formal_ino);
+                                       inum.no_formal_ino, 0);
        if (IS_ERR(inode))
                goto fail_gunlock2;
 
+       gfs2_inode_bh(GFS2_I(inode), bh);
+
        error = gfs2_inode_refresh(GFS2_I(inode));
        if (error)
                goto fail_gunlock2;
index 4517ac82c01c7953b75bc65375e45328262b86dc..351ac87ab384e263f6fd71b4f5ede70a484b9e48 100644 (file)
@@ -49,7 +49,8 @@ static inline void gfs2_inum_out(const struct gfs2_inode *ip,
 void gfs2_inode_attr_in(struct gfs2_inode *ip);
 void gfs2_set_iop(struct inode *inode);
 struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned type, 
-                               u64 no_addr, u64 no_formal_ino);
+                               u64 no_addr, u64 no_formal_ino,
+                               int skip_freeing);
 struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr);
 
 int gfs2_inode_refresh(struct gfs2_inode *ip);
index 24d70f73b65124f3a6960099a82dcf5544b0416d..9e8265d28377bda09e9a3ca478a96c090b6ab70e 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
-#include <linux/module.h>
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/list.h>
index fba1f1d87e4fbe92cceb66fd44eb7ee40a8a6d84..1f7b038530b4f3df924121395b02c522d770b255 100644 (file)
@@ -346,15 +346,16 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count,
 
 static unsigned int dev_poll(struct file *file, poll_table *wait)
 {
+       unsigned int mask = 0;
+
        poll_wait(file, &send_wq, wait);
 
        spin_lock(&ops_lock);
-       if (!list_empty(&send_list)) {
-               spin_unlock(&ops_lock);
-               return POLLIN | POLLRDNORM;
-       }
+       if (!list_empty(&send_list))
+               mask = POLLIN | POLLRDNORM;
        spin_unlock(&ops_lock);
-       return 0;
+
+       return mask;
 }
 
 static const struct file_operations dev_fops = {
index d9fe3ca40e1859ec8420c7e512bda40bfba486e6..ae9e6a25fe2ba67d390b507e21f678303ed54e59 100644 (file)
@@ -190,7 +190,6 @@ static struct kobj_type gdlm_ktype = {
 };
 
 static struct kset gdlm_kset = {
-       .kobj   = {.name = "lock_dlm",},
        .ktype  = &gdlm_ktype,
 };
 
@@ -224,6 +223,7 @@ int gdlm_sysfs_init(void)
 {
        int error;
 
+       kobject_set_name(&gdlm_kset.kobj, "lock_dlm");
        kobj_set_kset_s(&gdlm_kset, kernel_subsys);
        error = kset_register(&gdlm_kset);
        if (error)
index 1aca51e45092e0eb6c37691ccfa6c0af3cf51682..bd938f06481d47c77ac8bb19276281d95dfe45fb 100644 (file)
@@ -268,20 +268,16 @@ static inline int check_drop(struct gdlm_ls *ls)
        return 0;
 }
 
-static int gdlm_thread(void *data)
+static int gdlm_thread(void *data, int blist)
 {
        struct gdlm_ls *ls = (struct gdlm_ls *) data;
        struct gdlm_lock *lp = NULL;
-       int blist = 0;
        uint8_t complete, blocking, submit, drop;
        DECLARE_WAITQUEUE(wait, current);
 
        /* Only thread1 is allowed to do blocking callbacks since gfs
           may wait for a completion callback within a blocking cb. */
 
-       if (current == ls->thread1)
-               blist = 1;
-
        while (!kthread_should_stop()) {
                set_current_state(TASK_INTERRUPTIBLE);
                add_wait_queue(&ls->thread_wait, &wait);
@@ -333,12 +329,22 @@ static int gdlm_thread(void *data)
        return 0;
 }
 
+static int gdlm_thread1(void *data)
+{
+       return gdlm_thread(data, 1);
+}
+
+static int gdlm_thread2(void *data)
+{
+       return gdlm_thread(data, 0);
+}
+
 int gdlm_init_threads(struct gdlm_ls *ls)
 {
        struct task_struct *p;
        int error;
 
-       p = kthread_run(gdlm_thread, ls, "lock_dlm1");
+       p = kthread_run(gdlm_thread1, ls, "lock_dlm1");
        error = IS_ERR(p);
        if (error) {
                log_error("can't start lock_dlm1 thread %d", error);
@@ -346,7 +352,7 @@ int gdlm_init_threads(struct gdlm_ls *ls)
        }
        ls->thread1 = p;
 
-       p = kthread_run(gdlm_thread, ls, "lock_dlm2");
+       p = kthread_run(gdlm_thread2, ls, "lock_dlm2");
        error = IS_ERR(p);
        if (error) {
                log_error("can't start lock_dlm2 thread %d", error);
index 0d149c8c493a36ce1b9bb31593c5e9cfdb75465e..d3b8ce6fbbe34aafd0f0045ad1091bd0704f9c44 100644 (file)
@@ -9,7 +9,6 @@
 
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/fs.h>
index f49a12e24086d36e6975a733c3c1a8b9793c244d..7df7024732523b8beddb57e3a6d6c3d37e035768 100644 (file)
@@ -59,6 +59,26 @@ unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct,
        return blks;
 }
 
+/**
+ * gfs2_remove_from_ail - Remove an entry from the ail lists, updating counters
+ * @mapping: The associated mapping (maybe NULL)
+ * @bd: The gfs2_bufdata to remove
+ *
+ * The log lock _must_ be held when calling this function
+ *
+ */
+
+void gfs2_remove_from_ail(struct address_space *mapping, struct gfs2_bufdata *bd)
+{
+       bd->bd_ail = NULL;
+       list_del_init(&bd->bd_ail_st_list);
+       list_del_init(&bd->bd_ail_gl_list);
+       atomic_dec(&bd->bd_gl->gl_ail_count);
+       if (mapping)
+               gfs2_meta_cache_flush(GFS2_I(mapping->host));
+       brelse(bd->bd_bh);
+}
+
 /**
  * gfs2_ail1_start_one - Start I/O on a part of the AIL
  * @sdp: the filesystem
@@ -83,17 +103,9 @@ static void gfs2_ail1_start_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
 
                        gfs2_assert(sdp, bd->bd_ail == ai);
 
-                       if (!bh){
-                               list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list);
-                                continue;
-                        }
-
                        if (!buffer_busy(bh)) {
-                               if (!buffer_uptodate(bh)) {
-                                       gfs2_log_unlock(sdp);
+                               if (!buffer_uptodate(bh))
                                        gfs2_io_error_bh(sdp, bh);
-                                       gfs2_log_lock(sdp);
-                               }
                                list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list);
                                continue;
                        }
@@ -103,9 +115,16 @@ static void gfs2_ail1_start_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
 
                        list_move(&bd->bd_ail_st_list, &ai->ai_ail1_list);
 
+                       get_bh(bh);
                        gfs2_log_unlock(sdp);
-                       wait_on_buffer(bh);
-                       ll_rw_block(WRITE, 1, &bh);
+                       lock_buffer(bh);
+                       if (test_clear_buffer_dirty(bh)) {
+                               bh->b_end_io = end_buffer_write_sync;
+                               submit_bh(WRITE, bh);
+                       } else {
+                               unlock_buffer(bh);
+                               brelse(bh);
+                       }
                        gfs2_log_lock(sdp);
 
                        retry = 1;
@@ -130,11 +149,6 @@ static int gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai, int fl
                                         bd_ail_st_list) {
                bh = bd->bd_bh;
 
-               if (!bh){
-                       list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list);
-                       continue;
-               }
-
                gfs2_assert(sdp, bd->bd_ail == ai);
 
                if (buffer_busy(bh)) {
@@ -155,13 +169,14 @@ static int gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai, int fl
 
 static void gfs2_ail1_start(struct gfs2_sbd *sdp, int flags)
 {
-       struct list_head *head = &sdp->sd_ail1_list;
+       struct list_head *head;
        u64 sync_gen;
        struct list_head *first;
        struct gfs2_ail *first_ai, *ai, *tmp;
        int done = 0;
 
        gfs2_log_lock(sdp);
+       head = &sdp->sd_ail1_list;
        if (list_empty(head)) {
                gfs2_log_unlock(sdp);
                return;
@@ -233,11 +248,7 @@ static void gfs2_ail2_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
                bd = list_entry(head->prev, struct gfs2_bufdata,
                                bd_ail_st_list);
                gfs2_assert(sdp, bd->bd_ail == ai);
-               bd->bd_ail = NULL;
-               list_del(&bd->bd_ail_st_list);
-               list_del(&bd->bd_ail_gl_list);
-               atomic_dec(&bd->bd_gl->gl_ail_count);
-               brelse(bd->bd_bh);
+               gfs2_remove_from_ail(bd->bd_bh->b_page->mapping, bd);
        }
 }
 
@@ -439,10 +450,10 @@ static unsigned int current_tail(struct gfs2_sbd *sdp)
        return tail;
 }
 
-static inline void log_incr_head(struct gfs2_sbd *sdp)
+void gfs2_log_incr_head(struct gfs2_sbd *sdp)
 {
        if (sdp->sd_log_flush_head == sdp->sd_log_tail)
-               gfs2_assert_withdraw(sdp, sdp->sd_log_flush_head == sdp->sd_log_head);
+               BUG_ON(sdp->sd_log_flush_head != sdp->sd_log_head);
 
        if (++sdp->sd_log_flush_head == sdp->sd_jdesc->jd_blocks) {
                sdp->sd_log_flush_head = 0;
@@ -450,6 +461,23 @@ static inline void log_incr_head(struct gfs2_sbd *sdp)
        }
 }
 
+/**
+ * gfs2_log_write_endio - End of I/O for a log buffer
+ * @bh: The buffer head
+ * @uptodate: I/O Status
+ *
+ */
+
+static void gfs2_log_write_endio(struct buffer_head *bh, int uptodate)
+{
+       struct gfs2_sbd *sdp = bh->b_private;
+       bh->b_private = NULL;
+
+       end_buffer_write_sync(bh, uptodate);
+       if (atomic_dec_and_test(&sdp->sd_log_in_flight))
+               wake_up(&sdp->sd_log_flush_wait);
+}
+
 /**
  * gfs2_log_get_buf - Get and initialize a buffer to use for log control data
  * @sdp: The GFS2 superblock
@@ -460,24 +488,42 @@ static inline void log_incr_head(struct gfs2_sbd *sdp)
 struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp)
 {
        u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head);
-       struct gfs2_log_buf *lb;
        struct buffer_head *bh;
 
-       lb = kzalloc(sizeof(struct gfs2_log_buf), GFP_NOFS | __GFP_NOFAIL);
-       list_add(&lb->lb_list, &sdp->sd_log_flush_list);
-
-       bh = lb->lb_bh = sb_getblk(sdp->sd_vfs, blkno);
+       bh = sb_getblk(sdp->sd_vfs, blkno);
        lock_buffer(bh);
        memset(bh->b_data, 0, bh->b_size);
        set_buffer_uptodate(bh);
        clear_buffer_dirty(bh);
-       unlock_buffer(bh);
-
-       log_incr_head(sdp);
+       gfs2_log_incr_head(sdp);
+       atomic_inc(&sdp->sd_log_in_flight);
+       bh->b_private = sdp;
+       bh->b_end_io = gfs2_log_write_endio;
 
        return bh;
 }
 
+/**
+ * gfs2_fake_write_endio - 
+ * @bh: The buffer head
+ * @uptodate: The I/O Status
+ *
+ */
+
+static void gfs2_fake_write_endio(struct buffer_head *bh, int uptodate)
+{
+       struct buffer_head *real_bh = bh->b_private;
+       struct gfs2_bufdata *bd = real_bh->b_private;
+       struct gfs2_sbd *sdp = bd->bd_gl->gl_sbd;
+
+       end_buffer_write_sync(bh, uptodate);
+       free_buffer_head(bh);
+       unlock_buffer(real_bh);
+       brelse(real_bh);
+       if (atomic_dec_and_test(&sdp->sd_log_in_flight))
+               wake_up(&sdp->sd_log_flush_wait);
+}
+
 /**
  * gfs2_log_fake_buf - Build a fake buffer head to write metadata buffer to log
  * @sdp: the filesystem
@@ -490,22 +536,20 @@ struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp,
                                      struct buffer_head *real)
 {
        u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head);
-       struct gfs2_log_buf *lb;
        struct buffer_head *bh;
 
-       lb = kzalloc(sizeof(struct gfs2_log_buf), GFP_NOFS | __GFP_NOFAIL);
-       list_add(&lb->lb_list, &sdp->sd_log_flush_list);
-       lb->lb_real = real;
-
-       bh = lb->lb_bh = alloc_buffer_head(GFP_NOFS | __GFP_NOFAIL);
+       bh = alloc_buffer_head(GFP_NOFS | __GFP_NOFAIL);
        atomic_set(&bh->b_count, 1);
-       bh->b_state = (1 << BH_Mapped) | (1 << BH_Uptodate);
+       bh->b_state = (1 << BH_Mapped) | (1 << BH_Uptodate) | (1 << BH_Lock);
        set_bh_page(bh, real->b_page, bh_offset(real));
        bh->b_blocknr = blkno;
        bh->b_size = sdp->sd_sb.sb_bsize;
        bh->b_bdev = sdp->sd_vfs->s_bdev;
+       bh->b_private = real;
+       bh->b_end_io = gfs2_fake_write_endio;
 
-       log_incr_head(sdp);
+       gfs2_log_incr_head(sdp);
+       atomic_inc(&sdp->sd_log_in_flight);
 
        return bh;
 }
@@ -572,45 +616,75 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags, int pull)
                gfs2_assert_withdraw(sdp, !pull);
 
        sdp->sd_log_idle = (tail == sdp->sd_log_flush_head);
-       log_incr_head(sdp);
+       gfs2_log_incr_head(sdp);
 }
 
 static void log_flush_commit(struct gfs2_sbd *sdp)
 {
-       struct list_head *head = &sdp->sd_log_flush_list;
-       struct gfs2_log_buf *lb;
-       struct buffer_head *bh;
-       int flushcount = 0;
+       DEFINE_WAIT(wait);
+
+       if (atomic_read(&sdp->sd_log_in_flight)) {
+               do {
+                       prepare_to_wait(&sdp->sd_log_flush_wait, &wait,
+                                       TASK_UNINTERRUPTIBLE);
+                       if (atomic_read(&sdp->sd_log_in_flight))
+                               io_schedule();
+               } while(atomic_read(&sdp->sd_log_in_flight));
+               finish_wait(&sdp->sd_log_flush_wait, &wait);
+       }
 
-       while (!list_empty(head)) {
-               lb = list_entry(head->next, struct gfs2_log_buf, lb_list);
-               list_del(&lb->lb_list);
-               bh = lb->lb_bh;
+       log_write_header(sdp, 0, 0);
+}
 
-               wait_on_buffer(bh);
-               if (!buffer_uptodate(bh))
-                       gfs2_io_error_bh(sdp, bh);
-               if (lb->lb_real) {
-                       while (atomic_read(&bh->b_count) != 1)  /* Grrrr... */
-                               schedule();
-                       free_buffer_head(bh);
-               } else
+static void gfs2_ordered_write(struct gfs2_sbd *sdp)
+{
+       struct gfs2_bufdata *bd;
+       struct buffer_head *bh;
+       LIST_HEAD(written);
+
+       gfs2_log_lock(sdp);
+       while (!list_empty(&sdp->sd_log_le_ordered)) {
+               bd = list_entry(sdp->sd_log_le_ordered.next, struct gfs2_bufdata, bd_le.le_list);
+               list_move(&bd->bd_le.le_list, &written);
+               bh = bd->bd_bh;
+               if (!buffer_dirty(bh))
+                       continue;
+               get_bh(bh);
+               gfs2_log_unlock(sdp);
+               lock_buffer(bh);
+               if (test_clear_buffer_dirty(bh)) {
+                       bh->b_end_io = end_buffer_write_sync;
+                       submit_bh(WRITE, bh);
+               } else {
+                       unlock_buffer(bh);
                        brelse(bh);
-               kfree(lb);
-               flushcount++;
+               }
+               gfs2_log_lock(sdp);
        }
+       list_splice(&written, &sdp->sd_log_le_ordered);
+       gfs2_log_unlock(sdp);
+}
 
-       /* If nothing was journaled, the header is unplanned and unwanted. */
-       if (flushcount) {
-               log_write_header(sdp, 0, 0);
-       } else {
-               unsigned int tail;
-               tail = current_tail(sdp);
+static void gfs2_ordered_wait(struct gfs2_sbd *sdp)
+{
+       struct gfs2_bufdata *bd;
+       struct buffer_head *bh;
 
-               gfs2_ail1_empty(sdp, 0);
-               if (sdp->sd_log_tail != tail)
-                       log_pull_tail(sdp, tail);
+       gfs2_log_lock(sdp);
+       while (!list_empty(&sdp->sd_log_le_ordered)) {
+               bd = list_entry(sdp->sd_log_le_ordered.prev, struct gfs2_bufdata, bd_le.le_list);
+               bh = bd->bd_bh;
+               if (buffer_locked(bh)) {
+                       get_bh(bh);
+                       gfs2_log_unlock(sdp);
+                       wait_on_buffer(bh);
+                       brelse(bh);
+                       gfs2_log_lock(sdp);
+                       continue;
+               }
+               list_del_init(&bd->bd_le.le_list);
        }
+       gfs2_log_unlock(sdp);
 }
 
 /**
@@ -640,10 +714,16 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
        INIT_LIST_HEAD(&ai->ai_ail1_list);
        INIT_LIST_HEAD(&ai->ai_ail2_list);
 
-       gfs2_assert_withdraw(sdp,
-                            sdp->sd_log_num_buf + sdp->sd_log_num_jdata ==
-                            sdp->sd_log_commited_buf +
-                            sdp->sd_log_commited_databuf);
+       if (sdp->sd_log_num_buf != sdp->sd_log_commited_buf) {
+               printk(KERN_INFO "GFS2: log buf %u %u\n", sdp->sd_log_num_buf,
+                      sdp->sd_log_commited_buf);
+               gfs2_assert_withdraw(sdp, 0);
+       }
+       if (sdp->sd_log_num_databuf != sdp->sd_log_commited_databuf) {
+               printk(KERN_INFO "GFS2: log databuf %u %u\n",
+                      sdp->sd_log_num_databuf, sdp->sd_log_commited_databuf);
+               gfs2_assert_withdraw(sdp, 0);
+       }
        gfs2_assert_withdraw(sdp,
                        sdp->sd_log_num_revoke == sdp->sd_log_commited_revoke);
 
@@ -651,8 +731,11 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
        sdp->sd_log_flush_wrapped = 0;
        ai->ai_first = sdp->sd_log_flush_head;
 
+       gfs2_ordered_write(sdp);
        lops_before_commit(sdp);
-       if (!list_empty(&sdp->sd_log_flush_list))
+       gfs2_ordered_wait(sdp);
+
+       if (sdp->sd_log_head != sdp->sd_log_flush_head)
                log_flush_commit(sdp);
        else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle){
                gfs2_log_lock(sdp);
@@ -744,7 +827,6 @@ void gfs2_log_shutdown(struct gfs2_sbd *sdp)
        gfs2_assert_withdraw(sdp, !sdp->sd_log_blks_reserved);
        gfs2_assert_withdraw(sdp, !sdp->sd_log_num_gl);
        gfs2_assert_withdraw(sdp, !sdp->sd_log_num_buf);
-       gfs2_assert_withdraw(sdp, !sdp->sd_log_num_jdata);
        gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke);
        gfs2_assert_withdraw(sdp, !sdp->sd_log_num_rg);
        gfs2_assert_withdraw(sdp, !sdp->sd_log_num_databuf);
index 8e7aa0f2910961fedd690f9641732bc9e7ed64a7..dae2824006273462408a78a36684a432ec16f9a6 100644 (file)
@@ -52,12 +52,14 @@ int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags);
 
 int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks);
 void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks);
+void gfs2_log_incr_head(struct gfs2_sbd *sdp);
 
 struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp);
 struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp,
                                      struct buffer_head *real);
 void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl);
 void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *trans);
+void gfs2_remove_from_ail(struct address_space *mapping, struct gfs2_bufdata *bd);
 
 void gfs2_log_shutdown(struct gfs2_sbd *sdp);
 void gfs2_meta_syncfs(struct gfs2_sbd *sdp);
index 3b395c41b2f3f9acefc623e6e008949231b1e8d3..6c27cea761c6b6a195bd92f90592d3641367a18c 100644 (file)
 #include "trans.h"
 #include "util.h"
 
-static void glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
+/**
+ * gfs2_pin - Pin a buffer in memory
+ * @sdp: The superblock
+ * @bh: The buffer to be pinned
+ *
+ * The log lock must be held when calling this function
+ */
+static void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh)
+{
+       struct gfs2_bufdata *bd;
+
+       gfs2_assert_withdraw(sdp, test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags));
+
+       clear_buffer_dirty(bh);
+       if (test_set_buffer_pinned(bh))
+               gfs2_assert_withdraw(sdp, 0);
+       if (!buffer_uptodate(bh))
+               gfs2_io_error_bh(sdp, bh);
+       bd = bh->b_private;
+       /* If this buffer is in the AIL and it has already been written
+        * to in-place disk block, remove it from the AIL.
+        */
+       if (bd->bd_ail)
+               list_move(&bd->bd_ail_st_list, &bd->bd_ail->ai_ail2_list);
+       get_bh(bh);
+}
+
+/**
+ * gfs2_unpin - Unpin a buffer
+ * @sdp: the filesystem the buffer belongs to
+ * @bh: The buffer to unpin
+ * @ai:
+ *
+ */
+
+static void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh,
+                      struct gfs2_ail *ai)
+{
+       struct gfs2_bufdata *bd = bh->b_private;
+
+       gfs2_assert_withdraw(sdp, buffer_uptodate(bh));
+
+       if (!buffer_pinned(bh))
+               gfs2_assert_withdraw(sdp, 0);
+
+       lock_buffer(bh);
+       mark_buffer_dirty(bh);
+       clear_buffer_pinned(bh);
+
+       gfs2_log_lock(sdp);
+       if (bd->bd_ail) {
+               list_del(&bd->bd_ail_st_list);
+               brelse(bh);
+       } else {
+               struct gfs2_glock *gl = bd->bd_gl;
+               list_add(&bd->bd_ail_gl_list, &gl->gl_ail_list);
+               atomic_inc(&gl->gl_ail_count);
+       }
+       bd->bd_ail = ai;
+       list_add(&bd->bd_ail_st_list, &ai->ai_ail1_list);
+       gfs2_log_unlock(sdp);
+       unlock_buffer(bh);
+}
+
+
+static inline struct gfs2_log_descriptor *bh_log_desc(struct buffer_head *bh)
+{
+       return (struct gfs2_log_descriptor *)bh->b_data;
+}
+
+static inline __be64 *bh_log_ptr(struct buffer_head *bh)
+{
+       struct gfs2_log_descriptor *ld = bh_log_desc(bh);
+       return (__force __be64 *)(ld + 1);
+}
+
+static inline __be64 *bh_ptr_end(struct buffer_head *bh)
+{
+       return (__force __be64 *)(bh->b_data + bh->b_size);
+}
+
+
+static struct buffer_head *gfs2_get_log_desc(struct gfs2_sbd *sdp, u32 ld_type)
+{
+       struct buffer_head *bh = gfs2_log_get_buf(sdp);
+       struct gfs2_log_descriptor *ld = bh_log_desc(bh);
+       ld->ld_header.mh_magic = cpu_to_be32(GFS2_MAGIC);
+       ld->ld_header.mh_type = cpu_to_be32(GFS2_METATYPE_LD);
+       ld->ld_header.mh_format = cpu_to_be32(GFS2_FORMAT_LD);
+       ld->ld_type = cpu_to_be32(ld_type);
+       ld->ld_length = 0;
+       ld->ld_data1 = 0;
+       ld->ld_data2 = 0;
+       memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved));
+       return bh;
+}
+
+static void __glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
 {
        struct gfs2_glock *gl;
        struct gfs2_trans *tr = current->journal_info;
@@ -38,15 +135,19 @@ static void glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
        if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(gl)))
                return;
 
-       gfs2_log_lock(sdp);
-       if (!list_empty(&le->le_list)){
-               gfs2_log_unlock(sdp);
+       if (!list_empty(&le->le_list))
                return;
-       }
+
        gfs2_glock_hold(gl);
        set_bit(GLF_DIRTY, &gl->gl_flags);
        sdp->sd_log_num_gl++;
        list_add(&le->le_list, &sdp->sd_log_le_gl);
+}
+
+static void glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
+{
+       gfs2_log_lock(sdp);
+       __glock_lo_add(sdp, le);
        gfs2_log_unlock(sdp);
 }
 
@@ -71,30 +172,25 @@ static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
        struct gfs2_bufdata *bd = container_of(le, struct gfs2_bufdata, bd_le);
        struct gfs2_trans *tr;
 
+       lock_buffer(bd->bd_bh);
        gfs2_log_lock(sdp);
-       if (!list_empty(&bd->bd_list_tr)) {
-               gfs2_log_unlock(sdp);
-               return;
-       }
+       if (!list_empty(&bd->bd_list_tr))
+               goto out;
        tr = current->journal_info;
        tr->tr_touched = 1;
        tr->tr_num_buf++;
        list_add(&bd->bd_list_tr, &tr->tr_list_buf);
-       gfs2_log_unlock(sdp);
-
        if (!list_empty(&le->le_list))
-               return;
-
-       gfs2_trans_add_gl(bd->bd_gl);
-
+               goto out;
+       __glock_lo_add(sdp, &bd->bd_gl->gl_le);
        gfs2_meta_check(sdp, bd->bd_bh);
        gfs2_pin(sdp, bd->bd_bh);
-       gfs2_log_lock(sdp);
        sdp->sd_log_num_buf++;
        list_add(&le->le_list, &sdp->sd_log_le_buf);
-       gfs2_log_unlock(sdp);
-
        tr->tr_num_buf_new++;
+out:
+       gfs2_log_unlock(sdp);
+       unlock_buffer(bd->bd_bh);
 }
 
 static void buf_lo_incore_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
@@ -117,8 +213,7 @@ static void buf_lo_before_commit(struct gfs2_sbd *sdp)
        struct buffer_head *bh;
        struct gfs2_log_descriptor *ld;
        struct gfs2_bufdata *bd1 = NULL, *bd2;
-       unsigned int total = sdp->sd_log_num_buf;
-       unsigned int offset = BUF_OFFSET;
+       unsigned int total;
        unsigned int limit;
        unsigned int num;
        unsigned n;
@@ -127,22 +222,20 @@ static void buf_lo_before_commit(struct gfs2_sbd *sdp)
        limit = buf_limit(sdp);
        /* for 4k blocks, limit = 503 */
 
+       gfs2_log_lock(sdp);
+       total = sdp->sd_log_num_buf;
        bd1 = bd2 = list_prepare_entry(bd1, &sdp->sd_log_le_buf, bd_le.le_list);
        while(total) {
                num = total;
                if (total > limit)
                        num = limit;
-               bh = gfs2_log_get_buf(sdp);
-               ld = (struct gfs2_log_descriptor *)bh->b_data;
-               ptr = (__be64 *)(bh->b_data + offset);
-               ld->ld_header.mh_magic = cpu_to_be32(GFS2_MAGIC);
-               ld->ld_header.mh_type = cpu_to_be32(GFS2_METATYPE_LD);
-               ld->ld_header.mh_format = cpu_to_be32(GFS2_FORMAT_LD);
-               ld->ld_type = cpu_to_be32(GFS2_LOG_DESC_METADATA);
+               gfs2_log_unlock(sdp);
+               bh = gfs2_get_log_desc(sdp, GFS2_LOG_DESC_METADATA);
+               gfs2_log_lock(sdp);
+               ld = bh_log_desc(bh);
+               ptr = bh_log_ptr(bh);
                ld->ld_length = cpu_to_be32(num + 1);
                ld->ld_data1 = cpu_to_be32(num);
-               ld->ld_data2 = cpu_to_be32(0);
-               memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved));
 
                n = 0;
                list_for_each_entry_continue(bd1, &sdp->sd_log_le_buf,
@@ -152,21 +245,27 @@ static void buf_lo_before_commit(struct gfs2_sbd *sdp)
                                break;
                }
 
-               set_buffer_dirty(bh);
-               ll_rw_block(WRITE, 1, &bh);
+               gfs2_log_unlock(sdp);
+               submit_bh(WRITE, bh);
+               gfs2_log_lock(sdp);
 
                n = 0;
                list_for_each_entry_continue(bd2, &sdp->sd_log_le_buf,
                                             bd_le.le_list) {
+                       get_bh(bd2->bd_bh);
+                       gfs2_log_unlock(sdp);
+                       lock_buffer(bd2->bd_bh);
                        bh = gfs2_log_fake_buf(sdp, bd2->bd_bh);
-                       set_buffer_dirty(bh);
-                       ll_rw_block(WRITE, 1, &bh);
+                       submit_bh(WRITE, bh);
+                       gfs2_log_lock(sdp);
                        if (++n >= num)
                                break;
                }
 
+               BUG_ON(total < num);
                total -= num;
        }
+       gfs2_log_unlock(sdp);
 }
 
 static void buf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
@@ -270,11 +369,8 @@ static void revoke_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
        tr = current->journal_info;
        tr->tr_touched = 1;
        tr->tr_num_revoke++;
-
-       gfs2_log_lock(sdp);
        sdp->sd_log_num_revoke++;
        list_add(&le->le_list, &sdp->sd_log_le_revoke);
-       gfs2_log_unlock(sdp);
 }
 
 static void revoke_lo_before_commit(struct gfs2_sbd *sdp)
@@ -284,32 +380,25 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp)
        struct buffer_head *bh;
        unsigned int offset;
        struct list_head *head = &sdp->sd_log_le_revoke;
-       struct gfs2_revoke *rv;
+       struct gfs2_bufdata *bd;
 
        if (!sdp->sd_log_num_revoke)
                return;
 
-       bh = gfs2_log_get_buf(sdp);
-       ld = (struct gfs2_log_descriptor *)bh->b_data;
-       ld->ld_header.mh_magic = cpu_to_be32(GFS2_MAGIC);
-       ld->ld_header.mh_type = cpu_to_be32(GFS2_METATYPE_LD);
-       ld->ld_header.mh_format = cpu_to_be32(GFS2_FORMAT_LD);
-       ld->ld_type = cpu_to_be32(GFS2_LOG_DESC_REVOKE);
+       bh = gfs2_get_log_desc(sdp, GFS2_LOG_DESC_REVOKE);
+       ld = bh_log_desc(bh);
        ld->ld_length = cpu_to_be32(gfs2_struct2blk(sdp, sdp->sd_log_num_revoke,
                                                    sizeof(u64)));
        ld->ld_data1 = cpu_to_be32(sdp->sd_log_num_revoke);
-       ld->ld_data2 = cpu_to_be32(0);
-       memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved));
        offset = sizeof(struct gfs2_log_descriptor);
 
        while (!list_empty(head)) {
-               rv = list_entry(head->next, struct gfs2_revoke, rv_le.le_list);
-               list_del_init(&rv->rv_le.le_list);
+               bd = list_entry(head->next, struct gfs2_bufdata, bd_le.le_list);
+               list_del_init(&bd->bd_le.le_list);
                sdp->sd_log_num_revoke--;
 
                if (offset + sizeof(u64) > sdp->sd_sb.sb_bsize) {
-                       set_buffer_dirty(bh);
-                       ll_rw_block(WRITE, 1, &bh);
+                       submit_bh(WRITE, bh);
 
                        bh = gfs2_log_get_buf(sdp);
                        mh = (struct gfs2_meta_header *)bh->b_data;
@@ -319,15 +408,14 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp)
                        offset = sizeof(struct gfs2_meta_header);
                }
 
-               *(__be64 *)(bh->b_data + offset) = cpu_to_be64(rv->rv_blkno);
-               kfree(rv);
+               *(__be64 *)(bh->b_data + offset) = cpu_to_be64(bd->bd_blkno);
+               kmem_cache_free(gfs2_bufdata_cachep, bd);
 
                offset += sizeof(u64);
        }
        gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke);
 
-       set_buffer_dirty(bh);
-       ll_rw_block(WRITE, 1, &bh);
+       submit_bh(WRITE, bh);
 }
 
 static void revoke_lo_before_scan(struct gfs2_jdesc *jd,
@@ -466,222 +554,136 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
        struct address_space *mapping = bd->bd_bh->b_page->mapping;
        struct gfs2_inode *ip = GFS2_I(mapping->host);
 
+       lock_buffer(bd->bd_bh);
        gfs2_log_lock(sdp);
-       if (!list_empty(&bd->bd_list_tr)) {
-               gfs2_log_unlock(sdp);
-               return;
-       }
+       if (!list_empty(&bd->bd_list_tr))
+               goto out;
        tr->tr_touched = 1;
        if (gfs2_is_jdata(ip)) {
                tr->tr_num_buf++;
                list_add(&bd->bd_list_tr, &tr->tr_list_buf);
        }
-       gfs2_log_unlock(sdp);
        if (!list_empty(&le->le_list))
-               return;
+               goto out;
 
-       gfs2_trans_add_gl(bd->bd_gl);
+       __glock_lo_add(sdp, &bd->bd_gl->gl_le);
        if (gfs2_is_jdata(ip)) {
-               sdp->sd_log_num_jdata++;
                gfs2_pin(sdp, bd->bd_bh);
                tr->tr_num_databuf_new++;
+               sdp->sd_log_num_databuf++;
+               list_add(&le->le_list, &sdp->sd_log_le_databuf);
+       } else {
+               list_add(&le->le_list, &sdp->sd_log_le_ordered);
        }
-       gfs2_log_lock(sdp);
-       sdp->sd_log_num_databuf++;
-       list_add(&le->le_list, &sdp->sd_log_le_databuf);
+out:
        gfs2_log_unlock(sdp);
+       unlock_buffer(bd->bd_bh);
 }
 
-static int gfs2_check_magic(struct buffer_head *bh)
+static void gfs2_check_magic(struct buffer_head *bh)
 {
-       struct page *page = bh->b_page;
        void *kaddr;
        __be32 *ptr;
-       int rv = 0;
 
-       kaddr = kmap_atomic(page, KM_USER0);
+       clear_buffer_escaped(bh);
+       kaddr = kmap_atomic(bh->b_page, KM_USER0);
        ptr = kaddr + bh_offset(bh);
        if (*ptr == cpu_to_be32(GFS2_MAGIC))
-               rv = 1;
+               set_buffer_escaped(bh);
        kunmap_atomic(kaddr, KM_USER0);
-
-       return rv;
 }
 
-/**
- * databuf_lo_before_commit - Scan the data buffers, writing as we go
- *
- * Here we scan through the lists of buffers and make the assumption
- * that any buffer thats been pinned is being journaled, and that
- * any unpinned buffer is an ordered write data buffer and therefore
- * will be written back rather than journaled.
- */
-static void databuf_lo_before_commit(struct gfs2_sbd *sdp)
+static void gfs2_write_blocks(struct gfs2_sbd *sdp, struct buffer_head *bh,
+                             struct list_head *list, struct list_head *done,
+                             unsigned int n)
 {
-       LIST_HEAD(started);
-       struct gfs2_bufdata *bd1 = NULL, *bd2, *bdt;
-       struct buffer_head *bh = NULL,*bh1 = NULL;
+       struct buffer_head *bh1;
        struct gfs2_log_descriptor *ld;
-       unsigned int limit;
-       unsigned int total_dbuf;
-       unsigned int total_jdata = sdp->sd_log_num_jdata;
-       unsigned int num, n;
-       __be64 *ptr = NULL;
+       struct gfs2_bufdata *bd;
+       __be64 *ptr;
+
+       if (!bh)
+               return;
 
-       limit = databuf_limit(sdp);
+       ld = bh_log_desc(bh);
+       ld->ld_length = cpu_to_be32(n + 1);
+       ld->ld_data1 = cpu_to_be32(n);
 
-       /*
-        * Start writing ordered buffers, write journaled buffers
-        * into the log along with a header
-        */
+       ptr = bh_log_ptr(bh);
+       
+       get_bh(bh);
+       submit_bh(WRITE, bh);
        gfs2_log_lock(sdp);
-       total_dbuf = sdp->sd_log_num_databuf;
-       bd2 = bd1 = list_prepare_entry(bd1, &sdp->sd_log_le_databuf,
-                                      bd_le.le_list);
-       while(total_dbuf) {
-               num = total_jdata;
-               if (num > limit)
-                       num = limit;
-               n = 0;
-               list_for_each_entry_safe_continue(bd1, bdt,
-                                                 &sdp->sd_log_le_databuf,
-                                                 bd_le.le_list) {
-                       /* store off the buffer head in a local ptr since
-                        * gfs2_bufdata might change when we drop the log lock
-                        */
-                       bh1 = bd1->bd_bh;
-
-                       /* An ordered write buffer */
-                       if (bh1 && !buffer_pinned(bh1)) {
-                               list_move(&bd1->bd_le.le_list, &started);
-                               if (bd1 == bd2) {
-                                       bd2 = NULL;
-                                       bd2 = list_prepare_entry(bd2,
-                                                       &sdp->sd_log_le_databuf,
-                                                       bd_le.le_list);
-                               }
-                               total_dbuf--;
-                               if (bh1) {
-                                       if (buffer_dirty(bh1)) {
-                                               get_bh(bh1);
-
-                                               gfs2_log_unlock(sdp);
-
-                                               ll_rw_block(SWRITE, 1, &bh1);
-                                               brelse(bh1);
-
-                                               gfs2_log_lock(sdp);
-                                       }
-                                       continue;
-                               }
-                               continue;
-                       } else if (bh1) { /* A journaled buffer */
-                               int magic;
-                               gfs2_log_unlock(sdp);
-                               if (!bh) {
-                                       bh = gfs2_log_get_buf(sdp);
-                                       ld = (struct gfs2_log_descriptor *)
-                                            bh->b_data;
-                                       ptr = (__be64 *)(bh->b_data +
-                                                        DATABUF_OFFSET);
-                                       ld->ld_header.mh_magic =
-                                               cpu_to_be32(GFS2_MAGIC);
-                                       ld->ld_header.mh_type =
-                                               cpu_to_be32(GFS2_METATYPE_LD);
-                                       ld->ld_header.mh_format =
-                                               cpu_to_be32(GFS2_FORMAT_LD);
-                                       ld->ld_type =
-                                               cpu_to_be32(GFS2_LOG_DESC_JDATA);
-                                       ld->ld_length = cpu_to_be32(num + 1);
-                                       ld->ld_data1 = cpu_to_be32(num);
-                                       ld->ld_data2 = cpu_to_be32(0);
-                                       memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved));
-                               }
-                               magic = gfs2_check_magic(bh1);
-                               *ptr++ = cpu_to_be64(bh1->b_blocknr);
-                               *ptr++ = cpu_to_be64((__u64)magic);
-                               clear_buffer_escaped(bh1);
-                               if (unlikely(magic != 0))
-                                       set_buffer_escaped(bh1);
-                               gfs2_log_lock(sdp);
-                               if (++n >= num)
-                                       break;
-                       } else if (!bh1) {
-                               total_dbuf--;
-                               sdp->sd_log_num_databuf--;
-                               list_del_init(&bd1->bd_le.le_list);
-                               if (bd1 == bd2) {
-                                       bd2 = NULL;
-                                       bd2 = list_prepare_entry(bd2,
-                                               &sdp->sd_log_le_databuf,
-                                               bd_le.le_list);
-                                }
-                               kmem_cache_free(gfs2_bufdata_cachep, bd1);
-                       }
+       while(!list_empty(list)) {
+               bd = list_entry(list->next, struct gfs2_bufdata, bd_le.le_list);
+               list_move_tail(&bd->bd_le.le_list, done);
+               get_bh(bd->bd_bh);
+               while (be64_to_cpu(*ptr) != bd->bd_bh->b_blocknr) {
+                       gfs2_log_incr_head(sdp);
+                       ptr += 2;
                }
                gfs2_log_unlock(sdp);
-               if (bh) {
-                       set_buffer_mapped(bh);
-                       set_buffer_dirty(bh);
-                       ll_rw_block(WRITE, 1, &bh);
-                       bh = NULL;
+               lock_buffer(bd->bd_bh);
+               if (buffer_escaped(bd->bd_bh)) {
+                       void *kaddr;
+                       bh1 = gfs2_log_get_buf(sdp);
+                       kaddr = kmap_atomic(bd->bd_bh->b_page, KM_USER0);
+                       memcpy(bh1->b_data, kaddr + bh_offset(bd->bd_bh),
+                              bh1->b_size);
+                       kunmap_atomic(kaddr, KM_USER0);
+                       *(__be32 *)bh1->b_data = 0;
+                       clear_buffer_escaped(bd->bd_bh);
+                       unlock_buffer(bd->bd_bh);
+                       brelse(bd->bd_bh);
+               } else {
+                       bh1 = gfs2_log_fake_buf(sdp, bd->bd_bh);
                }
-               n = 0;
+               submit_bh(WRITE, bh1);
                gfs2_log_lock(sdp);
-               list_for_each_entry_continue(bd2, &sdp->sd_log_le_databuf,
-                                            bd_le.le_list) {
-                       if (!bd2->bd_bh)
-                               continue;
-                       /* copy buffer if it needs escaping */
-                       gfs2_log_unlock(sdp);
-                       if (unlikely(buffer_escaped(bd2->bd_bh))) {
-                               void *kaddr;
-                               struct page *page = bd2->bd_bh->b_page;
-                               bh = gfs2_log_get_buf(sdp);
-                               kaddr = kmap_atomic(page, KM_USER0);
-                               memcpy(bh->b_data,
-                                      kaddr + bh_offset(bd2->bd_bh),
-                                      sdp->sd_sb.sb_bsize);
-                               kunmap_atomic(kaddr, KM_USER0);
-                               *(__be32 *)bh->b_data = 0;
-                       } else {
-                               bh = gfs2_log_fake_buf(sdp, bd2->bd_bh);
-                       }
-                       set_buffer_dirty(bh);
-                       ll_rw_block(WRITE, 1, &bh);
-                       gfs2_log_lock(sdp);
-                       if (++n >= num)
-                               break;
-               }
-               bh = NULL;
-               BUG_ON(total_dbuf < num);
-               total_dbuf -= num;
-               total_jdata -= num;
+               ptr += 2;
        }
        gfs2_log_unlock(sdp);
+       brelse(bh);
+}
 
-       /* Wait on all ordered buffers */
-       while (!list_empty(&started)) {
-               gfs2_log_lock(sdp);
-               bd1 = list_entry(started.next, struct gfs2_bufdata,
-                                bd_le.le_list);
-               list_del_init(&bd1->bd_le.le_list);
-               sdp->sd_log_num_databuf--;
-               bh = bd1->bd_bh;
-               if (bh) {
-                       bh->b_private = NULL;
-                       get_bh(bh);
-                       gfs2_log_unlock(sdp);
-                       wait_on_buffer(bh);
-                       brelse(bh);
-               } else
-                       gfs2_log_unlock(sdp);
+/**
+ * databuf_lo_before_commit - Scan the data buffers, writing as we go
+ *
+ */
 
-               kmem_cache_free(gfs2_bufdata_cachep, bd1);
-       }
+static void databuf_lo_before_commit(struct gfs2_sbd *sdp)
+{
+       struct gfs2_bufdata *bd = NULL;
+       struct buffer_head *bh = NULL;
+       unsigned int n = 0;
+       __be64 *ptr = NULL, *end = NULL;
+       LIST_HEAD(processed);
+       LIST_HEAD(in_progress);
 
-       /* We've removed all the ordered write bufs here, so only jdata left */
-       gfs2_assert_warn(sdp, sdp->sd_log_num_databuf == sdp->sd_log_num_jdata);
+       gfs2_log_lock(sdp);
+       while (!list_empty(&sdp->sd_log_le_databuf)) {
+               if (ptr == end) {
+                       gfs2_log_unlock(sdp);
+                       gfs2_write_blocks(sdp, bh, &in_progress, &processed, n);
+                       n = 0;
+                       bh = gfs2_get_log_desc(sdp, GFS2_LOG_DESC_JDATA);
+                       ptr = bh_log_ptr(bh);
+                       end = bh_ptr_end(bh) - 1;
+                       gfs2_log_lock(sdp);
+                       continue;
+               }
+               bd = list_entry(sdp->sd_log_le_databuf.next, struct gfs2_bufdata, bd_le.le_list);
+               list_move_tail(&bd->bd_le.le_list, &in_progress);
+               gfs2_check_magic(bd->bd_bh);
+               *ptr++ = cpu_to_be64(bd->bd_bh->b_blocknr);
+               *ptr++ = cpu_to_be64(buffer_escaped(bh) ? 1 : 0);
+               n++;
+       }
+       gfs2_log_unlock(sdp);
+       gfs2_write_blocks(sdp, bh, &in_progress, &processed, n);
+       gfs2_log_lock(sdp);
+       list_splice(&processed, &sdp->sd_log_le_databuf);
+       gfs2_log_unlock(sdp);
 }
 
 static int databuf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start,
@@ -765,11 +767,9 @@ static void databuf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
                bd = list_entry(head->next, struct gfs2_bufdata, bd_le.le_list);
                list_del_init(&bd->bd_le.le_list);
                sdp->sd_log_num_databuf--;
-               sdp->sd_log_num_jdata--;
                gfs2_unpin(sdp, bd->bd_bh, ai);
        }
        gfs2_assert_warn(sdp, !sdp->sd_log_num_databuf);
-       gfs2_assert_warn(sdp, !sdp->sd_log_num_jdata);
 }
 
 
@@ -817,10 +817,10 @@ const struct gfs2_log_operations gfs2_databuf_lops = {
 
 const struct gfs2_log_operations *gfs2_log_ops[] = {
        &gfs2_glock_lops,
+       &gfs2_databuf_lops,
        &gfs2_buf_lops,
-       &gfs2_revoke_lops,
        &gfs2_rg_lops,
-       &gfs2_databuf_lops,
+       &gfs2_revoke_lops,
        NULL,
 };
 
index d5d4e68b88070430e667aec80d1bb91b6e571c28..79c91fd8381bc11d61bba006daba21a1cf713f81 100644 (file)
@@ -107,6 +107,8 @@ static int __init init_gfs2_fs(void)
 fail_unregister:
        unregister_filesystem(&gfs2_fs_type);
 fail:
+       gfs2_glock_exit();
+
        if (gfs2_bufdata_cachep)
                kmem_cache_destroy(gfs2_bufdata_cachep);
 
@@ -127,6 +129,7 @@ fail:
 
 static void __exit exit_gfs2_fs(void)
 {
+       gfs2_glock_exit();
        gfs2_unregister_debugfs();
        unregister_filesystem(&gfs2_fs_type);
        unregister_filesystem(&gfs2meta_fs_type);
index 8da343b34ae733de759c09cefa64e84b71a887c7..4da423985e4f9178dd752a92fa5c102cd287e66a 100644 (file)
@@ -297,74 +297,35 @@ void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh,
                unlock_page(bh->b_page);
 }
 
-/**
- * gfs2_pin - Pin a buffer in memory
- * @sdp: the filesystem the buffer belongs to
- * @bh: The buffer to be pinned
- *
- */
-
-void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh)
+void gfs2_remove_from_journal(struct buffer_head *bh, struct gfs2_trans *tr, int meta)
 {
+       struct gfs2_sbd *sdp = GFS2_SB(bh->b_page->mapping->host);
        struct gfs2_bufdata *bd = bh->b_private;
-
-       gfs2_assert_withdraw(sdp, test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags));
-
-       if (test_set_buffer_pinned(bh))
-               gfs2_assert_withdraw(sdp, 0);
-
-       wait_on_buffer(bh);
-
-       /* If this buffer is in the AIL and it has already been written
-          to in-place disk block, remove it from the AIL. */
-
-       gfs2_log_lock(sdp);
-       if (bd->bd_ail && !buffer_in_io(bh))
-               list_move(&bd->bd_ail_st_list, &bd->bd_ail->ai_ail2_list);
-       gfs2_log_unlock(sdp);
-
-       clear_buffer_dirty(bh);
-       wait_on_buffer(bh);
-
-       if (!buffer_uptodate(bh))
-               gfs2_io_error_bh(sdp, bh);
-
-       get_bh(bh);
-}
-
-/**
- * gfs2_unpin - Unpin a buffer
- * @sdp: the filesystem the buffer belongs to
- * @bh: The buffer to unpin
- * @ai:
- *
- */
-
-void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh,
-               struct gfs2_ail *ai)
-{
-       struct gfs2_bufdata *bd = bh->b_private;
-
-       gfs2_assert_withdraw(sdp, buffer_uptodate(bh));
-
-       if (!buffer_pinned(bh))
-               gfs2_assert_withdraw(sdp, 0);
-
-       mark_buffer_dirty(bh);
-       clear_buffer_pinned(bh);
-
-       gfs2_log_lock(sdp);
-       if (bd->bd_ail) {
-               list_del(&bd->bd_ail_st_list);
+       if (test_clear_buffer_pinned(bh)) {
+               list_del_init(&bd->bd_le.le_list);
+               if (meta) {
+                       gfs2_assert_warn(sdp, sdp->sd_log_num_buf);
+                       sdp->sd_log_num_buf--;
+                       tr->tr_num_buf_rm++;
+               } else {
+                       gfs2_assert_warn(sdp, sdp->sd_log_num_databuf);
+                       sdp->sd_log_num_databuf--;
+                       tr->tr_num_databuf_rm++;
+               }
+               tr->tr_touched = 1;
                brelse(bh);
-       } else {
-               struct gfs2_glock *gl = bd->bd_gl;
-               list_add(&bd->bd_ail_gl_list, &gl->gl_ail_list);
-               atomic_inc(&gl->gl_ail_count);
        }
-       bd->bd_ail = ai;
-       list_add(&bd->bd_ail_st_list, &ai->ai_ail1_list);
-       gfs2_log_unlock(sdp);
+       if (bd) {
+               if (bd->bd_ail) {
+                       gfs2_remove_from_ail(NULL, bd);
+                       bh->b_private = NULL;
+                       bd->bd_bh = NULL;
+                       bd->bd_blkno = bh->b_blocknr;
+                       gfs2_trans_add_revoke(sdp, bd);
+               }
+       }
+       clear_buffer_dirty(bh);
+       clear_buffer_uptodate(bh);
 }
 
 /**
@@ -383,44 +344,11 @@ void gfs2_meta_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen)
        while (blen) {
                bh = getbuf(ip->i_gl, bstart, NO_CREATE);
                if (bh) {
-                       struct gfs2_bufdata *bd = bh->b_private;
-
-                       if (test_clear_buffer_pinned(bh)) {
-                               struct gfs2_trans *tr = current->journal_info;
-                               struct gfs2_inode *bh_ip =
-                                       GFS2_I(bh->b_page->mapping->host);
-
-                               gfs2_log_lock(sdp);
-                               list_del_init(&bd->bd_le.le_list);
-                               gfs2_assert_warn(sdp, sdp->sd_log_num_buf);
-                               sdp->sd_log_num_buf--;
-                               gfs2_log_unlock(sdp);
-                               if (bh_ip->i_inode.i_private != NULL)
-                                       tr->tr_num_databuf_rm++;
-                               else
-                                       tr->tr_num_buf_rm++;
-                               brelse(bh);
-                       }
-                       if (bd) {
-                               gfs2_log_lock(sdp);
-                               if (bd->bd_ail) {
-                                       u64 blkno = bh->b_blocknr;
-                                       bd->bd_ail = NULL;
-                                       list_del(&bd->bd_ail_st_list);
-                                       list_del(&bd->bd_ail_gl_list);
-                                       atomic_dec(&bd->bd_gl->gl_ail_count);
-                                       brelse(bh);
-                                       gfs2_log_unlock(sdp);
-                                       gfs2_trans_add_revoke(sdp, blkno);
-                               } else
-                                       gfs2_log_unlock(sdp);
-                       }
-
                        lock_buffer(bh);
-                       clear_buffer_dirty(bh);
-                       clear_buffer_uptodate(bh);
+                       gfs2_log_lock(sdp);
+                       gfs2_remove_from_journal(bh, current->journal_info, 1);
+                       gfs2_log_unlock(sdp);
                        unlock_buffer(bh);
-
                        brelse(bh);
                }
 
@@ -446,10 +374,10 @@ void gfs2_meta_cache_flush(struct gfs2_inode *ip)
 
        for (x = 0; x < GFS2_MAX_META_HEIGHT; x++) {
                bh_slot = &ip->i_cache[x];
-               if (!*bh_slot)
-                       break;
-               brelse(*bh_slot);
-               *bh_slot = NULL;
+               if (*bh_slot) {
+                       brelse(*bh_slot);
+                       *bh_slot = NULL;
+               }
        }
 
        spin_unlock(&ip->i_spin);
index 527bf19d9690f5c58203e1ca1c3fbb0b1e5fa8ae..b7048222ebb46fb1c4fdd9157430823a48e8c603 100644 (file)
@@ -50,9 +50,9 @@ int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh);
 
 void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh,
                         int meta);
-void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh);
-void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh,
-               struct gfs2_ail *ai);
+
+void gfs2_remove_from_journal(struct buffer_head *bh, struct gfs2_trans *tr,
+                             int meta);
 
 void gfs2_meta_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen);
 
index 4864659555d4f94d49132a2727a4acd0b5e1d5e4..b941f9f9f958e84a1fcf1a1431726e4f399a3b6c 100644 (file)
@@ -42,6 +42,7 @@ enum {
        Opt_nosuiddir,
        Opt_data_writeback,
        Opt_data_ordered,
+       Opt_err,
 };
 
 static match_table_t tokens = {
@@ -64,7 +65,8 @@ static match_table_t tokens = {
        {Opt_suiddir, "suiddir"},
        {Opt_nosuiddir, "nosuiddir"},
        {Opt_data_writeback, "data=writeback"},
-       {Opt_data_ordered, "data=ordered"}
+       {Opt_data_ordered, "data=ordered"},
+       {Opt_err, NULL}
 };
 
 /**
@@ -237,6 +239,7 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, char *data_arg, int remount)
                case Opt_data_ordered:
                        args->ar_data = GFS2_DATA_ORDERED;
                        break;
+               case Opt_err:
                default:
                        fs_info(sdp, "unknown option: %s\n", o);
                        error = -EINVAL;
index 42a5f58f6fca4adf5ad1faae9edec36939b05d2c..873a511ef2bea93b273aa20404f44fee8d1a410b 100644 (file)
@@ -90,7 +90,7 @@ static int gfs2_get_block_noalloc(struct inode *inode, sector_t lblock,
        error = gfs2_block_map(inode, lblock, 0, bh_result);
        if (error)
                return error;
-       if (bh_result->b_blocknr == 0)
+       if (!buffer_mapped(bh_result))
                return -EIO;
        return 0;
 }
@@ -414,7 +414,8 @@ static int gfs2_prepare_write(struct file *file, struct page *page,
        if (ind_blocks || data_blocks)
                rblocks += RES_STATFS + RES_QUOTA;
 
-       error = gfs2_trans_begin(sdp, rblocks, 0);
+       error = gfs2_trans_begin(sdp, rblocks,
+                                PAGE_CACHE_SIZE/sdp->sd_sb.sb_bsize);
        if (error)
                goto out_trans_fail;
 
@@ -616,58 +617,50 @@ static sector_t gfs2_bmap(struct address_space *mapping, sector_t lblock)
        return dblock;
 }
 
-static void discard_buffer(struct gfs2_sbd *sdp, struct buffer_head *bh)
+static void gfs2_discard(struct gfs2_sbd *sdp, struct buffer_head *bh)
 {
        struct gfs2_bufdata *bd;
 
+       lock_buffer(bh);
        gfs2_log_lock(sdp);
+       clear_buffer_dirty(bh);
        bd = bh->b_private;
        if (bd) {
-               bd->bd_bh = NULL;
-               bh->b_private = NULL;
-               if (!bd->bd_ail && list_empty(&bd->bd_le.le_list))
-                       kmem_cache_free(gfs2_bufdata_cachep, bd);
+               if (!list_empty(&bd->bd_le.le_list) && !buffer_pinned(bh))
+                       list_del_init(&bd->bd_le.le_list);
+               else
+                       gfs2_remove_from_journal(bh, current->journal_info, 0);
        }
-       gfs2_log_unlock(sdp);
-
-       lock_buffer(bh);
-       clear_buffer_dirty(bh);
        bh->b_bdev = NULL;
        clear_buffer_mapped(bh);
        clear_buffer_req(bh);
        clear_buffer_new(bh);
-       clear_buffer_delay(bh);
+       gfs2_log_unlock(sdp);
        unlock_buffer(bh);
 }
 
 static void gfs2_invalidatepage(struct page *page, unsigned long offset)
 {
        struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host);
-       struct buffer_head *head, *bh, *next;
-       unsigned int curr_off = 0;
+       struct buffer_head *bh, *head;
+       unsigned long pos = 0;
 
        BUG_ON(!PageLocked(page));
        if (offset == 0)
                ClearPageChecked(page);
        if (!page_has_buffers(page))
-               return;
+               goto out;
 
        bh = head = page_buffers(page);
        do {
-               unsigned int next_off = curr_off + bh->b_size;
-               next = bh->b_this_page;
-
-               if (offset <= curr_off)
-                       discard_buffer(sdp, bh);
-
-               curr_off = next_off;
-               bh = next;
+               if (offset <= pos)
+                       gfs2_discard(sdp, bh);
+               pos += bh->b_size;
+               bh = bh->b_this_page;
        } while (bh != head);
-
-       if (!offset)
+out:
+       if (offset == 0)
                try_to_release_page(page, 0);
-
-       return;
 }
 
 /**
@@ -735,59 +728,6 @@ out:
        return rv;
 }
 
-/**
- * stuck_releasepage - We're stuck in gfs2_releasepage().  Print stuff out.
- * @bh: the buffer we're stuck on
- *
- */
-
-static void stuck_releasepage(struct buffer_head *bh)
-{
-       struct inode *inode = bh->b_page->mapping->host;
-       struct gfs2_sbd *sdp = inode->i_sb->s_fs_info;
-       struct gfs2_bufdata *bd = bh->b_private;
-       struct gfs2_glock *gl;
-static unsigned limit = 0;
-
-       if (limit > 3)
-               return;
-       limit++;
-
-       fs_warn(sdp, "stuck in gfs2_releasepage() %p\n", inode);
-       fs_warn(sdp, "blkno = %llu, bh->b_count = %d\n",
-               (unsigned long long)bh->b_blocknr, atomic_read(&bh->b_count));
-       fs_warn(sdp, "pinned = %u\n", buffer_pinned(bh));
-       fs_warn(sdp, "bh->b_private = %s\n", (bd) ? "!NULL" : "NULL");
-
-       if (!bd)
-               return;
-
-       gl = bd->bd_gl;
-
-       fs_warn(sdp, "gl = (%u, %llu)\n",
-               gl->gl_name.ln_type, (unsigned long long)gl->gl_name.ln_number);
-
-       fs_warn(sdp, "bd_list_tr = %s, bd_le.le_list = %s\n",
-               (list_empty(&bd->bd_list_tr)) ? "no" : "yes",
-               (list_empty(&bd->bd_le.le_list)) ? "no" : "yes");
-
-       if (gl->gl_ops == &gfs2_inode_glops) {
-               struct gfs2_inode *ip = gl->gl_object;
-               unsigned int x;
-
-               if (!ip)
-                       return;
-
-               fs_warn(sdp, "ip = %llu %llu\n",
-                       (unsigned long long)ip->i_no_formal_ino,
-                       (unsigned long long)ip->i_no_addr);
-
-               for (x = 0; x < GFS2_MAX_META_HEIGHT; x++)
-                       fs_warn(sdp, "ip->i_cache[%u] = %s\n",
-                               x, (ip->i_cache[x]) ? "!NULL" : "NULL");
-       }
-}
-
 /**
  * gfs2_releasepage - free the metadata associated with a page
  * @page: the page that's being released
@@ -805,41 +745,39 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask)
        struct gfs2_sbd *sdp = aspace->i_sb->s_fs_info;
        struct buffer_head *bh, *head;
        struct gfs2_bufdata *bd;
-       unsigned long t = jiffies + gfs2_tune_get(sdp, gt_stall_secs) * HZ;
 
        if (!page_has_buffers(page))
-               goto out;
+               return 0;
 
+       gfs2_log_lock(sdp);
        head = bh = page_buffers(page);
        do {
-               while (atomic_read(&bh->b_count)) {
-                       if (!atomic_read(&aspace->i_writecount))
-                               return 0;
-
-                       if (!(gfp_mask & __GFP_WAIT))
-                               return 0;
-
-                       if (time_after_eq(jiffies, t)) {
-                               stuck_releasepage(bh);
-                               /* should we withdraw here? */
-                               return 0;
-                       }
-
-                       yield();
-               }
-
+               if (atomic_read(&bh->b_count))
+                       goto cannot_release;
+               bd = bh->b_private;
+               if (bd && bd->bd_ail)
+                       goto cannot_release;
                gfs2_assert_warn(sdp, !buffer_pinned(bh));
                gfs2_assert_warn(sdp, !buffer_dirty(bh));
+               bh = bh->b_this_page;
+       } while(bh != head);
+       gfs2_log_unlock(sdp);
 
+       head = bh = page_buffers(page);
+       do {
                gfs2_log_lock(sdp);
                bd = bh->b_private;
                if (bd) {
                        gfs2_assert_warn(sdp, bd->bd_bh == bh);
                        gfs2_assert_warn(sdp, list_empty(&bd->bd_list_tr));
-                       gfs2_assert_warn(sdp, !bd->bd_ail);
-                       bd->bd_bh = NULL;
-                       if (!list_empty(&bd->bd_le.le_list))
-                               bd = NULL;
+                       if (!list_empty(&bd->bd_le.le_list)) {
+                               if (!buffer_pinned(bh))
+                                       list_del_init(&bd->bd_le.le_list);
+                               else
+                                       bd = NULL;
+                       }
+                       if (bd)
+                               bd->bd_bh = NULL;
                        bh->b_private = NULL;
                }
                gfs2_log_unlock(sdp);
@@ -849,8 +787,10 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask)
                bh = bh->b_this_page;
        } while (bh != head);
 
-out:
        return try_to_free_buffers(page);
+cannot_release:
+       gfs2_log_unlock(sdp);
+       return 0;
 }
 
 const struct address_space_operations gfs2_file_aops = {
index b8312edee0e45dc89787f042b350c679e85a6ac6..e2d1347796a9b391eff23d7ee592a4093c684f4f 100644 (file)
@@ -237,7 +237,7 @@ static struct dentry *gfs2_get_dentry(struct super_block *sb, void *inum_obj)
 
        inode = gfs2_inode_lookup(sb, DT_UNKNOWN,
                                        inum->no_addr,
-                                       0);
+                                       0, 0);
        if (!inode)
                goto fail;
        if (IS_ERR(inode)) {
index 94d76ace0b95b840427552c33636f3c0bab46fd3..46a9e10ff17b6719bd8f5fc08e3072263b9c95fd 100644 (file)
@@ -571,7 +571,8 @@ static int do_flock(struct file *file, int cmd, struct file_lock *fl)
        int error = 0;
 
        state = (fl->fl_type == F_WRLCK) ? LM_ST_EXCLUSIVE : LM_ST_SHARED;
-       flags = (IS_SETLKW(cmd) ? 0 : LM_FLAG_TRY) | GL_EXACT | GL_NOCACHE;
+       flags = (IS_SETLKW(cmd) ? 0 : LM_FLAG_TRY) | GL_EXACT | GL_NOCACHE 
+               | GL_FLOCK;
 
        mutex_lock(&fp->f_fl_mutex);
 
@@ -579,21 +580,19 @@ static int do_flock(struct file *file, int cmd, struct file_lock *fl)
        if (gl) {
                if (fl_gh->gh_state == state)
                        goto out;
-               gfs2_glock_hold(gl);
                flock_lock_file_wait(file,
                                     &(struct file_lock){.fl_type = F_UNLCK});
-               gfs2_glock_dq_uninit(fl_gh);
+               gfs2_glock_dq_wait(fl_gh);
+               gfs2_holder_reinit(state, flags, fl_gh);
        } else {
                error = gfs2_glock_get(GFS2_SB(&ip->i_inode),
                                      ip->i_no_addr, &gfs2_flock_glops,
                                      CREATE, &gl);
                if (error)
                        goto out;
+               gfs2_holder_init(gl, state, flags, fl_gh);
+               gfs2_glock_put(gl);
        }
-
-       gfs2_holder_init(gl, state, flags, fl_gh);
-       gfs2_glock_put(gl);
-
        error = gfs2_glock_nq(fl_gh);
        if (error) {
                gfs2_holder_uninit(fl_gh);
index cf5aa50505488d95a62719f9728660e742728575..17de58e83d92e3e10907a50e641858620d5b3ba5 100644 (file)
 #include "lm.h"
 #include "mount.h"
 #include "ops_fstype.h"
+#include "ops_dentry.h"
 #include "ops_super.h"
 #include "recovery.h"
 #include "rgrp.h"
 #include "super.h"
 #include "sys.h"
 #include "util.h"
+#include "log.h"
 
 #define DO 0
 #define UNDO 1
 
-extern struct dentry_operations gfs2_dops;
-
 static struct gfs2_sbd *init_sbd(struct super_block *sb)
 {
        struct gfs2_sbd *sdp;
@@ -82,13 +82,15 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
        INIT_LIST_HEAD(&sdp->sd_log_le_revoke);
        INIT_LIST_HEAD(&sdp->sd_log_le_rg);
        INIT_LIST_HEAD(&sdp->sd_log_le_databuf);
+       INIT_LIST_HEAD(&sdp->sd_log_le_ordered);
 
        mutex_init(&sdp->sd_log_reserve_mutex);
        INIT_LIST_HEAD(&sdp->sd_ail1_list);
        INIT_LIST_HEAD(&sdp->sd_ail2_list);
 
        init_rwsem(&sdp->sd_log_flush_lock);
-       INIT_LIST_HEAD(&sdp->sd_log_flush_list);
+       atomic_set(&sdp->sd_log_in_flight, 0);
+       init_waitqueue_head(&sdp->sd_log_flush_wait);
 
        INIT_LIST_HEAD(&sdp->sd_revoke_list);
 
@@ -145,7 +147,8 @@ static int init_names(struct gfs2_sbd *sdp, int silent)
        snprintf(sdp->sd_proto_name, GFS2_FSNAME_LEN, "%s", proto);
        snprintf(sdp->sd_table_name, GFS2_FSNAME_LEN, "%s", table);
 
-       while ((table = strchr(sdp->sd_table_name, '/')))
+       table = sdp->sd_table_name;
+       while ((table = strchr(table, '/')))
                *table = '_';
 
 out:
@@ -161,14 +164,6 @@ static int init_locking(struct gfs2_sbd *sdp, struct gfs2_holder *mount_gh,
        if (undo)
                goto fail_trans;
 
-       p = kthread_run(gfs2_scand, sdp, "gfs2_scand");
-       error = IS_ERR(p);
-       if (error) {
-               fs_err(sdp, "can't start scand thread: %d\n", error);
-               return error;
-       }
-       sdp->sd_scand_process = p;
-
        for (sdp->sd_glockd_num = 0;
             sdp->sd_glockd_num < sdp->sd_args.ar_num_glockd;
             sdp->sd_glockd_num++) {
@@ -229,14 +224,13 @@ fail:
        while (sdp->sd_glockd_num--)
                kthread_stop(sdp->sd_glockd_process[sdp->sd_glockd_num]);
 
-       kthread_stop(sdp->sd_scand_process);
        return error;
 }
 
 static inline struct inode *gfs2_lookup_root(struct super_block *sb,
                                             u64 no_addr)
 {
-       return gfs2_inode_lookup(sb, DT_DIR, no_addr, 0);
+       return gfs2_inode_lookup(sb, DT_DIR, no_addr, 0, 0);
 }
 
 static int init_sb(struct gfs2_sbd *sdp, int silent, int undo)
@@ -301,8 +295,9 @@ static int init_sb(struct gfs2_sbd *sdp, int silent, int undo)
                fs_err(sdp, "can't get root dentry\n");
                error = -ENOMEM;
                iput(inode);
-       }
-       sb->s_root->d_op = &gfs2_dops;
+       } else
+               sb->s_root->d_op = &gfs2_dops;
+       
 out:
        gfs2_glock_dq_uninit(&sb_gh);
        return error;
@@ -368,7 +363,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
 
                ip = GFS2_I(sdp->sd_jdesc->jd_inode);
                error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED,
-                                          LM_FLAG_NOEXP | GL_EXACT,
+                                          LM_FLAG_NOEXP | GL_EXACT | GL_NOCACHE,
                                           &sdp->sd_jinode_gh);
                if (error) {
                        fs_err(sdp, "can't acquire journal inode glock: %d\n",
@@ -818,7 +813,6 @@ static struct super_block* get_gfs2_sb(const char *dev_name)
        struct nameidata nd;
        struct file_system_type *fstype;
        struct super_block *sb = NULL, *s;
-       struct list_head *l;
        int error;
 
        error = path_lookup(dev_name, LOOKUP_FOLLOW, &nd);
@@ -830,8 +824,7 @@ static struct super_block* get_gfs2_sb(const char *dev_name)
        error = vfs_getattr(nd.mnt, nd.dentry, &stat);
 
        fstype = get_fs_type("gfs2");
-       list_for_each(l, &fstype->fs_supers) {
-               s = list_entry(l, struct super_block, s_instances);
+       list_for_each_entry(s, &fstype->fs_supers, s_instances) {
                if ((S_ISBLK(stat.mode) && s->s_dev == stat.rdev) ||
                    (S_ISDIR(stat.mode) && s == nd.dentry->d_inode->i_sb)) {
                        sb = s;
@@ -861,7 +854,7 @@ static int gfs2_get_sb_meta(struct file_system_type *fs_type, int flags,
                error = -ENOENT;
                goto error;
        }
-       sdp = (struct gfs2_sbd*) sb->s_fs_info;
+       sdp = sb->s_fs_info;
        if (sdp->sd_vfs_meta) {
                printk(KERN_WARNING "GFS2: gfs2meta mount already exists\n");
                error = -EBUSY;
@@ -896,7 +889,10 @@ error:
 
 static void gfs2_kill_sb(struct super_block *sb)
 {
-       gfs2_delete_debugfs_file(sb->s_fs_info);
+       if (sb->s_fs_info) {
+               gfs2_delete_debugfs_file(sb->s_fs_info);
+               gfs2_meta_syncfs(sb->s_fs_info);
+       }
        kill_block_super(sb);
 }
 
index 911c115b5c6c29ecf16aabe087c2be507bb58f71..291f0c7eaa3bcf8249876a73e43f8920dbfa1f24 100644 (file)
@@ -69,7 +69,7 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry,
                        mark_inode_dirty(inode);
                        break;
                } else if (PTR_ERR(inode) != -EEXIST ||
-                          (nd->intent.open.flags & O_EXCL)) {
+                          (nd && (nd->intent.open.flags & O_EXCL))) {
                        gfs2_holder_uninit(ghs);
                        return PTR_ERR(inode);
                }
@@ -278,17 +278,25 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry)
        gfs2_holder_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + 2);
 
 
-       error = gfs2_glock_nq_m(3, ghs);
+       error = gfs2_glock_nq(ghs); /* parent */
        if (error)
-               goto out;
+               goto out_parent;
+
+       error = gfs2_glock_nq(ghs + 1); /* child */
+       if (error)
+               goto out_child;
+
+       error = gfs2_glock_nq(ghs + 2); /* rgrp */
+       if (error)
+               goto out_rgrp;
 
        error = gfs2_unlink_ok(dip, &dentry->d_name, ip);
        if (error)
-               goto out_gunlock;
+               goto out_rgrp;
 
        error = gfs2_trans_begin(sdp, 2*RES_DINODE + RES_LEAF + RES_RG_BIT, 0);
        if (error)
-               goto out_gunlock;
+               goto out_rgrp;
 
        error = gfs2_dir_del(dip, &dentry->d_name);
         if (error)
@@ -298,12 +306,15 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry)
 
 out_end_trans:
        gfs2_trans_end(sdp);
-out_gunlock:
-       gfs2_glock_dq_m(3, ghs);
-out:
-       gfs2_holder_uninit(ghs);
-       gfs2_holder_uninit(ghs + 1);
+       gfs2_glock_dq(ghs + 2);
+out_rgrp:
        gfs2_holder_uninit(ghs + 2);
+       gfs2_glock_dq(ghs + 1);
+out_child:
+       gfs2_holder_uninit(ghs + 1);
+       gfs2_glock_dq(ghs);
+out_parent:
+       gfs2_holder_uninit(ghs);
        gfs2_glock_dq_uninit(&ri_gh);
        return error;
 }
@@ -894,12 +905,17 @@ static int gfs2_permission(struct inode *inode, int mask, struct nameidata *nd)
 static int setattr_size(struct inode *inode, struct iattr *attr)
 {
        struct gfs2_inode *ip = GFS2_I(inode);
+       struct gfs2_sbd *sdp = GFS2_SB(inode);
        int error;
 
        if (attr->ia_size != ip->i_di.di_size) {
-               error = vmtruncate(inode, attr->ia_size);
+               error = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks);
                if (error)
                        return error;
+               error = vmtruncate(inode, attr->ia_size);
+               gfs2_trans_end(sdp);
+               if (error) 
+                       return error;
        }
 
        error = gfs2_truncatei(ip, attr->ia_size);
index 603d940f1159c2c6612d4e2c4d65cc08a946d327..950f31460e8b756d64967e22abca0c51709d4f03 100644 (file)
@@ -92,7 +92,6 @@ static void gfs2_put_super(struct super_block *sb)
        kthread_stop(sdp->sd_recoverd_process);
        while (sdp->sd_glockd_num--)
                kthread_stop(sdp->sd_glockd_process[sdp->sd_glockd_num]);
-       kthread_stop(sdp->sd_scand_process);
 
        if (!(sb->s_flags & MS_RDONLY)) {
                error = gfs2_make_fs_ro(sdp);
@@ -456,12 +455,15 @@ static void gfs2_delete_inode(struct inode *inode)
        }
 
        error = gfs2_dinode_dealloc(ip);
-       /*
-        * Must do this before unlock to avoid trying to write back
-        * potentially dirty data now that inode no longer exists
-        * on disk.
-        */
+       if (error)
+               goto out_unlock;
+
+       error = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks);
+       if (error)
+               goto out_unlock;
+       /* Needs to be done before glock release & also in a transaction */
        truncate_inode_pages(&inode->i_data, 0);
+       gfs2_trans_end(sdp);
 
 out_unlock:
        gfs2_glock_dq(&ip->i_iopen_gh);
index 6e546ee8f3d4d237e01f44aac67db0a35dc0f296..addb51e0f1353118267fff55ebe74f3d1a8f6eb9 100644 (file)
@@ -70,6 +70,7 @@ struct gfs2_quota_host {
        u64 qu_limit;
        u64 qu_warn;
        s64 qu_value;
+       u32 qu_ll_next;
 };
 
 struct gfs2_quota_change_host {
@@ -580,6 +581,7 @@ static void gfs2_quota_in(struct gfs2_quota_host *qu, const void *buf)
        qu->qu_limit = be64_to_cpu(str->qu_limit);
        qu->qu_warn = be64_to_cpu(str->qu_warn);
        qu->qu_value = be64_to_cpu(str->qu_value);
+       qu->qu_ll_next = be32_to_cpu(str->qu_ll_next);
 }
 
 static void gfs2_quota_out(const struct gfs2_quota_host *qu, void *buf)
@@ -589,6 +591,7 @@ static void gfs2_quota_out(const struct gfs2_quota_host *qu, void *buf)
        str->qu_limit = cpu_to_be64(qu->qu_limit);
        str->qu_warn = cpu_to_be64(qu->qu_warn);
        str->qu_value = cpu_to_be64(qu->qu_value);
+       str->qu_ll_next = cpu_to_be32(qu->qu_ll_next);
        memset(&str->qu_reserved, 0, sizeof(str->qu_reserved));
 }
 
@@ -614,6 +617,16 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
        s64 value;
        int err = -EIO;
 
+       if (gfs2_is_stuffed(ip)) {
+               struct gfs2_alloc *al = NULL;
+               al = gfs2_alloc_get(ip);
+               /* just request 1 blk */
+               al->al_requested = 1;
+               gfs2_inplace_reserve(ip);
+               gfs2_unstuff_dinode(ip, NULL);
+               gfs2_inplace_release(ip);
+               gfs2_alloc_put(ip);
+       }
        page = grab_cache_page(mapping, index);
        if (!page)
                return -ENOMEM;
index 5ada38c99a2c95e49a1abb99a828fa0f860306eb..beb6c7ac0086623d5fe9fe39da480ce4b31419a0 100644 (file)
@@ -469,7 +469,7 @@ int gfs2_recover_journal(struct gfs2_jdesc *jd)
                };
 
                error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED,
-                                          LM_FLAG_NOEXP, &ji_gh);
+                                          LM_FLAG_NOEXP | GL_NOCACHE, &ji_gh);
                if (error)
                        goto fail_gunlock_j;
        } else {
index ce48c4594ec88f9dc9fb64eb8d0413c5a04cc272..708c287e1d0ef7327d08a8ca5d14ca36ac6e04ad 100644 (file)
@@ -31,6 +31,7 @@
 #include "inode.h"
 
 #define BFITNOENT ((u32)~0)
+#define NO_BLOCK ((u64)~0)
 
 /*
  * These routines are used by the resource group routines (rgrp.c)
@@ -116,8 +117,7 @@ static unsigned char gfs2_testbit(struct gfs2_rgrpd *rgd, unsigned char *buffer,
  * @buffer: the buffer that holds the bitmaps
  * @buflen: the length (in bytes) of the buffer
  * @goal: start search at this block's bit-pair (within @buffer)
- * @old_state: GFS2_BLKST_XXX the state of the block we're looking for;
- *       bit 0 = alloc(1)/free(0), bit 1 = meta(1)/data(0)
+ * @old_state: GFS2_BLKST_XXX the state of the block we're looking for.
  *
  * Scope of @goal and returned block number is only within this bitmap buffer,
  * not entire rgrp or filesystem.  @buffer will be offset from the actual
@@ -137,9 +137,13 @@ static u32 gfs2_bitfit(struct gfs2_rgrpd *rgd, unsigned char *buffer,
        byte = buffer + (goal / GFS2_NBBY);
        bit = (goal % GFS2_NBBY) * GFS2_BIT_SIZE;
        end = buffer + buflen;
-       alloc = (old_state & 1) ? 0 : 0x55;
+       alloc = (old_state == GFS2_BLKST_FREE) ? 0x55 : 0;
 
        while (byte < end) {
+               /* If we're looking for a free block we can eliminate all
+                  bitmap settings with 0x55, which represents four data
+                  blocks in a row.  If we're looking for a data block, we can
+                  eliminate 0x00 which corresponds to four free blocks. */
                if ((*byte & 0x55) == alloc) {
                        blk += (8 - bit) >> 1;
 
@@ -859,23 +863,28 @@ static int try_rgrp_fit(struct gfs2_rgrpd *rgd, struct gfs2_alloc *al)
 static struct inode *try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked)
 {
        struct inode *inode;
-       u32 goal = 0;
+       u32 goal = 0, block;
        u64 no_addr;
+       struct gfs2_sbd *sdp = rgd->rd_sbd;
 
        for(;;) {
                if (goal >= rgd->rd_data)
                        break;
-               goal = rgblk_search(rgd, goal, GFS2_BLKST_UNLINKED,
-                                   GFS2_BLKST_UNLINKED);
-               if (goal == BFITNOENT)
+               down_write(&sdp->sd_log_flush_lock);
+               block = rgblk_search(rgd, goal, GFS2_BLKST_UNLINKED,
+                                    GFS2_BLKST_UNLINKED);
+               up_write(&sdp->sd_log_flush_lock);
+               if (block == BFITNOENT)
                        break;
-               no_addr = goal + rgd->rd_data0;
+               /* rgblk_search can return a block < goal, so we need to
+                  keep it marching forward. */
+               no_addr = block + rgd->rd_data0;
                goal++;
-               if (no_addr < *last_unlinked)
+               if (*last_unlinked != NO_BLOCK && no_addr <= *last_unlinked)
                        continue;
                *last_unlinked = no_addr;
                inode = gfs2_inode_lookup(rgd->rd_sbd->sd_vfs, DT_UNKNOWN,
-                                         no_addr, -1);
+                                         no_addr, -1, 1);
                if (!IS_ERR(inode))
                        return inode;
        }
@@ -1152,7 +1161,7 @@ int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file, unsigned int line)
        struct gfs2_alloc *al = &ip->i_alloc;
        struct inode *inode;
        int error = 0;
-       u64 last_unlinked = 0;
+       u64 last_unlinked = NO_BLOCK;
 
        if (gfs2_assert_warn(sdp, al->al_requested))
                return -EINVAL;
@@ -1289,7 +1298,9 @@ static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal,
           allocatable block anywhere else, we want to be able wrap around and
           search in the first part of our first-searched bit block.  */
        for (x = 0; x <= length; x++) {
-               if (bi->bi_clone)
+               /* The GFS2_BLKST_UNLINKED state doesn't apply to the clone
+                  bitmaps, so we must search the originals for that. */
+               if (old_state != GFS2_BLKST_UNLINKED && bi->bi_clone)
                        blk = gfs2_bitfit(rgd, bi->bi_clone + bi->bi_offset,
                                          bi->bi_len, goal, old_state);
                else
@@ -1305,9 +1316,7 @@ static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal,
                goal = 0;
        }
 
-       if (old_state != new_state) {
-               gfs2_assert_withdraw(rgd->rd_sbd, blk != BFITNOENT);
-
+       if (blk != BFITNOENT && old_state != new_state) {
                gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1);
                gfs2_setbit(rgd, bi->bi_bh->b_data + bi->bi_offset,
                            bi->bi_len, blk, new_state);
index a2da76b5ae4cc5ac8e37b343b5ca10335484c343..dd3e737f528e0b111387b506608e63fc99ef5c0b 100644 (file)
@@ -58,7 +58,6 @@ void gfs2_tune_init(struct gfs2_tune *gt)
        gt->gt_incore_log_blocks = 1024;
        gt->gt_log_flush_secs = 60;
        gt->gt_jindex_refresh_secs = 60;
-       gt->gt_scand_secs = 15;
        gt->gt_recoverd_secs = 60;
        gt->gt_logd_secs = 1;
        gt->gt_quotad_secs = 5;
index c26c21b53c19a2ccb26d1e75ee81569634f943b3..06e0b7768d9743817eef2715ced2cc1d025b0f2d 100644 (file)
@@ -222,7 +222,6 @@ static struct kobj_type gfs2_ktype = {
 };
 
 static struct kset gfs2_kset = {
-       .kobj   = {.name = "gfs2"},
        .ktype  = &gfs2_ktype,
 };
 
@@ -442,7 +441,6 @@ TUNE_ATTR(quota_simul_sync, 1);
 TUNE_ATTR(quota_cache_secs, 1);
 TUNE_ATTR(stall_secs, 1);
 TUNE_ATTR(statfs_quantum, 1);
-TUNE_ATTR_DAEMON(scand_secs, scand_process);
 TUNE_ATTR_DAEMON(recoverd_secs, recoverd_process);
 TUNE_ATTR_DAEMON(logd_secs, logd_process);
 TUNE_ATTR_DAEMON(quotad_secs, quotad_process);
@@ -464,7 +462,6 @@ static struct attribute *tune_attrs[] = {
        &tune_attr_quota_cache_secs.attr,
        &tune_attr_stall_secs.attr,
        &tune_attr_statfs_quantum.attr,
-       &tune_attr_scand_secs.attr,
        &tune_attr_recoverd_secs.attr,
        &tune_attr_logd_secs.attr,
        &tune_attr_quotad_secs.attr,
@@ -553,6 +550,7 @@ int gfs2_sys_init(void)
 {
        gfs2_sys_margs = NULL;
        spin_lock_init(&gfs2_sys_margs_lock);
+       kobject_set_name(&gfs2_kset.kobj, "gfs2");
        kobj_set_kset_s(&gfs2_kset, fs_subsys);
        return kset_register(&gfs2_kset);
 }
index f8dabf8446bb417000b556b53d5f29b7fc74e8fd..717983e2c2ae3a6b262dd5e29c7a0abb29f1bc8a 100644 (file)
@@ -142,25 +142,25 @@ void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta)
        lops_add(sdp, &bd->bd_le);
 }
 
-void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, u64 blkno)
+void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd)
 {
-       struct gfs2_revoke *rv = kmalloc(sizeof(struct gfs2_revoke),
-                                        GFP_NOFS | __GFP_NOFAIL);
-       lops_init_le(&rv->rv_le, &gfs2_revoke_lops);
-       rv->rv_blkno = blkno;
-       lops_add(sdp, &rv->rv_le);
+       BUG_ON(!list_empty(&bd->bd_le.le_list));
+       BUG_ON(!list_empty(&bd->bd_ail_st_list));
+       BUG_ON(!list_empty(&bd->bd_ail_gl_list));
+       lops_init_le(&bd->bd_le, &gfs2_revoke_lops);
+       lops_add(sdp, &bd->bd_le);
 }
 
 void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno)
 {
-       struct gfs2_revoke *rv;
+       struct gfs2_bufdata *bd;
        int found = 0;
 
        gfs2_log_lock(sdp);
 
-       list_for_each_entry(rv, &sdp->sd_log_le_revoke, rv_le.le_list) {
-               if (rv->rv_blkno == blkno) {
-                       list_del(&rv->rv_le.le_list);
+       list_for_each_entry(bd, &sdp->sd_log_le_revoke, bd_le.le_list) {
+               if (bd->bd_blkno == blkno) {
+                       list_del_init(&bd->bd_le.le_list);
                        gfs2_assert_withdraw(sdp, sdp->sd_log_num_revoke);
                        sdp->sd_log_num_revoke--;
                        found = 1;
@@ -172,7 +172,7 @@ void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno)
 
        if (found) {
                struct gfs2_trans *tr = current->journal_info;
-               kfree(rv);
+               kmem_cache_free(gfs2_bufdata_cachep, bd);
                tr->tr_num_revoke_rm++;
        }
 }
index 23d4cbe1de5b7b81b0c5e460bc7578704f8efece..043d5f4b9c4c34d5c519e574563219decd4603a1 100644 (file)
@@ -32,7 +32,7 @@ void gfs2_trans_end(struct gfs2_sbd *sdp);
 
 void gfs2_trans_add_gl(struct gfs2_glock *gl);
 void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta);
-void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, u64 blkno);
+void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd);
 void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno);
 void gfs2_trans_add_rg(struct gfs2_rgrpd *rgd);
 
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 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..e15f2cf8ac1584bb35854e31bdfc8533cb5ed2aa 100644 (file)
@@ -1475,7 +1475,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 +1680,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 +1722,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 +1822,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 af4ef808fa940589d8bcc282b708269e8b30c03e..345798ebd366b85019bd163d42e11a9be39cd098 100644 (file)
@@ -17,6 +17,18 @@ ToDo/Notes:
          happen is unclear however so it is worth waiting until someone hits
          the problem.
 
+2.1.29 - Fix a deadlock at mount time.
+
+       - During mount the VFS holds s_umount lock on the superblock.  So when
+         we try to empty the journal $LogFile contents by calling
+         ntfs_attr_set() when the machine does not have much memory and the
+         journal is large ntfs_attr_set() results in the VM trying to balance
+         dirty pages which in turn tries to that the s_umount lock and thus we
+         get a deadlock.  The solution is to not use ntfs_attr_set() and
+         instead do the zeroing by hand at the block level rather than page
+         cache level.
+       - Fix sparse warnings.
+
 2.1.28 - Fix a deadlock.
 
        - Fix deadlock in fs/ntfs/inode.c::ntfs_put_inode().  Thanks to Sergey
index 8255083855653478890d62c0a43fc6a8142328f9..58b6be992544333d2723b366d5af57caad5f97a5 100644 (file)
@@ -6,7 +6,7 @@ ntfs-objs := aops.o attrib.o collate.o compress.o debug.o dir.o file.o \
             index.o inode.o mft.o mst.o namei.o runlist.o super.o sysctl.o \
             unistr.o upcase.o
 
-EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.28\"
+EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.29\"
 
 ifeq ($(CONFIG_NTFS_DEBUG),y)
 EXTRA_CFLAGS += -DDEBUG
index 6e5c2534f4bc806b965957254a6bea80af646c62..cfdc7900d2710f70bee9aa7d591d8b8fb4c85c31 100644 (file)
@@ -2,7 +2,7 @@
  * aops.c - NTFS kernel address space operations and page cache handling.
  *         Part of the Linux-NTFS project.
  *
- * Copyright (c) 2001-2006 Anton Altaparmakov
+ * Copyright (c) 2001-2007 Anton Altaparmakov
  * Copyright (c) 2002 Richard Russon
  *
  * This program/include file is free software; you can redistribute it and/or
@@ -396,7 +396,7 @@ static int ntfs_readpage(struct file *file, struct page *page)
        loff_t i_size;
        struct inode *vi;
        ntfs_inode *ni, *base_ni;
-       u8 *kaddr;
+       u8 *addr;
        ntfs_attr_search_ctx *ctx;
        MFT_RECORD *mrec;
        unsigned long flags;
@@ -491,15 +491,15 @@ retry_readpage:
                /* Race with shrinking truncate. */
                attr_len = i_size;
        }
-       kaddr = kmap_atomic(page, KM_USER0);
+       addr = kmap_atomic(page, KM_USER0);
        /* Copy the data to the page. */
-       memcpy(kaddr, (u8*)ctx->attr +
+       memcpy(addr, (u8*)ctx->attr +
                        le16_to_cpu(ctx->attr->data.resident.value_offset),
                        attr_len);
        /* Zero the remainder of the page. */
-       memset(kaddr + attr_len, 0, PAGE_CACHE_SIZE - attr_len);
+       memset(addr + attr_len, 0, PAGE_CACHE_SIZE - attr_len);
        flush_dcache_page(page);
-       kunmap_atomic(kaddr, KM_USER0);
+       kunmap_atomic(addr, KM_USER0);
 put_unm_err_out:
        ntfs_attr_put_search_ctx(ctx);
 unm_err_out:
@@ -1344,7 +1344,7 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc)
        loff_t i_size;
        struct inode *vi = page->mapping->host;
        ntfs_inode *base_ni = NULL, *ni = NTFS_I(vi);
-       char *kaddr;
+       char *addr;
        ntfs_attr_search_ctx *ctx = NULL;
        MFT_RECORD *m = NULL;
        u32 attr_len;
@@ -1484,14 +1484,14 @@ retry_writepage:
                /* Shrinking cannot fail. */
                BUG_ON(err);
        }
-       kaddr = kmap_atomic(page, KM_USER0);
+       addr = kmap_atomic(page, KM_USER0);
        /* Copy the data from the page to the mft record. */
        memcpy((u8*)ctx->attr +
                        le16_to_cpu(ctx->attr->data.resident.value_offset),
-                       kaddr, attr_len);
+                       addr, attr_len);
        /* Zero out of bounds area in the page cache page. */
-       memset(kaddr + attr_len, 0, PAGE_CACHE_SIZE - attr_len);
-       kunmap_atomic(kaddr, KM_USER0);
+       memset(addr + attr_len, 0, PAGE_CACHE_SIZE - attr_len);
+       kunmap_atomic(addr, KM_USER0);
        flush_dcache_page(page);
        flush_dcache_mft_record_page(ctx->ntfs_ino);
        /* We are done with the page. */
index 1c08fefe487a9d4a04da37c06a5567566985091d..92dabdcf2b80b2c0d8f1f5832e9eb0043be391d3 100644 (file)
@@ -1,7 +1,7 @@
 /**
  * attrib.c - NTFS attribute operations.  Part of the Linux-NTFS project.
  *
- * Copyright (c) 2001-2006 Anton Altaparmakov
+ * Copyright (c) 2001-2007 Anton Altaparmakov
  * Copyright (c) 2002 Richard Russon
  *
  * This program/include file is free software; you can redistribute it and/or
@@ -2500,7 +2500,7 @@ int ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt, const u8 val)
        struct page *page;
        u8 *kaddr;
        pgoff_t idx, end;
-       unsigned int start_ofs, end_ofs, size;
+       unsigned start_ofs, end_ofs, size;
 
        ntfs_debug("Entering for ofs 0x%llx, cnt 0x%llx, val 0x%hx.",
                        (long long)ofs, (long long)cnt, val);
@@ -2548,6 +2548,8 @@ int ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt, const u8 val)
                kunmap_atomic(kaddr, KM_USER0);
                set_page_dirty(page);
                page_cache_release(page);
+               balance_dirty_pages_ratelimited(mapping);
+               cond_resched();
                if (idx == end)
                        goto done;
                idx++;
@@ -2604,6 +2606,8 @@ int ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt, const u8 val)
                kunmap_atomic(kaddr, KM_USER0);
                set_page_dirty(page);
                page_cache_release(page);
+               balance_dirty_pages_ratelimited(mapping);
+               cond_resched();
        }
 done:
        ntfs_debug("Done.");
index ffcc504a1667be04daea41339c53cd16d7ca84e4..c814204d4ea0d8ab6533ebd2c59d0b626669bc61 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * file.c - NTFS kernel file operations.  Part of the Linux-NTFS project.
  *
- * Copyright (c) 2001-2006 Anton Altaparmakov
+ * Copyright (c) 2001-2007 Anton Altaparmakov
  *
  * This program/include file is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as published
@@ -26,7 +26,6 @@
 #include <linux/swap.h>
 #include <linux/uio.h>
 #include <linux/writeback.h>
-#include <linux/sched.h>
 
 #include <asm/page.h>
 #include <asm/uaccess.h>
@@ -362,7 +361,7 @@ static inline void ntfs_fault_in_pages_readable(const char __user *uaddr,
        volatile char c;
 
        /* Set @end to the first byte outside the last page we care about. */
-       end = (const char __user*)PAGE_ALIGN((ptrdiff_t __user)uaddr + bytes);
+       end = (const char __user*)PAGE_ALIGN((unsigned long)uaddr + bytes);
 
        while (!__get_user(c, uaddr) && (uaddr += PAGE_SIZE, uaddr < end))
                ;
@@ -532,7 +531,8 @@ static int ntfs_prepare_pages_for_non_resident_write(struct page **pages,
        blocksize_bits = vol->sb->s_blocksize_bits;
        u = 0;
        do {
-               struct page *page = pages[u];
+               page = pages[u];
+               BUG_ON(!page);
                /*
                 * create_empty_buffers() will create uptodate/dirty buffers if
                 * the page is uptodate/dirty.
@@ -1291,7 +1291,7 @@ static inline size_t ntfs_copy_from_user(struct page **pages,
                size_t bytes)
 {
        struct page **last_page = pages + nr_pages;
-       char *kaddr;
+       char *addr;
        size_t total = 0;
        unsigned len;
        int left;
@@ -1300,13 +1300,13 @@ static inline size_t ntfs_copy_from_user(struct page **pages,
                len = PAGE_CACHE_SIZE - ofs;
                if (len > bytes)
                        len = bytes;
-               kaddr = kmap_atomic(*pages, KM_USER0);
-               left = __copy_from_user_inatomic(kaddr + ofs, buf, len);
-               kunmap_atomic(kaddr, KM_USER0);
+               addr = kmap_atomic(*pages, KM_USER0);
+               left = __copy_from_user_inatomic(addr + ofs, buf, len);
+               kunmap_atomic(addr, KM_USER0);
                if (unlikely(left)) {
                        /* Do it the slow way. */
-                       kaddr = kmap(*pages);
-                       left = __copy_from_user(kaddr + ofs, buf, len);
+                       addr = kmap(*pages);
+                       left = __copy_from_user(addr + ofs, buf, len);
                        kunmap(*pages);
                        if (unlikely(left))
                                goto err_out;
@@ -1408,26 +1408,26 @@ static inline size_t ntfs_copy_from_user_iovec(struct page **pages,
                size_t *iov_ofs, size_t bytes)
 {
        struct page **last_page = pages + nr_pages;
-       char *kaddr;
+       char *addr;
        size_t copied, len, total = 0;
 
        do {
                len = PAGE_CACHE_SIZE - ofs;
                if (len > bytes)
                        len = bytes;
-               kaddr = kmap_atomic(*pages, KM_USER0);
-               copied = __ntfs_copy_from_user_iovec_inatomic(kaddr + ofs,
+               addr = kmap_atomic(*pages, KM_USER0);
+               copied = __ntfs_copy_from_user_iovec_inatomic(addr + ofs,
                                *iov, *iov_ofs, len);
-               kunmap_atomic(kaddr, KM_USER0);
+               kunmap_atomic(addr, KM_USER0);
                if (unlikely(copied != len)) {
                        /* Do it the slow way. */
-                       kaddr = kmap(*pages);
-                       copied = __ntfs_copy_from_user_iovec_inatomic(kaddr + ofs,
+                       addr = kmap(*pages);
+                       copied = __ntfs_copy_from_user_iovec_inatomic(addr + ofs,
                                        *iov, *iov_ofs, len);
                        /*
                         * Zero the rest of the target like __copy_from_user().
                         */
-                       memset(kaddr + ofs + copied, 0, len - copied);
+                       memset(addr + ofs + copied, 0, len - copied);
                        kunmap(*pages);
                        if (unlikely(copied != len))
                                goto err_out;
@@ -1735,8 +1735,6 @@ static int ntfs_commit_pages_after_write(struct page **pages,
        read_unlock_irqrestore(&ni->size_lock, flags);
        BUG_ON(initialized_size != i_size);
        if (end > initialized_size) {
-               unsigned long flags;
-
                write_lock_irqsave(&ni->size_lock, flags);
                ni->initialized_size = end;
                i_size_write(vi, end);
index b532a730cec2378072a20304fb85d07ed0d529f3..e9da092e27723a91d5c2bc9bd60a1645b494ca00 100644 (file)
@@ -34,7 +34,6 @@
 #include "dir.h"
 #include "debug.h"
 #include "inode.h"
-#include "attrib.h"
 #include "lcnalloc.h"
 #include "malloc.h"
 #include "mft.h"
@@ -2500,8 +2499,6 @@ retry_truncate:
        /* Resize the attribute record to best fit the new attribute size. */
        if (new_size < vol->mft_record_size &&
                        !ntfs_resident_attr_value_resize(m, a, new_size)) {
-               unsigned long flags;
-
                /* The resize succeeded! */
                flush_dcache_mft_record_page(ctx->ntfs_ino);
                mark_mft_record_dirty(ctx->ntfs_ino);
index acfed325f4ec17481099f505dc3dcb2a37751dd6..d7932e95b1fdfe09ad3e46c78799aa1304d87dc5 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * logfile.c - NTFS kernel journal handling. Part of the Linux-NTFS project.
  *
- * Copyright (c) 2002-2005 Anton Altaparmakov
+ * Copyright (c) 2002-2007 Anton Altaparmakov
  *
  * This program/include file is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as published
@@ -724,24 +724,139 @@ bool ntfs_is_logfile_clean(struct inode *log_vi, const RESTART_PAGE_HEADER *rp)
  */
 bool ntfs_empty_logfile(struct inode *log_vi)
 {
-       ntfs_volume *vol = NTFS_SB(log_vi->i_sb);
+       VCN vcn, end_vcn;
+       ntfs_inode *log_ni = NTFS_I(log_vi);
+       ntfs_volume *vol = log_ni->vol;
+       struct super_block *sb = vol->sb;
+       runlist_element *rl;
+       unsigned long flags;
+       unsigned block_size, block_size_bits;
+       int err;
+       bool should_wait = true;
 
        ntfs_debug("Entering.");
-       if (!NVolLogFileEmpty(vol)) {
-               int err;
-               
-               err = ntfs_attr_set(NTFS_I(log_vi), 0, i_size_read(log_vi),
-                               0xff);
-               if (unlikely(err)) {
-                       ntfs_error(vol->sb, "Failed to fill $LogFile with "
-                                       "0xff bytes (error code %i).", err);
-                       return false;
-               }
-               /* Set the flag so we do not have to do it again on remount. */
-               NVolSetLogFileEmpty(vol);
+       if (NVolLogFileEmpty(vol)) {
+               ntfs_debug("Done.");
+               return true;
        }
+       /*
+        * We cannot use ntfs_attr_set() because we may be still in the middle
+        * of a mount operation.  Thus we do the emptying by hand by first
+        * zapping the page cache pages for the $LogFile/$DATA attribute and
+        * then emptying each of the buffers in each of the clusters specified
+        * by the runlist by hand.
+        */
+       block_size = sb->s_blocksize;
+       block_size_bits = sb->s_blocksize_bits;
+       vcn = 0;
+       read_lock_irqsave(&log_ni->size_lock, flags);
+       end_vcn = (log_ni->initialized_size + vol->cluster_size_mask) >>
+                       vol->cluster_size_bits;
+       read_unlock_irqrestore(&log_ni->size_lock, flags);
+       truncate_inode_pages(log_vi->i_mapping, 0);
+       down_write(&log_ni->runlist.lock);
+       rl = log_ni->runlist.rl;
+       if (unlikely(!rl || vcn < rl->vcn || !rl->length)) {
+map_vcn:
+               err = ntfs_map_runlist_nolock(log_ni, vcn, NULL);
+               if (err) {
+                       ntfs_error(sb, "Failed to map runlist fragment (error "
+                                       "%d).", -err);
+                       goto err;
+               }
+               rl = log_ni->runlist.rl;
+               BUG_ON(!rl || vcn < rl->vcn || !rl->length);
+       }
+       /* Seek to the runlist element containing @vcn. */
+       while (rl->length && vcn >= rl[1].vcn)
+               rl++;
+       do {
+               LCN lcn;
+               sector_t block, end_block;
+               s64 len;
+
+               /*
+                * If this run is not mapped map it now and start again as the
+                * runlist will have been updated.
+                */
+               lcn = rl->lcn;
+               if (unlikely(lcn == LCN_RL_NOT_MAPPED)) {
+                       vcn = rl->vcn;
+                       goto map_vcn;
+               }
+               /* If this run is not valid abort with an error. */
+               if (unlikely(!rl->length || lcn < LCN_HOLE))
+                       goto rl_err;
+               /* Skip holes. */
+               if (lcn == LCN_HOLE)
+                       continue;
+               block = lcn << vol->cluster_size_bits >> block_size_bits;
+               len = rl->length;
+               if (rl[1].vcn > end_vcn)
+                       len = end_vcn - rl->vcn;
+               end_block = (lcn + len) << vol->cluster_size_bits >>
+                               block_size_bits;
+               /* Iterate over the blocks in the run and empty them. */
+               do {
+                       struct buffer_head *bh;
+
+                       /* Obtain the buffer, possibly not uptodate. */
+                       bh = sb_getblk(sb, block);
+                       BUG_ON(!bh);
+                       /* Setup buffer i/o submission. */
+                       lock_buffer(bh);
+                       bh->b_end_io = end_buffer_write_sync;
+                       get_bh(bh);
+                       /* Set the entire contents of the buffer to 0xff. */
+                       memset(bh->b_data, -1, block_size);
+                       if (!buffer_uptodate(bh))
+                               set_buffer_uptodate(bh);
+                       if (buffer_dirty(bh))
+                               clear_buffer_dirty(bh);
+                       /*
+                        * Submit the buffer and wait for i/o to complete but
+                        * only for the first buffer so we do not miss really
+                        * serious i/o errors.  Once the first buffer has
+                        * completed ignore errors afterwards as we can assume
+                        * that if one buffer worked all of them will work.
+                        */
+                       submit_bh(WRITE, bh);
+                       if (should_wait) {
+                               should_wait = false;
+                               wait_on_buffer(bh);
+                               if (unlikely(!buffer_uptodate(bh)))
+                                       goto io_err;
+                       }
+                       brelse(bh);
+               } while (++block < end_block);
+       } while ((++rl)->vcn < end_vcn);
+       up_write(&log_ni->runlist.lock);
+       /*
+        * Zap the pages again just in case any got instantiated whilst we were
+        * emptying the blocks by hand.  FIXME: We may not have completed
+        * writing to all the buffer heads yet so this may happen too early.
+        * We really should use a kernel thread to do the emptying
+        * asynchronously and then we can also set the volume dirty and output
+        * an error message if emptying should fail.
+        */
+       truncate_inode_pages(log_vi->i_mapping, 0);
+       /* Set the flag so we do not have to do it again on remount. */
+       NVolSetLogFileEmpty(vol);
        ntfs_debug("Done.");
        return true;
+io_err:
+       ntfs_error(sb, "Failed to write buffer.  Unmount and run chkdsk.");
+       goto dirty_err;
+rl_err:
+       ntfs_error(sb, "Runlist is corrupt.  Unmount and run chkdsk.");
+dirty_err:
+       NVolSetErrors(vol);
+       err = -EIO;
+err:
+       up_write(&log_ni->runlist.lock);
+       ntfs_error(sb, "Failed to fill $LogFile with 0xff bytes (error %d).",
+                       -err);
+       return false;
 }
 
 #endif /* NTFS_RW */
index 9afd72c7ad0db7c81f4487302971c2340cabecf0..56a9a6d25a2a8cddde3776a408bbd5b7535aa89c 100644 (file)
@@ -1,7 +1,7 @@
 /**
  * runlist.c - NTFS runlist handling code.  Part of the Linux-NTFS project.
  *
- * Copyright (c) 2001-2005 Anton Altaparmakov
+ * Copyright (c) 2001-2007 Anton Altaparmakov
  * Copyright (c) 2002-2005 Richard Russon
  *
  * This program/include file is free software; you can redistribute it and/or
@@ -1714,7 +1714,7 @@ extend_hole:
                                        sizeof(*rl));
                /* Adjust the beginning of the tail if necessary. */
                if (end > rl->vcn) {
-                       s64 delta = end - rl->vcn;
+                       delta = end - rl->vcn;
                        rl->vcn = end;
                        rl->length -= delta;
                        /* Only adjust the lcn if it is real. */
index 778a850b4634755c897c9708b2e2062e995e589b..4ba7f0bdc248e0ff4656b3a5a9bd56851233636f 100644 (file)
@@ -354,7 +354,6 @@ struct ocfs2_insert_type {
        enum ocfs2_append_type  ins_appending;
        enum ocfs2_contig_type  ins_contig;
        int                     ins_contig_index;
-       int                     ins_free_records;
        int                     ins_tree_depth;
 };
 
@@ -362,7 +361,6 @@ struct ocfs2_merge_ctxt {
        enum ocfs2_contig_type  c_contig_type;
        int                     c_has_empty_extent;
        int                     c_split_covers_rec;
-       int                     c_used_tail_recs;
 };
 
 /*
@@ -2808,36 +2806,28 @@ static int ocfs2_try_to_merge_extent(struct inode *inode,
                                     struct ocfs2_merge_ctxt *ctxt)
 
 {
-       int ret = 0, delete_tail_recs = 0;
+       int ret = 0;
        struct ocfs2_extent_list *el = path_leaf_el(left_path);
        struct ocfs2_extent_rec *rec = &el->l_recs[split_index];
 
        BUG_ON(ctxt->c_contig_type == CONTIG_NONE);
 
-       if (ctxt->c_split_covers_rec) {
-               delete_tail_recs++;
-
-               if (ctxt->c_contig_type == CONTIG_LEFTRIGHT ||
-                   ctxt->c_has_empty_extent)
-                       delete_tail_recs++;
-
-               if (ctxt->c_has_empty_extent) {
-                       /*
-                        * The merge code will need to create an empty
-                        * extent to take the place of the newly
-                        * emptied slot. Remove any pre-existing empty
-                        * extents - having more than one in a leaf is
-                        * illegal.
-                        */
-                       ret = ocfs2_rotate_tree_left(inode, handle, left_path,
-                                                    dealloc);
-                       if (ret) {
-                               mlog_errno(ret);
-                               goto out;
-                       }
-                       split_index--;
-                       rec = &el->l_recs[split_index];
+       if (ctxt->c_split_covers_rec && ctxt->c_has_empty_extent) {
+               /*
+                * The merge code will need to create an empty
+                * extent to take the place of the newly
+                * emptied slot. Remove any pre-existing empty
+                * extents - having more than one in a leaf is
+                * illegal.
+                */
+               ret = ocfs2_rotate_tree_left(inode, handle, left_path,
+                                            dealloc);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
                }
+               split_index--;
+               rec = &el->l_recs[split_index];
        }
 
        if (ctxt->c_contig_type == CONTIG_LEFTRIGHT) {
@@ -3593,6 +3583,7 @@ static int ocfs2_figure_insert_type(struct inode *inode,
                                    struct buffer_head *di_bh,
                                    struct buffer_head **last_eb_bh,
                                    struct ocfs2_extent_rec *insert_rec,
+                                   int *free_records,
                                    struct ocfs2_insert_type *insert)
 {
        int ret;
@@ -3633,7 +3624,7 @@ static int ocfs2_figure_insert_type(struct inode *inode,
         * XXX: This test is simplistic, we can search for empty
         * extent records too.
         */
-       insert->ins_free_records = le16_to_cpu(el->l_count) -
+       *free_records = le16_to_cpu(el->l_count) -
                le16_to_cpu(el->l_next_free_rec);
 
        if (!insert->ins_tree_depth) {
@@ -3730,10 +3721,13 @@ int ocfs2_insert_extent(struct ocfs2_super *osb,
                        struct ocfs2_alloc_context *meta_ac)
 {
        int status;
+       int uninitialized_var(free_records);
        struct buffer_head *last_eb_bh = NULL;
        struct ocfs2_insert_type insert = {0, };
        struct ocfs2_extent_rec rec;
 
+       BUG_ON(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL);
+
        mlog(0, "add %u clusters at position %u to inode %llu\n",
             new_clusters, cpos, (unsigned long long)OCFS2_I(inode)->ip_blkno);
 
@@ -3752,7 +3746,7 @@ int ocfs2_insert_extent(struct ocfs2_super *osb,
        rec.e_flags = flags;
 
        status = ocfs2_figure_insert_type(inode, fe_bh, &last_eb_bh, &rec,
-                                         &insert);
+                                         &free_records, &insert);
        if (status < 0) {
                mlog_errno(status);
                goto bail;
@@ -3762,9 +3756,9 @@ int ocfs2_insert_extent(struct ocfs2_super *osb,
             "Insert.contig_index: %d, Insert.free_records: %d, "
             "Insert.tree_depth: %d\n",
             insert.ins_appending, insert.ins_contig, insert.ins_contig_index,
-            insert.ins_free_records, insert.ins_tree_depth);
+            free_records, insert.ins_tree_depth);
 
-       if (insert.ins_contig == CONTIG_NONE && insert.ins_free_records == 0) {
+       if (insert.ins_contig == CONTIG_NONE && free_records == 0) {
                status = ocfs2_grow_tree(inode, handle, fe_bh,
                                         &insert.ins_tree_depth, &last_eb_bh,
                                         meta_ac);
@@ -3847,26 +3841,17 @@ leftright:
 
        if (le16_to_cpu(rightmost_el->l_next_free_rec) ==
            le16_to_cpu(rightmost_el->l_count)) {
-               int old_depth = depth;
-
                ret = ocfs2_grow_tree(inode, handle, di_bh, &depth, last_eb_bh,
                                      meta_ac);
                if (ret) {
                        mlog_errno(ret);
                        goto out;
                }
-
-               if (old_depth != depth) {
-                       eb = (struct ocfs2_extent_block *)(*last_eb_bh)->b_data;
-                       rightmost_el = &eb->h_list;
-               }
        }
 
        memset(&insert, 0, sizeof(struct ocfs2_insert_type));
        insert.ins_appending = APPEND_NONE;
        insert.ins_contig = CONTIG_NONE;
-       insert.ins_free_records = le16_to_cpu(rightmost_el->l_count)
-               - le16_to_cpu(rightmost_el->l_next_free_rec);
        insert.ins_tree_depth = depth;
 
        insert_range = le32_to_cpu(split_rec.e_cpos) +
@@ -4015,11 +4000,6 @@ static int __ocfs2_mark_extent_written(struct inode *inode,
        } else
                rightmost_el = path_root_el(path);
 
-       ctxt.c_used_tail_recs = le16_to_cpu(rightmost_el->l_next_free_rec);
-       if (ctxt.c_used_tail_recs > 0 &&
-           ocfs2_is_empty_extent(&rightmost_el->l_recs[0]))
-               ctxt.c_used_tail_recs--;
-
        if (rec->e_cpos == split_rec->e_cpos &&
            rec->e_leaf_clusters == split_rec->e_leaf_clusters)
                ctxt.c_split_covers_rec = 1;
@@ -4028,10 +4008,9 @@ static int __ocfs2_mark_extent_written(struct inode *inode,
 
        ctxt.c_has_empty_extent = ocfs2_is_empty_extent(&el->l_recs[0]);
 
-       mlog(0, "index: %d, contig: %u, used_tail_recs: %u, "
-            "has_empty: %u, split_covers: %u\n", split_index,
-            ctxt.c_contig_type, ctxt.c_used_tail_recs,
-            ctxt.c_has_empty_extent, ctxt.c_split_covers_rec);
+       mlog(0, "index: %d, contig: %u, has_empty: %u, split_covers: %u\n",
+            split_index, ctxt.c_contig_type, ctxt.c_has_empty_extent,
+            ctxt.c_split_covers_rec);
 
        if (ctxt.c_contig_type == CONTIG_NONE) {
                if (ctxt.c_split_covers_rec)
@@ -4180,27 +4159,18 @@ static int ocfs2_split_tree(struct inode *inode, struct buffer_head *di_bh,
 
        if (le16_to_cpu(rightmost_el->l_next_free_rec) ==
            le16_to_cpu(rightmost_el->l_count)) {
-               int old_depth = depth;
-
                ret = ocfs2_grow_tree(inode, handle, di_bh, &depth, &last_eb_bh,
                                      meta_ac);
                if (ret) {
                        mlog_errno(ret);
                        goto out;
                }
-
-               if (old_depth != depth) {
-                       eb = (struct ocfs2_extent_block *)last_eb_bh->b_data;
-                       rightmost_el = &eb->h_list;
-               }
        }
 
        memset(&insert, 0, sizeof(struct ocfs2_insert_type));
        insert.ins_appending = APPEND_NONE;
        insert.ins_contig = CONTIG_NONE;
        insert.ins_split = SPLIT_RIGHT;
-       insert.ins_free_records = le16_to_cpu(rightmost_el->l_count)
-               - le16_to_cpu(rightmost_el->l_next_free_rec);
        insert.ins_tree_depth = depth;
 
        ret = ocfs2_do_insert_extent(inode, handle, di_bh, &split_rec, &insert);
@@ -5665,12 +5635,50 @@ static int ocfs2_ordered_zero_func(handle_t *handle, struct buffer_head *bh)
        return ocfs2_journal_dirty_data(handle, bh);
 }
 
+static void ocfs2_map_and_dirty_page(struct inode *inode, handle_t *handle,
+                                    unsigned int from, unsigned int to,
+                                    struct page *page, int zero, u64 *phys)
+{
+       int ret, partial = 0;
+
+       ret = ocfs2_map_page_blocks(page, phys, inode, from, to, 0);
+       if (ret)
+               mlog_errno(ret);
+
+       if (zero)
+               zero_user_page(page, from, to - from, KM_USER0);
+
+       /*
+        * Need to set the buffers we zero'd into uptodate
+        * here if they aren't - ocfs2_map_page_blocks()
+        * might've skipped some
+        */
+       if (ocfs2_should_order_data(inode)) {
+               ret = walk_page_buffers(handle,
+                                       page_buffers(page),
+                                       from, to, &partial,
+                                       ocfs2_ordered_zero_func);
+               if (ret < 0)
+                       mlog_errno(ret);
+       } else {
+               ret = walk_page_buffers(handle, page_buffers(page),
+                                       from, to, &partial,
+                                       ocfs2_writeback_zero_func);
+               if (ret < 0)
+                       mlog_errno(ret);
+       }
+
+       if (!partial)
+               SetPageUptodate(page);
+
+       flush_dcache_page(page);
+}
+
 static void ocfs2_zero_cluster_pages(struct inode *inode, loff_t start,
                                     loff_t end, struct page **pages,
                                     int numpages, u64 phys, handle_t *handle)
 {
-       int i, ret, partial = 0;
-       void *kaddr;
+       int i;
        struct page *page;
        unsigned int from, to = PAGE_CACHE_SIZE;
        struct super_block *sb = inode->i_sb;
@@ -5691,87 +5699,31 @@ static void ocfs2_zero_cluster_pages(struct inode *inode, loff_t start,
                BUG_ON(from > PAGE_CACHE_SIZE);
                BUG_ON(to > PAGE_CACHE_SIZE);
 
-               ret = ocfs2_map_page_blocks(page, &phys, inode, from, to, 0);
-               if (ret)
-                       mlog_errno(ret);
-
-               kaddr = kmap_atomic(page, KM_USER0);
-               memset(kaddr + from, 0, to - from);
-               kunmap_atomic(kaddr, KM_USER0);
-
-               /*
-                * Need to set the buffers we zero'd into uptodate
-                * here if they aren't - ocfs2_map_page_blocks()
-                * might've skipped some
-                */
-               if (ocfs2_should_order_data(inode)) {
-                       ret = walk_page_buffers(handle,
-                                               page_buffers(page),
-                                               from, to, &partial,
-                                               ocfs2_ordered_zero_func);
-                       if (ret < 0)
-                               mlog_errno(ret);
-               } else {
-                       ret = walk_page_buffers(handle, page_buffers(page),
-                                               from, to, &partial,
-                                               ocfs2_writeback_zero_func);
-                       if (ret < 0)
-                               mlog_errno(ret);
-               }
-
-               if (!partial)
-                       SetPageUptodate(page);
-
-               flush_dcache_page(page);
+               ocfs2_map_and_dirty_page(inode, handle, from, to, page, 1,
+                                        &phys);
 
                start = (page->index + 1) << PAGE_CACHE_SHIFT;
        }
 out:
-       if (pages) {
-               for (i = 0; i < numpages; i++) {
-                       page = pages[i];
-                       unlock_page(page);
-                       mark_page_accessed(page);
-                       page_cache_release(page);
-               }
-       }
+       if (pages)
+               ocfs2_unlock_and_free_pages(pages, numpages);
 }
 
 static int ocfs2_grab_eof_pages(struct inode *inode, loff_t start, loff_t end,
-                               struct page **pages, int *num, u64 *phys)
+                               struct page **pages, int *num)
 {
-       int i, numpages = 0, ret = 0;
-       unsigned int ext_flags;
+       int numpages, ret = 0;
        struct super_block *sb = inode->i_sb;
        struct address_space *mapping = inode->i_mapping;
        unsigned long index;
        loff_t last_page_bytes;
 
-       BUG_ON(!ocfs2_sparse_alloc(OCFS2_SB(sb)));
        BUG_ON(start > end);
 
-       if (start == end)
-               goto out;
-
        BUG_ON(start >> OCFS2_SB(sb)->s_clustersize_bits !=
               (end - 1) >> OCFS2_SB(sb)->s_clustersize_bits);
 
-       ret = ocfs2_extent_map_get_blocks(inode, start >> sb->s_blocksize_bits,
-                                         phys, NULL, &ext_flags);
-       if (ret) {
-               mlog_errno(ret);
-               goto out;
-       }
-
-       /* Tail is a hole. */
-       if (*phys == 0)
-               goto out;
-
-       /* Tail is marked as unwritten, we can count on write to zero
-        * in that case. */
-       if (ext_flags & OCFS2_EXT_UNWRITTEN)
-               goto out;
-
+       numpages = 0;
        last_page_bytes = PAGE_ALIGN(end);
        index = start >> PAGE_CACHE_SHIFT;
        do {
@@ -5788,14 +5740,8 @@ static int ocfs2_grab_eof_pages(struct inode *inode, loff_t start, loff_t end,
 
 out:
        if (ret != 0) {
-               if (pages) {
-                       for (i = 0; i < numpages; i++) {
-                               if (pages[i]) {
-                                       unlock_page(pages[i]);
-                                       page_cache_release(pages[i]);
-                               }
-                       }
-               }
+               if (pages)
+                       ocfs2_unlock_and_free_pages(pages, numpages);
                numpages = 0;
        }
 
@@ -5816,18 +5762,20 @@ out:
 int ocfs2_zero_range_for_truncate(struct inode *inode, handle_t *handle,
                                  u64 range_start, u64 range_end)
 {
-       int ret, numpages;
+       int ret = 0, numpages;
        struct page **pages = NULL;
        u64 phys;
+       unsigned int ext_flags;
+       struct super_block *sb = inode->i_sb;
 
        /*
         * File systems which don't support sparse files zero on every
         * extend.
         */
-       if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb)))
+       if (!ocfs2_sparse_alloc(OCFS2_SB(sb)))
                return 0;
 
-       pages = kcalloc(ocfs2_pages_per_cluster(inode->i_sb),
+       pages = kcalloc(ocfs2_pages_per_cluster(sb),
                        sizeof(struct page *), GFP_NOFS);
        if (pages == NULL) {
                ret = -ENOMEM;
@@ -5835,16 +5783,31 @@ int ocfs2_zero_range_for_truncate(struct inode *inode, handle_t *handle,
                goto out;
        }
 
-       ret = ocfs2_grab_eof_pages(inode, range_start, range_end, pages,
-                                  &numpages, &phys);
+       if (range_start == range_end)
+               goto out;
+
+       ret = ocfs2_extent_map_get_blocks(inode,
+                                         range_start >> sb->s_blocksize_bits,
+                                         &phys, NULL, &ext_flags);
        if (ret) {
                mlog_errno(ret);
                goto out;
        }
 
-       if (numpages == 0)
+       /*
+        * Tail is a hole, or is marked unwritten. In either case, we
+        * can count on read and write to return/push zero's.
+        */
+       if (phys == 0 || ext_flags & OCFS2_EXT_UNWRITTEN)
                goto out;
 
+       ret = ocfs2_grab_eof_pages(inode, range_start, range_end, pages,
+                                  &numpages);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
        ocfs2_zero_cluster_pages(inode, range_start, range_end, pages,
                                 numpages, phys, handle);
 
@@ -5865,6 +5828,178 @@ out:
        return ret;
 }
 
+static void ocfs2_zero_dinode_id2(struct inode *inode, struct ocfs2_dinode *di)
+{
+       unsigned int blocksize = 1 << inode->i_sb->s_blocksize_bits;
+
+       memset(&di->id2, 0, blocksize - offsetof(struct ocfs2_dinode, id2));
+}
+
+void ocfs2_dinode_new_extent_list(struct inode *inode,
+                                 struct ocfs2_dinode *di)
+{
+       ocfs2_zero_dinode_id2(inode, di);
+       di->id2.i_list.l_tree_depth = 0;
+       di->id2.i_list.l_next_free_rec = 0;
+       di->id2.i_list.l_count = cpu_to_le16(ocfs2_extent_recs_per_inode(inode->i_sb));
+}
+
+void ocfs2_set_inode_data_inline(struct inode *inode, struct ocfs2_dinode *di)
+{
+       struct ocfs2_inode_info *oi = OCFS2_I(inode);
+       struct ocfs2_inline_data *idata = &di->id2.i_data;
+
+       spin_lock(&oi->ip_lock);
+       oi->ip_dyn_features |= OCFS2_INLINE_DATA_FL;
+       di->i_dyn_features = cpu_to_le16(oi->ip_dyn_features);
+       spin_unlock(&oi->ip_lock);
+
+       /*
+        * We clear the entire i_data structure here so that all
+        * fields can be properly initialized.
+        */
+       ocfs2_zero_dinode_id2(inode, di);
+
+       idata->id_count = cpu_to_le16(ocfs2_max_inline_data(inode->i_sb));
+}
+
+int ocfs2_convert_inline_data_to_extents(struct inode *inode,
+                                        struct buffer_head *di_bh)
+{
+       int ret, i, has_data, num_pages = 0;
+       handle_t *handle;
+       u64 uninitialized_var(block);
+       struct ocfs2_inode_info *oi = OCFS2_I(inode);
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+       struct ocfs2_alloc_context *data_ac = NULL;
+       struct page **pages = NULL;
+       loff_t end = osb->s_clustersize;
+
+       has_data = i_size_read(inode) ? 1 : 0;
+
+       if (has_data) {
+               pages = kcalloc(ocfs2_pages_per_cluster(osb->sb),
+                               sizeof(struct page *), GFP_NOFS);
+               if (pages == NULL) {
+                       ret = -ENOMEM;
+                       mlog_errno(ret);
+                       goto out;
+               }
+
+               ret = ocfs2_reserve_clusters(osb, 1, &data_ac);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+       }
+
+       handle = ocfs2_start_trans(osb, OCFS2_INLINE_TO_EXTENTS_CREDITS);
+       if (IS_ERR(handle)) {
+               ret = PTR_ERR(handle);
+               mlog_errno(ret);
+               goto out_unlock;
+       }
+
+       ret = ocfs2_journal_access(handle, inode, di_bh,
+                                  OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       if (has_data) {
+               u32 bit_off, num;
+               unsigned int page_end;
+               u64 phys;
+
+               ret = ocfs2_claim_clusters(osb, handle, data_ac, 1, &bit_off,
+                                          &num);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out_commit;
+               }
+
+               /*
+                * Save two copies, one for insert, and one that can
+                * be changed by ocfs2_map_and_dirty_page() below.
+                */
+               block = phys = ocfs2_clusters_to_blocks(inode->i_sb, bit_off);
+
+               /*
+                * Non sparse file systems zero on extend, so no need
+                * to do that now.
+                */
+               if (!ocfs2_sparse_alloc(osb) &&
+                   PAGE_CACHE_SIZE < osb->s_clustersize)
+                       end = PAGE_CACHE_SIZE;
+
+               ret = ocfs2_grab_eof_pages(inode, 0, end, pages, &num_pages);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out_commit;
+               }
+
+               /*
+                * This should populate the 1st page for us and mark
+                * it up to date.
+                */
+               ret = ocfs2_read_inline_data(inode, pages[0], di_bh);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out_commit;
+               }
+
+               page_end = PAGE_CACHE_SIZE;
+               if (PAGE_CACHE_SIZE > osb->s_clustersize)
+                       page_end = osb->s_clustersize;
+
+               for (i = 0; i < num_pages; i++)
+                       ocfs2_map_and_dirty_page(inode, handle, 0, page_end,
+                                                pages[i], i > 0, &phys);
+       }
+
+       spin_lock(&oi->ip_lock);
+       oi->ip_dyn_features &= ~OCFS2_INLINE_DATA_FL;
+       di->i_dyn_features = cpu_to_le16(oi->ip_dyn_features);
+       spin_unlock(&oi->ip_lock);
+
+       ocfs2_dinode_new_extent_list(inode, di);
+
+       ocfs2_journal_dirty(handle, di_bh);
+
+       if (has_data) {
+               /*
+                * An error at this point should be extremely rare. If
+                * this proves to be false, we could always re-build
+                * the in-inode data from our pages.
+                */
+               ret = ocfs2_insert_extent(osb, handle, inode, di_bh,
+                                         0, block, 1, 0, NULL);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out_commit;
+               }
+
+               inode->i_blocks = ocfs2_inode_sector_count(inode);
+       }
+
+out_commit:
+       ocfs2_commit_trans(osb, handle);
+
+out_unlock:
+       if (data_ac)
+               ocfs2_free_alloc_context(data_ac);
+
+out:
+       if (pages) {
+               ocfs2_unlock_and_free_pages(pages, num_pages);
+               kfree(pages);
+       }
+
+       return ret;
+}
+
 /*
  * It is expected, that by the time you call this function,
  * inode->i_size and fe->i_size have been adjusted.
@@ -6090,6 +6225,81 @@ bail:
        return status;
 }
 
+/*
+ * 'start' is inclusive, 'end' is not.
+ */
+int ocfs2_truncate_inline(struct inode *inode, struct buffer_head *di_bh,
+                         unsigned int start, unsigned int end, int trunc)
+{
+       int ret;
+       unsigned int numbytes;
+       handle_t *handle;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+       struct ocfs2_inline_data *idata = &di->id2.i_data;
+
+       if (end > i_size_read(inode))
+               end = i_size_read(inode);
+
+       BUG_ON(start >= end);
+
+       if (!(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) ||
+           !(le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_DATA_FL) ||
+           !ocfs2_supports_inline_data(osb)) {
+               ocfs2_error(inode->i_sb,
+                           "Inline data flags for inode %llu don't agree! "
+                           "Disk: 0x%x, Memory: 0x%x, Superblock: 0x%x\n",
+                           (unsigned long long)OCFS2_I(inode)->ip_blkno,
+                           le16_to_cpu(di->i_dyn_features),
+                           OCFS2_I(inode)->ip_dyn_features,
+                           osb->s_feature_incompat);
+               ret = -EROFS;
+               goto out;
+       }
+
+       handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
+       if (IS_ERR(handle)) {
+               ret = PTR_ERR(handle);
+               mlog_errno(ret);
+               goto out;
+       }
+
+       ret = ocfs2_journal_access(handle, inode, di_bh,
+                                  OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       numbytes = end - start;
+       memset(idata->id_data + start, 0, numbytes);
+
+       /*
+        * No need to worry about the data page here - it's been
+        * truncated already and inline data doesn't need it for
+        * pushing zero's to disk, so we'll let readpage pick it up
+        * later.
+        */
+       if (trunc) {
+               i_size_write(inode, start);
+               di->i_size = cpu_to_le64(start);
+       }
+
+       inode->i_blocks = ocfs2_inode_sector_count(inode);
+       inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+
+       di->i_ctime = di->i_mtime = cpu_to_le64(inode->i_ctime.tv_sec);
+       di->i_ctime_nsec = di->i_mtime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec);
+
+       ocfs2_journal_dirty(handle, di_bh);
+
+out_commit:
+       ocfs2_commit_trans(osb, handle);
+
+out:
+       return ret;
+}
+
 static void ocfs2_free_truncate_context(struct ocfs2_truncate_context *tc)
 {
        /*
index 990df48ae8d361459ee27b42cccfb7b0f935c222..42ff94bd8011f541cfd82ad45faaca17f742a80a 100644 (file)
@@ -62,6 +62,11 @@ static inline int ocfs2_extend_meta_needed(struct ocfs2_dinode *fe)
        return le16_to_cpu(fe->id2.i_list.l_tree_depth) + 2;
 }
 
+void ocfs2_dinode_new_extent_list(struct inode *inode, struct ocfs2_dinode *di);
+void ocfs2_set_inode_data_inline(struct inode *inode, struct ocfs2_dinode *di);
+int ocfs2_convert_inline_data_to_extents(struct inode *inode,
+                                        struct buffer_head *di_bh);
+
 int ocfs2_truncate_log_init(struct ocfs2_super *osb);
 void ocfs2_truncate_log_shutdown(struct ocfs2_super *osb);
 void ocfs2_schedule_truncate_log_flush(struct ocfs2_super *osb,
@@ -115,6 +120,8 @@ int ocfs2_commit_truncate(struct ocfs2_super *osb,
                          struct inode *inode,
                          struct buffer_head *fe_bh,
                          struct ocfs2_truncate_context *tc);
+int ocfs2_truncate_inline(struct inode *inode, struct buffer_head *di_bh,
+                         unsigned int start, unsigned int end, int trunc);
 
 int ocfs2_find_leaf(struct inode *inode, struct ocfs2_extent_list *root_el,
                    u32 cpos, struct buffer_head **leaf_bh);
index f37f25c931f59f7e8b6b5c27ab502529f8621834..34d10452c56d305f13edeb8cab0228bac50304f4 100644 (file)
@@ -206,9 +206,70 @@ bail:
        return err;
 }
 
+int ocfs2_read_inline_data(struct inode *inode, struct page *page,
+                          struct buffer_head *di_bh)
+{
+       void *kaddr;
+       unsigned int size;
+       struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+
+       if (!(le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_DATA_FL)) {
+               ocfs2_error(inode->i_sb, "Inode %llu lost inline data flag",
+                           (unsigned long long)OCFS2_I(inode)->ip_blkno);
+               return -EROFS;
+       }
+
+       size = i_size_read(inode);
+
+       if (size > PAGE_CACHE_SIZE ||
+           size > ocfs2_max_inline_data(inode->i_sb)) {
+               ocfs2_error(inode->i_sb,
+                           "Inode %llu has with inline data has bad size: %u",
+                           (unsigned long long)OCFS2_I(inode)->ip_blkno, size);
+               return -EROFS;
+       }
+
+       kaddr = kmap_atomic(page, KM_USER0);
+       if (size)
+               memcpy(kaddr, di->id2.i_data.id_data, size);
+       /* Clear the remaining part of the page */
+       memset(kaddr + size, 0, PAGE_CACHE_SIZE - size);
+       flush_dcache_page(page);
+       kunmap_atomic(kaddr, KM_USER0);
+
+       SetPageUptodate(page);
+
+       return 0;
+}
+
+static int ocfs2_readpage_inline(struct inode *inode, struct page *page)
+{
+       int ret;
+       struct buffer_head *di_bh = NULL;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+       BUG_ON(!PageLocked(page));
+       BUG_ON(!OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL);
+
+       ret = ocfs2_read_block(osb, OCFS2_I(inode)->ip_blkno, &di_bh,
+                              OCFS2_BH_CACHED, inode);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       ret = ocfs2_read_inline_data(inode, page, di_bh);
+out:
+       unlock_page(page);
+
+       brelse(di_bh);
+       return ret;
+}
+
 static int ocfs2_readpage(struct file *file, struct page *page)
 {
        struct inode *inode = page->mapping->host;
+       struct ocfs2_inode_info *oi = OCFS2_I(inode);
        loff_t start = (loff_t)page->index << PAGE_CACHE_SHIFT;
        int ret, unlock = 1;
 
@@ -222,7 +283,7 @@ static int ocfs2_readpage(struct file *file, struct page *page)
                goto out;
        }
 
-       if (down_read_trylock(&OCFS2_I(inode)->ip_alloc_sem) == 0) {
+       if (down_read_trylock(&oi->ip_alloc_sem) == 0) {
                ret = AOP_TRUNCATED_PAGE;
                goto out_meta_unlock;
        }
@@ -252,7 +313,10 @@ static int ocfs2_readpage(struct file *file, struct page *page)
                goto out_alloc;
        }
 
-       ret = block_read_full_page(page, ocfs2_get_block);
+       if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL)
+               ret = ocfs2_readpage_inline(inode, page);
+       else
+               ret = block_read_full_page(page, ocfs2_get_block);
        unlock = 0;
 
        ocfs2_data_unlock(inode, 0);
@@ -301,12 +365,8 @@ int ocfs2_prepare_write_nolock(struct inode *inode, struct page *page,
 {
        int ret;
 
-       down_read(&OCFS2_I(inode)->ip_alloc_sem);
-
        ret = block_prepare_write(page, from, to, ocfs2_get_block);
 
-       up_read(&OCFS2_I(inode)->ip_alloc_sem);
-
        return ret;
 }
 
@@ -401,7 +461,9 @@ static sector_t ocfs2_bmap(struct address_space *mapping, sector_t block)
                down_read(&OCFS2_I(inode)->ip_alloc_sem);
        }
 
-       err = ocfs2_extent_map_get_blocks(inode, block, &p_blkno, NULL, NULL);
+       if (!(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL))
+               err = ocfs2_extent_map_get_blocks(inode, block, &p_blkno, NULL,
+                                                 NULL);
 
        if (!INODE_JOURNAL(inode)) {
                up_read(&OCFS2_I(inode)->ip_alloc_sem);
@@ -415,7 +477,6 @@ static sector_t ocfs2_bmap(struct address_space *mapping, sector_t block)
                goto bail;
        }
 
-
 bail:
        status = err ? 0 : p_blkno;
 
@@ -570,6 +631,13 @@ static ssize_t ocfs2_direct_IO(int rw,
 
        mlog_entry_void();
 
+       /*
+        * Fallback to buffered I/O if we see an inode without
+        * extents.
+        */
+       if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
+               return 0;
+
        if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) {
                /*
                 * We get PR data locks even for O_DIRECT.  This
@@ -834,18 +902,22 @@ struct ocfs2_write_ctxt {
        struct ocfs2_cached_dealloc_ctxt w_dealloc;
 };
 
-static void ocfs2_free_write_ctxt(struct ocfs2_write_ctxt *wc)
+void ocfs2_unlock_and_free_pages(struct page **pages, int num_pages)
 {
        int i;
 
-       for(i = 0; i < wc->w_num_pages; i++) {
-               if (wc->w_pages[i] == NULL)
-                       continue;
-
-               unlock_page(wc->w_pages[i]);
-               mark_page_accessed(wc->w_pages[i]);
-               page_cache_release(wc->w_pages[i]);
+       for(i = 0; i < num_pages; i++) {
+               if (pages[i]) {
+                       unlock_page(pages[i]);
+                       mark_page_accessed(pages[i]);
+                       page_cache_release(pages[i]);
+               }
        }
+}
+
+static void ocfs2_free_write_ctxt(struct ocfs2_write_ctxt *wc)
+{
+       ocfs2_unlock_and_free_pages(wc->w_pages, wc->w_num_pages);
 
        brelse(wc->w_di_bh);
        kfree(wc);
@@ -1360,6 +1432,160 @@ out:
        return ret;
 }
 
+static int ocfs2_write_begin_inline(struct address_space *mapping,
+                                   struct inode *inode,
+                                   struct ocfs2_write_ctxt *wc)
+{
+       int ret;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       struct page *page;
+       handle_t *handle;
+       struct ocfs2_dinode *di = (struct ocfs2_dinode *)wc->w_di_bh->b_data;
+
+       page = find_or_create_page(mapping, 0, GFP_NOFS);
+       if (!page) {
+               ret = -ENOMEM;
+               mlog_errno(ret);
+               goto out;
+       }
+       /*
+        * If we don't set w_num_pages then this page won't get unlocked
+        * and freed on cleanup of the write context.
+        */
+       wc->w_pages[0] = wc->w_target_page = page;
+       wc->w_num_pages = 1;
+
+       handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
+       if (IS_ERR(handle)) {
+               ret = PTR_ERR(handle);
+               mlog_errno(ret);
+               goto out;
+       }
+
+       ret = ocfs2_journal_access(handle, inode, wc->w_di_bh,
+                                  OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret) {
+               ocfs2_commit_trans(osb, handle);
+
+               mlog_errno(ret);
+               goto out;
+       }
+
+       if (!(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL))
+               ocfs2_set_inode_data_inline(inode, di);
+
+       if (!PageUptodate(page)) {
+               ret = ocfs2_read_inline_data(inode, page, wc->w_di_bh);
+               if (ret) {
+                       ocfs2_commit_trans(osb, handle);
+
+                       goto out;
+               }
+       }
+
+       wc->w_handle = handle;
+out:
+       return ret;
+}
+
+int ocfs2_size_fits_inline_data(struct buffer_head *di_bh, u64 new_size)
+{
+       struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+
+       if (new_size < le16_to_cpu(di->id2.i_data.id_count))
+               return 1;
+       return 0;
+}
+
+static int ocfs2_try_to_write_inline_data(struct address_space *mapping,
+                                         struct inode *inode, loff_t pos,
+                                         unsigned len, struct page *mmap_page,
+                                         struct ocfs2_write_ctxt *wc)
+{
+       int ret, written = 0;
+       loff_t end = pos + len;
+       struct ocfs2_inode_info *oi = OCFS2_I(inode);
+
+       mlog(0, "Inode %llu, write of %u bytes at off %llu. features: 0x%x\n",
+            (unsigned long long)oi->ip_blkno, len, (unsigned long long)pos,
+            oi->ip_dyn_features);
+
+       /*
+        * Handle inodes which already have inline data 1st.
+        */
+       if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+               if (mmap_page == NULL &&
+                   ocfs2_size_fits_inline_data(wc->w_di_bh, end))
+                       goto do_inline_write;
+
+               /*
+                * The write won't fit - we have to give this inode an
+                * inline extent list now.
+                */
+               ret = ocfs2_convert_inline_data_to_extents(inode, wc->w_di_bh);
+               if (ret)
+                       mlog_errno(ret);
+               goto out;
+       }
+
+       /*
+        * Check whether the inode can accept inline data.
+        */
+       if (oi->ip_clusters != 0 || i_size_read(inode) != 0)
+               return 0;
+
+       /*
+        * Check whether the write can fit.
+        */
+       if (mmap_page || end > ocfs2_max_inline_data(inode->i_sb))
+               return 0;
+
+do_inline_write:
+       ret = ocfs2_write_begin_inline(mapping, inode, wc);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       /*
+        * This signals to the caller that the data can be written
+        * inline.
+        */
+       written = 1;
+out:
+       return written ? written : ret;
+}
+
+/*
+ * This function only does anything for file systems which can't
+ * handle sparse files.
+ *
+ * What we want to do here is fill in any hole between the current end
+ * of allocation and the end of our write. That way the rest of the
+ * write path can treat it as an non-allocating write, which has no
+ * special case code for sparse/nonsparse files.
+ */
+static int ocfs2_expand_nonsparse_inode(struct inode *inode, loff_t pos,
+                                       unsigned len,
+                                       struct ocfs2_write_ctxt *wc)
+{
+       int ret;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       loff_t newsize = pos + len;
+
+       if (ocfs2_sparse_alloc(osb))
+               return 0;
+
+       if (newsize <= i_size_read(inode))
+               return 0;
+
+       ret = ocfs2_extend_no_holes(inode, newsize, newsize - len);
+       if (ret)
+               mlog_errno(ret);
+
+       return ret;
+}
+
 int ocfs2_write_begin_nolock(struct address_space *mapping,
                             loff_t pos, unsigned len, unsigned flags,
                             struct page **pagep, void **fsdata,
@@ -1381,6 +1607,25 @@ int ocfs2_write_begin_nolock(struct address_space *mapping,
                return ret;
        }
 
+       if (ocfs2_supports_inline_data(osb)) {
+               ret = ocfs2_try_to_write_inline_data(mapping, inode, pos, len,
+                                                    mmap_page, wc);
+               if (ret == 1) {
+                       ret = 0;
+                       goto success;
+               }
+               if (ret < 0) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+       }
+
+       ret = ocfs2_expand_nonsparse_inode(inode, pos, len, wc);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
        ret = ocfs2_populate_write_desc(inode, wc, &clusters_to_alloc,
                                        &extents_to_split);
        if (ret) {
@@ -1462,6 +1707,7 @@ int ocfs2_write_begin_nolock(struct address_space *mapping,
        if (meta_ac)
                ocfs2_free_alloc_context(meta_ac);
 
+success:
        *pagep = wc->w_target_page;
        *fsdata = wc;
        return 0;
@@ -1529,6 +1775,31 @@ out_fail:
        return ret;
 }
 
+static void ocfs2_write_end_inline(struct inode *inode, loff_t pos,
+                                  unsigned len, unsigned *copied,
+                                  struct ocfs2_dinode *di,
+                                  struct ocfs2_write_ctxt *wc)
+{
+       void *kaddr;
+
+       if (unlikely(*copied < len)) {
+               if (!PageUptodate(wc->w_target_page)) {
+                       *copied = 0;
+                       return;
+               }
+       }
+
+       kaddr = kmap_atomic(wc->w_target_page, KM_USER0);
+       memcpy(di->id2.i_data.id_data + pos, kaddr + pos, *copied);
+       kunmap_atomic(kaddr, KM_USER0);
+
+       mlog(0, "Data written to inode at offset %llu. "
+            "id_count = %u, copied = %u, i_dyn_features = 0x%x\n",
+            (unsigned long long)pos, *copied,
+            le16_to_cpu(di->id2.i_data.id_count),
+            le16_to_cpu(di->i_dyn_features));
+}
+
 int ocfs2_write_end_nolock(struct address_space *mapping,
                           loff_t pos, unsigned len, unsigned copied,
                           struct page *page, void *fsdata)
@@ -1542,6 +1813,11 @@ int ocfs2_write_end_nolock(struct address_space *mapping,
        handle_t *handle = wc->w_handle;
        struct page *tmppage;
 
+       if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+               ocfs2_write_end_inline(inode, pos, len, &copied, di, wc);
+               goto out_write_size;
+       }
+
        if (unlikely(copied < len)) {
                if (!PageUptodate(wc->w_target_page))
                        copied = 0;
@@ -1579,6 +1855,7 @@ int ocfs2_write_end_nolock(struct address_space *mapping,
                block_commit_write(tmppage, from, to);
        }
 
+out_write_size:
        pos += copied;
        if (pos > inode->i_size) {
                i_size_write(inode, pos);
index 389579bd64e372e8294858d63d5b0d913fee648a..113560877dbb2f821a25ab3b36387b578de044cc 100644 (file)
@@ -34,6 +34,8 @@ int ocfs2_map_page_blocks(struct page *page, u64 *p_blkno,
                          struct inode *inode, unsigned int from,
                          unsigned int to, int new);
 
+void ocfs2_unlock_and_free_pages(struct page **pages, int num_pages);
+
 int walk_page_buffers( handle_t *handle,
                        struct buffer_head *head,
                        unsigned from,
@@ -59,6 +61,10 @@ int ocfs2_write_begin_nolock(struct address_space *mapping,
                             struct page **pagep, void **fsdata,
                             struct buffer_head *di_bh, struct page *mmap_page);
 
+int ocfs2_read_inline_data(struct inode *inode, struct page *page,
+                          struct buffer_head *di_bh);
+int ocfs2_size_fits_inline_data(struct buffer_head *di_bh, u64 new_size);
+
 /* all ocfs2_dio_end_io()'s fault */
 #define ocfs2_iocb_is_rw_locked(iocb) \
        test_bit(0, (unsigned long *)&iocb->private)
index e9e042b93dbf520ed9dc2c4b64a0e1b96590c0a1..a4882c8df945ef402694d8b4a392261a0db45dea 100644 (file)
@@ -143,7 +143,7 @@ static struct kobj_type mlog_ktype = {
 };
 
 static struct kset mlog_kset = {
-       .kobj   = {.name = "logmask", .ktype = &mlog_ktype},
+       .kobj   = {.ktype = &mlog_ktype},
 };
 
 int mlog_sys_init(struct kset *o2cb_subsys)
@@ -156,6 +156,7 @@ int mlog_sys_init(struct kset *o2cb_subsys)
        }
        mlog_attr_ptrs[i] = NULL;
 
+       kobject_set_name(&mlog_kset.kobj, "logmask");
        kobj_set_kset_s(&mlog_kset, *o2cb_subsys);
        return kset_register(&mlog_kset);
 }
index 0d5fdde959c8018a2d244ae678d16fde1e5b3f33..7453b70c1a1901ee6ee551be4a258a20a63d9526 100644 (file)
 #include "journal.h"
 #include "namei.h"
 #include "suballoc.h"
+#include "super.h"
 #include "uptodate.h"
 
 #include "buffer_head_io.h"
 
+#define NAMEI_RA_CHUNKS  2
+#define NAMEI_RA_BLOCKS  4
+#define NAMEI_RA_SIZE        (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS)
+#define NAMEI_RA_INDEX(c,b)  (((c) * NAMEI_RA_BLOCKS) + (b))
+
 static unsigned char ocfs2_filetype_table[] = {
        DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
 };
@@ -66,12 +72,614 @@ static unsigned char ocfs2_filetype_table[] = {
 static int ocfs2_extend_dir(struct ocfs2_super *osb,
                            struct inode *dir,
                            struct buffer_head *parent_fe_bh,
+                           unsigned int blocks_wanted,
                            struct buffer_head **new_de_bh);
+static int ocfs2_do_extend_dir(struct super_block *sb,
+                              handle_t *handle,
+                              struct inode *dir,
+                              struct buffer_head *parent_fe_bh,
+                              struct ocfs2_alloc_context *data_ac,
+                              struct ocfs2_alloc_context *meta_ac,
+                              struct buffer_head **new_bh);
+
 /*
- * ocfs2_readdir()
+ * bh passed here can be an inode block or a dir data block, depending
+ * on the inode inline data flag.
+ */
+static int ocfs2_check_dir_entry(struct inode * dir,
+                                struct ocfs2_dir_entry * de,
+                                struct buffer_head * bh,
+                                unsigned long offset)
+{
+       const char *error_msg = NULL;
+       const int rlen = le16_to_cpu(de->rec_len);
+
+       if (rlen < OCFS2_DIR_REC_LEN(1))
+               error_msg = "rec_len is smaller than minimal";
+       else if (rlen % 4 != 0)
+               error_msg = "rec_len % 4 != 0";
+       else if (rlen < OCFS2_DIR_REC_LEN(de->name_len))
+               error_msg = "rec_len is too small for name_len";
+       else if (((char *) de - bh->b_data) + rlen > dir->i_sb->s_blocksize)
+               error_msg = "directory entry across blocks";
+
+       if (error_msg != NULL)
+               mlog(ML_ERROR, "bad entry in directory #%llu: %s - "
+                    "offset=%lu, inode=%llu, rec_len=%d, name_len=%d\n",
+                    (unsigned long long)OCFS2_I(dir)->ip_blkno, error_msg,
+                    offset, (unsigned long long)le64_to_cpu(de->inode), rlen,
+                    de->name_len);
+       return error_msg == NULL ? 1 : 0;
+}
+
+static inline int ocfs2_match(int len,
+                             const char * const name,
+                             struct ocfs2_dir_entry *de)
+{
+       if (len != de->name_len)
+               return 0;
+       if (!de->inode)
+               return 0;
+       return !memcmp(name, de->name, len);
+}
+
+/*
+ * Returns 0 if not found, -1 on failure, and 1 on success
+ */
+static int inline ocfs2_search_dirblock(struct buffer_head *bh,
+                                       struct inode *dir,
+                                       const char *name, int namelen,
+                                       unsigned long offset,
+                                       char *first_de,
+                                       unsigned int bytes,
+                                       struct ocfs2_dir_entry **res_dir)
+{
+       struct ocfs2_dir_entry *de;
+       char *dlimit, *de_buf;
+       int de_len;
+       int ret = 0;
+
+       mlog_entry_void();
+
+       de_buf = first_de;
+       dlimit = de_buf + bytes;
+
+       while (de_buf < dlimit) {
+               /* this code is executed quadratically often */
+               /* do minimal checking `by hand' */
+
+               de = (struct ocfs2_dir_entry *) de_buf;
+
+               if (de_buf + namelen <= dlimit &&
+                   ocfs2_match(namelen, name, de)) {
+                       /* found a match - just to be sure, do a full check */
+                       if (!ocfs2_check_dir_entry(dir, de, bh, offset)) {
+                               ret = -1;
+                               goto bail;
+                       }
+                       *res_dir = de;
+                       ret = 1;
+                       goto bail;
+               }
+
+               /* prevent looping on a bad block */
+               de_len = le16_to_cpu(de->rec_len);
+               if (de_len <= 0) {
+                       ret = -1;
+                       goto bail;
+               }
+
+               de_buf += de_len;
+               offset += de_len;
+       }
+
+bail:
+       mlog_exit(ret);
+       return ret;
+}
+
+static struct buffer_head *ocfs2_find_entry_id(const char *name,
+                                              int namelen,
+                                              struct inode *dir,
+                                              struct ocfs2_dir_entry **res_dir)
+{
+       int ret, found;
+       struct buffer_head *di_bh = NULL;
+       struct ocfs2_dinode *di;
+       struct ocfs2_inline_data *data;
+
+       ret = ocfs2_read_block(OCFS2_SB(dir->i_sb), OCFS2_I(dir)->ip_blkno,
+                              &di_bh, OCFS2_BH_CACHED, dir);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       di = (struct ocfs2_dinode *)di_bh->b_data;
+       data = &di->id2.i_data;
+
+       found = ocfs2_search_dirblock(di_bh, dir, name, namelen, 0,
+                                     data->id_data, i_size_read(dir), res_dir);
+       if (found == 1)
+               return di_bh;
+
+       brelse(di_bh);
+out:
+       return NULL;
+}
+
+struct buffer_head *ocfs2_find_entry_el(const char *name, int namelen,
+                                       struct inode *dir,
+                                       struct ocfs2_dir_entry **res_dir)
+{
+       struct super_block *sb;
+       struct buffer_head *bh_use[NAMEI_RA_SIZE];
+       struct buffer_head *bh, *ret = NULL;
+       unsigned long start, block, b;
+       int ra_max = 0;         /* Number of bh's in the readahead
+                                  buffer, bh_use[] */
+       int ra_ptr = 0;         /* Current index into readahead
+                                  buffer */
+       int num = 0;
+       int nblocks, i, err;
+
+       mlog_entry_void();
+
+       sb = dir->i_sb;
+
+       nblocks = i_size_read(dir) >> sb->s_blocksize_bits;
+       start = OCFS2_I(dir)->ip_dir_start_lookup;
+       if (start >= nblocks)
+               start = 0;
+       block = start;
+
+restart:
+       do {
+               /*
+                * We deal with the read-ahead logic here.
+                */
+               if (ra_ptr >= ra_max) {
+                       /* Refill the readahead buffer */
+                       ra_ptr = 0;
+                       b = block;
+                       for (ra_max = 0; ra_max < NAMEI_RA_SIZE; ra_max++) {
+                               /*
+                                * Terminate if we reach the end of the
+                                * directory and must wrap, or if our
+                                * search has finished at this block.
+                                */
+                               if (b >= nblocks || (num && block == start)) {
+                                       bh_use[ra_max] = NULL;
+                                       break;
+                               }
+                               num++;
+
+                               bh = ocfs2_bread(dir, b++, &err, 1);
+                               bh_use[ra_max] = bh;
+                       }
+               }
+               if ((bh = bh_use[ra_ptr++]) == NULL)
+                       goto next;
+               wait_on_buffer(bh);
+               if (!buffer_uptodate(bh)) {
+                       /* read error, skip block & hope for the best */
+                       ocfs2_error(dir->i_sb, "reading directory %llu, "
+                                   "offset %lu\n",
+                                   (unsigned long long)OCFS2_I(dir)->ip_blkno,
+                                   block);
+                       brelse(bh);
+                       goto next;
+               }
+               i = ocfs2_search_dirblock(bh, dir, name, namelen,
+                                         block << sb->s_blocksize_bits,
+                                         bh->b_data, sb->s_blocksize,
+                                         res_dir);
+               if (i == 1) {
+                       OCFS2_I(dir)->ip_dir_start_lookup = block;
+                       ret = bh;
+                       goto cleanup_and_exit;
+               } else {
+                       brelse(bh);
+                       if (i < 0)
+                               goto cleanup_and_exit;
+               }
+       next:
+               if (++block >= nblocks)
+                       block = 0;
+       } while (block != start);
+
+       /*
+        * If the directory has grown while we were searching, then
+        * search the last part of the directory before giving up.
+        */
+       block = nblocks;
+       nblocks = i_size_read(dir) >> sb->s_blocksize_bits;
+       if (block < nblocks) {
+               start = 0;
+               goto restart;
+       }
+
+cleanup_and_exit:
+       /* Clean up the read-ahead blocks */
+       for (; ra_ptr < ra_max; ra_ptr++)
+               brelse(bh_use[ra_ptr]);
+
+       mlog_exit_ptr(ret);
+       return ret;
+}
+
+/*
+ * Try to find an entry of the provided name within 'dir'.
  *
+ * If nothing was found, NULL is returned. Otherwise, a buffer_head
+ * and pointer to the dir entry are passed back.
+ *
+ * Caller can NOT assume anything about the contents of the
+ * buffer_head - it is passed back only so that it can be passed into
+ * any one of the manipulation functions (add entry, delete entry,
+ * etc). As an example, bh in the extent directory case is a data
+ * block, in the inline-data case it actually points to an inode.
  */
-int ocfs2_readdir(struct file * filp, void * dirent, filldir_t filldir)
+struct buffer_head *ocfs2_find_entry(const char *name, int namelen,
+                                    struct inode *dir,
+                                    struct ocfs2_dir_entry **res_dir)
+{
+       *res_dir = NULL;
+
+       if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
+               return ocfs2_find_entry_id(name, namelen, dir, res_dir);
+
+       return ocfs2_find_entry_el(name, namelen, dir, res_dir);
+}
+
+/*
+ * Update inode number and type of a previously found directory entry.
+ */
+int ocfs2_update_entry(struct inode *dir, handle_t *handle,
+                      struct buffer_head *de_bh, struct ocfs2_dir_entry *de,
+                      struct inode *new_entry_inode)
+{
+       int ret;
+
+       /*
+        * The same code works fine for both inline-data and extent
+        * based directories, so no need to split this up.
+        */
+
+       ret = ocfs2_journal_access(handle, dir, de_bh,
+                                  OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       de->inode = cpu_to_le64(OCFS2_I(new_entry_inode)->ip_blkno);
+       ocfs2_set_de_type(de, new_entry_inode->i_mode);
+
+       ocfs2_journal_dirty(handle, de_bh);
+
+out:
+       return ret;
+}
+
+static int __ocfs2_delete_entry(handle_t *handle, struct inode *dir,
+                               struct ocfs2_dir_entry *de_del,
+                               struct buffer_head *bh, char *first_de,
+                               unsigned int bytes)
+{
+       struct ocfs2_dir_entry *de, *pde;
+       int i, status = -ENOENT;
+
+       mlog_entry("(0x%p, 0x%p, 0x%p, 0x%p)\n", handle, dir, de_del, bh);
+
+       i = 0;
+       pde = NULL;
+       de = (struct ocfs2_dir_entry *) first_de;
+       while (i < bytes) {
+               if (!ocfs2_check_dir_entry(dir, de, bh, i)) {
+                       status = -EIO;
+                       mlog_errno(status);
+                       goto bail;
+               }
+               if (de == de_del)  {
+                       status = ocfs2_journal_access(handle, dir, bh,
+                                                     OCFS2_JOURNAL_ACCESS_WRITE);
+                       if (status < 0) {
+                               status = -EIO;
+                               mlog_errno(status);
+                               goto bail;
+                       }
+                       if (pde)
+                               pde->rec_len =
+                                       cpu_to_le16(le16_to_cpu(pde->rec_len) +
+                                                   le16_to_cpu(de->rec_len));
+                       else
+                               de->inode = 0;
+                       dir->i_version++;
+                       status = ocfs2_journal_dirty(handle, bh);
+                       goto bail;
+               }
+               i += le16_to_cpu(de->rec_len);
+               pde = de;
+               de = (struct ocfs2_dir_entry *)((char *)de + le16_to_cpu(de->rec_len));
+       }
+bail:
+       mlog_exit(status);
+       return status;
+}
+
+static inline int ocfs2_delete_entry_id(handle_t *handle,
+                                       struct inode *dir,
+                                       struct ocfs2_dir_entry *de_del,
+                                       struct buffer_head *bh)
+{
+       int ret;
+       struct buffer_head *di_bh = NULL;
+       struct ocfs2_dinode *di;
+       struct ocfs2_inline_data *data;
+
+       ret = ocfs2_read_block(OCFS2_SB(dir->i_sb), OCFS2_I(dir)->ip_blkno,
+                              &di_bh, OCFS2_BH_CACHED, dir);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       di = (struct ocfs2_dinode *)di_bh->b_data;
+       data = &di->id2.i_data;
+
+       ret = __ocfs2_delete_entry(handle, dir, de_del, bh, data->id_data,
+                                  i_size_read(dir));
+
+       brelse(di_bh);
+out:
+       return ret;
+}
+
+static inline int ocfs2_delete_entry_el(handle_t *handle,
+                                       struct inode *dir,
+                                       struct ocfs2_dir_entry *de_del,
+                                       struct buffer_head *bh)
+{
+       return __ocfs2_delete_entry(handle, dir, de_del, bh, bh->b_data,
+                                   bh->b_size);
+}
+
+/*
+ * ocfs2_delete_entry deletes a directory entry by merging it with the
+ * previous entry
+ */
+int ocfs2_delete_entry(handle_t *handle,
+                      struct inode *dir,
+                      struct ocfs2_dir_entry *de_del,
+                      struct buffer_head *bh)
+{
+       if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
+               return ocfs2_delete_entry_id(handle, dir, de_del, bh);
+
+       return ocfs2_delete_entry_el(handle, dir, de_del, bh);
+}
+
+/*
+ * Check whether 'de' has enough room to hold an entry of
+ * 'new_rec_len' bytes.
+ */
+static inline int ocfs2_dirent_would_fit(struct ocfs2_dir_entry *de,
+                                        unsigned int new_rec_len)
+{
+       unsigned int de_really_used;
+
+       /* Check whether this is an empty record with enough space */
+       if (le64_to_cpu(de->inode) == 0 &&
+           le16_to_cpu(de->rec_len) >= new_rec_len)
+               return 1;
+
+       /*
+        * Record might have free space at the end which we can
+        * use.
+        */
+       de_really_used = OCFS2_DIR_REC_LEN(de->name_len);
+       if (le16_to_cpu(de->rec_len) >= (de_really_used + new_rec_len))
+           return 1;
+
+       return 0;
+}
+
+/* we don't always have a dentry for what we want to add, so people
+ * like orphan dir can call this instead.
+ *
+ * If you pass me insert_bh, I'll skip the search of the other dir
+ * blocks and put the record in there.
+ */
+int __ocfs2_add_entry(handle_t *handle,
+                     struct inode *dir,
+                     const char *name, int namelen,
+                     struct inode *inode, u64 blkno,
+                     struct buffer_head *parent_fe_bh,
+                     struct buffer_head *insert_bh)
+{
+       unsigned long offset;
+       unsigned short rec_len;
+       struct ocfs2_dir_entry *de, *de1;
+       struct ocfs2_dinode *di = (struct ocfs2_dinode *)parent_fe_bh->b_data;
+       struct super_block *sb = dir->i_sb;
+       int retval, status;
+       unsigned int size = sb->s_blocksize;
+       char *data_start = insert_bh->b_data;
+
+       mlog_entry_void();
+
+       if (!namelen)
+               return -EINVAL;
+
+       if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+               data_start = di->id2.i_data.id_data;
+               size = i_size_read(dir);
+
+               BUG_ON(insert_bh != parent_fe_bh);
+       }
+
+       rec_len = OCFS2_DIR_REC_LEN(namelen);
+       offset = 0;
+       de = (struct ocfs2_dir_entry *) data_start;
+       while (1) {
+               BUG_ON((char *)de >= (size + data_start));
+
+               /* These checks should've already been passed by the
+                * prepare function, but I guess we can leave them
+                * here anyway. */
+               if (!ocfs2_check_dir_entry(dir, de, insert_bh, offset)) {
+                       retval = -ENOENT;
+                       goto bail;
+               }
+               if (ocfs2_match(namelen, name, de)) {
+                       retval = -EEXIST;
+                       goto bail;
+               }
+
+               if (ocfs2_dirent_would_fit(de, rec_len)) {
+                       dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+                       retval = ocfs2_mark_inode_dirty(handle, dir, parent_fe_bh);
+                       if (retval < 0) {
+                               mlog_errno(retval);
+                               goto bail;
+                       }
+
+                       status = ocfs2_journal_access(handle, dir, insert_bh,
+                                                     OCFS2_JOURNAL_ACCESS_WRITE);
+                       /* By now the buffer is marked for journaling */
+                       offset += le16_to_cpu(de->rec_len);
+                       if (le64_to_cpu(de->inode)) {
+                               de1 = (struct ocfs2_dir_entry *)((char *) de +
+                                       OCFS2_DIR_REC_LEN(de->name_len));
+                               de1->rec_len =
+                                       cpu_to_le16(le16_to_cpu(de->rec_len) -
+                                       OCFS2_DIR_REC_LEN(de->name_len));
+                               de->rec_len = cpu_to_le16(OCFS2_DIR_REC_LEN(de->name_len));
+                               de = de1;
+                       }
+                       de->file_type = OCFS2_FT_UNKNOWN;
+                       if (blkno) {
+                               de->inode = cpu_to_le64(blkno);
+                               ocfs2_set_de_type(de, inode->i_mode);
+                       } else
+                               de->inode = 0;
+                       de->name_len = namelen;
+                       memcpy(de->name, name, namelen);
+
+                       dir->i_version++;
+                       status = ocfs2_journal_dirty(handle, insert_bh);
+                       retval = 0;
+                       goto bail;
+               }
+               offset += le16_to_cpu(de->rec_len);
+               de = (struct ocfs2_dir_entry *) ((char *) de + le16_to_cpu(de->rec_len));
+       }
+
+       /* when you think about it, the assert above should prevent us
+        * from ever getting here. */
+       retval = -ENOSPC;
+bail:
+
+       mlog_exit(retval);
+       return retval;
+}
+
+static int ocfs2_dir_foreach_blk_id(struct inode *inode,
+                                   unsigned long *f_version,
+                                   loff_t *f_pos, void *priv,
+                                   filldir_t filldir, int *filldir_err)
+{
+       int ret, i, filldir_ret;
+       unsigned long offset = *f_pos;
+       struct buffer_head *di_bh = NULL;
+       struct ocfs2_dinode *di;
+       struct ocfs2_inline_data *data;
+       struct ocfs2_dir_entry *de;
+
+       ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), OCFS2_I(inode)->ip_blkno,
+                              &di_bh, OCFS2_BH_CACHED, inode);
+       if (ret) {
+               mlog(ML_ERROR, "Unable to read inode block for dir %llu\n",
+                    (unsigned long long)OCFS2_I(inode)->ip_blkno);
+               goto out;
+       }
+
+       di = (struct ocfs2_dinode *)di_bh->b_data;
+       data = &di->id2.i_data;
+
+       while (*f_pos < i_size_read(inode)) {
+revalidate:
+               /* If the dir block has changed since the last call to
+                * readdir(2), then we might be pointing to an invalid
+                * dirent right now.  Scan from the start of the block
+                * to make sure. */
+               if (*f_version != inode->i_version) {
+                       for (i = 0; i < i_size_read(inode) && i < offset; ) {
+                               de = (struct ocfs2_dir_entry *)
+                                       (data->id_data + i);
+                               /* It's too expensive to do a full
+                                * dirent test each time round this
+                                * loop, but we do have to test at
+                                * least that it is non-zero.  A
+                                * failure will be detected in the
+                                * dirent test below. */
+                               if (le16_to_cpu(de->rec_len) <
+                                   OCFS2_DIR_REC_LEN(1))
+                                       break;
+                               i += le16_to_cpu(de->rec_len);
+                       }
+                       *f_pos = offset = i;
+                       *f_version = inode->i_version;
+               }
+
+               de = (struct ocfs2_dir_entry *) (data->id_data + *f_pos);
+               if (!ocfs2_check_dir_entry(inode, de, di_bh, *f_pos)) {
+                       /* On error, skip the f_pos to the end. */
+                       *f_pos = i_size_read(inode);
+                       goto out;
+               }
+               offset += le16_to_cpu(de->rec_len);
+               if (le64_to_cpu(de->inode)) {
+                       /* We might block in the next section
+                        * if the data destination is
+                        * currently swapped out.  So, use a
+                        * version stamp to detect whether or
+                        * not the directory has been modified
+                        * during the copy operation.
+                        */
+                       unsigned long version = *f_version;
+                       unsigned char d_type = DT_UNKNOWN;
+
+                       if (de->file_type < OCFS2_FT_MAX)
+                               d_type = ocfs2_filetype_table[de->file_type];
+
+                       filldir_ret = filldir(priv, de->name,
+                                             de->name_len,
+                                             *f_pos,
+                                             le64_to_cpu(de->inode),
+                                             d_type);
+                       if (filldir_ret) {
+                               if (filldir_err)
+                                       *filldir_err = filldir_ret;
+                               break;
+                       }
+                       if (version != *f_version)
+                               goto revalidate;
+               }
+               *f_pos += le16_to_cpu(de->rec_len);
+       }
+
+out:
+       brelse(di_bh);
+
+       return 0;
+}
+
+static int ocfs2_dir_foreach_blk_el(struct inode *inode,
+                                   unsigned long *f_version,
+                                   loff_t *f_pos, void *priv,
+                                   filldir_t filldir, int *filldir_err)
 {
        int error = 0;
        unsigned long offset, blk, last_ra_blk = 0;
@@ -79,45 +687,23 @@ int ocfs2_readdir(struct file * filp, void * dirent, filldir_t filldir)
        struct buffer_head * bh, * tmp;
        struct ocfs2_dir_entry * de;
        int err;
-       struct inode *inode = filp->f_path.dentry->d_inode;
        struct super_block * sb = inode->i_sb;
        unsigned int ra_sectors = 16;
-       int lock_level = 0;
-
-       mlog_entry("dirino=%llu\n",
-                  (unsigned long long)OCFS2_I(inode)->ip_blkno);
 
        stored = 0;
        bh = NULL;
 
-       error = ocfs2_meta_lock_atime(inode, filp->f_vfsmnt, &lock_level);
-       if (lock_level && error >= 0) {
-               /* We release EX lock which used to update atime
-                * and get PR lock again to reduce contention
-                * on commonly accessed directories. */
-               ocfs2_meta_unlock(inode, 1);
-               lock_level = 0;
-               error = ocfs2_meta_lock(inode, NULL, 0);
-       }
-       if (error < 0) {
-               if (error != -ENOENT)
-                       mlog_errno(error);
-               /* we haven't got any yet, so propagate the error. */
-               stored = error;
-               goto bail_nolock;
-       }
+       offset = (*f_pos) & (sb->s_blocksize - 1);
 
-       offset = filp->f_pos & (sb->s_blocksize - 1);
-
-       while (!error && !stored && filp->f_pos < i_size_read(inode)) {
-               blk = (filp->f_pos) >> sb->s_blocksize_bits;
+       while (!error && !stored && *f_pos < i_size_read(inode)) {
+               blk = (*f_pos) >> sb->s_blocksize_bits;
                bh = ocfs2_bread(inode, blk, &err, 0);
                if (!bh) {
                        mlog(ML_ERROR,
                             "directory #%llu contains a hole at offset %lld\n",
                             (unsigned long long)OCFS2_I(inode)->ip_blkno,
-                            filp->f_pos);
-                       filp->f_pos += sb->s_blocksize - offset;
+                            *f_pos);
+                       *f_pos += sb->s_blocksize - offset;
                        continue;
                }
 
@@ -143,7 +729,7 @@ revalidate:
                 * readdir(2), then we might be pointing to an invalid
                 * dirent right now.  Scan from the start of the block
                 * to make sure. */
-               if (filp->f_version != inode->i_version) {
+               if (*f_version != inode->i_version) {
                        for (i = 0; i < sb->s_blocksize && i < offset; ) {
                                de = (struct ocfs2_dir_entry *) (bh->b_data + i);
                                /* It's too expensive to do a full
@@ -158,21 +744,20 @@ revalidate:
                                i += le16_to_cpu(de->rec_len);
                        }
                        offset = i;
-                       filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1))
+                       *f_pos = ((*f_pos) & ~(sb->s_blocksize - 1))
                                | offset;
-                       filp->f_version = inode->i_version;
+                       *f_version = inode->i_version;
                }
 
-               while (!error && filp->f_pos < i_size_read(inode)
+               while (!error && *f_pos < i_size_read(inode)
                       && offset < sb->s_blocksize) {
                        de = (struct ocfs2_dir_entry *) (bh->b_data + offset);
                        if (!ocfs2_check_dir_entry(inode, de, bh, offset)) {
                                /* On error, skip the f_pos to the
                                   next block. */
-                               filp->f_pos = (filp->f_pos |
-                                              (sb->s_blocksize - 1)) + 1;
+                               *f_pos = ((*f_pos) | (sb->s_blocksize - 1)) + 1;
                                brelse(bh);
-                               goto bail;
+                               goto out;
                        }
                        offset += le16_to_cpu(de->rec_len);
                        if (le64_to_cpu(de->inode)) {
@@ -183,36 +768,109 @@ revalidate:
                                 * not the directory has been modified
                                 * during the copy operation.
                                 */
-                               unsigned long version = filp->f_version;
+                               unsigned long version = *f_version;
                                unsigned char d_type = DT_UNKNOWN;
 
                                if (de->file_type < OCFS2_FT_MAX)
                                        d_type = ocfs2_filetype_table[de->file_type];
-                               error = filldir(dirent, de->name,
+                               error = filldir(priv, de->name,
                                                de->name_len,
-                                               filp->f_pos,
-                                               ino_from_blkno(sb, le64_to_cpu(de->inode)),
+                                               *f_pos,
+                                               le64_to_cpu(de->inode),
                                                d_type);
-                               if (error)
+                               if (error) {
+                                       if (filldir_err)
+                                               *filldir_err = error;
                                        break;
-                               if (version != filp->f_version)
+                               }
+                               if (version != *f_version)
                                        goto revalidate;
                                stored ++;
                        }
-                       filp->f_pos += le16_to_cpu(de->rec_len);
+                       *f_pos += le16_to_cpu(de->rec_len);
                }
                offset = 0;
                brelse(bh);
        }
 
        stored = 0;
-bail:
+out:
+       return stored;
+}
+
+static int ocfs2_dir_foreach_blk(struct inode *inode, unsigned long *f_version,
+                                loff_t *f_pos, void *priv, filldir_t filldir,
+                                int *filldir_err)
+{
+       if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
+               return ocfs2_dir_foreach_blk_id(inode, f_version, f_pos, priv,
+                                               filldir, filldir_err);
+
+       return ocfs2_dir_foreach_blk_el(inode, f_version, f_pos, priv, filldir,
+                                       filldir_err);
+}
+
+/*
+ * This is intended to be called from inside other kernel functions,
+ * so we fake some arguments.
+ */
+int ocfs2_dir_foreach(struct inode *inode, loff_t *f_pos, void *priv,
+                     filldir_t filldir)
+{
+       int ret = 0, filldir_err = 0;
+       unsigned long version = inode->i_version;
+
+       while (*f_pos < i_size_read(inode)) {
+               ret = ocfs2_dir_foreach_blk(inode, &version, f_pos, priv,
+                                           filldir, &filldir_err);
+               if (ret || filldir_err)
+                       break;
+       }
+
+       if (ret > 0)
+               ret = -EIO;
+
+       return 0;
+}
+
+/*
+ * ocfs2_readdir()
+ *
+ */
+int ocfs2_readdir(struct file * filp, void * dirent, filldir_t filldir)
+{
+       int error = 0;
+       struct inode *inode = filp->f_path.dentry->d_inode;
+       int lock_level = 0;
+
+       mlog_entry("dirino=%llu\n",
+                  (unsigned long long)OCFS2_I(inode)->ip_blkno);
+
+       error = ocfs2_meta_lock_atime(inode, filp->f_vfsmnt, &lock_level);
+       if (lock_level && error >= 0) {
+               /* We release EX lock which used to update atime
+                * and get PR lock again to reduce contention
+                * on commonly accessed directories. */
+               ocfs2_meta_unlock(inode, 1);
+               lock_level = 0;
+               error = ocfs2_meta_lock(inode, NULL, 0);
+       }
+       if (error < 0) {
+               if (error != -ENOENT)
+                       mlog_errno(error);
+               /* we haven't got any yet, so propagate the error. */
+               goto bail_nolock;
+       }
+
+       error = ocfs2_dir_foreach_blk(inode, &filp->f_version, &filp->f_pos,
+                                     dirent, filldir, NULL);
+
        ocfs2_meta_unlock(inode, lock_level);
 
 bail_nolock:
-       mlog_exit(stored);
+       mlog_exit(error);
 
-       return stored;
+       return error;
 }
 
 /*
@@ -252,6 +910,23 @@ leave:
        return status;
 }
 
+/*
+ * Convenience function for callers which just want the block number
+ * mapped to a name and don't require the full dirent info, etc.
+ */
+int ocfs2_lookup_ino_from_name(struct inode *dir, const char *name,
+                              int namelen, u64 *blkno)
+{
+       int ret;
+       struct buffer_head *bh = NULL;
+       struct ocfs2_dir_entry *dirent = NULL;
+
+       ret = ocfs2_find_files_on_disk(name, namelen, blkno, dir, &bh, &dirent);
+       brelse(bh);
+
+       return ret;
+}
+
 /* Check for a name within a directory.
  *
  * Return 0 if the name does not exist
@@ -284,77 +959,414 @@ bail:
        return ret;
 }
 
+struct ocfs2_empty_dir_priv {
+       unsigned seen_dot;
+       unsigned seen_dot_dot;
+       unsigned seen_other;
+};
+static int ocfs2_empty_dir_filldir(void *priv, const char *name, int name_len,
+                                  loff_t pos, u64 ino, unsigned type)
+{
+       struct ocfs2_empty_dir_priv *p = priv;
+
+       /*
+        * Check the positions of "." and ".." records to be sure
+        * they're in the correct place.
+        */
+       if (name_len == 1 && !strncmp(".", name, 1) && pos == 0) {
+               p->seen_dot = 1;
+               return 0;
+       }
+
+       if (name_len == 2 && !strncmp("..", name, 2) &&
+           pos == OCFS2_DIR_REC_LEN(1)) {
+               p->seen_dot_dot = 1;
+               return 0;
+       }
+
+       p->seen_other = 1;
+       return 1;
+}
 /*
  * routine to check that the specified directory is empty (for rmdir)
+ *
+ * Returns 1 if dir is empty, zero otherwise.
  */
 int ocfs2_empty_dir(struct inode *inode)
 {
-       unsigned long offset;
-       struct buffer_head * bh;
-       struct ocfs2_dir_entry * de, * de1;
-       struct super_block * sb;
-       int err;
+       int ret;
+       loff_t start = 0;
+       struct ocfs2_empty_dir_priv priv;
+
+       memset(&priv, 0, sizeof(priv));
+
+       ret = ocfs2_dir_foreach(inode, &start, &priv, ocfs2_empty_dir_filldir);
+       if (ret)
+               mlog_errno(ret);
 
-       sb = inode->i_sb;
-       if ((i_size_read(inode) <
-            (OCFS2_DIR_REC_LEN(1) + OCFS2_DIR_REC_LEN(2))) ||
-           !(bh = ocfs2_bread(inode, 0, &err, 0))) {
-               mlog(ML_ERROR, "bad directory (dir #%llu) - no data block\n",
+       if (!priv.seen_dot || !priv.seen_dot_dot) {
+               mlog(ML_ERROR, "bad directory (dir #%llu) - no `.' or `..'\n",
                     (unsigned long long)OCFS2_I(inode)->ip_blkno);
+               /*
+                * XXX: Is it really safe to allow an unlink to continue?
+                */
                return 1;
        }
 
-       de = (struct ocfs2_dir_entry *) bh->b_data;
-       de1 = (struct ocfs2_dir_entry *)
-                       ((char *)de + le16_to_cpu(de->rec_len));
-       if ((le64_to_cpu(de->inode) != OCFS2_I(inode)->ip_blkno) ||
-                       !le64_to_cpu(de1->inode) ||
-                       strcmp(".", de->name) ||
-                       strcmp("..", de1->name)) {
-               mlog(ML_ERROR, "bad directory (dir #%llu) - no `.' or `..'\n",
-                    (unsigned long long)OCFS2_I(inode)->ip_blkno);
-               brelse(bh);
-               return 1;
+       return !priv.seen_other;
+}
+
+static void ocfs2_fill_initial_dirents(struct inode *inode,
+                                      struct inode *parent,
+                                      char *start, unsigned int size)
+{
+       struct ocfs2_dir_entry *de = (struct ocfs2_dir_entry *)start;
+
+       de->inode = cpu_to_le64(OCFS2_I(inode)->ip_blkno);
+       de->name_len = 1;
+       de->rec_len =
+               cpu_to_le16(OCFS2_DIR_REC_LEN(de->name_len));
+       strcpy(de->name, ".");
+       ocfs2_set_de_type(de, S_IFDIR);
+
+       de = (struct ocfs2_dir_entry *) ((char *)de + le16_to_cpu(de->rec_len));
+       de->inode = cpu_to_le64(OCFS2_I(parent)->ip_blkno);
+       de->rec_len = cpu_to_le16(size - OCFS2_DIR_REC_LEN(1));
+       de->name_len = 2;
+       strcpy(de->name, "..");
+       ocfs2_set_de_type(de, S_IFDIR);
+}
+
+/*
+ * This works together with code in ocfs2_mknod_locked() which sets
+ * the inline-data flag and initializes the inline-data section.
+ */
+static int ocfs2_fill_new_dir_id(struct ocfs2_super *osb,
+                                handle_t *handle,
+                                struct inode *parent,
+                                struct inode *inode,
+                                struct buffer_head *di_bh)
+{
+       int ret;
+       struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+       struct ocfs2_inline_data *data = &di->id2.i_data;
+       unsigned int size = le16_to_cpu(data->id_count);
+
+       ret = ocfs2_journal_access(handle, inode, di_bh,
+                                  OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
        }
-       offset = le16_to_cpu(de->rec_len) + le16_to_cpu(de1->rec_len);
-       de = (struct ocfs2_dir_entry *)((char *)de1 + le16_to_cpu(de1->rec_len));
-       while (offset < i_size_read(inode) ) {
-               if (!bh || (void *)de >= (void *)(bh->b_data + sb->s_blocksize)) {
-                       brelse(bh);
-                       bh = ocfs2_bread(inode,
-                                        offset >> sb->s_blocksize_bits, &err, 0);
-                       if (!bh) {
-                               mlog(ML_ERROR, "dir %llu has a hole at %lu\n",
-                                    (unsigned long long)OCFS2_I(inode)->ip_blkno, offset);
-                               offset += sb->s_blocksize;
-                               continue;
-                       }
-                       de = (struct ocfs2_dir_entry *) bh->b_data;
-               }
-               if (!ocfs2_check_dir_entry(inode, de, bh, offset)) {
-                       brelse(bh);
-                       return 1;
+
+       ocfs2_fill_initial_dirents(inode, parent, data->id_data, size);
+
+       ocfs2_journal_dirty(handle, di_bh);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       i_size_write(inode, size);
+       inode->i_nlink = 2;
+       inode->i_blocks = ocfs2_inode_sector_count(inode);
+
+       ret = ocfs2_mark_inode_dirty(handle, inode, di_bh);
+       if (ret < 0)
+               mlog_errno(ret);
+
+out:
+       return ret;
+}
+
+static int ocfs2_fill_new_dir_el(struct ocfs2_super *osb,
+                                handle_t *handle,
+                                struct inode *parent,
+                                struct inode *inode,
+                                struct buffer_head *fe_bh,
+                                struct ocfs2_alloc_context *data_ac)
+{
+       int status;
+       struct buffer_head *new_bh = NULL;
+
+       mlog_entry_void();
+
+       status = ocfs2_do_extend_dir(osb->sb, handle, inode, fe_bh,
+                                    data_ac, NULL, &new_bh);
+       if (status < 0) {
+               mlog_errno(status);
+               goto bail;
+       }
+
+       ocfs2_set_new_buffer_uptodate(inode, new_bh);
+
+       status = ocfs2_journal_access(handle, inode, new_bh,
+                                     OCFS2_JOURNAL_ACCESS_CREATE);
+       if (status < 0) {
+               mlog_errno(status);
+               goto bail;
+       }
+       memset(new_bh->b_data, 0, osb->sb->s_blocksize);
+
+       ocfs2_fill_initial_dirents(inode, parent, new_bh->b_data,
+                                  osb->sb->s_blocksize);
+
+       status = ocfs2_journal_dirty(handle, new_bh);
+       if (status < 0) {
+               mlog_errno(status);
+               goto bail;
+       }
+
+       i_size_write(inode, inode->i_sb->s_blocksize);
+       inode->i_nlink = 2;
+       inode->i_blocks = ocfs2_inode_sector_count(inode);
+       status = ocfs2_mark_inode_dirty(handle, inode, fe_bh);
+       if (status < 0) {
+               mlog_errno(status);
+               goto bail;
+       }
+
+       status = 0;
+bail:
+       if (new_bh)
+               brelse(new_bh);
+
+       mlog_exit(status);
+       return status;
+}
+
+int ocfs2_fill_new_dir(struct ocfs2_super *osb,
+                      handle_t *handle,
+                      struct inode *parent,
+                      struct inode *inode,
+                      struct buffer_head *fe_bh,
+                      struct ocfs2_alloc_context *data_ac)
+{
+       BUG_ON(!ocfs2_supports_inline_data(osb) && data_ac == NULL);
+
+       if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
+               return ocfs2_fill_new_dir_id(osb, handle, parent, inode, fe_bh);
+
+       return ocfs2_fill_new_dir_el(osb, handle, parent, inode, fe_bh,
+                                    data_ac);
+}
+
+static void ocfs2_expand_last_dirent(char *start, unsigned int old_size,
+                                    unsigned int new_size)
+{
+       struct ocfs2_dir_entry *de;
+       struct ocfs2_dir_entry *prev_de;
+       char *de_buf, *limit;
+       unsigned int bytes = new_size - old_size;
+
+       limit = start + old_size;
+       de_buf = start;
+       de = (struct ocfs2_dir_entry *)de_buf;
+       do {
+               prev_de = de;
+               de_buf += le16_to_cpu(de->rec_len);
+               de = (struct ocfs2_dir_entry *)de_buf;
+       } while (de_buf < limit);
+
+       le16_add_cpu(&prev_de->rec_len, bytes);
+}
+
+/*
+ * We allocate enough clusters to fulfill "blocks_wanted", but set
+ * i_size to exactly one block. Ocfs2_extend_dir() will handle the
+ * rest automatically for us.
+ *
+ * *first_block_bh is a pointer to the 1st data block allocated to the
+ *  directory.
+ */
+static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,
+                                  unsigned int blocks_wanted,
+                                  struct buffer_head **first_block_bh)
+{
+       int ret, credits = OCFS2_INLINE_TO_EXTENTS_CREDITS;
+       u32 alloc, bit_off, len;
+       struct super_block *sb = dir->i_sb;
+       u64 blkno, bytes = blocks_wanted << sb->s_blocksize_bits;
+       struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
+       struct ocfs2_inode_info *oi = OCFS2_I(dir);
+       struct ocfs2_alloc_context *data_ac;
+       struct buffer_head *dirdata_bh = NULL;
+       struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+       handle_t *handle;
+
+       alloc = ocfs2_clusters_for_bytes(sb, bytes);
+
+       /*
+        * We should never need more than 2 clusters for this -
+        * maximum dirent size is far less than one block. In fact,
+        * the only time we'd need more than one cluster is if
+        * blocksize == clustersize and the dirent won't fit in the
+        * extra space that the expansion to a single block gives. As
+        * of today, that only happens on 4k/4k file systems.
+        */
+       BUG_ON(alloc > 2);
+
+       ret = ocfs2_reserve_clusters(osb, alloc, &data_ac);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       down_write(&oi->ip_alloc_sem);
+
+       /*
+        * Prepare for worst case allocation scenario of two seperate
+        * extents.
+        */
+       if (alloc == 2)
+               credits += OCFS2_SUBALLOC_ALLOC;
+
+       handle = ocfs2_start_trans(osb, credits);
+       if (IS_ERR(handle)) {
+               ret = PTR_ERR(handle);
+               mlog_errno(ret);
+               goto out_sem;
+       }
+
+       /*
+        * Try to claim as many clusters as the bitmap can give though
+        * if we only get one now, that's enough to continue. The rest
+        * will be claimed after the conversion to extents.
+        */
+       ret = ocfs2_claim_clusters(osb, handle, data_ac, 1, &bit_off, &len);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       /*
+        * Operations are carefully ordered so that we set up the new
+        * data block first. The conversion from inline data to
+        * extents follows.
+        */
+       blkno = ocfs2_clusters_to_blocks(dir->i_sb, bit_off);
+       dirdata_bh = sb_getblk(sb, blkno);
+       if (!dirdata_bh) {
+               ret = -EIO;
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       ocfs2_set_new_buffer_uptodate(dir, dirdata_bh);
+
+       ret = ocfs2_journal_access(handle, dir, dirdata_bh,
+                                  OCFS2_JOURNAL_ACCESS_CREATE);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       memcpy(dirdata_bh->b_data, di->id2.i_data.id_data, i_size_read(dir));
+       memset(dirdata_bh->b_data + i_size_read(dir), 0,
+              sb->s_blocksize - i_size_read(dir));
+       ocfs2_expand_last_dirent(dirdata_bh->b_data, i_size_read(dir),
+                                sb->s_blocksize);
+
+       ret = ocfs2_journal_dirty(handle, dirdata_bh);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       /*
+        * Set extent, i_size, etc on the directory. After this, the
+        * inode should contain the same exact dirents as before and
+        * be fully accessible from system calls.
+        *
+        * We let the later dirent insert modify c/mtime - to the user
+        * the data hasn't changed.
+        */
+       ret = ocfs2_journal_access(handle, dir, di_bh,
+                                  OCFS2_JOURNAL_ACCESS_CREATE);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       spin_lock(&oi->ip_lock);
+       oi->ip_dyn_features &= ~OCFS2_INLINE_DATA_FL;
+       di->i_dyn_features = cpu_to_le16(oi->ip_dyn_features);
+       spin_unlock(&oi->ip_lock);
+
+       ocfs2_dinode_new_extent_list(dir, di);
+
+       i_size_write(dir, sb->s_blocksize);
+       dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+
+       di->i_size = cpu_to_le64(sb->s_blocksize);
+       di->i_ctime = di->i_mtime = cpu_to_le64(dir->i_ctime.tv_sec);
+       di->i_ctime_nsec = di->i_mtime_nsec = cpu_to_le32(dir->i_ctime.tv_nsec);
+       dir->i_blocks = ocfs2_inode_sector_count(dir);
+
+       /*
+        * This should never fail as our extent list is empty and all
+        * related blocks have been journaled already.
+        */
+       ret = ocfs2_insert_extent(osb, handle, dir, di_bh, 0, blkno, len, 0,
+                                 NULL);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       ret = ocfs2_journal_dirty(handle, di_bh);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       /*
+        * We asked for two clusters, but only got one in the 1st
+        * pass. Claim the 2nd cluster as a separate extent.
+        */
+       if (alloc > len) {
+               ret = ocfs2_claim_clusters(osb, handle, data_ac, 1, &bit_off,
+                                          &len);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out_commit;
                }
-               if (le64_to_cpu(de->inode)) {
-                       brelse(bh);
-                       return 0;
+               blkno = ocfs2_clusters_to_blocks(dir->i_sb, bit_off);
+
+               ret = ocfs2_insert_extent(osb, handle, dir, di_bh, 1, blkno,
+                                         len, 0, NULL);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
                }
-               offset += le16_to_cpu(de->rec_len);
-               de = (struct ocfs2_dir_entry *)
-                       ((char *)de + le16_to_cpu(de->rec_len));
        }
-       brelse(bh);
-       return 1;
+
+       *first_block_bh = dirdata_bh;
+       dirdata_bh = NULL;
+
+out_commit:
+       ocfs2_commit_trans(osb, handle);
+
+out_sem:
+       up_write(&oi->ip_alloc_sem);
+
+out:
+       if (data_ac)
+               ocfs2_free_alloc_context(data_ac);
+
+       brelse(dirdata_bh);
+
+       return ret;
 }
 
 /* returns a bh of the 1st new block in the allocation. */
-int ocfs2_do_extend_dir(struct super_block *sb,
-                       handle_t *handle,
-                       struct inode *dir,
-                       struct buffer_head *parent_fe_bh,
-                       struct ocfs2_alloc_context *data_ac,
-                       struct ocfs2_alloc_context *meta_ac,
-                       struct buffer_head **new_bh)
+static int ocfs2_do_extend_dir(struct super_block *sb,
+                              handle_t *handle,
+                              struct inode *dir,
+                              struct buffer_head *parent_fe_bh,
+                              struct ocfs2_alloc_context *data_ac,
+                              struct ocfs2_alloc_context *meta_ac,
+                              struct buffer_head **new_bh)
 {
        int status;
        int extend;
@@ -396,10 +1408,18 @@ bail:
        return status;
 }
 
-/* assumes you already have a cluster lock on the directory. */
+/*
+ * Assumes you already have a cluster lock on the directory.
+ *
+ * 'blocks_wanted' is only used if we have an inline directory which
+ * is to be turned into an extent based one. The size of the dirent to
+ * insert might be larger than the space gained by growing to just one
+ * block, so we may have to grow the inode by two blocks in that case.
+ */
 static int ocfs2_extend_dir(struct ocfs2_super *osb,
                            struct inode *dir,
                            struct buffer_head *parent_fe_bh,
+                           unsigned int blocks_wanted,
                            struct buffer_head **new_de_bh)
 {
        int status = 0;
@@ -415,6 +1435,38 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb,
 
        mlog_entry_void();
 
+       if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+               status = ocfs2_expand_inline_dir(dir, parent_fe_bh,
+                                                blocks_wanted, &new_bh);
+               if (status) {
+                       mlog_errno(status);
+                       goto bail;
+               }
+
+               if (blocks_wanted == 1) {
+                       /*
+                        * If the new dirent will fit inside the space
+                        * created by pushing out to one block, then
+                        * we can complete the operation
+                        * here. Otherwise we have to expand i_size
+                        * and format the 2nd block below.
+                        */
+                       BUG_ON(new_bh == NULL);
+                       goto bail_bh;
+               }
+
+               /*
+                * Get rid of 'new_bh' - we want to format the 2nd
+                * data block and return that instead.
+                */
+               brelse(new_bh);
+               new_bh = NULL;
+
+               dir_i_size = i_size_read(dir);
+               credits = OCFS2_SIMPLE_DIR_EXTEND_CREDITS;
+               goto do_extend;
+       }
+
        dir_i_size = i_size_read(dir);
        mlog(0, "extending dir %llu (i_size = %lld)\n",
             (unsigned long long)OCFS2_I(dir)->ip_blkno, dir_i_size);
@@ -452,6 +1504,7 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb,
                credits = OCFS2_SIMPLE_DIR_EXTEND_CREDITS;
        }
 
+do_extend:
        down_write(&OCFS2_I(dir)->ip_alloc_sem);
        drop_alloc_sem = 1;
 
@@ -497,6 +1550,7 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb,
                goto bail;
        }
 
+bail_bh:
        *new_de_bh = new_bh;
        get_bh(*new_de_bh);
 bail:
@@ -517,41 +1571,71 @@ bail:
        return status;
 }
 
-/*
- * Search the dir for a good spot, extending it if necessary. The
- * block containing an appropriate record is returned in ret_de_bh.
- */
-int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb,
-                                struct inode *dir,
-                                struct buffer_head *parent_fe_bh,
-                                const char *name,
-                                int namelen,
-                                struct buffer_head **ret_de_bh)
+static int ocfs2_find_dir_space_id(struct inode *dir, struct buffer_head *di_bh,
+                                  const char *name, int namelen,
+                                  struct buffer_head **ret_de_bh,
+                                  unsigned int *blocks_wanted)
 {
-       unsigned long offset;
-       struct buffer_head * bh = NULL;
-       unsigned short rec_len;
-       struct ocfs2_dinode *fe;
-       struct ocfs2_dir_entry *de;
-       struct super_block *sb;
-       int status;
+       int ret;
+       struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+       struct ocfs2_dir_entry *de, *last_de = NULL;
+       char *de_buf, *limit;
+       unsigned long offset = 0;
+       unsigned int rec_len, new_rec_len;
+
+       de_buf = di->id2.i_data.id_data;
+       limit = de_buf + i_size_read(dir);
+       rec_len = OCFS2_DIR_REC_LEN(namelen);
 
-       mlog_entry_void();
+       while (de_buf < limit) {
+               de = (struct ocfs2_dir_entry *)de_buf;
 
-       mlog(0, "getting ready to insert namelen %d into dir %llu\n",
-            namelen, (unsigned long long)OCFS2_I(dir)->ip_blkno);
+               if (!ocfs2_check_dir_entry(dir, de, di_bh, offset)) {
+                       ret = -ENOENT;
+                       goto out;
+               }
+               if (ocfs2_match(namelen, name, de)) {
+                       ret = -EEXIST;
+                       goto out;
+               }
+               if (ocfs2_dirent_would_fit(de, rec_len)) {
+                       /* Ok, we found a spot. Return this bh and let
+                        * the caller actually fill it in. */
+                       *ret_de_bh = di_bh;
+                       get_bh(*ret_de_bh);
+                       ret = 0;
+                       goto out;
+               }
 
-       BUG_ON(!S_ISDIR(dir->i_mode));
-       fe = (struct ocfs2_dinode *) parent_fe_bh->b_data;
-       BUG_ON(le64_to_cpu(fe->i_size) != i_size_read(dir));
+               last_de = de;
+               de_buf += le16_to_cpu(de->rec_len);
+               offset += le16_to_cpu(de->rec_len);
+       }
 
-       sb = dir->i_sb;
+       /*
+        * We're going to require expansion of the directory - figure
+        * out how many blocks we'll need so that a place for the
+        * dirent can be found.
+        */
+       *blocks_wanted = 1;
+       new_rec_len = le16_to_cpu(last_de->rec_len) + (dir->i_sb->s_blocksize - i_size_read(dir));
+       if (new_rec_len < (rec_len + OCFS2_DIR_REC_LEN(last_de->name_len)))
+               *blocks_wanted = 2;
+
+       ret = -ENOSPC;
+out:
+       return ret;
+}
 
-       if (!namelen) {
-               status = -EINVAL;
-               mlog_errno(status);
-               goto bail;
-       }
+static int ocfs2_find_dir_space_el(struct inode *dir, const char *name,
+                                  int namelen, struct buffer_head **ret_de_bh)
+{
+       unsigned long offset;
+       struct buffer_head *bh = NULL;
+       unsigned short rec_len;
+       struct ocfs2_dir_entry *de;
+       struct super_block *sb = dir->i_sb;
+       int status;
 
        bh = ocfs2_bread(dir, 0, &status, 0);
        if (!bh) {
@@ -568,17 +1652,11 @@ int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb,
                        bh = NULL;
 
                        if (i_size_read(dir) <= offset) {
-                               status = ocfs2_extend_dir(osb,
-                                                         dir,
-                                                         parent_fe_bh,
-                                                         &bh);
-                               if (status < 0) {
-                                       mlog_errno(status);
-                                       goto bail;
-                               }
-                               BUG_ON(!bh);
-                               *ret_de_bh = bh;
-                               get_bh(*ret_de_bh);
+                               /*
+                                * Caller will have to expand this
+                                * directory.
+                                */
+                               status = -ENOSPC;
                                goto bail;
                        }
                        bh = ocfs2_bread(dir,
@@ -600,10 +1678,7 @@ int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb,
                        status = -EEXIST;
                        goto bail;
                }
-               if (((le64_to_cpu(de->inode) == 0) &&
-                    (le16_to_cpu(de->rec_len) >= rec_len)) ||
-                   (le16_to_cpu(de->rec_len) >=
-                    (OCFS2_DIR_REC_LEN(de->name_len) + rec_len))) {
+               if (ocfs2_dirent_would_fit(de, rec_len)) {
                        /* Ok, we found a spot. Return this bh and let
                         * the caller actually fill it in. */
                        *ret_de_bh = bh;
@@ -623,3 +1698,61 @@ bail:
        mlog_exit(status);
        return status;
 }
+
+int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb,
+                                struct inode *dir,
+                                struct buffer_head *parent_fe_bh,
+                                const char *name,
+                                int namelen,
+                                struct buffer_head **ret_de_bh)
+{
+       int ret;
+       unsigned int blocks_wanted = 1;
+       struct buffer_head *bh = NULL;
+
+       mlog(0, "getting ready to insert namelen %d into dir %llu\n",
+            namelen, (unsigned long long)OCFS2_I(dir)->ip_blkno);
+
+       *ret_de_bh = NULL;
+
+       if (!namelen) {
+               ret = -EINVAL;
+               mlog_errno(ret);
+               goto out;
+       }
+
+       if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+               ret = ocfs2_find_dir_space_id(dir, parent_fe_bh, name,
+                                             namelen, &bh, &blocks_wanted);
+       } else
+               ret = ocfs2_find_dir_space_el(dir, name, namelen, &bh);
+
+       if (ret && ret != -ENOSPC) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       if (ret == -ENOSPC) {
+               /*
+                * We have to expand the directory to add this name.
+                */
+               BUG_ON(bh);
+
+               ret = ocfs2_extend_dir(osb, dir, parent_fe_bh, blocks_wanted,
+                                      &bh);
+               if (ret) {
+                       if (ret != -ENOSPC)
+                               mlog_errno(ret);
+                       goto out;
+               }
+
+               BUG_ON(!bh);
+       }
+
+       *ret_de_bh = bh;
+       bh = NULL;
+out:
+       if (bh)
+               brelse(bh);
+       return ret;
+}
index 3f67e146864a695d32bfe7b724d283a825a403ab..ce48b9080d87c8b2a69839b9b33ee8433f2ee786 100644 (file)
 #ifndef OCFS2_DIR_H
 #define OCFS2_DIR_H
 
+struct buffer_head *ocfs2_find_entry(const char *name,
+                                    int namelen,
+                                    struct inode *dir,
+                                    struct ocfs2_dir_entry **res_dir);
+int ocfs2_delete_entry(handle_t *handle,
+                      struct inode *dir,
+                      struct ocfs2_dir_entry *de_del,
+                      struct buffer_head *bh);
+int __ocfs2_add_entry(handle_t *handle,
+                     struct inode *dir,
+                     const char *name, int namelen,
+                     struct inode *inode, u64 blkno,
+                     struct buffer_head *parent_fe_bh,
+                     struct buffer_head *insert_bh);
+static inline int ocfs2_add_entry(handle_t *handle,
+                                 struct dentry *dentry,
+                                 struct inode *inode, u64 blkno,
+                                 struct buffer_head *parent_fe_bh,
+                                 struct buffer_head *insert_bh)
+{
+       return __ocfs2_add_entry(handle, dentry->d_parent->d_inode,
+                                dentry->d_name.name, dentry->d_name.len,
+                                inode, blkno, parent_fe_bh, insert_bh);
+}
+int ocfs2_update_entry(struct inode *dir, handle_t *handle,
+                      struct buffer_head *de_bh, struct ocfs2_dir_entry *de,
+                      struct inode *new_entry_inode);
+
 int ocfs2_check_dir_for_entry(struct inode *dir,
                              const char *name,
                              int namelen);
-int ocfs2_empty_dir(struct inode *inode);  /* FIXME: to namei.c */
+int ocfs2_empty_dir(struct inode *inode);
 int ocfs2_find_files_on_disk(const char *name,
                             int namelen,
                             u64 *blkno,
                             struct inode *inode,
                             struct buffer_head **dirent_bh,
                             struct ocfs2_dir_entry **dirent);
+int ocfs2_lookup_ino_from_name(struct inode *dir, const char *name,
+                              int namelen, u64 *blkno);
 int ocfs2_readdir(struct file *filp, void *dirent, filldir_t filldir);
+int ocfs2_dir_foreach(struct inode *inode, loff_t *f_pos, void *priv,
+                     filldir_t filldir);
 int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb,
                                 struct inode *dir,
                                 struct buffer_head *parent_fe_bh,
@@ -44,11 +76,11 @@ int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb,
                                 int namelen,
                                 struct buffer_head **ret_de_bh);
 struct ocfs2_alloc_context;
-int ocfs2_do_extend_dir(struct super_block *sb,
-                       handle_t *handle,
-                       struct inode *dir,
-                       struct buffer_head *parent_fe_bh,
-                       struct ocfs2_alloc_context *data_ac,
-                       struct ocfs2_alloc_context *meta_ac,
-                       struct buffer_head **new_bh);
+int ocfs2_fill_new_dir(struct ocfs2_super *osb,
+                      handle_t *handle,
+                      struct inode *parent,
+                      struct inode *inode,
+                      struct buffer_head *fe_bh,
+                      struct ocfs2_alloc_context *data_ac);
+
 #endif /* OCFS2_DIR_H */
index f71250ed166fe9d3eac561e9aec5a9bb99e98813..41c76ff2fcfbc4d725be65a4498b5fd603aa6f2c 100644 (file)
@@ -1482,6 +1482,7 @@ static void __ocfs2_stuff_meta_lvb(struct inode *inode)
        lvb->lvb_imtime_packed =
                cpu_to_be64(ocfs2_pack_timespec(&inode->i_mtime));
        lvb->lvb_iattr    = cpu_to_be32(oi->ip_attr);
+       lvb->lvb_idynfeatures = cpu_to_be16(oi->ip_dyn_features);
        lvb->lvb_igeneration = cpu_to_be32(inode->i_generation);
 
 out:
@@ -1515,6 +1516,7 @@ static void ocfs2_refresh_inode_from_lvb(struct inode *inode)
        i_size_write(inode, be64_to_cpu(lvb->lvb_isize));
 
        oi->ip_attr = be32_to_cpu(lvb->lvb_iattr);
+       oi->ip_dyn_features = be16_to_cpu(lvb->lvb_idynfeatures);
        ocfs2_set_inode_flags(inode);
 
        /* fast-symlinks are a special case */
index 492bad32a8c0a6be8b576321adb871ecce4b44ee..87a785e41205c4cef900e6d38aeebf288a7f1adf 100644 (file)
 
 #include "dcache.h"
 
-#define OCFS2_LVB_VERSION 4
+#define OCFS2_LVB_VERSION 5
 
 struct ocfs2_meta_lvb {
        __u8         lvb_version;
        __u8         lvb_reserved0;
-       __be16       lvb_reserved1;
+       __be16       lvb_idynfeatures;
        __be32       lvb_iclusters;
        __be32       lvb_iuid;
        __be32       lvb_igid;
index bc48177bd183eac14ae94ff2c1f787d6ce013649..c3bbc198f9ce66d6a0c4bf2b02bb581932e12ee1 100644 (file)
@@ -88,8 +88,6 @@ static struct dentry *ocfs2_get_parent(struct dentry *child)
        struct dentry *parent;
        struct inode *inode;
        struct inode *dir = child->d_inode;
-       struct buffer_head *dirent_bh = NULL;
-       struct ocfs2_dir_entry *dirent;
 
        mlog_entry("(0x%p, '%.*s')\n", child,
                   child->d_name.len, child->d_name.name);
@@ -105,8 +103,7 @@ static struct dentry *ocfs2_get_parent(struct dentry *child)
                goto bail;
        }
 
-       status = ocfs2_find_files_on_disk("..", 2, &blkno, dir, &dirent_bh,
-                                         &dirent);
+       status = ocfs2_lookup_ino_from_name(dir, "..", 2, &blkno);
        if (status < 0) {
                parent = ERR_PTR(-ENOENT);
                goto bail_unlock;
@@ -131,9 +128,6 @@ static struct dentry *ocfs2_get_parent(struct dentry *child)
 bail_unlock:
        ocfs2_meta_unlock(dir, 0);
 
-       if (dirent_bh)
-               brelse(dirent_bh);
-
 bail:
        mlog_exit_ptr(parent);
 
index 03c1d365c78b25601dfc1c51001065df5d3aefc7..c58668a326fe87f58074741965c531761fe97359 100644 (file)
@@ -387,6 +387,12 @@ int ocfs2_get_clusters(struct inode *inode, u32 v_cluster,
        struct ocfs2_extent_rec *rec;
        u32 coff;
 
+       if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+               ret = -ERANGE;
+               mlog_errno(ret);
+               goto out;
+       }
+
        ret = ocfs2_extent_map_lookup(inode, v_cluster, p_cluster,
                                      num_clusters, extent_flags);
        if (ret == 0)
index f3bc3658e7a5ef69ee677c2822b541c557da84b7..a62b14eb40650e6af179d49665e21bfaa553ab0e 100644 (file)
@@ -397,6 +397,15 @@ static int ocfs2_truncate_file(struct inode *inode,
        unmap_mapping_range(inode->i_mapping, new_i_size + PAGE_SIZE - 1, 0, 1);
        truncate_inode_pages(inode->i_mapping, new_i_size);
 
+       if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+               status = ocfs2_truncate_inline(inode, di_bh, new_i_size,
+                                              i_size_read(inode), 0);
+               if (status)
+                       mlog_errno(status);
+
+               goto bail_unlock_data;
+       }
+
        /* alright, we're going to need to do a full blown alloc size
         * change. Orphan the inode so that recovery can complete the
         * truncate if necessary. This does the task of marking
@@ -779,25 +788,6 @@ leave:
        return status;
 }
 
-static int ocfs2_extend_allocation(struct inode *inode, u32 logical_start,
-                                  u32 clusters_to_add, int mark_unwritten)
-{
-       int ret;
-
-       /*
-        * The alloc sem blocks peope in read/write from reading our
-        * allocation until we're done changing it. We depend on
-        * i_mutex to block other extend/truncate calls while we're
-        * here.
-        */
-       down_write(&OCFS2_I(inode)->ip_alloc_sem);
-       ret = __ocfs2_extend_allocation(inode, logical_start, clusters_to_add,
-                                       mark_unwritten);
-       up_write(&OCFS2_I(inode)->ip_alloc_sem);
-
-       return ret;
-}
-
 /* Some parts of this taken from generic_cont_expand, which turned out
  * to be too fragile to do exactly what we need without us having to
  * worry about recursive locking in ->prepare_write() and
@@ -889,25 +879,48 @@ out:
        return ret;
 }
 
-/* 
- * A tail_to_skip value > 0 indicates that we're being called from
- * ocfs2_file_aio_write(). This has the following implications:
- *
- * - we don't want to update i_size
- * - di_bh will be NULL, which is fine because it's only used in the
- *   case where we want to update i_size.
- * - ocfs2_zero_extend() will then only be filling the hole created
- *   between i_size and the start of the write.
- */
+int ocfs2_extend_no_holes(struct inode *inode, u64 new_i_size, u64 zero_to)
+{
+       int ret;
+       u32 clusters_to_add;
+       struct ocfs2_inode_info *oi = OCFS2_I(inode);
+
+       clusters_to_add = ocfs2_clusters_for_bytes(inode->i_sb, new_i_size);
+       if (clusters_to_add < oi->ip_clusters)
+               clusters_to_add = 0;
+       else
+               clusters_to_add -= oi->ip_clusters;
+
+       if (clusters_to_add) {
+               ret = __ocfs2_extend_allocation(inode, oi->ip_clusters,
+                                               clusters_to_add, 0);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+       }
+
+       /*
+        * Call this even if we don't add any clusters to the tree. We
+        * still need to zero the area between the old i_size and the
+        * new i_size.
+        */
+       ret = ocfs2_zero_extend(inode, zero_to);
+       if (ret < 0)
+               mlog_errno(ret);
+
+out:
+       return ret;
+}
+
 static int ocfs2_extend_file(struct inode *inode,
                             struct buffer_head *di_bh,
-                            u64 new_i_size,
-                            size_t tail_to_skip)
+                            u64 new_i_size)
 {
-       int ret = 0;
-       u32 clusters_to_add = 0;
+       int ret = 0, data_locked = 0;
+       struct ocfs2_inode_info *oi = OCFS2_I(inode);
 
-       BUG_ON(!tail_to_skip && !di_bh);
+       BUG_ON(!di_bh);
 
        /* setattr sometimes calls us like this. */
        if (new_i_size == 0)
@@ -917,13 +930,18 @@ static int ocfs2_extend_file(struct inode *inode,
                goto out;
        BUG_ON(new_i_size < i_size_read(inode));
 
-       if (ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) {
-               BUG_ON(tail_to_skip != 0);
+       /*
+        * Fall through for converting inline data, even if the fs
+        * supports sparse files.
+        *
+        * The check for inline data here is legal - nobody can add
+        * the feature since we have i_mutex. We must check it again
+        * after acquiring ip_alloc_sem though, as paths like mmap
+        * might have raced us to converting the inode to extents.
+        */
+       if (!(oi->ip_dyn_features & OCFS2_INLINE_DATA_FL)
+           && ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb)))
                goto out_update_size;
-       }
-
-       clusters_to_add = ocfs2_clusters_for_bytes(inode->i_sb, new_i_size) - 
-               OCFS2_I(inode)->ip_clusters;
 
        /* 
         * protect the pages that ocfs2_zero_extend is going to be
@@ -937,39 +955,52 @@ static int ocfs2_extend_file(struct inode *inode,
                mlog_errno(ret);
                goto out;
        }
+       data_locked = 1;
+
+       /*
+        * The alloc sem blocks people in read/write from reading our
+        * allocation until we're done changing it. We depend on
+        * i_mutex to block other extend/truncate calls while we're
+        * here.
+        */
+       down_write(&oi->ip_alloc_sem);
+
+       if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+               /*
+                * We can optimize small extends by keeping the inodes
+                * inline data.
+                */
+               if (ocfs2_size_fits_inline_data(di_bh, new_i_size)) {
+                       up_write(&oi->ip_alloc_sem);
+                       goto out_update_size;
+               }
+
+               ret = ocfs2_convert_inline_data_to_extents(inode, di_bh);
+               if (ret) {
+                       up_write(&oi->ip_alloc_sem);
 
-       if (clusters_to_add) {
-               ret = ocfs2_extend_allocation(inode,
-                                             OCFS2_I(inode)->ip_clusters,
-                                             clusters_to_add, 0);
-               if (ret < 0) {
                        mlog_errno(ret);
                        goto out_unlock;
                }
        }
 
-       /*
-        * Call this even if we don't add any clusters to the tree. We
-        * still need to zero the area between the old i_size and the
-        * new i_size.
-        */
-       ret = ocfs2_zero_extend(inode, (u64)new_i_size - tail_to_skip);
+       if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb)))
+               ret = ocfs2_extend_no_holes(inode, new_i_size, new_i_size);
+
+       up_write(&oi->ip_alloc_sem);
+
        if (ret < 0) {
                mlog_errno(ret);
                goto out_unlock;
        }
 
 out_update_size:
-       if (!tail_to_skip) {
-               /* We're being called from ocfs2_setattr() which wants
-                * us to update i_size */
-               ret = ocfs2_simple_size_update(inode, di_bh, new_i_size);
-               if (ret < 0)
-                       mlog_errno(ret);
-       }
+       ret = ocfs2_simple_size_update(inode, di_bh, new_i_size);
+       if (ret < 0)
+               mlog_errno(ret);
 
 out_unlock:
-       if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb)))
+       if (data_locked)
                ocfs2_data_unlock(inode, 1);
 
 out:
@@ -1035,7 +1066,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
                if (i_size_read(inode) > attr->ia_size)
                        status = ocfs2_truncate_file(inode, bh, attr->ia_size);
                else
-                       status = ocfs2_extend_file(inode, bh, attr->ia_size, 0);
+                       status = ocfs2_extend_file(inode, bh, attr->ia_size);
                if (status < 0) {
                        if (status != -ENOSPC)
                                mlog_errno(status);
@@ -1243,6 +1274,31 @@ static int ocfs2_allocate_unwritten_extents(struct inode *inode,
 {
        int ret;
        u32 cpos, phys_cpos, clusters, alloc_size;
+       u64 end = start + len;
+       struct buffer_head *di_bh = NULL;
+
+       if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+               ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
+                                      OCFS2_I(inode)->ip_blkno, &di_bh,
+                                      OCFS2_BH_CACHED, inode);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+
+               /*
+                * Nothing to do if the requested reservation range
+                * fits within the inode.
+                */
+               if (ocfs2_size_fits_inline_data(di_bh, end))
+                       goto out;
+
+               ret = ocfs2_convert_inline_data_to_extents(inode, di_bh);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+       }
 
        /*
         * We consider both start and len to be inclusive.
@@ -1288,6 +1344,8 @@ next:
 
        ret = 0;
 out:
+
+       brelse(di_bh);
        return ret;
 }
 
@@ -1469,6 +1527,14 @@ static int ocfs2_remove_inode_range(struct inode *inode,
        if (byte_len == 0)
                return 0;
 
+       if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+               ret = ocfs2_truncate_inline(inode, di_bh, byte_start,
+                                           byte_start + byte_len, 1);
+               if (ret)
+                       mlog_errno(ret);
+               return ret;
+       }
+
        trunc_start = ocfs2_clusters_for_bytes(osb->sb, byte_start);
        trunc_len = (byte_start + byte_len) >> osb->s_clustersize_bits;
        if (trunc_len >= trunc_start)
@@ -1713,15 +1779,13 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
                                         int appending,
                                         int *direct_io)
 {
-       int ret = 0, meta_level = appending;
+       int ret = 0, meta_level = 0;
        struct inode *inode = dentry->d_inode;
-       u32 clusters;
-       loff_t newsize, saved_pos;
+       loff_t saved_pos, end;
 
        /* 
-        * We sample i_size under a read level meta lock to see if our write
-        * is extending the file, if it is we back off and get a write level
-        * meta lock.
+        * We start with a read level meta lock and only jump to an ex
+        * if we need to make modifications here.
         */
        for(;;) {
                ret = ocfs2_meta_lock(inode, NULL, meta_level);
@@ -1763,87 +1827,47 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
                        saved_pos = *ppos;
                }
 
-               if (ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) {
-                       loff_t end = saved_pos + count;
+               end = saved_pos + count;
 
-                       /*
-                        * Skip the O_DIRECT checks if we don't need
-                        * them.
-                        */
-                       if (!direct_io || !(*direct_io))
-                               break;
-
-                       /*
-                        * Allowing concurrent direct writes means
-                        * i_size changes wouldn't be synchronized, so
-                        * one node could wind up truncating another
-                        * nodes writes.
-                        */
-                       if (end > i_size_read(inode)) {
-                               *direct_io = 0;
-                               break;
-                       }
-
-                       /*
-                        * We don't fill holes during direct io, so
-                        * check for them here. If any are found, the
-                        * caller will have to retake some cluster
-                        * locks and initiate the io as buffered.
-                        */
-                       ret = ocfs2_check_range_for_holes(inode, saved_pos,
-                                                         count);
-                       if (ret == 1) {
-                               *direct_io = 0;
-                               ret = 0;
-                       } else if (ret < 0)
-                               mlog_errno(ret);
+               /*
+                * Skip the O_DIRECT checks if we don't need
+                * them.
+                */
+               if (!direct_io || !(*direct_io))
                        break;
-               }
 
                /*
-                * The rest of this loop is concerned with legacy file
-                * systems which don't support sparse files.
+                * There's no sane way to do direct writes to an inode
+                * with inline data.
                 */
-
-               newsize = count + saved_pos;
-
-               mlog(0, "pos=%lld newsize=%lld cursize=%lld\n",
-                    (long long) saved_pos, (long long) newsize,
-                    (long long) i_size_read(inode));
-
-               /* No need for a higher level metadata lock if we're
-                * never going past i_size. */
-               if (newsize <= i_size_read(inode))
+               if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+                       *direct_io = 0;
                        break;
-
-               if (meta_level == 0) {
-                       ocfs2_meta_unlock(inode, meta_level);
-                       meta_level = 1;
-                       continue;
                }
 
-               spin_lock(&OCFS2_I(inode)->ip_lock);
-               clusters = ocfs2_clusters_for_bytes(inode->i_sb, newsize) -
-                       OCFS2_I(inode)->ip_clusters;
-               spin_unlock(&OCFS2_I(inode)->ip_lock);
-
-               mlog(0, "Writing at EOF, may need more allocation: "
-                    "i_size = %lld, newsize = %lld, need %u clusters\n",
-                    (long long) i_size_read(inode), (long long) newsize,
-                    clusters);
-
-               /* We only want to continue the rest of this loop if
-                * our extend will actually require more
-                * allocation. */
-               if (!clusters)
+               /*
+                * Allowing concurrent direct writes means
+                * i_size changes wouldn't be synchronized, so
+                * one node could wind up truncating another
+                * nodes writes.
+                */
+               if (end > i_size_read(inode)) {
+                       *direct_io = 0;
                        break;
-
-               ret = ocfs2_extend_file(inode, NULL, newsize, count);
-               if (ret < 0) {
-                       if (ret != -ENOSPC)
-                               mlog_errno(ret);
-                       goto out_unlock;
                }
+
+               /*
+                * We don't fill holes during direct io, so
+                * check for them here. If any are found, the
+                * caller will have to retake some cluster
+                * locks and initiate the io as buffered.
+                */
+               ret = ocfs2_check_range_for_holes(inode, saved_pos, count);
+               if (ret == 1) {
+                       *direct_io = 0;
+                       ret = 0;
+               } else if (ret < 0)
+                       mlog_errno(ret);
                break;
        }
 
index 36fe27f268ee2c84a6a02fbe8284f8a1aabc29f7..066f14add3a8c2f06ad465b2d9b81011ffaf0e4b 100644 (file)
@@ -47,6 +47,8 @@ int ocfs2_do_extend_allocation(struct ocfs2_super *osb,
                               struct ocfs2_alloc_context *data_ac,
                               struct ocfs2_alloc_context *meta_ac,
                               enum ocfs2_alloc_restarted *reason_ret);
+int ocfs2_extend_no_holes(struct inode *inode, u64 new_i_size,
+                         u64 zero_to);
 int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_dinode *di,
                          u32 clusters_to_add, u32 extents_to_split,
                          struct ocfs2_alloc_context **data_ac,
index c53a6763bbbebf7500f4c53e9e1e38ca9806eb15..1d5e0cb0fda1ded9ad69ae0365c9c082fc48ca55 100644 (file)
@@ -241,6 +241,7 @@ int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,
 
        OCFS2_I(inode)->ip_clusters = le32_to_cpu(fe->i_clusters);
        OCFS2_I(inode)->ip_attr = le32_to_cpu(fe->i_attr);
+       OCFS2_I(inode)->ip_dyn_features = le16_to_cpu(fe->i_dyn_features);
 
        inode->i_version = 1;
        inode->i_generation = le32_to_cpu(fe->i_generation);
@@ -513,6 +514,10 @@ static int ocfs2_truncate_for_delete(struct ocfs2_super *osb,
 
        fe = (struct ocfs2_dinode *) fe_bh->b_data;
 
+       /*
+        * This check will also skip truncate of inodes with inline
+        * data and fast symlinks.
+        */
        if (fe->i_clusters) {
                handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
                if (IS_ERR(handle)) {
@@ -1220,6 +1225,7 @@ int ocfs2_mark_inode_dirty(handle_t *handle,
        fe->i_clusters = cpu_to_le32(OCFS2_I(inode)->ip_clusters);
        ocfs2_get_inode_flags(OCFS2_I(inode));
        fe->i_attr = cpu_to_le32(OCFS2_I(inode)->ip_attr);
+       fe->i_dyn_features = cpu_to_le16(OCFS2_I(inode)->ip_dyn_features);
        spin_unlock(&OCFS2_I(inode)->ip_lock);
 
        fe->i_size = cpu_to_le64(i_size_read(inode));
@@ -1257,6 +1263,7 @@ void ocfs2_refresh_inode(struct inode *inode,
 
        OCFS2_I(inode)->ip_clusters = le32_to_cpu(fe->i_clusters);
        OCFS2_I(inode)->ip_attr = le32_to_cpu(fe->i_attr);
+       OCFS2_I(inode)->ip_dyn_features = le16_to_cpu(fe->i_dyn_features);
        ocfs2_set_inode_flags(inode);
        i_size_write(inode, le64_to_cpu(fe->i_size));
        inode->i_nlink = le16_to_cpu(fe->i_links_count);
index a41d0817121b21ed35e73def7ec91a5e603b7dec..70e881c5553621d4e8f6fc380f1b682c5499587d 100644 (file)
@@ -51,6 +51,7 @@ struct ocfs2_inode_info
 
        u32                             ip_flags; /* see below */
        u32                             ip_attr; /* inode attributes */
+       u16                             ip_dyn_features;
 
        /* protected by recovery_lock. */
        struct inode                    *ip_next_orphan;
index dbfb20bb27ea426e57ff71b031f247de699f1ff7..f9d01e25298decaa3b24ab3e3c38ee88d3d6c55c 100644 (file)
 #include "ocfs2.h"
 
 #include "alloc.h"
+#include "dir.h"
 #include "dlmglue.h"
 #include "extent_map.h"
 #include "heartbeat.h"
 #include "inode.h"
 #include "journal.h"
 #include "localalloc.h"
-#include "namei.h"
 #include "slot_map.h"
 #include "super.h"
 #include "vote.h"
@@ -1213,17 +1213,49 @@ bail:
        return status;
 }
 
+struct ocfs2_orphan_filldir_priv {
+       struct inode            *head;
+       struct ocfs2_super      *osb;
+};
+
+static int ocfs2_orphan_filldir(void *priv, const char *name, int name_len,
+                               loff_t pos, u64 ino, unsigned type)
+{
+       struct ocfs2_orphan_filldir_priv *p = priv;
+       struct inode *iter;
+
+       if (name_len == 1 && !strncmp(".", name, 1))
+               return 0;
+       if (name_len == 2 && !strncmp("..", name, 2))
+               return 0;
+
+       /* Skip bad inodes so that recovery can continue */
+       iter = ocfs2_iget(p->osb, ino,
+                         OCFS2_FI_FLAG_ORPHAN_RECOVERY);
+       if (IS_ERR(iter))
+               return 0;
+
+       mlog(0, "queue orphan %llu\n",
+            (unsigned long long)OCFS2_I(iter)->ip_blkno);
+       /* No locking is required for the next_orphan queue as there
+        * is only ever a single process doing orphan recovery. */
+       OCFS2_I(iter)->ip_next_orphan = p->head;
+       p->head = iter;
+
+       return 0;
+}
+
 static int ocfs2_queue_orphans(struct ocfs2_super *osb,
                               int slot,
                               struct inode **head)
 {
        int status;
        struct inode *orphan_dir_inode = NULL;
-       struct inode *iter;
-       unsigned long offset, blk, local;
-       struct buffer_head *bh = NULL;
-       struct ocfs2_dir_entry *de;
-       struct super_block *sb = osb->sb;
+       struct ocfs2_orphan_filldir_priv priv;
+       loff_t pos = 0;
+
+       priv.osb = osb;
+       priv.head = *head;
 
        orphan_dir_inode = ocfs2_get_system_file_inode(osb,
                                                       ORPHAN_DIR_SYSTEM_INODE,
@@ -1241,77 +1273,15 @@ static int ocfs2_queue_orphans(struct ocfs2_super *osb,
                goto out;
        }
 
-       offset = 0;
-       iter = NULL;
-       while(offset < i_size_read(orphan_dir_inode)) {
-               blk = offset >> sb->s_blocksize_bits;
-
-               bh = ocfs2_bread(orphan_dir_inode, blk, &status, 0);
-               if (!bh)
-                       status = -EINVAL;
-               if (status < 0) {
-                       if (bh)
-                               brelse(bh);
-                       mlog_errno(status);
-                       goto out_unlock;
-               }
-
-               local = 0;
-               while(offset < i_size_read(orphan_dir_inode)
-                     && local < sb->s_blocksize) {
-                       de = (struct ocfs2_dir_entry *) (bh->b_data + local);
-
-                       if (!ocfs2_check_dir_entry(orphan_dir_inode,
-                                                 de, bh, local)) {
-                               status = -EINVAL;
-                               mlog_errno(status);
-                               brelse(bh);
-                               goto out_unlock;
-                       }
-
-                       local += le16_to_cpu(de->rec_len);
-                       offset += le16_to_cpu(de->rec_len);
-
-                       /* I guess we silently fail on no inode? */
-                       if (!le64_to_cpu(de->inode))
-                               continue;
-                       if (de->file_type > OCFS2_FT_MAX) {
-                               mlog(ML_ERROR,
-                                    "block %llu contains invalid de: "
-                                    "inode = %llu, rec_len = %u, "
-                                    "name_len = %u, file_type = %u, "
-                                    "name='%.*s'\n",
-                                    (unsigned long long)bh->b_blocknr,
-                                    (unsigned long long)le64_to_cpu(de->inode),
-                                    le16_to_cpu(de->rec_len),
-                                    de->name_len,
-                                    de->file_type,
-                                    de->name_len,
-                                    de->name);
-                               continue;
-                       }
-                       if (de->name_len == 1 && !strncmp(".", de->name, 1))
-                               continue;
-                       if (de->name_len == 2 && !strncmp("..", de->name, 2))
-                               continue;
-
-                       iter = ocfs2_iget(osb, le64_to_cpu(de->inode),
-                                         OCFS2_FI_FLAG_ORPHAN_RECOVERY);
-                       if (IS_ERR(iter))
-                               continue;
-
-                       mlog(0, "queue orphan %llu\n",
-                            (unsigned long long)OCFS2_I(iter)->ip_blkno);
-                       /* No locking is required for the next_orphan
-                        * queue as there is only ever a single
-                        * process doing orphan recovery. */
-                       OCFS2_I(iter)->ip_next_orphan = *head;
-                       *head = iter;
-               }
-               brelse(bh);
+       status = ocfs2_dir_foreach(orphan_dir_inode, &pos, &priv,
+                                  ocfs2_orphan_filldir);
+       if (status) {
+               mlog_errno(status);
+               goto out;
        }
 
-out_unlock:
+       *head = priv.head;
+
        ocfs2_meta_unlock(orphan_dir_inode, 0);
 out:
        mutex_unlock(&orphan_dir_inode->i_mutex);
index ce60aab013aa2f7645fddb317b9a8c342654a50b..4b32e0961568e34372a7ad02c7c8b77b3e0c6c24 100644 (file)
@@ -282,6 +282,9 @@ int                  ocfs2_journal_dirty_data(handle_t *handle,
  * prev. group desc. if we relink. */
 #define OCFS2_SUBALLOC_ALLOC (3)
 
+#define OCFS2_INLINE_TO_EXTENTS_CREDITS (OCFS2_SUBALLOC_ALLOC          \
+                                        + OCFS2_INODE_UPDATE_CREDITS)
+
 /* dinode + group descriptor update. We don't relink on free yet. */
 #define OCFS2_SUBALLOC_FREE  (2)
 
index 701e6d04ed5d2a7ed45fa9bb6270fa6f7fa91c50..729259016c182f5a9f1e9e15da136419198dc2fd 100644 (file)
 
 #include "buffer_head_io.h"
 
-#define NAMEI_RA_CHUNKS  2
-#define NAMEI_RA_BLOCKS  4
-#define NAMEI_RA_SIZE        (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS)
-#define NAMEI_RA_INDEX(c,b)  (((c) * NAMEI_RA_BLOCKS) + (b))
-
-static int inline ocfs2_search_dirblock(struct buffer_head *bh,
-                                       struct inode *dir,
-                                       const char *name, int namelen,
-                                       unsigned long offset,
-                                       struct ocfs2_dir_entry **res_dir);
-
-static int ocfs2_delete_entry(handle_t *handle,
-                             struct inode *dir,
-                             struct ocfs2_dir_entry *de_del,
-                             struct buffer_head *bh);
-
-static int __ocfs2_add_entry(handle_t *handle,
-                            struct inode *dir,
-                            const char *name, int namelen,
-                            struct inode *inode, u64 blkno,
-                            struct buffer_head *parent_fe_bh,
-                            struct buffer_head *insert_bh);
-
 static int ocfs2_mknod_locked(struct ocfs2_super *osb,
                              struct inode *dir,
                              struct dentry *dentry, int mode,
@@ -97,13 +74,6 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb,
                              struct inode **ret_inode,
                              struct ocfs2_alloc_context *inode_ac);
 
-static int ocfs2_fill_new_dir(struct ocfs2_super *osb,
-                             handle_t *handle,
-                             struct inode *parent,
-                             struct inode *inode,
-                             struct buffer_head *fe_bh,
-                             struct ocfs2_alloc_context *data_ac);
-
 static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb,
                                    struct inode **ret_orphan_dir,
                                    struct inode *inode,
@@ -123,17 +93,6 @@ static int ocfs2_create_symlink_data(struct ocfs2_super *osb,
                                     struct inode *inode,
                                     const char *symname);
 
-static inline int ocfs2_add_entry(handle_t *handle,
-                                 struct dentry *dentry,
-                                 struct inode *inode, u64 blkno,
-                                 struct buffer_head *parent_fe_bh,
-                                 struct buffer_head *insert_bh)
-{
-       return __ocfs2_add_entry(handle, dentry->d_parent->d_inode,
-                                dentry->d_name.name, dentry->d_name.len,
-                                inode, blkno, parent_fe_bh, insert_bh);
-}
-
 /* An orphan dir name is an 8 byte value, printed as a hex string */
 #define OCFS2_ORPHAN_NAMELEN ((int)(2 * sizeof(u64)))
 
@@ -142,10 +101,8 @@ static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry,
 {
        int status;
        u64 blkno;
-       struct buffer_head *dirent_bh = NULL;
        struct inode *inode = NULL;
        struct dentry *ret;
-       struct ocfs2_dir_entry *dirent;
        struct ocfs2_inode_info *oi;
 
        mlog_entry("(0x%p, 0x%p, '%.*s')\n", dir, dentry,
@@ -167,9 +124,8 @@ static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry,
                goto bail;
        }
 
-       status = ocfs2_find_files_on_disk(dentry->d_name.name,
-                                         dentry->d_name.len, &blkno,
-                                         dir, &dirent_bh, &dirent);
+       status = ocfs2_lookup_ino_from_name(dir, dentry->d_name.name,
+                                           dentry->d_name.len, &blkno);
        if (status < 0)
                goto bail_add;
 
@@ -224,83 +180,12 @@ bail_unlock:
        ocfs2_meta_unlock(dir, 0);
 
 bail:
-       if (dirent_bh)
-               brelse(dirent_bh);
 
        mlog_exit_ptr(ret);
 
        return ret;
 }
 
-static int ocfs2_fill_new_dir(struct ocfs2_super *osb,
-                             handle_t *handle,
-                             struct inode *parent,
-                             struct inode *inode,
-                             struct buffer_head *fe_bh,
-                             struct ocfs2_alloc_context *data_ac)
-{
-       int status;
-       struct buffer_head *new_bh = NULL;
-       struct ocfs2_dir_entry *de = NULL;
-
-       mlog_entry_void();
-
-       status = ocfs2_do_extend_dir(osb->sb, handle, inode, fe_bh,
-                                    data_ac, NULL, &new_bh);
-       if (status < 0) {
-               mlog_errno(status);
-               goto bail;
-       }
-
-       ocfs2_set_new_buffer_uptodate(inode, new_bh);
-
-       status = ocfs2_journal_access(handle, inode, new_bh,
-                                     OCFS2_JOURNAL_ACCESS_CREATE);
-       if (status < 0) {
-               mlog_errno(status);
-               goto bail;
-       }
-       memset(new_bh->b_data, 0, osb->sb->s_blocksize);
-
-       de = (struct ocfs2_dir_entry *) new_bh->b_data;
-       de->inode = cpu_to_le64(OCFS2_I(inode)->ip_blkno);
-       de->name_len = 1;
-       de->rec_len =
-               cpu_to_le16(OCFS2_DIR_REC_LEN(de->name_len));
-       strcpy(de->name, ".");
-       ocfs2_set_de_type(de, S_IFDIR);
-       de = (struct ocfs2_dir_entry *) ((char *)de + le16_to_cpu(de->rec_len));
-       de->inode = cpu_to_le64(OCFS2_I(parent)->ip_blkno);
-       de->rec_len = cpu_to_le16(inode->i_sb->s_blocksize -
-                                 OCFS2_DIR_REC_LEN(1));
-       de->name_len = 2;
-       strcpy(de->name, "..");
-       ocfs2_set_de_type(de, S_IFDIR);
-
-       status = ocfs2_journal_dirty(handle, new_bh);
-       if (status < 0) {
-               mlog_errno(status);
-               goto bail;
-       }
-
-       i_size_write(inode, inode->i_sb->s_blocksize);
-       inode->i_nlink = 2;
-       inode->i_blocks = ocfs2_inode_sector_count(inode);
-       status = ocfs2_mark_inode_dirty(handle, inode, fe_bh);
-       if (status < 0) {
-               mlog_errno(status);
-               goto bail;
-       }
-
-       status = 0;
-bail:
-       if (new_bh)
-               brelse(new_bh);
-
-       mlog_exit(status);
-       return status;
-}
-
 static int ocfs2_mknod(struct inode *dir,
                       struct dentry *dentry,
                       int mode,
@@ -365,9 +250,8 @@ static int ocfs2_mknod(struct inode *dir,
                goto leave;
        }
 
-       /* are we making a directory? If so, reserve a cluster for his
-        * 1st extent. */
-       if (S_ISDIR(mode)) {
+       /* Reserve a cluster if creating an extent based directory. */
+       if (S_ISDIR(mode) && !ocfs2_supports_inline_data(osb)) {
                status = ocfs2_reserve_clusters(osb, 1, &data_ac);
                if (status < 0) {
                        if (status != -ENOSPC)
@@ -564,10 +448,21 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb,
                cpu_to_le32(CURRENT_TIME.tv_nsec);
        fe->i_dtime = 0;
 
-       fel = &fe->id2.i_list;
-       fel->l_tree_depth = 0;
-       fel->l_next_free_rec = 0;
-       fel->l_count = cpu_to_le16(ocfs2_extent_recs_per_inode(osb->sb));
+       /*
+        * If supported, directories start with inline data.
+        */
+       if (S_ISDIR(mode) && ocfs2_supports_inline_data(osb)) {
+               u16 feat = le16_to_cpu(fe->i_dyn_features);
+
+               fe->i_dyn_features = cpu_to_le16(feat | OCFS2_INLINE_DATA_FL);
+
+               fe->id2.i_data.id_count = cpu_to_le16(ocfs2_max_inline_data(osb->sb));
+       } else {
+               fel = &fe->id2.i_list;
+               fel->l_tree_depth = 0;
+               fel->l_next_free_rec = 0;
+               fel->l_count = cpu_to_le16(ocfs2_extent_recs_per_inode(osb->sb));
+       }
 
        status = ocfs2_journal_dirty(handle, *new_fe_bh);
        if (status < 0) {
@@ -1048,11 +943,6 @@ static void ocfs2_double_unlock(struct inode *inode1, struct inode *inode2)
                ocfs2_meta_unlock(inode2, 1);
 }
 
-#define PARENT_INO(buffer) \
-       ((struct ocfs2_dir_entry *) \
-        ((char *)buffer + \
-         le16_to_cpu(((struct ocfs2_dir_entry *)buffer)->rec_len)))->inode
-
 static int ocfs2_rename(struct inode *old_dir,
                        struct dentry *old_dentry,
                        struct inode *new_dir,
@@ -1070,12 +960,12 @@ static int ocfs2_rename(struct inode *old_dir,
        struct buffer_head *old_inode_bh = NULL;
        struct buffer_head *insert_entry_bh = NULL;
        struct ocfs2_super *osb = NULL;
-       u64 newfe_blkno;
+       u64 newfe_blkno, old_de_ino;
        handle_t *handle = NULL;
        struct buffer_head *old_dir_bh = NULL;
        struct buffer_head *new_dir_bh = NULL;
-       struct ocfs2_dir_entry *old_de = NULL, *new_de = NULL; // dirent for old_dentry
-                                                              // and new_dentry
+       struct ocfs2_dir_entry *old_inode_dot_dot_de = NULL, *old_de = NULL,
+               *new_de = NULL;
        struct buffer_head *new_de_bh = NULL, *old_de_bh = NULL; // bhs for above
        struct buffer_head *old_inode_de_bh = NULL; // if old_dentry is a dir,
                                                    // this is the 1st dirent bh
@@ -1159,27 +1049,35 @@ static int ocfs2_rename(struct inode *old_dir,
        }
 
        if (S_ISDIR(old_inode->i_mode)) {
-               status = -EIO;
-               old_inode_de_bh = ocfs2_bread(old_inode, 0, &status, 0);
-               if (!old_inode_de_bh)
+               u64 old_inode_parent;
+
+               status = ocfs2_find_files_on_disk("..", 2, &old_inode_parent,
+                                                 old_inode, &old_inode_de_bh,
+                                                 &old_inode_dot_dot_de);
+               if (status) {
+                       status = -EIO;
                        goto bail;
+               }
 
-               status = -EIO;
-               if (le64_to_cpu(PARENT_INO(old_inode_de_bh->b_data)) !=
-                   OCFS2_I(old_dir)->ip_blkno)
+               if (old_inode_parent != OCFS2_I(old_dir)->ip_blkno) {
+                       status = -EIO;
                        goto bail;
-               status = -EMLINK;
-               if (!new_inode && new_dir!=old_dir &&
-                   new_dir->i_nlink >= OCFS2_LINK_MAX)
+               }
+
+               if (!new_inode && new_dir != old_dir &&
+                   new_dir->i_nlink >= OCFS2_LINK_MAX) {
+                       status = -EMLINK;
                        goto bail;
+               }
        }
 
-       status = -ENOENT;
-       old_de_bh = ocfs2_find_entry(old_dentry->d_name.name,
-                                    old_dentry->d_name.len,
-                                    old_dir, &old_de);
-       if (!old_de_bh)
+       status = ocfs2_lookup_ino_from_name(old_dir, old_dentry->d_name.name,
+                                           old_dentry->d_name.len,
+                                           &old_de_ino);
+       if (status) {
+               status = -ENOENT;
                goto bail;
+       }
 
        /*
         *  Check for inode number is _not_ due to possible IO errors.
@@ -1187,8 +1085,10 @@ static int ocfs2_rename(struct inode *old_dir,
         *  and merrily kill the link to whatever was created under the
         *  same name. Goodbye sticky bit ;-<
         */
-       if (le64_to_cpu(old_de->inode) != OCFS2_I(old_inode)->ip_blkno)
+       if (old_de_ino != OCFS2_I(old_inode)->ip_blkno) {
+               status = -ENOENT;
                goto bail;
+       }
 
        /* check if the target already exists (in which case we need
         * to delete it */
@@ -1321,20 +1221,13 @@ static int ocfs2_rename(struct inode *old_dir,
                }
 
                /* change the dirent to point to the correct inode */
-               status = ocfs2_journal_access(handle, new_dir, new_de_bh,
-                                             OCFS2_JOURNAL_ACCESS_WRITE);
+               status = ocfs2_update_entry(new_dir, handle, new_de_bh,
+                                           new_de, old_inode);
                if (status < 0) {
                        mlog_errno(status);
                        goto bail;
                }
-               new_de->inode = cpu_to_le64(OCFS2_I(old_inode)->ip_blkno);
-               new_de->file_type = old_de->file_type;
                new_dir->i_version++;
-               status = ocfs2_journal_dirty(handle, new_de_bh);
-               if (status < 0) {
-                       mlog_errno(status);
-                       goto bail;
-               }
 
                if (S_ISDIR(new_inode->i_mode))
                        newfe->i_links_count = 0;
@@ -1370,7 +1263,21 @@ static int ocfs2_rename(struct inode *old_dir,
        } else
                mlog_errno(status);
 
-       /* now that the name has been added to new_dir, remove the old name */
+       /*
+        * Now that the name has been added to new_dir, remove the old name.
+        *
+        * We don't keep any directory entry context around until now
+        * because the insert might have changed the type of directory
+        * we're dealing with.
+        */
+       old_de_bh = ocfs2_find_entry(old_dentry->d_name.name,
+                                    old_dentry->d_name.len,
+                                    old_dir, &old_de);
+       if (!old_de_bh) {
+               status = -EIO;
+               goto bail;
+       }
+
        status = ocfs2_delete_entry(handle, old_dir, old_de, old_de_bh);
        if (status < 0) {
                mlog_errno(status);
@@ -1383,12 +1290,8 @@ static int ocfs2_rename(struct inode *old_dir,
        }
        old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
        if (old_inode_de_bh) {
-               status = ocfs2_journal_access(handle, old_inode,
-                                            old_inode_de_bh,
-                                            OCFS2_JOURNAL_ACCESS_WRITE);
-               PARENT_INO(old_inode_de_bh->b_data) =
-                       cpu_to_le64(OCFS2_I(new_dir)->ip_blkno);
-               status = ocfs2_journal_dirty(handle, old_inode_de_bh);
+               status = ocfs2_update_entry(old_inode, handle, old_inode_de_bh,
+                                           old_inode_dot_dot_de, new_dir);
                old_dir->i_nlink--;
                if (new_inode) {
                        new_inode->i_nlink--;
@@ -1767,329 +1670,6 @@ bail:
        return status;
 }
 
-int ocfs2_check_dir_entry(struct inode * dir,
-                         struct ocfs2_dir_entry * de,
-                         struct buffer_head * bh,
-                         unsigned long offset)
-{
-       const char *error_msg = NULL;
-       const int rlen = le16_to_cpu(de->rec_len);
-
-       if (rlen < OCFS2_DIR_REC_LEN(1))
-               error_msg = "rec_len is smaller than minimal";
-       else if (rlen % 4 != 0)
-               error_msg = "rec_len % 4 != 0";
-       else if (rlen < OCFS2_DIR_REC_LEN(de->name_len))
-               error_msg = "rec_len is too small for name_len";
-       else if (((char *) de - bh->b_data) + rlen > dir->i_sb->s_blocksize)
-               error_msg = "directory entry across blocks";
-
-       if (error_msg != NULL)
-               mlog(ML_ERROR, "bad entry in directory #%llu: %s - "
-                    "offset=%lu, inode=%llu, rec_len=%d, name_len=%d\n",
-                    (unsigned long long)OCFS2_I(dir)->ip_blkno, error_msg,
-                    offset, (unsigned long long)le64_to_cpu(de->inode), rlen,
-                    de->name_len);
-       return error_msg == NULL ? 1 : 0;
-}
-
-/* we don't always have a dentry for what we want to add, so people
- * like orphan dir can call this instead.
- *
- * If you pass me insert_bh, I'll skip the search of the other dir
- * blocks and put the record in there.
- */
-static int __ocfs2_add_entry(handle_t *handle,
-                            struct inode *dir,
-                            const char *name, int namelen,
-                            struct inode *inode, u64 blkno,
-                            struct buffer_head *parent_fe_bh,
-                            struct buffer_head *insert_bh)
-{
-       unsigned long offset;
-       unsigned short rec_len;
-       struct ocfs2_dir_entry *de, *de1;
-       struct super_block *sb;
-       int retval, status;
-
-       mlog_entry_void();
-
-       sb = dir->i_sb;
-
-       if (!namelen)
-               return -EINVAL;
-
-       rec_len = OCFS2_DIR_REC_LEN(namelen);
-       offset = 0;
-       de = (struct ocfs2_dir_entry *) insert_bh->b_data;
-       while (1) {
-               BUG_ON((char *)de >= sb->s_blocksize + insert_bh->b_data);
-               /* These checks should've already been passed by the
-                * prepare function, but I guess we can leave them
-                * here anyway. */
-               if (!ocfs2_check_dir_entry(dir, de, insert_bh, offset)) {
-                       retval = -ENOENT;
-                       goto bail;
-               }
-               if (ocfs2_match(namelen, name, de)) {
-                       retval = -EEXIST;
-                       goto bail;
-               }
-               if (((le64_to_cpu(de->inode) == 0) &&
-                    (le16_to_cpu(de->rec_len) >= rec_len)) ||
-                   (le16_to_cpu(de->rec_len) >=
-                    (OCFS2_DIR_REC_LEN(de->name_len) + rec_len))) {
-                       dir->i_mtime = dir->i_ctime = CURRENT_TIME;
-                       retval = ocfs2_mark_inode_dirty(handle, dir, parent_fe_bh);
-                       if (retval < 0) {
-                               mlog_errno(retval);
-                               goto bail;
-                       }
-
-                       status = ocfs2_journal_access(handle, dir, insert_bh,
-                                                     OCFS2_JOURNAL_ACCESS_WRITE);
-                       /* By now the buffer is marked for journaling */
-                       offset += le16_to_cpu(de->rec_len);
-                       if (le64_to_cpu(de->inode)) {
-                               de1 = (struct ocfs2_dir_entry *)((char *) de +
-                                       OCFS2_DIR_REC_LEN(de->name_len));
-                               de1->rec_len =
-                                       cpu_to_le16(le16_to_cpu(de->rec_len) -
-                                       OCFS2_DIR_REC_LEN(de->name_len));
-                               de->rec_len = cpu_to_le16(OCFS2_DIR_REC_LEN(de->name_len));
-                               de = de1;
-                       }
-                       de->file_type = OCFS2_FT_UNKNOWN;
-                       if (blkno) {
-                               de->inode = cpu_to_le64(blkno);
-                               ocfs2_set_de_type(de, inode->i_mode);
-                       } else
-                               de->inode = 0;
-                       de->name_len = namelen;
-                       memcpy(de->name, name, namelen);
-
-                       dir->i_version++;
-                       status = ocfs2_journal_dirty(handle, insert_bh);
-                       retval = 0;
-                       goto bail;
-               }
-               offset += le16_to_cpu(de->rec_len);
-               de = (struct ocfs2_dir_entry *) ((char *) de + le16_to_cpu(de->rec_len));
-       }
-
-       /* when you think about it, the assert above should prevent us
-        * from ever getting here. */
-       retval = -ENOSPC;
-bail:
-
-       mlog_exit(retval);
-       return retval;
-}
-
-
-/*
- * ocfs2_delete_entry deletes a directory entry by merging it with the
- * previous entry
- */
-static int ocfs2_delete_entry(handle_t *handle,
-                             struct inode *dir,
-                             struct ocfs2_dir_entry *de_del,
-                             struct buffer_head *bh)
-{
-       struct ocfs2_dir_entry *de, *pde;
-       int i, status = -ENOENT;
-
-       mlog_entry("(0x%p, 0x%p, 0x%p, 0x%p)\n", handle, dir, de_del, bh);
-
-       i = 0;
-       pde = NULL;
-       de = (struct ocfs2_dir_entry *) bh->b_data;
-       while (i < bh->b_size) {
-               if (!ocfs2_check_dir_entry(dir, de, bh, i)) {
-                       status = -EIO;
-                       mlog_errno(status);
-                       goto bail;
-               }
-               if (de == de_del)  {
-                       status = ocfs2_journal_access(handle, dir, bh,
-                                                     OCFS2_JOURNAL_ACCESS_WRITE);
-                       if (status < 0) {
-                               status = -EIO;
-                               mlog_errno(status);
-                               goto bail;
-                       }
-                       if (pde)
-                               pde->rec_len =
-                                       cpu_to_le16(le16_to_cpu(pde->rec_len) +
-                                                   le16_to_cpu(de->rec_len));
-                       else
-                               de->inode = 0;
-                       dir->i_version++;
-                       status = ocfs2_journal_dirty(handle, bh);
-                       goto bail;
-               }
-               i += le16_to_cpu(de->rec_len);
-               pde = de;
-               de = (struct ocfs2_dir_entry *)((char *)de + le16_to_cpu(de->rec_len));
-       }
-bail:
-       mlog_exit(status);
-       return status;
-}
-
-/*
- * Returns 0 if not found, -1 on failure, and 1 on success
- */
-static int inline ocfs2_search_dirblock(struct buffer_head *bh,
-                                       struct inode *dir,
-                                       const char *name, int namelen,
-                                       unsigned long offset,
-                                       struct ocfs2_dir_entry **res_dir)
-{
-       struct ocfs2_dir_entry *de;
-       char *dlimit, *de_buf;
-       int de_len;
-       int ret = 0;
-
-       mlog_entry_void();
-
-       de_buf = bh->b_data;
-       dlimit = de_buf + dir->i_sb->s_blocksize;
-
-       while (de_buf < dlimit) {
-               /* this code is executed quadratically often */
-               /* do minimal checking `by hand' */
-
-               de = (struct ocfs2_dir_entry *) de_buf;
-
-               if (de_buf + namelen <= dlimit &&
-                   ocfs2_match(namelen, name, de)) {
-                       /* found a match - just to be sure, do a full check */
-                       if (!ocfs2_check_dir_entry(dir, de, bh, offset)) {
-                               ret = -1;
-                               goto bail;
-                       }
-                       *res_dir = de;
-                       ret = 1;
-                       goto bail;
-               }
-
-               /* prevent looping on a bad block */
-               de_len = le16_to_cpu(de->rec_len);
-               if (de_len <= 0) {
-                       ret = -1;
-                       goto bail;
-               }
-
-               de_buf += de_len;
-               offset += de_len;
-       }
-
-bail:
-       mlog_exit(ret);
-       return ret;
-}
-
-struct buffer_head *ocfs2_find_entry(const char *name, int namelen,
-                                    struct inode *dir,
-                                    struct ocfs2_dir_entry **res_dir)
-{
-       struct super_block *sb;
-       struct buffer_head *bh_use[NAMEI_RA_SIZE];
-       struct buffer_head *bh, *ret = NULL;
-       unsigned long start, block, b;
-       int ra_max = 0;         /* Number of bh's in the readahead
-                                  buffer, bh_use[] */
-       int ra_ptr = 0;         /* Current index into readahead
-                                  buffer */
-       int num = 0;
-       int nblocks, i, err;
-
-       mlog_entry_void();
-
-       *res_dir = NULL;
-       sb = dir->i_sb;
-
-       nblocks = i_size_read(dir) >> sb->s_blocksize_bits;
-       start = OCFS2_I(dir)->ip_dir_start_lookup;
-       if (start >= nblocks)
-               start = 0;
-       block = start;
-
-restart:
-       do {
-               /*
-                * We deal with the read-ahead logic here.
-                */
-               if (ra_ptr >= ra_max) {
-                       /* Refill the readahead buffer */
-                       ra_ptr = 0;
-                       b = block;
-                       for (ra_max = 0; ra_max < NAMEI_RA_SIZE; ra_max++) {
-                               /*
-                                * Terminate if we reach the end of the
-                                * directory and must wrap, or if our
-                                * search has finished at this block.
-                                */
-                               if (b >= nblocks || (num && block == start)) {
-                                       bh_use[ra_max] = NULL;
-                                       break;
-                               }
-                               num++;
-
-                               bh = ocfs2_bread(dir, b++, &err, 1);
-                               bh_use[ra_max] = bh;
-                       }
-               }
-               if ((bh = bh_use[ra_ptr++]) == NULL)
-                       goto next;
-               wait_on_buffer(bh);
-               if (!buffer_uptodate(bh)) {
-                       /* read error, skip block & hope for the best */
-                       ocfs2_error(dir->i_sb, "reading directory %llu, "
-                                   "offset %lu\n",
-                                   (unsigned long long)OCFS2_I(dir)->ip_blkno,
-                                   block);
-                       brelse(bh);
-                       goto next;
-               }
-               i = ocfs2_search_dirblock(bh, dir, name, namelen,
-                                         block << sb->s_blocksize_bits,
-                                         res_dir);
-               if (i == 1) {
-                       OCFS2_I(dir)->ip_dir_start_lookup = block;
-                       ret = bh;
-                       goto cleanup_and_exit;
-               } else {
-                       brelse(bh);
-                       if (i < 0)
-                               goto cleanup_and_exit;
-               }
-       next:
-               if (++block >= nblocks)
-                       block = 0;
-       } while (block != start);
-
-       /*
-        * If the directory has grown while we were searching, then
-        * search the last part of the directory before giving up.
-        */
-       block = nblocks;
-       nblocks = i_size_read(dir) >> sb->s_blocksize_bits;
-       if (block < nblocks) {
-               start = 0;
-               goto restart;
-       }
-
-cleanup_and_exit:
-       /* Clean up the read-ahead blocks */
-       for (; ra_ptr < ra_max; ra_ptr++)
-               brelse(bh_use[ra_ptr]);
-
-       mlog_exit_ptr(ret);
-       return ret;
-}
-
 static int ocfs2_blkno_stringify(u64 blkno, char *name)
 {
        int status, namelen;
index 0975c7b7212bfdecfc9570c66c8865d6ce34060d..688aef64c879b1bac95d660c2cecde1a607d1409 100644 (file)
@@ -30,29 +30,10 @@ extern const struct inode_operations ocfs2_dir_iops;
 
 struct dentry *ocfs2_get_parent(struct dentry *child);
 
-int ocfs2_check_dir_entry (struct inode *dir,
-                          struct ocfs2_dir_entry *de,
-                          struct buffer_head *bh,
-                          unsigned long offset);
-struct buffer_head *ocfs2_find_entry(const char *name,
-                                    int namelen,
-                                    struct inode *dir,
-                                    struct ocfs2_dir_entry **res_dir);
 int ocfs2_orphan_del(struct ocfs2_super *osb,
                     handle_t *handle,
                     struct inode *orphan_dir_inode,
                     struct inode *inode,
                     struct buffer_head *orphan_dir_bh);
 
-static inline int ocfs2_match(int len,
-                             const char * const name,
-                             struct ocfs2_dir_entry *de)
-{
-       if (len != de->name_len)
-               return 0;
-       if (!de->inode)
-               return 0;
-       return !memcmp(name, de->name, len);
-}
-
 #endif /* OCFS2_NAMEI_H */
index 58307853fb4a5be7100405d720f720202bcec6f6..60a23e1906b0c054c9b3a7091a662437cb3c7ab5 100644 (file)
@@ -319,6 +319,13 @@ static inline int ocfs2_writes_unwritten_extents(struct ocfs2_super *osb)
        return 0;
 }
 
+static inline int ocfs2_supports_inline_data(struct ocfs2_super *osb)
+{
+       if (osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_INLINE_DATA)
+               return 1;
+       return 0;
+}
+
 /* set / clear functions because cluster events can make these happen
  * in parallel so we want the transitions to be atomic. this also
  * means that any future flags osb_flags must be protected by spinlock
index 82f8a75b207e4b015a65bb3de1acbc0a4a41502e..6ef876759a737eb098d7abbf70e87d69663114f9 100644 (file)
@@ -87,7 +87,8 @@
 
 #define OCFS2_FEATURE_COMPAT_SUPP      OCFS2_FEATURE_COMPAT_BACKUP_SB
 #define OCFS2_FEATURE_INCOMPAT_SUPP    (OCFS2_FEATURE_INCOMPAT_LOCAL_MOUNT \
-                                        | OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC)
+                                        | OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC \
+                                        | OCFS2_FEATURE_INCOMPAT_INLINE_DATA)
 #define OCFS2_FEATURE_RO_COMPAT_SUPP   OCFS2_FEATURE_RO_COMPAT_UNWRITTEN
 
 /*
 /* Support for sparse allocation in b-trees */
 #define OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC    0x0010
 
+/*
+ * Tunefs sets this incompat flag before starting an operation which
+ * would require cleanup on abort. This is done to protect users from
+ * inadvertently mounting the fs after an aborted run without
+ * fsck-ing.
+ *
+ * s_tunefs_flags on the super block describes precisely which
+ * operations were in progress.
+ */
+#define OCFS2_FEATURE_INCOMPAT_TUNEFS_INPROG   0x0020
+
+/* Support for data packed into inode blocks */
+#define OCFS2_FEATURE_INCOMPAT_INLINE_DATA     0x0040
+
 /*
  * backup superblock flag is used to indicate that this volume
  * has backup superblocks.
 /* the max backup superblock nums */
 #define OCFS2_MAX_BACKUP_SUPERBLOCKS   6
 
+/*
+ * Flags on ocfs2_super_block.s_tunefs_flags
+ */
+#define OCFS2_TUNEFS_INPROG_REMOVE_SLOT                0x0001  /* Removing slots */
+
 /*
  * Flags on ocfs2_dinode.i_flags
  */
 #define OCFS2_CHAIN_FL         (0x00000400)    /* Chain allocator */
 #define OCFS2_DEALLOC_FL       (0x00000800)    /* Truncate log */
 
+/*
+ * Flags on ocfs2_dinode.i_dyn_features
+ *
+ * These can change much more often than i_flags. When adding flags,
+ * keep in mind that i_dyn_features is only 16 bits wide.
+ */
+#define OCFS2_INLINE_DATA_FL   (0x0001)        /* Data stored in inode block */
+#define OCFS2_HAS_XATTR_FL     (0x0002)
+#define OCFS2_INLINE_XATTR_FL  (0x0004)
+#define OCFS2_INDEXED_DIR_FL   (0x0008)
+
 /* Inode attributes, keep in sync with EXT2 */
 #define OCFS2_SECRM_FL         (0x00000001)    /* Secure deletion */
 #define OCFS2_UNRM_FL          (0x00000002)    /* Undelete */
@@ -447,8 +478,8 @@ struct ocfs2_super_block {
        __le32 s_clustersize_bits;      /* Clustersize for this fs */
 /*40*/ __le16 s_max_slots;             /* Max number of simultaneous mounts
                                           before tunefs required */
-       __le16 s_reserved1;
-       __le32 s_reserved2;
+       __le16 s_tunefs_flag;
+       __le32 s_reserved1;
        __le64 s_first_cluster_group;   /* Block offset of 1st cluster
                                         * group header */
 /*50*/ __u8  s_label[OCFS2_MAX_VOL_LABEL_LEN]; /* Label for mounting, etc. */
@@ -470,6 +501,19 @@ struct ocfs2_local_alloc
 /*10*/ __u8   la_bitmap[0];
 };
 
+/*
+ * Data-in-inode header. This is only used if i_dyn_features has
+ * OCFS2_INLINE_DATA_FL set.
+ */
+struct ocfs2_inline_data
+{
+/*00*/ __le16  id_count;       /* Number of bytes that can be used
+                                * for data, starting at id_data */
+       __le16  id_reserved0;
+       __le32  id_reserved1;
+       __u8    id_data[0];     /* Start of user data */
+};
+
 /*
  * On disk inode for OCFS2
  */
@@ -502,7 +546,7 @@ struct ocfs2_dinode {
        __le32 i_attr;
        __le16 i_orphaned_slot;         /* Only valid when OCFS2_ORPHANED_FL
                                           was set in i_flags */
-       __le16 i_reserved1;
+       __le16 i_dyn_features;
 /*70*/ __le64 i_reserved2[8];
 /*B8*/ union {
                __le64 i_pad1;          /* Generic way to refer to this
@@ -528,6 +572,7 @@ struct ocfs2_dinode {
                struct ocfs2_chain_list         i_chain;
                struct ocfs2_extent_list        i_list;
                struct ocfs2_truncate_log       i_dealloc;
+               struct ocfs2_inline_data        i_data;
                __u8                            i_symlink[0];
        } id2;
 /* Actual on-disk size is one block */
@@ -577,6 +622,12 @@ static inline int ocfs2_fast_symlink_chars(struct super_block *sb)
                 offsetof(struct ocfs2_dinode, id2.i_symlink);
 }
 
+static inline int ocfs2_max_inline_data(struct super_block *sb)
+{
+       return sb->s_blocksize -
+               offsetof(struct ocfs2_dinode, id2.i_data.id_data);
+}
+
 static inline int ocfs2_extent_recs_per_inode(struct super_block *sb)
 {
        int size;
@@ -656,6 +707,11 @@ static inline int ocfs2_fast_symlink_chars(int blocksize)
        return blocksize - offsetof(struct ocfs2_dinode, id2.i_symlink);
 }
 
+static inline int ocfs2_max_inline_data(int blocksize)
+{
+       return blocksize - offsetof(struct ocfs2_dinode, id2.i_data.id_data);
+}
+
 static inline int ocfs2_extent_recs_per_inode(int blocksize)
 {
        int size;
index c034b5129c1e6a2d1823b68888b1ad89fe907248..0e2a1b45bf922f909936d1af3212e4e6d469edfd 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/parser.h>
 #include <linux/crc32.h>
 #include <linux/debugfs.h>
+#include <linux/mount.h>
 
 #include <cluster/nodemanager.h>
 
@@ -91,6 +92,7 @@ struct mount_options
 static int ocfs2_parse_options(struct super_block *sb, char *options,
                               struct mount_options *mopt,
                               int is_remount);
+static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt);
 static void ocfs2_put_super(struct super_block *sb);
 static int ocfs2_mount_volume(struct super_block *sb);
 static int ocfs2_remount(struct super_block *sb, int *flags, char *data);
@@ -105,7 +107,7 @@ static int ocfs2_sync_fs(struct super_block *sb, int wait);
 
 static int ocfs2_init_global_system_inodes(struct ocfs2_super *osb);
 static int ocfs2_init_local_system_inodes(struct ocfs2_super *osb);
-static int ocfs2_release_system_inodes(struct ocfs2_super *osb);
+static void ocfs2_release_system_inodes(struct ocfs2_super *osb);
 static int ocfs2_fill_local_node_info(struct ocfs2_super *osb);
 static int ocfs2_check_volume(struct ocfs2_super *osb);
 static int ocfs2_verify_volume(struct ocfs2_dinode *di,
@@ -133,6 +135,7 @@ static const struct super_operations ocfs2_sops = {
        .write_super    = ocfs2_write_super,
        .put_super      = ocfs2_put_super,
        .remount_fs     = ocfs2_remount,
+       .show_options   = ocfs2_show_options,
 };
 
 enum {
@@ -177,7 +180,7 @@ static void ocfs2_write_super(struct super_block *sb)
 
 static int ocfs2_sync_fs(struct super_block *sb, int wait)
 {
-       int status = 0;
+       int status;
        tid_t target;
        struct ocfs2_super *osb = OCFS2_SB(sb);
 
@@ -275,9 +278,9 @@ bail:
        return status;
 }
 
-static int ocfs2_release_system_inodes(struct ocfs2_super *osb)
+static void ocfs2_release_system_inodes(struct ocfs2_super *osb)
 {
-       int status = 0, i;
+       int i;
        struct inode *inode;
 
        mlog_entry_void();
@@ -302,8 +305,7 @@ static int ocfs2_release_system_inodes(struct ocfs2_super *osb)
                osb->root_inode = NULL;
        }
 
-       mlog_exit(status);
-       return status;
+       mlog_exit(0);
 }
 
 /* We're allocating fs objects, use GFP_NOFS */
@@ -453,7 +455,7 @@ static int ocfs2_sb_probe(struct super_block *sb,
                          struct buffer_head **bh,
                          int *sector_size)
 {
-       int status = 0, tmpstat;
+       int status, tmpstat;
        struct ocfs1_vol_disk_hdr *hdr;
        struct ocfs2_dinode *di;
        int blksize;
@@ -830,6 +832,41 @@ bail:
        return status;
 }
 
+static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt)
+{
+       struct ocfs2_super *osb = OCFS2_SB(mnt->mnt_sb);
+       unsigned long opts = osb->s_mount_opt;
+
+       if (opts & OCFS2_MOUNT_HB_LOCAL)
+               seq_printf(s, ",_netdev,heartbeat=local");
+       else
+               seq_printf(s, ",heartbeat=none");
+
+       if (opts & OCFS2_MOUNT_NOINTR)
+               seq_printf(s, ",nointr");
+
+       if (opts & OCFS2_MOUNT_DATA_WRITEBACK)
+               seq_printf(s, ",data=writeback");
+       else
+               seq_printf(s, ",data=ordered");
+
+       if (opts & OCFS2_MOUNT_BARRIER)
+               seq_printf(s, ",barrier=1");
+
+       if (opts & OCFS2_MOUNT_ERRORS_PANIC)
+               seq_printf(s, ",errors=panic");
+       else
+               seq_printf(s, ",errors=remount-ro");
+
+       if (osb->preferred_slot != OCFS2_INVALID_SLOT)
+               seq_printf(s, ",preferred_slot=%d", osb->preferred_slot);
+
+       if (osb->s_atime_quantum != OCFS2_DEFAULT_ATIME_QUANTUM)
+               seq_printf(s, ",atime_quantum=%u", osb->s_atime_quantum);
+
+       return 0;
+}
+
 static int __init ocfs2_init(void)
 {
        int status;
@@ -1209,12 +1246,13 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err)
                tmp = ocfs2_request_umount_vote(osb);
                if (tmp < 0)
                        mlog_errno(tmp);
+       }
 
-               if (osb->slot_num != OCFS2_INVALID_SLOT)
-                       ocfs2_put_slot(osb);
+       if (osb->slot_num != OCFS2_INVALID_SLOT)
+               ocfs2_put_slot(osb);
 
+       if (osb->dlm)
                ocfs2_super_unlock(osb, 1);
-       }
 
        ocfs2_release_system_inodes(osb);
 
@@ -1275,7 +1313,7 @@ static int ocfs2_initialize_super(struct super_block *sb,
                                  struct buffer_head *bh,
                                  int sector_size)
 {
-       int status = 0;
+       int status;
        int i, cbits, bbits;
        struct ocfs2_dinode *di = (struct ocfs2_dinode *)bh->b_data;
        struct inode *inode = NULL;
@@ -1596,7 +1634,7 @@ static int ocfs2_verify_volume(struct ocfs2_dinode *di,
 
 static int ocfs2_check_volume(struct ocfs2_super *osb)
 {
-       int status = 0;
+       int status;
        int dirty;
        int local;
        struct ocfs2_dinode *local_alloc = NULL; /* only used if we
index 5df6e35d09b149ba0ecbd7547b3a21587c0c50cb..fd2e846e3e6f6a76ec5c84f0d8eb8f91d751a9ba 100644 (file)
@@ -100,17 +100,14 @@ static struct inode * _ocfs2_get_system_file_inode(struct ocfs2_super *osb,
        char namebuf[40];
        struct inode *inode = NULL;
        u64 blkno;
-       struct buffer_head *dirent_bh = NULL;
-       struct ocfs2_dir_entry *de = NULL;
        int status = 0;
 
        ocfs2_sprintf_system_inode_name(namebuf,
                                        sizeof(namebuf),
                                        type, slot);
 
-       status = ocfs2_find_files_on_disk(namebuf, strlen(namebuf),
-                                         &blkno, osb->sys_root_inode,
-                                         &dirent_bh, &de);
+       status = ocfs2_lookup_ino_from_name(osb->sys_root_inode, namebuf,
+                                           strlen(namebuf), &blkno);
        if (status < 0) {
                goto bail;
        }
@@ -122,8 +119,7 @@ static struct inode * _ocfs2_get_system_file_inode(struct ocfs2_super *osb,
                goto bail;
        }
 bail:
-       if (dirent_bh)
-               brelse(dirent_bh);
+
        return inode;
 }
 
index 783c57ec07d34cb83828980f2fd88fe8c6a5ac63..722e12e5acc71e9b90051da29f5611b5e3182f9c 100644 (file)
@@ -381,10 +381,12 @@ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len,
        p->partno = part;
        p->policy = disk->policy;
 
-       if (isdigit(disk->kobj.name[strlen(disk->kobj.name)-1]))
-               snprintf(p->kobj.name,KOBJ_NAME_LEN,"%sp%d",disk->kobj.name,part);
+       if (isdigit(disk->kobj.k_name[strlen(disk->kobj.k_name)-1]))
+               kobject_set_name(&p->kobj, "%sp%d",
+                                kobject_name(&disk->kobj), part);
        else
-               snprintf(p->kobj.name,KOBJ_NAME_LEN,"%s%d",disk->kobj.name,part);
+               kobject_set_name(&p->kobj, "%s%d",
+                                kobject_name(&disk->kobj),part);
        p->kobj.parent = &disk->kobj;
        p->kobj.ktype = &ktype_part;
        kobject_init(&p->kobj);
@@ -477,9 +479,9 @@ void register_disk(struct gendisk *disk)
        struct hd_struct *p;
        int err;
 
-       strlcpy(disk->kobj.name,disk->disk_name,KOBJ_NAME_LEN);
+       kobject_set_name(&disk->kobj, "%s", disk->disk_name);
        /* ewww... some of these buggers have / in name... */
-       s = strchr(disk->kobj.name, '/');
+       s = strchr(disk->kobj.k_name, '/');
        if (s)
                *s = '!';
        if ((err = kobject_add(&disk->kobj)))
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);
index 5afe2a26f5d877f69b268c1fb827aa8dbea55ea0..006fc64227ddb16b051b85b0a959cfee7bd652a8 100644 (file)
@@ -1,9 +1,15 @@
 /*
- * bin.c - binary file operations for sysfs.
+ * fs/sysfs/bin.c - sysfs binary file implementation
  *
  * Copyright (c) 2003 Patrick Mochel
  * Copyright (c) 2003 Matthew Wilcox
  * Copyright (c) 2004 Silicon Graphics, Inc.
+ * Copyright (c) 2007 SUSE Linux Products GmbH
+ * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
+ *
+ * This file is released under the GPLv2.
+ *
+ * Please see Documentation/filesystems/sysfs.txt for more information.
  */
 
 #undef DEBUG
@@ -14,9 +20,9 @@
 #include <linux/kobject.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
 
 #include <asm/uaccess.h>
-#include <asm/semaphore.h>
 
 #include "sysfs.h"
 
@@ -30,8 +36,8 @@ static int
 fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count)
 {
        struct sysfs_dirent *attr_sd = dentry->d_fsdata;
-       struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;
-       struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
+       struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr;
+       struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
        int rc;
 
        /* need attr_sd for attr, its parent for kobj */
@@ -87,8 +93,8 @@ static int
 flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count)
 {
        struct sysfs_dirent *attr_sd = dentry->d_fsdata;
-       struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;
-       struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
+       struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr;
+       struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
        int rc;
 
        /* need attr_sd for attr, its parent for kobj */
@@ -140,8 +146,8 @@ static int mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct bin_buffer *bb = file->private_data;
        struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
-       struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;
-       struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
+       struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr;
+       struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
        int rc;
 
        mutex_lock(&bb->mutex);
@@ -167,12 +173,12 @@ static int mmap(struct file *file, struct vm_area_struct *vma)
 static int open(struct inode * inode, struct file * file)
 {
        struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
-       struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;
+       struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr;
        struct bin_buffer *bb = NULL;
        int error;
 
-       /* need attr_sd for attr */
-       if (!sysfs_get_active(attr_sd))
+       /* binary file operations requires both @sd and its parent */
+       if (!sysfs_get_active_two(attr_sd))
                return -ENODEV;
 
        error = -EACCES;
@@ -193,13 +199,12 @@ static int open(struct inode * inode, struct file * file)
        mutex_init(&bb->mutex);
        file->private_data = bb;
 
-       /* open succeeded, put active reference and pin attr_sd */
-       sysfs_put_active(attr_sd);
-       sysfs_get(attr_sd);
+       /* open succeeded, put active references */
+       sysfs_put_active_two(attr_sd);
        return 0;
 
  err_out:
-       sysfs_put_active(attr_sd);
+       sysfs_put_active_two(attr_sd);
        kfree(bb);
        return error;
 }
@@ -211,7 +216,6 @@ static int release(struct inode * inode, struct file * file)
 
        if (bb->mmapped)
                sysfs_put_active_two(attr_sd);
-       sysfs_put(attr_sd);
        kfree(bb->buffer);
        kfree(bb);
        return 0;
index 83e76b3813c9af674fb2c6fda9c2f891c89e0964..9161db4d6b5c55b40b71e3202cad31d93a0cdad1 100644 (file)
@@ -1,5 +1,13 @@
 /*
- * dir.c - Operations for sysfs directories.
+ * fs/sysfs/dir.c - sysfs core and dir operation implementation
+ *
+ * Copyright (c) 2001-3 Patrick Mochel
+ * Copyright (c) 2007 SUSE Linux Products GmbH
+ * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
+ *
+ * This file is released under the GPLv2.
+ *
+ * Please see Documentation/filesystems/sysfs.txt for more information.
  */
 
 #undef DEBUG
 #include <linux/namei.h>
 #include <linux/idr.h>
 #include <linux/completion.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include "sysfs.h"
 
 DEFINE_MUTEX(sysfs_mutex);
+DEFINE_MUTEX(sysfs_rename_mutex);
 spinlock_t sysfs_assoc_lock = SPIN_LOCK_UNLOCKED;
 
 static spinlock_t sysfs_ino_lock = SPIN_LOCK_UNLOCKED;
@@ -25,18 +34,28 @@ static DEFINE_IDA(sysfs_ino_ida);
  *     @sd: sysfs_dirent of interest
  *
  *     Link @sd into its sibling list which starts from
- *     sd->s_parent->s_children.
+ *     sd->s_parent->s_dir.children.
  *
  *     Locking:
  *     mutex_lock(sysfs_mutex)
  */
-void sysfs_link_sibling(struct sysfs_dirent *sd)
+static void sysfs_link_sibling(struct sysfs_dirent *sd)
 {
        struct sysfs_dirent *parent_sd = sd->s_parent;
+       struct sysfs_dirent **pos;
 
        BUG_ON(sd->s_sibling);
-       sd->s_sibling = parent_sd->s_children;
-       parent_sd->s_children = sd;
+
+       /* Store directory entries in order by ino.  This allows
+        * readdir to properly restart without having to add a
+        * cursor into the s_dir.children list.
+        */
+       for (pos = &parent_sd->s_dir.children; *pos; pos = &(*pos)->s_sibling) {
+               if (sd->s_ino < (*pos)->s_ino)
+                       break;
+       }
+       sd->s_sibling = *pos;
+       *pos = sd;
 }
 
 /**
@@ -44,16 +63,17 @@ void sysfs_link_sibling(struct sysfs_dirent *sd)
  *     @sd: sysfs_dirent of interest
  *
  *     Unlink @sd from its sibling list which starts from
- *     sd->s_parent->s_children.
+ *     sd->s_parent->s_dir.children.
  *
  *     Locking:
  *     mutex_lock(sysfs_mutex)
  */
-void sysfs_unlink_sibling(struct sysfs_dirent *sd)
+static void sysfs_unlink_sibling(struct sysfs_dirent *sd)
 {
        struct sysfs_dirent **pos;
 
-       for (pos = &sd->s_parent->s_children; *pos; pos = &(*pos)->s_sibling) {
+       for (pos = &sd->s_parent->s_dir.children; *pos;
+            pos = &(*pos)->s_sibling) {
                if (*pos == sd) {
                        *pos = sd->s_sibling;
                        sd->s_sibling = NULL;
@@ -67,96 +87,39 @@ void sysfs_unlink_sibling(struct sysfs_dirent *sd)
  *     @sd: sysfs_dirent of interest
  *
  *     Get dentry for @sd.  Dentry is looked up if currently not
- *     present.  This function climbs sysfs_dirent tree till it
- *     reaches a sysfs_dirent with valid dentry attached and descends
- *     down from there looking up dentry for each step.
+ *     present.  This function descends from the root looking up
+ *     dentry for each step.
  *
  *     LOCKING:
- *     Kernel thread context (may sleep)
+ *     mutex_lock(sysfs_rename_mutex)
  *
  *     RETURNS:
  *     Pointer to found dentry on success, ERR_PTR() value on error.
  */
 struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd)
 {
-       struct sysfs_dirent *cur;
-       struct dentry *parent_dentry, *dentry;
-       int i, depth;
-
-       /* Find the first parent which has valid s_dentry and get the
-        * dentry.
-        */
-       mutex_lock(&sysfs_mutex);
- restart0:
-       spin_lock(&sysfs_assoc_lock);
- restart1:
-       spin_lock(&dcache_lock);
+       struct dentry *dentry = dget(sysfs_sb->s_root);
 
-       dentry = NULL;
-       depth = 0;
-       cur = sd;
-       while (!cur->s_dentry || !cur->s_dentry->d_inode) {
-               if (cur->s_flags & SYSFS_FLAG_REMOVED) {
-                       dentry = ERR_PTR(-ENOENT);
-                       depth = 0;
-                       break;
-               }
-               cur = cur->s_parent;
-               depth++;
-       }
-       if (!IS_ERR(dentry))
-               dentry = dget_locked(cur->s_dentry);
+       while (dentry->d_fsdata != sd) {
+               struct sysfs_dirent *cur;
+               struct dentry *parent;
 
-       spin_unlock(&dcache_lock);
-       spin_unlock(&sysfs_assoc_lock);
-
-       /* from the found dentry, look up depth times */
-       while (depth--) {
-               /* find and get depth'th ancestor */
-               for (cur = sd, i = 0; cur && i < depth; i++)
+               /* find the first ancestor which hasn't been looked up */
+               cur = sd;
+               while (cur->s_parent != dentry->d_fsdata)
                        cur = cur->s_parent;
 
-               /* This can happen if tree structure was modified due
-                * to move/rename.  Restart.
-                */
-               if (i != depth) {
-                       dput(dentry);
-                       goto restart0;
-               }
-
-               sysfs_get(cur);
-
-               mutex_unlock(&sysfs_mutex);
-
                /* look it up */
-               parent_dentry = dentry;
-               dentry = lookup_one_len_kern(cur->s_name, parent_dentry,
+               parent = dentry;
+               mutex_lock(&parent->d_inode->i_mutex);
+               dentry = lookup_one_len_kern(cur->s_name, parent,
                                             strlen(cur->s_name));
-               dput(parent_dentry);
-
-               if (IS_ERR(dentry)) {
-                       sysfs_put(cur);
-                       return dentry;
-               }
+               mutex_unlock(&parent->d_inode->i_mutex);
+               dput(parent);
 
-               mutex_lock(&sysfs_mutex);
-               spin_lock(&sysfs_assoc_lock);
-
-               /* This, again, can happen if tree structure has
-                * changed and we looked up the wrong thing.  Restart.
-                */
-               if (cur->s_dentry != dentry) {
-                       dput(dentry);
-                       sysfs_put(cur);
-                       goto restart1;
-               }
-
-               spin_unlock(&sysfs_assoc_lock);
-
-               sysfs_put(cur);
+               if (IS_ERR(dentry))
+                       break;
        }
-
-       mutex_unlock(&sysfs_mutex);
        return dentry;
 }
 
@@ -319,7 +282,7 @@ void release_sysfs_dirent(struct sysfs_dirent * sd)
        parent_sd = sd->s_parent;
 
        if (sysfs_type(sd) == SYSFS_KOBJ_LINK)
-               sysfs_put(sd->s_elem.symlink.target_sd);
+               sysfs_put(sd->s_symlink.target_sd);
        if (sysfs_type(sd) & SYSFS_COPY_NAME)
                kfree(sd->s_name);
        kfree(sd->s_iattr);
@@ -335,22 +298,7 @@ static void sysfs_d_iput(struct dentry * dentry, struct inode * inode)
 {
        struct sysfs_dirent * sd = dentry->d_fsdata;
 
-       if (sd) {
-               /* sd->s_dentry is protected with sysfs_assoc_lock.
-                * This allows sysfs_drop_dentry() to dereference it.
-                */
-               spin_lock(&sysfs_assoc_lock);
-
-               /* The dentry might have been deleted or another
-                * lookup could have happened updating sd->s_dentry to
-                * point the new dentry.  Ignore if it isn't pointing
-                * to this dentry.
-                */
-               if (sd->s_dentry == dentry)
-                       sd->s_dentry = NULL;
-               spin_unlock(&sysfs_assoc_lock);
-               sysfs_put(sd);
-       }
+       sysfs_put(sd);
        iput(inode);
 }
 
@@ -378,7 +326,6 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
 
        atomic_set(&sd->s_count, 1);
        atomic_set(&sd->s_active, 0);
-       atomic_set(&sd->s_event, 1);
 
        sd->s_name = name;
        sd->s_mode = mode;
@@ -393,30 +340,6 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
        return NULL;
 }
 
-/**
- *     sysfs_attach_dentry - associate sysfs_dirent with dentry
- *     @sd: target sysfs_dirent
- *     @dentry: dentry to associate
- *
- *     Associate @sd with @dentry.  This is protected by
- *     sysfs_assoc_lock to avoid race with sysfs_d_iput().
- *
- *     LOCKING:
- *     mutex_lock(sysfs_mutex)
- */
-static void sysfs_attach_dentry(struct sysfs_dirent *sd, struct dentry *dentry)
-{
-       dentry->d_op = &sysfs_dentry_ops;
-       dentry->d_fsdata = sysfs_get(sd);
-
-       /* protect sd->s_dentry against sysfs_d_iput */
-       spin_lock(&sysfs_assoc_lock);
-       sd->s_dentry = dentry;
-       spin_unlock(&sysfs_assoc_lock);
-
-       d_rehash(dentry);
-}
-
 static int sysfs_ilookup_test(struct inode *inode, void *arg)
 {
        struct sysfs_dirent *sd = arg;
@@ -480,10 +403,8 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt,
  *     @sd: sysfs_dirent to be added
  *
  *     Get @acxt->parent_sd and set sd->s_parent to it and increment
- *     nlink of parent inode if @sd is a directory.  @sd is NOT
- *     linked into the children list of the parent.  The caller
- *     should invoke sysfs_link_sibling() after this function
- *     completes if @sd needs to be on the children list.
+ *     nlink of parent inode if @sd is a directory and link into the
+ *     children list of the parent.
  *
  *     This function should be called between calls to
  *     sysfs_addrm_start() and sysfs_addrm_finish() and should be
@@ -491,15 +412,30 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt,
  *
  *     LOCKING:
  *     Determined by sysfs_addrm_start().
+ *
+ *     RETURNS:
+ *     0 on success, -EEXIST if entry with the given name already
+ *     exists.
  */
-void sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
+int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
 {
+       if (sysfs_find_dirent(acxt->parent_sd, sd->s_name)) {
+               printk(KERN_WARNING "sysfs: duplicate filename '%s' "
+                      "can not be created\n", sd->s_name);
+               WARN_ON(1);
+               return -EEXIST;
+       }
+
        sd->s_parent = sysfs_get(acxt->parent_sd);
 
        if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode)
                inc_nlink(acxt->parent_inode);
 
        acxt->cnt++;
+
+       sysfs_link_sibling(sd);
+
+       return 0;
 }
 
 /**
@@ -508,9 +444,7 @@ void sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
  *     @sd: sysfs_dirent to be added
  *
  *     Mark @sd removed and drop nlink of parent inode if @sd is a
- *     directory.  @sd is NOT unlinked from the children list of the
- *     parent.  The caller is repsonsible for removing @sd from the
- *     children list before calling this function.
+ *     directory.  @sd is unlinked from the children list.
  *
  *     This function should be called between calls to
  *     sysfs_addrm_start() and sysfs_addrm_finish() and should be
@@ -521,7 +455,9 @@ void sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
  */
 void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
 {
-       BUG_ON(sd->s_sibling || (sd->s_flags & SYSFS_FLAG_REMOVED));
+       BUG_ON(sd->s_flags & SYSFS_FLAG_REMOVED);
+
+       sysfs_unlink_sibling(sd);
 
        sd->s_flags |= SYSFS_FLAG_REMOVED;
        sd->s_sibling = acxt->removed;
@@ -540,53 +476,49 @@ void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
  *     Drop dentry for @sd.  @sd must have been unlinked from its
  *     parent on entry to this function such that it can't be looked
  *     up anymore.
- *
- *     @sd->s_dentry which is protected with sysfs_assoc_lock points
- *     to the currently associated dentry but we're not holding a
- *     reference to it and racing with dput().  Grab dcache_lock and
- *     verify dentry before dropping it.  If @sd->s_dentry is NULL or
- *     dput() beats us, no need to bother.
  */
 static void sysfs_drop_dentry(struct sysfs_dirent *sd)
 {
-       struct dentry *dentry = NULL;
        struct inode *inode;
+       struct dentry *dentry;
 
-       /* We're not holding a reference to ->s_dentry dentry but the
-        * field will stay valid as long as sysfs_assoc_lock is held.
+       inode = ilookup(sysfs_sb, sd->s_ino);
+       if (!inode)
+               return;
+
+       /* Drop any existing dentries associated with sd.
+        *
+        * For the dentry to be properly freed we need to grab a
+        * reference to the dentry under the dcache lock,  unhash it,
+        * and then put it.  The playing with the dentry count allows
+        * dput to immediately free the dentry  if it is not in use.
         */
-       spin_lock(&sysfs_assoc_lock);
+repeat:
        spin_lock(&dcache_lock);
-
-       /* drop dentry if it's there and dput() didn't kill it yet */
-       if (sd->s_dentry && sd->s_dentry->d_inode) {
-               dentry = dget_locked(sd->s_dentry);
+       list_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+               if (d_unhashed(dentry))
+                       continue;
+               dget_locked(dentry);
                spin_lock(&dentry->d_lock);
                __d_drop(dentry);
                spin_unlock(&dentry->d_lock);
+               spin_unlock(&dcache_lock);
+               dput(dentry);
+               goto repeat;
        }
-
        spin_unlock(&dcache_lock);
-       spin_unlock(&sysfs_assoc_lock);
-
-       /* dentries for shadowed inodes are pinned, unpin */
-       if (dentry && sysfs_is_shadowed_inode(dentry->d_inode))
-               dput(dentry);
-       dput(dentry);
 
        /* adjust nlink and update timestamp */
-       inode = ilookup(sysfs_sb, sd->s_ino);
-       if (inode) {
-               mutex_lock(&inode->i_mutex);
+       mutex_lock(&inode->i_mutex);
 
-               inode->i_ctime = CURRENT_TIME;
+       inode->i_ctime = CURRENT_TIME;
+       drop_nlink(inode);
+       if (sysfs_type(sd) == SYSFS_DIR)
                drop_nlink(inode);
-               if (sysfs_type(sd) == SYSFS_DIR)
-                       drop_nlink(inode);
 
-               mutex_unlock(&inode->i_mutex);
-               iput(inode);
-       }
+       mutex_unlock(&inode->i_mutex);
+
+       iput(inode);
 }
 
 /**
@@ -599,11 +531,8 @@ static void sysfs_drop_dentry(struct sysfs_dirent *sd)
  *
  *     LOCKING:
  *     All mutexes acquired by sysfs_addrm_start() are released.
- *
- *     RETURNS:
- *     Number of added/removed sysfs_dirents since sysfs_addrm_start().
  */
-int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt)
+void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt)
 {
        /* release resources acquired by sysfs_addrm_start() */
        mutex_unlock(&sysfs_mutex);
@@ -629,8 +558,6 @@ int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt)
                sysfs_deactivate(sd);
                sysfs_put(sd);
        }
-
-       return acxt->cnt;
 }
 
 /**
@@ -651,8 +578,8 @@ struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
 {
        struct sysfs_dirent *sd;
 
-       for (sd = parent_sd->s_children; sd; sd = sd->s_sibling)
-               if (sysfs_type(sd) && !strcmp(sd->s_name, name))
+       for (sd = parent_sd->s_dir.children; sd; sd = sd->s_sibling)
+               if (!strcmp(sd->s_name, name))
                        return sd;
        return NULL;
 }
@@ -690,28 +617,25 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
        umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
        struct sysfs_addrm_cxt acxt;
        struct sysfs_dirent *sd;
+       int rc;
 
        /* allocate */
        sd = sysfs_new_dirent(name, mode, SYSFS_DIR);
        if (!sd)
                return -ENOMEM;
-       sd->s_elem.dir.kobj = kobj;
+       sd->s_dir.kobj = kobj;
 
        /* link in */
        sysfs_addrm_start(&acxt, parent_sd);
+       rc = sysfs_add_one(&acxt, sd);
+       sysfs_addrm_finish(&acxt);
 
-       if (!sysfs_find_dirent(parent_sd, name)) {
-               sysfs_add_one(&acxt, sd);
-               sysfs_link_sibling(sd);
-       }
-
-       if (!sysfs_addrm_finish(&acxt)) {
+       if (rc == 0)
+               *p_sd = sd;
+       else
                sysfs_put(sd);
-               return -EEXIST;
-       }
 
-       *p_sd = sd;
-       return 0;
+       return rc;
 }
 
 int sysfs_create_subdir(struct kobject *kobj, const char *name,
@@ -723,24 +647,18 @@ int sysfs_create_subdir(struct kobject *kobj, const char *name,
 /**
  *     sysfs_create_dir - create a directory for an object.
  *     @kobj:          object we're creating directory for. 
- *     @shadow_parent: parent object.
  */
-int sysfs_create_dir(struct kobject *kobj,
-                    struct sysfs_dirent *shadow_parent_sd)
+int sysfs_create_dir(struct kobject * kobj)
 {
        struct sysfs_dirent *parent_sd, *sd;
        int error = 0;
 
        BUG_ON(!kobj);
 
-       if (shadow_parent_sd)
-               parent_sd = shadow_parent_sd;
-       else if (kobj->parent)
+       if (kobj->parent)
                parent_sd = kobj->parent->sd;
-       else if (sysfs_mount && sysfs_mount->mnt_sb)
-               parent_sd = sysfs_mount->mnt_sb->s_root->d_fsdata;
        else
-               return -EFAULT;
+               parent_sd = &sysfs_root;
 
        error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd);
        if (!error)
@@ -748,39 +666,20 @@ int sysfs_create_dir(struct kobject *kobj,
        return error;
 }
 
-static int sysfs_count_nlink(struct sysfs_dirent *sd)
-{
-       struct sysfs_dirent *child;
-       int nr = 0;
-
-       for (child = sd->s_children; child; child = child->s_sibling)
-               if (sysfs_type(child) == SYSFS_DIR)
-                       nr++;
-       return nr + 2;
-}
-
 static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
                                struct nameidata *nd)
 {
        struct dentry *ret = NULL;
-       struct sysfs_dirent * parent_sd = dentry->d_parent->d_fsdata;
-       struct sysfs_dirent * sd;
-       struct bin_attribute *bin_attr;
+       struct sysfs_dirent *parent_sd = dentry->d_parent->d_fsdata;
+       struct sysfs_dirent *sd;
        struct inode *inode;
-       int found = 0;
 
        mutex_lock(&sysfs_mutex);
 
-       for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) {
-               if (sysfs_type(sd) &&
-                   !strcmp(sd->s_name, dentry->d_name.name)) {
-                       found = 1;
-                       break;
-               }
-       }
+       sd = sysfs_find_dirent(parent_sd, dentry->d_name.name);
 
        /* no such entry */
-       if (!found)
+       if (!sd)
                goto out_unlock;
 
        /* attach dentry and inode */
@@ -790,33 +689,11 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
                goto out_unlock;
        }
 
-       if (inode->i_state & I_NEW) {
-               /* initialize inode according to type */
-               switch (sysfs_type(sd)) {
-               case SYSFS_DIR:
-                       inode->i_op = &sysfs_dir_inode_operations;
-                       inode->i_fop = &sysfs_dir_operations;
-                       inode->i_nlink = sysfs_count_nlink(sd);
-                       break;
-               case SYSFS_KOBJ_ATTR:
-                       inode->i_size = PAGE_SIZE;
-                       inode->i_fop = &sysfs_file_operations;
-                       break;
-               case SYSFS_KOBJ_BIN_ATTR:
-                       bin_attr = sd->s_elem.bin_attr.bin_attr;
-                       inode->i_size = bin_attr->size;
-                       inode->i_fop = &bin_fops;
-                       break;
-               case SYSFS_KOBJ_LINK:
-                       inode->i_op = &sysfs_symlink_inode_operations;
-                       break;
-               default:
-                       BUG();
-               }
-       }
-
-       sysfs_instantiate(dentry, inode);
-       sysfs_attach_dentry(sd, dentry);
+       /* instantiate and hash dentry */
+       dentry->d_op = &sysfs_dentry_ops;
+       dentry->d_fsdata = sysfs_get(sd);
+       d_instantiate(dentry, inode);
+       d_rehash(dentry);
 
  out_unlock:
        mutex_unlock(&sysfs_mutex);
@@ -833,7 +710,6 @@ static void remove_dir(struct sysfs_dirent *sd)
        struct sysfs_addrm_cxt acxt;
 
        sysfs_addrm_start(&acxt, sd->s_parent);
-       sysfs_unlink_sibling(sd);
        sysfs_remove_one(&acxt, sd);
        sysfs_addrm_finish(&acxt);
 }
@@ -854,15 +730,13 @@ static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd)
 
        pr_debug("sysfs %s: removing dir\n", dir_sd->s_name);
        sysfs_addrm_start(&acxt, dir_sd);
-       pos = &dir_sd->s_children;
+       pos = &dir_sd->s_dir.children;
        while (*pos) {
                struct sysfs_dirent *sd = *pos;
 
-               if (sysfs_type(sd) && sysfs_type(sd) != SYSFS_DIR) {
-                       *pos = sd->s_sibling;
-                       sd->s_sibling = NULL;
+               if (sysfs_type(sd) != SYSFS_DIR)
                        sysfs_remove_one(&acxt, sd);
-               else
+               else
                        pos = &(*pos)->s_sibling;
        }
        sysfs_addrm_finish(&acxt);
@@ -890,90 +764,68 @@ void sysfs_remove_dir(struct kobject * kobj)
        __sysfs_remove_dir(sd);
 }
 
-int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd,
-                    const char *new_name)
+int sysfs_rename_dir(struct kobject * kobj, const char *new_name)
 {
        struct sysfs_dirent *sd = kobj->sd;
-       struct dentry *new_parent = NULL;
+       struct dentry *parent = NULL;
        struct dentry *old_dentry = NULL, *new_dentry = NULL;
        const char *dup_name = NULL;
        int error;
 
-       /* get dentries */
+       mutex_lock(&sysfs_rename_mutex);
+
+       error = 0;
+       if (strcmp(sd->s_name, new_name) == 0)
+               goto out;       /* nothing to rename */
+
+       /* get the original dentry */
        old_dentry = sysfs_get_dentry(sd);
        if (IS_ERR(old_dentry)) {
                error = PTR_ERR(old_dentry);
-               goto out_dput;
-       }
-
-       new_parent = sysfs_get_dentry(new_parent_sd);
-       if (IS_ERR(new_parent)) {
-               error = PTR_ERR(new_parent);
-               goto out_dput;
+               goto out;
        }
 
-       /* lock new_parent and get dentry for new name */
-       mutex_lock(&new_parent->d_inode->i_mutex);
+       parent = old_dentry->d_parent;
 
-       new_dentry = lookup_one_len(new_name, new_parent, strlen(new_name));
-       if (IS_ERR(new_dentry)) {
-               error = PTR_ERR(new_dentry);
-               goto out_unlock;
-       }
+       /* lock parent and get dentry for new name */
+       mutex_lock(&parent->d_inode->i_mutex);
+       mutex_lock(&sysfs_mutex);
 
-       /* By allowing two different directories with the same
-        * d_parent we allow this routine to move between different
-        * shadows of the same directory
-        */
-       error = -EINVAL;
-       if (old_dentry->d_parent->d_inode != new_parent->d_inode ||
-           new_dentry->d_parent->d_inode != new_parent->d_inode ||
-           old_dentry == new_dentry)
+       error = -EEXIST;
+       if (sysfs_find_dirent(sd->s_parent, new_name))
                goto out_unlock;
 
-       error = -EEXIST;
-       if (new_dentry->d_inode)
+       error = -ENOMEM;
+       new_dentry = d_alloc_name(parent, new_name);
+       if (!new_dentry)
                goto out_unlock;
 
        /* rename kobject and sysfs_dirent */
        error = -ENOMEM;
        new_name = dup_name = kstrdup(new_name, GFP_KERNEL);
        if (!new_name)
-               goto out_drop;
+               goto out_unlock;
 
        error = kobject_set_name(kobj, "%s", new_name);
        if (error)
-               goto out_drop;
-
-       mutex_lock(&sysfs_mutex);
+               goto out_unlock;
 
        dup_name = sd->s_name;
        sd->s_name = new_name;
 
-       /* move under the new parent */
+       /* rename */
        d_add(new_dentry, NULL);
-       d_move(sd->s_dentry, new_dentry);
-
-       sysfs_unlink_sibling(sd);
-       sysfs_get(new_parent_sd);
-       sysfs_put(sd->s_parent);
-       sd->s_parent = new_parent_sd;
-       sysfs_link_sibling(sd);
-
-       mutex_unlock(&sysfs_mutex);
+       d_move(old_dentry, new_dentry);
 
        error = 0;
-       goto out_unlock;
-
- out_drop:
-       d_drop(new_dentry);
  out_unlock:
-       mutex_unlock(&new_parent->d_inode->i_mutex);
- out_dput:
+       mutex_unlock(&sysfs_mutex);
+       mutex_unlock(&parent->d_inode->i_mutex);
        kfree(dup_name);
-       dput(new_parent);
        dput(old_dentry);
        dput(new_dentry);
+ out:
+       mutex_unlock(&sysfs_rename_mutex);
        return error;
 }
 
@@ -985,96 +837,69 @@ int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj)
        struct dentry *old_dentry = NULL, *new_dentry = NULL;
        int error;
 
+       mutex_lock(&sysfs_rename_mutex);
        BUG_ON(!sd->s_parent);
        new_parent_sd = new_parent_kobj->sd ? new_parent_kobj->sd : &sysfs_root;
 
+       error = 0;
+       if (sd->s_parent == new_parent_sd)
+               goto out;       /* nothing to move */
+
        /* get dentries */
        old_dentry = sysfs_get_dentry(sd);
        if (IS_ERR(old_dentry)) {
                error = PTR_ERR(old_dentry);
-               goto out_dput;
+               goto out;
        }
-       old_parent = sd->s_parent->s_dentry;
+       old_parent = old_dentry->d_parent;
 
        new_parent = sysfs_get_dentry(new_parent_sd);
        if (IS_ERR(new_parent)) {
                error = PTR_ERR(new_parent);
-               goto out_dput;
+               goto out;
        }
 
-       if (old_parent->d_inode == new_parent->d_inode) {
-               error = 0;
-               goto out_dput;  /* nothing to move */
-       }
 again:
        mutex_lock(&old_parent->d_inode->i_mutex);
        if (!mutex_trylock(&new_parent->d_inode->i_mutex)) {
                mutex_unlock(&old_parent->d_inode->i_mutex);
                goto again;
        }
+       mutex_lock(&sysfs_mutex);
 
-       new_dentry = lookup_one_len(kobj->name, new_parent, strlen(kobj->name));
-       if (IS_ERR(new_dentry)) {
-               error = PTR_ERR(new_dentry);
+       error = -EEXIST;
+       if (sysfs_find_dirent(new_parent_sd, sd->s_name))
                goto out_unlock;
-       } else
-               error = 0;
+
+       error = -ENOMEM;
+       new_dentry = d_alloc_name(new_parent, sd->s_name);
+       if (!new_dentry)
+               goto out_unlock;
+
+       error = 0;
        d_add(new_dentry, NULL);
-       d_move(sd->s_dentry, new_dentry);
+       d_move(old_dentry, new_dentry);
        dput(new_dentry);
 
        /* Remove from old parent's list and insert into new parent's list. */
-       mutex_lock(&sysfs_mutex);
-
        sysfs_unlink_sibling(sd);
        sysfs_get(new_parent_sd);
        sysfs_put(sd->s_parent);
        sd->s_parent = new_parent_sd;
        sysfs_link_sibling(sd);
 
-       mutex_unlock(&sysfs_mutex);
-
  out_unlock:
+       mutex_unlock(&sysfs_mutex);
        mutex_unlock(&new_parent->d_inode->i_mutex);
        mutex_unlock(&old_parent->d_inode->i_mutex);
- out_dput:
+ out:
        dput(new_parent);
        dput(old_dentry);
        dput(new_dentry);
+       mutex_unlock(&sysfs_rename_mutex);
        return error;
 }
 
-static int sysfs_dir_open(struct inode *inode, struct file *file)
-{
-       struct dentry * dentry = file->f_path.dentry;
-       struct sysfs_dirent * parent_sd = dentry->d_fsdata;
-       struct sysfs_dirent * sd;
-
-       sd = sysfs_new_dirent("_DIR_", 0, 0);
-       if (sd) {
-               mutex_lock(&sysfs_mutex);
-               sd->s_parent = sysfs_get(parent_sd);
-               sysfs_link_sibling(sd);
-               mutex_unlock(&sysfs_mutex);
-       }
-
-       file->private_data = sd;
-       return sd ? 0 : -ENOMEM;
-}
-
-static int sysfs_dir_close(struct inode *inode, struct file *file)
-{
-       struct sysfs_dirent * cursor = file->private_data;
-
-       mutex_lock(&sysfs_mutex);
-       sysfs_unlink_sibling(cursor);
-       mutex_unlock(&sysfs_mutex);
-
-       release_sysfs_dirent(cursor);
-
-       return 0;
-}
-
 /* Relationship between s_mode and the DT_xxx types */
 static inline unsigned char dt_type(struct sysfs_dirent *sd)
 {
@@ -1085,232 +910,51 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
 {
        struct dentry *dentry = filp->f_path.dentry;
        struct sysfs_dirent * parent_sd = dentry->d_fsdata;
-       struct sysfs_dirent *cursor = filp->private_data;
-       struct sysfs_dirent **pos;
+       struct sysfs_dirent *pos;
        ino_t ino;
-       int i = filp->f_pos;
 
-       switch (i) {
-               case 0:
-                       ino = parent_sd->s_ino;
-                       if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
-                               break;
+       if (filp->f_pos == 0) {
+               ino = parent_sd->s_ino;
+               if (filldir(dirent, ".", 1, filp->f_pos, ino, DT_DIR) == 0)
                        filp->f_pos++;
-                       i++;
-                       /* fallthrough */
-               case 1:
-                       if (parent_sd->s_parent)
-                               ino = parent_sd->s_parent->s_ino;
-                       else
-                               ino = parent_sd->s_ino;
-                       if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0)
-                               break;
+       }
+       if (filp->f_pos == 1) {
+               if (parent_sd->s_parent)
+                       ino = parent_sd->s_parent->s_ino;
+               else
+                       ino = parent_sd->s_ino;
+               if (filldir(dirent, "..", 2, filp->f_pos, ino, DT_DIR) == 0)
                        filp->f_pos++;
-                       i++;
-                       /* fallthrough */
-               default:
-                       mutex_lock(&sysfs_mutex);
-
-                       pos = &parent_sd->s_children;
-                       while (*pos != cursor)
-                               pos = &(*pos)->s_sibling;
-
-                       /* unlink cursor */
-                       *pos = cursor->s_sibling;
-
-                       if (filp->f_pos == 2)
-                               pos = &parent_sd->s_children;
-
-                       for ( ; *pos; pos = &(*pos)->s_sibling) {
-                               struct sysfs_dirent *next = *pos;
-                               const char * name;
-                               int len;
-
-                               if (!sysfs_type(next))
-                                       continue;
-
-                               name = next->s_name;
-                               len = strlen(name);
-                               ino = next->s_ino;
-
-                               if (filldir(dirent, name, len, filp->f_pos, ino,
-                                                dt_type(next)) < 0)
-                                       break;
+       }
+       if ((filp->f_pos > 1) && (filp->f_pos < INT_MAX)) {
+               mutex_lock(&sysfs_mutex);
 
-                               filp->f_pos++;
-                       }
+               /* Skip the dentries we have already reported */
+               pos = parent_sd->s_dir.children;
+               while (pos && (filp->f_pos > pos->s_ino))
+                       pos = pos->s_sibling;
 
-                       /* put cursor back in */
-                       cursor->s_sibling = *pos;
-                       *pos = cursor;
+               for ( ; pos; pos = pos->s_sibling) {
+                       const char * name;
+                       int len;
 
-                       mutex_unlock(&sysfs_mutex);
-       }
-       return 0;
-}
-
-static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin)
-{
-       struct dentry * dentry = file->f_path.dentry;
+                       name = pos->s_name;
+                       len = strlen(name);
+                       filp->f_pos = ino = pos->s_ino;
 
-       switch (origin) {
-               case 1:
-                       offset += file->f_pos;
-               case 0:
-                       if (offset >= 0)
+                       if (filldir(dirent, name, len, filp->f_pos, ino,
+                                        dt_type(pos)) < 0)
                                break;
-               default:
-                       return -EINVAL;
-       }
-       if (offset != file->f_pos) {
-               mutex_lock(&sysfs_mutex);
-
-               file->f_pos = offset;
-               if (file->f_pos >= 2) {
-                       struct sysfs_dirent *sd = dentry->d_fsdata;
-                       struct sysfs_dirent *cursor = file->private_data;
-                       struct sysfs_dirent **pos;
-                       loff_t n = file->f_pos - 2;
-
-                       sysfs_unlink_sibling(cursor);
-
-                       pos = &sd->s_children;
-                       while (n && *pos) {
-                               struct sysfs_dirent *next = *pos;
-                               if (sysfs_type(next))
-                                       n--;
-                               pos = &(*pos)->s_sibling;
-                       }
-
-                       cursor->s_sibling = *pos;
-                       *pos = cursor;
                }
-
+               if (!pos)
+                       filp->f_pos = INT_MAX;
                mutex_unlock(&sysfs_mutex);
        }
-
-       return offset;
-}
-
-
-/**
- *     sysfs_make_shadowed_dir - Setup so a directory can be shadowed
- *     @kobj:  object we're creating shadow of.
- */
-
-int sysfs_make_shadowed_dir(struct kobject *kobj,
-       void * (*follow_link)(struct dentry *, struct nameidata *))
-{
-       struct dentry *dentry;
-       struct inode *inode;
-       struct inode_operations *i_op;
-
-       /* get dentry for @kobj->sd, dentry of a shadowed dir is pinned */
-       dentry = sysfs_get_dentry(kobj->sd);
-       if (IS_ERR(dentry))
-               return PTR_ERR(dentry);
-
-       inode = dentry->d_inode;
-       if (inode->i_op != &sysfs_dir_inode_operations) {
-               dput(dentry);
-               return -EINVAL;
-       }
-
-       i_op = kmalloc(sizeof(*i_op), GFP_KERNEL);
-       if (!i_op)
-               return -ENOMEM;
-
-       memcpy(i_op, &sysfs_dir_inode_operations, sizeof(*i_op));
-       i_op->follow_link = follow_link;
-
-       /* Locking of inode->i_op?
-        * Since setting i_op is a single word write and they
-        * are atomic we should be ok here.
-        */
-       inode->i_op = i_op;
        return 0;
 }
 
-/**
- *     sysfs_create_shadow_dir - create a shadow directory for an object.
- *     @kobj:  object we're creating directory for.
- *
- *     sysfs_make_shadowed_dir must already have been called on this
- *     directory.
- */
-
-struct sysfs_dirent *sysfs_create_shadow_dir(struct kobject *kobj)
-{
-       struct sysfs_dirent *parent_sd = kobj->sd->s_parent;
-       struct dentry *dir, *parent, *shadow;
-       struct inode *inode;
-       struct sysfs_dirent *sd;
-       struct sysfs_addrm_cxt acxt;
-
-       dir = sysfs_get_dentry(kobj->sd);
-       if (IS_ERR(dir)) {
-               sd = (void *)dir;
-               goto out;
-       }
-       parent = dir->d_parent;
-
-       inode = dir->d_inode;
-       sd = ERR_PTR(-EINVAL);
-       if (!sysfs_is_shadowed_inode(inode))
-               goto out_dput;
-
-       shadow = d_alloc(parent, &dir->d_name);
-       if (!shadow)
-               goto nomem;
-
-       sd = sysfs_new_dirent("_SHADOW_", inode->i_mode, SYSFS_DIR);
-       if (!sd)
-               goto nomem;
-       sd->s_elem.dir.kobj = kobj;
-
-       sysfs_addrm_start(&acxt, parent_sd);
-
-       /* add but don't link into children list */
-       sysfs_add_one(&acxt, sd);
-
-       /* attach and instantiate dentry */
-       sysfs_attach_dentry(sd, shadow);
-       d_instantiate(shadow, igrab(inode));
-       inc_nlink(inode);       /* tj: synchronization? */
-
-       sysfs_addrm_finish(&acxt);
-
-       dget(shadow);           /* Extra count - pin the dentry in core */
-
-       goto out_dput;
-
- nomem:
-       dput(shadow);
-       sd = ERR_PTR(-ENOMEM);
- out_dput:
-       dput(dir);
- out:
-       return sd;
-}
-
-/**
- *     sysfs_remove_shadow_dir - remove an object's directory.
- *     @shadow_sd: sysfs_dirent of shadow directory
- *
- *     The only thing special about this is that we remove any files in
- *     the directory before we remove the directory, and we've inlined
- *     what used to be sysfs_rmdir() below, instead of calling separately.
- */
-
-void sysfs_remove_shadow_dir(struct sysfs_dirent *shadow_sd)
-{
-       __sysfs_remove_dir(shadow_sd);
-}
 
 const struct file_operations sysfs_dir_operations = {
-       .open           = sysfs_dir_open,
-       .release        = sysfs_dir_close,
-       .llseek         = sysfs_dir_lseek,
        .read           = generic_read_dir,
        .readdir        = sysfs_readdir,
 };
index 3e1cc062a74030687013da9c386476f3a164975f..d3be1e7fb48b6d3ad4ccb7ceccf1b1fbf637767e 100644 (file)
@@ -1,15 +1,22 @@
 /*
- * file.c - operations for regular (text) files.
+ * fs/sysfs/file.c - sysfs regular (text) file implementation
+ *
+ * Copyright (c) 2001-3 Patrick Mochel
+ * Copyright (c) 2007 SUSE Linux Products GmbH
+ * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
+ *
+ * This file is released under the GPLv2.
+ *
+ * Please see Documentation/filesystems/sysfs.txt for more information.
  */
 
 #include <linux/module.h>
-#include <linux/fsnotify.h>
 #include <linux/kobject.h>
 #include <linux/namei.h>
 #include <linux/poll.h>
 #include <linux/list.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
-#include <asm/semaphore.h>
 
 #include "sysfs.h"
 
@@ -50,14 +57,33 @@ static struct sysfs_ops subsys_sysfs_ops = {
        .store  = subsys_attr_store,
 };
 
+/*
+ * There's one sysfs_buffer for each open file and one
+ * sysfs_open_dirent for each sysfs_dirent with one or more open
+ * files.
+ *
+ * filp->private_data points to sysfs_buffer and
+ * sysfs_dirent->s_attr.open points to sysfs_open_dirent.  s_attr.open
+ * is protected by sysfs_open_dirent_lock.
+ */
+static spinlock_t sysfs_open_dirent_lock = SPIN_LOCK_UNLOCKED;
+
+struct sysfs_open_dirent {
+       atomic_t                refcnt;
+       atomic_t                event;
+       wait_queue_head_t       poll;
+       struct list_head        buffers; /* goes through sysfs_buffer.list */
+};
+
 struct sysfs_buffer {
        size_t                  count;
        loff_t                  pos;
        char                    * page;
        struct sysfs_ops        * ops;
-       struct semaphore        sem;
+       struct mutex            mutex;
        int                     needs_read_fill;
        int                     event;
+       struct list_head        list;
 };
 
 /**
@@ -74,7 +100,7 @@ struct sysfs_buffer {
 static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer)
 {
        struct sysfs_dirent *attr_sd = dentry->d_fsdata;
-       struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
+       struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
        struct sysfs_ops * ops = buffer->ops;
        int ret = 0;
        ssize_t count;
@@ -88,8 +114,8 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer
        if (!sysfs_get_active_two(attr_sd))
                return -ENODEV;
 
-       buffer->event = atomic_read(&attr_sd->s_event);
-       count = ops->show(kobj, attr_sd->s_elem.attr.attr, buffer->page);
+       buffer->event = atomic_read(&attr_sd->s_attr.open->event);
+       count = ops->show(kobj, attr_sd->s_attr.attr, buffer->page);
 
        sysfs_put_active_two(attr_sd);
 
@@ -128,7 +154,7 @@ sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos)
        struct sysfs_buffer * buffer = file->private_data;
        ssize_t retval = 0;
 
-       down(&buffer->sem);
+       mutex_lock(&buffer->mutex);
        if (buffer->needs_read_fill) {
                retval = fill_read_buffer(file->f_path.dentry,buffer);
                if (retval)
@@ -139,7 +165,7 @@ sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos)
        retval = simple_read_from_buffer(buf, count, ppos, buffer->page,
                                         buffer->count);
 out:
-       up(&buffer->sem);
+       mutex_unlock(&buffer->mutex);
        return retval;
 }
 
@@ -189,7 +215,7 @@ static int
 flush_write_buffer(struct dentry * dentry, struct sysfs_buffer * buffer, size_t count)
 {
        struct sysfs_dirent *attr_sd = dentry->d_fsdata;
-       struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
+       struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
        struct sysfs_ops * ops = buffer->ops;
        int rc;
 
@@ -197,7 +223,7 @@ flush_write_buffer(struct dentry * dentry, struct sysfs_buffer * buffer, size_t
        if (!sysfs_get_active_two(attr_sd))
                return -ENODEV;
 
-       rc = ops->store(kobj, attr_sd->s_elem.attr.attr, buffer->page, count);
+       rc = ops->store(kobj, attr_sd->s_attr.attr, buffer->page, count);
 
        sysfs_put_active_two(attr_sd);
 
@@ -228,20 +254,102 @@ sysfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t
        struct sysfs_buffer * buffer = file->private_data;
        ssize_t len;
 
-       down(&buffer->sem);
+       mutex_lock(&buffer->mutex);
        len = fill_write_buffer(buffer, buf, count);
        if (len > 0)
                len = flush_write_buffer(file->f_path.dentry, buffer, len);
        if (len > 0)
                *ppos += len;
-       up(&buffer->sem);
+       mutex_unlock(&buffer->mutex);
        return len;
 }
 
+/**
+ *     sysfs_get_open_dirent - get or create sysfs_open_dirent
+ *     @sd: target sysfs_dirent
+ *     @buffer: sysfs_buffer for this instance of open
+ *
+ *     If @sd->s_attr.open exists, increment its reference count;
+ *     otherwise, create one.  @buffer is chained to the buffers
+ *     list.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep).
+ *
+ *     RETURNS:
+ *     0 on success, -errno on failure.
+ */
+static int sysfs_get_open_dirent(struct sysfs_dirent *sd,
+                                struct sysfs_buffer *buffer)
+{
+       struct sysfs_open_dirent *od, *new_od = NULL;
+
+ retry:
+       spin_lock(&sysfs_open_dirent_lock);
+
+       if (!sd->s_attr.open && new_od) {
+               sd->s_attr.open = new_od;
+               new_od = NULL;
+       }
+
+       od = sd->s_attr.open;
+       if (od) {
+               atomic_inc(&od->refcnt);
+               list_add_tail(&buffer->list, &od->buffers);
+       }
+
+       spin_unlock(&sysfs_open_dirent_lock);
+
+       if (od) {
+               kfree(new_od);
+               return 0;
+       }
+
+       /* not there, initialize a new one and retry */
+       new_od = kmalloc(sizeof(*new_od), GFP_KERNEL);
+       if (!new_od)
+               return -ENOMEM;
+
+       atomic_set(&new_od->refcnt, 0);
+       atomic_set(&new_od->event, 1);
+       init_waitqueue_head(&new_od->poll);
+       INIT_LIST_HEAD(&new_od->buffers);
+       goto retry;
+}
+
+/**
+ *     sysfs_put_open_dirent - put sysfs_open_dirent
+ *     @sd: target sysfs_dirent
+ *     @buffer: associated sysfs_buffer
+ *
+ *     Put @sd->s_attr.open and unlink @buffer from the buffers list.
+ *     If reference count reaches zero, disassociate and free it.
+ *
+ *     LOCKING:
+ *     None.
+ */
+static void sysfs_put_open_dirent(struct sysfs_dirent *sd,
+                                 struct sysfs_buffer *buffer)
+{
+       struct sysfs_open_dirent *od = sd->s_attr.open;
+
+       spin_lock(&sysfs_open_dirent_lock);
+
+       list_del(&buffer->list);
+       if (atomic_dec_and_test(&od->refcnt))
+               sd->s_attr.open = NULL;
+       else
+               od = NULL;
+
+       spin_unlock(&sysfs_open_dirent_lock);
+
+       kfree(od);
+}
+
 static int sysfs_open_file(struct inode *inode, struct file *file)
 {
        struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
-       struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
+       struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
        struct sysfs_buffer * buffer;
        struct sysfs_ops * ops = NULL;
        int error;
@@ -294,33 +402,38 @@ static int sysfs_open_file(struct inode *inode, struct file *file)
        if (!buffer)
                goto err_out;
 
-       init_MUTEX(&buffer->sem);
+       mutex_init(&buffer->mutex);
        buffer->needs_read_fill = 1;
        buffer->ops = ops;
        file->private_data = buffer;
 
-       /* open succeeded, put active references and pin attr_sd */
+       /* make sure we have open dirent struct */
+       error = sysfs_get_open_dirent(attr_sd, buffer);
+       if (error)
+               goto err_free;
+
+       /* open succeeded, put active references */
        sysfs_put_active_two(attr_sd);
-       sysfs_get(attr_sd);
        return 0;
 
+ err_free:
+       kfree(buffer);
  err_out:
        sysfs_put_active_two(attr_sd);
        return error;
 }
 
-static int sysfs_release(struct inode * inode, struct file * filp)
+static int sysfs_release(struct inode *inode, struct file *filp)
 {
-       struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata;
+       struct sysfs_dirent *sd = filp->f_path.dentry->d_fsdata;
        struct sysfs_buffer *buffer = filp->private_data;
 
-       sysfs_put(attr_sd);
+       sysfs_put_open_dirent(sd, buffer);
+
+       if (buffer->page)
+               free_page((unsigned long)buffer->page);
+       kfree(buffer);
 
-       if (buffer) {
-               if (buffer->page)
-                       free_page((unsigned long)buffer->page);
-               kfree(buffer);
-       }
        return 0;
 }
 
@@ -335,24 +448,24 @@ static int sysfs_release(struct inode * inode, struct file * filp)
  * again will not get new data, or reset the state of 'poll'.
  * Reminder: this only works for attributes which actively support
  * it, and it is not possible to test an attribute from userspace
- * to see if it supports poll (Nether 'poll' or 'select' return
+ * to see if it supports poll (Neither 'poll' nor 'select' return
  * an appropriate error code).  When in doubt, set a suitable timeout value.
  */
 static unsigned int sysfs_poll(struct file *filp, poll_table *wait)
 {
        struct sysfs_buffer * buffer = filp->private_data;
        struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata;
-       struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
+       struct sysfs_open_dirent *od = attr_sd->s_attr.open;
 
        /* need parent for the kobj, grab both */
        if (!sysfs_get_active_two(attr_sd))
                goto trigger;
 
-       poll_wait(filp, &kobj->poll, wait);
+       poll_wait(filp, &od->poll, wait);
 
        sysfs_put_active_two(attr_sd);
 
-       if (buffer->event != atomic_read(&attr_sd->s_event))
+       if (buffer->event != atomic_read(&od->event))
                goto trigger;
 
        return 0;
@@ -373,8 +486,17 @@ void sysfs_notify(struct kobject *k, char *dir, char *attr)
        if (sd && attr)
                sd = sysfs_find_dirent(sd, attr);
        if (sd) {
-               atomic_inc(&sd->s_event);
-               wake_up_interruptible(&k->poll);
+               struct sysfs_open_dirent *od;
+
+               spin_lock(&sysfs_open_dirent_lock);
+
+               od = sd->s_attr.open;
+               if (od) {
+                       atomic_inc(&od->event);
+                       wake_up_interruptible(&od->poll);
+               }
+
+               spin_unlock(&sysfs_open_dirent_lock);
        }
 
        mutex_unlock(&sysfs_mutex);
@@ -397,25 +519,21 @@ int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,
        umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG;
        struct sysfs_addrm_cxt acxt;
        struct sysfs_dirent *sd;
+       int rc;
 
        sd = sysfs_new_dirent(attr->name, mode, type);
        if (!sd)
                return -ENOMEM;
-       sd->s_elem.attr.attr = (void *)attr;
+       sd->s_attr.attr = (void *)attr;
 
        sysfs_addrm_start(&acxt, dir_sd);
+       rc = sysfs_add_one(&acxt, sd);
+       sysfs_addrm_finish(&acxt);
 
-       if (!sysfs_find_dirent(dir_sd, attr->name)) {
-               sysfs_add_one(&acxt, sd);
-               sysfs_link_sibling(sd);
-       }
-
-       if (!sysfs_addrm_finish(&acxt)) {
+       if (rc)
                sysfs_put(sd);
-               return -EEXIST;
-       }
 
-       return 0;
+       return rc;
 }
 
 
@@ -457,42 +575,6 @@ int sysfs_add_file_to_group(struct kobject *kobj,
 }
 EXPORT_SYMBOL_GPL(sysfs_add_file_to_group);
 
-
-/**
- * sysfs_update_file - update the modified timestamp on an object attribute.
- * @kobj: object we're acting for.
- * @attr: attribute descriptor.
- */
-int sysfs_update_file(struct kobject * kobj, const struct attribute * attr)
-{
-       struct sysfs_dirent *victim_sd = NULL;
-       struct dentry *victim = NULL;
-       int rc;
-
-       rc = -ENOENT;
-       victim_sd = sysfs_get_dirent(kobj->sd, attr->name);
-       if (!victim_sd)
-               goto out;
-
-       victim = sysfs_get_dentry(victim_sd);
-       if (IS_ERR(victim)) {
-               rc = PTR_ERR(victim);
-               victim = NULL;
-               goto out;
-       }
-
-       mutex_lock(&victim->d_inode->i_mutex);
-       victim->d_inode->i_mtime = CURRENT_TIME;
-       fsnotify_modify(victim);
-       mutex_unlock(&victim->d_inode->i_mutex);
-       rc = 0;
- out:
-       dput(victim);
-       sysfs_put(victim_sd);
-       return rc;
-}
-
-
 /**
  * sysfs_chmod_file - update the modified mode value on an object attribute.
  * @kobj: object we're acting for.
@@ -513,7 +595,9 @@ int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode)
        if (!victim_sd)
                goto out;
 
+       mutex_lock(&sysfs_rename_mutex);
        victim = sysfs_get_dentry(victim_sd);
+       mutex_unlock(&sysfs_rename_mutex);
        if (IS_ERR(victim)) {
                rc = PTR_ERR(victim);
                victim = NULL;
@@ -521,10 +605,19 @@ int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode)
        }
 
        inode = victim->d_inode;
+
        mutex_lock(&inode->i_mutex);
+
        newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
        newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
        rc = notify_change(victim, &newattrs);
+
+       if (rc == 0) {
+               mutex_lock(&sysfs_mutex);
+               victim_sd->s_mode = newattrs.ia_mode;
+               mutex_unlock(&sysfs_mutex);
+       }
+
        mutex_unlock(&inode->i_mutex);
  out:
        dput(victim);
@@ -632,4 +725,3 @@ EXPORT_SYMBOL_GPL(sysfs_schedule_callback);
 
 EXPORT_SYMBOL_GPL(sysfs_create_file);
 EXPORT_SYMBOL_GPL(sysfs_remove_file);
-EXPORT_SYMBOL_GPL(sysfs_update_file);
index f318b73c790c8d2b058bd68ac6646b2adb550802..d1972374655a22377e94186b62564aaa83f2299f 100644 (file)
@@ -13,8 +13,6 @@
 #include <linux/dcache.h>
 #include <linux/namei.h>
 #include <linux/err.h>
-#include <linux/fs.h>
-#include <asm/semaphore.h>
 #include "sysfs.h"
 
 
index 10d1b52899f111a880ae858b3c9ef7833f915890..9236635111f4cc3629e3614c9e741a59a117abe6 100644 (file)
@@ -1,7 +1,11 @@
 /*
- * inode.c - basic inode and dentry operations.
+ * fs/sysfs/inode.c - basic sysfs inode and dentry operations
  *
- * sysfs is Copyright (c) 2001-3 Patrick Mochel
+ * Copyright (c) 2001-3 Patrick Mochel
+ * Copyright (c) 2007 SUSE Linux Products GmbH
+ * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
+ *
+ * This file is released under the GPLv2.
  *
  * Please see Documentation/filesystems/sysfs.txt for more information.
  */
@@ -14,7 +18,6 @@
 #include <linux/capability.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
-#include <asm/semaphore.h>
 #include "sysfs.h"
 
 extern struct super_block * sysfs_sb;
@@ -34,16 +37,6 @@ static const struct inode_operations sysfs_inode_operations ={
        .setattr        = sysfs_setattr,
 };
 
-void sysfs_delete_inode(struct inode *inode)
-{
-       /* Free the shadowed directory inode operations */
-       if (sysfs_is_shadowed_inode(inode)) {
-               kfree(inode->i_op);
-               inode->i_op = NULL;
-       }
-       return generic_delete_inode(inode);
-}
-
 int sysfs_setattr(struct dentry * dentry, struct iattr * iattr)
 {
        struct inode * inode = dentry->d_inode;
@@ -133,8 +126,22 @@ static inline void set_inode_attr(struct inode * inode, struct iattr * iattr)
  */
 static struct lock_class_key sysfs_inode_imutex_key;
 
+static int sysfs_count_nlink(struct sysfs_dirent *sd)
+{
+       struct sysfs_dirent *child;
+       int nr = 0;
+
+       for (child = sd->s_dir.children; child; child = child->s_sibling)
+               if (sysfs_type(child) == SYSFS_DIR)
+                       nr++;
+
+       return nr + 2;
+}
+
 static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
 {
+       struct bin_attribute *bin_attr;
+
        inode->i_blocks = 0;
        inode->i_mapping->a_ops = &sysfs_aops;
        inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info;
@@ -150,6 +157,32 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
                set_inode_attr(inode, sd->s_iattr);
        } else
                set_default_inode_attr(inode, sd->s_mode);
+
+
+       /* initialize inode according to type */
+       switch (sysfs_type(sd)) {
+       case SYSFS_DIR:
+               inode->i_op = &sysfs_dir_inode_operations;
+               inode->i_fop = &sysfs_dir_operations;
+               inode->i_nlink = sysfs_count_nlink(sd);
+               break;
+       case SYSFS_KOBJ_ATTR:
+               inode->i_size = PAGE_SIZE;
+               inode->i_fop = &sysfs_file_operations;
+               break;
+       case SYSFS_KOBJ_BIN_ATTR:
+               bin_attr = sd->s_bin_attr.bin_attr;
+               inode->i_size = bin_attr->size;
+               inode->i_fop = &bin_fops;
+               break;
+       case SYSFS_KOBJ_LINK:
+               inode->i_op = &sysfs_symlink_inode_operations;
+               break;
+       default:
+               BUG();
+       }
+
+       unlock_new_inode(inode);
 }
 
 /**
@@ -177,50 +210,24 @@ struct inode * sysfs_get_inode(struct sysfs_dirent *sd)
        return inode;
 }
 
-/**
- *     sysfs_instantiate - instantiate dentry
- *     @dentry: dentry to be instantiated
- *     @inode: inode associated with @sd
- *
- *     Unlock @inode if locked and instantiate @dentry with @inode.
- *
- *     LOCKING:
- *     None.
- */
-void sysfs_instantiate(struct dentry *dentry, struct inode *inode)
-{
-       BUG_ON(!dentry || dentry->d_inode);
-
-       if (inode->i_state & I_NEW)
-               unlock_new_inode(inode);
-
-       d_instantiate(dentry, inode);
-}
-
 int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name)
 {
        struct sysfs_addrm_cxt acxt;
-       struct sysfs_dirent **pos, *sd;
+       struct sysfs_dirent *sd;
 
        if (!dir_sd)
                return -ENOENT;
 
        sysfs_addrm_start(&acxt, dir_sd);
 
-       for (pos = &dir_sd->s_children; *pos; pos = &(*pos)->s_sibling) {
-               sd = *pos;
-
-               if (!sysfs_type(sd))
-                       continue;
-               if (!strcmp(sd->s_name, name)) {
-                       *pos = sd->s_sibling;
-                       sd->s_sibling = NULL;
-                       sysfs_remove_one(&acxt, sd);
-                       break;
-               }
-       }
+       sd = sysfs_find_dirent(dir_sd, name);
+       if (sd)
+               sysfs_remove_one(&acxt, sd);
+
+       sysfs_addrm_finish(&acxt);
 
-       if (sysfs_addrm_finish(&acxt))
+       if (sd)
                return 0;
-       return -ENOENT;
+       else
+               return -ENOENT;
 }
index fbc7b65fe26267d776a105f5d37f01627edf44a2..c76c540be3c830c57707d23a95cac5f8b83323a5 100644 (file)
@@ -1,5 +1,13 @@
 /*
- * mount.c - operations for initializing and mounting sysfs.
+ * fs/sysfs/symlink.c - operations for initializing and mounting sysfs
+ *
+ * Copyright (c) 2001-3 Patrick Mochel
+ * Copyright (c) 2007 SUSE Linux Products GmbH
+ * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
+ *
+ * This file is released under the GPLv2.
+ *
+ * Please see Documentation/filesystems/sysfs.txt for more information.
  */
 
 #define DEBUG 
 #include <linux/mount.h>
 #include <linux/pagemap.h>
 #include <linux/init.h>
-#include <asm/semaphore.h>
 
 #include "sysfs.h"
 
 /* Random magic number */
 #define SYSFS_MAGIC 0x62656572
 
-struct vfsmount *sysfs_mount;
+static struct vfsmount *sysfs_mount;
 struct super_block * sysfs_sb = NULL;
 struct kmem_cache *sysfs_dir_cachep;
 
 static const struct super_operations sysfs_ops = {
        .statfs         = simple_statfs,
-       .drop_inode     = sysfs_delete_inode,
+       .drop_inode     = generic_delete_inode,
 };
 
 struct sysfs_dirent sysfs_root = {
+       .s_name         = "",
        .s_count        = ATOMIC_INIT(1),
-       .s_flags        = SYSFS_ROOT,
+       .s_flags        = SYSFS_DIR,
        .s_mode         = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
        .s_ino          = 1,
 };
@@ -50,11 +58,6 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
                return -ENOMEM;
        }
 
-       inode->i_op = &sysfs_dir_inode_operations;
-       inode->i_fop = &sysfs_dir_operations;
-       inc_nlink(inode); /* directory, account for "." */
-       unlock_new_inode(inode);
-
        /* instantiate and link root dentry */
        root = d_alloc_root(inode);
        if (!root) {
@@ -62,7 +65,6 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
                iput(inode);
                return -ENOMEM;
        }
-       sysfs_root.s_dentry = root;
        root->d_fsdata = &sysfs_root;
        sb->s_root = root;
        return 0;
@@ -77,7 +79,7 @@ static int sysfs_get_sb(struct file_system_type *fs_type,
 static struct file_system_type sysfs_fs_type = {
        .name           = "sysfs",
        .get_sb         = sysfs_get_sb,
-       .kill_sb        = kill_litter_super,
+       .kill_sb        = kill_anon_super,
 };
 
 int __init sysfs_init(void)
index 4ce687f0b5d01751dfb8f8aa189c84360eaab39e..3eac20c63c419d45cc666a53251be208ebf1296a 100644 (file)
@@ -1,5 +1,13 @@
 /*
- * symlink.c - operations for sysfs symlinks.
+ * fs/sysfs/symlink.c - sysfs symlink implementation
+ *
+ * Copyright (c) 2001-3 Patrick Mochel
+ * Copyright (c) 2007 SUSE Linux Products GmbH
+ * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
+ *
+ * This file is released under the GPLv2.
+ *
+ * Please see Documentation/filesystems/sysfs.txt for more information.
  */
 
 #include <linux/fs.h>
@@ -7,7 +15,7 @@
 #include <linux/module.h>
 #include <linux/kobject.h>
 #include <linux/namei.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 #include "sysfs.h"
 
@@ -60,10 +68,9 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char
 
        BUG_ON(!name);
 
-       if (!kobj) {
-               if (sysfs_mount && sysfs_mount->mnt_sb)
-                       parent_sd = sysfs_mount->mnt_sb->s_root->d_fsdata;
-       } else
+       if (!kobj)
+               parent_sd = &sysfs_root;
+       else
                parent_sd = kobj->sd;
 
        error = -EFAULT;
@@ -87,20 +94,15 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char
        if (!sd)
                goto out_put;
 
-       sd->s_elem.symlink.target_sd = target_sd;
+       sd->s_symlink.target_sd = target_sd;
        target_sd = NULL;       /* reference is now owned by the symlink */
 
        sysfs_addrm_start(&acxt, parent_sd);
+       error = sysfs_add_one(&acxt, sd);
+       sysfs_addrm_finish(&acxt);
 
-       if (!sysfs_find_dirent(parent_sd, name)) {
-               sysfs_add_one(&acxt, sd);
-               sysfs_link_sibling(sd);
-       }
-
-       if (!sysfs_addrm_finish(&acxt)) {
-               error = -EEXIST;
+       if (error)
                goto out_put;
-       }
 
        return 0;
 
@@ -148,7 +150,7 @@ static int sysfs_getlink(struct dentry *dentry, char * path)
 {
        struct sysfs_dirent *sd = dentry->d_fsdata;
        struct sysfs_dirent *parent_sd = sd->s_parent;
-       struct sysfs_dirent *target_sd = sd->s_elem.symlink.target_sd;
+       struct sysfs_dirent *target_sd = sd->s_symlink.target_sd;
        int error;
 
        mutex_lock(&sysfs_mutex);
index 6b8c8d76d308c46b63598b5a6a9f0eb925429b12..f0326f281d1cdbbe228fce7146cd4d9bef3e9fe1 100644 (file)
@@ -1,20 +1,39 @@
+/*
+ * fs/sysfs/sysfs.h - sysfs internal header file
+ *
+ * Copyright (c) 2001-3 Patrick Mochel
+ * Copyright (c) 2007 SUSE Linux Products GmbH
+ * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
+ *
+ * This file is released under the GPLv2.
+ */
+
+struct sysfs_open_dirent;
+
+/* type-specific structures for sysfs_dirent->s_* union members */
 struct sysfs_elem_dir {
-       struct kobject          * kobj;
+       struct kobject          *kobj;
+       /* children list starts here and goes through sd->s_sibling */
+       struct sysfs_dirent     *children;
 };
 
 struct sysfs_elem_symlink {
-       struct sysfs_dirent     * target_sd;
+       struct sysfs_dirent     *target_sd;
 };
 
 struct sysfs_elem_attr {
-       struct attribute        * attr;
+       struct attribute        *attr;
+       struct sysfs_open_dirent *open;
 };
 
 struct sysfs_elem_bin_attr {
-       struct bin_attribute    * bin_attr;
+       struct bin_attribute    *bin_attr;
 };
 
 /*
+ * sysfs_dirent - the building block of sysfs hierarchy.  Each and
+ * every sysfs node is represented by single sysfs_dirent.
+ *
  * As long as s_count reference is held, the sysfs_dirent itself is
  * accessible.  Dereferencing s_elem or any other outer entity
  * requires s_active reference.
@@ -22,28 +41,43 @@ struct sysfs_elem_bin_attr {
 struct sysfs_dirent {
        atomic_t                s_count;
        atomic_t                s_active;
-       struct sysfs_dirent     * s_parent;
-       struct sysfs_dirent     * s_sibling;
-       struct sysfs_dirent     * s_children;
-       const char              * s_name;
+       struct sysfs_dirent     *s_parent;
+       struct sysfs_dirent     *s_sibling;
+       const char              *s_name;
 
        union {
-               struct sysfs_elem_dir           dir;
-               struct sysfs_elem_symlink       symlink;
-               struct sysfs_elem_attr          attr;
-               struct sysfs_elem_bin_attr      bin_attr;
-       }                       s_elem;
+               struct sysfs_elem_dir           s_dir;
+               struct sysfs_elem_symlink       s_symlink;
+               struct sysfs_elem_attr          s_attr;
+               struct sysfs_elem_bin_attr      s_bin_attr;
+       };
 
        unsigned int            s_flags;
-       umode_t                 s_mode;
        ino_t                   s_ino;
-       struct dentry           * s_dentry;
-       struct iattr            * s_iattr;
-       atomic_t                s_event;
+       umode_t                 s_mode;
+       struct iattr            *s_iattr;
 };
 
-#define SD_DEACTIVATED_BIAS    INT_MIN
+#define SD_DEACTIVATED_BIAS            INT_MIN
+
+#define SYSFS_TYPE_MASK                        0x00ff
+#define SYSFS_DIR                      0x0001
+#define SYSFS_KOBJ_ATTR                        0x0002
+#define SYSFS_KOBJ_BIN_ATTR            0x0004
+#define SYSFS_KOBJ_LINK                        0x0008
+#define SYSFS_COPY_NAME                        (SYSFS_DIR | SYSFS_KOBJ_LINK)
+
+#define SYSFS_FLAG_MASK                        ~SYSFS_TYPE_MASK
+#define SYSFS_FLAG_REMOVED             0x0200
+
+static inline unsigned int sysfs_type(struct sysfs_dirent *sd)
+{
+       return sd->s_flags & SYSFS_TYPE_MASK;
+}
 
+/*
+ * Context structure to be used while adding/removing nodes.
+ */
 struct sysfs_addrm_cxt {
        struct sysfs_dirent     *parent_sd;
        struct inode            *parent_inode;
@@ -51,63 +85,47 @@ struct sysfs_addrm_cxt {
        int                     cnt;
 };
 
-extern struct vfsmount * sysfs_mount;
+/*
+ * mount.c
+ */
 extern struct sysfs_dirent sysfs_root;
+extern struct super_block *sysfs_sb;
 extern struct kmem_cache *sysfs_dir_cachep;
 
-extern struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd);
-extern void sysfs_link_sibling(struct sysfs_dirent *sd);
-extern void sysfs_unlink_sibling(struct sysfs_dirent *sd);
-extern struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd);
-extern void sysfs_put_active(struct sysfs_dirent *sd);
-extern struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd);
-extern void sysfs_put_active_two(struct sysfs_dirent *sd);
-extern void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt,
-                             struct sysfs_dirent *parent_sd);
-extern void sysfs_add_one(struct sysfs_addrm_cxt *acxt,
-                         struct sysfs_dirent *sd);
-extern void sysfs_remove_one(struct sysfs_addrm_cxt *acxt,
-                            struct sysfs_dirent *sd);
-extern int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt);
-
-extern void sysfs_delete_inode(struct inode *inode);
-extern struct inode * sysfs_get_inode(struct sysfs_dirent *sd);
-extern void sysfs_instantiate(struct dentry *dentry, struct inode *inode);
-
-extern void release_sysfs_dirent(struct sysfs_dirent * sd);
-extern struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
-                                             const unsigned char *name);
-extern struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd,
-                                            const unsigned char *name);
-extern struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode,
-                                            int type);
-
-extern int sysfs_add_file(struct sysfs_dirent *dir_sd,
-                         const struct attribute *attr, int type);
-extern int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name);
-extern struct sysfs_dirent *sysfs_find(struct sysfs_dirent *dir, const char * name);
-
-extern int sysfs_create_subdir(struct kobject *kobj, const char *name,
-                              struct sysfs_dirent **p_sd);
-extern void sysfs_remove_subdir(struct sysfs_dirent *sd);
-
-extern int sysfs_setattr(struct dentry *dentry, struct iattr *iattr);
-
-extern spinlock_t sysfs_assoc_lock;
+/*
+ * dir.c
+ */
 extern struct mutex sysfs_mutex;
-extern struct super_block * sysfs_sb;
+extern struct mutex sysfs_rename_mutex;
+extern spinlock_t sysfs_assoc_lock;
+
 extern const struct file_operations sysfs_dir_operations;
-extern const struct file_operations sysfs_file_operations;
-extern const struct file_operations bin_fops;
 extern const struct inode_operations sysfs_dir_inode_operations;
-extern const struct inode_operations sysfs_symlink_inode_operations;
-
-static inline unsigned int sysfs_type(struct sysfs_dirent *sd)
-{
-       return sd->s_flags & SYSFS_TYPE_MASK;
-}
 
-static inline struct sysfs_dirent * sysfs_get(struct sysfs_dirent * sd)
+struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd);
+struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd);
+void sysfs_put_active(struct sysfs_dirent *sd);
+struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd);
+void sysfs_put_active_two(struct sysfs_dirent *sd);
+void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt,
+                      struct sysfs_dirent *parent_sd);
+int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd);
+void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd);
+void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt);
+
+struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
+                                      const unsigned char *name);
+struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd,
+                                     const unsigned char *name);
+struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type);
+
+void release_sysfs_dirent(struct sysfs_dirent *sd);
+
+int sysfs_create_subdir(struct kobject *kobj, const char *name,
+                       struct sysfs_dirent **p_sd);
+void sysfs_remove_subdir(struct sysfs_dirent *sd);
+
+static inline struct sysfs_dirent *sysfs_get(struct sysfs_dirent *sd)
 {
        if (sd) {
                WARN_ON(!atomic_read(&sd->s_count));
@@ -116,13 +134,33 @@ static inline struct sysfs_dirent * sysfs_get(struct sysfs_dirent * sd)
        return sd;
 }
 
-static inline void sysfs_put(struct sysfs_dirent * sd)
+static inline void sysfs_put(struct sysfs_dirent *sd)
 {
        if (sd && atomic_dec_and_test(&sd->s_count))
                release_sysfs_dirent(sd);
 }
 
-static inline int sysfs_is_shadowed_inode(struct inode *inode)
-{
-       return S_ISDIR(inode->i_mode) && inode->i_op->follow_link;
-}
+/*
+ * inode.c
+ */
+struct inode *sysfs_get_inode(struct sysfs_dirent *sd);
+int sysfs_setattr(struct dentry *dentry, struct iattr *iattr);
+int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name);
+
+/*
+ * file.c
+ */
+extern const struct file_operations sysfs_file_operations;
+
+int sysfs_add_file(struct sysfs_dirent *dir_sd,
+                  const struct attribute *attr, int type);
+
+/*
+ * bin.c
+ */
+extern const struct file_operations bin_fops;
+
+/*
+ * symlink.c
+ */
+extern const struct inode_operations sysfs_symlink_inode_operations;
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 62fb3618293d63ed50c076e51f4b8c2998583727..cf14f2ff40b6677edb7caa9da645530ed9f47281 100644 (file)
@@ -1,12 +1,7 @@
 #ifndef __ASM_GENERIC_LIBATA_PORTMAP_H
 #define __ASM_GENERIC_LIBATA_PORTMAP_H
 
-#define ATA_PRIMARY_CMD                0x1F0
-#define ATA_PRIMARY_CTL                0x3F6
 #define ATA_PRIMARY_IRQ(dev)   14
-
-#define ATA_SECONDARY_CMD      0x170
-#define ATA_SECONDARY_CTL      0x376
 #define ATA_SECONDARY_IRQ(dev) 15
 
 #endif
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 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);
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 ec2a8a2c737c81d09b0d9c7fd3f34623669e0169..93262f2546adc2d511925dce83290e870e35887d 100644 (file)
@@ -20,7 +20,7 @@ struct of_device
 extern ssize_t of_device_get_modalias(struct of_device *ofdev,
                                        char *str, ssize_t len);
 extern int of_device_uevent(struct device *dev,
-       char **envp, int num_envp, char *buffer, int buffer_size);
+                           struct kobj_uevent_env *env);
 
 /* This is just here during the transition */
 #include <linux/of_device.h>
index cdf431b061bbc5eb57cb1807f11cda8ffc888867..9b866816863c89a76069d1d3b9f857067a1aa27f 100644 (file)
@@ -14,8 +14,6 @@
 #define L1_CACHE_BYTES     256
 #define L1_CACHE_SHIFT     8
 
-#define ARCH_KMALLOC_MINALIGN  8
-
 #define __read_mostly __attribute__((__section__(".data.read_mostly")))
 
 #endif
index 1aeda27d5a8bb33e9aae6408391d387b7614699b..066aa70518ce0b0c94e4d0380abd9940c520c02f 100644 (file)
@@ -67,36 +67,55 @@ ccw_device_id_match(const struct ccw_device_id *array,
        return NULL;
 }
 
-/* The struct ccw device is our replacement for the globally accessible
- * ioinfo array. ioinfo will mutate into a subchannel device later.
+/**
+ * struct ccw_device - channel attached device
+ * @ccwlock: pointer to device lock
+ * @id: id of this device
+ * @drv: ccw driver for this device
+ * @dev: embedded device structure
+ * @online: online status of device
+ * @handler: interrupt handler
  *
- * Reference: Documentation/s390/driver-model.txt */
+ * @handler is a member of the device rather than the driver since a driver
+ * can have different interrupt handlers for different ccw devices
+ * (multi-subchannel drivers).
+ */
 struct ccw_device {
        spinlock_t *ccwlock;
+/* private: */
        struct ccw_device_private *private;     /* cio private information */
-       struct ccw_device_id id;        /* id of this device, driver_info is
-                                          set by ccw_find_driver */
-       struct ccw_driver *drv;         /* */
-       struct device dev;              /* */
+/* public: */
+       struct ccw_device_id id;
+       struct ccw_driver *drv;
+       struct device dev;
        int online;
-       /* This is sick, but a driver can have different interrupt handlers 
-          for different ccw_devices (multi-subchannel drivers)... */
        void (*handler) (struct ccw_device *, unsigned long, struct irb *);
 };
 
 
-/* Each ccw driver registers with the ccw root bus */
+/**
+ * struct ccw driver - device driver for channel attached devices
+ * @owner: owning module
+ * @ids: ids supported by this driver
+ * @probe: function called on probe
+ * @remove: function called on remove
+ * @set_online: called when setting device online
+ * @set_offline: called when setting device offline
+ * @notify: notify driver of device state changes
+ * @shutdown: called at device shutdown
+ * @driver: embedded device driver structure
+ * @name: device driver name
+ */
 struct ccw_driver {
-       struct module *owner;           /* for automatic MOD_INC_USE_COUNT   */
-       struct ccw_device_id *ids;      /* probe driver with these devs      */
-       int (*probe) (struct ccw_device *); /* ask driver to probe dev       */
+       struct module *owner;
+       struct ccw_device_id *ids;
+       int (*probe) (struct ccw_device *);
        void (*remove) (struct ccw_device *);
-                                       /* device is no longer available     */
        int (*set_online) (struct ccw_device *);
        int (*set_offline) (struct ccw_device *);
        int (*notify) (struct ccw_device *, int);
-       struct device_driver driver;    /* higher level structure, don't init
-                                          this from your driver             */
+       void (*shutdown) (struct ccw_device *);
+       struct device_driver driver;
        char *name;
 };
 
@@ -124,36 +143,10 @@ extern void ccw_device_clear_options(struct ccw_device *, unsigned long);
 /* Allow forced onlining of boxed devices. */
 #define CCWDEV_ALLOW_FORCE              0x0008
 
-/*
- * ccw_device_start()
- *
- *  Start a S/390 channel program. When the interrupt arrives, the
- *  IRQ handler is called, either immediately, delayed (dev-end missing,
- *  or sense required) or never (no IRQ handler registered).
- *  Depending on the action taken, ccw_device_start() returns:  
- *                           0      - Success
- *                          -EBUSY  - Device busy, or status pending
- *                          -ENODEV - Device not operational
- *                           -EINVAL - Device invalid for operation
- */
 extern int ccw_device_start(struct ccw_device *, struct ccw1 *,
                            unsigned long, __u8, unsigned long);
-/*
- * ccw_device_start_timeout()
- *
- * This function notifies the device driver if the channel program has not
- * completed during the specified time. If a timeout occurs, the channel
- * program is terminated via xsch(), hsch() or csch().
- */
 extern int ccw_device_start_timeout(struct ccw_device *, struct ccw1 *,
                                    unsigned long, __u8, unsigned long, int);
-/*
- * ccw_device_start_key()
- * ccw_device_start_key_timeout()
- *
- * Same as ccw_device_start() and ccw_device_start_timeout(), except a
- * storage key != default key can be provided for the I/O.
- */
 extern int ccw_device_start_key(struct ccw_device *, struct ccw1 *,
                                unsigned long, __u8, __u8, unsigned long);
 extern int ccw_device_start_timeout_key(struct ccw_device *, struct ccw1 *,
index 925b3ddfa1411419a39316a0053a786826cf4260..7109c7cab87ecfe4d57941f24c0d83c46604e719 100644 (file)
@@ -4,19 +4,41 @@
 struct ccw_device;
 struct ccw_driver;
 
+/**
+ * struct ccwgroup_device - ccw group device
+ * @creator_id: unique number of the driver
+ * @state: online/offline state
+ * @count: number of attached slave devices
+ * @dev: embedded device structure
+ * @cdev: variable number of slave devices, allocated as needed
+ */
 struct ccwgroup_device {
-       unsigned long creator_id;       /* unique number of the driver */
+       unsigned long creator_id;
        enum {
                CCWGROUP_OFFLINE,
                CCWGROUP_ONLINE,
        } state;
+/* private: */
        atomic_t onoff;
        struct mutex reg_mutex;
-       unsigned int count;             /* number of attached slave devices */
-       struct device   dev;            /* master device                    */
-       struct ccw_device *cdev[0];     /* variable number, allocate as needed */
+/* public: */
+       unsigned int count;
+       struct device   dev;
+       struct ccw_device *cdev[0];
 };
 
+/**
+ * struct ccwgroup_driver - driver for ccw group devices
+ * @owner: driver owner
+ * @name: driver name
+ * @max_slaves: maximum number of slave devices
+ * @driver_id: unique id
+ * @probe: function called on probe
+ * @remove: function called on remove
+ * @set_online: function called when device is set online
+ * @set_offline: function called when device is set offline
+ * @driver: embedded driver structure
+ */
 struct ccwgroup_driver {
        struct module *owner;
        char *name;
@@ -28,7 +50,7 @@ struct ccwgroup_driver {
        int (*set_online) (struct ccwgroup_device *);
        int (*set_offline) (struct ccwgroup_device *);
 
-       struct device_driver driver;            /* this driver */
+       struct device_driver driver;
 };
 
 extern int  ccwgroup_driver_register   (struct ccwgroup_driver *cdriver);
index 1982fb3441644f3f178691c69aebd66b8e9dfb26..2f08c16e44adf649b2596cf5fff833a48dbb4208 100644 (file)
 #define LPM_ANYPATH 0xff
 #define __MAX_CSSID 0
 
-/*
- * subchannel status word
+/**
+ * struct scsw - subchannel status word
+ * @key: subchannel key
+ * @sctl: suspend control
+ * @eswf: esw format
+ * @cc: deferred condition code
+ * @fmt: format
+ * @pfch: prefetch
+ * @isic: initial-status interruption control
+ * @alcc: adress-limit checking control
+ * @ssi: supress-suspended interruption
+ * @zcc: zero condition code
+ * @ectl: extended control
+ * @pno: path not operational
+ * @res: reserved
+ * @fctl: function control
+ * @actl: activity control
+ * @stctl: status control
+ * @cpa: channel program address
+ * @dstat: device status
+ * @cstat: subchannel status
+ * @count: residual count
  */
 struct scsw {
-       __u32 key  : 4;         /* subchannel key */
-       __u32 sctl : 1;         /* suspend control */
-       __u32 eswf : 1;         /* ESW format */
-       __u32 cc   : 2;         /* deferred condition code */
-       __u32 fmt  : 1;         /* format */
-       __u32 pfch : 1;         /* prefetch */
-       __u32 isic : 1;         /* initial-status interruption control */
-       __u32 alcc : 1;         /* address-limit checking control */
-       __u32 ssi  : 1;         /* supress-suspended interruption */
-       __u32 zcc  : 1;         /* zero condition code */
-       __u32 ectl : 1;         /* extended control */
-       __u32 pno  : 1;         /* path not operational */
-       __u32 res  : 1;         /* reserved */
-       __u32 fctl : 3;         /* function control */
-       __u32 actl : 7;         /* activity control */
-       __u32 stctl : 5;        /* status control */
-       __u32 cpa;              /* channel program address */
-       __u32 dstat : 8;        /* device status */
-       __u32 cstat : 8;        /* subchannel status */
-       __u32 count : 16;       /* residual count */
+       __u32 key  : 4;
+       __u32 sctl : 1;
+       __u32 eswf : 1;
+       __u32 cc   : 2;
+       __u32 fmt  : 1;
+       __u32 pfch : 1;
+       __u32 isic : 1;
+       __u32 alcc : 1;
+       __u32 ssi  : 1;
+       __u32 zcc  : 1;
+       __u32 ectl : 1;
+       __u32 pno  : 1;
+       __u32 res  : 1;
+       __u32 fctl : 3;
+       __u32 actl : 7;
+       __u32 stctl : 5;
+       __u32 cpa;
+       __u32 dstat : 8;
+       __u32 cstat : 8;
+       __u32 count : 16;
 } __attribute__ ((packed));
 
 #define SCSW_FCTL_CLEAR_FUNC    0x1
@@ -110,11 +130,22 @@ struct scsw {
 #define SNS2_ENV_DATA_PRESENT  0x10
 #define SNS2_INPRECISE_END     0x04
 
+/**
+ * struct ccw1 - channel command word
+ * @cmd_code: command code
+ * @flags: flags, like IDA adressing, etc.
+ * @count: byte count
+ * @cda: data address
+ *
+ * The ccw is the basic structure to build channel programs that perform
+ * operations with the device or the control unit. Only Format-1 channel
+ * command words are supported.
+ */
 struct ccw1 {
-       __u8  cmd_code;         /* command code */
-       __u8  flags;            /* flags, like IDA addressing, etc. */
-       __u16 count;            /* byte count */
-       __u32 cda;              /* data address */
+       __u8  cmd_code;
+       __u8  flags;
+       __u16 count;
+       __u32 cda;
 } __attribute__ ((packed,aligned(8)));
 
 #define CCW_FLAG_DC            0x80
@@ -140,102 +171,162 @@ struct ccw1 {
 
 #define SENSE_MAX_COUNT                0x20
 
+/**
+ * struct erw - extended report word
+ * @res0: reserved
+ * @auth: authorization check
+ * @pvrf: path-verification-required flag
+ * @cpt: channel-path timeout
+ * @fsavf: failing storage address validity flag
+ * @cons: concurrent sense
+ * @scavf: secondary ccw address validity flag
+ * @fsaf: failing storage address format
+ * @scnt: sense count, if @cons == %1
+ * @res16: reserved
+ */
 struct erw {
-       __u32 res0  : 3;        /* reserved */
-       __u32 auth  : 1;        /* Authorization check */
-       __u32 pvrf  : 1;        /* path-verification-required flag */
-       __u32 cpt   : 1;        /* channel-path timeout */
-       __u32 fsavf : 1;        /* Failing storage address validity flag */
-       __u32 cons  : 1;        /* concurrent-sense */
-       __u32 scavf : 1;        /* Secondary ccw address validity flag */
-       __u32 fsaf  : 1;        /* Failing storage address format */
-       __u32 scnt  : 6;        /* sense count if cons == 1 */
-       __u32 res16 : 16;       /* reserved */
+       __u32 res0  : 3;
+       __u32 auth  : 1;
+       __u32 pvrf  : 1;
+       __u32 cpt   : 1;
+       __u32 fsavf : 1;
+       __u32 cons  : 1;
+       __u32 scavf : 1;
+       __u32 fsaf  : 1;
+       __u32 scnt  : 6;
+       __u32 res16 : 16;
 } __attribute__ ((packed));
 
-/*
- * subchannel logout area
+/**
+ * struct sublog - subchannel logout area
+ * @res0: reserved
+ * @esf: extended status flags
+ * @lpum: last path used mask
+ * @arep: ancillary report
+ * @fvf: field-validity flags
+ * @sacc: storage access code
+ * @termc: termination code
+ * @devsc: device-status check
+ * @serr: secondary error
+ * @ioerr: i/o-error alert
+ * @seqc: sequence code
  */
 struct sublog {
-       __u32 res0  : 1;        /* reserved */
-       __u32 esf   : 7;        /* extended status flags */
-       __u32 lpum  : 8;        /* last path used mask */
-       __u32 arep  : 1;        /* ancillary report */
-       __u32 fvf   : 5;        /* field-validity flags */
-       __u32 sacc  : 2;        /* storage access code */
-       __u32 termc : 2;        /* termination code */
-       __u32 devsc : 1;        /* device-status check */
-       __u32 serr  : 1;        /* secondary error */
-       __u32 ioerr : 1;        /* i/o-error alert */
-       __u32 seqc  : 3;        /* sequence code */
+       __u32 res0  : 1;
+       __u32 esf   : 7;
+       __u32 lpum  : 8;
+       __u32 arep  : 1;
+       __u32 fvf   : 5;
+       __u32 sacc  : 2;
+       __u32 termc : 2;
+       __u32 devsc : 1;
+       __u32 serr  : 1;
+       __u32 ioerr : 1;
+       __u32 seqc  : 3;
 } __attribute__ ((packed));
 
-/*
- * Format 0 Extended Status Word (ESW)
+/**
+ * struct esw0 - Format 0 Extended Status Word (ESW)
+ * @sublog: subchannel logout
+ * @erw: extended report word
+ * @faddr: failing storage address
+ * @saddr: secondary ccw address
  */
 struct esw0 {
-       struct sublog sublog;   /* subchannel logout */
-       struct erw erw;         /* extended report word */
-       __u32  faddr[2];        /* failing storage address */
-       __u32  saddr;           /* secondary ccw address */
+       struct sublog sublog;
+       struct erw erw;
+       __u32  faddr[2];
+       __u32  saddr;
 } __attribute__ ((packed));
 
-/*
- * Format 1 Extended Status Word (ESW)
+/**
+ * struct esw1 - Format 1 Extended Status Word (ESW)
+ * @zero0: reserved zeros
+ * @lpum: last path used mask
+ * @zero16: reserved zeros
+ * @erw: extended report word
+ * @zeros: three fullwords of zeros
  */
 struct esw1 {
-       __u8  zero0;            /* reserved zeros */
-       __u8  lpum;             /* last path used mask */
-       __u16 zero16;           /* reserved zeros */
-       struct erw erw;         /* extended report word */
-       __u32 zeros[3];         /* 2 fullwords of zeros */
+       __u8  zero0;
+       __u8  lpum;
+       __u16 zero16;
+       struct erw erw;
+       __u32 zeros[3];
 } __attribute__ ((packed));
 
-/*
- * Format 2 Extended Status Word (ESW)
+/**
+ * struct esw2 - Format 2 Extended Status Word (ESW)
+ * @zero0: reserved zeros
+ * @lpum: last path used mask
+ * @dcti: device-connect-time interval
+ * @erw: extended report word
+ * @zeros: three fullwords of zeros
  */
 struct esw2 {
-       __u8  zero0;            /* reserved zeros */
-       __u8  lpum;             /* last path used mask */
-       __u16 dcti;             /* device-connect-time interval */
-       struct erw erw;         /* extended report word */
-       __u32 zeros[3];         /* 2 fullwords of zeros */
+       __u8  zero0;
+       __u8  lpum;
+       __u16 dcti;
+       struct erw erw;
+       __u32 zeros[3];
 } __attribute__ ((packed));
 
-/*
- * Format 3 Extended Status Word (ESW)
+/**
+ * struct esw3 - Format 3 Extended Status Word (ESW)
+ * @zero0: reserved zeros
+ * @lpum: last path used mask
+ * @res: reserved
+ * @erw: extended report word
+ * @zeros: three fullwords of zeros
  */
 struct esw3 {
-       __u8  zero0;            /* reserved zeros */
-       __u8  lpum;             /* last path used mask */
-       __u16 res;              /* reserved */
-       struct erw erw;         /* extended report word */
-       __u32 zeros[3];         /* 2 fullwords of zeros */
+       __u8  zero0;
+       __u8  lpum;
+       __u16 res;
+       struct erw erw;
+       __u32 zeros[3];
 } __attribute__ ((packed));
 
-/*
- * interruption response block
+/**
+ * struct irb - interruption response block
+ * @scsw: subchannel status word
+ * @esw: extened status word, 4 formats
+ * @ecw: extended control word
+ *
+ * The irb that is handed to the device driver when an interrupt occurs. For
+ * solicited interrupts, the common I/O layer already performs checks whether
+ * a field is valid; a field not being valid is always passed as %0.
+ * If a unit check occured, @ecw may contain sense data; this is retrieved
+ * by the common I/O layer itself if the device doesn't support concurrent
+ * sense (so that the device driver never needs to perform basic sene itself).
+ * For unsolicited interrupts, the irb is passed as-is (expect for sense data,
+ * if applicable).
  */
 struct irb {
-       struct scsw scsw;       /* subchannel status word */
-       union {                 /* extended status word, 4 formats */
+       struct scsw scsw;
+       union {
                struct esw0 esw0;
                struct esw1 esw1;
                struct esw2 esw2;
                struct esw3 esw3;
        } esw;
-       __u8   ecw[32];         /* extended control word */
+       __u8   ecw[32];
 } __attribute__ ((packed,aligned(4)));
 
-/*
- * command information word  (CIW) layout
+/**
+ * struct ciw - command information word  (CIW) layout
+ * @et: entry type
+ * @reserved: reserved bits
+ * @ct: command type
+ * @cmd: command code
+ * @count: command count
  */
 struct ciw {
-       __u32 et       :  2;    /* entry type */
-       __u32 reserved :  2;    /* reserved */
-       __u32 ct       :  4;    /* command type */
-       __u32 cmd      :  8;    /* command */
-       __u32 count    : 16;    /* coun */
+       __u32 et       :  2;
+       __u32 reserved :  2;
+       __u32 ct       :  4;
+       __u32 cmd      :  8;
+       __u32 count    : 16;
 } __attribute__ ((packed));
 
 #define CIW_TYPE_RCD   0x0     /* read configuration data */
@@ -258,11 +349,32 @@ struct ciw {
 /* Sick revalidation of device. */
 #define CIO_REVALIDATE 0x0008
 
+/**
+ * struct ccw_dev_id - unique identifier for ccw devices
+ * @ssid: subchannel set id
+ * @devno: device number
+ *
+ * This structure is not directly based on any hardware structure. The
+ * hardware identifies a device by its device number and its subchannel,
+ * which is in turn identified by its id. In order to get a unique identifier
+ * for ccw devices across subchannel sets, @struct ccw_dev_id has been
+ * introduced.
+ */
 struct ccw_dev_id {
        u8 ssid;
        u16 devno;
 };
 
+/**
+ * ccw_device_id_is_equal() - compare two ccw_dev_ids
+ * @dev_id1: a ccw_dev_id
+ * @dev_id2: another ccw_dev_id
+ * Returns:
+ *  %1 if the two structures are equal field-by-field,
+ *  %0 if not.
+ * Context:
+ *  any
+ */
 static inline int ccw_dev_id_is_equal(struct ccw_dev_id *dev_id1,
                                      struct ccw_dev_id *dev_id2)
 {
index 021e7c3223ece8f931db8fca9f7d1d10cc8d029d..50196857d27a8e55dc4939333bb44fbc5d23fa0b 100644 (file)
@@ -1,29 +1,29 @@
 #ifndef S390_CMB_H
 #define S390_CMB_H
 /**
- * struct cmbdata -- channel measurement block data for user space
+ * struct cmbdata - channel measurement block data for user space
+ * @size: size of the stored data
+ * @elapsed_time: time since last sampling
+ * @ssch_rsch_count: number of ssch and rsch
+ * @sample_count: number of samples
+ * @device_connect_time: time of device connect
+ * @function_pending_time: time of function pending
+ * @device_disconnect_time: time of device disconnect
+ * @control_unit_queuing_time: time of control unit queuing
+ * @device_active_only_time: time of device active only
+ * @device_busy_time: time of device busy (ext. format)
+ * @initial_command_response_time: initial command response time (ext. format)
  *
- * @size:      size of the stored data
- * @ssch_rsch_count: XXX
- * @sample_count:
- * @device_connect_time:
- * @function_pending_time:
- * @device_disconnect_time:
- * @control_unit_queuing_time:
- * @device_active_only_time:
- * @device_busy_time:
- * @initial_command_response_time:
- *
- * all values are stored as 64 bit for simplicity, especially
+ * All values are stored as 64 bit for simplicity, especially
  * in 32 bit emulation mode. All time values are normalized to
  * nanoseconds.
  * Currently, two formats are known, which differ by the size of
  * this structure, i.e. the last two members are only set when
  * the extended channel measurement facility (first shipped in
  * z990 machines) is activated.
- * Potentially, more fields could be added, which results in a
+ * Potentially, more fields could be added, which would result in a
  * new ioctl number.
- **/
+ */
 struct cmbdata {
        __u64 size;
        __u64 elapsed_time;
@@ -41,53 +41,18 @@ struct cmbdata {
 };
 
 /* enable channel measurement */
-#define BIODASDCMFENABLE       _IO(DASD_IOCTL_LETTER,32)
+#define BIODASDCMFENABLE       _IO(DASD_IOCTL_LETTER, 32)
 /* enable channel measurement */
-#define BIODASDCMFDISABLE      _IO(DASD_IOCTL_LETTER,33)
+#define BIODASDCMFDISABLE      _IO(DASD_IOCTL_LETTER, 33)
 /* read channel measurement data */
-#define BIODASDREADALLCMB      _IOWR(DASD_IOCTL_LETTER,33,struct cmbdata)
+#define BIODASDREADALLCMB      _IOWR(DASD_IOCTL_LETTER, 33, struct cmbdata)
 
 #ifdef __KERNEL__
 struct ccw_device;
-/**
- * enable_cmf() - switch on the channel measurement for a specific device
- *  @cdev:     The ccw device to be enabled
- *  returns 0 for success or a negative error value.
- *
- *  Context:
- *    non-atomic
- **/
 extern int enable_cmf(struct ccw_device *cdev);
-
-/**
- * disable_cmf() - switch off the channel measurement for a specific device
- *  @cdev:     The ccw device to be disabled
- *  returns 0 for success or a negative error value.
- *
- *  Context:
- *    non-atomic
- **/
 extern int disable_cmf(struct ccw_device *cdev);
-
-/**
- * cmf_read() - read one value from the current channel measurement block
- * @cmf:       the channel to be read
- * @index:     the name of the value that is read
- *
- *  Context:
- *    any
- **/
-
 extern u64 cmf_read(struct ccw_device *cdev, int index);
-/**
- * cmf_readall() - read one value from the current channel measurement block
- * @cmf:       the channel to be read
- * @data:      a pointer to a data block that will be filled
- *
- *  Context:
- *    any
- **/
-extern int cmf_readall(struct ccw_device *cdev, struct cmbdata*data);
+extern int cmf_readall(struct ccw_device *cdev, struct cmbdata *data);
 
 #endif /* __KERNEL__ */
 #endif /* S390_CMB_H */
index f326451ed6ecbcf04a5ddada0622ddd3801d5a08..ceec3826a67c03729d090d7251fc93db677f8d45 100644 (file)
@@ -9,11 +9,12 @@
 #ifndef _S390_PAGE_H
 #define _S390_PAGE_H
 
+#include <linux/const.h>
 #include <asm/types.h>
 
 /* PAGE_SHIFT determines the page size */
 #define PAGE_SHIFT      12
-#define PAGE_SIZE       (1UL << PAGE_SHIFT)
+#define PAGE_SIZE      (_AC(1,UL) << PAGE_SHIFT)
 #define PAGE_MASK       (~(PAGE_SIZE-1))
 #define PAGE_DEFAULT_ACC       0
 #define PAGE_DEFAULT_KEY       (PAGE_DEFAULT_ACC << 4)
index 3208dc6c412c19a9d7695d65f1d397b6e9130df1..39bb5192dc3145aeecb7ed8f10fbd640d3aa85c9 100644 (file)
@@ -107,11 +107,18 @@ extern char empty_zero_page[PAGE_SIZE];
  * any out-of-bounds memory accesses will hopefully be caught.
  * The vmalloc() routines leaves a hole of 4kB between each vmalloced
  * area for the same reason. ;)
+ * vmalloc area starts at 4GB to prevent syscall table entry exchanging
+ * from modules.
  */
 extern unsigned long vmalloc_end;
-#define VMALLOC_OFFSET  (8*1024*1024)
-#define VMALLOC_START   (((unsigned long) high_memory + VMALLOC_OFFSET) \
-                        & ~(VMALLOC_OFFSET-1))
+
+#ifdef CONFIG_64BIT
+#define VMALLOC_ADDR   (max(0x100000000UL, (unsigned long) high_memory))
+#else
+#define VMALLOC_ADDR   ((unsigned long) high_memory)
+#endif
+#define VMALLOC_OFFSET (8*1024*1024)
+#define VMALLOC_START  ((VMALLOC_ADDR + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
 #define VMALLOC_END    vmalloc_end
 
 /*
index 1e72362cad78b6a50e2200325479617a3ac4a06f..2afc060266a2f4468d074174f8b9dd931f58255b 100644 (file)
@@ -5,7 +5,7 @@
  *  include/asm-s390/s390_ext.h
  *
  *  S390 version
- *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Copyright IBM Corp. 1999,2007
  *    Author(s): Holger Smolinski (Holger.Smolinski@de.ibm.com),
  *               Martin Schwidefsky (schwidefsky@de.ibm.com)
  */
 
 typedef void (*ext_int_handler_t)(__u16 code);
 
-/*
- * Warning: if you change ext_int_info_t you have to change the
- * external interrupt handler in entry.S too.
- */ 
 typedef struct ext_int_info_t {
        struct ext_int_info_t *next;
        ext_int_handler_t handler;
        __u16 code;
-} __attribute__ ((packed)) ext_int_info_t;
+} ext_int_info_t;
 
 extern ext_int_info_t *ext_int_hash[];
 
index 64a3cd05cae1abb0a764665ef1110e5ae6567739..d866d3385556d3f06d00e870b80d5b0e06b209bb 100644 (file)
@@ -130,6 +130,8 @@ extern void pfault_fini(void);
        __ret;                                                            \
 })
 
+extern void __xchg_called_with_bad_pointer(void);
+
 static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
 {
        unsigned long addr, old;
@@ -150,8 +152,7 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
                        : "=&d" (old), "=m" (*(int *) addr)
                        : "d" (x << shift), "d" (~(255 << shift)), "a" (addr),
                          "m" (*(int *) addr) : "memory", "cc", "0");
-               x = old >> shift;
-               break;
+               return old >> shift;
        case 2:
                addr = (unsigned long) ptr;
                shift = (2 ^ (addr & 2)) << 3;
@@ -166,8 +167,7 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
                        : "=&d" (old), "=m" (*(int *) addr)
                        : "d" (x << shift), "d" (~(65535 << shift)), "a" (addr),
                          "m" (*(int *) addr) : "memory", "cc", "0");
-               x = old >> shift;
-               break;
+               return old >> shift;
        case 4:
                asm volatile(
                        "       l       %0,0(%3)\n"
@@ -176,8 +176,7 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
                        : "=&d" (old), "=m" (*(int *) ptr)
                        : "d" (x), "a" (ptr), "m" (*(int *) ptr)
                        : "memory", "cc");
-               x = old;
-               break;
+               return old;
 #ifdef __s390x__
        case 8:
                asm volatile(
@@ -187,11 +186,11 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
                        : "=&d" (old), "=m" (*(long *) ptr)
                        : "d" (x), "a" (ptr), "m" (*(long *) ptr)
                        : "memory", "cc");
-               x = old;
-               break;
+               return old;
 #endif /* __s390x__ */
-        }
-        return x;
+       }
+       __xchg_called_with_bad_pointer();
+       return x;
 }
 
 /*
@@ -206,6 +205,8 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
        ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
                                        (unsigned long)(n),sizeof(*(ptr))))
 
+extern void __cmpxchg_called_with_bad_pointer(void);
+
 static inline unsigned long
 __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
 {
@@ -270,7 +271,8 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
                return prev;
 #endif /* __s390x__ */
         }
-        return old;
+       __cmpxchg_called_with_bad_pointer();
+       return old;
 }
 
 /*
index b90e55888a554b271227467b48388c5b462feda9..a5dada6177514fc650ea27a5cdf556d6702e233c 100644 (file)
@@ -91,7 +91,7 @@ struct ica_rsa_modexpo_crt {
  *         VUD block
  *         key block
  */
-struct ica_CPRBX {
+struct CPRBX {
        unsigned short  cprb_len;       /* CPRB length        220        */
        unsigned char   cprb_ver_id;    /* CPRB version id.   0x02       */
        unsigned char   pad_000[3];     /* Alignment pad bytes           */
@@ -130,7 +130,7 @@ struct ica_CPRBX {
        unsigned char   cntrl_domain[4];/* Control domain                */
        unsigned char   S390enf_mask[4];/* S/390 enforcement mask        */
        unsigned char   pad_004[36];    /* reserved                      */
-};
+} __attribute__((packed));
 
 /**
  * xcRB
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);
 
diff --git a/include/asm-x86/8253pit.h b/include/asm-x86/8253pit.h
deleted file mode 100644 (file)
index d3c2b38..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#ifdef CONFIG_X86_32
-# include "8253pit_32.h"
-#else
-# include "8253pit_64.h"
-#endif
diff --git a/include/asm-x86/8253pit_32.h b/include/asm-x86/8253pit_32.h
deleted file mode 100644 (file)
index 96c7c35..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * 8253/8254 Programmable Interval Timer
- */
-
-#ifndef _8253PIT_H
-#define _8253PIT_H
-
-#include <asm/timex.h>
-
-#define PIT_TICK_RATE  CLOCK_TICK_RATE
-
-#endif
diff --git a/include/asm-x86/8253pit_64.h b/include/asm-x86/8253pit_64.h
deleted file mode 100644 (file)
index 285f784..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * 8253/8254 Programmable Interval Timer
- */
-
-#ifndef _8253PIT_H
-#define _8253PIT_H
-
-#define PIT_TICK_RATE  1193182UL
-
-#endif
index 85125ef3c4143a362b9758114544c17f6ee38686..3c8f21eef0be4837be2c99dc96b7269eb086b086 100644 (file)
@@ -19,7 +19,7 @@
 extern int apic_verbosity;
 extern int apic_runs_main_timer;
 extern int ioapic_force;
-extern int apic_mapped;
+extern int disable_apic_timer;
 
 /*
  * Define the default level of output to be very little
@@ -79,8 +79,6 @@ extern void smp_local_timer_interrupt (void);
 extern void setup_boot_APIC_clock (void);
 extern void setup_secondary_APIC_clock (void);
 extern int APIC_init_uniprocessor (void);
-extern void disable_APIC_timer(void);
-extern void enable_APIC_timer(void);
 extern void setup_apic_routing(void);
 
 extern void setup_APIC_extended_lvt(unsigned char lvt_off, unsigned char vector,
@@ -95,10 +93,6 @@ extern int apic_is_clustered_box(void);
 #define K8_APIC_EXT_INT_MSG_EXT 0x7
 #define K8_APIC_EXT_LVT_ENTRY_THRESHOLD    0
 
-void smp_send_timer_broadcast_ipi(void);
-void switch_APIC_timer_to_ipi(void *cpumask);
-void switch_ipi_to_APIC_timer(void *cpumask);
-
 #define ARCH_APICTIMER_STOPS_ON_C3     1
 
 extern unsigned boot_cpu_id;
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 6da4bbbea3dc71cf023fb4079db62a9a2287edf2..d94898831bac6d2e66ecaaa75972789841048bd5 100644 (file)
@@ -156,4 +156,54 @@ static inline int is_geode(void)
        return (is_geode_gx() || is_geode_lx());
 }
 
+/* MFGPTs */
+
+#define MFGPT_MAX_TIMERS       8
+#define MFGPT_TIMER_ANY                -1
+
+#define MFGPT_DOMAIN_WORKING   1
+#define MFGPT_DOMAIN_STANDBY   2
+#define MFGPT_DOMAIN_ANY       (MFGPT_DOMAIN_WORKING | MFGPT_DOMAIN_STANDBY)
+
+#define MFGPT_CMP1             0
+#define MFGPT_CMP2             1
+
+#define MFGPT_EVENT_IRQ                0
+#define MFGPT_EVENT_NMI                1
+#define MFGPT_EVENT_RESET      3
+
+#define MFGPT_REG_CMP1         0
+#define MFGPT_REG_CMP2         2
+#define MFGPT_REG_COUNTER      4
+#define MFGPT_REG_SETUP                6
+
+#define MFGPT_SETUP_CNTEN      (1 << 15)
+#define MFGPT_SETUP_CMP2       (1 << 14)
+#define MFGPT_SETUP_CMP1       (1 << 13)
+#define MFGPT_SETUP_SETUP      (1 << 12)
+#define MFGPT_SETUP_STOPEN     (1 << 11)
+#define MFGPT_SETUP_EXTEN      (1 << 10)
+#define MFGPT_SETUP_REVEN      (1 << 5)
+#define MFGPT_SETUP_CLKSEL     (1 << 4)
+
+static inline void geode_mfgpt_write(int timer, u16 reg, u16 value)
+{
+       u32 base = geode_get_dev_base(GEODE_DEV_MFGPT);
+       outw(value, base + reg + (timer * 8));
+}
+
+static inline u16 geode_mfgpt_read(int timer, u16 reg)
+{
+       u32 base = geode_get_dev_base(GEODE_DEV_MFGPT);
+       return inw(base + reg + (timer * 8));
+}
+
+extern int __init geode_mfgpt_detect(void);
+extern int geode_mfgpt_toggle_event(int timer, int cmp, int event, int enable);
+extern int geode_mfgpt_set_irq(int timer, int cmp, int irq, int enable);
+extern int geode_mfgpt_alloc_timer(int timer, int domain, struct module *owner);
+
+#define geode_mfgpt_setup_irq(t, c, i) geode_mfgpt_set_irq((t), (c), (i), 1)
+#define geode_mfgpt_release_irq(t, c, i) geode_mfgpt_set_irq((t), (c), (i), 0)
+
 #endif
index 0e358dc405f820f6259cf61b247201a568bc9e64..34649585bb5992455c6e1339f8750d0837ef82f9 100644 (file)
@@ -9,6 +9,7 @@ typedef struct {
        unsigned long idle_timestamp;
        unsigned int __nmi_count;       /* arch dependent */
        unsigned int apic_timer_irqs;   /* arch dependent */
+       unsigned int irq0_irqs;
 } ____cacheline_aligned irq_cpustat_t;
 
 DECLARE_PER_CPU(irq_cpustat_t, irq_stat);
index 9eff48601254a88ed6cb0c54cf0a7ebb79fe2ccf..d4ab6db050b6cc0646e564a1a29039853bde249e 100644 (file)
@@ -1,5 +1,93 @@
-#ifdef CONFIG_X86_32
-# include "hpet_32.h"
+#ifndef ASM_X86_HPET_H
+#define ASM_X86_HPET_H
+
+#ifdef CONFIG_HPET_TIMER
+
+/*
+ * Documentation on HPET can be found at:
+ *      http://www.intel.com/ial/home/sp/pcmmspec.htm
+ *      ftp://download.intel.com/ial/home/sp/mmts098.pdf
+ */
+
+#define HPET_MMAP_SIZE         1024
+
+#define HPET_ID                        0x000
+#define HPET_PERIOD            0x004
+#define HPET_CFG               0x010
+#define HPET_STATUS            0x020
+#define HPET_COUNTER           0x0f0
+#define HPET_T0_CFG            0x100
+#define HPET_T0_CMP            0x108
+#define HPET_T0_ROUTE          0x110
+#define HPET_T1_CFG            0x120
+#define HPET_T1_CMP            0x128
+#define HPET_T1_ROUTE          0x130
+#define HPET_T2_CFG            0x140
+#define HPET_T2_CMP            0x148
+#define HPET_T2_ROUTE          0x150
+
+#define HPET_ID_REV            0x000000ff
+#define HPET_ID_NUMBER         0x00001f00
+#define HPET_ID_64BIT          0x00002000
+#define HPET_ID_LEGSUP         0x00008000
+#define HPET_ID_VENDOR         0xffff0000
+#define        HPET_ID_NUMBER_SHIFT    8
+#define HPET_ID_VENDOR_SHIFT   16
+
+#define HPET_ID_VENDOR_8086    0x8086
+
+#define HPET_CFG_ENABLE                0x001
+#define HPET_CFG_LEGACY                0x002
+#define        HPET_LEGACY_8254        2
+#define        HPET_LEGACY_RTC         8
+
+#define HPET_TN_LEVEL          0x0002
+#define HPET_TN_ENABLE         0x0004
+#define HPET_TN_PERIODIC       0x0008
+#define HPET_TN_PERIODIC_CAP   0x0010
+#define HPET_TN_64BIT_CAP      0x0020
+#define HPET_TN_SETVAL         0x0040
+#define HPET_TN_32BIT          0x0100
+#define HPET_TN_ROUTE          0x3e00
+#define HPET_TN_FSB            0x4000
+#define HPET_TN_FSB_CAP                0x8000
+#define HPET_TN_ROUTE_SHIFT    9
+
+/* Max HPET Period is 10^8 femto sec as in HPET spec */
+#define HPET_MAX_PERIOD                100000000UL
+/*
+ * Min HPET period is 10^5 femto sec just for safety. If it is less than this,
+ * then 32 bit HPET counter wrapsaround in less than 0.5 sec.
+ */
+#define HPET_MIN_PERIOD                100000UL
+
+/* hpet memory map physical address */
+extern unsigned long hpet_address;
+extern unsigned long force_hpet_address;
+extern int is_hpet_enabled(void);
+extern int hpet_enable(void);
+extern unsigned long hpet_readl(unsigned long a);
+extern void force_hpet_resume(void);
+
+#ifdef CONFIG_HPET_EMULATE_RTC
+
+#include <linux/interrupt.h>
+
+extern int hpet_mask_rtc_irq_bit(unsigned long bit_mask);
+extern int hpet_set_rtc_irq_bit(unsigned long bit_mask);
+extern int hpet_set_alarm_time(unsigned char hrs, unsigned char min,
+                              unsigned char sec);
+extern int hpet_set_periodic_freq(unsigned long freq);
+extern int hpet_rtc_dropped_irq(void);
+extern int hpet_rtc_timer_init(void);
+extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id);
+
+#endif /* CONFIG_HPET_EMULATE_RTC */
+
 #else
-# include "hpet_64.h"
-#endif
+
+static inline int hpet_enable(void) { return 0; }
+static inline unsigned long hpet_readl(unsigned long a) { return 0; }
+
+#endif /* CONFIG_HPET_TIMER */
+#endif /* ASM_X86_HPET_H */
diff --git a/include/asm-x86/hpet_32.h b/include/asm-x86/hpet_32.h
deleted file mode 100644 (file)
index c82dc7e..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-
-#ifndef _I386_HPET_H
-#define _I386_HPET_H
-
-#ifdef CONFIG_HPET_TIMER
-
-/*
- * Documentation on HPET can be found at:
- *      http://www.intel.com/ial/home/sp/pcmmspec.htm
- *      ftp://download.intel.com/ial/home/sp/mmts098.pdf
- */
-
-#define HPET_MMAP_SIZE         1024
-
-#define HPET_ID                        0x000
-#define HPET_PERIOD            0x004
-#define HPET_CFG               0x010
-#define HPET_STATUS            0x020
-#define HPET_COUNTER           0x0f0
-#define HPET_T0_CFG            0x100
-#define HPET_T0_CMP            0x108
-#define HPET_T0_ROUTE          0x110
-#define HPET_T1_CFG            0x120
-#define HPET_T1_CMP            0x128
-#define HPET_T1_ROUTE          0x130
-#define HPET_T2_CFG            0x140
-#define HPET_T2_CMP            0x148
-#define HPET_T2_ROUTE          0x150
-
-#define HPET_ID_REV            0x000000ff
-#define HPET_ID_NUMBER         0x00001f00
-#define HPET_ID_64BIT          0x00002000
-#define HPET_ID_LEGSUP         0x00008000
-#define HPET_ID_VENDOR         0xffff0000
-#define        HPET_ID_NUMBER_SHIFT    8
-#define HPET_ID_VENDOR_SHIFT   16
-
-#define HPET_ID_VENDOR_8086    0x8086
-
-#define HPET_CFG_ENABLE                0x001
-#define HPET_CFG_LEGACY                0x002
-#define        HPET_LEGACY_8254        2
-#define        HPET_LEGACY_RTC         8
-
-#define HPET_TN_LEVEL          0x0002
-#define HPET_TN_ENABLE         0x0004
-#define HPET_TN_PERIODIC       0x0008
-#define HPET_TN_PERIODIC_CAP   0x0010
-#define HPET_TN_64BIT_CAP      0x0020
-#define HPET_TN_SETVAL         0x0040
-#define HPET_TN_32BIT          0x0100
-#define HPET_TN_ROUTE          0x3e00
-#define HPET_TN_FSB            0x4000
-#define HPET_TN_FSB_CAP                0x8000
-#define HPET_TN_ROUTE_SHIFT    9
-
-/* Max HPET Period is 10^8 femto sec as in HPET spec */
-#define HPET_MAX_PERIOD                100000000UL
-/*
- * Min HPET period is 10^5 femto sec just for safety. If it is less than this,
- * then 32 bit HPET counter wrapsaround in less than 0.5 sec.
- */
-#define HPET_MIN_PERIOD                100000UL
-
-/* hpet memory map physical address */
-extern unsigned long hpet_address;
-extern int is_hpet_enabled(void);
-extern int hpet_enable(void);
-
-#ifdef CONFIG_HPET_EMULATE_RTC
-
-#include <linux/interrupt.h>
-
-extern int hpet_mask_rtc_irq_bit(unsigned long bit_mask);
-extern int hpet_set_rtc_irq_bit(unsigned long bit_mask);
-extern int hpet_set_alarm_time(unsigned char hrs, unsigned char min,
-                              unsigned char sec);
-extern int hpet_set_periodic_freq(unsigned long freq);
-extern int hpet_rtc_dropped_irq(void);
-extern int hpet_rtc_timer_init(void);
-extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id);
-
-#endif /* CONFIG_HPET_EMULATE_RTC */
-
-#else
-
-static inline int hpet_enable(void) { return 0; }
-
-#endif /* CONFIG_HPET_TIMER */
-#endif /* _I386_HPET_H */
diff --git a/include/asm-x86/hpet_64.h b/include/asm-x86/hpet_64.h
deleted file mode 100644 (file)
index fd4deca..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef _ASM_X8664_HPET_H
-#define _ASM_X8664_HPET_H 1
-
-#include <asm/hpet_32.h>
-
-#define HPET_TICK_RATE (HZ * 100000UL)
-
-extern int hpet_rtc_timer_init(void);
-extern int hpet_arch_init(void);
-extern int hpet_timer_stop_set_go(unsigned long tick);
-extern int hpet_reenable(void);
-extern unsigned int hpet_calibrate_tsc(void);
-
-extern int hpet_use_timer;
-extern unsigned long hpet_period;
-extern unsigned long hpet_tick;
-
-#endif
index b2a4f995a33f91ccf4826f547f447c594419ce6b..747548ec5d1ddce5fb1574b77b47d119f84e0754 100644 (file)
@@ -1,5 +1,15 @@
-#ifdef CONFIG_X86_32
-# include "i8253_32.h"
-#else
-# include "i8253_64.h"
-#endif
+#ifndef __ASM_I8253_H__
+#define __ASM_I8253_H__
+
+/* i8253A PIT registers */
+#define PIT_MODE               0x43
+#define PIT_CH0                        0x40
+#define PIT_CH2                        0x42
+
+extern spinlock_t i8253_lock;
+
+extern struct clock_event_device *global_clock_event;
+
+extern void setup_pit_timer(void);
+
+#endif /* __ASM_I8253_H__ */
diff --git a/include/asm-x86/i8253_32.h b/include/asm-x86/i8253_32.h
deleted file mode 100644 (file)
index 7577d05..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef __ASM_I8253_H__
-#define __ASM_I8253_H__
-
-#include <linux/clockchips.h>
-
-/* i8253A PIT registers */
-#define PIT_MODE               0x43
-#define PIT_CH0                        0x40
-#define PIT_CH2                        0x42
-
-extern spinlock_t i8253_lock;
-
-extern struct clock_event_device *global_clock_event;
-
-extern void setup_pit_timer(void);
-
-#endif /* __ASM_I8253_H__ */
diff --git a/include/asm-x86/i8253_64.h b/include/asm-x86/i8253_64.h
deleted file mode 100644 (file)
index 015d8df..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_I8253_H__
-#define __ASM_I8253_H__
-
-extern spinlock_t i8253_lock;
-
-#endif /* __ASM_I8253_H__ */
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 a8cac8c2cde7d960e92de995943b17ace4c4b896..e883619663476e7f0659e6ebafb3c5d1a6712870 100644 (file)
@@ -1,5 +1,95 @@
+#ifndef __x86_PCI_H
+#define __x86_PCI_H
+
+#include <linux/mm.h> /* for struct page */
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <asm/scatterlist.h>
+#include <asm/io.h>
+
+
+#ifdef __KERNEL__
+
+struct pci_sysdata {
+       int             domain;         /* PCI domain */
+       int             node;           /* NUMA node */
+#ifdef CONFIG_X86_64
+       void*           iommu;          /* IOMMU private data */
+#endif
+};
+
+/* scan a bus after allocating a pci_sysdata for it */
+extern struct pci_bus *pci_scan_bus_with_sysdata(int busno);
+
+static inline int pci_domain_nr(struct pci_bus *bus)
+{
+       struct pci_sysdata *sd = bus->sysdata;
+       return sd->domain;
+}
+
+static inline int pci_proc_domain(struct pci_bus *bus)
+{
+       return pci_domain_nr(bus);
+}
+
+
+/* Can be used to override the logic in pci_scan_bus for skipping
+   already-configured bus numbers - to be used for buggy BIOSes
+   or architectures with incomplete PCI setup by the loader */
+
+#ifdef CONFIG_PCI
+extern unsigned int pcibios_assign_all_busses(void);
+#else
+#define pcibios_assign_all_busses()    0
+#endif
+#define pcibios_scan_all_fns(a, b)     0
+
+extern unsigned long pci_mem_start;
+#define PCIBIOS_MIN_IO         0x1000
+#define PCIBIOS_MIN_MEM                (pci_mem_start)
+
+#define PCIBIOS_MIN_CARDBUS_IO 0x4000
+
+void pcibios_config_init(void);
+struct pci_bus * pcibios_scan_root(int bus);
+
+void pcibios_set_master(struct pci_dev *dev);
+void pcibios_penalize_isa_irq(int irq, int active);
+struct irq_routing_table *pcibios_get_irq_routing_table(void);
+int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq);
+
+
+#define HAVE_PCI_MMAP
+extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
+                              enum pci_mmap_state mmap_state, int write_combine);
+
+
+#ifdef CONFIG_PCI
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+                                       enum pci_dma_burst_strategy *strat,
+                                       unsigned long *strategy_parameter)
+{
+       *strat = PCI_DMA_BURST_INFINITY;
+       *strategy_parameter = ~0UL;
+}
+#endif
+
+
+#endif  /* __KERNEL__ */
+
 #ifdef CONFIG_X86_32
 # include "pci_32.h"
 #else
 # include "pci_64.h"
+#endif
+
+/* implement the pci_ DMA API in terms of the generic device dma_ one */
+#include <asm-generic/pci-dma-compat.h>
+
+/* generic pci stuff */
+#include <asm-generic/pci.h>
+
+
+
 #endif
index 4fcacc71138594d4e14f72739e92f511b9506561..8c4c3a0368e27735eebbc8553cfa7decd67734fb 100644 (file)
@@ -4,50 +4,11 @@
 
 #ifdef __KERNEL__
 
-struct pci_sysdata {
-       int             node;           /* NUMA node */
-};
-
-/* scan a bus after allocating a pci_sysdata for it */
-extern struct pci_bus *pci_scan_bus_with_sysdata(int busno);
-
-#include <linux/mm.h>          /* for struct page */
-
-/* Can be used to override the logic in pci_scan_bus for skipping
-   already-configured bus numbers - to be used for buggy BIOSes
-   or architectures with incomplete PCI setup by the loader */
-
-#ifdef CONFIG_PCI
-extern unsigned int pcibios_assign_all_busses(void);
-#else
-#define pcibios_assign_all_busses()    0
-#endif
-#define pcibios_scan_all_fns(a, b)     0
-
-extern unsigned long pci_mem_start;
-#define PCIBIOS_MIN_IO         0x1000
-#define PCIBIOS_MIN_MEM                (pci_mem_start)
-
-#define PCIBIOS_MIN_CARDBUS_IO 0x4000
-
-void pcibios_config_init(void);
-struct pci_bus * pcibios_scan_root(int bus);
-
-void pcibios_set_master(struct pci_dev *dev);
-void pcibios_penalize_isa_irq(int irq, int active);
-struct irq_routing_table *pcibios_get_irq_routing_table(void);
-int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq);
 
 /* Dynamic DMA mapping stuff.
  * i386 has everything mapped statically.
  */
 
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <asm/scatterlist.h>
-#include <linux/string.h>
-#include <asm/io.h>
-
 struct pci_dev;
 
 /* The PCI address space does equal the physical memory
@@ -64,27 +25,8 @@ struct pci_dev;
 #define pci_unmap_len(PTR, LEN_NAME)           (0)
 #define pci_unmap_len_set(PTR, LEN_NAME, VAL)  do { } while (0)
 
-#define HAVE_PCI_MMAP
-extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
-                              enum pci_mmap_state mmap_state, int write_combine);
-
-
-#ifdef CONFIG_PCI
-static inline void pci_dma_burst_advice(struct pci_dev *pdev,
-                                       enum pci_dma_burst_strategy *strat,
-                                       unsigned long *strategy_parameter)
-{
-       *strat = PCI_DMA_BURST_INFINITY;
-       *strategy_parameter = ~0UL;
-}
-#endif
 
 #endif /* __KERNEL__ */
 
-/* implement the pci_ DMA API in terms of the generic device dma_ one */
-#include <asm-generic/pci-dma-compat.h>
-
-/* generic pci stuff */
-#include <asm-generic/pci.h>
 
 #endif /* __i386_PCI_H */
index 5da8cb0c0599fccc883992354929238aa8700bd1..9baa46d9f594893a011b9e803566e17f2ac3f150 100644 (file)
@@ -1,16 +1,9 @@
 #ifndef __x8664_PCI_H
 #define __x8664_PCI_H
 
-#include <asm/io.h>
 
 #ifdef __KERNEL__
 
-struct pci_sysdata {
-       int             node;           /* NUMA node */
-       void*           iommu;          /* IOMMU private data */
-};
-
-extern struct pci_bus *pci_scan_bus_with_sysdata(int busno);
 
 #ifdef CONFIG_CALGARY_IOMMU
 static inline void* pci_iommu(struct pci_bus *bus)
@@ -26,40 +19,11 @@ static inline void set_pci_iommu(struct pci_bus *bus, void *val)
 }
 #endif /* CONFIG_CALGARY_IOMMU */
 
-#include <linux/mm.h> /* for struct page */
-
-/* Can be used to override the logic in pci_scan_bus for skipping
-   already-configured bus numbers - to be used for buggy BIOSes
-   or architectures with incomplete PCI setup by the loader */
-
-#ifdef CONFIG_PCI
-extern unsigned int pcibios_assign_all_busses(void);
-#else
-#define pcibios_assign_all_busses()    0
-#endif
-#define pcibios_scan_all_fns(a, b)     0
-
-extern unsigned long pci_mem_start;
-#define PCIBIOS_MIN_IO         0x1000
-#define PCIBIOS_MIN_MEM                (pci_mem_start)
-
-#define PCIBIOS_MIN_CARDBUS_IO 0x4000
 
-void pcibios_config_init(void);
-struct pci_bus * pcibios_scan_root(int bus);
 extern int (*pci_config_read)(int seg, int bus, int dev, int fn, int reg, int len, u32 *value);
 extern int (*pci_config_write)(int seg, int bus, int dev, int fn, int reg, int len, u32 value);
 
-void pcibios_set_master(struct pci_dev *dev);
-void pcibios_penalize_isa_irq(int irq, int active);
-struct irq_routing_table *pcibios_get_irq_routing_table(void);
-int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq);
 
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <asm/scatterlist.h>
-#include <linux/string.h>
-#include <asm/page.h>
 
 extern void pci_iommu_alloc(void);
 extern int iommu_setup(char *opt);
@@ -100,27 +64,7 @@ extern int iommu_setup(char *opt);
 
 #endif
 
-#include <asm-generic/pci-dma-compat.h>
-
-#ifdef CONFIG_PCI
-static inline void pci_dma_burst_advice(struct pci_dev *pdev,
-                                       enum pci_dma_burst_strategy *strat,
-                                       unsigned long *strategy_parameter)
-{
-       *strat = PCI_DMA_BURST_INFINITY;
-       *strategy_parameter = ~0UL;
-}
-#endif
-
-#define HAVE_PCI_MMAP
-extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
-                              enum pci_mmap_state mmap_state, int write_combine);
-
 #endif /* __KERNEL__ */
 
-/* generic pci stuff */
-#ifdef CONFIG_PCI
-#include <asm-generic/pci.h>
-#endif
 
 #endif /* __x8664_PCI_H */
index 5642634843c472921ec08802fda4f36ca6a0ce1b..fb49f80eb94f9f03929392f058e4669ca5eb6968 100644 (file)
@@ -29,6 +29,7 @@ struct x8664_pda {
        short isidle;
        struct mm_struct *active_mm;
        unsigned apic_timer_irqs;
+       unsigned irq0_irqs;
 } ____cacheline_aligned_in_smp;
 
 extern struct x8664_pda *_cpu_pda[];
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 31f20ad65876b25f588e6c2e7e693fff23eb19b0..c44a3a93b5a49f06c686eed86d508377b0156f49 100644 (file)
@@ -51,9 +51,6 @@ extern void reserve_bootmem_generic(unsigned long phys, unsigned len);
 
 extern void load_gs_index(unsigned gs);
 
-extern void stop_timer_interrupt(void);
-extern void main_timer_handler(void);
-
 extern unsigned long end_pfn_map; 
 
 extern void show_trace(struct task_struct *, struct pt_regs *, unsigned long * rsp);
@@ -90,14 +87,10 @@ extern int timer_over_8254;
 
 extern int gsi_irq_sharing(int gsi);
 
-extern void smp_local_timer_interrupt(void);
-
 extern int force_mwait;
 
 long do_arch_prctl(struct task_struct *task, int code, unsigned long addr);
 
-void i8254_timer_resume(void);
-
 #define round_up(x,y) (((x) + (y) - 1) & ~((y)-1))
 #define round_down(x,y) ((x) & ~((y)-1))
 
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 d01c18cfccef956a503d15256a139db8207ba7ff..39a21ab030f02a6244746bc1f706c884cdd59e8b 100644 (file)
@@ -1,5 +1,18 @@
-#ifdef CONFIG_X86_32
-# include "timex_32.h"
+/* x86 architecture timex specifications */
+#ifndef _ASM_X86_TIMEX_H
+#define _ASM_X86_TIMEX_H
+
+#include <asm/processor.h>
+#include <asm/tsc.h>
+
+#ifdef CONFIG_X86_ELAN
+#  define PIT_TICK_RATE 1189200 /* AMD Elan has different frequency! */
 #else
-# include "timex_64.h"
+#  define PIT_TICK_RATE 1193182 /* Underlying HZ */
+#endif
+#define CLOCK_TICK_RATE        PIT_TICK_RATE
+
+extern int read_current_timer(unsigned long *timer_value);
+#define ARCH_HAS_READ_CURRENT_TIMER    1
+
 #endif
diff --git a/include/asm-x86/timex_32.h b/include/asm-x86/timex_32.h
deleted file mode 100644 (file)
index 3666044..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * linux/include/asm-i386/timex.h
- *
- * i386 architecture timex specifications
- */
-#ifndef _ASMi386_TIMEX_H
-#define _ASMi386_TIMEX_H
-
-#include <asm/processor.h>
-#include <asm/tsc.h>
-
-#ifdef CONFIG_X86_ELAN
-#  define CLOCK_TICK_RATE 1189200 /* AMD Elan has different frequency! */
-#else
-#  define CLOCK_TICK_RATE 1193182 /* Underlying HZ */
-#endif
-
-
-extern int read_current_timer(unsigned long *timer_value);
-#define ARCH_HAS_READ_CURRENT_TIMER    1
-
-#endif
diff --git a/include/asm-x86/timex_64.h b/include/asm-x86/timex_64.h
deleted file mode 100644 (file)
index 6ed21f4..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * linux/include/asm-x86_64/timex.h
- *
- * x86-64 architecture timex specifications
- */
-#ifndef _ASMx8664_TIMEX_H
-#define _ASMx8664_TIMEX_H
-
-#include <asm/8253pit.h>
-#include <asm/msr.h>
-#include <asm/vsyscall.h>
-#include <asm/system.h>
-#include <asm/processor.h>
-#include <asm/tsc.h>
-#include <linux/compiler.h>
-
-#define CLOCK_TICK_RATE        PIT_TICK_RATE   /* Underlying HZ */
-
-extern int read_current_timer(unsigned long *timer_value);
-#define ARCH_HAS_READ_CURRENT_TIMER    1
-
-#define USEC_PER_TICK (USEC_PER_SEC / HZ)
-#define NSEC_PER_TICK (NSEC_PER_SEC / HZ)
-#define FSEC_PER_TICK (FSEC_PER_SEC / HZ)
-
-#define NS_SCALE        10 /* 2^10, carefully chosen */
-#define US_SCALE        32 /* 2^32, arbitralrily chosen */
-
-extern void mark_tsc_unstable(char *msg);
-extern void set_cyc2ns_scale(unsigned long khz);
-#endif
index a4d806610b7ff5c56dc51a628ca8f20ad73d1c89..6baab30dc2c8be051e81286bcb9e0ce97d37d724 100644 (file)
@@ -1,13 +1,14 @@
 /*
- * linux/include/asm-i386/tsc.h
- *
- * i386 TSC related functions
+ * x86 TSC related functions
  */
-#ifndef _ASM_i386_TSC_H
-#define _ASM_i386_TSC_H
+#ifndef _ASM_X86_TSC_H
+#define _ASM_X86_TSC_H
 
 #include <asm/processor.h>
 
+#define NS_SCALE       10 /* 2^10, carefully chosen */
+#define US_SCALE       32 /* 2^32, arbitralrily chosen */
+
 /*
  * Standard way to access the cycle counter.
  */
@@ -72,4 +73,8 @@ int check_tsc_unstable(void);
 extern void check_tsc_sync_source(int cpu);
 extern void check_tsc_sync_target(void);
 
+#ifdef CONFIG_X86_64
+extern void tsc_calibrate(void);
+#endif
+
 #endif
index 3b8ceb4af2cf6045290d79570187bd5f2206556b..f01c49f5d108d50666535d0fb1e52cc1bdc97c2d 100644 (file)
@@ -29,9 +29,6 @@ enum vsyscall_num {
 #define VGETCPU_RDTSCP 1
 #define VGETCPU_LSL    2
 
-#define hpet_readl(a)           readl((const void __iomem *)fix_to_virt(FIX_HPET_BASE) + a)
-#define hpet_writel(d,a)        writel(d, (void __iomem *)fix_to_virt(FIX_HPET_BASE) + a)
-
 extern int __vgetcpu_mode;
 extern volatile unsigned long __jiffies;
 
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 c043c1ccf1c5098530bfef18941db54b716131b7..a4f373f8b79863e88c57b711b00bf5766bede086 100644 (file)
@@ -230,6 +230,12 @@ enum {
 
        SETFEATURES_SPINUP      = 0x07, /* Spin-up drive */
 
+       SETFEATURES_SATA_ENABLE = 0x10, /* Enable use of SATA feature */
+       SETFEATURES_SATA_DISABLE = 0x90, /* Disable use of SATA feature */
+
+       /* SETFEATURE Sector counts for SATA features */
+       SATA_AN                 = 0x05,  /* Asynchronous Notification */
+
        /* ATAPI stuff */
        ATAPI_PKT_DMA           = (1 << 0),
        ATAPI_DMADIR            = (1 << 2),     /* ATAPI data dir:
@@ -281,6 +287,15 @@ enum {
        SERR_PROTOCOL           = (1 << 10), /* protocol violation */
        SERR_INTERNAL           = (1 << 11), /* host internal error */
        SERR_PHYRDY_CHG         = (1 << 16), /* PHY RDY changed */
+       SERR_PHY_INT_ERR        = (1 << 17), /* PHY internal error */
+       SERR_COMM_WAKE          = (1 << 18), /* Comm wake */
+       SERR_10B_8B_ERR         = (1 << 19), /* 10b to 8b decode error */
+       SERR_DISPARITY          = (1 << 20), /* Disparity */
+       SERR_CRC                = (1 << 21), /* CRC error */
+       SERR_HANDSHAKE          = (1 << 22), /* Handshake error */
+       SERR_LINK_SEQ_ERR       = (1 << 23), /* Link sequence error */
+       SERR_TRANS_ST_ERROR     = (1 << 24), /* Transport state trans. error */
+       SERR_UNRECOG_FIS        = (1 << 25), /* Unrecognized FIS */
        SERR_DEV_XCHG           = (1 << 26), /* device exchanged */
 
        /* struct ata_taskfile flags */
@@ -341,24 +356,17 @@ struct ata_taskfile {
 };
 
 #define ata_id_is_ata(id)      (((id)[0] & (1 << 15)) == 0)
-#define ata_id_rahead_enabled(id) ((id)[85] & (1 << 6))
-#define ata_id_wcache_enabled(id) ((id)[85] & (1 << 5))
-#define ata_id_hpa_enabled(id) ((id)[85] & (1 << 10))
-#define ata_id_has_fua(id)     ((id)[84] & (1 << 6))
-#define ata_id_has_flush(id)   ((id)[83] & (1 << 12))
-#define ata_id_has_flush_ext(id) ((id)[83] & (1 << 13))
-#define ata_id_has_lba48(id)   ((id)[83] & (1 << 10))
-#define ata_id_has_hpa(id)     ((id)[82] & (1 << 10))
-#define ata_id_has_wcache(id)  ((id)[82] & (1 << 5))
-#define ata_id_has_pm(id)      ((id)[82] & (1 << 3))
 #define ata_id_has_lba(id)     ((id)[49] & (1 << 9))
 #define ata_id_has_dma(id)     ((id)[49] & (1 << 8))
 #define ata_id_has_ncq(id)     ((id)[76] & (1 << 8))
 #define ata_id_queue_depth(id) (((id)[75] & 0x1f) + 1)
 #define ata_id_removeable(id)  ((id)[0] & (1 << 7))
-#define ata_id_has_dword_io(id)        ((id)[50] & (1 << 0))
+#define ata_id_has_dword_io(id)        ((id)[48] & (1 << 0))
+#define ata_id_has_atapi_AN(id)        \
+       ( (((id)[76] != 0x0000) && ((id)[76] != 0xffff)) && \
+         ((id)[78] & (1 << 5)) )
 #define ata_id_iordy_disable(id) ((id)[49] & (1 << 10))
-#define ata_id_has_iordy(id) ((id)[49] & (1 << 9))
+#define ata_id_has_iordy(id) ((id)[49] & (1 << 11))
 #define ata_id_u32(id,n)       \
        (((u32) (id)[(n) + 1] << 16) | ((u32) (id)[(n)]))
 #define ata_id_u64(id,n)       \
@@ -369,6 +377,90 @@ struct ata_taskfile {
 
 #define ata_id_cdb_intr(id)    (((id)[0] & 0x60) == 0x20)
 
+static inline int ata_id_has_fua(const u16 *id)
+{
+       if ((id[84] & 0xC000) != 0x4000)
+               return 0;
+       return id[84] & (1 << 6);
+}
+
+static inline int ata_id_has_flush(const u16 *id)
+{
+       if ((id[83] & 0xC000) != 0x4000)
+               return 0;
+       return id[83] & (1 << 12);
+}
+
+static inline int ata_id_has_flush_ext(const u16 *id)
+{
+       if ((id[83] & 0xC000) != 0x4000)
+               return 0;
+       return id[83] & (1 << 13);
+}
+
+static inline int ata_id_has_lba48(const u16 *id)
+{
+       if ((id[83] & 0xC000) != 0x4000)
+               return 0;
+       return id[83] & (1 << 10);
+}
+
+static inline int ata_id_hpa_enabled(const u16 *id)
+{
+       /* Yes children, word 83 valid bits cover word 82 data */
+       if ((id[83] & 0xC000) != 0x4000)
+               return 0;
+       /* And 87 covers 85-87 */
+       if ((id[87] & 0xC000) != 0x4000)
+               return 0;
+       /* Check command sets enabled as well as supported */
+       if ((id[85] & ( 1 << 10)) == 0)
+               return 0;
+       return id[82] & (1 << 10);
+}
+
+static inline int ata_id_has_wcache(const u16 *id)
+{
+       /* Yes children, word 83 valid bits cover word 82 data */
+       if ((id[83] & 0xC000) != 0x4000)
+               return 0;
+       return id[82] & (1 << 5);
+}
+
+static inline int ata_id_has_pm(const u16 *id)
+{
+       if ((id[83] & 0xC000) != 0x4000)
+               return 0;
+       return id[82] & (1 << 3);
+}
+
+static inline int ata_id_rahead_enabled(const u16 *id)
+{
+       if ((id[87] & 0xC000) != 0x4000)
+               return 0;
+       return id[85] & (1 << 6);
+}
+
+static inline int ata_id_wcache_enabled(const u16 *id)
+{
+       if ((id[87] & 0xC000) != 0x4000)
+               return 0;
+       return id[85] & (1 << 5);
+}
+
+/**
+ *     ata_id_major_version    -       get ATA level of drive
+ *     @id: Identify data
+ *
+ *     Caveats:
+ *             ATA-1 considers identify optional
+ *             ATA-2 introduces mandatory identify
+ *             ATA-3 introduces word 80 and accurate reporting
+ *
+ *     The practical impact of this is that ata_id_major_version cannot
+ *     reliably report on drives below ATA3. 
+ */
+
 static inline unsigned int ata_id_major_version(const u16 *id)
 {
        unsigned int mver;
index 95be0ac57e76b9276b0a9bd1d79dc09398704fac..5ed888b04b29b4360b55cecf975e01f5094499d1 100644 (file)
 
 #include <asm/scatterlist.h>
 
-#ifdef CONFIG_LBD
-# include <asm/div64.h>
-# define sector_div(a, b) do_div(a, b)
-#else
-# define sector_div(n, b)( \
-{ \
-       int _res; \
-       _res = (n) % (b); \
-       (n) /= (b); \
-       _res; \
-} \
-)
-#endif
-
 struct scsi_ioctl_command;
 
 struct request_queue;
index 2e105a12fe291ee730a2b9fb72f23f632e1aac7b..7e11d23ac36a40db833cdb3bbd6788c92439bc7c 100644 (file)
@@ -290,12 +290,7 @@ static inline void blk_add_trace_remap(struct request_queue *q, struct bio *bio,
 #define blk_add_trace_generic(q, rq, rw, what) do { } while (0)
 #define blk_add_trace_pdu_int(q, what, bio, pdu)       do { } while (0)
 #define blk_add_trace_remap(q, bio, dev, f, t) do {} while (0)
-static inline int do_blk_trace_setup(struct request_queue *q,
-                                    struct block_device *bdev,
-                                    struct blk_user_trace_setup *buts)
-{
-       return 0;
-}
+#define do_blk_trace_setup(q, bdev, buts)      (-ENOTTY)
 #endif /* CONFIG_BLK_DEV_IO_TRACE */
 #endif /* __KERNEL__ */
 #endif
index def5a659b8a53653b194844242404bdeb78d916c..c33b0dc28e4db5de75df8a2419c128d22c8e29d9 100644 (file)
@@ -8,7 +8,7 @@
 #ifndef _LINUX_CLOCKCHIPS_H
 #define _LINUX_CLOCKCHIPS_H
 
-#ifdef CONFIG_GENERIC_CLOCKEVENTS
+#ifdef CONFIG_GENERIC_CLOCKEVENTS_BUILD
 
 #include <linux/clocksource.h>
 #include <linux/cpumask.h>
@@ -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,
@@ -126,11 +127,14 @@ extern int clockevents_register_notifier(struct notifier_block *nb);
 extern int clockevents_program_event(struct clock_event_device *dev,
                                     ktime_t expires, ktime_t now);
 
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
 extern void clockevents_notify(unsigned long reason, void *arg);
-
 #else
+# define clockevents_notify(reason, arg) do { } while (0)
+#endif
+
+#else /* CONFIG_GENERIC_CLOCKEVENTS_BUILD */
 
-static inline void clockevents_resume_events(void) { }
 #define clockevents_notify(reason, arg) do { } while (0)
 
 #endif
index 3ec6e7ff5fbd3514cb332fac4f4ad18cab98a717..23932d7741a996721162dc264290adbed5248f6a 100644 (file)
  *                     CPUFREQ NOTIFIER INTERFACE                    *
  *********************************************************************/
 
-int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list);
-int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list);
-
 #define CPUFREQ_TRANSITION_NOTIFIER    (0)
 #define CPUFREQ_POLICY_NOTIFIER                (1)
 
+#ifdef CONFIG_CPU_FREQ
+int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list);
+int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list);
+#else          /* CONFIG_CPU_FREQ */
+static inline int cpufreq_register_notifier(struct notifier_block *nb,
+                                               unsigned int list)
+{
+       return 0;
+}
+static inline int cpufreq_unregister_notifier(struct notifier_block *nb,
+                                               unsigned int list)
+{
+       return 0;
+}
+#endif         /* CONFIG_CPU_FREQ */
 
 /* if (cpufreq_driver->target) exists, the ->governor decides what frequency
  * within the limits is used. If (cpufreq_driver->setpolicy> exists, these
@@ -155,6 +167,9 @@ struct cpufreq_governor {
        char    name[CPUFREQ_NAME_LEN];
        int     (*governor)     (struct cpufreq_policy *policy,
                                 unsigned int event);
+       unsigned int max_transition_latency; /* HW must be able to switch to
+                       next freq faster than this value in nano secs or we
+                       will fallback to performance governor */
        struct list_head        governor_list;
        struct module           *owner;
 };
@@ -279,12 +294,24 @@ static inline unsigned int cpufreq_quick_get(unsigned int cpu)
  *********************************************************************/
 
 
-#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE
+/*
+  Performance governor is fallback governor if any other gov failed to
+  auto load due latency restrictions
+*/
+#ifdef CONFIG_CPU_FREQ_GOV_PERFORMANCE
 extern struct cpufreq_governor cpufreq_gov_performance;
-#define CPUFREQ_DEFAULT_GOVERNOR       &cpufreq_gov_performance
+#endif
+#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE
+#define CPUFREQ_DEFAULT_GOVERNOR       (&cpufreq_gov_performance)
 #elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE)
 extern struct cpufreq_governor cpufreq_gov_userspace;
-#define CPUFREQ_DEFAULT_GOVERNOR       &cpufreq_gov_userspace
+#define CPUFREQ_DEFAULT_GOVERNOR       (&cpufreq_gov_userspace)
+#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND)
+extern struct cpufreq_governor cpufreq_gov_ondemand;
+#define CPUFREQ_DEFAULT_GOVERNOR       (&cpufreq_gov_ondemand)
+#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE)
+extern struct cpufreq_governor cpufreq_gov_conservative;
+#define CPUFREQ_DEFAULT_GOVERNOR       (&cpufreq_gov_conservative)
 #endif
 
 
index 104e51e20e14a56b67e97b868e1bf2847d8b1f91..f592d6de3b971592a2b289e57175d776c212f3b1 100644 (file)
@@ -49,6 +49,12 @@ struct dentry *debugfs_create_u32(const char *name, mode_t mode,
                                  struct dentry *parent, u32 *value);
 struct dentry *debugfs_create_u64(const char *name, mode_t mode,
                                  struct dentry *parent, u64 *value);
+struct dentry *debugfs_create_x8(const char *name, mode_t mode,
+                                struct dentry *parent, u8 *value);
+struct dentry *debugfs_create_x16(const char *name, mode_t mode,
+                                 struct dentry *parent, u16 *value);
+struct dentry *debugfs_create_x32(const char *name, mode_t mode,
+                                 struct dentry *parent, u32 *value);
 struct dentry *debugfs_create_bool(const char *name, mode_t mode,
                                  struct dentry *parent, u32 *value);
 
@@ -122,6 +128,27 @@ static inline struct dentry *debugfs_create_u64(const char *name, mode_t mode,
        return ERR_PTR(-ENODEV);
 }
 
+static inline struct dentry *debugfs_create_x8(const char *name, mode_t mode,
+                                              struct dentry *parent,
+                                              u8 *value)
+{
+       return ERR_PTR(-ENODEV);
+}
+
+static inline struct dentry *debugfs_create_x16(const char *name, mode_t mode,
+                                               struct dentry *parent,
+                                               u16 *value)
+{
+       return ERR_PTR(-ENODEV);
+}
+
+static inline struct dentry *debugfs_create_x32(const char *name, mode_t mode,
+                                               struct dentry *parent,
+                                               u32 *value)
+{
+       return ERR_PTR(-ENODEV);
+}
+
 static inline struct dentry *debugfs_create_bool(const char *name, mode_t mode,
                                                 struct dentry *parent,
                                                 u32 *value)
index 3a38d1f70cb7c070faa253a2173db130a43917b6..2e15822fe40931cb88eb627971f1a5db41f9c892 100644 (file)
@@ -64,12 +64,9 @@ struct bus_type {
        struct bus_attribute    * bus_attrs;
        struct device_attribute * dev_attrs;
        struct driver_attribute * drv_attrs;
-       struct bus_attribute drivers_autoprobe_attr;
-       struct bus_attribute drivers_probe_attr;
 
        int             (*match)(struct device * dev, struct device_driver * drv);
-       int             (*uevent)(struct device *dev, char **envp,
-                                 int num_envp, char *buffer, int buffer_size);
+       int             (*uevent)(struct device *dev, struct kobj_uevent_env *env);
        int             (*probe)(struct device * dev);
        int             (*remove)(struct device * dev);
        void            (*shutdown)(struct device * dev);
@@ -189,10 +186,8 @@ struct class {
        struct class_device_attribute   * class_dev_attrs;
        struct device_attribute         * dev_attrs;
 
-       int     (*uevent)(struct class_device *dev, char **envp,
-                          int num_envp, char *buffer, int buffer_size);
-       int     (*dev_uevent)(struct device *dev, char **envp, int num_envp,
-                               char *buffer, int buffer_size);
+       int     (*uevent)(struct class_device *dev, struct kobj_uevent_env *env);
+       int     (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);
 
        void    (*release)(struct class_device *dev);
        void    (*class_release)(struct class *class);
@@ -268,8 +263,7 @@ struct class_device {
        struct attribute_group  ** groups;      /* optional groups */
 
        void    (*release)(struct class_device *dev);
-       int     (*uevent)(struct class_device *dev, char **envp,
-                          int num_envp, char *buffer, int buffer_size);
+       int     (*uevent)(struct class_device *dev, struct kobj_uevent_env *env);
        char    class_id[BUS_ID_SIZE];  /* unique to this class */
 };
 
@@ -337,8 +331,7 @@ extern void class_device_destroy(struct class *cls, dev_t devt);
 struct device_type {
        const char *name;
        struct attribute_group **groups;
-       int (*uevent)(struct device *dev, char **envp, int num_envp,
-                     char *buffer, int buffer_size);
+       int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
        void (*release)(struct device *dev);
        int (*suspend)(struct device * dev, pm_message_t state);
        int (*resume)(struct device * dev);
index a44a6a078f0a68b487ff6d049c71b6ceea154a05..c3c19f926e6f37cdcca6ab95e6ea06a5b0522462 100644 (file)
@@ -169,6 +169,33 @@ struct gfs2_rgrp {
        __u8 rg_reserved[80]; /* Several fields from gfs1 now reserved */
 };
 
+/*
+ * quota linked list: user quotas and group quotas form two separate 
+ * singly linked lists. ll_next stores uids or gids of next quotas in the 
+ * linked list.
+
+Given the uid/gid, how to calculate the quota file offsets for the corresponding
+gfs2_quota structures on disk:
+
+for user quotas, given uid,
+offset = uid * sizeof(struct gfs2_quota);
+
+for group quotas, given gid,
+offset = (gid * sizeof(struct gfs2_quota)) + sizeof(struct gfs2_quota);
+
+
+  uid:0   gid:0       uid:12   gid:12      uid:17   gid:17     uid:5142 gid:5142
++-------+-------+    +-------+-------+    +-------+- - - -+    +- - - -+-------+
+| valid | valid | :: | valid | valid | :: | valid | inval | :: | inval | valid |
++-------+-------+    +-------+-------+    +-------+- - - -+    +- - - -+-------+
+next:12   next:12    next:17 next:5142    next:NULL                    next:NULL
+    |       |            |       |            |<-- user quota list         |
+     \______|___________/ \______|___________/         group quota list -->|
+            |                    |                                         |
+             \__________________/ \_______________________________________/
+
+*/
+
 /*
  * quota structure
  */
@@ -177,7 +204,8 @@ struct gfs2_quota {
        __be64 qu_limit;
        __be64 qu_warn;
        __be64 qu_value;
-       __u8 qu_reserved[64];
+       __be32 qu_ll_next; /* location of next quota in list */
+       __u8 qu_reserved[60];
 };
 
 /*
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 6eb3aead7f1d93775ba4020e9d252df5210c757a..52d1bd434a500abb69f5cc94b8225bf856080f5d 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 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 c080f61fb024fb053e111a8878d9c7b12788c001..d7a5e034c3a219197007df6923e9a79507762022 100644 (file)
@@ -36,8 +36,6 @@
 /* LATCH is used in the interval timer and ftape setup. */
 #define LATCH  ((CLOCK_TICK_RATE + HZ/2) / HZ) /* For divider */
 
-#define LATCH_HPET ((HPET_TICK_RATE + HZ/2) / HZ)
-
 /* Suppose we want to devide two numbers NOM and DEN: NOM/DEN, the we can
  * improve accuracy by shifting LSH bits, hence calculating:
  *     (NOM << LSH) / DEN
 /* HZ is the requested value. ACTHZ is actual HZ ("<< 8" is for accuracy) */
 #define ACTHZ (SH_DIV (CLOCK_TICK_RATE, LATCH, 8))
 
-#define ACTHZ_HPET (SH_DIV (HPET_TICK_RATE, LATCH_HPET, 8))
-
 /* TICK_NSEC is the time between ticks in nsec assuming real ACTHZ */
 #define TICK_NSEC (SH_DIV (1000000UL * 1000, ACTHZ, 8))
 
-#define TICK_NSEC_HPET (SH_DIV(1000000UL * 1000, ACTHZ_HPET, 8))
-
 /* TICK_USEC is the time between ticks in usec assuming fake USER_HZ */
 #define TICK_USEC ((1000000UL + USER_HZ/2) / USER_HZ)
 
index 47160fe378c98f84b5c5295a7f987744f163a956..d9725a28a2655d14919906359198e0685e98e56c 100644 (file)
@@ -42,6 +42,20 @@ extern const char linux_proc_banner[];
 #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
 #define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
 
+#ifdef CONFIG_LBD
+# include <asm/div64.h>
+# define sector_div(a, b) do_div(a, b)
+#else
+# define sector_div(n, b)( \
+{ \
+       int _res; \
+       _res = (n) % (b); \
+       (n) /= (b); \
+       _res; \
+} \
+)
+#endif
+
 /**
  * upper_32_bits - return bits 32-63 of a number
  * @n: the number we're accessing
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 949706c33622dfca669418f4fa3e0551bc79c529..4a0d27f475d7485ba13ee691b9b3978b7a3ed9a8 100644 (file)
@@ -1,8 +1,10 @@
 /*
  * kobject.h - generic kernel object infrastructure.
  *
- * Copyright (c) 2002-2003     Patrick Mochel
- * Copyright (c) 2002-2003     Open Source Development Labs
+ * Copyright (c) 2002-2003 Patrick Mochel
+ * Copyright (c) 2002-2003 Open Source Development Labs
+ * Copyright (c) 2006-2007 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (c) 2006-2007 Novell Inc.
  *
  * This file is released under the GPLv2.
  *
@@ -29,6 +31,8 @@
 
 #define KOBJ_NAME_LEN                  20
 #define UEVENT_HELPER_PATH_LEN         256
+#define UEVENT_NUM_ENVP                        32      /* number of env pointers */
+#define UEVENT_BUFFER_SIZE             2048    /* buffer for the variables */
 
 /* path to the userspace helper executed on an event */
 extern char uevent_helper[];
@@ -56,19 +60,14 @@ enum kobject_action {
        KOBJ_MAX
 };
 
-/* The list of strings defining the valid kobject actions as specified above */
-extern const char *kobject_actions[];
-
 struct kobject {
        const char              * k_name;
-       char                    name[KOBJ_NAME_LEN];
        struct kref             kref;
        struct list_head        entry;
        struct kobject          * parent;
        struct kset             * kset;
        struct kobj_type        * ktype;
        struct sysfs_dirent     * sd;
-       wait_queue_head_t       poll;
 };
 
 extern int kobject_set_name(struct kobject *, const char *, ...)
@@ -83,14 +82,9 @@ extern void kobject_init(struct kobject *);
 extern void kobject_cleanup(struct kobject *);
 
 extern int __must_check kobject_add(struct kobject *);
-extern int __must_check kobject_shadow_add(struct kobject *kobj,
-                                          struct sysfs_dirent *shadow_parent);
 extern void kobject_del(struct kobject *);
 
 extern int __must_check kobject_rename(struct kobject *, const char *new_name);
-extern int __must_check kobject_shadow_rename(struct kobject *kobj,
-                                             struct sysfs_dirent *new_parent,
-                                             const char *new_name);
 extern int __must_check kobject_move(struct kobject *, struct kobject *);
 
 extern int __must_check kobject_register(struct kobject *);
@@ -111,36 +105,44 @@ struct kobj_type {
        struct attribute        ** default_attrs;
 };
 
+struct kobj_uevent_env {
+       char *envp[UEVENT_NUM_ENVP];
+       int envp_idx;
+       char buf[UEVENT_BUFFER_SIZE];
+       int buflen;
+};
+
 struct kset_uevent_ops {
        int (*filter)(struct kset *kset, struct kobject *kobj);
        const char *(*name)(struct kset *kset, struct kobject *kobj);
-       int (*uevent)(struct kset *kset, struct kobject *kobj, char **envp,
-                       int num_envp, char *buffer, int buffer_size);
+       int (*uevent)(struct kset *kset, struct kobject *kobj,
+                     struct kobj_uevent_env *env);
 };
 
-/*
- *     struct kset - a set of kobjects of a specific type, belonging
- *     to a specific subsystem.
- *
- *     All kobjects of a kset should be embedded in an identical 
- *     type. This type may have a descriptor, which the kset points
- *     to. This allows there to exist sets of objects of the same
- *     type in different subsystems.
+/**
+ * struct kset - a set of kobjects of a specific type, belonging to a specific subsystem.
  *
- *     A subsystem does not have to be a list of only one type 
- *     of object; multiple ksets can belong to one subsystem. All 
- *     ksets of a subsystem share the subsystem's lock.
+ * A kset defines a group of kobjects.  They can be individually
+ * different "types" but overall these kobjects all want to be grouped
+ * together and operated on in the same manner.  ksets are used to
+ * define the attribute callbacks and other common events that happen to
+ * a kobject.
  *
- *     Each kset can support specific event variables; it can
- *     supress the event generation or add subsystem specific
- *     variables carried with the event.
+ * @ktype: the struct kobj_type for this specific kset
+ * @list: the list of all kobjects for this kset
+ * @list_lock: a lock for iterating over the kobjects
+ * @kobj: the embedded kobject for this kset (recursion, isn't it fun...)
+ * @uevent_ops: the set of uevent operations for this kset.  These are
+ * called whenever a kobject has something happen to it so that the kset
+ * can add new environment variables, or filter out the uevents if so
+ * desired.
  */
 struct kset {
-       struct kobj_type        * ktype;
+       struct kobj_type        *ktype;
        struct list_head        list;
        spinlock_t              list_lock;
        struct kobject          kobj;
-       struct kset_uevent_ops  * uevent_ops;
+       struct kset_uevent_ops  *uevent_ops;
 };
 
 
@@ -179,18 +181,18 @@ extern struct kobject * kset_find_obj(struct kset *, const char *);
  * Use this when initializing an embedded kset with no other 
  * fields to initialize.
  */
-#define set_kset_name(str)     .kset = { .kobj = { .name = str } }
+#define set_kset_name(str)     .kset = { .kobj = { .k_name = str } }
 
 
 #define decl_subsys(_name,_type,_uevent_ops) \
 struct kset _name##_subsys = { \
-       .kobj = { .name = __stringify(_name) }, \
+       .kobj = { .k_name = __stringify(_name) }, \
        .ktype = _type, \
        .uevent_ops =_uevent_ops, \
 }
 #define decl_subsys_name(_varname,_name,_type,_uevent_ops) \
 struct kset _varname##_subsys = { \
-       .kobj = { .name = __stringify(_name) }, \
+       .kobj = { .k_name = __stringify(_name) }, \
        .ktype = _type, \
        .uevent_ops =_uevent_ops, \
 }
@@ -218,49 +220,9 @@ extern struct kset hypervisor_subsys;
 #define kobj_set_kset_s(obj,subsys) \
        (obj)->kobj.kset = &(subsys)
 
-/**
- *     kset_set_kset_s(obj,subsys) - set kset for embedded kset.
- *     @obj:           ptr to some object type.
- *     @subsys:        a subsystem object (not a ptr).
- *
- *     Can be used for any object type with an embedded ->kset.
- *     Sets the kset of @obj's  embedded kobject (via its embedded
- *     kset) to @subsys.kset. This makes @obj a member of that 
- *     kset.
- */
-
-#define kset_set_kset_s(obj,subsys) \
-       (obj)->kset.kobj.kset = &(subsys)
-
-/**
- *     subsys_set_kset(obj,subsys) - set kset for subsystem
- *     @obj:           ptr to some object type.
- *     @_subsys:       a subsystem object (not a ptr).
- *
- *     Can be used for any object type with an embedded ->subsys.
- *     Sets the kset of @obj's kobject to @subsys.kset. This makes
- *     the object a member of that kset.
- */
-
-#define subsys_set_kset(obj,_subsys) \
-       (obj)->subsys.kobj.kset = &(_subsys)
-
-extern void subsystem_init(struct kset *);
 extern int __must_check subsystem_register(struct kset *);
 extern void subsystem_unregister(struct kset *);
 
-static inline struct kset *subsys_get(struct kset *s)
-{
-       if (s)
-               return kset_get(s);
-       return NULL;
-}
-
-static inline void subsys_put(struct kset *s)
-{
-       kset_put(s);
-}
-
 struct subsys_attribute {
        struct attribute attr;
        ssize_t (*show)(struct kset *, char *);
@@ -275,10 +237,11 @@ int kobject_uevent(struct kobject *kobj, enum kobject_action action);
 int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
                        char *envp[]);
 
-int add_uevent_var(char **envp, int num_envp, int *cur_index,
-                       char *buffer, int buffer_size, int *cur_len,
-                       const char *format, ...)
-       __attribute__((format (printf, 7, 8)));
+int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...)
+       __attribute__((format (printf, 2, 3)));
+
+int kobject_action_type(const char *buf, size_t count,
+                       enum kobject_action *type);
 #else
 static inline int kobject_uevent(struct kobject *kobj, enum kobject_action action)
 { return 0; }
@@ -287,10 +250,12 @@ static inline int kobject_uevent_env(struct kobject *kobj,
                                      char *envp[])
 { return 0; }
 
-static inline int add_uevent_var(char **envp, int num_envp, int *cur_index,
-                                     char *buffer, int buffer_size, int *cur_len, 
-                                     const char *format, ...)
+static inline int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...)
 { return 0; }
+
+static inline int kobject_action_type(const char *buf, size_t count,
+                       enum kobject_action *type)
+{ return -EINVAL; }
 #endif
 
 #endif /* __KERNEL__ */
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 a67bb9075e9bbd0023a42e2ede2ed8b0fa601c52..229a9ff9f9241995e5e22ef4ead50394c76f3bb3 100644 (file)
@@ -28,7 +28,6 @@
 
 #include <linux/delay.h>
 #include <linux/interrupt.h>
-#include <linux/pci.h>
 #include <linux/dma-mapping.h>
 #include <asm/scatterlist.h>
 #include <linux/io.h>
@@ -107,12 +106,6 @@ static inline u32 ata_msg_init(int dval, int default_msg_enable_bits)
 /* defines only for the constants which don't work well as enums */
 #define ATA_TAG_POISON         0xfafbfcfdU
 
-/* move to PCI layer? */
-static inline struct device *pci_dev_to_dev(struct pci_dev *pdev)
-{
-       return &pdev->dev;
-}
-
 enum {
        /* various global constants */
        LIBATA_MAX_PRD          = ATA_MAX_PRD / 2,
@@ -139,11 +132,12 @@ enum {
        ATA_DFLAG_FLUSH_EXT     = (1 << 4), /* do FLUSH_EXT instead of FLUSH */
        ATA_DFLAG_ACPI_PENDING  = (1 << 5), /* ACPI resume action pending */
        ATA_DFLAG_ACPI_FAILED   = (1 << 6), /* ACPI on devcfg has failed */
-       ATA_DFLAG_CFG_MASK      = (1 << 8) - 1,
+       ATA_DFLAG_AN            = (1 << 7), /* AN configured */
+       ATA_DFLAG_CFG_MASK      = (1 << 12) - 1,
 
-       ATA_DFLAG_PIO           = (1 << 8), /* device limited to PIO mode */
-       ATA_DFLAG_NCQ_OFF       = (1 << 9), /* device limited to non-NCQ mode */
-       ATA_DFLAG_SPUNDOWN      = (1 << 10), /* XXX: for spindown_compat */
+       ATA_DFLAG_PIO           = (1 << 12), /* device limited to PIO mode */
+       ATA_DFLAG_NCQ_OFF       = (1 << 13), /* device limited to non-NCQ mode */
+       ATA_DFLAG_SPUNDOWN      = (1 << 14), /* XXX: for spindown_compat */
        ATA_DFLAG_INIT_MASK     = (1 << 16) - 1,
 
        ATA_DFLAG_DETACH        = (1 << 16),
@@ -154,7 +148,22 @@ enum {
        ATA_DEV_ATA_UNSUP       = 2,    /* ATA device (unsupported) */
        ATA_DEV_ATAPI           = 3,    /* ATAPI device */
        ATA_DEV_ATAPI_UNSUP     = 4,    /* ATAPI device (unsupported) */
-       ATA_DEV_NONE            = 5,    /* no device */
+       ATA_DEV_PMP             = 5,    /* SATA port multiplier */
+       ATA_DEV_PMP_UNSUP       = 6,    /* SATA port multiplier (unsupported) */
+       ATA_DEV_SEMB            = 7,    /* SEMB */
+       ATA_DEV_SEMB_UNSUP      = 8,    /* SEMB (unsupported) */
+       ATA_DEV_NONE            = 9,    /* no device */
+
+       /* struct ata_link flags */
+       ATA_LFLAG_HRST_TO_RESUME = (1 << 0), /* hardreset to resume link */
+       ATA_LFLAG_SKIP_D2H_BSY  = (1 << 1), /* can't wait for the first D2H
+                                            * Register FIS clearing BSY */
+       ATA_LFLAG_NO_SRST       = (1 << 2), /* avoid softreset */
+       ATA_LFLAG_ASSUME_ATA    = (1 << 3), /* assume ATA class */
+       ATA_LFLAG_ASSUME_SEMB   = (1 << 4), /* assume SEMB class */
+       ATA_LFLAG_ASSUME_CLASS  = ATA_LFLAG_ASSUME_ATA | ATA_LFLAG_ASSUME_SEMB,
+       ATA_LFLAG_NO_RETRY      = (1 << 5), /* don't retry this link */
+       ATA_LFLAG_DISABLED      = (1 << 6), /* link is disabled */
 
        /* struct ata_port flags */
        ATA_FLAG_SLAVE_POSS     = (1 << 0), /* host supports slave dev */
@@ -170,13 +179,12 @@ enum {
        ATA_FLAG_PIO_POLLING    = (1 << 9), /* use polling PIO if LLD
                                             * doesn't handle PIO interrupts */
        ATA_FLAG_NCQ            = (1 << 10), /* host supports NCQ */
-       ATA_FLAG_HRST_TO_RESUME = (1 << 11), /* hardreset to resume phy */
-       ATA_FLAG_SKIP_D2H_BSY   = (1 << 12), /* can't wait for the first D2H
-                                             * Register FIS clearing BSY */
        ATA_FLAG_DEBUGMSG       = (1 << 13),
        ATA_FLAG_IGN_SIMPLEX    = (1 << 15), /* ignore SIMPLEX */
        ATA_FLAG_NO_IORDY       = (1 << 16), /* controller lacks iordy */
        ATA_FLAG_ACPI_SATA      = (1 << 17), /* need native SATA ACPI layout */
+       ATA_FLAG_AN             = (1 << 18), /* controller supports AN */
+       ATA_FLAG_PMP            = (1 << 19), /* controller supports PMP */
 
        /* The following flag belongs to ap->pflags but is kept in
         * ap->flags because it's referenced in many LLDs and will be
@@ -195,6 +203,7 @@ enum {
        ATA_PFLAG_UNLOADING     = (1 << 5), /* module is unloading */
        ATA_PFLAG_SCSI_HOTPLUG  = (1 << 6), /* SCSI hotplug scheduled */
        ATA_PFLAG_INITIALIZING  = (1 << 7), /* being initialized, don't touch */
+       ATA_PFLAG_RESETTING     = (1 << 8), /* reset in progress */
 
        ATA_PFLAG_SUSPENDED     = (1 << 17), /* port is suspended (power) */
        ATA_PFLAG_PM_PENDING    = (1 << 18), /* PM operation pending */
@@ -207,6 +216,7 @@ enum {
        ATA_QCFLAG_DMAMAP       = ATA_QCFLAG_SG | ATA_QCFLAG_SINGLE,
        ATA_QCFLAG_IO           = (1 << 3), /* standard IO command */
        ATA_QCFLAG_RESULT_TF    = (1 << 4), /* result TF requested */
+       ATA_QCFLAG_CLEAR_EXCL   = (1 << 5), /* clear excl_link on completion */
 
        ATA_QCFLAG_FAILED       = (1 << 16), /* cmd failed and is owned by EH */
        ATA_QCFLAG_SENSE_VALID  = (1 << 17), /* sense data valid */
@@ -263,6 +273,10 @@ enum {
        /* ering size */
        ATA_ERING_SIZE          = 32,
 
+       /* return values for ->qc_defer */
+       ATA_DEFER_LINK          = 1,
+       ATA_DEFER_PORT          = 2,
+
        /* desc_len for ata_eh_info and context */
        ATA_EH_DESC_LEN         = 80,
 
@@ -270,6 +284,7 @@ enum {
        ATA_EH_REVALIDATE       = (1 << 0),
        ATA_EH_SOFTRESET        = (1 << 1),
        ATA_EH_HARDRESET        = (1 << 2),
+       ATA_EH_ENABLE_LINK      = (1 << 3),
 
        ATA_EH_RESET_MASK       = ATA_EH_SOFTRESET | ATA_EH_HARDRESET,
        ATA_EH_PERDEV_MASK      = ATA_EH_REVALIDATE,
@@ -289,12 +304,16 @@ enum {
        ATA_EHI_DID_RESET       = ATA_EHI_DID_SOFTRESET | ATA_EHI_DID_HARDRESET,
        ATA_EHI_RESET_MODIFIER_MASK = ATA_EHI_RESUME_LINK,
 
-       /* max repeat if error condition is still set after ->error_handler */
-       ATA_EH_MAX_REPEAT       = 5,
+       /* max tries if error condition is still set after ->error_handler */
+       ATA_EH_MAX_TRIES        = 5,
 
        /* how hard are we gonna try to probe/recover devices */
        ATA_PROBE_MAX_TRIES     = 3,
        ATA_EH_DEV_TRIES        = 3,
+       ATA_EH_PMP_TRIES        = 5,
+       ATA_EH_PMP_LINK_TRIES   = 3,
+
+       SATA_PMP_SCR_TIMEOUT    = 250,
 
        /* Horkage types. May be set by libata or controller on drives
           (some horkage may be drive/controller pair dependant */
@@ -304,6 +323,14 @@ enum {
        ATA_HORKAGE_NONCQ       = (1 << 2),     /* Don't use NCQ */
        ATA_HORKAGE_MAX_SEC_128 = (1 << 3),     /* Limit max sects to 128 */
        ATA_HORKAGE_BROKEN_HPA  = (1 << 4),     /* Broken HPA */
+       ATA_HORKAGE_SKIP_PM     = (1 << 5),     /* Skip PM operations */
+       ATA_HORKAGE_HPA_SIZE    = (1 << 6),     /* native size off by one */
+
+        /* DMA mask for user DMA control: User visible values; DO NOT 
+           renumber */
+       ATA_DMA_MASK_ATA        = (1 << 0),     /* DMA on ATA Disk */
+       ATA_DMA_MASK_ATAPI      = (1 << 1),     /* DMA on ATAPI */
+       ATA_DMA_MASK_CFA        = (1 << 2),     /* DMA on CF Card */
 };
 
 enum hsm_task_states {
@@ -333,14 +360,15 @@ enum ata_completion_errors {
 struct scsi_device;
 struct ata_port_operations;
 struct ata_port;
+struct ata_link;
 struct ata_queued_cmd;
 
 /* typedefs */
 typedef void (*ata_qc_cb_t) (struct ata_queued_cmd *qc);
-typedef int (*ata_prereset_fn_t)(struct ata_port *ap, unsigned long deadline);
-typedef int (*ata_reset_fn_t)(struct ata_port *ap, unsigned int *classes,
+typedef int (*ata_prereset_fn_t)(struct ata_link *link, unsigned long deadline);
+typedef int (*ata_reset_fn_t)(struct ata_link *link, unsigned int *classes,
                              unsigned long deadline);
-typedef void (*ata_postreset_fn_t)(struct ata_port *ap, unsigned int *classes);
+typedef void (*ata_postreset_fn_t)(struct ata_link *link, unsigned int *classes);
 
 struct ata_ioports {
        void __iomem            *cmd_addr;
@@ -363,8 +391,6 @@ struct ata_ioports {
 struct ata_host {
        spinlock_t              lock;
        struct device           *dev;
-       unsigned long           irq;
-       unsigned long           irq2;
        void __iomem * const    *iomap;
        unsigned int            n_ports;
        void                    *private_data;
@@ -436,7 +462,7 @@ struct ata_ering {
 };
 
 struct ata_device {
-       struct ata_port         *ap;
+       struct ata_link         *link;
        unsigned int            devno;          /* 0 or 1 */
        unsigned long           flags;          /* ATA_DFLAG_xxx */
        unsigned int            horkage;        /* List of broken features */
@@ -447,7 +473,12 @@ struct ata_device {
        /* n_sector is used as CLEAR_OFFSET, read comment above CLEAR_OFFSET */
        u64                     n_sectors;      /* size of device, if ATA */
        unsigned int            class;          /* ATA_DEV_xxx */
-       u16                     id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */
+
+       union {
+               u16             id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */
+               u32             gscr[SATA_PMP_GSCR_DWORDS]; /* PMP GSCR block */
+       };
+
        u8                      pio_mode;
        u8                      dma_mode;
        u8                      xfer_mode;
@@ -510,6 +541,27 @@ struct ata_acpi_gtm {
        u32 flags;
 } __packed;
 
+struct ata_link {
+       struct ata_port         *ap;
+       int                     pmp;            /* port multiplier port # */
+
+       unsigned int            active_tag;     /* active tag on this link */
+       u32                     sactive;        /* active NCQ commands */
+
+       unsigned int            flags;          /* ATA_LFLAG_xxx */
+
+       unsigned int            hw_sata_spd_limit;
+       unsigned int            sata_spd_limit;
+       unsigned int            sata_spd;       /* current SATA PHY speed */
+
+       /* record runtime error info, protected by host_set lock */
+       struct ata_eh_info      eh_info;
+       /* EH context */
+       struct ata_eh_context   eh_context;
+
+       struct ata_device       device[ATA_MAX_DEVICES];
+};
+
 struct ata_port {
        struct Scsi_Host        *scsi_host; /* our co-allocated scsi host */
        const struct ata_port_operations *ops;
@@ -533,23 +585,17 @@ struct ata_port {
        unsigned int            mwdma_mask;
        unsigned int            udma_mask;
        unsigned int            cbl;    /* cable type; ATA_CBL_xxx */
-       unsigned int            hw_sata_spd_limit;
-       unsigned int            sata_spd_limit; /* SATA PHY speed limit */
-       unsigned int            sata_spd;       /* current SATA PHY speed */
-
-       /* record runtime error info, protected by host lock */
-       struct ata_eh_info      eh_info;
-       /* EH context owned by EH */
-       struct ata_eh_context   eh_context;
-
-       struct ata_device       device[ATA_MAX_DEVICES];
 
        struct ata_queued_cmd   qcmd[ATA_MAX_QUEUE];
        unsigned long           qc_allocated;
        unsigned int            qc_active;
+       int                     nr_active_links; /* #links with active qcs */
+
+       struct ata_link         link;   /* host default link */
 
-       unsigned int            active_tag;
-       u32                     sactive;
+       int                     nr_pmp_links;   /* nr of available PMP links */
+       struct ata_link         *pmp_link;      /* array of PMP links */
+       struct ata_link         *excl_link;     /* for PMP qc exclusion */
 
        struct ata_port_stats   stats;
        struct ata_host         *host;
@@ -565,6 +611,7 @@ struct ata_port {
        u32                     msg_enable;
        struct list_head        eh_done_q;
        wait_queue_head_t       eh_wait_q;
+       int                     eh_tries;
 
        pm_message_t            pm_mesg;
        int                     *pm_result;
@@ -582,8 +629,6 @@ struct ata_port {
 };
 
 struct ata_port_operations {
-       void (*port_disable) (struct ata_port *);
-
        void (*dev_config) (struct ata_device *);
 
        void (*set_piomode) (struct ata_port *, struct ata_device *);
@@ -599,7 +644,7 @@ struct ata_port_operations {
        void (*dev_select)(struct ata_port *ap, unsigned int device);
 
        void (*phy_reset) (struct ata_port *ap); /* obsolete */
-       int  (*set_mode) (struct ata_port *ap, struct ata_device **r_failed_dev);
+       int  (*set_mode) (struct ata_link *link, struct ata_device **r_failed_dev);
 
        int (*cable_detect) (struct ata_port *ap);
 
@@ -610,9 +655,14 @@ struct ata_port_operations {
 
        void (*data_xfer) (struct ata_device *, unsigned char *, unsigned int, int);
 
+       int (*qc_defer) (struct ata_queued_cmd *qc);
        void (*qc_prep) (struct ata_queued_cmd *qc);
        unsigned int (*qc_issue) (struct ata_queued_cmd *qc);
 
+       /* port multiplier */
+       void (*pmp_attach) (struct ata_port *ap);
+       void (*pmp_detach) (struct ata_port *ap);
+
        /* Error handlers.  ->error_handler overrides ->eng_timeout and
         * indicates that new-style EH is in place.
         */
@@ -626,7 +676,6 @@ struct ata_port_operations {
        irq_handler_t irq_handler;
        void (*irq_clear) (struct ata_port *);
        u8 (*irq_on) (struct ata_port *);
-       u8 (*irq_ack) (struct ata_port *ap, unsigned int chk_drq);
 
        int (*scr_read) (struct ata_port *ap, unsigned int sc_reg, u32 *val);
        int (*scr_write) (struct ata_port *ap, unsigned int sc_reg, u32 val);
@@ -646,6 +695,7 @@ struct ata_port_operations {
 struct ata_port_info {
        struct scsi_host_template       *sht;
        unsigned long           flags;
+       unsigned long           link_flags;
        unsigned long           pio_mask;
        unsigned long           mwdma_mask;
        unsigned long           udma_mask;
@@ -689,38 +739,27 @@ static inline int ata_port_is_dummy(struct ata_port *ap)
        return ap->ops == &ata_dummy_port_ops;
 }
 
-extern void sata_print_link_status(struct ata_port *ap);
+extern void sata_print_link_status(struct ata_link *link);
 extern void ata_port_probe(struct ata_port *);
 extern void __sata_phy_reset(struct ata_port *ap);
 extern void sata_phy_reset(struct ata_port *ap);
 extern void ata_bus_reset(struct ata_port *ap);
-extern int sata_set_spd(struct ata_port *ap);
-extern int sata_phy_debounce(struct ata_port *ap, const unsigned long *param,
-                            unsigned long deadline);
-extern int sata_phy_resume(struct ata_port *ap, const unsigned long *param,
-                          unsigned long deadline);
-extern int ata_std_prereset(struct ata_port *ap, unsigned long deadline);
-extern int ata_std_softreset(struct ata_port *ap, unsigned int *classes,
+extern int sata_set_spd(struct ata_link *link);
+extern int sata_link_debounce(struct ata_link *link,
+                       const unsigned long *params, unsigned long deadline);
+extern int sata_link_resume(struct ata_link *link, const unsigned long *params,
+                           unsigned long deadline);
+extern int ata_std_prereset(struct ata_link *link, unsigned long deadline);
+extern int ata_std_softreset(struct ata_link *link, unsigned int *classes,
                             unsigned long deadline);
-extern int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing,
-                              unsigned long deadline);
-extern int sata_std_hardreset(struct ata_port *ap, unsigned int *class,
+extern int sata_link_hardreset(struct ata_link *link,
+                       const unsigned long *timing, unsigned long deadline);
+extern int sata_std_hardreset(struct ata_link *link, unsigned int *class,
                              unsigned long deadline);
-extern void ata_std_postreset(struct ata_port *ap, unsigned int *classes);
+extern void ata_std_postreset(struct ata_link *link, unsigned int *classes);
 extern void ata_port_disable(struct ata_port *);
 extern void ata_std_ports(struct ata_ioports *ioaddr);
-#ifdef CONFIG_PCI
-extern int ata_pci_init_one (struct pci_dev *pdev,
-                            const struct ata_port_info * const * ppi);
-extern void ata_pci_remove_one (struct pci_dev *pdev);
-#ifdef CONFIG_PM
-extern void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t mesg);
-extern int __must_check ata_pci_device_do_resume(struct pci_dev *pdev);
-extern int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
-extern int ata_pci_device_resume(struct pci_dev *pdev);
-#endif
-extern int ata_pci_clear_simplex(struct pci_dev *pdev);
-#endif /* CONFIG_PCI */
+
 extern struct ata_host *ata_host_alloc(struct device *dev, int max_ports);
 extern struct ata_host *ata_host_alloc_pinfo(struct device *dev,
                        const struct ata_port_info * const * ppi, int n_ports);
@@ -746,12 +785,12 @@ extern int ata_sas_slave_configure(struct scsi_device *, struct ata_port *);
 extern int ata_sas_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *),
                            struct ata_port *ap);
 extern unsigned int ata_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc);
-extern int sata_scr_valid(struct ata_port *ap);
-extern int sata_scr_read(struct ata_port *ap, int reg, u32 *val);
-extern int sata_scr_write(struct ata_port *ap, int reg, u32 val);
-extern int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val);
-extern int ata_port_online(struct ata_port *ap);
-extern int ata_port_offline(struct ata_port *ap);
+extern int sata_scr_valid(struct ata_link *link);
+extern int sata_scr_read(struct ata_link *link, int reg, u32 *val);
+extern int sata_scr_write(struct ata_link *link, int reg, u32 val);
+extern int sata_scr_write_flush(struct ata_link *link, int reg, u32 val);
+extern int ata_link_online(struct ata_link *link);
+extern int ata_link_offline(struct ata_link *link);
 #ifdef CONFIG_PM
 extern int ata_host_suspend(struct ata_host *host, pm_message_t mesg);
 extern void ata_host_resume(struct ata_host *host);
@@ -765,7 +804,8 @@ extern void ata_port_queue_task(struct ata_port *ap, work_func_t fn,
 extern u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val,
                             unsigned long interval_msec,
                             unsigned long timeout_msec);
-extern unsigned int ata_dev_try_classify(struct ata_port *, unsigned int, u8 *);
+extern unsigned int ata_dev_try_classify(struct ata_device *dev, int present,
+                                        u8 *r_err);
 
 /*
  * Default driver ops implementations
@@ -787,6 +827,7 @@ extern void ata_data_xfer(struct ata_device *adev, unsigned char *buf,
                          unsigned int buflen, int write_data);
 extern void ata_data_xfer_noirq(struct ata_device *adev, unsigned char *buf,
                                unsigned int buflen, int write_data);
+extern int ata_std_qc_defer(struct ata_queued_cmd *qc);
 extern void ata_dumb_qc_prep(struct ata_queued_cmd *qc);
 extern void ata_qc_prep(struct ata_queued_cmd *qc);
 extern void ata_noop_qc_prep(struct ata_queued_cmd *qc);
@@ -830,11 +871,8 @@ extern void ata_scsi_slave_destroy(struct scsi_device *sdev);
 extern int ata_scsi_change_queue_depth(struct scsi_device *sdev,
                                       int queue_depth);
 extern struct ata_device *ata_dev_pair(struct ata_device *adev);
-extern int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev);
+extern int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev);
 extern u8 ata_irq_on(struct ata_port *ap);
-extern u8 ata_dummy_irq_on(struct ata_port *ap);
-extern u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq);
-extern u8 ata_dummy_irq_ack(struct ata_port *ap, unsigned int chk_drq);
 
 extern int ata_cable_40wire(struct ata_port *ap);
 extern int ata_cable_80wire(struct ata_port *ap);
@@ -869,8 +907,29 @@ enum {
                                  ATA_TIMING_CYCLE | ATA_TIMING_UDMA,
 };
 
+/* libata-acpi.c */
+#ifdef CONFIG_ATA_ACPI
+extern int ata_acpi_cbl_80wire(struct ata_port *ap);
+int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm);
+int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *stm);
+#else
+static inline int ata_acpi_cbl_80wire(struct ata_port *ap) { return 0; }
+#endif
 
 #ifdef CONFIG_PCI
+struct pci_dev;
+
+extern int ata_pci_init_one (struct pci_dev *pdev,
+                            const struct ata_port_info * const * ppi);
+extern void ata_pci_remove_one (struct pci_dev *pdev);
+#ifdef CONFIG_PM
+extern void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t mesg);
+extern int __must_check ata_pci_device_do_resume(struct pci_dev *pdev);
+extern int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
+extern int ata_pci_device_resume(struct pci_dev *pdev);
+#endif
+extern int ata_pci_clear_simplex(struct pci_dev *pdev);
+
 struct pci_bits {
        unsigned int            reg;    /* PCI config register to read */
        unsigned int            width;  /* 1 (8 bit), 2 (16 bit), 4 (32 bit) */
@@ -887,14 +946,30 @@ extern int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bit
 extern unsigned long ata_pci_default_filter(struct ata_device *, unsigned long);
 #endif /* CONFIG_PCI */
 
+/*
+ * PMP
+ */
+extern int sata_pmp_qc_defer_cmd_switch(struct ata_queued_cmd *qc);
+extern int sata_pmp_std_prereset(struct ata_link *link, unsigned long deadline);
+extern int sata_pmp_std_hardreset(struct ata_link *link, unsigned int *class,
+                                 unsigned long deadline);
+extern void sata_pmp_std_postreset(struct ata_link *link, unsigned int *class);
+extern void sata_pmp_do_eh(struct ata_port *ap,
+               ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
+               ata_reset_fn_t hardreset, ata_postreset_fn_t postreset,
+               ata_prereset_fn_t pmp_prereset, ata_reset_fn_t pmp_softreset,
+               ata_reset_fn_t pmp_hardreset, ata_postreset_fn_t pmp_postreset);
+
 /*
  * EH
  */
 extern void ata_eng_timeout(struct ata_port *ap);
 
 extern void ata_port_schedule_eh(struct ata_port *ap);
+extern int ata_link_abort(struct ata_link *link);
 extern int ata_port_abort(struct ata_port *ap);
 extern int ata_port_freeze(struct ata_port *ap);
+extern int sata_async_notification(struct ata_port *ap);
 
 extern void ata_eh_freeze_port(struct ata_port *ap);
 extern void ata_eh_thaw_port(struct ata_port *ap);
@@ -912,14 +987,25 @@ extern void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
 #define ata_port_printk(ap, lv, fmt, args...) \
        printk(lv"ata%u: "fmt, (ap)->print_id , ##args)
 
+#define ata_link_printk(link, lv, fmt, args...) do { \
+       if ((link)->ap->nr_pmp_links) \
+               printk(lv"ata%u.%02u: "fmt, (link)->ap->print_id, \
+                      (link)->pmp , ##args); \
+       else \
+               printk(lv"ata%u: "fmt, (link)->ap->print_id , ##args); \
+       } while(0)
+
 #define ata_dev_printk(dev, lv, fmt, args...) \
-       printk(lv"ata%u.%02u: "fmt, (dev)->ap->print_id, (dev)->devno , ##args)
+       printk(lv"ata%u.%02u: "fmt, (dev)->link->ap->print_id, \
+              (dev)->link->pmp + (dev)->devno , ##args)
 
 /*
  * ata_eh_info helpers
  */
-extern void __ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...);
-extern void ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...);
+extern void __ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...)
+       __attribute__ ((format (printf, 2, 3)));
+extern void ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...)
+       __attribute__ ((format (printf, 2, 3)));
 extern void ata_ehi_clear_desc(struct ata_eh_info *ehi);
 
 static inline void ata_ehi_schedule_probe(struct ata_eh_info *ehi)
@@ -933,9 +1019,20 @@ static inline void ata_ehi_hotplugged(struct ata_eh_info *ehi)
 {
        ata_ehi_schedule_probe(ehi);
        ehi->flags |= ATA_EHI_HOTPLUGGED;
+       ehi->action |= ATA_EH_ENABLE_LINK;
        ehi->err_mask |= AC_ERR_ATA_BUS;
 }
 
+/*
+ * port description helpers
+ */
+extern void ata_port_desc(struct ata_port *ap, const char *fmt, ...)
+       __attribute__ ((format (printf, 2, 3)));
+#ifdef CONFIG_PCI
+extern void ata_port_pbar_desc(struct ata_port *ap, int bar, ssize_t offset,
+                              const char *name);
+#endif
+
 /*
  * qc helpers
  */
@@ -991,12 +1088,14 @@ static inline unsigned int ata_tag_internal(unsigned int tag)
  */
 static inline unsigned int ata_class_enabled(unsigned int class)
 {
-       return class == ATA_DEV_ATA || class == ATA_DEV_ATAPI;
+       return class == ATA_DEV_ATA || class == ATA_DEV_ATAPI ||
+               class == ATA_DEV_PMP || class == ATA_DEV_SEMB;
 }
 
 static inline unsigned int ata_class_disabled(unsigned int class)
 {
-       return class == ATA_DEV_ATA_UNSUP || class == ATA_DEV_ATAPI_UNSUP;
+       return class == ATA_DEV_ATA_UNSUP || class == ATA_DEV_ATAPI_UNSUP ||
+               class == ATA_DEV_PMP_UNSUP || class == ATA_DEV_SEMB_UNSUP;
 }
 
 static inline unsigned int ata_class_absent(unsigned int class)
@@ -1020,15 +1119,62 @@ static inline unsigned int ata_dev_absent(const struct ata_device *dev)
 }
 
 /*
- * port helpers
+ * link helpers
  */
-static inline int ata_port_max_devices(const struct ata_port *ap)
+static inline int ata_is_host_link(const struct ata_link *link)
+{
+       return link == &link->ap->link;
+}
+
+static inline int ata_link_max_devices(const struct ata_link *link)
 {
-       if (ap->flags & ATA_FLAG_SLAVE_POSS)
+       if (ata_is_host_link(link) && link->ap->flags & ATA_FLAG_SLAVE_POSS)
                return 2;
        return 1;
 }
 
+static inline int ata_link_active(struct ata_link *link)
+{
+       return ata_tag_valid(link->active_tag) || link->sactive;
+}
+
+static inline struct ata_link *ata_port_first_link(struct ata_port *ap)
+{
+       if (ap->nr_pmp_links)
+               return ap->pmp_link;
+       return &ap->link;
+}
+
+static inline struct ata_link *ata_port_next_link(struct ata_link *link)
+{
+       struct ata_port *ap = link->ap;
+
+       if (link == &ap->link) {
+               if (!ap->nr_pmp_links)
+                       return NULL;
+               return ap->pmp_link;
+       }
+
+       if (++link - ap->pmp_link < ap->nr_pmp_links)
+               return link;
+       return NULL;
+}
+
+#define __ata_port_for_each_link(lk, ap) \
+       for ((lk) = &(ap)->link; (lk); (lk) = ata_port_next_link(lk))
+
+#define ata_port_for_each_link(link, ap) \
+       for ((link) = ata_port_first_link(ap); (link); \
+            (link) = ata_port_next_link(link))
+
+#define ata_link_for_each_dev(dev, link) \
+       for ((dev) = (link)->device; \
+            (dev) < (link)->device + ata_link_max_devices(link) || ((dev) = NULL); \
+            (dev)++)
+
+#define ata_link_for_each_dev_reverse(dev, link) \
+       for ((dev) = (link)->device + ata_link_max_devices(link) - 1; \
+            (dev) >= (link)->device || ((dev) = NULL); (dev)--)
 
 static inline u8 ata_chk_status(struct ata_port *ap)
 {
@@ -1110,9 +1256,11 @@ static inline u8 ata_wait_idle(struct ata_port *ap)
 {
        u8 status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
 
+#ifdef ATA_DEBUG
        if (status != 0xff && (status & (ATA_BUSY | ATA_DRQ)))
-               DPRINTK("ATA: abnormal status 0x%X on port 0x%p\n",
-                       status, ap->ioaddr.status_addr);
+               ata_port_printk(ap, KERN_DEBUG, "abnormal Status 0x%X\n",
+                               status);
+#endif
 
        return status;
 }
@@ -1149,7 +1297,7 @@ static inline void ata_tf_init(struct ata_device *dev, struct ata_taskfile *tf)
 {
        memset(tf, 0, sizeof(*tf));
 
-       tf->ctl = dev->ap->ctl;
+       tf->ctl = dev->link->ap->ctl;
        if (dev->devno == 0)
                tf->device = ATA_DEVICE_OBS;
        else
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 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 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 038a0dc7273abee4592afe4b6c793722c06d2cf4..768b93359f9034268dc8db53923d63bec3d86df4 100644 (file)
@@ -685,13 +685,16 @@ extern void pci_unblock_user_cfg_access(struct pci_dev *dev);
  * a PCI domain is defined to be a set of PCI busses which share
  * configuration space.
  */
-#ifndef CONFIG_PCI_DOMAINS
+#ifdef CONFIG_PCI_DOMAINS
+extern int pci_domains_supported;
+#else
+enum { pci_domains_supported = 0 };
 static inline int pci_domain_nr(struct pci_bus *bus) { return 0; }
 static inline int pci_proc_domain(struct pci_bus *bus)
 {
        return 0;
 }
-#endif
+#endif /* CONFIG_PCI_DOMAINS */
 
 #else /* CONFIG_PCI is not enabled */
 
index 3948708c42ca66156ce733dacf7b263445c094f5..2aaf1c16ce981ed83e35caa1e16f7cef3beb5a3e 100644 (file)
 #define PCI_DEVICE_ID_UMC_UM8886BF     0x673a
 #define PCI_DEVICE_ID_UMC_UM8886A      0x886a
 
+#define PCI_VENDOR_ID_PICOPOWER                0x1066
+#define PCI_DEVICE_ID_PICOPOWER_PT86C523       0x0002
+#define PCI_DEVICE_ID_PICOPOWER_PT86C523BBP    0x8002
 
 #define PCI_VENDOR_ID_MYLEX            0x1069
 #define PCI_DEVICE_ID_MYLEX_DAC960_P   0x0001
 #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
 #define PCI_DEVICE_ID_INTEL_82801EB_5  0x24d5
 #define PCI_DEVICE_ID_INTEL_82801EB_6  0x24d6
 #define PCI_DEVICE_ID_INTEL_82801EB_11 0x24db
+#define PCI_DEVICE_ID_INTEL_82801EB_12 0x24dc
 #define PCI_DEVICE_ID_INTEL_82801EB_13 0x24dd
 #define PCI_DEVICE_ID_INTEL_ESB_1      0x25a1
 #define PCI_DEVICE_ID_INTEL_ESB_2      0x25a2
index 423d592c55d5a6827e6b3719b0a7b7e570e2099d..c1914a8b94a975fa5360722536b49a3746c29028 100644 (file)
 #define PCI_BRIDGE_CONTROL     0x3e
 #define  PCI_BRIDGE_CTL_PARITY 0x01    /* Enable parity detection on secondary interface */
 #define  PCI_BRIDGE_CTL_SERR   0x02    /* The same for SERR forwarding */
-#define  PCI_BRIDGE_CTL_NO_ISA 0x04    /* Disable bridging of ISA ports */
+#define  PCI_BRIDGE_CTL_ISA    0x04    /* Enable ISA mode */
 #define  PCI_BRIDGE_CTL_VGA    0x08    /* Forward VGA addresses */
 #define  PCI_BRIDGE_CTL_MASTER_ABORT   0x20  /* Report master aborts */
 #define  PCI_BRIDGE_CTL_BUS_RESET      0x40    /* Secondary bus reset */
 #define  PCI_CAP_ID_CHSWP      0x06    /* CompactPCI HotSwap */
 #define  PCI_CAP_ID_PCIX       0x07    /* PCI-X */
 #define  PCI_CAP_ID_HT         0x08    /* HyperTransport */
-#define  PCI_CAP_ID_VNDR       0x09    /* Vendor specific capability */
+#define  PCI_CAP_ID_VNDR       0x09    /* Vendor specific */
+#define  PCI_CAP_ID_DBG                0x0A    /* Debug port */
+#define  PCI_CAP_ID_CCRC       0x0B    /* CompactPCI Central Resource Control */
 #define  PCI_CAP_ID_SHPC       0x0C    /* PCI Standard Hot-Plug Controller */
+#define  PCI_CAP_ID_SSVID      0x0D    /* Bridge subsystem vendor/device ID */
+#define  PCI_CAP_ID_AGP3       0x0E    /* AGP Target PCI-PCI bridge */
 #define  PCI_CAP_ID_EXP        0x10    /* PCI Express */
 #define  PCI_CAP_ID_MSIX       0x11    /* MSI-X */
 #define PCI_CAP_LIST_NEXT      1       /* Next capability in the list */
index 8bbd459eafdcbd64532613e3b45820c6986373a2..e80804316cdb2e9c78c3ec15ab26435e056bd6bb 100644 (file)
@@ -15,7 +15,7 @@
 
 struct platform_device {
        const char      * name;
-       u32             id;
+       int             id;
        struct device   dev;
        u32             num_resources;
        struct resource * resource;
@@ -35,9 +35,10 @@ extern struct resource *platform_get_resource_byname(struct platform_device *, u
 extern int platform_get_irq_byname(struct platform_device *, char *);
 extern int platform_add_devices(struct platform_device **, int);
 
-extern struct platform_device *platform_device_register_simple(char *, unsigned int, struct resource *, unsigned int);
+extern struct platform_device *platform_device_register_simple(char *, int id,
+                                       struct resource *, unsigned int);
 
-extern struct platform_device *platform_device_alloc(const char *name, unsigned int id);
+extern struct platform_device *platform_device_alloc(const char *name, int id);
 extern int platform_device_add_resources(struct platform_device *pdev, struct resource *res, unsigned int num);
 extern int platform_device_add_data(struct platform_device *pdev, const void *data, size_t size);
 extern int platform_device_add(struct platform_device *pdev);
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 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 be8228e50a2750398f19d9f1699d84e7575cad91..149ab62329e238aab4ce518c41e4070764a8d32d 100644 (file)
@@ -3,6 +3,8 @@
  *
  * Copyright (c) 2001,2002 Patrick Mochel
  * Copyright (c) 2004 Silicon Graphics, Inc.
+ * Copyright (c) 2007 SUSE Linux Products GmbH
+ * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
  *
  * Please see Documentation/filesystems/sysfs.txt for more information.
  */
 
 struct kobject;
 struct module;
-struct nameidata;
-struct dentry;
-struct sysfs_dirent;
 
 /* FIXME
  * The *owner field is no longer used, but leave around
  * until the tree gets cleaned up fully.
  */
 struct attribute {
-       const char              * name;
-       struct module           * owner;
+       const char              *name;
+       struct module           *owner;
        mode_t                  mode;
 };
 
 struct attribute_group {
-       const char              * name;
-       struct attribute        ** attrs;
+       const char              *name;
+       struct attribute        **attrs;
 };
 
 
@@ -77,72 +76,41 @@ struct sysfs_ops {
        ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t);
 };
 
-#define SYSFS_TYPE_MASK                0x00ff
-#define SYSFS_ROOT             0x0001
-#define SYSFS_DIR              0x0002
-#define SYSFS_KOBJ_ATTR        0x0004
-#define SYSFS_KOBJ_BIN_ATTR    0x0008
-#define SYSFS_KOBJ_LINK        0x0020
-#define SYSFS_COPY_NAME                (SYSFS_DIR | SYSFS_KOBJ_LINK)
-
-#define SYSFS_FLAG_MASK                ~SYSFS_TYPE_MASK
-#define SYSFS_FLAG_REMOVED     0x0100
-
 #ifdef CONFIG_SYSFS
 
-extern int sysfs_schedule_callback(struct kobject *kobj,
-               void (*func)(void *), void *data, struct module *owner);
-
-extern int __must_check
-sysfs_create_dir(struct kobject *kobj, struct sysfs_dirent *shadow_parent_sd);
-
-extern void
-sysfs_remove_dir(struct kobject *);
-
-extern int __must_check
-sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd,
-                const char *new_name);
-
-extern int __must_check
-sysfs_move_dir(struct kobject *, struct kobject *);
-
-extern int __must_check
-sysfs_create_file(struct kobject *, const struct attribute *);
+int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *),
+                           void *data, struct module *owner);
 
-extern int __must_check
-sysfs_update_file(struct kobject *, const struct attribute *);
+int __must_check sysfs_create_dir(struct kobject *kobj);
+void sysfs_remove_dir(struct kobject *kobj);
+int __must_check sysfs_rename_dir(struct kobject *kobj, const char *new_name);
+int __must_check sysfs_move_dir(struct kobject *kobj,
+                               struct kobject *new_parent_kobj);
 
-extern int __must_check
-sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode);
-
-extern void
-sysfs_remove_file(struct kobject *, const struct attribute *);
-
-extern int __must_check
-sysfs_create_link(struct kobject * kobj, struct kobject * target, const char * name);
-
-extern void
-sysfs_remove_link(struct kobject *, const char * name);
+int __must_check sysfs_create_file(struct kobject *kobj,
+                                  const struct attribute *attr);
+int __must_check sysfs_chmod_file(struct kobject *kobj, struct attribute *attr,
+                                 mode_t mode);
+void sysfs_remove_file(struct kobject *kobj, const struct attribute *attr);
 
 int __must_check sysfs_create_bin_file(struct kobject *kobj,
-                                       struct bin_attribute *attr);
+                                      struct bin_attribute *attr);
 void sysfs_remove_bin_file(struct kobject *kobj, struct bin_attribute *attr);
 
-int __must_check sysfs_create_group(struct kobject *,
-                                       const struct attribute_group *);
-void sysfs_remove_group(struct kobject *, const struct attribute_group *);
+int __must_check sysfs_create_link(struct kobject *kobj, struct kobject *target,
+                                  const char *name);
+void sysfs_remove_link(struct kobject *kobj, const char *name);
+
+int __must_check sysfs_create_group(struct kobject *kobj,
+                                   const struct attribute_group *grp);
+void sysfs_remove_group(struct kobject *kobj,
+                       const struct attribute_group *grp);
 int sysfs_add_file_to_group(struct kobject *kobj,
-               const struct attribute *attr, const char *group);
+                       const struct attribute *attr, const char *group);
 void sysfs_remove_file_from_group(struct kobject *kobj,
-               const struct attribute *attr, const char *group);
-
-void sysfs_notify(struct kobject * k, char *dir, char *attr);
-
+                       const struct attribute *attr, const char *group);
 
-extern int sysfs_make_shadowed_dir(struct kobject *kobj,
-       void * (*follow_link)(struct dentry *, struct nameidata *));
-extern struct sysfs_dirent *sysfs_create_shadow_dir(struct kobject *kobj);
-extern void sysfs_remove_shadow_dir(struct sysfs_dirent *shadow_sd);
+void sysfs_notify(struct kobject *kobj, char *dir, char *attr);
 
 extern int __must_check sysfs_init(void);
 
@@ -154,75 +122,76 @@ static inline int sysfs_schedule_callback(struct kobject *kobj,
        return -ENOSYS;
 }
 
-static inline int sysfs_create_dir(struct kobject *kobj,
-                                  struct sysfs_dirent *shadow_parent_sd)
+static inline int sysfs_create_dir(struct kobject *kobj)
 {
        return 0;
 }
 
-static inline void sysfs_remove_dir(struct kobject * k)
+static inline void sysfs_remove_dir(struct kobject *kobj)
 {
        ;
 }
 
-static inline int sysfs_rename_dir(struct kobject *kobj,
-                                  struct sysfs_dirent *new_parent_sd,
-                                  const char *new_name)
+static inline int sysfs_rename_dir(struct kobject *kobj, const char *new_name)
 {
        return 0;
 }
 
-static inline int sysfs_move_dir(struct kobject * k, struct kobject * new_parent)
+static inline int sysfs_move_dir(struct kobject *kobj,
+                                struct kobject *new_parent_kobj)
 {
        return 0;
 }
 
-static inline int sysfs_create_file(struct kobject * k, const struct attribute * a)
+static inline int sysfs_create_file(struct kobject *kobj,
+                                   const struct attribute *attr)
 {
        return 0;
 }
 
-static inline int sysfs_update_file(struct kobject * k, const struct attribute * a)
-{
-       return 0;
-}
-static inline int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode)
+static inline int sysfs_chmod_file(struct kobject *kobj,
+                                  struct attribute *attr, mode_t mode)
 {
        return 0;
 }
 
-static inline void sysfs_remove_file(struct kobject * k, const struct attribute * a)
+static inline void sysfs_remove_file(struct kobject *kobj,
+                                    const struct attribute *attr)
 {
        ;
 }
 
-static inline int sysfs_create_link(struct kobject * k, struct kobject * t, const char * n)
+static inline int sysfs_create_bin_file(struct kobject *kobj,
+                                       struct bin_attribute *attr)
 {
        return 0;
 }
 
-static inline void sysfs_remove_link(struct kobject * k, const char * name)
+static inline int sysfs_remove_bin_file(struct kobject *kobj,
+                                       struct bin_attribute *attr)
 {
-       ;
+       return 0;
 }
 
-
-static inline int sysfs_create_bin_file(struct kobject * k, struct bin_attribute * a)
+static inline int sysfs_create_link(struct kobject *kobj,
+                                   struct kobject *target, const char *name)
 {
        return 0;
 }
 
-static inline int sysfs_remove_bin_file(struct kobject * k, struct bin_attribute * a)
+static inline void sysfs_remove_link(struct kobject *kobj, const char *name)
 {
-       return 0;
+       ;
 }
 
-static inline int sysfs_create_group(struct kobject * k, const struct attribute_group *g)
+static inline int sysfs_create_group(struct kobject *kobj,
+                                    const struct attribute_group *grp)
 {
        return 0;
 }
 
-static inline void sysfs_remove_group(struct kobject * k, const struct attribute_group * g)
+static inline void sysfs_remove_group(struct kobject *kobj,
+                                     const struct attribute_group *grp)
 {
        ;
 }
@@ -238,14 +207,8 @@ static inline void sysfs_remove_file_from_group(struct kobject *kobj,
 {
 }
 
-static inline void sysfs_notify(struct kobject * k, char *dir, char *attr)
-{
-}
-
-static inline int sysfs_make_shadowed_dir(struct kobject *kobj,
-       void * (*follow_link)(struct dentry *, struct nameidata *))
+static inline void sysfs_notify(struct kobject *kobj, char *dir, char *attr)
 {
-       return 0;
 }
 
 static inline int __must_check sysfs_init(void)
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 6570719eafdf8038056e4ba3562b36e2446b7cb9..60478f6e5dc63ee04f305c535f397a98377a82a2 100644 (file)
@@ -21,7 +21,6 @@
  * (Note: the *_driver.minor_start values 1, 64, 128, 192 are
  * hardcoded at present.)
  */
-#define NR_PTYS        CONFIG_LEGACY_PTY_COUNT   /* Number of legacy ptys */
 #define NR_UNIX98_PTY_DEFAULT  4096      /* Default maximum for Unix98 ptys */
 #define NR_UNIX98_PTY_MAX      (1 << MINORBITS) /* Absolute limit */
 #define NR_LDISCS              17
index 4f33a58fa9d1c687baa8e3d76773a4c61d9cc23c..c5c8f169d3cffe001f893d09c0b93272efeb1986 100644 (file)
@@ -52,6 +52,7 @@ struct ep_device;
  * @ep_dev: ep_device for sysfs info
  * @extra: descriptors following this endpoint in the configuration
  * @extralen: how many bytes of "extra" are valid
+ * @enabled: URBs may be submitted to this endpoint
  *
  * USB requests are always queued to a given endpoint, identified by a
  * descriptor within an active interface in a given USB configuration.
@@ -64,6 +65,7 @@ struct usb_host_endpoint {
 
        unsigned char *extra;   /* Extra descriptors */
        int extralen;
+       int enabled;
 };
 
 /* host-side wrapper for one interface setting's parsed descriptors */
@@ -344,6 +346,11 @@ struct usb_tt;
  *
  * Usbcore drivers should not set usbdev->state directly.  Instead use
  * usb_set_device_state().
+ *
+ * @authorized: (user space) policy determines if we authorize this
+ *              device to be used or not. By default, wired USB
+ *              devices are authorized. WUSB devices are not, until we
+ *              authorize them from user space. FIXME -- complete doc
  */
 struct usb_device {
        int             devnum;         /* Address on USB bus */
@@ -376,8 +383,11 @@ struct usb_device {
        u8 portnum;                     /* Parent port number (origin 1) */
        u8 level;                       /* Number of USB hub ancestors */
 
+       unsigned can_submit:1;          /* URBs may be submitted */
        unsigned discon_suspended:1;    /* Disconnected while suspended */
        unsigned have_langid:1;         /* whether string_langid is valid */
+       unsigned authorized:1;          /* Policy has determined we can use it */
+       unsigned wusb:1;                /* Device is Wireless USB */
        int string_langid;              /* language ID for strings */
 
        /* static strings from the device */
@@ -405,6 +415,7 @@ struct usb_device {
 
        int pm_usage_cnt;               /* usage counter for autosuspend */
        u32 quirks;                     /* quirks of the whole device */
+       atomic_t urbnum;                /* number of URBs submitted for the whole device */
 
 #ifdef CONFIG_PM
        struct delayed_work autosuspend; /* for delayed autosuspends */
@@ -419,6 +430,7 @@ struct usb_device {
        unsigned persist_enabled:1;     /* USB_PERSIST enabled for this dev */
        unsigned autosuspend_disabled:1; /* autosuspend and autoresume */
        unsigned autoresume_disabled:1;  /*  disabled by the user */
+       unsigned skip_sys_resume:1;     /* skip the next system resume */
 #endif
 };
 #define        to_usb_device(d) container_of(d, struct usb_device, dev)
@@ -554,6 +566,29 @@ static inline int usb_make_path (struct usb_device *dev, char *buf,
 
 /*-------------------------------------------------------------------------*/
 
+/**
+ * usb_endpoint_num - get the endpoint's number
+ * @epd: endpoint to be checked
+ *
+ * Returns @epd's number: 0 to 15.
+ */
+static inline int usb_endpoint_num(const struct usb_endpoint_descriptor *epd)
+{
+       return epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+}
+
+/**
+ * usb_endpoint_type - get the endpoint's transfer type
+ * @epd: endpoint to be checked
+ *
+ * Returns one of USB_ENDPOINT_XFER_{CONTROL, ISOC, BULK, INT} according
+ * to @epd's transfer type.
+ */
+static inline int usb_endpoint_type(const struct usb_endpoint_descriptor *epd)
+{
+       return epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+}
+
 /**
  * usb_endpoint_dir_in - check if the endpoint has IN direction
  * @epd: endpoint to be checked
@@ -996,6 +1031,8 @@ extern int usb_disabled(void);
 
 /*
  * urb->transfer_flags:
+ *
+ * Note: URB_DIR_IN/OUT is automatically set in usb_submit_urb().
  */
 #define URB_SHORT_NOT_OK       0x0001  /* report short reads as errors */
 #define URB_ISO_ASAP           0x0002  /* iso-only, urb->start_frame
@@ -1008,6 +1045,10 @@ extern int usb_disabled(void);
                                         * needed */
 #define URB_FREE_BUFFER                0x0100  /* Free transfer buffer with the URB */
 
+#define URB_DIR_IN             0x0200  /* Transfer from device to host */
+#define URB_DIR_OUT            0
+#define URB_DIR_MASK           URB_DIR_IN
+
 struct usb_iso_packet_descriptor {
        unsigned int offset;
        unsigned int length;            /* expected length */
@@ -1037,6 +1078,8 @@ typedef void (*usb_complete_t)(struct urb *);
  * @urb_list: For use by current owner of the URB.
  * @anchor_list: membership in the list of an anchor
  * @anchor: to anchor URBs to a common mooring
+ * @ep: Points to the endpoint's data structure.  Will eventually
+ *     replace @pipe.
  * @pipe: Holds endpoint number, direction, type, and more.
  *     Create these values with the eight macros available;
  *     usb_{snd,rcv}TYPEpipe(dev,endpoint), where the TYPE is "ctrl"
@@ -1201,10 +1244,10 @@ struct urb
 {
        /* private: usb core and host controller only fields in the urb */
        struct kref kref;               /* reference count of the URB */
-       spinlock_t lock;                /* lock for the URB */
        void *hcpriv;                   /* private data for host controller */
        atomic_t use_count;             /* concurrent submissions counter */
        u8 reject;                      /* submissions will fail */
+       int unlinked;                   /* unlink error code */
 
        /* public: documented fields in the urb that can be used by drivers */
        struct list_head urb_list;      /* list head for use by the urb's
@@ -1212,6 +1255,7 @@ struct urb
        struct list_head anchor_list;   /* the URB may be anchored by the driver */
        struct usb_anchor *anchor;
        struct usb_device *dev;         /* (in) pointer to associated device */
+       struct usb_host_endpoint *ep;   /* (internal) pointer to endpoint struct */
        unsigned int pipe;              /* (in) pipe information */
        int status;                     /* (return) non-ISO status */
        unsigned int transfer_flags;    /* (in) URB_SHORT_NOT_OK | ...*/
@@ -1257,7 +1301,6 @@ static inline void usb_fill_control_urb (struct urb *urb,
                                         usb_complete_t complete_fn,
                                         void *context)
 {
-       spin_lock_init(&urb->lock);
        urb->dev = dev;
        urb->pipe = pipe;
        urb->setup_packet = setup_packet;
@@ -1288,7 +1331,6 @@ static inline void usb_fill_bulk_urb (struct urb *urb,
                                      usb_complete_t complete_fn,
                                      void *context)
 {
-       spin_lock_init(&urb->lock);
        urb->dev = dev;
        urb->pipe = pipe;
        urb->transfer_buffer = transfer_buffer;
@@ -1324,7 +1366,6 @@ static inline void usb_fill_int_urb (struct urb *urb,
                                     void *context,
                                     int interval)
 {
-       spin_lock_init(&urb->lock);
        urb->dev = dev;
        urb->pipe = pipe;
        urb->transfer_buffer = transfer_buffer;
@@ -1352,6 +1393,30 @@ extern void usb_unanchor_urb(struct urb *urb);
 extern int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor,
                                         unsigned int timeout);
 
+/**
+ * usb_urb_dir_in - check if an URB describes an IN transfer
+ * @urb: URB to be checked
+ *
+ * Returns 1 if @urb describes an IN transfer (device-to-host),
+ * otherwise 0.
+ */
+static inline int usb_urb_dir_in(struct urb *urb)
+{
+       return (urb->transfer_flags & URB_DIR_MASK) == URB_DIR_IN;
+}
+
+/**
+ * usb_urb_dir_out - check if an URB describes an OUT transfer
+ * @urb: URB to be checked
+ *
+ * Returns 1 if @urb describes an OUT transfer (host-to-device),
+ * otherwise 0.
+ */
+static inline int usb_urb_dir_out(struct urb *urb)
+{
+       return (urb->transfer_flags & URB_DIR_MASK) == URB_DIR_OUT;
+}
+
 void *usb_buffer_alloc (struct usb_device *dev, size_t size,
        gfp_t mem_flags, dma_addr_t *dma);
 void usb_buffer_free (struct usb_device *dev, size_t size,
@@ -1364,13 +1429,13 @@ void usb_buffer_unmap (struct urb *urb);
 #endif
 
 struct scatterlist;
-int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
+int usb_buffer_map_sg(const struct usb_device *dev, int is_in,
                      struct scatterlist *sg, int nents);
 #if 0
-void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe,
+void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in,
                           struct scatterlist *sg, int n_hw_ents);
 #endif
-void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe,
+void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in,
                         struct scatterlist *sg, int n_hw_ents);
 
 /*-------------------------------------------------------------------*
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
new file mode 100644 (file)
index 0000000..46705e9
--- /dev/null
@@ -0,0 +1,866 @@
+/*
+ * <linux/usb/gadget.h>
+ *
+ * We call the USB code inside a Linux-based peripheral device a "gadget"
+ * driver, except for the hardware-specific bus glue.  One USB host can
+ * master many USB gadgets, but the gadgets are only slaved to one host.
+ *
+ *
+ * (C) Copyright 2002-2004 by David Brownell
+ * All Rights Reserved.
+ *
+ * This software is licensed under the GNU GPL version 2.
+ */
+
+#ifndef __LINUX_USB_GADGET_H
+#define __LINUX_USB_GADGET_H
+
+#ifdef __KERNEL__
+
+struct usb_ep;
+
+/**
+ * struct usb_request - describes one i/o request
+ * @buf: Buffer used for data.  Always provide this; some controllers
+ *     only use PIO, or don't use DMA for some endpoints.
+ * @dma: DMA address corresponding to 'buf'.  If you don't set this
+ *     field, and the usb controller needs one, it is responsible
+ *     for mapping and unmapping the buffer.
+ * @length: Length of that data
+ * @no_interrupt: If true, hints that no completion irq is needed.
+ *     Helpful sometimes with deep request queues that are handled
+ *     directly by DMA controllers.
+ * @zero: If true, when writing data, makes the last packet be "short"
+ *     by adding a zero length packet as needed;
+ * @short_not_ok: When reading data, makes short packets be
+ *     treated as errors (queue stops advancing till cleanup).
+ * @complete: Function called when request completes, so this request and
+ *     its buffer may be re-used.
+ *     Reads terminate with a short packet, or when the buffer fills,
+ *     whichever comes first.  When writes terminate, some data bytes
+ *     will usually still be in flight (often in a hardware fifo).
+ *     Errors (for reads or writes) stop the queue from advancing
+ *     until the completion function returns, so that any transfers
+ *     invalidated by the error may first be dequeued.
+ * @context: For use by the completion callback
+ * @list: For use by the gadget driver.
+ * @status: Reports completion code, zero or a negative errno.
+ *     Normally, faults block the transfer queue from advancing until
+ *     the completion callback returns.
+ *     Code "-ESHUTDOWN" indicates completion caused by device disconnect,
+ *     or when the driver disabled the endpoint.
+ * @actual: Reports bytes transferred to/from the buffer.  For reads (OUT
+ *     transfers) this may be less than the requested length.  If the
+ *     short_not_ok flag is set, short reads are treated as errors
+ *     even when status otherwise indicates successful completion.
+ *     Note that for writes (IN transfers) some data bytes may still
+ *     reside in a device-side FIFO when the request is reported as
+ *     complete.
+ *
+ * These are allocated/freed through the endpoint they're used with.  The
+ * hardware's driver can add extra per-request data to the memory it returns,
+ * which often avoids separate memory allocations (potential failures),
+ * later when the request is queued.
+ *
+ * Request flags affect request handling, such as whether a zero length
+ * packet is written (the "zero" flag), whether a short read should be
+ * treated as an error (blocking request queue advance, the "short_not_ok"
+ * flag), or hinting that an interrupt is not required (the "no_interrupt"
+ * flag, for use with deep request queues).
+ *
+ * Bulk endpoints can use any size buffers, and can also be used for interrupt
+ * transfers. interrupt-only endpoints can be much less functional.
+ */
+       // NOTE this is analagous to 'struct urb' on the host side,
+       // except that it's thinner and promotes more pre-allocation.
+
+struct usb_request {
+       void                    *buf;
+       unsigned                length;
+       dma_addr_t              dma;
+
+       unsigned                no_interrupt:1;
+       unsigned                zero:1;
+       unsigned                short_not_ok:1;
+
+       void                    (*complete)(struct usb_ep *ep,
+                                       struct usb_request *req);
+       void                    *context;
+       struct list_head        list;
+
+       int                     status;
+       unsigned                actual;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* endpoint-specific parts of the api to the usb controller hardware.
+ * unlike the urb model, (de)multiplexing layers are not required.
+ * (so this api could slash overhead if used on the host side...)
+ *
+ * note that device side usb controllers commonly differ in how many
+ * endpoints they support, as well as their capabilities.
+ */
+struct usb_ep_ops {
+       int (*enable) (struct usb_ep *ep,
+               const struct usb_endpoint_descriptor *desc);
+       int (*disable) (struct usb_ep *ep);
+
+       struct usb_request *(*alloc_request) (struct usb_ep *ep,
+               gfp_t gfp_flags);
+       void (*free_request) (struct usb_ep *ep, struct usb_request *req);
+
+       int (*queue) (struct usb_ep *ep, struct usb_request *req,
+               gfp_t gfp_flags);
+       int (*dequeue) (struct usb_ep *ep, struct usb_request *req);
+
+       int (*set_halt) (struct usb_ep *ep, int value);
+       int (*fifo_status) (struct usb_ep *ep);
+       void (*fifo_flush) (struct usb_ep *ep);
+};
+
+/**
+ * struct usb_ep - device side representation of USB endpoint
+ * @name:identifier for the endpoint, such as "ep-a" or "ep9in-bulk"
+ * @ops: Function pointers used to access hardware-specific operations.
+ * @ep_list:the gadget's ep_list holds all of its endpoints
+ * @maxpacket:The maximum packet size used on this endpoint.  The initial
+ *     value can sometimes be reduced (hardware allowing), according to
+ *      the endpoint descriptor used to configure the endpoint.
+ * @driver_data:for use by the gadget driver.  all other fields are
+ *     read-only to gadget drivers.
+ *
+ * the bus controller driver lists all the general purpose endpoints in
+ * gadget->ep_list.  the control endpoint (gadget->ep0) is not in that list,
+ * and is accessed only in response to a driver setup() callback.
+ */
+struct usb_ep {
+       void                    *driver_data;
+
+       const char              *name;
+       const struct usb_ep_ops *ops;
+       struct list_head        ep_list;
+       unsigned                maxpacket:16;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * usb_ep_enable - configure endpoint, making it usable
+ * @ep:the endpoint being configured.  may not be the endpoint named "ep0".
+ *     drivers discover endpoints through the ep_list of a usb_gadget.
+ * @desc:descriptor for desired behavior.  caller guarantees this pointer
+ *     remains valid until the endpoint is disabled; the data byte order
+ *     is little-endian (usb-standard).
+ *
+ * when configurations are set, or when interface settings change, the driver
+ * will enable or disable the relevant endpoints.  while it is enabled, an
+ * endpoint may be used for i/o until the driver receives a disconnect() from
+ * the host or until the endpoint is disabled.
+ *
+ * the ep0 implementation (which calls this routine) must ensure that the
+ * hardware capabilities of each endpoint match the descriptor provided
+ * for it.  for example, an endpoint named "ep2in-bulk" would be usable
+ * for interrupt transfers as well as bulk, but it likely couldn't be used
+ * for iso transfers or for endpoint 14.  some endpoints are fully
+ * configurable, with more generic names like "ep-a".  (remember that for
+ * USB, "in" means "towards the USB master".)
+ *
+ * returns zero, or a negative error code.
+ */
+static inline int
+usb_ep_enable (struct usb_ep *ep, const struct usb_endpoint_descriptor *desc)
+{
+       return ep->ops->enable (ep, desc);
+}
+
+/**
+ * usb_ep_disable - endpoint is no longer usable
+ * @ep:the endpoint being unconfigured.  may not be the endpoint named "ep0".
+ *
+ * no other task may be using this endpoint when this is called.
+ * any pending and uncompleted requests will complete with status
+ * indicating disconnect (-ESHUTDOWN) before this call returns.
+ * gadget drivers must call usb_ep_enable() again before queueing
+ * requests to the endpoint.
+ *
+ * returns zero, or a negative error code.
+ */
+static inline int
+usb_ep_disable (struct usb_ep *ep)
+{
+       return ep->ops->disable (ep);
+}
+
+/**
+ * usb_ep_alloc_request - allocate a request object to use with this endpoint
+ * @ep:the endpoint to be used with with the request
+ * @gfp_flags:GFP_* flags to use
+ *
+ * Request objects must be allocated with this call, since they normally
+ * need controller-specific setup and may even need endpoint-specific
+ * resources such as allocation of DMA descriptors.
+ * Requests may be submitted with usb_ep_queue(), and receive a single
+ * completion callback.  Free requests with usb_ep_free_request(), when
+ * they are no longer needed.
+ *
+ * Returns the request, or null if one could not be allocated.
+ */
+static inline struct usb_request *
+usb_ep_alloc_request (struct usb_ep *ep, gfp_t gfp_flags)
+{
+       return ep->ops->alloc_request (ep, gfp_flags);
+}
+
+/**
+ * usb_ep_free_request - frees a request object
+ * @ep:the endpoint associated with the request
+ * @req:the request being freed
+ *
+ * Reverses the effect of usb_ep_alloc_request().
+ * Caller guarantees the request is not queued, and that it will
+ * no longer be requeued (or otherwise used).
+ */
+static inline void
+usb_ep_free_request (struct usb_ep *ep, struct usb_request *req)
+{
+       ep->ops->free_request (ep, req);
+}
+
+/**
+ * usb_ep_queue - queues (submits) an I/O request to an endpoint.
+ * @ep:the endpoint associated with the request
+ * @req:the request being submitted
+ * @gfp_flags: GFP_* flags to use in case the lower level driver couldn't
+ *     pre-allocate all necessary memory with the request.
+ *
+ * This tells the device controller to perform the specified request through
+ * that endpoint (reading or writing a buffer).  When the request completes,
+ * including being canceled by usb_ep_dequeue(), the request's completion
+ * routine is called to return the request to the driver.  Any endpoint
+ * (except control endpoints like ep0) may have more than one transfer
+ * request queued; they complete in FIFO order.  Once a gadget driver
+ * submits a request, that request may not be examined or modified until it
+ * is given back to that driver through the completion callback.
+ *
+ * Each request is turned into one or more packets.  The controller driver
+ * never merges adjacent requests into the same packet.  OUT transfers
+ * will sometimes use data that's already buffered in the hardware.
+ * Drivers can rely on the fact that the first byte of the request's buffer
+ * always corresponds to the first byte of some USB packet, for both
+ * IN and OUT transfers.
+ *
+ * Bulk endpoints can queue any amount of data; the transfer is packetized
+ * automatically.  The last packet will be short if the request doesn't fill it
+ * out completely.  Zero length packets (ZLPs) should be avoided in portable
+ * protocols since not all usb hardware can successfully handle zero length
+ * packets.  (ZLPs may be explicitly written, and may be implicitly written if
+ * the request 'zero' flag is set.)  Bulk endpoints may also be used
+ * for interrupt transfers; but the reverse is not true, and some endpoints
+ * won't support every interrupt transfer.  (Such as 768 byte packets.)
+ *
+ * Interrupt-only endpoints are less functional than bulk endpoints, for
+ * example by not supporting queueing or not handling buffers that are
+ * larger than the endpoint's maxpacket size.  They may also treat data
+ * toggle differently.
+ *
+ * Control endpoints ... after getting a setup() callback, the driver queues
+ * one response (even if it would be zero length).  That enables the
+ * status ack, after transfering data as specified in the response.  Setup
+ * functions may return negative error codes to generate protocol stalls.
+ * (Note that some USB device controllers disallow protocol stall responses
+ * in some cases.)  When control responses are deferred (the response is
+ * written after the setup callback returns), then usb_ep_set_halt() may be
+ * used on ep0 to trigger protocol stalls.
+ *
+ * For periodic endpoints, like interrupt or isochronous ones, the usb host
+ * arranges to poll once per interval, and the gadget driver usually will
+ * have queued some data to transfer at that time.
+ *
+ * Returns zero, or a negative error code.  Endpoints that are not enabled
+ * report errors; errors will also be
+ * reported when the usb peripheral is disconnected.
+ */
+static inline int
+usb_ep_queue (struct usb_ep *ep, struct usb_request *req, gfp_t gfp_flags)
+{
+       return ep->ops->queue (ep, req, gfp_flags);
+}
+
+/**
+ * usb_ep_dequeue - dequeues (cancels, unlinks) an I/O request from an endpoint
+ * @ep:the endpoint associated with the request
+ * @req:the request being canceled
+ *
+ * if the request is still active on the endpoint, it is dequeued and its
+ * completion routine is called (with status -ECONNRESET); else a negative
+ * error code is returned.
+ *
+ * note that some hardware can't clear out write fifos (to unlink the request
+ * at the head of the queue) except as part of disconnecting from usb.  such
+ * restrictions prevent drivers from supporting configuration changes,
+ * even to configuration zero (a "chapter 9" requirement).
+ */
+static inline int usb_ep_dequeue (struct usb_ep *ep, struct usb_request *req)
+{
+       return ep->ops->dequeue (ep, req);
+}
+
+/**
+ * usb_ep_set_halt - sets the endpoint halt feature.
+ * @ep: the non-isochronous endpoint being stalled
+ *
+ * Use this to stall an endpoint, perhaps as an error report.
+ * Except for control endpoints,
+ * the endpoint stays halted (will not stream any data) until the host
+ * clears this feature; drivers may need to empty the endpoint's request
+ * queue first, to make sure no inappropriate transfers happen.
+ *
+ * Note that while an endpoint CLEAR_FEATURE will be invisible to the
+ * gadget driver, a SET_INTERFACE will not be.  To reset endpoints for the
+ * current altsetting, see usb_ep_clear_halt().  When switching altsettings,
+ * it's simplest to use usb_ep_enable() or usb_ep_disable() for the endpoints.
+ *
+ * Returns zero, or a negative error code.  On success, this call sets
+ * underlying hardware state that blocks data transfers.
+ * Attempts to halt IN endpoints will fail (returning -EAGAIN) if any
+ * transfer requests are still queued, or if the controller hardware
+ * (usually a FIFO) still holds bytes that the host hasn't collected.
+ */
+static inline int
+usb_ep_set_halt (struct usb_ep *ep)
+{
+       return ep->ops->set_halt (ep, 1);
+}
+
+/**
+ * usb_ep_clear_halt - clears endpoint halt, and resets toggle
+ * @ep:the bulk or interrupt endpoint being reset
+ *
+ * Use this when responding to the standard usb "set interface" request,
+ * for endpoints that aren't reconfigured, after clearing any other state
+ * in the endpoint's i/o queue.
+ *
+ * Returns zero, or a negative error code.  On success, this call clears
+ * the underlying hardware state reflecting endpoint halt and data toggle.
+ * Note that some hardware can't support this request (like pxa2xx_udc),
+ * and accordingly can't correctly implement interface altsettings.
+ */
+static inline int
+usb_ep_clear_halt (struct usb_ep *ep)
+{
+       return ep->ops->set_halt (ep, 0);
+}
+
+/**
+ * usb_ep_fifo_status - returns number of bytes in fifo, or error
+ * @ep: the endpoint whose fifo status is being checked.
+ *
+ * FIFO endpoints may have "unclaimed data" in them in certain cases,
+ * such as after aborted transfers.  Hosts may not have collected all
+ * the IN data written by the gadget driver (and reported by a request
+ * completion).  The gadget driver may not have collected all the data
+ * written OUT to it by the host.  Drivers that need precise handling for
+ * fault reporting or recovery may need to use this call.
+ *
+ * This returns the number of such bytes in the fifo, or a negative
+ * errno if the endpoint doesn't use a FIFO or doesn't support such
+ * precise handling.
+ */
+static inline int
+usb_ep_fifo_status (struct usb_ep *ep)
+{
+       if (ep->ops->fifo_status)
+               return ep->ops->fifo_status (ep);
+       else
+               return -EOPNOTSUPP;
+}
+
+/**
+ * usb_ep_fifo_flush - flushes contents of a fifo
+ * @ep: the endpoint whose fifo is being flushed.
+ *
+ * This call may be used to flush the "unclaimed data" that may exist in
+ * an endpoint fifo after abnormal transaction terminations.  The call
+ * must never be used except when endpoint is not being used for any
+ * protocol translation.
+ */
+static inline void
+usb_ep_fifo_flush (struct usb_ep *ep)
+{
+       if (ep->ops->fifo_flush)
+               ep->ops->fifo_flush (ep);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+struct usb_gadget;
+
+/* the rest of the api to the controller hardware: device operations,
+ * which don't involve endpoints (or i/o).
+ */
+struct usb_gadget_ops {
+       int     (*get_frame)(struct usb_gadget *);
+       int     (*wakeup)(struct usb_gadget *);
+       int     (*set_selfpowered) (struct usb_gadget *, int is_selfpowered);
+       int     (*vbus_session) (struct usb_gadget *, int is_active);
+       int     (*vbus_draw) (struct usb_gadget *, unsigned mA);
+       int     (*pullup) (struct usb_gadget *, int is_on);
+       int     (*ioctl)(struct usb_gadget *,
+                               unsigned code, unsigned long param);
+};
+
+/**
+ * struct usb_gadget - represents a usb slave device
+ * @ops: Function pointers used to access hardware-specific operations.
+ * @ep0: Endpoint zero, used when reading or writing responses to
+ *     driver setup() requests
+ * @ep_list: List of other endpoints supported by the device.
+ * @speed: Speed of current connection to USB host.
+ * @is_dualspeed: True if the controller supports both high and full speed
+ *     operation.  If it does, the gadget driver must also support both.
+ * @is_otg: True if the USB device port uses a Mini-AB jack, so that the
+ *     gadget driver must provide a USB OTG descriptor.
+ * @is_a_peripheral: False unless is_otg, the "A" end of a USB cable
+ *     is in the Mini-AB jack, and HNP has been used to switch roles
+ *     so that the "A" device currently acts as A-Peripheral, not A-Host.
+ * @a_hnp_support: OTG device feature flag, indicating that the A-Host
+ *     supports HNP at this port.
+ * @a_alt_hnp_support: OTG device feature flag, indicating that the A-Host
+ *     only supports HNP on a different root port.
+ * @b_hnp_enable: OTG device feature flag, indicating that the A-Host
+ *     enabled HNP support.
+ * @name: Identifies the controller hardware type.  Used in diagnostics
+ *     and sometimes configuration.
+ * @dev: Driver model state for this abstract device.
+ *
+ * Gadgets have a mostly-portable "gadget driver" implementing device
+ * functions, handling all usb configurations and interfaces.  Gadget
+ * drivers talk to hardware-specific code indirectly, through ops vectors.
+ * That insulates the gadget driver from hardware details, and packages
+ * the hardware endpoints through generic i/o queues.  The "usb_gadget"
+ * and "usb_ep" interfaces provide that insulation from the hardware.
+ *
+ * Except for the driver data, all fields in this structure are
+ * read-only to the gadget driver.  That driver data is part of the
+ * "driver model" infrastructure in 2.6 (and later) kernels, and for
+ * earlier systems is grouped in a similar structure that's not known
+ * to the rest of the kernel.
+ *
+ * Values of the three OTG device feature flags are updated before the
+ * setup() call corresponding to USB_REQ_SET_CONFIGURATION, and before
+ * driver suspend() calls.  They are valid only when is_otg, and when the
+ * device is acting as a B-Peripheral (so is_a_peripheral is false).
+ */
+struct usb_gadget {
+       /* readonly to gadget driver */
+       const struct usb_gadget_ops     *ops;
+       struct usb_ep                   *ep0;
+       struct list_head                ep_list;        /* of usb_ep */
+       enum usb_device_speed           speed;
+       unsigned                        is_dualspeed:1;
+       unsigned                        is_otg:1;
+       unsigned                        is_a_peripheral:1;
+       unsigned                        b_hnp_enable:1;
+       unsigned                        a_hnp_support:1;
+       unsigned                        a_alt_hnp_support:1;
+       const char                      *name;
+       struct device                   dev;
+};
+
+static inline void set_gadget_data (struct usb_gadget *gadget, void *data)
+       { dev_set_drvdata (&gadget->dev, data); }
+static inline void *get_gadget_data (struct usb_gadget *gadget)
+       { return dev_get_drvdata (&gadget->dev); }
+
+/* iterates the non-control endpoints; 'tmp' is a struct usb_ep pointer */
+#define gadget_for_each_ep(tmp,gadget) \
+       list_for_each_entry(tmp, &(gadget)->ep_list, ep_list)
+
+
+/**
+ * gadget_is_dualspeed - return true iff the hardware handles high speed
+ * @gadget: controller that might support both high and full speeds
+ */
+static inline int gadget_is_dualspeed(struct usb_gadget *g)
+{
+#ifdef CONFIG_USB_GADGET_DUALSPEED
+       /* runtime test would check "g->is_dualspeed" ... that might be
+        * useful to work around hardware bugs, but is mostly pointless
+        */
+       return 1;
+#else
+       return 0;
+#endif
+}
+
+/**
+ * gadget_is_otg - return true iff the hardware is OTG-ready
+ * @gadget: controller that might have a Mini-AB connector
+ *
+ * This is a runtime test, since kernels with a USB-OTG stack sometimes
+ * run on boards which only have a Mini-B (or Mini-A) connector.
+ */
+static inline int gadget_is_otg(struct usb_gadget *g)
+{
+#ifdef CONFIG_USB_OTG
+       return g->is_otg;
+#else
+       return 0;
+#endif
+}
+
+
+/**
+ * usb_gadget_frame_number - returns the current frame number
+ * @gadget: controller that reports the frame number
+ *
+ * Returns the usb frame number, normally eleven bits from a SOF packet,
+ * or negative errno if this device doesn't support this capability.
+ */
+static inline int usb_gadget_frame_number (struct usb_gadget *gadget)
+{
+       return gadget->ops->get_frame (gadget);
+}
+
+/**
+ * usb_gadget_wakeup - tries to wake up the host connected to this gadget
+ * @gadget: controller used to wake up the host
+ *
+ * Returns zero on success, else negative error code if the hardware
+ * doesn't support such attempts, or its support has not been enabled
+ * by the usb host.  Drivers must return device descriptors that report
+ * their ability to support this, or hosts won't enable it.
+ *
+ * This may also try to use SRP to wake the host and start enumeration,
+ * even if OTG isn't otherwise in use.  OTG devices may also start
+ * remote wakeup even when hosts don't explicitly enable it.
+ */
+static inline int usb_gadget_wakeup (struct usb_gadget *gadget)
+{
+       if (!gadget->ops->wakeup)
+               return -EOPNOTSUPP;
+       return gadget->ops->wakeup (gadget);
+}
+
+/**
+ * usb_gadget_set_selfpowered - sets the device selfpowered feature.
+ * @gadget:the device being declared as self-powered
+ *
+ * this affects the device status reported by the hardware driver
+ * to reflect that it now has a local power supply.
+ *
+ * returns zero on success, else negative errno.
+ */
+static inline int
+usb_gadget_set_selfpowered (struct usb_gadget *gadget)
+{
+       if (!gadget->ops->set_selfpowered)
+               return -EOPNOTSUPP;
+       return gadget->ops->set_selfpowered (gadget, 1);
+}
+
+/**
+ * usb_gadget_clear_selfpowered - clear the device selfpowered feature.
+ * @gadget:the device being declared as bus-powered
+ *
+ * this affects the device status reported by the hardware driver.
+ * some hardware may not support bus-powered operation, in which
+ * case this feature's value can never change.
+ *
+ * returns zero on success, else negative errno.
+ */
+static inline int
+usb_gadget_clear_selfpowered (struct usb_gadget *gadget)
+{
+       if (!gadget->ops->set_selfpowered)
+               return -EOPNOTSUPP;
+       return gadget->ops->set_selfpowered (gadget, 0);
+}
+
+/**
+ * usb_gadget_vbus_connect - Notify controller that VBUS is powered
+ * @gadget:The device which now has VBUS power.
+ *
+ * This call is used by a driver for an external transceiver (or GPIO)
+ * that detects a VBUS power session starting.  Common responses include
+ * resuming the controller, activating the D+ (or D-) pullup to let the
+ * host detect that a USB device is attached, and starting to draw power
+ * (8mA or possibly more, especially after SET_CONFIGURATION).
+ *
+ * Returns zero on success, else negative errno.
+ */
+static inline int
+usb_gadget_vbus_connect(struct usb_gadget *gadget)
+{
+       if (!gadget->ops->vbus_session)
+               return -EOPNOTSUPP;
+       return gadget->ops->vbus_session (gadget, 1);
+}
+
+/**
+ * usb_gadget_vbus_draw - constrain controller's VBUS power usage
+ * @gadget:The device whose VBUS usage is being described
+ * @mA:How much current to draw, in milliAmperes.  This should be twice
+ *     the value listed in the configuration descriptor bMaxPower field.
+ *
+ * This call is used by gadget drivers during SET_CONFIGURATION calls,
+ * reporting how much power the device may consume.  For example, this
+ * could affect how quickly batteries are recharged.
+ *
+ * Returns zero on success, else negative errno.
+ */
+static inline int
+usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA)
+{
+       if (!gadget->ops->vbus_draw)
+               return -EOPNOTSUPP;
+       return gadget->ops->vbus_draw (gadget, mA);
+}
+
+/**
+ * usb_gadget_vbus_disconnect - notify controller about VBUS session end
+ * @gadget:the device whose VBUS supply is being described
+ *
+ * This call is used by a driver for an external transceiver (or GPIO)
+ * that detects a VBUS power session ending.  Common responses include
+ * reversing everything done in usb_gadget_vbus_connect().
+ *
+ * Returns zero on success, else negative errno.
+ */
+static inline int
+usb_gadget_vbus_disconnect(struct usb_gadget *gadget)
+{
+       if (!gadget->ops->vbus_session)
+               return -EOPNOTSUPP;
+       return gadget->ops->vbus_session (gadget, 0);
+}
+
+/**
+ * usb_gadget_connect - software-controlled connect to USB host
+ * @gadget:the peripheral being connected
+ *
+ * Enables the D+ (or potentially D-) pullup.  The host will start
+ * enumerating this gadget when the pullup is active and a VBUS session
+ * is active (the link is powered).  This pullup is always enabled unless
+ * usb_gadget_disconnect() has been used to disable it.
+ *
+ * Returns zero on success, else negative errno.
+ */
+static inline int
+usb_gadget_connect (struct usb_gadget *gadget)
+{
+       if (!gadget->ops->pullup)
+               return -EOPNOTSUPP;
+       return gadget->ops->pullup (gadget, 1);
+}
+
+/**
+ * usb_gadget_disconnect - software-controlled disconnect from USB host
+ * @gadget:the peripheral being disconnected
+ *
+ * Disables the D+ (or potentially D-) pullup, which the host may see
+ * as a disconnect (when a VBUS session is active).  Not all systems
+ * support software pullup controls.
+ *
+ * This routine may be used during the gadget driver bind() call to prevent
+ * the peripheral from ever being visible to the USB host, unless later
+ * usb_gadget_connect() is called.  For example, user mode components may
+ * need to be activated before the system can talk to hosts.
+ *
+ * Returns zero on success, else negative errno.
+ */
+static inline int
+usb_gadget_disconnect (struct usb_gadget *gadget)
+{
+       if (!gadget->ops->pullup)
+               return -EOPNOTSUPP;
+       return gadget->ops->pullup (gadget, 0);
+}
+
+
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * struct usb_gadget_driver - driver for usb 'slave' devices
+ * @function: String describing the gadget's function
+ * @speed: Highest speed the driver handles.
+ * @bind: Invoked when the driver is bound to a gadget, usually
+ *     after registering the driver.
+ *     At that point, ep0 is fully initialized, and ep_list holds
+ *     the currently-available endpoints.
+ *     Called in a context that permits sleeping.
+ * @setup: Invoked for ep0 control requests that aren't handled by
+ *     the hardware level driver. Most calls must be handled by
+ *     the gadget driver, including descriptor and configuration
+ *     management.  The 16 bit members of the setup data are in
+ *     USB byte order. Called in_interrupt; this may not sleep.  Driver
+ *     queues a response to ep0, or returns negative to stall.
+ * @disconnect: Invoked after all transfers have been stopped,
+ *     when the host is disconnected.  May be called in_interrupt; this
+ *     may not sleep.  Some devices can't detect disconnect, so this might
+ *     not be called except as part of controller shutdown.
+ * @unbind: Invoked when the driver is unbound from a gadget,
+ *     usually from rmmod (after a disconnect is reported).
+ *     Called in a context that permits sleeping.
+ * @suspend: Invoked on USB suspend.  May be called in_interrupt.
+ * @resume: Invoked on USB resume.  May be called in_interrupt.
+ * @driver: Driver model state for this driver.
+ *
+ * Devices are disabled till a gadget driver successfully bind()s, which
+ * means the driver will handle setup() requests needed to enumerate (and
+ * meet "chapter 9" requirements) then do some useful work.
+ *
+ * If gadget->is_otg is true, the gadget driver must provide an OTG
+ * descriptor during enumeration, or else fail the bind() call.  In such
+ * cases, no USB traffic may flow until both bind() returns without
+ * having called usb_gadget_disconnect(), and the USB host stack has
+ * initialized.
+ *
+ * Drivers use hardware-specific knowledge to configure the usb hardware.
+ * endpoint addressing is only one of several hardware characteristics that
+ * are in descriptors the ep0 implementation returns from setup() calls.
+ *
+ * Except for ep0 implementation, most driver code shouldn't need change to
+ * run on top of different usb controllers.  It'll use endpoints set up by
+ * that ep0 implementation.
+ *
+ * The usb controller driver handles a few standard usb requests.  Those
+ * include set_address, and feature flags for devices, interfaces, and
+ * endpoints (the get_status, set_feature, and clear_feature requests).
+ *
+ * Accordingly, the driver's setup() callback must always implement all
+ * get_descriptor requests, returning at least a device descriptor and
+ * a configuration descriptor.  Drivers must make sure the endpoint
+ * descriptors match any hardware constraints. Some hardware also constrains
+ * other descriptors. (The pxa250 allows only configurations 1, 2, or 3).
+ *
+ * The driver's setup() callback must also implement set_configuration,
+ * and should also implement set_interface, get_configuration, and
+ * get_interface.  Setting a configuration (or interface) is where
+ * endpoints should be activated or (config 0) shut down.
+ *
+ * (Note that only the default control endpoint is supported.  Neither
+ * hosts nor devices generally support control traffic except to ep0.)
+ *
+ * Most devices will ignore USB suspend/resume operations, and so will
+ * not provide those callbacks.  However, some may need to change modes
+ * when the host is not longer directing those activities.  For example,
+ * local controls (buttons, dials, etc) may need to be re-enabled since
+ * the (remote) host can't do that any longer; or an error state might
+ * be cleared, to make the device behave identically whether or not
+ * power is maintained.
+ */
+struct usb_gadget_driver {
+       char                    *function;
+       enum usb_device_speed   speed;
+       int                     (*bind)(struct usb_gadget *);
+       void                    (*unbind)(struct usb_gadget *);
+       int                     (*setup)(struct usb_gadget *,
+                                       const struct usb_ctrlrequest *);
+       void                    (*disconnect)(struct usb_gadget *);
+       void                    (*suspend)(struct usb_gadget *);
+       void                    (*resume)(struct usb_gadget *);
+
+       // FIXME support safe rmmod
+       struct device_driver    driver;
+};
+
+
+
+/*-------------------------------------------------------------------------*/
+
+/* driver modules register and unregister, as usual.
+ * these calls must be made in a context that can sleep.
+ *
+ * these will usually be implemented directly by the hardware-dependent
+ * usb bus interface driver, which will only support a single driver.
+ */
+
+/**
+ * usb_gadget_register_driver - register a gadget driver
+ * @driver:the driver being registered
+ *
+ * Call this in your gadget driver's module initialization function,
+ * to tell the underlying usb controller driver about your driver.
+ * The driver's bind() function will be called to bind it to a
+ * gadget before this registration call returns.  It's expected that
+ * the bind() functions will be in init sections.
+ * This function must be called in a context that can sleep.
+ */
+int usb_gadget_register_driver (struct usb_gadget_driver *driver);
+
+/**
+ * usb_gadget_unregister_driver - unregister a gadget driver
+ * @driver:the driver being unregistered
+ *
+ * Call this in your gadget driver's module cleanup function,
+ * to tell the underlying usb controller that your driver is
+ * going away.  If the controller is connected to a USB host,
+ * it will first disconnect().  The driver is also requested
+ * to unbind() and clean up any device state, before this procedure
+ * finally returns.  It's expected that the unbind() functions
+ * will in in exit sections, so may not be linked in some kernels.
+ * This function must be called in a context that can sleep.
+ */
+int usb_gadget_unregister_driver (struct usb_gadget_driver *driver);
+
+/*-------------------------------------------------------------------------*/
+
+/* utility to simplify dealing with string descriptors */
+
+/**
+ * struct usb_string - wraps a C string and its USB id
+ * @id:the (nonzero) ID for this string
+ * @s:the string, in UTF-8 encoding
+ *
+ * If you're using usb_gadget_get_string(), use this to wrap a string
+ * together with its ID.
+ */
+struct usb_string {
+       u8                      id;
+       const char              *s;
+};
+
+/**
+ * struct usb_gadget_strings - a set of USB strings in a given language
+ * @language:identifies the strings' language (0x0409 for en-us)
+ * @strings:array of strings with their ids
+ *
+ * If you're using usb_gadget_get_string(), use this to wrap all the
+ * strings for a given language.
+ */
+struct usb_gadget_strings {
+       u16                     language;       /* 0x0409 for en-us */
+       struct usb_string       *strings;
+};
+
+/* put descriptor for string with that id into buf (buflen >= 256) */
+int usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf);
+
+/*-------------------------------------------------------------------------*/
+
+/* utility to simplify managing config descriptors */
+
+/* write vector of descriptors into buffer */
+int usb_descriptor_fillbuf(void *, unsigned,
+               const struct usb_descriptor_header **);
+
+/* build config descriptor from single descriptor vector */
+int usb_gadget_config_buf(const struct usb_config_descriptor *config,
+       void *buf, unsigned buflen, const struct usb_descriptor_header **desc);
+
+/*-------------------------------------------------------------------------*/
+
+/* utility wrapping a simple endpoint selection policy */
+
+extern struct usb_ep *usb_ep_autoconfig (struct usb_gadget *,
+                       struct usb_endpoint_descriptor *) __devinit;
+
+extern void usb_ep_autoconfig_reset (struct usb_gadget *) __devinit;
+
+#endif  /* __KERNEL__ */
+
+#endif /* __LINUX_USB_GADGET_H */
index 8da374caf582aeb3136c5d3f90722906ca8fa2dd..2692ec9389ca2047120f2b175b34076b88c0c049 100644 (file)
@@ -4,11 +4,8 @@
  * belong here.
  */
 
-/* device must not be autosuspended */
-#define USB_QUIRK_NO_AUTOSUSPEND       0x00000001
-
 /* string descriptors must not be fetched using a 255-byte read */
-#define USB_QUIRK_STRING_FETCH_255     0x00000002
+#define USB_QUIRK_STRING_FETCH_255     0x00000001
 
 /* device can't resume correctly so reset it instead */
-#define USB_QUIRK_RESET_RESUME         0x00000004
+#define USB_QUIRK_RESET_RESUME         0x00000002
index e8b8928232c85ca2db65b12b997acc4832dbb55e..488ce128885ceb1232bac30c2e3ec897edb50e5d 100644 (file)
@@ -141,7 +141,7 @@ struct usb_serial {
 };
 #define to_usb_serial(d) container_of(d, struct usb_serial, kref)
 
-#define NUM_DONT_CARE  (-1)
+#define NUM_DONT_CARE  99
 
 /* get and set the serial private data pointer helper functions */
 static inline void *usb_get_serial_data (struct usb_serial *serial)
@@ -160,12 +160,18 @@ static inline void usb_set_serial_data (struct usb_serial *serial, void *data)
  *     in the syslog messages when a device is inserted or removed.
  * @id_table: pointer to a list of usb_device_id structures that define all
  *     of the devices this structure can support.
- * @num_interrupt_in: the number of interrupt in endpoints this device will
- *     have.
- * @num_interrupt_out: the number of interrupt out endpoints this device will
- *     have.
- * @num_bulk_in: the number of bulk in endpoints this device will have.
- * @num_bulk_out: the number of bulk out endpoints this device will have.
+ * @num_interrupt_in: If a device doesn't have this many interrupt-in
+ *     endpoints, it won't be sent to the driver's attach() method.
+ *     (But it might still be sent to the probe() method.)
+ * @num_interrupt_out: If a device doesn't have this many interrupt-out
+ *     endpoints, it won't be sent to the driver's attach() method.
+ *     (But it might still be sent to the probe() method.)
+ * @num_bulk_in: If a device doesn't have this many bulk-in
+ *     endpoints, it won't be sent to the driver's attach() method.
+ *     (But it might still be sent to the probe() method.)
+ * @num_bulk_out: If a device doesn't have this many bulk-out
+ *     endpoints, it won't be sent to the driver's attach() method.
+ *     (But it might still be sent to the probe() method.)
  * @num_ports: the number of different ports this device will have.
  * @calc_num_ports: pointer to a function to determine how many ports this
  *     device has dynamically.  It will be called after the probe()
diff --git a/include/linux/usb_gadget.h b/include/linux/usb_gadget.h
deleted file mode 100644 (file)
index 4f59b2a..0000000
+++ /dev/null
@@ -1,833 +0,0 @@
-/*
- * <linux/usb_gadget.h>
- *
- * We call the USB code inside a Linux-based peripheral device a "gadget"
- * driver, except for the hardware-specific bus glue.  One USB host can
- * master many USB gadgets, but the gadgets are only slaved to one host.
- *
- *
- * (C) Copyright 2002-2004 by David Brownell
- * All Rights Reserved.
- *
- * This software is licensed under the GNU GPL version 2.
- */
-
-#ifndef __LINUX_USB_GADGET_H
-#define __LINUX_USB_GADGET_H
-
-#ifdef __KERNEL__
-
-struct usb_ep;
-
-/**
- * struct usb_request - describes one i/o request
- * @buf: Buffer used for data.  Always provide this; some controllers
- *     only use PIO, or don't use DMA for some endpoints.
- * @dma: DMA address corresponding to 'buf'.  If you don't set this
- *     field, and the usb controller needs one, it is responsible
- *     for mapping and unmapping the buffer.
- * @length: Length of that data
- * @no_interrupt: If true, hints that no completion irq is needed.
- *     Helpful sometimes with deep request queues that are handled
- *     directly by DMA controllers.
- * @zero: If true, when writing data, makes the last packet be "short"
- *     by adding a zero length packet as needed;
- * @short_not_ok: When reading data, makes short packets be
- *     treated as errors (queue stops advancing till cleanup).
- * @complete: Function called when request completes, so this request and
- *     its buffer may be re-used.
- *     Reads terminate with a short packet, or when the buffer fills,
- *     whichever comes first.  When writes terminate, some data bytes
- *     will usually still be in flight (often in a hardware fifo).
- *     Errors (for reads or writes) stop the queue from advancing
- *     until the completion function returns, so that any transfers
- *     invalidated by the error may first be dequeued.
- * @context: For use by the completion callback
- * @list: For use by the gadget driver.
- * @status: Reports completion code, zero or a negative errno.
- *     Normally, faults block the transfer queue from advancing until
- *     the completion callback returns.
- *     Code "-ESHUTDOWN" indicates completion caused by device disconnect,
- *     or when the driver disabled the endpoint.
- * @actual: Reports bytes transferred to/from the buffer.  For reads (OUT
- *     transfers) this may be less than the requested length.  If the
- *     short_not_ok flag is set, short reads are treated as errors
- *     even when status otherwise indicates successful completion.
- *     Note that for writes (IN transfers) some data bytes may still
- *     reside in a device-side FIFO when the request is reported as
- *     complete.
- *
- * These are allocated/freed through the endpoint they're used with.  The
- * hardware's driver can add extra per-request data to the memory it returns,
- * which often avoids separate memory allocations (potential failures),
- * later when the request is queued.
- *
- * Request flags affect request handling, such as whether a zero length
- * packet is written (the "zero" flag), whether a short read should be
- * treated as an error (blocking request queue advance, the "short_not_ok"
- * flag), or hinting that an interrupt is not required (the "no_interrupt"
- * flag, for use with deep request queues).
- *
- * Bulk endpoints can use any size buffers, and can also be used for interrupt
- * transfers. interrupt-only endpoints can be much less functional.
- */
-       // NOTE this is analagous to 'struct urb' on the host side,
-       // except that it's thinner and promotes more pre-allocation.
-
-struct usb_request {
-       void                    *buf;
-       unsigned                length;
-       dma_addr_t              dma;
-
-       unsigned                no_interrupt:1;
-       unsigned                zero:1;
-       unsigned                short_not_ok:1;
-
-       void                    (*complete)(struct usb_ep *ep,
-                                       struct usb_request *req);
-       void                    *context;
-       struct list_head        list;
-
-       int                     status;
-       unsigned                actual;
-};
-
-/*-------------------------------------------------------------------------*/
-
-/* endpoint-specific parts of the api to the usb controller hardware.
- * unlike the urb model, (de)multiplexing layers are not required.
- * (so this api could slash overhead if used on the host side...)
- *
- * note that device side usb controllers commonly differ in how many
- * endpoints they support, as well as their capabilities.
- */
-struct usb_ep_ops {
-       int (*enable) (struct usb_ep *ep,
-               const struct usb_endpoint_descriptor *desc);
-       int (*disable) (struct usb_ep *ep);
-
-       struct usb_request *(*alloc_request) (struct usb_ep *ep,
-               gfp_t gfp_flags);
-       void (*free_request) (struct usb_ep *ep, struct usb_request *req);
-
-       int (*queue) (struct usb_ep *ep, struct usb_request *req,
-               gfp_t gfp_flags);
-       int (*dequeue) (struct usb_ep *ep, struct usb_request *req);
-
-       int (*set_halt) (struct usb_ep *ep, int value);
-       int (*fifo_status) (struct usb_ep *ep);
-       void (*fifo_flush) (struct usb_ep *ep);
-};
-
-/**
- * struct usb_ep - device side representation of USB endpoint
- * @name:identifier for the endpoint, such as "ep-a" or "ep9in-bulk"
- * @ops: Function pointers used to access hardware-specific operations.
- * @ep_list:the gadget's ep_list holds all of its endpoints
- * @maxpacket:The maximum packet size used on this endpoint.  The initial
- *     value can sometimes be reduced (hardware allowing), according to
- *      the endpoint descriptor used to configure the endpoint.
- * @driver_data:for use by the gadget driver.  all other fields are
- *     read-only to gadget drivers.
- *
- * the bus controller driver lists all the general purpose endpoints in
- * gadget->ep_list.  the control endpoint (gadget->ep0) is not in that list,
- * and is accessed only in response to a driver setup() callback.
- */
-struct usb_ep {
-       void                    *driver_data;
-
-       const char              *name;
-       const struct usb_ep_ops *ops;
-       struct list_head        ep_list;
-       unsigned                maxpacket:16;
-};
-
-/*-------------------------------------------------------------------------*/
-
-/**
- * usb_ep_enable - configure endpoint, making it usable
- * @ep:the endpoint being configured.  may not be the endpoint named "ep0".
- *     drivers discover endpoints through the ep_list of a usb_gadget.
- * @desc:descriptor for desired behavior.  caller guarantees this pointer
- *     remains valid until the endpoint is disabled; the data byte order
- *     is little-endian (usb-standard).
- *
- * when configurations are set, or when interface settings change, the driver
- * will enable or disable the relevant endpoints.  while it is enabled, an
- * endpoint may be used for i/o until the driver receives a disconnect() from
- * the host or until the endpoint is disabled.
- *
- * the ep0 implementation (which calls this routine) must ensure that the
- * hardware capabilities of each endpoint match the descriptor provided
- * for it.  for example, an endpoint named "ep2in-bulk" would be usable
- * for interrupt transfers as well as bulk, but it likely couldn't be used
- * for iso transfers or for endpoint 14.  some endpoints are fully
- * configurable, with more generic names like "ep-a".  (remember that for
- * USB, "in" means "towards the USB master".)
- *
- * returns zero, or a negative error code.
- */
-static inline int
-usb_ep_enable (struct usb_ep *ep, const struct usb_endpoint_descriptor *desc)
-{
-       return ep->ops->enable (ep, desc);
-}
-
-/**
- * usb_ep_disable - endpoint is no longer usable
- * @ep:the endpoint being unconfigured.  may not be the endpoint named "ep0".
- *
- * no other task may be using this endpoint when this is called.
- * any pending and uncompleted requests will complete with status
- * indicating disconnect (-ESHUTDOWN) before this call returns.
- * gadget drivers must call usb_ep_enable() again before queueing
- * requests to the endpoint.
- *
- * returns zero, or a negative error code.
- */
-static inline int
-usb_ep_disable (struct usb_ep *ep)
-{
-       return ep->ops->disable (ep);
-}
-
-/**
- * usb_ep_alloc_request - allocate a request object to use with this endpoint
- * @ep:the endpoint to be used with with the request
- * @gfp_flags:GFP_* flags to use
- *
- * Request objects must be allocated with this call, since they normally
- * need controller-specific setup and may even need endpoint-specific
- * resources such as allocation of DMA descriptors.
- * Requests may be submitted with usb_ep_queue(), and receive a single
- * completion callback.  Free requests with usb_ep_free_request(), when
- * they are no longer needed.
- *
- * Returns the request, or null if one could not be allocated.
- */
-static inline struct usb_request *
-usb_ep_alloc_request (struct usb_ep *ep, gfp_t gfp_flags)
-{
-       return ep->ops->alloc_request (ep, gfp_flags);
-}
-
-/**
- * usb_ep_free_request - frees a request object
- * @ep:the endpoint associated with the request
- * @req:the request being freed
- *
- * Reverses the effect of usb_ep_alloc_request().
- * Caller guarantees the request is not queued, and that it will
- * no longer be requeued (or otherwise used).
- */
-static inline void
-usb_ep_free_request (struct usb_ep *ep, struct usb_request *req)
-{
-       ep->ops->free_request (ep, req);
-}
-
-/**
- * usb_ep_queue - queues (submits) an I/O request to an endpoint.
- * @ep:the endpoint associated with the request
- * @req:the request being submitted
- * @gfp_flags: GFP_* flags to use in case the lower level driver couldn't
- *     pre-allocate all necessary memory with the request.
- *
- * This tells the device controller to perform the specified request through
- * that endpoint (reading or writing a buffer).  When the request completes,
- * including being canceled by usb_ep_dequeue(), the request's completion
- * routine is called to return the request to the driver.  Any endpoint
- * (except control endpoints like ep0) may have more than one transfer
- * request queued; they complete in FIFO order.  Once a gadget driver
- * submits a request, that request may not be examined or modified until it
- * is given back to that driver through the completion callback.
- *
- * Each request is turned into one or more packets.  The controller driver
- * never merges adjacent requests into the same packet.  OUT transfers
- * will sometimes use data that's already buffered in the hardware.
- * Drivers can rely on the fact that the first byte of the request's buffer
- * always corresponds to the first byte of some USB packet, for both
- * IN and OUT transfers.
- *
- * Bulk endpoints can queue any amount of data; the transfer is packetized
- * automatically.  The last packet will be short if the request doesn't fill it
- * out completely.  Zero length packets (ZLPs) should be avoided in portable
- * protocols since not all usb hardware can successfully handle zero length
- * packets.  (ZLPs may be explicitly written, and may be implicitly written if
- * the request 'zero' flag is set.)  Bulk endpoints may also be used
- * for interrupt transfers; but the reverse is not true, and some endpoints
- * won't support every interrupt transfer.  (Such as 768 byte packets.)
- *
- * Interrupt-only endpoints are less functional than bulk endpoints, for
- * example by not supporting queueing or not handling buffers that are
- * larger than the endpoint's maxpacket size.  They may also treat data
- * toggle differently.
- *
- * Control endpoints ... after getting a setup() callback, the driver queues
- * one response (even if it would be zero length).  That enables the
- * status ack, after transfering data as specified in the response.  Setup
- * functions may return negative error codes to generate protocol stalls.
- * (Note that some USB device controllers disallow protocol stall responses
- * in some cases.)  When control responses are deferred (the response is
- * written after the setup callback returns), then usb_ep_set_halt() may be
- * used on ep0 to trigger protocol stalls.
- *
- * For periodic endpoints, like interrupt or isochronous ones, the usb host
- * arranges to poll once per interval, and the gadget driver usually will
- * have queued some data to transfer at that time.
- *
- * Returns zero, or a negative error code.  Endpoints that are not enabled
- * report errors; errors will also be
- * reported when the usb peripheral is disconnected.
- */
-static inline int
-usb_ep_queue (struct usb_ep *ep, struct usb_request *req, gfp_t gfp_flags)
-{
-       return ep->ops->queue (ep, req, gfp_flags);
-}
-
-/**
- * usb_ep_dequeue - dequeues (cancels, unlinks) an I/O request from an endpoint
- * @ep:the endpoint associated with the request
- * @req:the request being canceled
- *
- * if the request is still active on the endpoint, it is dequeued and its
- * completion routine is called (with status -ECONNRESET); else a negative
- * error code is returned.
- *
- * note that some hardware can't clear out write fifos (to unlink the request
- * at the head of the queue) except as part of disconnecting from usb.  such
- * restrictions prevent drivers from supporting configuration changes,
- * even to configuration zero (a "chapter 9" requirement).
- */
-static inline int usb_ep_dequeue (struct usb_ep *ep, struct usb_request *req)
-{
-       return ep->ops->dequeue (ep, req);
-}
-
-/**
- * usb_ep_set_halt - sets the endpoint halt feature.
- * @ep: the non-isochronous endpoint being stalled
- *
- * Use this to stall an endpoint, perhaps as an error report.
- * Except for control endpoints,
- * the endpoint stays halted (will not stream any data) until the host
- * clears this feature; drivers may need to empty the endpoint's request
- * queue first, to make sure no inappropriate transfers happen.
- *
- * Note that while an endpoint CLEAR_FEATURE will be invisible to the
- * gadget driver, a SET_INTERFACE will not be.  To reset endpoints for the
- * current altsetting, see usb_ep_clear_halt().  When switching altsettings,
- * it's simplest to use usb_ep_enable() or usb_ep_disable() for the endpoints.
- *
- * Returns zero, or a negative error code.  On success, this call sets
- * underlying hardware state that blocks data transfers.
- * Attempts to halt IN endpoints will fail (returning -EAGAIN) if any
- * transfer requests are still queued, or if the controller hardware
- * (usually a FIFO) still holds bytes that the host hasn't collected.
- */
-static inline int
-usb_ep_set_halt (struct usb_ep *ep)
-{
-       return ep->ops->set_halt (ep, 1);
-}
-
-/**
- * usb_ep_clear_halt - clears endpoint halt, and resets toggle
- * @ep:the bulk or interrupt endpoint being reset
- *
- * Use this when responding to the standard usb "set interface" request,
- * for endpoints that aren't reconfigured, after clearing any other state
- * in the endpoint's i/o queue.
- *
- * Returns zero, or a negative error code.  On success, this call clears
- * the underlying hardware state reflecting endpoint halt and data toggle.
- * Note that some hardware can't support this request (like pxa2xx_udc),
- * and accordingly can't correctly implement interface altsettings.
- */
-static inline int
-usb_ep_clear_halt (struct usb_ep *ep)
-{
-       return ep->ops->set_halt (ep, 0);
-}
-
-/**
- * usb_ep_fifo_status - returns number of bytes in fifo, or error
- * @ep: the endpoint whose fifo status is being checked.
- *
- * FIFO endpoints may have "unclaimed data" in them in certain cases,
- * such as after aborted transfers.  Hosts may not have collected all
- * the IN data written by the gadget driver (and reported by a request
- * completion).  The gadget driver may not have collected all the data
- * written OUT to it by the host.  Drivers that need precise handling for
- * fault reporting or recovery may need to use this call.
- *
- * This returns the number of such bytes in the fifo, or a negative
- * errno if the endpoint doesn't use a FIFO or doesn't support such
- * precise handling.
- */
-static inline int
-usb_ep_fifo_status (struct usb_ep *ep)
-{
-       if (ep->ops->fifo_status)
-               return ep->ops->fifo_status (ep);
-       else
-               return -EOPNOTSUPP;
-}
-
-/**
- * usb_ep_fifo_flush - flushes contents of a fifo
- * @ep: the endpoint whose fifo is being flushed.
- *
- * This call may be used to flush the "unclaimed data" that may exist in
- * an endpoint fifo after abnormal transaction terminations.  The call
- * must never be used except when endpoint is not being used for any
- * protocol translation.
- */
-static inline void
-usb_ep_fifo_flush (struct usb_ep *ep)
-{
-       if (ep->ops->fifo_flush)
-               ep->ops->fifo_flush (ep);
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-struct usb_gadget;
-
-/* the rest of the api to the controller hardware: device operations,
- * which don't involve endpoints (or i/o).
- */
-struct usb_gadget_ops {
-       int     (*get_frame)(struct usb_gadget *);
-       int     (*wakeup)(struct usb_gadget *);
-       int     (*set_selfpowered) (struct usb_gadget *, int is_selfpowered);
-       int     (*vbus_session) (struct usb_gadget *, int is_active);
-       int     (*vbus_draw) (struct usb_gadget *, unsigned mA);
-       int     (*pullup) (struct usb_gadget *, int is_on);
-       int     (*ioctl)(struct usb_gadget *,
-                               unsigned code, unsigned long param);
-};
-
-/**
- * struct usb_gadget - represents a usb slave device
- * @ops: Function pointers used to access hardware-specific operations.
- * @ep0: Endpoint zero, used when reading or writing responses to
- *     driver setup() requests
- * @ep_list: List of other endpoints supported by the device.
- * @speed: Speed of current connection to USB host.
- * @is_dualspeed: True if the controller supports both high and full speed
- *     operation.  If it does, the gadget driver must also support both.
- * @is_otg: True if the USB device port uses a Mini-AB jack, so that the
- *     gadget driver must provide a USB OTG descriptor.
- * @is_a_peripheral: False unless is_otg, the "A" end of a USB cable
- *     is in the Mini-AB jack, and HNP has been used to switch roles
- *     so that the "A" device currently acts as A-Peripheral, not A-Host.
- * @a_hnp_support: OTG device feature flag, indicating that the A-Host
- *     supports HNP at this port.
- * @a_alt_hnp_support: OTG device feature flag, indicating that the A-Host
- *     only supports HNP on a different root port.
- * @b_hnp_enable: OTG device feature flag, indicating that the A-Host
- *     enabled HNP support.
- * @name: Identifies the controller hardware type.  Used in diagnostics
- *     and sometimes configuration.
- * @dev: Driver model state for this abstract device.
- *
- * Gadgets have a mostly-portable "gadget driver" implementing device
- * functions, handling all usb configurations and interfaces.  Gadget
- * drivers talk to hardware-specific code indirectly, through ops vectors.
- * That insulates the gadget driver from hardware details, and packages
- * the hardware endpoints through generic i/o queues.  The "usb_gadget"
- * and "usb_ep" interfaces provide that insulation from the hardware.
- *
- * Except for the driver data, all fields in this structure are
- * read-only to the gadget driver.  That driver data is part of the
- * "driver model" infrastructure in 2.6 (and later) kernels, and for
- * earlier systems is grouped in a similar structure that's not known
- * to the rest of the kernel.
- *
- * Values of the three OTG device feature flags are updated before the
- * setup() call corresponding to USB_REQ_SET_CONFIGURATION, and before
- * driver suspend() calls.  They are valid only when is_otg, and when the
- * device is acting as a B-Peripheral (so is_a_peripheral is false).
- */
-struct usb_gadget {
-       /* readonly to gadget driver */
-       const struct usb_gadget_ops     *ops;
-       struct usb_ep                   *ep0;
-       struct list_head                ep_list;        /* of usb_ep */
-       enum usb_device_speed           speed;
-       unsigned                        is_dualspeed:1;
-       unsigned                        is_otg:1;
-       unsigned                        is_a_peripheral:1;
-       unsigned                        b_hnp_enable:1;
-       unsigned                        a_hnp_support:1;
-       unsigned                        a_alt_hnp_support:1;
-       const char                      *name;
-       struct device                   dev;
-};
-
-static inline void set_gadget_data (struct usb_gadget *gadget, void *data)
-       { dev_set_drvdata (&gadget->dev, data); }
-static inline void *get_gadget_data (struct usb_gadget *gadget)
-       { return dev_get_drvdata (&gadget->dev); }
-
-/* iterates the non-control endpoints; 'tmp' is a struct usb_ep pointer */
-#define gadget_for_each_ep(tmp,gadget) \
-       list_for_each_entry(tmp, &(gadget)->ep_list, ep_list)
-
-
-/**
- * usb_gadget_frame_number - returns the current frame number
- * @gadget: controller that reports the frame number
- *
- * Returns the usb frame number, normally eleven bits from a SOF packet,
- * or negative errno if this device doesn't support this capability.
- */
-static inline int usb_gadget_frame_number (struct usb_gadget *gadget)
-{
-       return gadget->ops->get_frame (gadget);
-}
-
-/**
- * usb_gadget_wakeup - tries to wake up the host connected to this gadget
- * @gadget: controller used to wake up the host
- *
- * Returns zero on success, else negative error code if the hardware
- * doesn't support such attempts, or its support has not been enabled
- * by the usb host.  Drivers must return device descriptors that report
- * their ability to support this, or hosts won't enable it.
- *
- * This may also try to use SRP to wake the host and start enumeration,
- * even if OTG isn't otherwise in use.  OTG devices may also start
- * remote wakeup even when hosts don't explicitly enable it.
- */
-static inline int usb_gadget_wakeup (struct usb_gadget *gadget)
-{
-       if (!gadget->ops->wakeup)
-               return -EOPNOTSUPP;
-       return gadget->ops->wakeup (gadget);
-}
-
-/**
- * usb_gadget_set_selfpowered - sets the device selfpowered feature.
- * @gadget:the device being declared as self-powered
- *
- * this affects the device status reported by the hardware driver
- * to reflect that it now has a local power supply.
- *
- * returns zero on success, else negative errno.
- */
-static inline int
-usb_gadget_set_selfpowered (struct usb_gadget *gadget)
-{
-       if (!gadget->ops->set_selfpowered)
-               return -EOPNOTSUPP;
-       return gadget->ops->set_selfpowered (gadget, 1);
-}
-
-/**
- * usb_gadget_clear_selfpowered - clear the device selfpowered feature.
- * @gadget:the device being declared as bus-powered
- *
- * this affects the device status reported by the hardware driver.
- * some hardware may not support bus-powered operation, in which
- * case this feature's value can never change.
- *
- * returns zero on success, else negative errno.
- */
-static inline int
-usb_gadget_clear_selfpowered (struct usb_gadget *gadget)
-{
-       if (!gadget->ops->set_selfpowered)
-               return -EOPNOTSUPP;
-       return gadget->ops->set_selfpowered (gadget, 0);
-}
-
-/**
- * usb_gadget_vbus_connect - Notify controller that VBUS is powered
- * @gadget:The device which now has VBUS power.
- *
- * This call is used by a driver for an external transceiver (or GPIO)
- * that detects a VBUS power session starting.  Common responses include
- * resuming the controller, activating the D+ (or D-) pullup to let the
- * host detect that a USB device is attached, and starting to draw power
- * (8mA or possibly more, especially after SET_CONFIGURATION).
- *
- * Returns zero on success, else negative errno.
- */
-static inline int
-usb_gadget_vbus_connect(struct usb_gadget *gadget)
-{
-       if (!gadget->ops->vbus_session)
-               return -EOPNOTSUPP;
-       return gadget->ops->vbus_session (gadget, 1);
-}
-
-/**
- * usb_gadget_vbus_draw - constrain controller's VBUS power usage
- * @gadget:The device whose VBUS usage is being described
- * @mA:How much current to draw, in milliAmperes.  This should be twice
- *     the value listed in the configuration descriptor bMaxPower field.
- *
- * This call is used by gadget drivers during SET_CONFIGURATION calls,
- * reporting how much power the device may consume.  For example, this
- * could affect how quickly batteries are recharged.
- *
- * Returns zero on success, else negative errno.
- */
-static inline int
-usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA)
-{
-       if (!gadget->ops->vbus_draw)
-               return -EOPNOTSUPP;
-       return gadget->ops->vbus_draw (gadget, mA);
-}
-
-/**
- * usb_gadget_vbus_disconnect - notify controller about VBUS session end
- * @gadget:the device whose VBUS supply is being described
- *
- * This call is used by a driver for an external transceiver (or GPIO)
- * that detects a VBUS power session ending.  Common responses include
- * reversing everything done in usb_gadget_vbus_connect().
- *
- * Returns zero on success, else negative errno.
- */
-static inline int
-usb_gadget_vbus_disconnect(struct usb_gadget *gadget)
-{
-       if (!gadget->ops->vbus_session)
-               return -EOPNOTSUPP;
-       return gadget->ops->vbus_session (gadget, 0);
-}
-
-/**
- * usb_gadget_connect - software-controlled connect to USB host
- * @gadget:the peripheral being connected
- *
- * Enables the D+ (or potentially D-) pullup.  The host will start
- * enumerating this gadget when the pullup is active and a VBUS session
- * is active (the link is powered).  This pullup is always enabled unless
- * usb_gadget_disconnect() has been used to disable it.
- *
- * Returns zero on success, else negative errno.
- */
-static inline int
-usb_gadget_connect (struct usb_gadget *gadget)
-{
-       if (!gadget->ops->pullup)
-               return -EOPNOTSUPP;
-       return gadget->ops->pullup (gadget, 1);
-}
-
-/**
- * usb_gadget_disconnect - software-controlled disconnect from USB host
- * @gadget:the peripheral being disconnected
- *
- * Disables the D+ (or potentially D-) pullup, which the host may see
- * as a disconnect (when a VBUS session is active).  Not all systems
- * support software pullup controls.
- *
- * This routine may be used during the gadget driver bind() call to prevent
- * the peripheral from ever being visible to the USB host, unless later
- * usb_gadget_connect() is called.  For example, user mode components may
- * need to be activated before the system can talk to hosts.
- *
- * Returns zero on success, else negative errno.
- */
-static inline int
-usb_gadget_disconnect (struct usb_gadget *gadget)
-{
-       if (!gadget->ops->pullup)
-               return -EOPNOTSUPP;
-       return gadget->ops->pullup (gadget, 0);
-}
-
-
-
-/*-------------------------------------------------------------------------*/
-
-/**
- * struct usb_gadget_driver - driver for usb 'slave' devices
- * @function: String describing the gadget's function
- * @speed: Highest speed the driver handles.
- * @bind: Invoked when the driver is bound to a gadget, usually
- *     after registering the driver.
- *     At that point, ep0 is fully initialized, and ep_list holds
- *     the currently-available endpoints.
- *     Called in a context that permits sleeping.
- * @setup: Invoked for ep0 control requests that aren't handled by
- *     the hardware level driver. Most calls must be handled by
- *     the gadget driver, including descriptor and configuration
- *     management.  The 16 bit members of the setup data are in
- *     USB byte order. Called in_interrupt; this may not sleep.  Driver
- *     queues a response to ep0, or returns negative to stall.
- * @disconnect: Invoked after all transfers have been stopped,
- *     when the host is disconnected.  May be called in_interrupt; this
- *     may not sleep.  Some devices can't detect disconnect, so this might
- *     not be called except as part of controller shutdown.
- * @unbind: Invoked when the driver is unbound from a gadget,
- *     usually from rmmod (after a disconnect is reported).
- *     Called in a context that permits sleeping.
- * @suspend: Invoked on USB suspend.  May be called in_interrupt.
- * @resume: Invoked on USB resume.  May be called in_interrupt.
- * @driver: Driver model state for this driver.
- *
- * Devices are disabled till a gadget driver successfully bind()s, which
- * means the driver will handle setup() requests needed to enumerate (and
- * meet "chapter 9" requirements) then do some useful work.
- *
- * If gadget->is_otg is true, the gadget driver must provide an OTG
- * descriptor during enumeration, or else fail the bind() call.  In such
- * cases, no USB traffic may flow until both bind() returns without
- * having called usb_gadget_disconnect(), and the USB host stack has
- * initialized.
- *
- * Drivers use hardware-specific knowledge to configure the usb hardware.
- * endpoint addressing is only one of several hardware characteristics that
- * are in descriptors the ep0 implementation returns from setup() calls.
- *
- * Except for ep0 implementation, most driver code shouldn't need change to
- * run on top of different usb controllers.  It'll use endpoints set up by
- * that ep0 implementation.
- *
- * The usb controller driver handles a few standard usb requests.  Those
- * include set_address, and feature flags for devices, interfaces, and
- * endpoints (the get_status, set_feature, and clear_feature requests).
- *
- * Accordingly, the driver's setup() callback must always implement all
- * get_descriptor requests, returning at least a device descriptor and
- * a configuration descriptor.  Drivers must make sure the endpoint
- * descriptors match any hardware constraints. Some hardware also constrains
- * other descriptors. (The pxa250 allows only configurations 1, 2, or 3).
- *
- * The driver's setup() callback must also implement set_configuration,
- * and should also implement set_interface, get_configuration, and
- * get_interface.  Setting a configuration (or interface) is where
- * endpoints should be activated or (config 0) shut down.
- *
- * (Note that only the default control endpoint is supported.  Neither
- * hosts nor devices generally support control traffic except to ep0.)
- *
- * Most devices will ignore USB suspend/resume operations, and so will
- * not provide those callbacks.  However, some may need to change modes
- * when the host is not longer directing those activities.  For example,
- * local controls (buttons, dials, etc) may need to be re-enabled since
- * the (remote) host can't do that any longer; or an error state might
- * be cleared, to make the device behave identically whether or not
- * power is maintained.
- */
-struct usb_gadget_driver {
-       char                    *function;
-       enum usb_device_speed   speed;
-       int                     (*bind)(struct usb_gadget *);
-       void                    (*unbind)(struct usb_gadget *);
-       int                     (*setup)(struct usb_gadget *,
-                                       const struct usb_ctrlrequest *);
-       void                    (*disconnect)(struct usb_gadget *);
-       void                    (*suspend)(struct usb_gadget *);
-       void                    (*resume)(struct usb_gadget *);
-
-       // FIXME support safe rmmod
-       struct device_driver    driver;
-};
-
-
-
-/*-------------------------------------------------------------------------*/
-
-/* driver modules register and unregister, as usual.
- * these calls must be made in a context that can sleep.
- *
- * these will usually be implemented directly by the hardware-dependent
- * usb bus interface driver, which will only support a single driver.
- */
-
-/**
- * usb_gadget_register_driver - register a gadget driver
- * @driver:the driver being registered
- *
- * Call this in your gadget driver's module initialization function,
- * to tell the underlying usb controller driver about your driver.
- * The driver's bind() function will be called to bind it to a
- * gadget before this registration call returns.  It's expected that
- * the bind() functions will be in init sections.
- * This function must be called in a context that can sleep.
- */
-int usb_gadget_register_driver (struct usb_gadget_driver *driver);
-
-/**
- * usb_gadget_unregister_driver - unregister a gadget driver
- * @driver:the driver being unregistered
- *
- * Call this in your gadget driver's module cleanup function,
- * to tell the underlying usb controller that your driver is
- * going away.  If the controller is connected to a USB host,
- * it will first disconnect().  The driver is also requested
- * to unbind() and clean up any device state, before this procedure
- * finally returns.  It's expected that the unbind() functions
- * will in in exit sections, so may not be linked in some kernels.
- * This function must be called in a context that can sleep.
- */
-int usb_gadget_unregister_driver (struct usb_gadget_driver *driver);
-
-/*-------------------------------------------------------------------------*/
-
-/* utility to simplify dealing with string descriptors */
-
-/**
- * struct usb_string - wraps a C string and its USB id
- * @id:the (nonzero) ID for this string
- * @s:the string, in UTF-8 encoding
- *
- * If you're using usb_gadget_get_string(), use this to wrap a string
- * together with its ID.
- */
-struct usb_string {
-       u8                      id;
-       const char              *s;
-};
-
-/**
- * struct usb_gadget_strings - a set of USB strings in a given language
- * @language:identifies the strings' language (0x0409 for en-us)
- * @strings:array of strings with their ids
- *
- * If you're using usb_gadget_get_string(), use this to wrap all the
- * strings for a given language.
- */
-struct usb_gadget_strings {
-       u16                     language;       /* 0x0409 for en-us */
-       struct usb_string       *strings;
-};
-
-/* put descriptor for string with that id into buf (buflen >= 256) */
-int usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf);
-
-/*-------------------------------------------------------------------------*/
-
-/* utility to simplify managing config descriptors */
-
-/* write vector of descriptors into buffer */
-int usb_descriptor_fillbuf(void *, unsigned,
-               const struct usb_descriptor_header **);
-
-/* build config descriptor from single descriptor vector */
-int usb_gadget_config_buf(const struct usb_config_descriptor *config,
-       void *buf, unsigned buflen, const struct usb_descriptor_header **desc);
-
-/*-------------------------------------------------------------------------*/
-
-/* utility wrapping a simple endpoint selection policy */
-
-extern struct usb_ep *usb_ep_autoconfig (struct usb_gadget *,
-                       struct usb_endpoint_descriptor *) __devinit;
-
-extern void usb_ep_autoconfig_reset (struct usb_gadget *) __devinit;
-
-#endif  /* __KERNEL__ */
-
-#endif /* __LINUX_USB_GADGET_H */
diff --git a/include/linux/usb_sl811.h b/include/linux/usb_sl811.h
deleted file mode 100644 (file)
index 4f2d012..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-
-/*
- * board initialization should put one of these into dev->platform_data
- * and place the sl811hs onto platform_bus named "sl811-hcd".
- */
-
-struct sl811_platform_data {
-       unsigned        can_wakeup:1;
-
-       /* given port_power, msec/2 after power on till power good */
-       u8              potpg;
-
-       /* mA/2 power supplied on this port (max = default = 250) */
-       u8              power;
-
-       /* sl811 relies on an external source of VBUS current */
-       void            (*port_power)(struct device *dev, int is_on);
-
-       /* pulse sl811 nRST (probably with a GPIO) */
-       void            (*reset)(struct device *dev);
-
-       // some boards need something like these:
-       // int          (*check_overcurrent)(struct device *dev);
-       // void         (*clock_enable)(struct device *dev, int is_on);
-};
-
index e63e0c03ee0d2be327022ad17fcefe8127ea12e7..2fb46bc9340d9b40617042ba8bb253754e4b6f67 100644 (file)
@@ -31,9 +31,9 @@ struct output_properties {
 struct output_device {
        int request_state;
        struct output_properties *props;
-       struct class_device class_dev;
+       struct device dev;
 };
-#define to_output_device(obj) container_of(obj, struct output_device, class_dev)
+#define to_output_device(obj) container_of(obj, struct output_device, dev)
 struct output_device *video_output_register(const char *name,
        struct device *dev,
        void *devdata,
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 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 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 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 f66351126544801116759583e26736f45ffb8402..8d53106a0a92c1dd619b6dc0f5e7841fc10824b4 100644 (file)
@@ -23,3 +23,8 @@ config HIGH_RES_TIMERS
          hardware is not capable then this option only increases
          the size of the kernel image.
 
+config GENERIC_CLOCKEVENTS_BUILD
+       bool
+       default y
+       depends on GENERIC_CLOCKEVENTS || GENERIC_CLOCKEVENTS_MIGR
+
index 99b6034fc86b40defbc2ecde23647c014eedcd9c..905b0b50792da7a9da1f3bbab3428604ec6ea9fb 100644 (file)
@@ -1,6 +1,6 @@
 obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o
 
-obj-$(CONFIG_GENERIC_CLOCKEVENTS)              += clockevents.o
+obj-$(CONFIG_GENERIC_CLOCKEVENTS_BUILD)                += clockevents.o
 obj-$(CONFIG_GENERIC_CLOCKEVENTS)              += tick-common.o
 obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)    += tick-broadcast.o
 obj-$(CONFIG_TICK_ONESHOT)                     += tick-oneshot.o
index 41dd3105ce7fd6846aabecb2f3d1b31410994bc4..822beebe664a59e98d3557c98a7ff8632423f6a1 100644 (file)
@@ -194,6 +194,7 @@ void clockevents_exchange_device(struct clock_event_device *old,
        local_irq_restore(flags);
 }
 
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
 /**
  * clockevents_notify - notification about relevant events
  */
@@ -222,4 +223,4 @@ void clockevents_notify(unsigned long reason, void *arg)
        spin_unlock(&clockevents_lock);
 }
 EXPORT_SYMBOL_GPL(clockevents_notify);
-
+#endif
index 0962e0577660722b11d69171a8d4ce5a57017ad6..fc3fc79b3d593c7e4c5e170431a6204228f2e697 100644 (file)
@@ -64,8 +64,9 @@ static void tick_broadcast_start_periodic(struct clock_event_device *bc)
  */
 int tick_check_broadcast_device(struct clock_event_device *dev)
 {
-       if (tick_broadcast_device.evtdev ||
-           (dev->features & CLOCK_EVT_FEAT_C3STOP))
+       if ((tick_broadcast_device.evtdev &&
+            tick_broadcast_device.evtdev->rating >= dev->rating) ||
+            (dev->features & CLOCK_EVT_FEAT_C3STOP))
                return 0;
 
        clockevents_exchange_device(NULL, dev);
@@ -176,8 +177,6 @@ static void tick_do_periodic_broadcast(void)
  */
 static void tick_handle_periodic_broadcast(struct clock_event_device *dev)
 {
-       dev->next_event.tv64 = KTIME_MAX;
-
        tick_do_periodic_broadcast();
 
        /*
@@ -218,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))
@@ -515,11 +531,9 @@ static void tick_broadcast_clear_oneshot(int cpu)
  */
 void tick_broadcast_setup_oneshot(struct clock_event_device *bc)
 {
-       if (bc->mode != CLOCK_EVT_MODE_ONESHOT) {
-               bc->event_handler = tick_handle_oneshot_broadcast;
-               clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT);
-               bc->next_event.tv64 = KTIME_MAX;
-       }
+       bc->event_handler = tick_handle_oneshot_broadcast;
+       clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT);
+       bc->next_event.tv64 = KTIME_MAX;
 }
 
 /*
index 77a21abc87167482ff63efea9480c4ed11cbb21b..1bea399a9ef009293958a8b37ac90dd5869fac40 100644 (file)
@@ -200,7 +200,7 @@ static int tick_check_new_device(struct clock_event_device *newdev)
 
        cpu = smp_processor_id();
        if (!cpu_isset(cpu, newdev->cpumask))
-               goto out;
+               goto out_bc;
 
        td = &per_cpu(tick_cpu_device, cpu);
        curdev = td->evtdev;
@@ -265,7 +265,7 @@ out_bc:
         */
        if (tick_check_broadcast_device(newdev))
                ret = NOTIFY_STOP;
-out:
+
        spin_unlock_irqrestore(&tick_device_lock, flags);
 
        return ret;
@@ -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 4f3f3e2565017e4e37c88d7c6f11f4326695cdcc..6c4ea33bb2cb0f8ffe2e1010f29ec11c375d2ddf 100644 (file)
@@ -10,7 +10,7 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \
 lib-$(CONFIG_MMU) += ioremap.o
 lib-$(CONFIG_SMP) += cpumask.o
 
-lib-y  += kobject.o kref.o kobject_uevent.o klist.o
+lib-y  += kobject.o kref.o klist.o
 
 obj-y += div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \
         bust_spinlocks.o hexdump.o kasprintf.o
@@ -20,6 +20,7 @@ CFLAGS_kobject.o += -DDEBUG
 CFLAGS_kobject_uevent.o += -DDEBUG
 endif
 
+lib-$(CONFIG_HOTPLUG) += kobject_uevent.o
 obj-$(CONFIG_GENERIC_IOMAP) += iomap.o
 obj-$(CONFIG_HAS_IOMEM) += iomap_copy.o devres.o
 obj-$(CONFIG_CHECK_SIGNATURE) += check_signature.o
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 4b08e0ff95c8bf53745cd6d5257476e0d652b92c..03d40360ff1be9682f4c192fec63e45b0d9e33fd 100644 (file)
@@ -2,6 +2,8 @@
  * kobject.c - library routines for handling generic kernel objects
  *
  * Copyright (c) 2002-2003 Patrick Mochel <mochel@osdl.org>
+ * Copyright (c) 2006-2007 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (c) 2006-2007 Novell Inc.
  *
  * This file is released under the GPLv2.
  *
@@ -44,11 +46,11 @@ static int populate_dir(struct kobject * kobj)
        return error;
 }
 
-static int create_dir(struct kobject *kobj, struct sysfs_dirent *shadow_parent)
+static int create_dir(struct kobject * kobj)
 {
        int error = 0;
        if (kobject_name(kobj)) {
-               error = sysfs_create_dir(kobj, shadow_parent);
+               error = sysfs_create_dir(kobj);
                if (!error) {
                        if ((error = populate_dir(kobj)))
                                sysfs_remove_dir(kobj);
@@ -131,7 +133,6 @@ void kobject_init(struct kobject * kobj)
                return;
        kref_init(&kobj->kref);
        INIT_LIST_HEAD(&kobj->entry);
-       init_waitqueue_head(&kobj->poll);
        kobj->kset = kset_get(kobj->kset);
 }
 
@@ -157,12 +158,11 @@ static void unlink(struct kobject * kobj)
 }
 
 /**
- *     kobject_shadow_add - add an object to the hierarchy.
+ *     kobject_add - add an object to the hierarchy.
  *     @kobj:  object.
- *     @shadow_parent: sysfs directory to add to.
  */
 
-int kobject_shadow_add(struct kobject *kobj, struct sysfs_dirent *shadow_parent)
+int kobject_add(struct kobject * kobj)
 {
        int error = 0;
        struct kobject * parent;
@@ -170,7 +170,7 @@ int kobject_shadow_add(struct kobject *kobj, struct sysfs_dirent *shadow_parent)
        if (!(kobj = kobject_get(kobj)))
                return -ENOENT;
        if (!kobj->k_name)
-               kobj->k_name = kobj->name;
+               kobject_set_name(kobj, "NO_NAME");
        if (!*kobj->k_name) {
                pr_debug("kobject attempted to be registered with no name!\n");
                WARN_ON(1);
@@ -181,7 +181,7 @@ int kobject_shadow_add(struct kobject *kobj, struct sysfs_dirent *shadow_parent)
 
        pr_debug("kobject %s: registering. parent: %s, set: %s\n",
                 kobject_name(kobj), parent ? kobject_name(parent) : "<NULL>", 
-                kobj->kset ? kobj->kset->kobj.name : "<NULL>" );
+                kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>" );
 
        if (kobj->kset) {
                spin_lock(&kobj->kset->list_lock);
@@ -194,7 +194,7 @@ int kobject_shadow_add(struct kobject *kobj, struct sysfs_dirent *shadow_parent)
                kobj->parent = parent;
        }
 
-       error = create_dir(kobj, shadow_parent);
+       error = create_dir(kobj);
        if (error) {
                /* unlink does the kobject_put() for us */
                unlink(kobj);
@@ -215,16 +215,6 @@ int kobject_shadow_add(struct kobject *kobj, struct sysfs_dirent *shadow_parent)
        return error;
 }
 
-/**
- *     kobject_add - add an object to the hierarchy.
- *     @kobj:  object.
- */
-int kobject_add(struct kobject * kobj)
-{
-       return kobject_shadow_add(kobj, NULL);
-}
-
-
 /**
  *     kobject_register - initialize and add an object.
  *     @kobj:  object in question.
@@ -255,54 +245,50 @@ int kobject_register(struct kobject * kobj)
 int kobject_set_name(struct kobject * kobj, const char * fmt, ...)
 {
        int error = 0;
-       int limit = KOBJ_NAME_LEN;
+       int limit;
        int need;
        va_list args;
-       char * name;
+       char *name;
 
-       /* 
-        * First, try the static array 
-        */
-       va_start(args,fmt);
-       need = vsnprintf(kobj->name,limit,fmt,args);
+       /* find out how big a buffer we need */
+       name = kmalloc(1024, GFP_KERNEL);
+       if (!name) {
+               error = -ENOMEM;
+               goto done;
+       }
+       va_start(args, fmt);
+       need = vsnprintf(name, 1024, fmt, args);
        va_end(args);
-       if (need < limit) 
-               name = kobj->name;
-       else {
-               /* 
-                * Need more space? Allocate it and try again 
-                */
-               limit = need + 1;
-               name = kmalloc(limit,GFP_KERNEL);
-               if (!name) {
-                       error = -ENOMEM;
-                       goto Done;
-               }
-               va_start(args,fmt);
-               need = vsnprintf(name,limit,fmt,args);
-               va_end(args);
-
-               /* Still? Give up. */
-               if (need >= limit) {
-                       kfree(name);
-                       error = -EFAULT;
-                       goto Done;
-               }
+       kfree(name);
+
+       /* Allocate the new space and copy the string in */
+       limit = need + 1;
+       name = kmalloc(limit, GFP_KERNEL);
+       if (!name) {
+               error = -ENOMEM;
+               goto done;
+       }
+       va_start(args, fmt);
+       need = vsnprintf(name, limit, fmt, args);
+       va_end(args);
+
+       /* something wrong with the string we copied? */
+       if (need >= limit) {
+               kfree(name);
+               error = -EFAULT;
+               goto done;
        }
 
        /* Free the old name, if necessary. */
-       if (kobj->k_name && kobj->k_name != kobj->name)
-               kfree(kobj->k_name);
+       kfree(kobj->k_name);
 
        /* Now, set the new name */
        kobj->k_name = name;
- Done:
+done:
        return error;
 }
-
 EXPORT_SYMBOL(kobject_set_name);
 
-
 /**
  *     kobject_rename - change the name of an object
  *     @kobj:  object in question.
@@ -338,7 +324,7 @@ int kobject_rename(struct kobject * kobj, const char *new_name)
        /* Note : if we want to send the new name alone, not the full path,
         * we could probably use kobject_name(kobj); */
 
-       error = sysfs_rename_dir(kobj, kobj->parent->sd, new_name);
+       error = sysfs_rename_dir(kobj, new_name);
 
        /* This function is mostly/only used for network interface.
         * Some hotplug package track interfaces by their name and
@@ -354,27 +340,6 @@ out:
        return error;
 }
 
-/**
- *     kobject_rename - change the name of an object
- *     @kobj:  object in question.
- *     @new_parent: object's new parent
- *     @new_name: object's new name
- */
-
-int kobject_shadow_rename(struct kobject *kobj,
-                         struct sysfs_dirent *new_parent, const char *new_name)
-{
-       int error = 0;
-
-       kobj = kobject_get(kobj);
-       if (!kobj)
-               return -EINVAL;
-       error = sysfs_rename_dir(kobj, new_parent, new_name);
-       kobject_put(kobj);
-
-       return error;
-}
-
 /**
  *     kobject_move - move object to another parent
  *     @kobj:  object in question.
@@ -477,13 +442,16 @@ void kobject_cleanup(struct kobject * kobj)
        struct kobj_type * t = get_ktype(kobj);
        struct kset * s = kobj->kset;
        struct kobject * parent = kobj->parent;
+       const char *name = kobj->k_name;
 
        pr_debug("kobject %s: cleaning up\n",kobject_name(kobj));
-       if (kobj->k_name != kobj->name)
-               kfree(kobj->k_name);
-       kobj->k_name = NULL;
-       if (t && t->release)
+       if (t && t->release) {
                t->release(kobj);
+               /* If we have a release function, we can guess that this was
+                * not a statically allocated kobject, so we should be safe to
+                * free the name */
+               kfree(name);
+       }
        if (s)
                kset_put(s);
        kobject_put(parent);
@@ -651,11 +619,6 @@ struct kobject * kset_find_obj(struct kset * kset, const char * name)
        return ret;
 }
 
-void subsystem_init(struct kset *s)
-{
-       kset_init(s);
-}
-
 int subsystem_register(struct kset *s)
 {
        return kset_register(s);
@@ -679,9 +642,9 @@ int subsys_create_file(struct kset *s, struct subsys_attribute *a)
        if (!s || !a)
                return -EINVAL;
 
-       if (subsys_get(s)) {
+       if (kset_get(s)) {
                error = sysfs_create_file(&s->kobj, &a->attr);
-               subsys_put(s);
+               kset_put(s);
        }
        return error;
 }
index e06a8dcec0f04ce9e566901be3fa52c786a74e41..2e4eae5b0824400de9f6eeafb5483c3fde8f5b0c 100644 (file)
 #include <linux/kobject.h>
 #include <net/sock.h>
 
-#define BUFFER_SIZE    2048    /* buffer for the variables */
-#define NUM_ENVP       32      /* number of env pointers */
 
-/* the strings here must match the enum in include/linux/kobject.h */
-const char *kobject_actions[] = {
-       "add",
-       "remove",
-       "change",
-       "move",
-       "online",
-       "offline",
-};
-
-#if defined(CONFIG_HOTPLUG)
 u64 uevent_seqnum;
-char uevent_helper[UEVENT_HELPER_PATH_LEN] = "/sbin/hotplug";
+char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH;
 static DEFINE_SPINLOCK(sequence_lock);
 #if defined(CONFIG_NET)
 static struct sock *uevent_sock;
 #endif
 
+/* the strings here must match the enum in include/linux/kobject.h */
+static const char *kobject_actions[] = {
+       [KOBJ_ADD] =            "add",
+       [KOBJ_REMOVE] =         "remove",
+       [KOBJ_CHANGE] =         "change",
+       [KOBJ_MOVE] =           "move",
+       [KOBJ_ONLINE] =         "online",
+       [KOBJ_OFFLINE] =        "offline",
+};
+
+/**
+ * kobject_action_type - translate action string to numeric type
+ *
+ * @buf: buffer containing the action string, newline is ignored
+ * @len: length of buffer
+ * @type: pointer to the location to store the action type
+ *
+ * Returns 0 if the action string was recognized.
+ */
+int kobject_action_type(const char *buf, size_t count,
+                       enum kobject_action *type)
+{
+       enum kobject_action action;
+       int ret = -EINVAL;
+
+       if (count && buf[count-1] == '\n')
+               count--;
+
+       if (!count)
+               goto out;
+
+       for (action = 0; action < ARRAY_SIZE(kobject_actions); action++) {
+               if (strncmp(kobject_actions[action], buf, count) != 0)
+                       continue;
+               if (kobject_actions[action][count] != '\0')
+                       continue;
+               *type = action;
+               ret = 0;
+               break;
+       }
+out:
+       return ret;
+}
+
 /**
  * kobject_uevent_env - send an uevent with environmental data
  *
- * @action: action that is happening (usually KOBJ_MOVE)
+ * @action: action that is happening
  * @kobj: struct kobject that the action is happening to
  * @envp_ext: pointer to environmental data
  *
@@ -54,36 +85,26 @@ static struct sock *uevent_sock;
  * corresponding error when it fails.
  */
 int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
-                       char *envp_ext[])
+                      char *envp_ext[])
 {
-       char **envp;
-       char *buffer;
-       char *scratch;
-       const char *action_string;
+       struct kobj_uevent_env *env;
+       const char *action_string = kobject_actions[action];
        const char *devpath = NULL;
        const char *subsystem;
        struct kobject *top_kobj;
        struct kset *kset;
        struct kset_uevent_ops *uevent_ops;
        u64 seq;
-       char *seq_buff;
        int i = 0;
        int retval = 0;
-       int j;
 
        pr_debug("%s\n", __FUNCTION__);
 
-       action_string = kobject_actions[action];
-       if (!action_string) {
-               pr_debug("kobject attempted to send uevent without action_string!\n");
-               return -EINVAL;
-       }
-
        /* search the kset we belong to */
        top_kobj = kobj;
-       while (!top_kobj->kset && top_kobj->parent) {
+       while (!top_kobj->kset && top_kobj->parent)
                top_kobj = top_kobj->parent;
-       }
+
        if (!top_kobj->kset) {
                pr_debug("kobject attempted to send uevent without kset!\n");
                return -EINVAL;
@@ -92,7 +113,7 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
        kset = top_kobj->kset;
        uevent_ops = kset->uevent_ops;
 
-       /*  skip the event, if the filter returns zero. */
+       /* skip the event, if the filter returns zero. */
        if (uevent_ops && uevent_ops->filter)
                if (!uevent_ops->filter(kset, kobj)) {
                        pr_debug("kobject filter function caused the event to drop!\n");
@@ -109,18 +130,11 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
                return 0;
        }
 
-       /* environment index */
-       envp = kzalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL);
-       if (!envp)
+       /* environment buffer */
+       env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
+       if (!env)
                return -ENOMEM;
 
-       /* environment values */
-       buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
-       if (!buffer) {
-               retval = -ENOMEM;
-               goto exit;
-       }
-
        /* complete object path */
        devpath = kobject_get_path(kobj, GFP_KERNEL);
        if (!devpath) {
@@ -128,29 +142,29 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
                goto exit;
        }
 
-       /* event environemnt for helper process only */
-       envp[i++] = "HOME=/";
-       envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
-
        /* default keys */
-       scratch = buffer;
-       envp [i++] = scratch;
-       scratch += sprintf(scratch, "ACTION=%s", action_string) + 1;
-       envp [i++] = scratch;
-       scratch += sprintf (scratch, "DEVPATH=%s", devpath) + 1;
-       envp [i++] = scratch;
-       scratch += sprintf(scratch, "SUBSYSTEM=%s", subsystem) + 1;
-       for (j = 0; envp_ext && envp_ext[j]; j++)
-               envp[i++] = envp_ext[j];
-       /* just reserve the space, overwrite it after kset call has returned */
-       envp[i++] = seq_buff = scratch;
-       scratch += strlen("SEQNUM=18446744073709551616") + 1;
+       retval = add_uevent_var(env, "ACTION=%s", action_string);
+       if (retval)
+               goto exit;
+       retval = add_uevent_var(env, "DEVPATH=%s", devpath);
+       if (retval)
+               goto exit;
+       retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem);
+       if (retval)
+               goto exit;
+
+       /* keys passed in from the caller */
+       if (envp_ext) {
+               for (i = 0; envp_ext[i]; i++) {
+                       retval = add_uevent_var(env, envp_ext[i]);
+                       if (retval)
+                               goto exit;
+               }
+       }
 
        /* let the kset specific function add its stuff */
        if (uevent_ops && uevent_ops->uevent) {
-               retval = uevent_ops->uevent(kset, kobj,
-                                 &envp[i], NUM_ENVP - i, scratch,
-                                 BUFFER_SIZE - (scratch - buffer));
+               retval = uevent_ops->uevent(kset, kobj, env);
                if (retval) {
                        pr_debug ("%s - uevent() returned %d\n",
                                  __FUNCTION__, retval);
@@ -158,11 +172,13 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
                }
        }
 
-       /* we will send an event, request a new sequence number */
+       /* we will send an event, so request a new sequence number */
        spin_lock(&sequence_lock);
        seq = ++uevent_seqnum;
        spin_unlock(&sequence_lock);
-       sprintf(seq_buff, "SEQNUM=%llu", (unsigned long long)seq);
+       retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)seq);
+       if (retval)
+               goto exit;
 
 #if defined(CONFIG_NET)
        /* send netlink message */
@@ -172,17 +188,19 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
 
                /* allocate message with the maximum possible size */
                len = strlen(action_string) + strlen(devpath) + 2;
-               skb = alloc_skb(len + BUFFER_SIZE, GFP_KERNEL);
+               skb = alloc_skb(len + env->buflen, GFP_KERNEL);
                if (skb) {
+                       char *scratch;
+
                        /* add header */
                        scratch = skb_put(skb, len);
                        sprintf(scratch, "%s@%s", action_string, devpath);
 
                        /* copy keys to our continuous event payload buffer */
-                       for (i = 2; envp[i]; i++) {
-                               len = strlen(envp[i]) + 1;
+                       for (i = 0; i < env->envp_idx; i++) {
+                               len = strlen(env->envp[i]) + 1;
                                scratch = skb_put(skb, len);
-                               strcpy(scratch, envp[i]);
+                               strcpy(scratch, env->envp[i]);
                        }
 
                        NETLINK_CB(skb).dst_group = 1;
@@ -198,13 +216,19 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
                argv [0] = uevent_helper;
                argv [1] = (char *)subsystem;
                argv [2] = NULL;
-               call_usermodehelper (argv[0], argv, envp, UMH_WAIT_EXEC);
+               retval = add_uevent_var(env, "HOME=/");
+               if (retval)
+                       goto exit;
+               retval = add_uevent_var(env, "PATH=/sbin:/bin:/usr/sbin:/usr/bin");
+               if (retval)
+                       goto exit;
+
+               call_usermodehelper (argv[0], argv, env->envp, UMH_WAIT_EXEC);
        }
 
 exit:
        kfree(devpath);
-       kfree(buffer);
-       kfree(envp);
+       kfree(env);
        return retval;
 }
 
@@ -213,7 +237,7 @@ EXPORT_SYMBOL_GPL(kobject_uevent_env);
 /**
  * kobject_uevent - notify userspace by ending an uevent
  *
- * @action: action that is happening (usually KOBJ_ADD and KOBJ_REMOVE)
+ * @action: action that is happening
  * @kobj: struct kobject that the action is happening to
  *
  * Returns 0 if kobject_uevent() is completed with success or the
@@ -227,52 +251,38 @@ int kobject_uevent(struct kobject *kobj, enum kobject_action action)
 EXPORT_SYMBOL_GPL(kobject_uevent);
 
 /**
- * add_uevent_var - helper for creating event variables
- * @envp: Pointer to table of environment variables, as passed into
- * uevent() method.
- * @num_envp: Number of environment variable slots available, as
- * passed into uevent() method.
- * @cur_index: Pointer to current index into @envp.  It should be
- * initialized to 0 before the first call to add_uevent_var(),
- * and will be incremented on success.
- * @buffer: Pointer to buffer for environment variables, as passed
- * into uevent() method.
- * @buffer_size: Length of @buffer, as passed into uevent() method.
- * @cur_len: Pointer to current length of space used in @buffer.
- * Should be initialized to 0 before the first call to
- * add_uevent_var(), and will be incremented on success.
- * @format: Format for creating environment variable (of the form
- * "XXX=%x") for snprintf().
+ * add_uevent_var - add key value string to the environment buffer
+ * @env: environment buffer structure
+ * @format: printf format for the key=value pair
  *
  * Returns 0 if environment variable was added successfully or -ENOMEM
  * if no space was available.
  */
-int add_uevent_var(char **envp, int num_envp, int *cur_index,
-                  char *buffer, int buffer_size, int *cur_len,
-                  const char *format, ...)
+int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...)
 {
        va_list args;
+       int len;
 
-       /*
-        * We check against num_envp - 1 to make sure there is at
-        * least one slot left after we return, since kobject_uevent()
-        * needs to set the last slot to NULL.
-        */
-       if (*cur_index >= num_envp - 1)
+       if (env->envp_idx >= ARRAY_SIZE(env->envp)) {
+               printk(KERN_ERR "add_uevent_var: too many keys\n");
+               WARN_ON(1);
                return -ENOMEM;
-
-       envp[*cur_index] = buffer + *cur_len;
+       }
 
        va_start(args, format);
-       *cur_len += vsnprintf(envp[*cur_index],
-                             max(buffer_size - *cur_len, 0),
-                             format, args) + 1;
+       len = vsnprintf(&env->buf[env->buflen],
+                       sizeof(env->buf) - env->buflen,
+                       format, args);
        va_end(args);
 
-       if (*cur_len > buffer_size)
+       if (len >= (sizeof(env->buf) - env->buflen)) {
+               printk(KERN_ERR "add_uevent_var: buffer size too small\n");
+               WARN_ON(1);
                return -ENOMEM;
+       }
 
-       (*cur_index)++;
+       env->envp[env->envp_idx++] = &env->buf[env->buflen];
+       env->buflen += len + 1;
        return 0;
 }
 EXPORT_SYMBOL_GPL(add_uevent_var);
@@ -293,5 +303,3 @@ static int __init kobject_uevent_init(void)
 
 postcore_initcall(kobject_uevent_init);
 #endif
-
-#endif /* CONFIG_HOTPLUG */
index a7381d55663a9f219f8313a4801614309ba9d207..30c1400e749e8299be6767e32e9f3531ae18a0a4 100644 (file)
@@ -497,6 +497,7 @@ void
 swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr,
                      dma_addr_t dma_handle)
 {
+       WARN_ON(irqs_disabled());
        if (!(vaddr >= (void *)io_tlb_start
                     && vaddr < (void *)io_tlb_end))
                free_pages((unsigned long) vaddr, get_order(size));
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 f094a0879c16ddedcb386c6ca749a23f6c32fe9c..9ef07eda2c437be45c4fbba4a984c2ca04d929c9 100644 (file)
@@ -105,10 +105,9 @@ static struct class_device_attribute *atm_attrs[] = {
        NULL
 };
 
-static int atm_uevent(struct class_device *cdev, char **envp, int num_envp, char *buf, int size)
+static int atm_uevent(struct class_device *cdev, struct kobj_uevent_env *env)
 {
        struct atm_dev *adev;
-       int i = 0, len = 0;
 
        if (!cdev)
                return -ENODEV;
@@ -117,11 +116,9 @@ static int atm_uevent(struct class_device *cdev, char **envp, int num_envp, char
        if (!adev)
                return -ENODEV;
 
-       if (add_uevent_var(envp, num_envp, &i, buf, size, &len,
-                          "NAME=%s%d", adev->type, adev->number))
+       if (add_uevent_var(env, "NAME=%s%d", adev->type, adev->number))
                return -ENOMEM;
 
-       envp[i] = NULL;
        return 0;
 }
 
index c65f54e0e27febec09a75df717374ed05d015e11..3312e8f2abe47b46e2af85212b93de67adf6c3de 100644 (file)
@@ -435,7 +435,7 @@ int br_sysfs_addbr(struct net_device *dev)
        err = kobject_register(&br->ifobj);
        if (err) {
                pr_info("%s: can't add kobject (directory) %s/%s\n",
-                       __FUNCTION__, dev->name, br->ifobj.name);
+                       __FUNCTION__, dev->name, kobject_name(&br->ifobj));
                goto out3;
        }
        return 0;
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 909a03d6c0e9578abf0894a19dd800080aa1ca03..6628e457ddc0f1179e3e5fc42e965eaf19b9b283 100644 (file)
@@ -396,28 +396,22 @@ static struct attribute_group wireless_group = {
 #endif /* CONFIG_SYSFS */
 
 #ifdef CONFIG_HOTPLUG
-static int netdev_uevent(struct device *d, char **envp,
-                        int num_envp, char *buf, int size)
+static int netdev_uevent(struct device *d, struct kobj_uevent_env *env)
 {
        struct net_device *dev = to_net_dev(d);
-       int retval, len = 0, i = 0;
+       int retval;
 
        /* pass interface to uevent. */
-       retval = add_uevent_var(envp, num_envp, &i,
-                               buf, size, &len,
-                               "INTERFACE=%s", dev->name);
+       retval = add_uevent_var(env, "INTERFACE=%s", dev->name);
        if (retval)
                goto exit;
 
        /* pass ifindex to uevent.
         * ifindex is useful as it won't change (interface name may change)
         * and is what RtNetlink uses natively. */
-       retval = add_uevent_var(envp, num_envp, &i,
-                               buf, size, &len,
-                               "IFINDEX=%d", dev->ifindex);
+       retval = add_uevent_var(env, "IFINDEX=%d", dev->ifindex);
 
 exit:
-       envp[i] = NULL;
        return retval;
 }
 #endif
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 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 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 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 2d5d2255a27cd54bb12c1a21724680a5cdba617d..29f820e182511fcf8a70bf672e32887404f9cb10 100644 (file)
@@ -53,8 +53,7 @@ static void wiphy_dev_release(struct device *dev)
 }
 
 #ifdef CONFIG_HOTPLUG
-static int wiphy_uevent(struct device *dev, char **envp,
-                       int num_envp, char *buf, int size)
+static int wiphy_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        /* TODO, we probably need stuff here */
        return 0;
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 64d1639143359cc85d93d0b2740bf86d62e6e830..f84f3e505788f36d0ecaee4eb33b13cf60263383 100644 (file)
@@ -56,13 +56,12 @@ static int soundbus_probe(struct device *dev)
 }
 
 
-static int soundbus_uevent(struct device *dev, char **envp, int num_envp,
-                          char *buffer, int buffer_size)
+static int soundbus_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        struct soundbus_dev * soundbus_dev;
        struct of_device * of;
        const char *compat;
-       int retval = 0, i = 0, length = 0;
+       int retval = 0;
        int cplen, seen = 0;
 
        if (!dev)
@@ -75,15 +74,11 @@ static int soundbus_uevent(struct device *dev, char **envp, int num_envp,
        of = &soundbus_dev->ofdev;
 
        /* stuff we want to pass to /sbin/hotplug */
-       retval = add_uevent_var(envp, num_envp, &i,
-                               buffer, buffer_size, &length,
-                               "OF_NAME=%s", of->node->name);
+       retval = add_uevent_var(env, "OF_NAME=%s", of->node->name);
        if (retval)
                return retval;
 
-       retval = add_uevent_var(envp, num_envp, &i,
-                               buffer, buffer_size, &length,
-                               "OF_TYPE=%s", of->node->type);
+       retval = add_uevent_var(env, "OF_TYPE=%s", of->node->type);
        if (retval)
                return retval;
 
@@ -93,27 +88,19 @@ static int soundbus_uevent(struct device *dev, char **envp, int num_envp,
 
        compat = of_get_property(of->node, "compatible", &cplen);
        while (compat && cplen > 0) {
-               int tmp = length;
-               retval = add_uevent_var(envp, num_envp, &i,
-                                       buffer, buffer_size, &length,
-                                       "OF_COMPATIBLE_%d=%s", seen, compat);
+               int tmp = env->buflen;
+               retval = add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat);
                if (retval)
                        return retval;
-               compat += length - tmp;
-               cplen -= length - tmp;
+               compat += env->buflen - tmp;
+               cplen -= env->buflen - tmp;
                seen += 1;
        }
 
-       retval = add_uevent_var(envp, num_envp, &i,
-                               buffer, buffer_size, &length,
-                               "OF_COMPATIBLE_N=%d", seen);
+       retval = add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen);
        if (retval)
                return retval;
-       retval = add_uevent_var(envp, num_envp, &i,
-                               buffer, buffer_size, &length,
-                               "MODALIAS=%s", soundbus_dev->modalias);
-
-       envp[i] = NULL;
+       retval = add_uevent_var(env, "MODALIAS=%s", soundbus_dev->modalias);
 
        return retval;
 }
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) {
This page took 3.055762 seconds and 5 git commands to generate.