summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/stable/sysfs-driver-qla2xxx8
-rw-r--r--Documentation/ABI/testing/procfs-diskstats2
-rw-r--r--Documentation/ABI/testing/sysfs-block2
-rw-r--r--Documentation/DMA-mapping.txt6
-rw-r--r--Documentation/DocBook/genericirq.tmpl4
-rw-r--r--Documentation/DocBook/kernel-hacking.tmpl2
-rw-r--r--Documentation/DocBook/mtdnand.tmpl2
-rw-r--r--Documentation/DocBook/v4l/videodev2.h.xml2
-rw-r--r--Documentation/DocBook/writing-an-alsa-driver.tmpl2
-rw-r--r--Documentation/dvb/README.dvb-usb2
-rw-r--r--Documentation/edac.txt7
-rw-r--r--Documentation/filesystems/proc.txt4
-rw-r--r--Documentation/gpio.txt4
-rw-r--r--Documentation/kernel-parameters.txt9
-rw-r--r--Documentation/lguest/lguest.c2
-rw-r--r--Documentation/misc-devices/c2port.txt (renamed from Documentation/c2port.txt)0
-rw-r--r--Documentation/misc-devices/ics932s401 (renamed from Documentation/ics932s401)0
-rw-r--r--Documentation/oops-tracing.txt2
-rw-r--r--Documentation/power/regulator/consumer.txt2
-rw-r--r--Documentation/scsi/ChangeLog.megaraid_sas64
-rw-r--r--Documentation/spi/spi-summary2
-rw-r--r--Documentation/sysctl/kernel.txt6
-rw-r--r--Documentation/sysctl/vm.txt2
-rw-r--r--Documentation/timers/hpet.txt2
-rw-r--r--Documentation/video4linux/gspca.txt2
-rw-r--r--Documentation/vm/page-types.c2
-rw-r--r--Documentation/vm/slub.txt2
-rw-r--r--MAINTAINERS18
-rw-r--r--arch/alpha/mm/numa.c2
-rw-r--r--arch/arm/common/scoop.c2
-rw-r--r--arch/arm/configs/da830_omapl137_defconfig1254
-rw-r--r--arch/arm/configs/da8xx_omapl_defconfig (renamed from arch/arm/configs/da850_omapl138_defconfig)257
-rw-r--r--arch/arm/configs/davinci_all_defconfig126
-rw-r--r--arch/arm/mach-bcmring/include/csp/reg.h2
-rw-r--r--arch/arm/mach-bcmring/include/mach/csp/dmacHw_priv.h2
-rw-r--r--arch/arm/mach-bcmring/include/mach/csp/mm_addr.h2
-rw-r--r--arch/arm/mach-bcmring/include/mach/dma.h2
-rw-r--r--arch/arm/mach-davinci/Kconfig59
-rw-r--r--arch/arm/mach-davinci/Makefile5
-rw-r--r--arch/arm/mach-davinci/board-da830-evm.c466
-rw-r--r--arch/arm/mach-davinci/board-da850-evm.c437
-rw-r--r--arch/arm/mach-davinci/board-dm355-evm.c16
-rw-r--r--arch/arm/mach-davinci/board-dm355-leopard.c13
-rw-r--r--arch/arm/mach-davinci/board-dm365-evm.c57
-rw-r--r--arch/arm/mach-davinci/board-dm644x-evm.c15
-rw-r--r--arch/arm/mach-davinci/board-dm646x-evm.c86
-rw-r--r--arch/arm/mach-davinci/board-neuros-osd2.c323
-rw-r--r--arch/arm/mach-davinci/board-sffsdr.c20
-rw-r--r--arch/arm/mach-davinci/clock.c231
-rw-r--r--arch/arm/mach-davinci/clock.h17
-rw-r--r--arch/arm/mach-davinci/common.c4
-rw-r--r--arch/arm/mach-davinci/cp_intc.c3
-rw-r--r--arch/arm/mach-davinci/cpufreq.c226
-rw-r--r--arch/arm/mach-davinci/cpuidle.c197
-rw-r--r--arch/arm/mach-davinci/da830.c75
-rw-r--r--arch/arm/mach-davinci/da850.c298
-rw-r--r--arch/arm/mach-davinci/devices-da8xx.c106
-rw-r--r--arch/arm/mach-davinci/devices.c6
-rw-r--r--arch/arm/mach-davinci/dm355.c2
-rw-r--r--arch/arm/mach-davinci/dm365.c107
-rw-r--r--arch/arm/mach-davinci/dm644x.c7
-rw-r--r--arch/arm/mach-davinci/dm646x.c11
-rw-r--r--arch/arm/mach-davinci/dma.c105
-rw-r--r--arch/arm/mach-davinci/gpio.c9
-rw-r--r--arch/arm/mach-davinci/include/mach/asp.h3
-rw-r--r--arch/arm/mach-davinci/include/mach/common.h6
-rw-r--r--arch/arm/mach-davinci/include/mach/cpufreq.h26
-rw-r--r--arch/arm/mach-davinci/include/mach/cpuidle.h17
-rw-r--r--arch/arm/mach-davinci/include/mach/da8xx.h26
-rw-r--r--arch/arm/mach-davinci/include/mach/dm365.h10
-rw-r--r--arch/arm/mach-davinci/include/mach/dm644x.h1
-rw-r--r--arch/arm/mach-davinci/include/mach/irqs.h1
-rw-r--r--arch/arm/mach-davinci/include/mach/mux.h20
-rw-r--r--arch/arm/mach-davinci/include/mach/system.h3
-rw-r--r--arch/arm/mach-davinci/include/mach/usb.h59
-rw-r--r--arch/arm/mach-davinci/mux.c1
-rw-r--r--arch/arm/mach-davinci/psc.c3
-rw-r--r--arch/arm/mach-davinci/serial.c6
-rw-r--r--arch/arm/mach-davinci/sram.c3
-rw-r--r--arch/arm/mach-davinci/time.c6
-rw-r--r--arch/arm/mach-davinci/usb.c84
-rw-r--r--arch/arm/mach-lh7a40x/include/mach/hardware.h2
-rw-r--r--arch/arm/mach-orion5x/pci.c2
-rw-r--r--arch/arm/mach-pxa/include/mach/palmld.h2
-rw-r--r--arch/arm/mach-pxa/include/mach/palmt5.h2
-rw-r--r--arch/arm/mach-pxa/include/mach/palmtc.h2
-rw-r--r--arch/arm/mach-pxa/include/mach/palmte2.h2
-rw-r--r--arch/arm/mach-pxa/include/mach/palmtx.h2
-rw-r--r--arch/arm/mach-pxa/include/mach/palmz72.h2
-rw-r--r--arch/arm/mach-s3c2400/Kconfig6
-rw-r--r--arch/arm/mach-s3c2410/Kconfig2
-rw-r--r--arch/arm/mach-s3c2412/Kconfig4
-rw-r--r--arch/arm/mach-s3c2440/Kconfig3
-rw-r--r--arch/arm/mach-s3c2442/Kconfig4
-rw-r--r--arch/arm/mach-s3c2443/Kconfig2
-rw-r--r--arch/arm/mach-s3c6400/Kconfig2
-rw-r--r--arch/arm/mach-s3c6400/setup-sdhci.c2
-rw-r--r--arch/arm/mach-s3c6410/Kconfig2
-rw-r--r--arch/arm/mach-s3c6410/setup-sdhci.c2
-rw-r--r--arch/arm/mach-s5pc100/Kconfig2
-rw-r--r--arch/arm/mach-sa1100/dma.c2
-rw-r--r--arch/arm/mach-u300/include/mach/u300-regs.h2
-rw-r--r--arch/arm/plat-mxc/include/mach/iomux-mx3.h2
-rw-r--r--arch/arm/plat-mxc/include/mach/iomux-mxc91231.h2
-rw-r--r--arch/arm/plat-mxc/pwm.c2
-rw-r--r--arch/arm/plat-omap/dma.c2
-rw-r--r--arch/arm/plat-omap/include/plat/omap16xx.h2
-rw-r--r--arch/arm/plat-s3c/Kconfig2
-rw-r--r--arch/arm/plat-s3c/pwm.c2
-rw-r--r--arch/arm/plat-s3c24xx/Kconfig2
-rw-r--r--arch/arm/plat-s3c24xx/adc.c2
-rw-r--r--arch/arm/plat-s3c24xx/dma.c6
-rw-r--r--arch/arm/plat-s3c24xx/include/plat/map.h2
-rw-r--r--arch/arm/plat-s3c24xx/irq.c2
-rw-r--r--arch/arm/plat-s3c64xx/Kconfig2
-rw-r--r--arch/arm/plat-s5pc1xx/Kconfig2
-rw-r--r--arch/avr32/boards/hammerhead/Kconfig2
-rw-r--r--arch/blackfin/kernel/process.c6
-rw-r--r--arch/blackfin/kernel/traps.c2
-rw-r--r--arch/blackfin/mach-bf518/include/mach/defBF51x_base.h4
-rw-r--r--arch/blackfin/mach-bf527/include/mach/defBF52x_base.h4
-rw-r--r--arch/blackfin/mach-bf537/include/mach/defBF534.h4
-rw-r--r--arch/blackfin/mach-bf548/include/mach/defBF544.h4
-rw-r--r--arch/blackfin/mach-bf548/include/mach/defBF547.h4
-rw-r--r--arch/blackfin/mach-bf548/include/mach/defBF548.h4
-rw-r--r--arch/blackfin/mach-bf548/include/mach/defBF549.h4
-rw-r--r--arch/cris/arch-v10/mm/fault.c3
-rw-r--r--arch/cris/arch-v10/mm/tlb.c22
-rw-r--r--arch/cris/mm/fault.c2
-rw-r--r--arch/frv/kernel/process.c5
-rw-r--r--arch/h8300/kernel/process.c5
-rw-r--r--arch/ia64/hp/common/sba_iommu.c2
-rw-r--r--arch/ia64/ia32/ia32_entry.S2
-rw-r--r--arch/ia64/include/asm/perfmon_default_smpl.h2
-rw-r--r--arch/ia64/include/asm/sn/shubio.h2
-rw-r--r--arch/ia64/include/asm/unistd.h2
-rw-r--r--arch/ia64/kernel/esi.c2
-rw-r--r--arch/ia64/kernel/perfmon.c2
-rw-r--r--arch/ia64/kernel/time.c4
-rw-r--r--arch/m68k/ifpsp060/src/fpsp.S28
-rw-r--r--arch/m68k/ifpsp060/src/pfpsp.S26
-rw-r--r--arch/m68k/include/asm/bootinfo.h2
-rw-r--r--arch/m68k/include/asm/processor.h2
-rw-r--r--arch/m68k/include/asm/ptrace.h2
-rw-r--r--arch/m68k/include/asm/thread_info_no.h4
-rw-r--r--arch/m68knommu/Kconfig7
-rw-r--r--arch/m68knommu/kernel/process.c5
-rw-r--r--arch/m68knommu/kernel/setup.c92
-rw-r--r--arch/m68knommu/kernel/vmlinux.lds.S47
-rw-r--r--arch/m68knommu/platform/523x/gpio.c5
-rw-r--r--arch/m68knommu/platform/527x/gpio.c6
-rw-r--r--arch/m68knommu/platform/528x/gpio.c2
-rw-r--r--arch/m68knommu/platform/coldfire/clk.c7
-rw-r--r--arch/m68knommu/platform/coldfire/head.S10
-rw-r--r--arch/microblaze/lib/memcpy.c2
-rw-r--r--arch/microblaze/lib/memmove.c2
-rw-r--r--arch/microblaze/lib/memset.c2
-rw-r--r--arch/mips/include/asm/mach-pnx833x/gpio.h2
-rw-r--r--arch/mips/include/asm/sgi/ioc.h2
-rw-r--r--arch/mips/include/asm/sibyte/sb1250_mac.h2
-rw-r--r--arch/mips/include/asm/sn/sn0/hubio.h2
-rw-r--r--arch/mips/include/asm/time.h14
-rw-r--r--arch/mips/kernel/smtc.c2
-rw-r--r--arch/mips/kernel/time.c33
-rw-r--r--arch/mips/math-emu/dp_sub.c2
-rw-r--r--arch/mips/txx9/generic/smsc_fdc37m81x.c2
-rw-r--r--arch/mn10300/kernel/process.c12
-rw-r--r--arch/parisc/kernel/perf.c2
-rw-r--r--arch/powerpc/include/asm/reg_fsl_emb.h2
-rw-r--r--arch/powerpc/kernel/kgdb.c2
-rw-r--r--arch/powerpc/kernel/tau_6xx.c2
-rw-r--r--arch/powerpc/kernel/time.c7
-rw-r--r--arch/powerpc/kernel/vdso.c2
-rw-r--r--arch/powerpc/oprofile/op_model_cell.c6
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_pci.c2
-rw-r--r--arch/powerpc/platforms/powermac/pci.c2
-rw-r--r--arch/powerpc/sysdev/dart_iommu.c2
-rw-r--r--arch/s390/Kconfig15
-rw-r--r--arch/s390/crypto/prng.c2
-rw-r--r--arch/s390/defconfig1
-rw-r--r--arch/s390/include/asm/atomic.h8
-rw-r--r--arch/s390/include/asm/ccwdev.h4
-rw-r--r--arch/s390/include/asm/cputime.h8
-rw-r--r--arch/s390/include/asm/mmu_context.h4
-rw-r--r--arch/s390/include/asm/pgalloc.h3
-rw-r--r--arch/s390/include/asm/pgtable.h4
-rw-r--r--arch/s390/include/asm/setup.h17
-rw-r--r--arch/s390/include/asm/smp.h54
-rw-r--r--arch/s390/include/asm/sockios.h21
-rw-r--r--arch/s390/include/asm/termbits.h206
-rw-r--r--arch/s390/include/asm/todclk.h23
-rw-r--r--arch/s390/include/asm/uaccess.h2
-rw-r--r--arch/s390/kernel/Makefile1
-rw-r--r--arch/s390/kernel/compat_linux.c6
-rw-r--r--arch/s390/kernel/compat_linux.h4
-rw-r--r--arch/s390/kernel/head64.S3
-rw-r--r--arch/s390/kernel/s390_ext.c2
-rw-r--r--arch/s390/kernel/setup.c36
-rw-r--r--arch/s390/kernel/time.c7
-rw-r--r--arch/s390/kernel/vdso.c9
-rw-r--r--arch/s390/kernel/vtime.c2
-rw-r--r--arch/s390/kvm/Kconfig1
-rw-r--r--arch/s390/lib/uaccess_mvcos.c4
-rw-r--r--arch/s390/lib/uaccess_pt.c147
-rw-r--r--arch/s390/math-emu/math.c4
-rw-r--r--arch/s390/mm/cmm.c61
-rw-r--r--arch/s390/mm/fault.c378
-rw-r--r--arch/s390/mm/pgtable.c2
-rw-r--r--arch/s390/mm/vmem.c11
-rw-r--r--arch/sh/Kconfig29
-rw-r--r--arch/sh/Makefile4
-rw-r--r--arch/sh/boards/Makefile1
-rw-r--r--arch/sh/boards/mach-ap325rxa/Makefile2
-rw-r--r--arch/sh/boards/mach-ap325rxa/sdram.S69
-rw-r--r--arch/sh/boards/mach-ap325rxa/setup.c (renamed from arch/sh/boards/board-ap325rxa.c)97
-rw-r--r--arch/sh/boards/mach-ecovec24/Makefile2
-rw-r--r--arch/sh/boards/mach-ecovec24/sdram.S52
-rw-r--r--arch/sh/boards/mach-ecovec24/setup.c197
-rw-r--r--arch/sh/boards/mach-highlander/setup.c2
-rw-r--r--arch/sh/boards/mach-kfr2r09/Makefile2
-rw-r--r--arch/sh/boards/mach-kfr2r09/sdram.S80
-rw-r--r--arch/sh/boards/mach-kfr2r09/setup.c238
-rw-r--r--arch/sh/boards/mach-migor/Makefile2
-rw-r--r--arch/sh/boards/mach-migor/sdram.S69
-rw-r--r--arch/sh/boards/mach-migor/setup.c65
-rw-r--r--arch/sh/boards/mach-r2d/irq.c2
-rw-r--r--arch/sh/boards/mach-se/7722/irq.c32
-rw-r--r--arch/sh/boards/mach-se/7722/setup.c17
-rw-r--r--arch/sh/boards/mach-se/7724/Makefile2
-rw-r--r--arch/sh/boards/mach-se/7724/sdram.S52
-rw-r--r--arch/sh/boards/mach-se/7724/setup.c96
-rw-r--r--arch/sh/boot/compressed/misc.c2
-rw-r--r--arch/sh/boot/romimage/Makefile12
-rw-r--r--arch/sh/boot/romimage/head.S38
-rw-r--r--arch/sh/drivers/dma/dma-sysfs.c2
-rw-r--r--arch/sh/drivers/pci/Kconfig19
-rw-r--r--arch/sh/include/asm/addrspace.h9
-rw-r--r--arch/sh/include/asm/atomic.h9
-rw-r--r--arch/sh/include/asm/bitops.h4
-rw-r--r--arch/sh/include/asm/bugs.h4
-rw-r--r--arch/sh/include/asm/dma-mapping.h233
-rw-r--r--arch/sh/include/asm/dwarf.h28
-rw-r--r--arch/sh/include/asm/fixmap.h12
-rw-r--r--arch/sh/include/asm/fpu.h26
-rw-r--r--arch/sh/include/asm/ftrace.h17
-rw-r--r--arch/sh/include/asm/gpio.h82
-rw-r--r--arch/sh/include/asm/hardirq.h13
-rw-r--r--arch/sh/include/asm/io.h16
-rw-r--r--arch/sh/include/asm/irqflags.h31
-rw-r--r--arch/sh/include/asm/irqflags_32.h99
-rw-r--r--arch/sh/include/asm/irqflags_64.h85
-rw-r--r--arch/sh/include/asm/mmu.h13
-rw-r--r--arch/sh/include/asm/pci.h30
-rw-r--r--arch/sh/include/asm/perf_event.h31
-rw-r--r--arch/sh/include/asm/pgtable.h26
-rw-r--r--arch/sh/include/asm/pgtable_32.h2
-rw-r--r--arch/sh/include/asm/processor_32.h3
-rw-r--r--arch/sh/include/asm/scatterlist.h2
-rw-r--r--arch/sh/include/asm/suspend.h65
-rw-r--r--arch/sh/include/asm/system.h4
-rw-r--r--arch/sh/include/asm/system_32.h29
-rw-r--r--arch/sh/include/asm/system_64.h26
-rw-r--r--arch/sh/include/asm/thread_info.h30
-rw-r--r--arch/sh/include/asm/topology.h8
-rw-r--r--arch/sh/include/asm/ubc.h11
-rw-r--r--arch/sh/include/asm/watchdog.h59
-rw-r--r--arch/sh/include/cpu-sh4/cpu/watchdog.h13
-rw-r--r--arch/sh/include/mach-common/mach/titan.h2
-rw-r--r--arch/sh/include/mach-ecovec24/mach/partner-jet-setup.txt3
-rw-r--r--arch/sh/include/mach-se/mach/se7722.h11
-rw-r--r--arch/sh/kernel/Makefile10
-rw-r--r--arch/sh/kernel/asm-offsets.c23
-rw-r--r--arch/sh/kernel/cpu/Makefile1
-rw-r--r--arch/sh/kernel/cpu/init.c28
-rw-r--r--arch/sh/kernel/cpu/sh2a/fpu.c27
-rw-r--r--arch/sh/kernel/cpu/sh3/entry.S33
-rw-r--r--arch/sh/kernel/cpu/sh4/Makefile8
-rw-r--r--arch/sh/kernel/cpu/sh4/fpu.c28
-rw-r--r--arch/sh/kernel/cpu/sh4/perf_event.c253
-rw-r--r--arch/sh/kernel/cpu/sh4a/Makefile1
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7724.c2
-rw-r--r--arch/sh/kernel/cpu/sh4a/perf_event.c269
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7724.c264
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-shx3.c45
-rw-r--r--arch/sh/kernel/cpu/sh4a/smp-shx3.c37
-rw-r--r--arch/sh/kernel/cpu/sh5/entry.S2
-rw-r--r--arch/sh/kernel/cpu/shmobile/cpuidle.c42
-rw-r--r--arch/sh/kernel/cpu/shmobile/pm.c117
-rw-r--r--arch/sh/kernel/cpu/shmobile/pm_runtime.c17
-rw-r--r--arch/sh/kernel/cpu/shmobile/sleep.S344
-rw-r--r--arch/sh/kernel/cpu/ubc.S59
-rw-r--r--arch/sh/kernel/dma-nommu.c82
-rw-r--r--arch/sh/kernel/dwarf.c222
-rw-r--r--arch/sh/kernel/entry-common.S2
-rw-r--r--arch/sh/kernel/ftrace.c146
-rw-r--r--arch/sh/kernel/head_32.S2
-rw-r--r--arch/sh/kernel/idle.c78
-rw-r--r--arch/sh/kernel/io_generic.c4
-rw-r--r--arch/sh/kernel/irq.c14
-rw-r--r--arch/sh/kernel/irq_32.c57
-rw-r--r--arch/sh/kernel/irq_64.c51
-rw-r--r--arch/sh/kernel/machine_kexec.c6
-rw-r--r--arch/sh/kernel/machvec.c4
-rw-r--r--arch/sh/kernel/module.c9
-rw-r--r--arch/sh/kernel/perf_callchain.c98
-rw-r--r--arch/sh/kernel/perf_event.c312
-rw-r--r--arch/sh/kernel/process_32.c42
-rw-r--r--arch/sh/kernel/process_64.c2
-rw-r--r--arch/sh/kernel/return_address.c54
-rw-r--r--arch/sh/kernel/setup.c4
-rw-r--r--arch/sh/kernel/sh_ksyms_32.c67
-rw-r--r--arch/sh/kernel/sh_ksyms_64.c10
-rw-r--r--arch/sh/kernel/signal_32.c24
-rw-r--r--arch/sh/kernel/signal_64.c13
-rw-r--r--arch/sh/kernel/smp.c4
-rw-r--r--arch/sh/kernel/topology.c26
-rw-r--r--arch/sh/kernel/traps.c8
-rw-r--r--arch/sh/kernel/traps_32.c82
-rw-r--r--arch/sh/lib/Makefile7
-rw-r--r--arch/sh/lib/memset-sh4.S107
-rw-r--r--arch/sh/math-emu/math.c6
-rw-r--r--arch/sh/mm/Kconfig19
-rw-r--r--arch/sh/mm/Makefile3
-rw-r--r--arch/sh/mm/cache-sh4.c501
-rw-r--r--arch/sh/mm/cache-sh5.c2
-rw-r--r--arch/sh/mm/cache-sh7705.c2
-rw-r--r--arch/sh/mm/cache.c18
-rw-r--r--arch/sh/mm/consistent.c28
-rw-r--r--arch/sh/mm/init.c19
-rw-r--r--arch/sh/mm/kmap.c4
-rw-r--r--arch/sh/mm/numa.c2
-rw-r--r--arch/sh/mm/pmb-fixed.c45
-rw-r--r--arch/sh/mm/pmb.c268
-rw-r--r--arch/sh/oprofile/Makefile4
-rw-r--r--arch/sh/oprofile/common.c38
-rw-r--r--arch/sh/oprofile/op_impl.h2
-rw-r--r--arch/sh/oprofile/op_model_sh7750.c255
-rw-r--r--arch/sparc/kernel/time_64.c2
-rw-r--r--arch/um/drivers/mmapper_kern.c11
-rw-r--r--arch/um/drivers/random.c3
-rw-r--r--arch/x86/Kconfig9
-rw-r--r--arch/x86/Kconfig.cpu14
-rw-r--r--arch/x86/Makefile_32.cpu7
-rw-r--r--arch/x86/boot/compressed/head_64.S3
-rw-r--r--arch/x86/boot/compressed/vmlinux.lds.S3
-rw-r--r--arch/x86/boot/video.c6
-rw-r--r--arch/x86/crypto/Makefile3
-rw-r--r--arch/x86/crypto/aesni-intel_asm.S517
-rw-r--r--arch/x86/crypto/ghash-clmulni-intel_asm.S157
-rw-r--r--arch/x86/crypto/ghash-clmulni-intel_glue.c333
-rw-r--r--arch/x86/include/asm/acpi.h3
-rw-r--r--arch/x86/include/asm/cache.h7
-rw-r--r--arch/x86/include/asm/cacheflush.h1
-rw-r--r--arch/x86/include/asm/cpufeature.h1
-rw-r--r--arch/x86/include/asm/desc_defs.h4
-rw-r--r--arch/x86/include/asm/e820.h23
-rw-r--r--arch/x86/include/asm/elf.h20
-rw-r--r--arch/x86/include/asm/entry_arch.h2
-rw-r--r--arch/x86/include/asm/hardirq.h2
-rw-r--r--arch/x86/include/asm/hpet.h7
-rw-r--r--arch/x86/include/asm/hw_irq.h4
-rw-r--r--arch/x86/include/asm/i387.h7
-rw-r--r--arch/x86/include/asm/inst.h150
-rw-r--r--arch/x86/include/asm/irq.h2
-rw-r--r--arch/x86/include/asm/irq_vectors.h2
-rw-r--r--arch/x86/include/asm/k8.h5
-rw-r--r--arch/x86/include/asm/microcode.h2
-rw-r--r--arch/x86/include/asm/mmzone_32.h2
-rw-r--r--arch/x86/include/asm/mpspec.h11
-rw-r--r--arch/x86/include/asm/page_types.h3
-rw-r--r--arch/x86/include/asm/pgtable.h6
-rw-r--r--arch/x86/include/asm/proto.h17
-rw-r--r--arch/x86/include/asm/sections.h6
-rw-r--r--arch/x86/include/asm/sigcontext.h4
-rw-r--r--arch/x86/include/asm/uv/uv_bau.h2
-rw-r--r--arch/x86/include/asm/x86_init.h4
-rw-r--r--arch/x86/kernel/acpi/boot.c3
-rw-r--r--arch/x86/kernel/acpi/sleep.c24
-rw-r--r--arch/x86/kernel/amd_iommu.c4
-rw-r--r--arch/x86/kernel/apic/apic.c2
-rw-r--r--arch/x86/kernel/apic/io_apic.c49
-rw-r--r--arch/x86/kernel/apic/numaq_32.c5
-rw-r--r--arch/x86/kernel/apic/x2apic_uv_x.c19
-rw-r--r--arch/x86/kernel/cpu/common.c2
-rw-r--r--arch/x86/kernel/cpu/intel.c6
-rw-r--r--arch/x86/kernel/cpu/intel_cacheinfo.c5
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce.c6
-rw-r--r--arch/x86/kernel/cpu/mtrr/cleanup.c51
-rw-r--r--arch/x86/kernel/cpu/perf_event.c2
-rw-r--r--arch/x86/kernel/entry_64.S4
-rw-r--r--arch/x86/kernel/ftrace.c17
-rw-r--r--arch/x86/kernel/head_32.S18
-rw-r--r--arch/x86/kernel/head_64.S3
-rw-r--r--arch/x86/kernel/hpet.c77
-rw-r--r--arch/x86/kernel/irq.c20
-rw-r--r--arch/x86/kernel/irqinit.c4
-rw-r--r--arch/x86/kernel/kprobes.c4
-rw-r--r--arch/x86/kernel/machine_kexec_32.c6
-rw-r--r--arch/x86/kernel/microcode_amd.c87
-rw-r--r--arch/x86/kernel/microcode_core.c8
-rw-r--r--arch/x86/kernel/mpparse.c44
-rw-r--r--arch/x86/kernel/process_64.c32
-rw-r--r--arch/x86/kernel/quirks.c9
-rw-r--r--arch/x86/kernel/reboot_fixups_32.c1
-rw-r--r--arch/x86/kernel/setup.c106
-rw-r--r--arch/x86/kernel/tlb_uv.c4
-rw-r--r--arch/x86/kernel/uv_time.c80
-rw-r--r--arch/x86/kernel/visws_quirks.c2
-rw-r--r--arch/x86/kernel/vmiclock_32.c2
-rw-r--r--arch/x86/kernel/vmlinux.lds.S38
-rw-r--r--arch/x86/kernel/vsyscall_64.c5
-rw-r--r--arch/x86/kernel/x86_init.c2
-rw-r--r--arch/x86/mm/init.c4
-rw-r--r--arch/x86/mm/init_32.c10
-rw-r--r--arch/x86/mm/init_64.c35
-rw-r--r--arch/x86/mm/ioremap.c26
-rw-r--r--arch/x86/mm/k8topology_64.c101
-rw-r--r--arch/x86/mm/kmmio.c4
-rw-r--r--arch/x86/mm/numa_32.c4
-rw-r--r--arch/x86/mm/numa_64.c252
-rw-r--r--arch/x86/mm/pageattr.c22
-rw-r--r--arch/x86/mm/pat.c20
-rw-r--r--arch/x86/mm/setup_nx.c59
-rw-r--r--arch/x86/mm/srat_64.c29
-rw-r--r--arch/x86/mm/tlb.c3
-rw-r--r--arch/x86/xen/enlighten.c4
-rw-r--r--arch/x86/xen/smp.c2
-rw-r--r--block/blk-iopoll.c2
-rw-r--r--crypto/Kconfig9
-rw-r--r--crypto/ansi_cprng.c82
-rw-r--r--crypto/cryptd.c7
-rw-r--r--crypto/digest.c240
-rw-r--r--crypto/hash.c183
-rw-r--r--crypto/proc.c7
-rw-r--r--crypto/testmgr.c11
-rw-r--r--crypto/testmgr.h15
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/acpi/numa.c10
-rw-r--r--drivers/acpi/video_detect.c10
-rw-r--r--drivers/ata/ata_piix.c2
-rw-r--r--drivers/ata/libata-scsi.c7
-rw-r--r--drivers/ata/libata-sff.c6
-rw-r--r--drivers/ata/pata_cs5535.c2
-rw-r--r--drivers/ata/sata_fsl.c6
-rw-r--r--drivers/ata/sata_nv.c2
-rw-r--r--drivers/atm/iphase.c2
-rw-r--r--drivers/base/dd.c2
-rw-r--r--drivers/block/ataflop.c3
-rw-r--r--drivers/block/cciss_cmd.h2
-rw-r--r--drivers/bluetooth/btmrvl_sdio.c2
-rw-r--r--drivers/bluetooth/hci_ldisc.c2
-rw-r--r--drivers/cdrom/gdrom.c10
-rw-r--r--drivers/char/agp/frontend.c28
-rw-r--r--drivers/char/cs5535_gpio.c3
-rw-r--r--drivers/char/efirtc.c12
-rw-r--r--drivers/char/generic_nvram.c9
-rw-r--r--drivers/char/hw_random/core.c109
-rw-r--r--drivers/char/hw_random/virtio-rng.c78
-rw-r--r--drivers/char/mem.c19
-rw-r--r--drivers/char/misc.c5
-rw-r--r--drivers/char/mspec.c2
-rw-r--r--drivers/char/n_r3964.c2
-rw-r--r--drivers/char/nvram.c5
-rw-r--r--drivers/char/pc8736x_gpio.c2
-rw-r--r--drivers/char/rio/route.h2
-rw-r--r--drivers/char/scx200_gpio.c2
-rw-r--r--drivers/char/tb0219.c6
-rw-r--r--drivers/char/tty_ioctl.c2
-rw-r--r--drivers/char/vt.c11
-rw-r--r--drivers/cpuidle/governor.c4
-rw-r--r--drivers/crypto/hifn_795x.c2
-rw-r--r--drivers/dma/at_hdmac.c2
-rw-r--r--drivers/firewire/core-topology.c2
-rw-r--r--drivers/gpu/drm/drm_crtc.c4
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c2
-rw-r--r--drivers/gpu/drm/i915/intel_fb.c2
-rw-r--r--drivers/gpu/drm/i915/intel_sdvo.c2
-rw-r--r--drivers/gpu/drm/radeon/atombios.h16
-rw-r--r--drivers/gpu/drm/radeon/r600.c4
-rw-r--r--drivers/gpu/drm/radeon/radeon_fb.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_state.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_ttm.c2
-rw-r--r--drivers/gpu/drm/radeon/rv770.c4
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_util.c2
-rw-r--r--drivers/hid/hid-core.c9
-rw-r--r--drivers/hid/hid-cypress.c2
-rw-r--r--drivers/hid/hid-ids.h7
-rw-r--r--drivers/hid/hid-lg.c33
-rw-r--r--drivers/hid/usbhid/hid-core.c12
-rw-r--r--drivers/hid/usbhid/hid-pidff.c5
-rw-r--r--drivers/hid/usbhid/hid-quirks.c4
-rw-r--r--drivers/hid/usbhid/hiddev.c5
-rw-r--r--drivers/hwmon/adm1029.c2
-rw-r--r--drivers/hwmon/lm93.c2
-rw-r--r--drivers/ide/Kconfig45
-rw-r--r--drivers/ide/alim15x3.c12
-rw-r--r--drivers/ide/au1xxx-ide.c7
-rw-r--r--drivers/ide/cmd64x.c17
-rw-r--r--drivers/ide/cs5535.c1
-rw-r--r--drivers/ide/cy82c693.c27
-rw-r--r--drivers/ide/hpt366.c65
-rw-r--r--drivers/ide/ide-tape.c21
-rw-r--r--drivers/ide/ide_platform.c8
-rw-r--r--drivers/ide/pdc202xx_old.c15
-rw-r--r--drivers/ide/sis5513.c9
-rw-r--r--drivers/ide/sl82c105.c24
-rw-r--r--drivers/ide/slc90e66.c3
-rw-r--r--drivers/ide/tx4938ide.c2
-rw-r--r--drivers/ieee1394/dv1394.c2
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_hal.c2
-rw-r--r--drivers/infiniband/hw/ipath/ipath_file_ops.c1
-rw-r--r--drivers/infiniband/hw/ipath/ipath_iba6110.c2
-rw-r--r--drivers/infiniband/hw/ipath/ipath_sd7220.c4
-rw-r--r--drivers/infiniband/hw/mlx4/qp.c2
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.c1
-rw-r--r--drivers/infiniband/ulp/iser/iser_verbs.c2
-rw-r--r--drivers/input/keyboard/sh_keysc.c2
-rw-r--r--drivers/input/misc/hp_sdc_rtc.c2
-rw-r--r--drivers/input/serio/hp_sdc.c2
-rw-r--r--drivers/input/serio/hp_sdc_mlc.c2
-rw-r--r--drivers/input/touchscreen/atmel-wm97xx.c2
-rw-r--r--drivers/input/touchscreen/mainstone-wm97xx.c4
-rw-r--r--drivers/input/touchscreen/zylonite-wm97xx.c2
-rw-r--r--drivers/isdn/act2000/Kconfig4
-rw-r--r--drivers/isdn/capi/Kconfig4
-rw-r--r--drivers/isdn/capi/capidrv.c2
-rw-r--r--drivers/isdn/hardware/eicon/di.c2
-rw-r--r--drivers/isdn/hardware/eicon/maintidi.c4
-rw-r--r--drivers/isdn/hardware/mISDN/hfcsusb.c2
-rw-r--r--drivers/isdn/hardware/mISDN/hfcsusb.h2
-rw-r--r--drivers/isdn/hardware/mISDN/mISDNisar.c2
-rw-r--r--drivers/isdn/hisax/hfc_usb.c2
-rw-r--r--drivers/isdn/hysdn/Kconfig4
-rw-r--r--drivers/isdn/i4l/isdn_net.c2
-rw-r--r--drivers/isdn/i4l/isdn_ppp.c6
-rw-r--r--drivers/isdn/i4l/isdn_ttyfax.c2
-rw-r--r--drivers/isdn/icn/Kconfig4
-rw-r--r--drivers/isdn/mISDN/dsp_core.c2
-rw-r--r--drivers/isdn/mISDN/tei.c2
-rw-r--r--drivers/isdn/pcbit/Kconfig4
-rw-r--r--drivers/isdn/sc/Kconfig4
-rw-r--r--drivers/macintosh/ans-lcd.c45
-rw-r--r--drivers/macintosh/therm_windtunnel.c2
-rw-r--r--drivers/md/dm-crypt.c2
-rw-r--r--drivers/md/dm-mpath.c8
-rw-r--r--drivers/media/common/saa7146_i2c.c2
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.h2
-rw-r--r--drivers/media/dvb/dvb-core/dvb_net.c2
-rw-r--r--drivers/media/dvb/dvb-usb/anysee.c2
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb-mb.c2
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-remote.c2
-rw-r--r--drivers/media/dvb/dvb-usb/usb-urb.c4
-rw-r--r--drivers/media/dvb/frontends/au8522_decoder.c2
-rw-r--r--drivers/media/dvb/frontends/cx24110.c4
-rw-r--r--drivers/media/dvb/frontends/cx24113.c2
-rw-r--r--drivers/media/dvb/frontends/dib3000mb.c2
-rw-r--r--drivers/media/dvb/frontends/drx397xD.c2
-rw-r--r--drivers/media/dvb/frontends/lgdt330x.c4
-rw-r--r--drivers/media/dvb/frontends/stb0899_drv.c2
-rw-r--r--drivers/media/dvb/ttpci/av7110.c4
-rw-r--r--drivers/media/dvb/ttpci/budget-patch.c2
-rw-r--r--drivers/media/radio/radio-mr800.c2
-rw-r--r--drivers/media/video/cx18/cx18-av-core.h2
-rw-r--r--drivers/media/video/cx18/cx18-driver.c4
-rw-r--r--drivers/media/video/cx18/cx18-mailbox.h2
-rw-r--r--drivers/media/video/cx231xx/cx231xx-avcore.c8
-rw-r--r--drivers/media/video/cx23885/cx23885-core.c4
-rw-r--r--drivers/media/video/cx23885/cx23885-dvb.c2
-rw-r--r--drivers/media/video/cx88/cx88-core.c2
-rw-r--r--drivers/media/video/davinci/dm355_ccdc.c6
-rw-r--r--drivers/media/video/davinci/dm644x_ccdc.c4
-rw-r--r--drivers/media/video/davinci/vpss.c2
-rw-r--r--drivers/media/video/gspca/sonixb.c2
-rw-r--r--drivers/media/video/gspca/spca500.c2
-rw-r--r--drivers/media/video/gspca/spca501.c6
-rw-r--r--drivers/media/video/gspca/sunplus.c2
-rw-r--r--drivers/media/video/gspca/zc3xx.c2
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.c4
-rw-r--r--drivers/media/video/ov772x.c2
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h2
-rw-r--r--drivers/media/video/s2255drv.c2
-rw-r--r--drivers/media/video/saa7134/saa7134-core.c4
-rw-r--r--drivers/media/video/saa7164/saa7164-core.c4
-rw-r--r--drivers/media/video/zoran/zoran.h2
-rw-r--r--drivers/message/fusion/mptbase.h4
-rw-r--r--drivers/message/fusion/mptctl.c5
-rw-r--r--drivers/message/fusion/mptscsih.c95
-rw-r--r--drivers/message/fusion/mptscsih.h3
-rw-r--r--drivers/message/i2o/i2o_block.c2
-rw-r--r--drivers/message/i2o/iop.c4
-rw-r--r--drivers/mfd/Kconfig8
-rw-r--r--drivers/mfd/Makefile1
-rw-r--r--drivers/mfd/sh_mobile_sdhi.c156
-rw-r--r--drivers/misc/sgi-gru/grufile.c2
-rw-r--r--drivers/mmc/card/sdio_uart.c40
-rw-r--r--drivers/mmc/host/Kconfig2
-rw-r--r--drivers/mmc/host/s3cmci.c2
-rw-r--r--drivers/mtd/chips/Kconfig3
-rw-r--r--drivers/mtd/devices/Kconfig3
-rw-r--r--drivers/mtd/devices/slram.c2
-rw-r--r--drivers/mtd/lpddr/Kconfig3
-rw-r--r--drivers/mtd/maps/Kconfig8
-rw-r--r--drivers/mtd/nand/Kconfig2
-rw-r--r--drivers/mtd/nand/diskonchip.c2
-rw-r--r--drivers/mtd/nand/nand_ecc.c2
-rw-r--r--drivers/mtd/nand/s3c2410.c2
-rw-r--r--drivers/mtd/onenand/Kconfig4
-rw-r--r--drivers/mtd/ubi/Kconfig2
-rw-r--r--drivers/net/82596.c2
-rw-r--r--drivers/net/amd8111e.c7
-rw-r--r--drivers/net/appletalk/cops.c2
-rw-r--r--drivers/net/ariadne.h2
-rw-r--r--drivers/net/atl1c/atl1c_main.c2
-rw-r--r--drivers/net/benet/be_cmds.h2
-rw-r--r--drivers/net/benet/be_main.c2
-rw-r--r--drivers/net/bnx2x_reg.h2
-rw-r--r--drivers/net/bonding/bond_alb.c2
-rw-r--r--drivers/net/cxgb3/sge.c2
-rw-r--r--drivers/net/ehea/ehea_ethtool.c4
-rw-r--r--drivers/net/hamradio/baycom_ser_fdx.c2
-rw-r--r--drivers/net/irda/smsc-ircc2.c2
-rw-r--r--drivers/net/iseries_veth.c2
-rw-r--r--drivers/net/lasi_82596.c2
-rw-r--r--drivers/net/lib82596.c2
-rw-r--r--drivers/net/mlx4/en_rx.c2
-rw-r--r--drivers/net/mlx4/en_tx.c2
-rw-r--r--drivers/net/mlx4/mlx4_en.h2
-rw-r--r--drivers/net/ps3_gelic_net.c2
-rw-r--r--drivers/net/ps3_gelic_wireless.h2
-rw-r--r--drivers/net/qla3xxx.c2
-rw-r--r--drivers/net/s2io.c2
-rw-r--r--drivers/net/sis900.c4
-rw-r--r--drivers/net/skfp/h/smc.h8
-rw-r--r--drivers/net/skfp/skfddi.c2
-rw-r--r--drivers/net/sky2.c2
-rw-r--r--drivers/net/smsc911x.c2
-rw-r--r--drivers/net/smsc911x.h2
-rw-r--r--drivers/net/spider_net.c2
-rw-r--r--drivers/net/stmmac/gmac.c2
-rw-r--r--drivers/net/stmmac/gmac.h4
-rw-r--r--drivers/net/tokenring/ibmtr.c2
-rw-r--r--drivers/net/tokenring/smctr.c2
-rw-r--r--drivers/net/ucc_geth.c2
-rw-r--r--drivers/net/ucc_geth.h20
-rw-r--r--drivers/net/usb/smsc95xx.c2
-rw-r--r--drivers/net/wan/hdlc_fr.c2
-rw-r--r--drivers/net/wan/lmc/lmc_main.c2
-rw-r--r--drivers/net/wimax/i2400m/rx.c2
-rw-r--r--drivers/net/wireless/ath/ath5k/base.h4
-rw-r--r--drivers/net/wireless/ath/ath5k/eeprom.c2
-rw-r--r--drivers/net/wireless/ath/ath5k/phy.c6
-rw-r--r--drivers/net/wireless/ath/ath9k/rc.c2
-rw-r--r--drivers/net/wireless/b43/main.c2
-rw-r--r--drivers/net/wireless/b43legacy/main.c2
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2100.c6
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2200.c8
-rw-r--r--drivers/net/wireless/ipw2x00/libipw_module.c2
-rw-r--r--drivers/net/wireless/iwmc3200wifi/hal.c2
-rw-r--r--drivers/net/wireless/iwmc3200wifi/rx.c2
-rw-r--r--drivers/net/wireless/libertas/if_sdio.c2
-rw-r--r--drivers/net/wireless/orinoco/hermes_dld.c4
-rw-r--r--drivers/net/wireless/prism54/isl_ioctl.c4
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.h2
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.h2
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.h2
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.h2
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.h2
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c2
-rw-r--r--drivers/parisc/ccio-dma.c2
-rw-r--r--drivers/parisc/eisa_eeprom.c10
-rw-r--r--drivers/pci/intr_remapping.c89
-rw-r--r--drivers/pci/intr_remapping.h7
-rw-r--r--drivers/platform/Kconfig2
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c2
-rw-r--r--drivers/pnp/pnpbios/rsparser.c8
-rw-r--r--drivers/ps3/ps3-sys-manager.c2
-rw-r--r--drivers/rtc/rtc-ds1302.c2
-rw-r--r--drivers/rtc/rtc-ds1511.c4
-rw-r--r--drivers/rtc/rtc-stk17ta8.c2
-rw-r--r--drivers/rtc/rtc-v3020.c2
-rw-r--r--drivers/s390/block/dasd.c237
-rw-r--r--drivers/s390/block/dasd_3990_erp.c47
-rw-r--r--drivers/s390/block/dasd_alias.c77
-rw-r--r--drivers/s390/block/dasd_diag.c20
-rw-r--r--drivers/s390/block/dasd_eckd.c170
-rw-r--r--drivers/s390/block/dasd_eckd.h4
-rw-r--r--drivers/s390/block/dasd_eer.c5
-rw-r--r--drivers/s390/block/dasd_fba.c11
-rw-r--r--drivers/s390/block/dasd_int.h13
-rw-r--r--drivers/s390/block/dasd_ioctl.c4
-rw-r--r--drivers/s390/block/dasd_proc.c2
-rw-r--r--drivers/s390/char/con3215.c1
-rw-r--r--drivers/s390/char/con3270.c1
-rw-r--r--drivers/s390/char/fs3270.c12
-rw-r--r--drivers/s390/char/monreader.c8
-rw-r--r--drivers/s390/char/monwriter.c7
-rw-r--r--drivers/s390/char/sclp_cmd.c1
-rw-r--r--drivers/s390/char/tape.h9
-rw-r--r--drivers/s390/char/tape_34xx.c8
-rw-r--r--drivers/s390/char/tape_3590.c2
-rw-r--r--drivers/s390/char/tape_block.c17
-rw-r--r--drivers/s390/char/tape_char.c54
-rw-r--r--drivers/s390/char/tape_core.c65
-rw-r--r--drivers/s390/char/tape_proc.c2
-rw-r--r--drivers/s390/char/tty3270.c20
-rw-r--r--drivers/s390/char/vmlogrdr.c8
-rw-r--r--drivers/s390/char/vmur.c3
-rw-r--r--drivers/s390/char/vmwatchdog.c29
-rw-r--r--drivers/s390/cio/Makefile2
-rw-r--r--drivers/s390/cio/ccwreq.c328
-rw-r--r--drivers/s390/cio/chp.c2
-rw-r--r--drivers/s390/cio/cio.c1
-rw-r--r--drivers/s390/cio/cio.h8
-rw-r--r--drivers/s390/cio/cmf.c2
-rw-r--r--drivers/s390/cio/css.c57
-rw-r--r--drivers/s390/cio/css.h3
-rw-r--r--drivers/s390/cio/device.c1006
-rw-r--r--drivers/s390/cio/device.h25
-rw-r--r--drivers/s390/cio/device_fsm.c411
-rw-r--r--drivers/s390/cio/device_id.c375
-rw-r--r--drivers/s390/cio/device_ops.c142
-rw-r--r--drivers/s390/cio/device_pgid.c963
-rw-r--r--drivers/s390/cio/device_status.c3
-rw-r--r--drivers/s390/cio/io_sch.h73
-rw-r--r--drivers/s390/crypto/ap_bus.c31
-rw-r--r--drivers/s390/crypto/ap_bus.h18
-rw-r--r--drivers/s390/crypto/zcrypt_api.c11
-rw-r--r--drivers/s390/crypto/zcrypt_api.h2
-rw-r--r--drivers/s390/crypto/zcrypt_cex2a.c75
-rw-r--r--drivers/s390/crypto/zcrypt_pcica.c2
-rw-r--r--drivers/s390/crypto/zcrypt_pcicc.c2
-rw-r--r--drivers/s390/crypto/zcrypt_pcixcc.c38
-rw-r--r--drivers/s390/net/qeth_core_mpc.h2
-rw-r--r--drivers/s390/scsi/zfcp_aux.c388
-rw-r--r--drivers/s390/scsi/zfcp_ccw.c179
-rw-r--r--drivers/s390/scsi/zfcp_cfdc.c26
-rw-r--r--drivers/s390/scsi/zfcp_dbf.c134
-rw-r--r--drivers/s390/scsi/zfcp_dbf.h10
-rw-r--r--drivers/s390/scsi/zfcp_def.h323
-rw-r--r--drivers/s390/scsi/zfcp_erp.c138
-rw-r--r--drivers/s390/scsi/zfcp_ext.h38
-rw-r--r--drivers/s390/scsi/zfcp_fc.c677
-rw-r--r--drivers/s390/scsi/zfcp_fc.h260
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c367
-rw-r--r--drivers/s390/scsi/zfcp_fsf.h53
-rw-r--r--drivers/s390/scsi/zfcp_scsi.c156
-rw-r--r--drivers/s390/scsi/zfcp_sysfs.c250
-rw-r--r--drivers/sbus/char/envctrl.c4
-rw-r--r--drivers/scsi/3w-9xxx.c8
-rw-r--r--drivers/scsi/3w-sas.c1924
-rw-r--r--drivers/scsi/3w-sas.h396
-rw-r--r--drivers/scsi/3w-xxxx.c8
-rw-r--r--drivers/scsi/53c700.c9
-rw-r--r--drivers/scsi/Kconfig29
-rw-r--r--drivers/scsi/Makefile3
-rw-r--r--drivers/scsi/aacraid/aacraid.h6
-rw-r--r--drivers/scsi/aacraid/comminit.c2
-rw-r--r--drivers/scsi/aacraid/linit.c6
-rw-r--r--drivers/scsi/advansys.c2
-rw-r--r--drivers/scsi/aic7xxx/aic79xx.seq4
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_core.c2
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.c2
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx.seq2
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_core.c2
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.c2
-rw-r--r--drivers/scsi/aic94xx/aic94xx_reg_def.h2
-rw-r--r--drivers/scsi/arcmsr/arcmsr_hba.c5
-rw-r--r--drivers/scsi/be2iscsi/be.h24
-rw-r--r--drivers/scsi/be2iscsi/be_cmds.c263
-rw-r--r--drivers/scsi/be2iscsi/be_cmds.h37
-rw-r--r--drivers/scsi/be2iscsi/be_iscsi.c23
-rw-r--r--drivers/scsi/be2iscsi/be_main.c1019
-rw-r--r--drivers/scsi/be2iscsi/be_main.h49
-rw-r--r--drivers/scsi/be2iscsi/be_mgmt.c69
-rw-r--r--drivers/scsi/be2iscsi/be_mgmt.h8
-rw-r--r--drivers/scsi/bfa/bfa_cb_ioim_macros.h10
-rw-r--r--drivers/scsi/bfa/bfa_cee.c2
-rw-r--r--drivers/scsi/bfa/bfa_csdebug.c4
-rw-r--r--drivers/scsi/bfa/bfa_fcpim.c4
-rw-r--r--drivers/scsi/bfa/bfa_fcpim_priv.h4
-rw-r--r--drivers/scsi/bfa/bfa_fcport.c59
-rw-r--r--drivers/scsi/bfa/bfa_fcs_lport.c11
-rw-r--r--drivers/scsi/bfa/bfa_fcxp.c8
-rw-r--r--drivers/scsi/bfa/bfa_intr.c2
-rw-r--r--drivers/scsi/bfa/bfa_intr_priv.h18
-rw-r--r--drivers/scsi/bfa/bfa_ioc.c10
-rw-r--r--drivers/scsi/bfa/bfa_ioc.h12
-rw-r--r--drivers/scsi/bfa/bfa_iocfc.c8
-rw-r--r--drivers/scsi/bfa/bfa_iocfc.h8
-rw-r--r--drivers/scsi/bfa/bfa_ioim.c4
-rw-r--r--drivers/scsi/bfa/bfa_itnim.c6
-rw-r--r--drivers/scsi/bfa/bfa_log.c4
-rw-r--r--drivers/scsi/bfa/bfa_port_priv.h4
-rw-r--r--drivers/scsi/bfa/bfa_rport.c6
-rw-r--r--drivers/scsi/bfa/bfa_tskim.c9
-rw-r--r--drivers/scsi/bfa/bfa_uf.c2
-rw-r--r--drivers/scsi/bfa/bfad.c6
-rw-r--r--drivers/scsi/bfa/bfad_fwimg.c8
-rw-r--r--drivers/scsi/bfa/bfad_im.c2
-rw-r--r--drivers/scsi/bfa/bfad_im_compat.h2
-rw-r--r--drivers/scsi/bfa/bfad_intr.c3
-rw-r--r--drivers/scsi/bfa/fabric.c18
-rw-r--r--drivers/scsi/bfa/fcbuild.c190
-rw-r--r--drivers/scsi/bfa/fcbuild.h6
-rw-r--r--drivers/scsi/bfa/fcpim.c7
-rw-r--r--drivers/scsi/bfa/fcs.h2
-rw-r--r--drivers/scsi/bfa/fdmi.c8
-rw-r--r--drivers/scsi/bfa/include/aen/bfa_aen.h2
-rw-r--r--drivers/scsi/bfa/include/bfa.h10
-rw-r--r--drivers/scsi/bfa/include/bfa_svc.h8
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi.h12
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_ioc.h2
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_lps.h4
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_rport.h8
-rw-r--r--drivers/scsi/bfa/include/cs/bfa_checksum.h6
-rw-r--r--drivers/scsi/bfa/include/cs/bfa_sm.h6
-rw-r--r--drivers/scsi/bfa/include/cs/bfa_trc.h2
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_pport.h2
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_tsensor.h2
-rw-r--r--drivers/scsi/bfa/include/fcs/bfa_fcs_fabric.h2
-rw-r--r--drivers/scsi/bfa/include/fcs/bfa_fcs_lport.h17
-rw-r--r--drivers/scsi/bfa/include/protocol/ct.h14
-rw-r--r--drivers/scsi/bfa/include/protocol/fc.h22
-rw-r--r--drivers/scsi/bfa/loop.c233
-rw-r--r--drivers/scsi/bfa/lport_api.c15
-rw-r--r--drivers/scsi/bfa/ns.c5
-rw-r--r--drivers/scsi/bfa/plog.c2
-rw-r--r--drivers/scsi/bfa/rport_ftrs.c28
-rw-r--r--drivers/scsi/bfa/vfapi.c2
-rw-r--r--drivers/scsi/bfa/vport.c20
-rw-r--r--drivers/scsi/bnx2i/bnx2i.h1
-rw-r--r--drivers/scsi/bnx2i/bnx2i_iscsi.c12
-rw-r--r--drivers/scsi/constants.c1
-rw-r--r--drivers/scsi/cxgb3i/cxgb3i_iscsi.c2
-rw-r--r--drivers/scsi/dc395x.c2
-rw-r--r--drivers/scsi/device_handler/scsi_dh.c28
-rw-r--r--drivers/scsi/device_handler/scsi_dh_alua.c139
-rw-r--r--drivers/scsi/device_handler/scsi_dh_emc.c7
-rw-r--r--drivers/scsi/device_handler/scsi_dh_hp_sw.c94
-rw-r--r--drivers/scsi/device_handler/scsi_dh_rdac.c115
-rw-r--r--drivers/scsi/dmx3191d.c2
-rw-r--r--drivers/scsi/fcoe/fcoe.c1376
-rw-r--r--drivers/scsi/fcoe/fcoe.h82
-rw-r--r--drivers/scsi/fcoe/libfcoe.c433
-rw-r--r--drivers/scsi/fnic/fnic.h25
-rw-r--r--drivers/scsi/fnic/fnic_fcs.c499
-rw-r--r--drivers/scsi/fnic/fnic_isr.c18
-rw-r--r--drivers/scsi/fnic/fnic_main.c104
-rw-r--r--drivers/scsi/fnic/fnic_res.c5
-rw-r--r--drivers/scsi/fnic/fnic_res.h54
-rw-r--r--drivers/scsi/fnic/fnic_scsi.c96
-rw-r--r--drivers/scsi/fnic/vnic_scsi.h1
-rw-r--r--drivers/scsi/hosts.c13
-rw-r--r--drivers/scsi/hptiop.c7
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.c335
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.h12
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c7
-rw-r--r--drivers/scsi/ipr.c7
-rw-r--r--drivers/scsi/iscsi_tcp.c2
-rw-r--r--drivers/scsi/libfc/Makefile4
-rw-r--r--drivers/scsi/libfc/fc_disc.c85
-rw-r--r--drivers/scsi/libfc/fc_elsct.c79
-rw-r--r--drivers/scsi/libfc/fc_exch.c932
-rw-r--r--drivers/scsi/libfc/fc_fcp.c1044
-rw-r--r--drivers/scsi/libfc/fc_frame.c13
-rw-r--r--drivers/scsi/libfc/fc_libfc.c134
-rw-r--r--drivers/scsi/libfc/fc_libfc.h112
-rw-r--r--drivers/scsi/libfc/fc_lport.c855
-rw-r--r--drivers/scsi/libfc/fc_npiv.c161
-rw-r--r--drivers/scsi/libfc/fc_rport.c409
-rw-r--r--drivers/scsi/libiscsi.c389
-rw-r--r--drivers/scsi/libiscsi_tcp.c2
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c6
-rw-r--r--drivers/scsi/lpfc/lpfc.h17
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c266
-rw-r--r--drivers/scsi/lpfc/lpfc_bsg.c5
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h14
-rw-r--r--drivers/scsi/lpfc/lpfc_ct.c53
-rw-r--r--drivers/scsi/lpfc/lpfc_debugfs.c10
-rw-r--r--drivers/scsi/lpfc/lpfc_disc.h4
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c80
-rwxr-xr-x[-rw-r--r--]drivers/scsi/lpfc/lpfc_hbadisc.c129
-rw-r--r--drivers/scsi/lpfc/lpfc_hw.h34
-rw-r--r--drivers/scsi/lpfc/lpfc_hw4.h131
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c577
-rw-r--r--drivers/scsi/lpfc/lpfc_mbox.c35
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c7
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c394
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c1250
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.h27
-rw-r--r--drivers/scsi/lpfc/lpfc_sli4.h34
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h3
-rw-r--r--drivers/scsi/lpfc/lpfc_vport.c4
-rw-r--r--drivers/scsi/megaraid.h2
-rw-r--r--drivers/scsi/megaraid/mbox_defs.h2
-rw-r--r--drivers/scsi/megaraid/megaraid_mbox.c9
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.c738
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.h149
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2.h5
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h274
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_ioc.h18
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_raid.h14
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_tool.h16
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.c152
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.h37
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_ctl.c197
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_ctl.h4
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_scsih.c821
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_transport.c86
-rw-r--r--drivers/scsi/ncr53c8xx.c2
-rw-r--r--drivers/scsi/nsp32.c2
-rw-r--r--drivers/scsi/osd/osd_initiator.c121
-rw-r--r--drivers/scsi/osd/osd_uld.c260
-rw-r--r--drivers/scsi/pm8001/Makefile12
-rw-r--r--drivers/scsi/pm8001/pm8001_chips.h89
-rw-r--r--drivers/scsi/pm8001/pm8001_ctl.c573
-rw-r--r--drivers/scsi/pm8001/pm8001_ctl.h67
-rw-r--r--drivers/scsi/pm8001/pm8001_defs.h112
-rw-r--r--drivers/scsi/pm8001/pm8001_hwi.c4458
-rw-r--r--drivers/scsi/pm8001/pm8001_hwi.h1030
-rw-r--r--drivers/scsi/pm8001/pm8001_init.c891
-rw-r--r--drivers/scsi/pm8001/pm8001_sas.c1103
-rw-r--r--drivers/scsi/pm8001/pm8001_sas.h481
-rw-r--r--drivers/scsi/pmcraid.c13
-rw-r--r--drivers/scsi/pmcraid.h6
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c3
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.c78
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h9
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h3
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c12
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c144
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c50
-rw-r--r--drivers/scsi/qla2xxx/qla_mid.c2
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c67
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h2
-rw-r--r--drivers/scsi/qlogicpti.h2
-rw-r--r--drivers/scsi/scsi.c10
-rw-r--r--drivers/scsi/scsi_debug.c351
-rw-r--r--drivers/scsi/scsi_devinfo.c13
-rw-r--r--drivers/scsi/scsi_error.c65
-rw-r--r--drivers/scsi/scsi_ioctl.c3
-rw-r--r--drivers/scsi/scsi_lib.c11
-rw-r--r--drivers/scsi/scsi_lib_dma.c4
-rw-r--r--drivers/scsi/scsi_netlink.c2
-rw-r--r--drivers/scsi/scsi_scan.c3
-rw-r--r--drivers/scsi/scsi_sysfs.c44
-rw-r--r--drivers/scsi/scsi_transport_fc.c99
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c13
-rw-r--r--drivers/scsi/scsi_transport_sas.c6
-rw-r--r--drivers/scsi/st.c3
-rw-r--r--drivers/scsi/stex.c282
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_glue.c2
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_hipd.c2
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_hipd.h2
-rw-r--r--drivers/scsi/vmw_pvscsi.c1407
-rw-r--r--drivers/scsi/vmw_pvscsi.h397
-rw-r--r--drivers/scsi/wd7000.c2
-rw-r--r--drivers/serial/8250_pnp.c4
-rw-r--r--drivers/serial/Kconfig2
-rw-r--r--drivers/serial/mcf.c2
-rw-r--r--drivers/serial/pmac_zilog.h2
-rw-r--r--drivers/serial/sh-sci.c59
-rw-r--r--drivers/serial/sh-sci.h2
-rw-r--r--drivers/serial/ucc_uart.c2
-rw-r--r--drivers/sh/Makefile1
-rw-r--r--drivers/sh/intc.c123
-rw-r--r--drivers/sh/maple/maple.c4
-rw-r--r--drivers/sh/pfc.c (renamed from arch/sh/kernel/gpio.c)43
-rw-r--r--drivers/spi/spidev.c5
-rw-r--r--drivers/staging/otus/80211core/pub_zfi.h2
-rw-r--r--drivers/staging/otus/zdcompat.h2
-rw-r--r--drivers/staging/rtl8187se/r8180.h2
-rw-r--r--drivers/staging/rtl8192su/r8192S_phyreg.h2
-rw-r--r--drivers/staging/wavelan/wavelan_cs.c2
-rw-r--r--drivers/telephony/ixj.c4
-rw-r--r--drivers/usb/atm/ueagle-atm.c2
-rw-r--r--drivers/usb/class/usbtmc.c2
-rw-r--r--drivers/usb/core/message.c2
-rw-r--r--drivers/usb/gadget/f_acm.c2
-rw-r--r--drivers/usb/gadget/pxa27x_udc.c2
-rw-r--r--drivers/usb/host/ehci-hcd.c2
-rw-r--r--drivers/usb/host/fhci-sched.c2
-rw-r--r--drivers/usb/wusbcore/crypto.c2
-rw-r--r--drivers/usb/wusbcore/wa-xfer.c4
-rw-r--r--drivers/uwb/i1480/dfu/usb.c2
-rw-r--r--drivers/uwb/neh.c2
-rw-r--r--drivers/uwb/wlp/txrx.c2
-rw-r--r--drivers/video/atmel_lcdfb.c2
-rw-r--r--drivers/video/aty/atyfb_base.c4
-rw-r--r--drivers/video/backlight/atmel-pwm-bl.c2
-rw-r--r--drivers/video/backlight/tosa_lcd.c2
-rw-r--r--drivers/video/console/sticore.c2
-rw-r--r--drivers/video/console/vgacon.c5
-rw-r--r--drivers/video/fb_defio.c2
-rw-r--r--drivers/video/gbefb.c2
-rw-r--r--drivers/video/omap/lcd_ams_delta.c4
-rw-r--r--drivers/video/omap/lcd_mipid.c4
-rw-r--r--drivers/video/sgivwfb.c4
-rw-r--r--drivers/video/sh_mobile_lcdcfb.c32
-rw-r--r--drivers/video/stifb.c4
-rw-r--r--drivers/video/tdfxfb.c2
-rw-r--r--drivers/video/via/dvi.c4
-rw-r--r--drivers/video/vt8623fb.c2
-rw-r--r--drivers/watchdog/coh901327_wdt.c2
-rw-r--r--drivers/watchdog/iTCO_wdt.c68
-rw-r--r--drivers/watchdog/machzwd.c2
-rw-r--r--drivers/watchdog/s3c2410_wdt.c89
-rw-r--r--drivers/watchdog/sb_wdog.c4
-rw-r--r--drivers/watchdog/wdrtas.c6
-rw-r--r--drivers/xen/cpu_hotplug.c2
-rw-r--r--fs/binfmt_elf.c2
-rw-r--r--fs/bio.c2
-rw-r--r--fs/btrfs/extent_map.c2
-rw-r--r--fs/cifs/README2
-rw-r--r--fs/cifs/cifsglob.h2
-rw-r--r--fs/cifs/cifspdu.h2
-rw-r--r--fs/cifs/inode.c4
-rw-r--r--fs/cifs/smbdes.c2
-rw-r--r--fs/compat_ioctl.c2
-rw-r--r--fs/debugfs/inode.c6
-rw-r--r--fs/dlm/plock.c2
-rw-r--r--fs/ext3/inode.c2
-rw-r--r--fs/ext4/inode.c8
-rw-r--r--fs/ext4/mballoc.c2
-rw-r--r--fs/jffs2/compr.c2
-rw-r--r--fs/jffs2/readinode.c2
-rw-r--r--fs/jffs2/xattr.c2
-rw-r--r--fs/jfs/jfs_dmap.c4
-rw-r--r--fs/ncpfs/ioctl.c2
-rw-r--r--fs/notify/inotify/inotify_user.c4
-rw-r--r--fs/ntfs/compress.c2
-rw-r--r--fs/ntfs/file.c4
-rw-r--r--fs/ntfs/logfile.c2
-rw-r--r--fs/ocfs2/alloc.c2
-rw-r--r--fs/ocfs2/blockcheck.c2
-rw-r--r--fs/ocfs2/dlm/dlmmaster.c2
-rw-r--r--fs/ocfs2/dlmglue.c2
-rw-r--r--fs/ocfs2/journal.c2
-rw-r--r--fs/ocfs2/refcounttree.c2
-rw-r--r--fs/omfs/bitmap.c2
-rw-r--r--fs/qnx4/bitmap.c2
-rw-r--r--fs/qnx4/dir.c6
-rw-r--r--fs/qnx4/inode.c26
-rw-r--r--fs/qnx4/namei.c6
-rw-r--r--fs/reiserfs/Makefile2
-rw-r--r--fs/reiserfs/bitmap.c4
-rw-r--r--fs/reiserfs/dir.c10
-rw-r--r--fs/reiserfs/do_balan.c17
-rw-r--r--fs/reiserfs/file.c2
-rw-r--r--fs/reiserfs/fix_node.c21
-rw-r--r--fs/reiserfs/inode.c97
-rw-r--r--fs/reiserfs/ioctl.c77
-rw-r--r--fs/reiserfs/journal.c130
-rw-r--r--fs/reiserfs/lock.c88
-rw-r--r--fs/reiserfs/namei.c20
-rw-r--r--fs/reiserfs/prints.c4
-rw-r--r--fs/reiserfs/resize.c2
-rw-r--r--fs/reiserfs/stree.c53
-rw-r--r--fs/reiserfs/super.c52
-rw-r--r--fs/reiserfs/xattr.c6
-rw-r--r--fs/ubifs/recovery.c2
-rw-r--r--fs/xfs/quota/xfs_dquot.h2
-rw-r--r--include/asm-generic/memory_model.h2
-rw-r--r--include/asm-generic/unistd.h2
-rw-r--r--include/crypto/algapi.h1
-rw-r--r--include/crypto/cryptd.h1
-rw-r--r--include/linux/cciss_ioctl.h2
-rw-r--r--include/linux/chio.h2
-rw-r--r--include/linux/clockchips.h19
-rw-r--r--include/linux/clocksource.h18
-rw-r--r--include/linux/crypto.h27
-rw-r--r--include/linux/dm-log-userspace.h2
-rw-r--r--include/linux/dmar.h10
-rw-r--r--include/linux/hid.h1
-rw-r--r--include/linux/hpet.h2
-rw-r--r--include/linux/hrtimer.h4
-rw-r--r--include/linux/hw_random.h7
-rw-r--r--include/linux/ide.h4
-rw-r--r--include/linux/in6.h2
-rw-r--r--include/linux/input/sh_keysc.h (renamed from arch/sh/include/asm/sh_keysc.h)6
-rw-r--r--include/linux/irq.h2
-rw-r--r--include/linux/libata.h2
-rw-r--r--include/linux/mfd/ezx-pcap.h4
-rw-r--r--include/linux/mfd/sh_mobile_sdhi.h8
-rw-r--r--include/linux/pci_ids.h2
-rw-r--r--include/linux/pktcdvd.h2
-rw-r--r--include/linux/reiserfs_fs.h71
-rw-r--r--include/linux/reiserfs_fs_sb.h20
-rw-r--r--include/linux/screen_info.h5
-rw-r--r--include/linux/serial_reg.h8
-rw-r--r--include/linux/sh_intc.h7
-rw-r--r--include/linux/sh_pfc.h96
-rw-r--r--include/linux/spi/spi_bitbang.h2
-rw-r--r--include/linux/sysctl.h10
-rw-r--r--include/linux/tick.h5
-rw-r--r--include/linux/time.h1
-rw-r--r--include/linux/timex.h9
-rw-r--r--include/linux/usb/wusb.h2
-rw-r--r--include/linux/videodev2.h2
-rw-r--r--include/linux/vt_kern.h3
-rw-r--r--include/net/sctp/structs.h2
-rw-r--r--include/net/tcp.h2
-rw-r--r--include/net/wimax.h2
-rw-r--r--include/scsi/Kbuild1
-rw-r--r--include/scsi/fc/Kbuild4
-rw-r--r--include/scsi/fc/fc_els.h6
-rw-r--r--include/scsi/fc/fc_fcoe.h12
-rw-r--r--include/scsi/fc/fc_fcp.h8
-rw-r--r--include/scsi/fc/fc_fip.h12
-rw-r--r--include/scsi/fc/fc_fs.h2
-rw-r--r--include/scsi/fc/fc_gs.h2
-rw-r--r--include/scsi/fc/fc_ns.h35
-rw-r--r--include/scsi/fc_encode.h68
-rw-r--r--include/scsi/fc_frame.h22
-rw-r--r--include/scsi/iscsi_if.h3
-rw-r--r--include/scsi/iscsi_proto.h2
-rw-r--r--include/scsi/libfc.h1158
-rw-r--r--include/scsi/libfcoe.h93
-rw-r--r--include/scsi/libiscsi.h4
-rw-r--r--include/scsi/libsas.h3
-rw-r--r--include/scsi/osd_initiator.h81
-rw-r--r--include/scsi/osd_protocol.h1
-rw-r--r--include/scsi/osd_sense.h3
-rw-r--r--include/scsi/scsi.h4
-rw-r--r--include/scsi/scsi_device.h12
-rw-r--r--include/scsi/scsi_dh.h6
-rw-r--r--include/scsi/scsi_host.h24
-rw-r--r--include/scsi/scsi_transport_fc.h1
-rw-r--r--include/sound/ac97_codec.h2
-rw-r--r--include/sound/wm8993.h2
-rw-r--r--include/video/sgivw.h11
-rw-r--r--init/Kconfig2
-rw-r--r--init/calibrate.c24
-rw-r--r--ipc/msg.c2
-rw-r--r--kernel/cpu.c5
-rw-r--r--kernel/hrtimer.c3
-rw-r--r--kernel/irq/manage.c2
-rw-r--r--kernel/irq/spurious.c2
-rw-r--r--kernel/itimer.c7
-rw-r--r--kernel/perf_event.c4
-rw-r--r--kernel/pm_qos_params.c20
-rw-r--r--kernel/posix-cpu-timers.c5
-rw-r--r--kernel/sys.c14
-rw-r--r--kernel/time.c1
-rw-r--r--kernel/time/clockevents.c13
-rw-r--r--kernel/time/clocksource.c99
-rw-r--r--kernel/time/tick-oneshot.c4
-rw-r--r--kernel/time/tick-sched.c141
-rw-r--r--kernel/time/timekeeping.c125
-rw-r--r--kernel/time/timer_list.c10
-rw-r--r--kernel/user-return-notifier.c6
-rw-r--r--lib/Kconfig.debug2
-rw-r--r--lib/decompress_bunzip2.c2
-rw-r--r--lib/dma-debug.c2
-rw-r--r--lib/idr.c4
-rw-r--r--lib/swiotlb.c2
-rw-r--r--mm/filemap.c2
-rw-r--r--mm/kmemleak.c4
-rw-r--r--mm/memcontrol.c6
-rw-r--r--mm/memory-failure.c2
-rw-r--r--mm/truncate.c2
-rw-r--r--net/bluetooth/bnep/core.c4
-rw-r--r--net/ipv4/netfilter/ipt_ECN.c2
-rw-r--r--net/irda/irlap.c14
-rw-r--r--net/irda/irlap_event.c2
-rw-r--r--net/irda/irlmp.c4
-rw-r--r--net/mac80211/mesh_pathtbl.c4
-rw-r--r--net/netlabel/netlabel_domainhash.c2
-rw-r--r--net/sched/act_api.c2
-rw-r--r--net/sctp/sm_sideeffect.c2
-rw-r--r--net/sctp/sm_statefuns.c2
-rw-r--r--net/sctp/sysctl.c1
-rw-r--r--net/sunrpc/xprtrdma/svc_rdma_sendto.c2
-rw-r--r--net/wimax/op-reset.c2
-rw-r--r--samples/Kconfig3
-rw-r--r--scripts/kconfig/mconf.c2
-rw-r--r--security/selinux/netlabel.c2
-rw-r--r--security/selinux/ss/services.c2
-rw-r--r--sound/Kconfig4
-rw-r--r--sound/isa/cs423x/cs4236.c2
-rw-r--r--sound/isa/opti9xx/miro.c2
-rw-r--r--sound/isa/opti9xx/opti92x-ad1848.c2
-rw-r--r--sound/oss/Kconfig2
-rw-r--r--sound/oss/dmasound/dmasound_paula.c2
-rw-r--r--sound/pci/ca0106/ca0106_proc.c2
-rw-r--r--sound/pci/cs46xx/imgs/cwcdma.asp9
-rw-r--r--sound/pci/emu10k1/emu10k1x.c2
-rw-r--r--sound/pci/hda/patch_cirrus.c2
-rw-r--r--sound/pci/hda/patch_cmedia.c2
-rw-r--r--sound/pci/hda/patch_realtek.c2
-rw-r--r--sound/pci/ice1712/juli.c2
-rw-r--r--sound/pci/rme9652/hdspm.c4
-rw-r--r--sound/soc/codecs/uda134x.c4
-rw-r--r--sound/soc/codecs/wm8903.c6
-rw-r--r--sound/soc/codecs/wm8993.c4
-rw-r--r--sound/soc/s3c24xx/s3c24xx_simtec.c2
-rw-r--r--sound/soc/s6000/s6000-pcm.c2
-rw-r--r--sound/sound_core.c2
-rw-r--r--sound/synth/emux/soundfont.c2
1199 files changed, 41969 insertions, 17754 deletions
diff --git a/Documentation/ABI/stable/sysfs-driver-qla2xxx b/Documentation/ABI/stable/sysfs-driver-qla2xxx
new file mode 100644
index 0000000..9a59d84
--- /dev/null
+++ b/Documentation/ABI/stable/sysfs-driver-qla2xxx
@@ -0,0 +1,8 @@
+What: /sys/bus/pci/drivers/qla2xxx/.../devices/*
+Date: September 2009
+Contact: QLogic Linux Driver <linux-driver@qlogic.com>
+Description: qla2xxx-udev.sh currently looks for uevent CHANGE events to
+ signal a firmware-dump has been generated by the driver and is
+ ready for retrieval.
+Users: qla2xxx-udev.sh. Proposed changes should be mailed to
+ linux-driver@qlogic.com
diff --git a/Documentation/ABI/testing/procfs-diskstats b/Documentation/ABI/testing/procfs-diskstats
index 9923390..f91a973 100644
--- a/Documentation/ABI/testing/procfs-diskstats
+++ b/Documentation/ABI/testing/procfs-diskstats
@@ -8,7 +8,7 @@ Description:
1 - major number
2 - minor mumber
3 - device name
- 4 - reads completed succesfully
+ 4 - reads completed successfully
5 - reads merged
6 - sectors read
7 - time spent reading (ms)
diff --git a/Documentation/ABI/testing/sysfs-block b/Documentation/ABI/testing/sysfs-block
index 5f3beda..d2f9033 100644
--- a/Documentation/ABI/testing/sysfs-block
+++ b/Documentation/ABI/testing/sysfs-block
@@ -4,7 +4,7 @@ Contact: Jerome Marchand <jmarchan@redhat.com>
Description:
The /sys/block/<disk>/stat files displays the I/O
statistics of disk <disk>. They contain 11 fields:
- 1 - reads completed succesfully
+ 1 - reads completed successfully
2 - reads merged
3 - sectors read
4 - time spent reading (ms)
diff --git a/Documentation/DMA-mapping.txt b/Documentation/DMA-mapping.txt
index 01f24e9..ecad88d 100644
--- a/Documentation/DMA-mapping.txt
+++ b/Documentation/DMA-mapping.txt
@@ -214,7 +214,7 @@ most specific mask.
Here is pseudo-code showing how this might be done:
#define PLAYBACK_ADDRESS_BITS DMA_BIT_MASK(32)
- #define RECORD_ADDRESS_BITS 0x00ffffff
+ #define RECORD_ADDRESS_BITS DMA_BIT_MASK(24)
struct my_sound_card *card;
struct pci_dev *pdev;
@@ -224,14 +224,14 @@ Here is pseudo-code showing how this might be done:
card->playback_enabled = 1;
} else {
card->playback_enabled = 0;
- printk(KERN_WARN "%s: Playback disabled due to DMA limitations.\n",
+ printk(KERN_WARNING "%s: Playback disabled due to DMA limitations.\n",
card->name);
}
if (!pci_set_dma_mask(pdev, RECORD_ADDRESS_BITS)) {
card->record_enabled = 1;
} else {
card->record_enabled = 0;
- printk(KERN_WARN "%s: Record disabled due to DMA limitations.\n",
+ printk(KERN_WARNING "%s: Record disabled due to DMA limitations.\n",
card->name);
}
diff --git a/Documentation/DocBook/genericirq.tmpl b/Documentation/DocBook/genericirq.tmpl
index c671a01..1448b33 100644
--- a/Documentation/DocBook/genericirq.tmpl
+++ b/Documentation/DocBook/genericirq.tmpl
@@ -417,8 +417,8 @@ desc->chip->end();
</para>
<para>
To make use of the split implementation, replace the call to
- __do_IRQ by a call to desc->chip->handle_irq() and associate
- the appropriate handler function to desc->chip->handle_irq().
+ __do_IRQ by a call to desc->handle_irq() and associate
+ the appropriate handler function to desc->handle_irq().
In most cases the generic handler implementations should
be sufficient.
</para>
diff --git a/Documentation/DocBook/kernel-hacking.tmpl b/Documentation/DocBook/kernel-hacking.tmpl
index 992e67e..7b3f493 100644
--- a/Documentation/DocBook/kernel-hacking.tmpl
+++ b/Documentation/DocBook/kernel-hacking.tmpl
@@ -352,7 +352,7 @@ asmlinkage long sys_mycall(int arg)
</para>
<programlisting>
-if (signal_pending())
+if (signal_pending(current))
return -ERESTARTSYS;
</programlisting>
diff --git a/Documentation/DocBook/mtdnand.tmpl b/Documentation/DocBook/mtdnand.tmpl
index df0d089..f508a8a 100644
--- a/Documentation/DocBook/mtdnand.tmpl
+++ b/Documentation/DocBook/mtdnand.tmpl
@@ -362,7 +362,7 @@ module_exit(board_cleanup);
<sect1 id="Multiple_chip_control">
<title>Multiple chip control</title>
<para>
- The nand driver can control chip arrays. Therefor the
+ The nand driver can control chip arrays. Therefore the
board driver must provide an own select_chip function. This
function must (de)select the requested chip.
The function pointer in the nand_chip structure must
diff --git a/Documentation/DocBook/v4l/videodev2.h.xml b/Documentation/DocBook/v4l/videodev2.h.xml
index 9700206..26303e5 100644
--- a/Documentation/DocBook/v4l/videodev2.h.xml
+++ b/Documentation/DocBook/v4l/videodev2.h.xml
@@ -492,7 +492,7 @@ struct <link linkend="v4l2-jpegcompression">v4l2_jpegcompression</link> {
* you do, leave them untouched.
* Inluding less markers will make the
* resulting code smaller, but there will
- * be fewer aplications which can read it.
+ * be fewer applications which can read it.
* The presence of the APP and COM marker
* is influenced by APP_len and COM_len
* ONLY, not by this property! */
diff --git a/Documentation/DocBook/writing-an-alsa-driver.tmpl b/Documentation/DocBook/writing-an-alsa-driver.tmpl
index 7a2e0e9..0d0f7b4 100644
--- a/Documentation/DocBook/writing-an-alsa-driver.tmpl
+++ b/Documentation/DocBook/writing-an-alsa-driver.tmpl
@@ -5318,7 +5318,7 @@ struct _snd_pcm_runtime {
pages of the given size and map them onto the virtually contiguous
memory. The virtual pointer is addressed in runtime-&gt;dma_area.
The physical address (runtime-&gt;dma_addr) is set to zero,
- because the buffer is physically non-contigous.
+ because the buffer is physically non-contiguous.
The physical address table is set up in sgbuf-&gt;table.
You can get the physical address at a certain offset via
<function>snd_pcm_sgbuf_get_addr()</function>.
diff --git a/Documentation/dvb/README.dvb-usb b/Documentation/dvb/README.dvb-usb
index bf2a9cd..c8238e4 100644
--- a/Documentation/dvb/README.dvb-usb
+++ b/Documentation/dvb/README.dvb-usb
@@ -85,7 +85,7 @@ http://www.linuxtv.org/wiki/index.php/DVB_USB
- moved transfer control (pid filter, fifo control) from usb driver to frontend, it seems
better settled there (added xfer_ops-struct)
- created a common files for frontends (mc/p/mb)
- 2004-09-28 - added support for a new device (Unkown, vendor ID is Hyper-Paltek)
+ 2004-09-28 - added support for a new device (Unknown, vendor ID is Hyper-Paltek)
2004-09-20 - added support for a new device (Compro DVB-U2000), thanks
to Amaury Demol for reporting
- changed usb TS transfer method (several urbs, stopping transfer
diff --git a/Documentation/edac.txt b/Documentation/edac.txt
index 06f8f46..79c5332 100644
--- a/Documentation/edac.txt
+++ b/Documentation/edac.txt
@@ -80,7 +80,7 @@ is:
broken_parity_status
-as is located in /sys/devices/pci<XXX>/0000:XX:YY.Z directorys for
+as is located in /sys/devices/pci<XXX>/0000:XX:YY.Z directories for
PCI devices.
FUTURE HARDWARE SCANNING
@@ -288,9 +288,8 @@ Total UE count that had no information attribute fileY:
'ue_noinfo_count'
- This attribute file displays the number of UEs that
- have occurred have occurred with no informations as to which DIMM
- slot is having errors.
+ This attribute file displays the number of UEs that have occurred
+ with no information as to which DIMM slot is having errors.
Total Correctable Errors count attribute file:
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index 4af0018..94b9f20 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -1089,8 +1089,8 @@ The "processes" line gives the number of processes and threads created, which
includes (but is not limited to) those created by calls to the fork() and
clone() system calls.
-The "procs_running" line gives the number of processes currently running on
-CPUs.
+The "procs_running" line gives the total number of threads that are
+running or ready to run (i.e., the total number of runnable threads).
The "procs_blocked" line gives the number of processes currently blocked,
waiting for I/O to complete.
diff --git a/Documentation/gpio.txt b/Documentation/gpio.txt
index fa4dc07..e4e7dae 100644
--- a/Documentation/gpio.txt
+++ b/Documentation/gpio.txt
@@ -380,7 +380,7 @@ rare; use gpiochip_remove() when it is unavoidable.
Most often a gpio_chip is part of an instance-specific structure with state
not exposed by the GPIO interfaces, such as addressing, power management,
-and more. Chips such as codecs will have complex non-GPIO state,
+and more. Chips such as codecs will have complex non-GPIO state.
Any debugfs dump method should normally ignore signals which haven't been
requested as GPIOs. They can use gpiochip_is_requested(), which returns
@@ -531,7 +531,7 @@ and have the following read/write attributes:
This file exists only if the pin can be configured as an
interrupt generating input pin.
-GPIO controllers have paths like /sys/class/gpio/chipchip42/ (for the
+GPIO controllers have paths like /sys/class/gpio/gpiochip42/ (for the
controller implementing GPIOs starting at #42) and have the following
read-only attributes:
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 495a39a..777dc8a 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -2747,6 +2747,15 @@ and is between 256 and 4096 characters. It is defined in the file
Default is 1, i.e. UTF-8 mode is enabled for all
newly opened terminals.
+ vt.global_cursor_default=
+ [VT]
+ Format=<-1|0|1>
+ Set system-wide default for whether a cursor
+ is shown on new VTs. Default is -1,
+ i.e. cursors will be created by default unless
+ overridden by individual drivers. 0 will hide
+ cursors, 1 will display them.
+
waveartist= [HW,OSS]
Format: <io>,<irq>,<dma>,<dma2>
diff --git a/Documentation/lguest/lguest.c b/Documentation/lguest/lguest.c
index 098de5b..4220851 100644
--- a/Documentation/lguest/lguest.c
+++ b/Documentation/lguest/lguest.c
@@ -304,7 +304,7 @@ static void *map_zeroed_pages(unsigned int num)
addr = mmap(NULL, getpagesize() * num,
PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, fd, 0);
if (addr == MAP_FAILED)
- err(1, "Mmaping %u pages of /dev/zero", num);
+ err(1, "Mmapping %u pages of /dev/zero", num);
/*
* One neat mmap feature is that you can close the fd, and it
diff --git a/Documentation/c2port.txt b/Documentation/misc-devices/c2port.txt
index d9bf93e..d9bf93e 100644
--- a/Documentation/c2port.txt
+++ b/Documentation/misc-devices/c2port.txt
diff --git a/Documentation/ics932s401 b/Documentation/misc-devices/ics932s401
index 07a739f..07a739f 100644
--- a/Documentation/ics932s401
+++ b/Documentation/misc-devices/ics932s401
diff --git a/Documentation/oops-tracing.txt b/Documentation/oops-tracing.txt
index b152e81..c10c022 100644
--- a/Documentation/oops-tracing.txt
+++ b/Documentation/oops-tracing.txt
@@ -257,6 +257,8 @@ characters, each representing a particular tainted value.
10: 'W' if a warning has previously been issued by the kernel.
+ 11: 'C' if a staging driver has been loaded.
+
The primary reason for the 'Tainted: ' string is to tell kernel
debuggers if this is a clean kernel or if anything unusual has
occurred. Tainting is permanent: even if an offending module is
diff --git a/Documentation/power/regulator/consumer.txt b/Documentation/power/regulator/consumer.txt
index 5f83fd2..cdebb51 100644
--- a/Documentation/power/regulator/consumer.txt
+++ b/Documentation/power/regulator/consumer.txt
@@ -104,7 +104,7 @@ to set the limit to 500mA when supplying power.
Consumers can control their supply current limit by calling :-
-int regulator_set_current_limit(regulator, min_uV, max_uV);
+int regulator_set_current_limit(regulator, min_uA, max_uA);
Where min_uA and max_uA are the minimum and maximum acceptable current limit in
microamps.
diff --git a/Documentation/scsi/ChangeLog.megaraid_sas b/Documentation/scsi/ChangeLog.megaraid_sas
index c851ef4..17ffa06 100644
--- a/Documentation/scsi/ChangeLog.megaraid_sas
+++ b/Documentation/scsi/ChangeLog.megaraid_sas
@@ -1,3 +1,65 @@
+1 Release Date : Tues. July 28, 2009 10:12:45 PST 2009 -
+ (emaild-id:megaraidlinux@lsi.com)
+ Bo Yang
+
+2 Current Version : 00.00.04.12
+3 Older Version : 00.00.04.10
+
+1. Change the AEN sys PD update from scsi_scan to
+ scsi_add_device and scsi_remove_device.
+2. Takeoff the debug print-out in aen_polling routine.
+
+1 Release Date : Thur. July 02, 2009 10:12:45 PST 2009 -
+ (emaild-id:megaraidlinux@lsi.com)
+ Bo Yang
+
+2 Current Version : 00.00.04.10
+3 Older Version : 00.00.04.08
+
+1. Add the 3 mins timeout during the controller initialize.
+2. Add the fix for 64bit sense date errors.
+
+1 Release Date : Tues. May 05, 2009 10:12:45 PST 2009 -
+ (emaild-id:megaraidlinux@lsi.com)
+ Bo Yang
+
+2 Current Version : 00.00.04.08
+3 Older Version : 00.00.04.06
+
+1. Add the fix of pending in FW after deleted the logic drives.
+2. Add the fix of deallocating memory after get pdlist.
+
+1 Release Date : Tues. March 26, 2009 10:12:45 PST 2009 -
+ (emaild-id:megaraidlinux@lsi.com)
+ Bo Yang
+
+2 Current Version : 00.00.04.06
+3 Older Version : 00.00.04.04
+
+1. Add the fix of the driver cmd empty fix of the driver cmd empty.
+2. Add the fix of the driver MSM AEN CMD cause the system slow.
+
+1 Release Date : Tues. March 03, 2009 10:12:45 PST 2009 -
+ (emaild-id:megaraidlinux@lsi.com)
+ Bo Yang
+
+2 Current Version : 00.00.04.04
+3 Older Version : 00.00.04.01
+
+1. Add the Tape drive fix to the driver: If the command is for
+ the tape device, set the pthru timeout to the os layer timeout value.
+
+2. Add Poll_wait mechanism to Gen-2 Linux driv.
+ In the aen handler, driver needs to wakeup poll handler similar to
+ the way it raises SIGIO.
+
+3. Add new controller new SAS2 support to the driver.
+
+4. Report the unconfigured PD (system PD) to OS.
+
+5. Add the IEEE SGL support to the driver
+
+6. Reasign the Application cmds to SAS2 controller
1 Release Date : Thur.July. 24 11:41:51 PST 2008 -
(emaild-id:megaraidlinux@lsi.com)
@@ -185,7 +247,7 @@ ii. FW enables WCE bit in Mode Sense cmd for drives that are configured
Disks are exposed with WCE=1. User is advised to enable Write Back
mode only when the controller has battery backup. At this time
Synhronize cache is not supported by the FW. Driver will short-cycle
- the cmd and return sucess without sending down to FW.
+ the cmd and return success without sending down to FW.
1 Release Date : Sun Jan. 14 11:21:32 PDT 2007 -
Sumant Patro <Sumant.Patro@lsil.com>/Bo Yang
diff --git a/Documentation/spi/spi-summary b/Documentation/spi/spi-summary
index deab51d..4884cb3 100644
--- a/Documentation/spi/spi-summary
+++ b/Documentation/spi/spi-summary
@@ -538,7 +538,7 @@ SPI MESSAGE QUEUE
The bulk of the driver will be managing the I/O queue fed by transfer().
That queue could be purely conceptual. For example, a driver used only
-for low-frequency sensor acess might be fine using synchronous PIO.
+for low-frequency sensor access might be fine using synchronous PIO.
But the queue will probably be very real, using message->queue, PIO,
often DMA (especially if the root filesystem is in SPI flash), and
diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt
index a028b92..8f7a0e7 100644
--- a/Documentation/sysctl/kernel.txt
+++ b/Documentation/sysctl/kernel.txt
@@ -139,9 +139,9 @@ core_pattern is used to specify a core dumpfile pattern name.
core_pipe_limit:
This sysctl is only applicable when core_pattern is configured to pipe core
-files to user space helper a (when the first character of core_pattern is a '|',
+files to a user space helper (when the first character of core_pattern is a '|',
see above). When collecting cores via a pipe to an application, it is
-occasionally usefull for the collecting application to gather data about the
+occasionally useful for the collecting application to gather data about the
crashing process from its /proc/pid directory. In order to do this safely, the
kernel must wait for the collecting process to exit, so as not to remove the
crashing processes proc files prematurely. This in turn creates the possibility
@@ -152,7 +152,7 @@ applications in parallel. If this value is exceeded, then those crashing
processes above that value are noted via the kernel log and their cores are
skipped. 0 is a special value, indicating that unlimited processes may be
captured in parallel, but that no waiting will take place (i.e. the collecting
-process is not guaranteed access to /proc/<crahing pid>/). This value defaults
+process is not guaranteed access to /proc/<crashing pid>/). This value defaults
to 0.
==============================================================
diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt
index a6e360d..fc5790d 100644
--- a/Documentation/sysctl/vm.txt
+++ b/Documentation/sysctl/vm.txt
@@ -370,7 +370,7 @@ The default is 1 percent.
mmap_min_addr
This file indicates the amount of address space which a user process will
-be restricted from mmaping. Since kernel null dereference bugs could
+be restricted from mmapping. Since kernel null dereference bugs could
accidentally operate based on the information in the first couple of pages
of memory userspace processes should not be allowed to write to them. By
default this value is set to 0 and no protections will be enforced by the
diff --git a/Documentation/timers/hpet.txt b/Documentation/timers/hpet.txt
index 04763a3..16d25e6 100644
--- a/Documentation/timers/hpet.txt
+++ b/Documentation/timers/hpet.txt
@@ -3,7 +3,7 @@
The High Precision Event Timer (HPET) hardware follows a specification
by Intel and Microsoft which can be found at
- http://www.intel.com/technology/architecture/hpetspec.htm
+ http://www.intel.com/hardwaredesign/hpetspec_1.pdf
Each HPET has one fixed-rate counter (at 10+ MHz, hence "High Precision")
and up to 32 comparators. Normally three or more comparators are provided,
diff --git a/Documentation/video4linux/gspca.txt b/Documentation/video4linux/gspca.txt
index 3f61825..6b29555 100644
--- a/Documentation/video4linux/gspca.txt
+++ b/Documentation/video4linux/gspca.txt
@@ -6,7 +6,7 @@ The modules are:
xxxx vend:prod
----
-spca501 0000:0000 MystFromOri Unknow Camera
+spca501 0000:0000 MystFromOri Unknown Camera
m5602 0402:5602 ALi Video Camera Controller
spca501 040a:0002 Kodak DVC-325
spca500 040a:0300 Kodak EZ200
diff --git a/Documentation/vm/page-types.c b/Documentation/vm/page-types.c
index 4793c6a..ea44ea5 100644
--- a/Documentation/vm/page-types.c
+++ b/Documentation/vm/page-types.c
@@ -301,7 +301,7 @@ static char *page_flag_name(uint64_t flags)
present = (flags >> i) & 1;
if (!page_flag_names[i]) {
if (present)
- fatal("unkown flag bit %d\n", i);
+ fatal("unknown flag bit %d\n", i);
continue;
}
buf[j++] = present ? page_flag_names[i][0] : '_';
diff --git a/Documentation/vm/slub.txt b/Documentation/vm/slub.txt
index 510917f..b37300e 100644
--- a/Documentation/vm/slub.txt
+++ b/Documentation/vm/slub.txt
@@ -245,7 +245,7 @@ been overwritten. Here a string of 8 characters was written into a slab that
has the length of 8 characters. However, a 8 character string needs a
terminating 0. That zero has overwritten the first byte of the Redzone field.
After reporting the details of the issue encountered the FIX SLUB message
-tell us that SLUB has restored the Redzone to its proper value and then
+tells us that SLUB has restored the Redzone to its proper value and then
system operations continue.
Emergency operations:
diff --git a/MAINTAINERS b/MAINTAINERS
index ea781c1..f7b0ced 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3139,6 +3139,7 @@ S: Supported
F: Documentation/s390/kvm.txt
F: arch/s390/include/asm/kvm*
F: arch/s390/kvm/
+F: drivers/s390/kvm/
KEXEC
M: Eric Biederman <ebiederm@xmission.com>
@@ -4195,6 +4196,13 @@ W: http://www.pmc-sierra.com/
S: Supported
F: drivers/scsi/pmcraid.*
+PMC SIERRA PM8001 DRIVER
+M: jack_wang@usish.com
+M: lindar_liu@usish.com
+L: linux-scsi@vger.kernel.org
+S: Supported
+F: drivers/scsi/pm8001/
+
POSIX CLOCKS and TIMERS
M: Thomas Gleixner <tglx@linutronix.de>
S: Supported
@@ -4553,6 +4561,7 @@ L: linux-s390@vger.kernel.org
W: http://www.ibm.com/developerworks/linux/linux390/
S: Supported
F: arch/s390/
+F: drivers/s390/
S390 NETWORK DRIVERS
M: Ursula Braun <ursula.braun@de.ibm.com>
@@ -4568,6 +4577,7 @@ M: Felix Beck <felix.beck@de.ibm.com>
M: Ralph Wuerthner <ralph.wuerthner@de.ibm.com>
M: linux390@de.ibm.com
L: linux-s390@vger.kernel.org
+W: http://www.ibm.com/developerworks/linux/linux390/
S: Supported
F: drivers/s390/crypto/
@@ -5769,6 +5779,14 @@ L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/vmxnet3/
+VMware PVSCSI driver
+M: Alok Kataria <akataria@vmware.com>
+M: VMware PV-Drivers <pv-drivers@vmware.com>
+L: linux-scsi@vger.kernel.org
+S: Maintained
+F: drivers/scsi/vmw_pvscsi.c
+F: drivers/scsi/vmw_pvscsi.h
+
VOLTAGE AND CURRENT REGULATOR FRAMEWORK
M: Liam Girdwood <lrg@slimlogic.co.uk>
M: Mark Brown <broonie@opensource.wolfsonmicro.com>
diff --git a/arch/alpha/mm/numa.c b/arch/alpha/mm/numa.c
index 10b4035..7b2c56d 100644
--- a/arch/alpha/mm/numa.c
+++ b/arch/alpha/mm/numa.c
@@ -197,7 +197,7 @@ setup_memory_node(int nid, void *kernel_end)
}
if (bootmap_start == -1)
- panic("couldn't find a contigous place for the bootmap");
+ panic("couldn't find a contiguous place for the bootmap");
/* Allocate the bootmap and mark the whole MM as reserved. */
bootmap_size = init_bootmem_node(NODE_DATA(nid), bootmap_start,
diff --git a/arch/arm/common/scoop.c b/arch/arm/common/scoop.c
index 7713a08..37bda5f 100644
--- a/arch/arm/common/scoop.c
+++ b/arch/arm/common/scoop.c
@@ -82,7 +82,7 @@ static int scoop_gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct scoop_dev *sdev = container_of(chip, struct scoop_dev, gpio);
- /* XXX: I'm usure, but it seems so */
+ /* XXX: I'm unsure, but it seems so */
return ioread16(sdev->base + SCOOP_GPRR) & (1 << (offset + 1));
}
diff --git a/arch/arm/configs/da830_omapl137_defconfig b/arch/arm/configs/da830_omapl137_defconfig
deleted file mode 100644
index 7c8e38f..0000000
--- a/arch/arm/configs/da830_omapl137_defconfig
+++ /dev/null
@@ -1,1254 +0,0 @@
-#
-# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc2-davinci1
-# Wed May 13 15:33:29 2009
-#
-CONFIG_ARM=y
-CONFIG_SYS_SUPPORTS_APM_EMULATION=y
-CONFIG_GENERIC_GPIO=y
-CONFIG_GENERIC_TIME=y
-CONFIG_GENERIC_CLOCKEVENTS=y
-CONFIG_MMU=y
-# CONFIG_NO_IOPORT is not set
-CONFIG_GENERIC_HARDIRQS=y
-CONFIG_STACKTRACE_SUPPORT=y
-CONFIG_HAVE_LATENCYTOP_SUPPORT=y
-CONFIG_LOCKDEP_SUPPORT=y
-CONFIG_TRACE_IRQFLAGS_SUPPORT=y
-CONFIG_HARDIRQS_SW_RESEND=y
-CONFIG_GENERIC_IRQ_PROBE=y
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_ARCH_HAS_ILOG2_U32 is not set
-# CONFIG_ARCH_HAS_ILOG2_U64 is not set
-CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_ZONE_DMA=y
-CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
-CONFIG_VECTORS_BASE=0xffff0000
-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 is not set
-CONFIG_SYSVIPC=y
-CONFIG_SYSVIPC_SYSCTL=y
-CONFIG_POSIX_MQUEUE=y
-CONFIG_POSIX_MQUEUE_SYSCTL=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_TASKSTATS is not set
-# CONFIG_AUDIT is not set
-
-#
-# RCU Subsystem
-#
-CONFIG_CLASSIC_RCU=y
-# CONFIG_TREE_RCU is not set
-# CONFIG_PREEMPT_RCU is not set
-# CONFIG_TREE_RCU_TRACE is not set
-# CONFIG_PREEMPT_RCU_TRACE is not set
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_GROUP_SCHED=y
-CONFIG_FAIR_GROUP_SCHED=y
-# CONFIG_RT_GROUP_SCHED is not set
-CONFIG_USER_SCHED=y
-# CONFIG_CGROUP_SCHED is not set
-# CONFIG_CGROUPS is not set
-CONFIG_SYSFS_DEPRECATED=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-# CONFIG_RELAY is not set
-# CONFIG_NAMESPACES is not set
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE=""
-CONFIG_RD_GZIP=y
-# CONFIG_RD_BZIP2 is not set
-# CONFIG_RD_LZMA is not set
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_SYSCTL=y
-CONFIG_ANON_INODES=y
-CONFIG_EMBEDDED=y
-CONFIG_UID16=y
-CONFIG_SYSCTL_SYSCALL=y
-CONFIG_KALLSYMS=y
-# CONFIG_KALLSYMS_ALL is not set
-# CONFIG_KALLSYMS_EXTRA_PASS is not set
-# CONFIG_STRIP_ASM_SYMS 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_SIGNALFD=y
-CONFIG_TIMERFD=y
-CONFIG_EVENTFD=y
-CONFIG_SHMEM=y
-CONFIG_AIO=y
-CONFIG_VM_EVENT_COUNTERS=y
-CONFIG_SLUB_DEBUG=y
-CONFIG_COMPAT_BRK=y
-# CONFIG_SLAB is not set
-CONFIG_SLUB=y
-# CONFIG_SLOB is not set
-# CONFIG_PROFILING is not set
-# CONFIG_MARKERS is not set
-CONFIG_HAVE_OPROFILE=y
-# CONFIG_KPROBES is not set
-CONFIG_HAVE_KPROBES=y
-CONFIG_HAVE_KRETPROBES=y
-CONFIG_HAVE_CLK=y
-# CONFIG_SLOW_WORK is not set
-CONFIG_HAVE_GENERIC_DMA_COHERENT=y
-CONFIG_SLABINFO=y
-CONFIG_RT_MUTEXES=y
-CONFIG_BASE_SMALL=0
-CONFIG_MODULES=y
-# CONFIG_MODULE_FORCE_LOAD is not set
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-# CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_BLOCK=y
-# CONFIG_LBD is not set
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_BLK_DEV_INTEGRITY is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-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"
-# CONFIG_FREEZER is not set
-
-#
-# System Type
-#
-# CONFIG_ARCH_AAEC2000 is not set
-# CONFIG_ARCH_INTEGRATOR is not set
-# CONFIG_ARCH_REALVIEW is not set
-# CONFIG_ARCH_VERSATILE is not set
-# CONFIG_ARCH_AT91 is not set
-# CONFIG_ARCH_CLPS711X is not set
-# CONFIG_ARCH_EBSA110 is not set
-# CONFIG_ARCH_EP93XX is not set
-# CONFIG_ARCH_GEMINI is not set
-# CONFIG_ARCH_FOOTBRIDGE is not set
-# CONFIG_ARCH_NETX is not set
-# CONFIG_ARCH_H720X is not set
-# CONFIG_ARCH_IMX is not set
-# CONFIG_ARCH_IOP13XX is not set
-# CONFIG_ARCH_IOP32X is not set
-# CONFIG_ARCH_IOP33X is not set
-# CONFIG_ARCH_IXP23XX is not set
-# CONFIG_ARCH_IXP2000 is not set
-# CONFIG_ARCH_IXP4XX is not set
-# CONFIG_ARCH_L7200 is not set
-# CONFIG_ARCH_KIRKWOOD is not set
-# CONFIG_ARCH_KS8695 is not set
-# CONFIG_ARCH_NS9XXX is not set
-# CONFIG_ARCH_LOKI is not set
-# CONFIG_ARCH_MV78XX0 is not set
-# CONFIG_ARCH_MXC is not set
-# CONFIG_ARCH_ORION5X is not set
-# CONFIG_ARCH_PNX4008 is not set
-# CONFIG_ARCH_PXA is not set
-# CONFIG_ARCH_MMP is not set
-# CONFIG_ARCH_RPC is not set
-# CONFIG_ARCH_SA1100 is not set
-# CONFIG_ARCH_S3C2410 is not set
-# CONFIG_ARCH_S3C64XX is not set
-# CONFIG_ARCH_SHARK is not set
-# CONFIG_ARCH_LH7A40X is not set
-CONFIG_ARCH_DAVINCI=y
-# CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_MSM is not set
-# CONFIG_ARCH_W90X900 is not set
-CONFIG_CP_INTC=y
-
-#
-# TI DaVinci Implementations
-#
-
-#
-# DaVinci Core Type
-#
-# CONFIG_ARCH_DAVINCI_DM644x is not set
-# CONFIG_ARCH_DAVINCI_DM646x is not set
-# CONFIG_ARCH_DAVINCI_DM355 is not set
-CONFIG_ARCH_DAVINCI_DA830=y
-
-#
-# DaVinci Board Type
-#
-CONFIG_MACH_DAVINCI_DA830_EVM=y
-CONFIG_DAVINCI_MUX=y
-# CONFIG_DAVINCI_MUX_DEBUG is not set
-# CONFIG_DAVINCI_MUX_WARNINGS is not set
-CONFIG_DAVINCI_RESET_CLOCKS=y
-
-#
-# Processor Type
-#
-CONFIG_CPU_32=y
-CONFIG_CPU_ARM926T=y
-CONFIG_CPU_32v5=y
-CONFIG_CPU_ABRT_EV5TJ=y
-CONFIG_CPU_PABRT_NOIFAR=y
-CONFIG_CPU_CACHE_VIVT=y
-CONFIG_CPU_COPY_V4WB=y
-CONFIG_CPU_TLB_V4WBI=y
-CONFIG_CPU_CP15=y
-CONFIG_CPU_CP15_MMU=y
-
-#
-# Processor Features
-#
-CONFIG_ARM_THUMB=y
-# CONFIG_CPU_ICACHE_DISABLE is not set
-# CONFIG_CPU_DCACHE_DISABLE is not set
-CONFIG_CPU_DCACHE_WRITETHROUGH=y
-# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
-# CONFIG_OUTER_CACHE is not set
-CONFIG_COMMON_CLKDEV=y
-
-#
-# Bus support
-#
-# CONFIG_PCI_SYSCALL is not set
-# CONFIG_ARCH_SUPPORTS_MSI is not set
-# CONFIG_PCCARD is not set
-
-#
-# Kernel Features
-#
-CONFIG_TICK_ONESHOT=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
-CONFIG_VMSPLIT_3G=y
-# CONFIG_VMSPLIT_2G is not set
-# CONFIG_VMSPLIT_1G is not set
-CONFIG_PAGE_OFFSET=0xC0000000
-CONFIG_PREEMPT=y
-CONFIG_HZ=100
-CONFIG_AEABI=y
-# CONFIG_OABI_COMPAT is not set
-CONFIG_ARCH_FLATMEM_HAS_HOLES=y
-# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
-# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
-# CONFIG_HIGHMEM 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_PAGEFLAGS_EXTENDED=y
-CONFIG_SPLIT_PTLOCK_CPUS=4096
-# CONFIG_PHYS_ADDR_T_64BIT is not set
-CONFIG_ZONE_DMA_FLAG=1
-CONFIG_BOUNCE=y
-CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
-CONFIG_HAVE_MLOCK=y
-CONFIG_HAVE_MLOCKED_PAGE_BIT=y
-CONFIG_LEDS=y
-# CONFIG_LEDS_CPU is not set
-CONFIG_ALIGNMENT_TRAP=y
-
-#
-# Boot options
-#
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE=""
-# CONFIG_XIP_KERNEL is not set
-# CONFIG_KEXEC is not set
-
-#
-# CPU Power Management
-#
-# CONFIG_CPU_IDLE is not set
-
-#
-# Floating point emulation
-#
-
-#
-# At least one emulation must be selected
-#
-# CONFIG_VFP is not set
-
-#
-# Userspace binary formats
-#
-CONFIG_BINFMT_ELF=y
-# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
-CONFIG_HAVE_AOUT=y
-# CONFIG_BINFMT_AOUT is not set
-# CONFIG_BINFMT_MISC is not set
-
-#
-# Power management options
-#
-# CONFIG_PM is not set
-CONFIG_ARCH_SUSPEND_POSSIBLE=y
-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_XFRM_STATISTICS 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_LRO 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=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_NDISC_NODETYPE=y
-# CONFIG_IPV6_TUNNEL is not set
-# CONFIG_IPV6_MULTIPLE_TABLES is not set
-# CONFIG_IPV6_MROUTE is not set
-# CONFIG_NETWORK_SECMARK is not set
-CONFIG_NETFILTER=y
-# CONFIG_NETFILTER_DEBUG is not set
-CONFIG_NETFILTER_ADVANCED=y
-
-#
-# Core Netfilter Configuration
-#
-# CONFIG_NETFILTER_NETLINK_QUEUE is not set
-# CONFIG_NETFILTER_NETLINK_LOG is not set
-# CONFIG_NF_CONNTRACK is not set
-# CONFIG_NETFILTER_XTABLES is not set
-# CONFIG_IP_VS is not set
-
-#
-# IP: Netfilter Configuration
-#
-# CONFIG_NF_DEFRAG_IPV4 is not set
-# CONFIG_IP_NF_QUEUE is not set
-# CONFIG_IP_NF_IPTABLES is not set
-# CONFIG_IP_NF_ARPTABLES is not set
-
-#
-# IPv6: Netfilter Configuration
-#
-# CONFIG_IP6_NF_QUEUE is not set
-# CONFIG_IP6_NF_IPTABLES 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_NET_DSA 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
-# CONFIG_PHONET is not set
-# CONFIG_NET_SCHED is not set
-# CONFIG_DCB is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_CAN is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
-# CONFIG_AF_RXRPC is not set
-# CONFIG_WIRELESS is not set
-# CONFIG_WIMAX is not set
-# CONFIG_RFKILL is not set
-# CONFIG_NET_9P is not set
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-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=m
-# CONFIG_BLK_DEV_CRYPTOLOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=1
-CONFIG_BLK_DEV_RAM_SIZE=32768
-# CONFIG_BLK_DEV_XIP is not set
-# CONFIG_CDROM_PKTCDVD is not set
-# CONFIG_ATA_OVER_ETH is not set
-CONFIG_MISC_DEVICES=y
-# CONFIG_ICS932S401 is not set
-# CONFIG_ENCLOSURE_SERVICES is not set
-# CONFIG_ISL29003 is not set
-# CONFIG_C2PORT is not set
-
-#
-# EEPROM support
-#
-CONFIG_EEPROM_AT24=y
-# CONFIG_EEPROM_LEGACY is not set
-# CONFIG_EEPROM_93CX6 is not set
-CONFIG_HAVE_IDE=y
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-# CONFIG_RAID_ATTRS is not set
-CONFIG_SCSI=m
-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=m
-# 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_SRP_ATTRS is not set
-CONFIG_SCSI_LOWLEVEL=y
-# CONFIG_ISCSI_TCP is not set
-# CONFIG_LIBFC is not set
-# CONFIG_LIBFCOE is not set
-# CONFIG_SCSI_DEBUG is not set
-# CONFIG_SCSI_DH is not set
-# CONFIG_SCSI_OSD_INITIATOR is not set
-# CONFIG_ATA is not set
-# CONFIG_MD is not set
-CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_MACVLAN is not set
-# CONFIG_EQUALIZER is not set
-CONFIG_TUN=m
-# CONFIG_VETH is not set
-CONFIG_PHYLIB=y
-
-#
-# MII PHY device drivers
-#
-# CONFIG_MARVELL_PHY is not set
-# CONFIG_DAVICOM_PHY is not set
-# CONFIG_QSEMI_PHY is not set
-CONFIG_LXT_PHY=y
-# CONFIG_CICADA_PHY is not set
-# CONFIG_VITESSE_PHY is not set
-# CONFIG_SMSC_PHY is not set
-# CONFIG_BROADCOM_PHY is not set
-# CONFIG_ICPLUS_PHY is not set
-# CONFIG_REALTEK_PHY is not set
-# CONFIG_NATIONAL_PHY is not set
-# CONFIG_STE10XP is not set
-CONFIG_LSI_ET1011C_PHY=y
-# CONFIG_FIXED_PHY is not set
-# CONFIG_MDIO_BITBANG is not set
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-# CONFIG_AX88796 is not set
-# CONFIG_SMC91X is not set
-CONFIG_TI_DAVINCI_EMAC=y
-# CONFIG_DM9000 is not set
-# CONFIG_ETHOC is not set
-# CONFIG_SMC911X is not set
-# CONFIG_SMSC911X is not set
-# CONFIG_DNET 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_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
-# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
-# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
-# CONFIG_B44 is not set
-# 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
-
-#
-# Enable WiMAX (Networking options) to see the WiMAX drivers
-#
-# CONFIG_WAN is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-CONFIG_NETCONSOLE=y
-# CONFIG_NETCONSOLE_DYNAMIC is not set
-CONFIG_NETPOLL=y
-CONFIG_NETPOLL_TRAP=y
-CONFIG_NET_POLL_CONTROLLER=y
-# CONFIG_ISDN 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=m
-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_EVDEV=m
-CONFIG_INPUT_EVBUG=m
-
-#
-# Input Device Drivers
-#
-CONFIG_INPUT_KEYBOARD=y
-CONFIG_KEYBOARD_ATKBD=m
-# CONFIG_KEYBOARD_SUNKBD is not set
-# CONFIG_KEYBOARD_LKKBD is not set
-CONFIG_KEYBOARD_XTKBD=m
-# CONFIG_KEYBOARD_NEWTON is not set
-# CONFIG_KEYBOARD_STOWAWAY is not set
-CONFIG_KEYBOARD_GPIO=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_AD7879_I2C is not set
-# CONFIG_TOUCHSCREEN_AD7879 is not set
-# CONFIG_TOUCHSCREEN_FUJITSU is not set
-# CONFIG_TOUCHSCREEN_GUNZE is not set
-# CONFIG_TOUCHSCREEN_ELO is not set
-# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
-# CONFIG_TOUCHSCREEN_MTOUCH is not set
-# CONFIG_TOUCHSCREEN_INEXIO is not set
-# CONFIG_TOUCHSCREEN_MK712 is not set
-# CONFIG_TOUCHSCREEN_PENMOUNT is not set
-# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
-# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
-# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
-# CONFIG_TOUCHSCREEN_TSC2007 is not set
-# CONFIG_INPUT_MISC is not set
-
-#
-# Hardware I/O ports
-#
-CONFIG_SERIO=y
-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_CONSOLE_TRANSLATIONS=y
-# CONFIG_VT_CONSOLE is not set
-CONFIG_HW_CONSOLE=y
-# CONFIG_VT_HW_CONSOLE_BINDING is not set
-CONFIG_DEVKMEM=y
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=3
-CONFIG_SERIAL_8250_RUNTIME_UARTS=3
-# CONFIG_SERIAL_8250_EXTENDED is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
-CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_IPMI_HANDLER is not set
-CONFIG_HW_RANDOM=m
-# CONFIG_HW_RANDOM_TIMERIOMEM is not set
-# CONFIG_R3964 is not set
-# CONFIG_RAW_DRIVER is not set
-# CONFIG_TCG_TPM is not set
-CONFIG_I2C=y
-CONFIG_I2C_BOARDINFO=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_HELPER_AUTO=y
-
-#
-# I2C Hardware Bus support
-#
-
-#
-# I2C system bus drivers (mostly embedded / system-on-chip)
-#
-CONFIG_I2C_DAVINCI=y
-# CONFIG_I2C_GPIO is not set
-# CONFIG_I2C_OCORES is not set
-# CONFIG_I2C_SIMTEC is not set
-
-#
-# External I2C/SMBus adapter drivers
-#
-# CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_TAOS_EVM is not set
-
-#
-# Other I2C/SMBus bus drivers
-#
-# CONFIG_I2C_PCA_PLATFORM is not set
-# CONFIG_I2C_STUB is not set
-
-#
-# Miscellaneous I2C Chip support
-#
-# CONFIG_DS1682 is not set
-# CONFIG_SENSORS_PCA9539 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
-# CONFIG_SPI is not set
-CONFIG_ARCH_REQUIRE_GPIOLIB=y
-CONFIG_GPIOLIB=y
-# CONFIG_DEBUG_GPIO is not set
-# CONFIG_GPIO_SYSFS is not set
-
-#
-# Memory mapped GPIO expanders:
-#
-
-#
-# I2C GPIO expanders:
-#
-# CONFIG_GPIO_MAX732X is not set
-# CONFIG_GPIO_PCA953X is not set
-CONFIG_GPIO_PCF857X=m
-
-#
-# PCI GPIO expanders:
-#
-
-#
-# SPI GPIO expanders:
-#
-# CONFIG_W1 is not set
-# CONFIG_POWER_SUPPLY is not set
-# CONFIG_HWMON is not set
-# CONFIG_THERMAL is not set
-# CONFIG_THERMAL_HWMON is not set
-CONFIG_WATCHDOG=y
-# CONFIG_WATCHDOG_NOWAYOUT is not set
-
-#
-# Watchdog Device Drivers
-#
-# CONFIG_SOFT_WATCHDOG is not set
-# CONFIG_DAVINCI_WATCHDOG is not set
-CONFIG_SSB_POSSIBLE=y
-
-#
-# Sonics Silicon Backplane
-#
-# CONFIG_SSB is not set
-
-#
-# Multifunction device drivers
-#
-# CONFIG_MFD_CORE is not set
-# CONFIG_MFD_SM501 is not set
-# CONFIG_MFD_ASIC3 is not set
-# CONFIG_HTC_EGPIO is not set
-# CONFIG_HTC_PASIC3 is not set
-# CONFIG_TPS65010 is not set
-# CONFIG_TWL4030_CORE is not set
-# CONFIG_MFD_TMIO is not set
-# CONFIG_MFD_T7L66XB is not set
-# CONFIG_MFD_TC6387XB is not set
-# CONFIG_MFD_TC6393XB is not set
-# CONFIG_PMIC_DA903X is not set
-# CONFIG_MFD_WM8400 is not set
-# CONFIG_MFD_WM8350_I2C is not set
-# CONFIG_MFD_PCF50633 is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-# CONFIG_DAB is not set
-
-#
-# Graphics support
-#
-# CONFIG_VGASTATE is not set
-# CONFIG_VIDEO_OUTPUT_CONTROL is not set
-# CONFIG_FB is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
-
-#
-# Display device support
-#
-# CONFIG_DISPLAY_SUPPORT is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-CONFIG_SOUND=m
-# CONFIG_SOUND_OSS_CORE is not set
-CONFIG_SND=m
-CONFIG_SND_TIMER=m
-CONFIG_SND_PCM=m
-CONFIG_SND_JACK=y
-# CONFIG_SND_SEQUENCER is not set
-# CONFIG_SND_MIXER_OSS is not set
-# CONFIG_SND_PCM_OSS is not set
-# CONFIG_SND_HRTIMER 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
-CONFIG_SND_DRIVERS=y
-# 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
-CONFIG_SND_ARM=y
-CONFIG_SND_SOC=m
-CONFIG_SND_DAVINCI_SOC=m
-CONFIG_SND_SOC_I2C_AND_SPI=m
-# CONFIG_SND_SOC_ALL_CODECS is not set
-# CONFIG_SOUND_PRIME is not set
-# CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
-# CONFIG_USB_MUSB_HOST is not set
-# CONFIG_USB_MUSB_PERIPHERAL is not set
-# CONFIG_USB_MUSB_OTG is not set
-# CONFIG_USB_GADGET_MUSB_HDRC is not set
-# CONFIG_USB_GADGET_AT91 is not set
-# CONFIG_USB_GADGET_ATMEL_USBA is not set
-# CONFIG_USB_GADGET_FSL_USB2 is not set
-# CONFIG_USB_GADGET_LH7A40X is not set
-# CONFIG_USB_GADGET_OMAP is not set
-# CONFIG_USB_GADGET_PXA25X is not set
-# CONFIG_USB_GADGET_PXA27X is not set
-# CONFIG_USB_GADGET_S3C2410 is not set
-# CONFIG_USB_GADGET_IMX is not set
-# CONFIG_USB_GADGET_M66592 is not set
-# CONFIG_USB_GADGET_AMD5536UDC is not set
-# CONFIG_USB_GADGET_FSL_QE is not set
-# CONFIG_USB_GADGET_CI13XXX is not set
-# CONFIG_USB_GADGET_NET2280 is not set
-# CONFIG_USB_GADGET_GOKU is not set
-# CONFIG_USB_GADGET_DUMMY_HCD is not set
-# 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_USB_G_PRINTER is not set
-# CONFIG_USB_CDC_COMPOSITE is not set
-# CONFIG_MMC is not set
-# CONFIG_MEMSTICK is not set
-# CONFIG_ACCESSIBILITY is not set
-# CONFIG_NEW_LEDS is not set
-CONFIG_RTC_LIB=y
-# CONFIG_RTC_CLASS is not set
-# CONFIG_DMADEVICES is not set
-# CONFIG_AUXDISPLAY is not set
-# CONFIG_REGULATOR is not set
-# CONFIG_UIO is not set
-# CONFIG_STAGING 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_DEFAULTS_TO_ORDERED is not set
-CONFIG_EXT3_FS_XATTR=y
-# CONFIG_EXT3_FS_POSIX_ACL is not set
-# CONFIG_EXT3_FS_SECURITY is not set
-# CONFIG_EXT4_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_FILE_LOCKING=y
-CONFIG_XFS_FS=m
-# CONFIG_XFS_QUOTA is not set
-# CONFIG_XFS_POSIX_ACL is not set
-# CONFIG_XFS_RT is not set
-# CONFIG_XFS_DEBUG is not set
-# CONFIG_OCFS2_FS is not set
-# CONFIG_BTRFS_FS is not set
-CONFIG_DNOTIFY=y
-CONFIG_INOTIFY=y
-CONFIG_INOTIFY_USER=y
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-CONFIG_AUTOFS4_FS=m
-# CONFIG_FUSE_FS is not set
-
-#
-# Caches
-#
-# CONFIG_FSCACHE 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_SYSCTL=y
-CONFIG_PROC_PAGE_MONITOR=y
-CONFIG_SYSFS=y
-CONFIG_TMPFS=y
-# CONFIG_TMPFS_POSIX_ACL is not set
-# CONFIG_HUGETLB_PAGE is not set
-# CONFIG_CONFIGFS_FS is not set
-CONFIG_MISC_FILESYSTEMS=y
-# 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=y
-# CONFIG_SQUASHFS is not set
-# CONFIG_VXFS_FS is not set
-CONFIG_MINIX_FS=m
-# CONFIG_OMFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_NILFS2_FS is not set
-CONFIG_NETWORK_FILESYSTEMS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_NFS_V3_ACL is not set
-# CONFIG_NFS_V4 is not set
-CONFIG_ROOT_NFS=y
-CONFIG_NFSD=m
-CONFIG_NFSD_V3=y
-# CONFIG_NFSD_V3_ACL is not set
-# CONFIG_NFSD_V4 is not set
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-CONFIG_EXPORTFS=m
-CONFIG_NFS_COMMON=y
-CONFIG_SUNRPC=y
-# CONFIG_RPCSEC_GSS_KRB5 is not set
-# CONFIG_RPCSEC_GSS_SPKM3 is not set
-CONFIG_SMB_FS=m
-# CONFIG_SMB_NLS_DEFAULT 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
-CONFIG_NLS=y
-CONFIG_NLS_DEFAULT="iso8859-1"
-CONFIG_NLS_CODEPAGE_437=y
-# 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 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=m
-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=m
-# CONFIG_DLM is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_PRINTK_TIME is not set
-CONFIG_ENABLE_WARN_DEPRECATED=y
-CONFIG_ENABLE_MUST_CHECK=y
-CONFIG_FRAME_WARN=1024
-# CONFIG_MAGIC_SYSRQ is not set
-# 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_BOOTPARAM_SOFTLOCKUP_PANIC is not set
-CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
-CONFIG_DETECT_HUNG_TASK=y
-# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
-CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
-CONFIG_SCHED_DEBUG=y
-# CONFIG_SCHEDSTATS is not set
-CONFIG_TIMER_STATS=y
-# CONFIG_DEBUG_OBJECTS is not set
-# CONFIG_SLUB_DEBUG_ON is not set
-# CONFIG_SLUB_STATS is not set
-CONFIG_DEBUG_PREEMPT=y
-CONFIG_DEBUG_RT_MUTEXES=y
-CONFIG_DEBUG_PI_LIST=y
-# CONFIG_RT_MUTEX_TESTER is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-CONFIG_DEBUG_MUTEXES=y
-# 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 is not set
-CONFIG_DEBUG_BUGVERBOSE=y
-# CONFIG_DEBUG_INFO is not set
-# CONFIG_DEBUG_VM is not set
-# CONFIG_DEBUG_WRITECOUNT is not set
-# CONFIG_DEBUG_MEMORY_INIT is not set
-# CONFIG_DEBUG_LIST is not set
-# CONFIG_DEBUG_SG is not set
-# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
-# CONFIG_RCU_TORTURE_TEST is not set
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-# CONFIG_BACKTRACE_SELF_TEST is not set
-# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
-# CONFIG_FAULT_INJECTION is not set
-# CONFIG_LATENCYTOP is not set
-# CONFIG_SYSCTL_SYSCALL_CHECK is not set
-# CONFIG_PAGE_POISONING is not set
-CONFIG_HAVE_FUNCTION_TRACER=y
-CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
-# CONFIG_FUNCTION_TRACER is not set
-# CONFIG_IRQSOFF_TRACER is not set
-# CONFIG_PREEMPT_TRACER is not set
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
-# CONFIG_STACK_TRACER is not set
-# CONFIG_KMEMTRACE is not set
-# CONFIG_WORKQUEUE_TRACER is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_DYNAMIC_DEBUG is not set
-# CONFIG_SAMPLES is not set
-CONFIG_HAVE_ARCH_KGDB=y
-# CONFIG_KGDB is not set
-CONFIG_ARM_UNWIND=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_ERRORS=y
-# CONFIG_DEBUG_STACK_USAGE is not set
-# CONFIG_DEBUG_LL is not set
-
-#
-# Security options
-#
-# CONFIG_KEYS is not set
-# CONFIG_SECURITY is not set
-# CONFIG_SECURITYFS is not set
-# CONFIG_SECURITY_FILE_CAPABILITIES is not set
-CONFIG_CRYPTO=y
-
-#
-# Crypto core or helper
-#
-# CONFIG_CRYPTO_FIPS is not set
-# CONFIG_CRYPTO_MANAGER is not set
-# CONFIG_CRYPTO_MANAGER2 is not set
-# CONFIG_CRYPTO_GF128MUL is not set
-# CONFIG_CRYPTO_NULL is not set
-# CONFIG_CRYPTO_CRYPTD is not set
-# CONFIG_CRYPTO_AUTHENC is not set
-# CONFIG_CRYPTO_TEST is not set
-
-#
-# Authenticated Encryption with Associated Data
-#
-# CONFIG_CRYPTO_CCM is not set
-# CONFIG_CRYPTO_GCM is not set
-# CONFIG_CRYPTO_SEQIV is not set
-
-#
-# Block modes
-#
-# CONFIG_CRYPTO_CBC is not set
-# CONFIG_CRYPTO_CTR is not set
-# CONFIG_CRYPTO_CTS is not set
-# CONFIG_CRYPTO_ECB is not set
-# CONFIG_CRYPTO_LRW is not set
-# CONFIG_CRYPTO_PCBC is not set
-# CONFIG_CRYPTO_XTS is not set
-
-#
-# Hash modes
-#
-# CONFIG_CRYPTO_HMAC is not set
-# CONFIG_CRYPTO_XCBC is not set
-
-#
-# Digest
-#
-# CONFIG_CRYPTO_CRC32C is not set
-# CONFIG_CRYPTO_MD4 is not set
-# CONFIG_CRYPTO_MD5 is not set
-# CONFIG_CRYPTO_MICHAEL_MIC is not set
-# CONFIG_CRYPTO_RMD128 is not set
-# CONFIG_CRYPTO_RMD160 is not set
-# CONFIG_CRYPTO_RMD256 is not set
-# CONFIG_CRYPTO_RMD320 is not set
-# CONFIG_CRYPTO_SHA1 is not set
-# CONFIG_CRYPTO_SHA256 is not set
-# CONFIG_CRYPTO_SHA512 is not set
-# CONFIG_CRYPTO_TGR192 is not set
-# CONFIG_CRYPTO_WP512 is not set
-
-#
-# Ciphers
-#
-# CONFIG_CRYPTO_AES is not set
-# CONFIG_CRYPTO_ANUBIS is not set
-# CONFIG_CRYPTO_ARC4 is not set
-# CONFIG_CRYPTO_BLOWFISH is not set
-# CONFIG_CRYPTO_CAMELLIA is not set
-# CONFIG_CRYPTO_CAST5 is not set
-# CONFIG_CRYPTO_CAST6 is not set
-# CONFIG_CRYPTO_DES is not set
-# CONFIG_CRYPTO_FCRYPT is not set
-# CONFIG_CRYPTO_KHAZAD is not set
-# CONFIG_CRYPTO_SALSA20 is not set
-# CONFIG_CRYPTO_SEED is not set
-# CONFIG_CRYPTO_SERPENT is not set
-# CONFIG_CRYPTO_TEA is not set
-# CONFIG_CRYPTO_TWOFISH is not set
-
-#
-# Compression
-#
-# CONFIG_CRYPTO_DEFLATE is not set
-# CONFIG_CRYPTO_ZLIB is not set
-# CONFIG_CRYPTO_LZO is not set
-
-#
-# Random Number Generation
-#
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
-# CONFIG_CRYPTO_HW is not set
-# CONFIG_BINARY_PRINTF is not set
-
-#
-# Library routines
-#
-CONFIG_BITREVERSE=y
-CONFIG_GENERIC_FIND_LAST_BIT=y
-CONFIG_CRC_CCITT=m
-# CONFIG_CRC16 is not set
-CONFIG_CRC_T10DIF=m
-# 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_DECOMPRESS_GZIP=y
-CONFIG_GENERIC_ALLOCATOR=y
-CONFIG_HAS_IOMEM=y
-CONFIG_HAS_IOPORT=y
-CONFIG_HAS_DMA=y
-CONFIG_NLATTR=y
diff --git a/arch/arm/configs/da850_omapl138_defconfig b/arch/arm/configs/da8xx_omapl_defconfig
index 842a70b..50bd25a 100644
--- a/arch/arm/configs/da850_omapl138_defconfig
+++ b/arch/arm/configs/da8xx_omapl_defconfig
@@ -1,15 +1,13 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-davinci1
-# Mon Jun 29 07:54:15 2009
+# Linux kernel version: 2.6.32-rc5
+# Thu Oct 22 12:19:19 2009
#
CONFIG_ARM=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
CONFIG_GENERIC_GPIO=y
CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_CLOCKEVENTS=y
-CONFIG_MMU=y
-# CONFIG_NO_IOPORT is not set
CONFIG_GENERIC_HARDIRQS=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
@@ -18,14 +16,14 @@ CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_HARDIRQS_SW_RESEND=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_ARCH_HAS_ILOG2_U32 is not set
-# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_HAS_CPUFREQ=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_ZONE_DMA=y
CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
CONFIG_VECTORS_BASE=0xffff0000
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -48,11 +46,12 @@ CONFIG_POSIX_MQUEUE_SYSCTL=y
#
# RCU Subsystem
#
-CONFIG_CLASSIC_RCU=y
-# CONFIG_TREE_RCU is not set
-# CONFIG_PREEMPT_RCU is not set
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
# CONFIG_TREE_RCU_TRACE is not set
-# CONFIG_PREEMPT_RCU_TRACE is not set
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
@@ -62,8 +61,7 @@ CONFIG_FAIR_GROUP_SCHED=y
CONFIG_USER_SCHED=y
# CONFIG_CGROUP_SCHED is not set
# CONFIG_CGROUPS is not set
-CONFIG_SYSFS_DEPRECATED=y
-CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
# CONFIG_RELAY is not set
# CONFIG_NAMESPACES is not set
CONFIG_BLK_DEV_INITRD=y
@@ -80,7 +78,6 @@ CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -93,6 +90,10 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+
+#
+# Kernel Performance Events And Counters
+#
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_SLUB_DEBUG=y
CONFIG_COMPAT_BRK=y
@@ -100,12 +101,16 @@ CONFIG_COMPAT_BRK=y
CONFIG_SLUB=y
# CONFIG_SLOB is not set
# CONFIG_PROFILING is not set
-# CONFIG_MARKERS is not set
CONFIG_HAVE_OPROFILE=y
# CONFIG_KPROBES is not set
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
# CONFIG_SLOW_WORK is not set
CONFIG_HAVE_GENERIC_DMA_COHERENT=y
CONFIG_SLABINFO=y
@@ -118,7 +123,7 @@ CONFIG_MODULE_FORCE_UNLOAD=y
CONFIG_MODVERSIONS=y
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -139,19 +144,22 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
#
# System Type
#
+CONFIG_MMU=y
# CONFIG_ARCH_AAEC2000 is not set
# CONFIG_ARCH_INTEGRATOR is not set
# CONFIG_ARCH_REALVIEW is not set
# CONFIG_ARCH_VERSATILE is not set
# CONFIG_ARCH_AT91 is not set
# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_GEMINI is not set
# CONFIG_ARCH_EBSA110 is not set
# CONFIG_ARCH_EP93XX is not set
-# CONFIG_ARCH_GEMINI is not set
# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_STMP3XXX is not set
# CONFIG_ARCH_NETX is not set
# CONFIG_ARCH_H720X is not set
-# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_NOMADIK is not set
# CONFIG_ARCH_IOP13XX is not set
# CONFIG_ARCH_IOP32X is not set
# CONFIG_ARCH_IOP33X is not set
@@ -160,25 +168,27 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
# CONFIG_ARCH_IXP4XX is not set
# CONFIG_ARCH_L7200 is not set
# CONFIG_ARCH_KIRKWOOD is not set
-# CONFIG_ARCH_KS8695 is not set
-# CONFIG_ARCH_NS9XXX is not set
# CONFIG_ARCH_LOKI is not set
# CONFIG_ARCH_MV78XX0 is not set
-# CONFIG_ARCH_MXC is not set
# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_W90X900 is not set
# CONFIG_ARCH_PNX4008 is not set
# CONFIG_ARCH_PXA is not set
-# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_MSM is not set
# CONFIG_ARCH_RPC is not set
# CONFIG_ARCH_SA1100 is not set
# CONFIG_ARCH_S3C2410 is not set
# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5PC1XX is not set
# CONFIG_ARCH_SHARK is not set
# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
CONFIG_ARCH_DAVINCI=y
# CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_MSM is not set
-# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_BCMRING is not set
CONFIG_CP_INTC=y
#
@@ -191,7 +201,7 @@ CONFIG_CP_INTC=y
# CONFIG_ARCH_DAVINCI_DM644x is not set
# CONFIG_ARCH_DAVINCI_DM355 is not set
# CONFIG_ARCH_DAVINCI_DM646x is not set
-# CONFIG_ARCH_DAVINCI_DA830 is not set
+CONFIG_ARCH_DAVINCI_DA830=y
CONFIG_ARCH_DAVINCI_DA850=y
CONFIG_ARCH_DAVINCI_DA8XX=y
# CONFIG_ARCH_DAVINCI_DM365 is not set
@@ -199,7 +209,14 @@ CONFIG_ARCH_DAVINCI_DA8XX=y
#
# DaVinci Board Type
#
+CONFIG_MACH_DAVINCI_DA830_EVM=y
+CONFIG_DA830_UI=y
+CONFIG_DA830_UI_LCD=y
+# CONFIG_DA830_UI_NAND is not set
CONFIG_MACH_DAVINCI_DA850_EVM=y
+CONFIG_DA850_UI_EXP=y
+CONFIG_DA850_UI_NONE=y
+# CONFIG_DA850_UI_RMII is not set
CONFIG_DAVINCI_MUX=y
# CONFIG_DAVINCI_MUX_DEBUG is not set
# CONFIG_DAVINCI_MUX_WARNINGS is not set
@@ -212,7 +229,7 @@ CONFIG_CPU_32=y
CONFIG_CPU_ARM926T=y
CONFIG_CPU_32v5=y
CONFIG_CPU_ABRT_EV5TJ=y
-CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_PABRT_LEGACY=y
CONFIG_CPU_CACHE_VIVT=y
CONFIG_CPU_COPY_V4WB=y
CONFIG_CPU_TLB_V4WBI=y
@@ -225,9 +242,9 @@ CONFIG_CPU_CP15_MMU=y
CONFIG_ARM_THUMB=y
# CONFIG_CPU_ICACHE_DISABLE is not set
# CONFIG_CPU_DCACHE_DISABLE is not set
-# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+CONFIG_CPU_DCACHE_WRITETHROUGH=y
# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
-# CONFIG_OUTER_CACHE is not set
+CONFIG_ARM_L1_CACHE_SHIFT=5
CONFIG_COMMON_CLKDEV=y
#
@@ -248,11 +265,12 @@ CONFIG_VMSPLIT_3G=y
# CONFIG_VMSPLIT_2G is not set
# CONFIG_VMSPLIT_1G is not set
CONFIG_PAGE_OFFSET=0xC0000000
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
CONFIG_PREEMPT=y
CONFIG_HZ=100
CONFIG_AEABI=y
# CONFIG_OABI_COMPAT is not set
-# CONFIG_ARCH_HAS_HOLES_MEMORYMODEL is not set
# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
# CONFIG_HIGHMEM is not set
@@ -268,12 +286,14 @@ CONFIG_SPLIT_PTLOCK_CPUS=4096
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_LEDS=y
# CONFIG_LEDS_CPU is not set
CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
#
# Boot options
@@ -287,7 +307,24 @@ CONFIG_CMDLINE=""
#
# CPU Power Management
#
-# CONFIG_CPU_IDLE 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 is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=m
+CONFIG_CPU_FREQ_GOV_POWERSAVE=m
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=m
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_LADDER=y
+CONFIG_CPU_IDLE_GOV_MENU=y
#
# Floating point emulation
@@ -401,6 +438,7 @@ CONFIG_NETFILTER_ADVANCED=y
# CONFIG_IP6_NF_IPTABLES is not set
# CONFIG_IP_DCCP is not set
# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
# CONFIG_TIPC is not set
# CONFIG_ATM is not set
# CONFIG_BRIDGE is not set
@@ -415,6 +453,7 @@ CONFIG_NETFILTER_ADVANCED=y
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -440,6 +479,7 @@ CONFIG_NETFILTER_ADVANCED=y
# Generic Driver Options
#
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_FW_LOADER is not set
@@ -460,6 +500,7 @@ CONFIG_BLK_DEV_RAM_SIZE=32768
# CONFIG_BLK_DEV_XIP is not set
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MG_DISK is not set
CONFIG_MISC_DEVICES=y
# CONFIG_ICS932S401 is not set
# CONFIG_ENCLOSURE_SERVICES is not set
@@ -471,6 +512,7 @@ CONFIG_MISC_DEVICES=y
#
CONFIG_EEPROM_AT24=y
# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -494,10 +536,6 @@ CONFIG_BLK_DEV_SD=m
# 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
@@ -522,7 +560,6 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_ATA is not set
# CONFIG_MD is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -553,7 +590,7 @@ CONFIG_NET_ETHERNET=y
CONFIG_MII=y
# CONFIG_AX88796 is not set
# CONFIG_SMC91X is not set
-# CONFIG_TI_DAVINCI_EMAC is not set
+CONFIG_TI_DAVINCI_EMAC=y
# CONFIG_DM9000 is not set
# CONFIG_ETHOC is not set
# CONFIG_SMC911X is not set
@@ -567,12 +604,11 @@ CONFIG_MII=y
# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851_MLL is not set
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
-
-#
-# Wireless LAN
-#
+CONFIG_WLAN=y
# CONFIG_WLAN_PRE80211 is not set
# CONFIG_WLAN_80211 is not set
@@ -588,6 +624,7 @@ CONFIG_NETPOLL=y
CONFIG_NETPOLL_TRAP=y
CONFIG_NET_POLL_CONTROLLER=y
# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
#
# Input device support
@@ -611,23 +648,30 @@ CONFIG_INPUT_EVBUG=m
# Input Device Drivers
#
CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ADP5588 is not set
CONFIG_KEYBOARD_ATKBD=m
-# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_QT2160 is not set
# CONFIG_KEYBOARD_LKKBD is not set
-CONFIG_KEYBOARD_XTKBD=m
+CONFIG_KEYBOARD_GPIO=y
+# CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
# CONFIG_KEYBOARD_STOWAWAY is not set
-CONFIG_KEYBOARD_GPIO=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+CONFIG_KEYBOARD_XTKBD=m
# CONFIG_INPUT_MOUSE is not set
# CONFIG_INPUT_JOYSTICK is not set
# CONFIG_INPUT_TABLET is not set
CONFIG_INPUT_TOUCHSCREEN=y
# CONFIG_TOUCHSCREEN_AD7879_I2C is not set
# CONFIG_TOUCHSCREEN_AD7879 is not set
+# CONFIG_TOUCHSCREEN_EETI is not set
# CONFIG_TOUCHSCREEN_FUJITSU is not set
# CONFIG_TOUCHSCREEN_GUNZE is not set
# CONFIG_TOUCHSCREEN_ELO is not set
# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_MCS5000 is not set
# CONFIG_TOUCHSCREEN_MTOUCH is not set
# CONFIG_TOUCHSCREEN_INEXIO is not set
# CONFIG_TOUCHSCREEN_MK712 is not set
@@ -636,6 +680,7 @@ CONFIG_INPUT_TOUCHSCREEN=y
# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
# CONFIG_TOUCHSCREEN_TSC2007 is not set
+# CONFIG_TOUCHSCREEN_W90X900 is not set
# CONFIG_INPUT_MISC is not set
#
@@ -684,6 +729,7 @@ CONFIG_HW_RANDOM=m
# CONFIG_TCG_TPM is not set
CONFIG_I2C=y
CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_HELPER_AUTO=y
@@ -695,6 +741,7 @@ CONFIG_I2C_HELPER_AUTO=y
# I2C system bus drivers (mostly embedded / system-on-chip)
#
CONFIG_I2C_DAVINCI=y
+# CONFIG_I2C_DESIGNWARE is not set
# CONFIG_I2C_GPIO is not set
# CONFIG_I2C_OCORES is not set
# CONFIG_I2C_SIMTEC is not set
@@ -715,14 +762,17 @@ CONFIG_I2C_DAVINCI=y
# Miscellaneous I2C Chip support
#
# CONFIG_DS1682 is not set
-# CONFIG_SENSORS_PCA9539 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
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_REQUIRE_GPIOLIB=y
CONFIG_GPIOLIB=y
# CONFIG_DEBUG_GPIO is not set
@@ -736,8 +786,8 @@ CONFIG_GPIOLIB=y
# I2C GPIO expanders:
#
# CONFIG_GPIO_MAX732X is not set
-# CONFIG_GPIO_PCA953X is not set
-CONFIG_GPIO_PCF857X=m
+CONFIG_GPIO_PCA953X=y
+CONFIG_GPIO_PCF857X=y
#
# PCI GPIO expanders:
@@ -746,11 +796,14 @@ CONFIG_GPIO_PCF857X=m
#
# SPI GPIO expanders:
#
+
+#
+# AC97 GPIO expanders:
+#
# CONFIG_W1 is not set
# CONFIG_POWER_SUPPLY is not set
# CONFIG_HWMON is not set
# CONFIG_THERMAL is not set
-# CONFIG_THERMAL_HWMON is not set
CONFIG_WATCHDOG=y
# CONFIG_WATCHDOG_NOWAYOUT is not set
@@ -782,31 +835,56 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_TC6393XB is not set
# CONFIG_PMIC_DA903X is not set
# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-# CONFIG_DAB is not set
+# CONFIG_AB3100_CORE is not set
+CONFIG_REGULATOR=y
+# CONFIG_REGULATOR_DEBUG is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_REGULATOR_MAX1586 is not set
+# CONFIG_REGULATOR_LP3971 is not set
+# CONFIG_REGULATOR_TPS65023 is not set
+CONFIG_REGULATOR_TPS6507X=y
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
#
# CONFIG_VGASTATE is not set
# CONFIG_VIDEO_OUTPUT_CONTROL is not set
-# CONFIG_FB is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE 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_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# 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_S1D13XXX is not set
+# CONFIG_FB_DAVINCI is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FB_DA8XX=y
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
@@ -819,6 +897,16 @@ CONFIG_SSB_POSSIBLE=y
#
# CONFIG_VGA_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 is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
CONFIG_SOUND=m
# CONFIG_SOUND_OSS_CORE is not set
CONFIG_SND=m
@@ -834,6 +922,11 @@ CONFIG_SND_SUPPORT_OLD_API=y
CONFIG_SND_VERBOSE_PROCFS=y
# CONFIG_SND_VERBOSE_PRINTK is not set
# CONFIG_SND_DEBUG is not set
+# CONFIG_SND_RAWMIDI_SEQ is not set
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+# CONFIG_SND_EMU10K1_SEQ is not set
CONFIG_SND_DRIVERS=y
# CONFIG_SND_DUMMY is not set
# CONFIG_SND_MTPAV is not set
@@ -842,6 +935,8 @@ CONFIG_SND_DRIVERS=y
CONFIG_SND_ARM=y
CONFIG_SND_SOC=m
CONFIG_SND_DAVINCI_SOC=m
+# CONFIG_SND_DA830_SOC_EVM is not set
+# CONFIG_SND_DA850_SOC_EVM is not set
CONFIG_SND_SOC_I2C_AND_SPI=m
# CONFIG_SND_SOC_ALL_CODECS is not set
# CONFIG_SOUND_PRIME is not set
@@ -849,14 +944,17 @@ CONFIG_SND_SOC_I2C_AND_SPI=m
# CONFIG_USB_SUPPORT is not set
# CONFIG_MMC is not set
# CONFIG_MEMSTICK is not set
-# CONFIG_ACCESSIBILITY is not set
# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
CONFIG_RTC_LIB=y
# CONFIG_RTC_CLASS is not set
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
-# CONFIG_REGULATOR is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -877,14 +975,17 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
CONFIG_XFS_FS=m
# CONFIG_XFS_QUOTA is not set
# CONFIG_XFS_POSIX_ACL is not set
# CONFIG_XFS_RT is not set
# CONFIG_XFS_DEBUG is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -943,7 +1044,6 @@ CONFIG_MINIX_FS=m
# CONFIG_ROMFS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_UFS_FS is not set
-# CONFIG_NILFS2_FS is not set
CONFIG_NETWORK_FILESYSTEMS=y
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
@@ -1039,6 +1139,7 @@ CONFIG_ENABLE_WARN_DEPRECATED=y
CONFIG_ENABLE_MUST_CHECK=y
CONFIG_FRAME_WARN=1024
# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
# CONFIG_UNUSED_SYMBOLS is not set
CONFIG_DEBUG_FS=y
# CONFIG_HEADERS_CHECK is not set
@@ -1056,6 +1157,7 @@ CONFIG_TIMER_STATS=y
# CONFIG_DEBUG_OBJECTS is not set
# CONFIG_SLUB_DEBUG_ON is not set
# CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
CONFIG_DEBUG_PREEMPT=y
CONFIG_DEBUG_RT_MUTEXES=y
CONFIG_DEBUG_PI_LIST=y
@@ -1076,29 +1178,29 @@ CONFIG_DEBUG_BUGVERBOSE=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
# CONFIG_FAULT_INJECTION is not set
# CONFIG_LATENCYTOP is not set
# CONFIG_SYSCTL_SYSCALL_CHECK is not set
# CONFIG_PAGE_POISONING is not set
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
# CONFIG_FUNCTION_TRACER is not set
# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_PREEMPT_TRACER is not set
# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
# CONFIG_STACK_TRACER is not set
# CONFIG_KMEMTRACE is not set
# CONFIG_WORKQUEUE_TRACER is not set
@@ -1125,7 +1227,6 @@ CONFIG_CRYPTO=y
#
# Crypto core or helper
#
-# CONFIG_CRYPTO_FIPS is not set
# CONFIG_CRYPTO_MANAGER is not set
# CONFIG_CRYPTO_MANAGER2 is not set
# CONFIG_CRYPTO_GF128MUL is not set
@@ -1157,11 +1258,13 @@ CONFIG_CRYPTO=y
#
# CONFIG_CRYPTO_HMAC is not set
# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
#
# Digest
#
# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
# CONFIG_CRYPTO_MD4 is not set
# CONFIG_CRYPTO_MD5 is not set
# CONFIG_CRYPTO_MICHAEL_MIC is not set
diff --git a/arch/arm/configs/davinci_all_defconfig b/arch/arm/configs/davinci_all_defconfig
index ddffe39..bd656e8 100644
--- a/arch/arm/configs/davinci_all_defconfig
+++ b/arch/arm/configs/davinci_all_defconfig
@@ -1,14 +1,13 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.31-rc3-davinci1
-# Fri Jul 17 08:26:52 2009
+# Linux kernel version: 2.6.32-rc4
+# Mon Oct 12 14:13:12 2009
#
CONFIG_ARM=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
CONFIG_GENERIC_GPIO=y
CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_CLOCKEVENTS=y
-CONFIG_MMU=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
@@ -46,11 +45,12 @@ CONFIG_POSIX_MQUEUE_SYSCTL=y
#
# RCU Subsystem
#
-CONFIG_CLASSIC_RCU=y
-# CONFIG_TREE_RCU is not set
-# CONFIG_PREEMPT_RCU is not set
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
# CONFIG_TREE_RCU_TRACE is not set
-# CONFIG_PREEMPT_RCU_TRACE is not set
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
@@ -91,17 +91,15 @@ CONFIG_SHMEM=y
CONFIG_AIO=y
#
-# Performance Counters
+# Kernel Performance Events And Counters
#
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_SLUB_DEBUG=y
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
# CONFIG_SLOB is not set
# CONFIG_PROFILING is not set
-# CONFIG_MARKERS is not set
CONFIG_HAVE_OPROFILE=y
# CONFIG_KPROBES is not set
CONFIG_HAVE_KPROBES=y
@@ -145,6 +143,7 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
#
# System Type
#
+CONFIG_MMU=y
# CONFIG_ARCH_AAEC2000 is not set
# CONFIG_ARCH_INTEGRATOR is not set
# CONFIG_ARCH_REALVIEW is not set
@@ -159,6 +158,7 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
# CONFIG_ARCH_STMP3XXX is not set
# CONFIG_ARCH_NETX is not set
# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_NOMADIK is not set
# CONFIG_ARCH_IOP13XX is not set
# CONFIG_ARCH_IOP32X is not set
# CONFIG_ARCH_IOP33X is not set
@@ -181,11 +181,13 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
# CONFIG_ARCH_SA1100 is not set
# CONFIG_ARCH_S3C2410 is not set
# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5PC1XX is not set
# CONFIG_ARCH_SHARK is not set
# CONFIG_ARCH_LH7A40X is not set
# CONFIG_ARCH_U300 is not set
CONFIG_ARCH_DAVINCI=y
# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_BCMRING is not set
CONFIG_AINTC=y
CONFIG_ARCH_DAVINCI_DMx=y
@@ -208,6 +210,7 @@ CONFIG_ARCH_DAVINCI_DM365=y
#
CONFIG_MACH_DAVINCI_EVM=y
CONFIG_MACH_SFFSDR=y
+CONFIG_MACH_NEUROS_OSD2=y
CONFIG_MACH_DAVINCI_DM355_EVM=y
CONFIG_MACH_DM355_LEOPARD=y
CONFIG_MACH_DAVINCI_DM6467_EVM=y
@@ -224,7 +227,7 @@ CONFIG_CPU_32=y
CONFIG_CPU_ARM926T=y
CONFIG_CPU_32v5=y
CONFIG_CPU_ABRT_EV5TJ=y
-CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_PABRT_LEGACY=y
CONFIG_CPU_CACHE_VIVT=y
CONFIG_CPU_COPY_V4WB=y
CONFIG_CPU_TLB_V4WBI=y
@@ -239,6 +242,7 @@ CONFIG_ARM_THUMB=y
# CONFIG_CPU_DCACHE_DISABLE is not set
# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+CONFIG_ARM_L1_CACHE_SHIFT=5
CONFIG_COMMON_CLKDEV=y
#
@@ -259,6 +263,8 @@ CONFIG_VMSPLIT_3G=y
# CONFIG_VMSPLIT_2G is not set
# CONFIG_VMSPLIT_1G is not set
CONFIG_PAGE_OFFSET=0xC0000000
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
CONFIG_PREEMPT=y
CONFIG_HZ=100
CONFIG_AEABI=y
@@ -280,6 +286,7 @@ CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+# CONFIG_KSM is not set
CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_LEDS=y
# CONFIG_LEDS_CPU is not set
@@ -412,6 +419,7 @@ CONFIG_NETFILTER_ADVANCED=y
# CONFIG_IP6_NF_IPTABLES is not set
# CONFIG_IP_DCCP is not set
# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
# CONFIG_TIPC is not set
# CONFIG_ATM is not set
# CONFIG_BRIDGE is not set
@@ -452,6 +460,7 @@ CONFIG_NETFILTER_ADVANCED=y
# Generic Driver Options
#
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_FW_LOADER is not set
@@ -461,9 +470,9 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_CONNECTOR is not set
CONFIG_MTD=m
# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
# CONFIG_MTD_CONCAT is not set
CONFIG_MTD_PARTITIONS=y
-# CONFIG_MTD_TESTS is not set
# CONFIG_MTD_REDBOOT_PARTS is not set
# CONFIG_MTD_AFS_PARTS is not set
# CONFIG_MTD_AR7_PARTS is not set
@@ -499,7 +508,7 @@ 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_INTELEXT=m
CONFIG_MTD_CFI_AMDSTD=m
# CONFIG_MTD_CFI_STAA is not set
CONFIG_MTD_CFI_UTIL=m
@@ -694,12 +703,10 @@ CONFIG_DM9000_DEBUGLEVEL=4
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_B44 is not set
# CONFIG_KS8842 is not set
+# CONFIG_KS8851_MLL is not set
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
-
-#
-# Wireless LAN
-#
+CONFIG_WLAN=y
# CONFIG_WLAN_PRE80211 is not set
# CONFIG_WLAN_80211 is not set
@@ -734,6 +741,7 @@ CONFIG_NETPOLL=y
CONFIG_NETPOLL_TRAP=y
CONFIG_NET_POLL_CONTROLLER=y
# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
#
# Input device support
@@ -745,10 +753,7 @@ CONFIG_INPUT=y
#
# Userland interfaces
#
-CONFIG_INPUT_MOUSEDEV=m
-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_EVDEV=m
CONFIG_INPUT_EVBUG=m
@@ -757,12 +762,16 @@ CONFIG_INPUT_EVBUG=m
# Input Device Drivers
#
CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ADP5588 is not set
CONFIG_KEYBOARD_ATKBD=m
+# CONFIG_QT2160 is not set
# CONFIG_KEYBOARD_LKKBD is not set
CONFIG_KEYBOARD_GPIO=y
# CONFIG_KEYBOARD_MATRIX is not set
# CONFIG_KEYBOARD_LM8323 is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
# CONFIG_KEYBOARD_STOWAWAY is not set
# CONFIG_KEYBOARD_SUNKBD is not set
CONFIG_KEYBOARD_XTKBD=m
@@ -777,6 +786,7 @@ CONFIG_INPUT_TOUCHSCREEN=y
# CONFIG_TOUCHSCREEN_GUNZE is not set
# CONFIG_TOUCHSCREEN_ELO is not set
# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_MCS5000 is not set
# CONFIG_TOUCHSCREEN_MTOUCH is not set
# CONFIG_TOUCHSCREEN_INEXIO is not set
# CONFIG_TOUCHSCREEN_MK712 is not set
@@ -787,7 +797,17 @@ CONFIG_INPUT_TOUCHSCREEN=y
# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
# CONFIG_TOUCHSCREEN_TSC2007 is not set
# CONFIG_TOUCHSCREEN_W90X900 is not set
-# CONFIG_INPUT_MISC is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_ATI_REMOTE is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_YEALINK is not set
+# CONFIG_INPUT_CM109 is not set
+# CONFIG_INPUT_UINPUT is not set
+# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
+CONFIG_INPUT_DM355EVM=m
+CONFIG_INPUT_DM365EVM=m
#
# Hardware I/O ports
@@ -828,13 +848,13 @@ CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
# CONFIG_IPMI_HANDLER is not set
-CONFIG_HW_RANDOM=m
-# CONFIG_HW_RANDOM_TIMERIOMEM 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=y
CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_HELPER_AUTO=y
@@ -868,13 +888,17 @@ CONFIG_I2C_DAVINCI=y
# Miscellaneous I2C Chip support
#
# CONFIG_DS1682 is not set
-# CONFIG_SENSORS_PCA9539 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
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_REQUIRE_GPIOLIB=y
CONFIG_GPIOLIB=y
# CONFIG_DEBUG_GPIO is not set
@@ -889,7 +913,7 @@ CONFIG_GPIOLIB=y
#
# CONFIG_GPIO_MAX732X is not set
# CONFIG_GPIO_PCA953X is not set
-CONFIG_GPIO_PCF857X=m
+CONFIG_GPIO_PCF857X=y
#
# PCI GPIO expanders:
@@ -898,10 +922,19 @@ CONFIG_GPIO_PCF857X=m
#
# SPI GPIO expanders:
#
+
+#
+# AC97 GPIO expanders:
+#
# CONFIG_W1 is not set
# CONFIG_POWER_SUPPLY is not set
CONFIG_HWMON=y
# CONFIG_HWMON_VID is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Native drivers
+#
# CONFIG_SENSORS_AD7414 is not set
# CONFIG_SENSORS_AD7418 is not set
# CONFIG_SENSORS_ADM1021 is not set
@@ -950,6 +983,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_ADS7828 is not set
# CONFIG_SENSORS_THMC50 is not set
# CONFIG_SENSORS_TMP401 is not set
+# CONFIG_SENSORS_TMP421 is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_W83781D is not set
# CONFIG_SENSORS_W83791D is not set
@@ -959,9 +993,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_W83L786NG is not set
# CONFIG_SENSORS_W83627HF is not set
# CONFIG_SENSORS_W83627EHF is not set
-# CONFIG_HWMON_DEBUG_CHIP is not set
# CONFIG_THERMAL is not set
-# CONFIG_THERMAL_HWMON is not set
CONFIG_WATCHDOG=y
# CONFIG_WATCHDOG_NOWAYOUT is not set
@@ -988,7 +1020,7 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_CORE is not set
# CONFIG_MFD_SM501 is not set
# CONFIG_MFD_ASIC3 is not set
-# CONFIG_MFD_DM355EVM_MSP is not set
+CONFIG_MFD_DM355EVM_MSP=y
# CONFIG_HTC_EGPIO is not set
# CONFIG_HTC_PASIC3 is not set
# CONFIG_TPS65010 is not set
@@ -999,9 +1031,11 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_TC6393XB is not set
# CONFIG_PMIC_DA903X is not set
# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
# CONFIG_AB3100_CORE is not set
+# CONFIG_REGULATOR is not set
# CONFIG_MEDIA_SUPPORT is not set
#
@@ -1013,9 +1047,9 @@ CONFIG_FB=y
CONFIG_FIRMWARE_EDID=y
# CONFIG_FB_DDC is not set
# CONFIG_FB_BOOT_VESA_SUPPORT 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_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
# CONFIG_FB_SYS_FILLRECT is not set
# CONFIG_FB_SYS_COPYAREA is not set
@@ -1032,6 +1066,7 @@ CONFIG_FIRMWARE_EDID=y
# Frame buffer hardware drivers
#
# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_DAVINCI=y
# CONFIG_FB_VIRTUAL is not set
# CONFIG_FB_METRONOME is not set
# CONFIG_FB_MB862XX is not set
@@ -1101,7 +1136,6 @@ CONFIG_SND_SOC_TLV320AIC3X=m
# CONFIG_SOUND_PRIME is not set
CONFIG_HID_SUPPORT=y
CONFIG_HID=m
-# CONFIG_HID_DEBUG is not set
# CONFIG_HIDRAW is not set
#
@@ -1130,6 +1164,7 @@ CONFIG_HID_CYPRESS=m
CONFIG_HID_EZKEY=m
# CONFIG_HID_KYE is not set
CONFIG_HID_GYRATION=m
+# CONFIG_HID_TWINHAN is not set
# CONFIG_HID_KENSINGTON is not set
CONFIG_HID_LOGITECH=m
# CONFIG_LOGITECH_FF is not set
@@ -1176,6 +1211,7 @@ CONFIG_USB_MON=m
# CONFIG_USB_OXU210HP_HCD is not set
# CONFIG_USB_ISP116X_HCD is not set
# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
# CONFIG_USB_SL811_HCD is not set
# CONFIG_USB_R8A66597_HCD is not set
# CONFIG_USB_HWA_HCD is not set
@@ -1269,6 +1305,7 @@ CONFIG_USB_GADGET_SELECTED=y
# CONFIG_USB_GADGET_LH7A40X is not set
# CONFIG_USB_GADGET_OMAP is not set
# CONFIG_USB_GADGET_PXA25X is not set
+# CONFIG_USB_GADGET_R8A66597 is not set
# CONFIG_USB_GADGET_PXA27X is not set
# CONFIG_USB_GADGET_S3C_HSOTG is not set
# CONFIG_USB_GADGET_IMX is not set
@@ -1286,6 +1323,7 @@ CONFIG_USB_ZERO=m
# CONFIG_USB_AUDIO is not set
CONFIG_USB_ETH=m
CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_ETH_EEM is not set
CONFIG_USB_GADGETFS=m
CONFIG_USB_FILE_STORAGE=m
# CONFIG_USB_FILE_STORAGE_TEST is not set
@@ -1316,8 +1354,10 @@ CONFIG_MMC_BLOCK=m
# MMC/SD/SDIO Host Controller Drivers
#
# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_AT91 is not set
+# CONFIG_MMC_ATMELMCI is not set
+CONFIG_MMC_DAVINCI=m
# CONFIG_MEMSTICK is not set
-# CONFIG_ACCESSIBILITY is not set
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=m
@@ -1345,6 +1385,7 @@ CONFIG_LEDS_TRIGGER_HEARTBEAT=m
#
# iptables trigger is under Netfilter config (LED target)
#
+# CONFIG_ACCESSIBILITY is not set
CONFIG_RTC_LIB=y
CONFIG_RTC_CLASS=m
@@ -1370,6 +1411,7 @@ CONFIG_RTC_INTF_DEV=y
# CONFIG_RTC_DRV_PCF8563 is not set
# CONFIG_RTC_DRV_PCF8583 is not set
# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_DM355EVM is not set
# CONFIG_RTC_DRV_S35390A is not set
# CONFIG_RTC_DRV_FM3130 is not set
# CONFIG_RTC_DRV_RX8581 is not set
@@ -1399,8 +1441,11 @@ CONFIG_RTC_INTF_DEV=y
#
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
-# CONFIG_REGULATOR is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -1429,6 +1474,7 @@ CONFIG_XFS_FS=m
# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
CONFIG_FILE_LOCKING=y
CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
@@ -1500,7 +1546,6 @@ CONFIG_MINIX_FS=m
# CONFIG_ROMFS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_UFS_FS is not set
-# CONFIG_NILFS2_FS is not set
CONFIG_NETWORK_FILESYSTEMS=y
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
@@ -1596,6 +1641,7 @@ CONFIG_ENABLE_WARN_DEPRECATED=y
CONFIG_ENABLE_MUST_CHECK=y
CONFIG_FRAME_WARN=1024
# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
# CONFIG_UNUSED_SYMBOLS is not set
CONFIG_DEBUG_FS=y
# CONFIG_HEADERS_CHECK is not set
@@ -1634,11 +1680,14 @@ CONFIG_DEBUG_BUGVERBOSE=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+CONFIG_FRAME_POINTER=y
# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
# CONFIG_FAULT_INJECTION is not set
# CONFIG_LATENCYTOP is not set
# CONFIG_SYSCTL_SYSCALL_CHECK is not set
@@ -1663,7 +1712,7 @@ CONFIG_BRANCH_PROFILE_NONE=y
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
-CONFIG_ARM_UNWIND=y
+# CONFIG_ARM_UNWIND is not set
CONFIG_DEBUG_USER=y
CONFIG_DEBUG_ERRORS=y
# CONFIG_DEBUG_STACK_USAGE is not set
@@ -1681,7 +1730,6 @@ CONFIG_CRYPTO=y
#
# Crypto core or helper
#
-# CONFIG_CRYPTO_FIPS is not set
# CONFIG_CRYPTO_MANAGER is not set
# CONFIG_CRYPTO_MANAGER2 is not set
# CONFIG_CRYPTO_GF128MUL is not set
@@ -1713,11 +1761,13 @@ CONFIG_CRYPTO=y
#
# CONFIG_CRYPTO_HMAC is not set
# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
#
# Digest
#
# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
# CONFIG_CRYPTO_MD4 is not set
# CONFIG_CRYPTO_MD5 is not set
# CONFIG_CRYPTO_MICHAEL_MIC is not set
diff --git a/arch/arm/mach-bcmring/include/csp/reg.h b/arch/arm/mach-bcmring/include/csp/reg.h
index e5f60bf..56654d2 100644
--- a/arch/arm/mach-bcmring/include/csp/reg.h
+++ b/arch/arm/mach-bcmring/include/csp/reg.h
@@ -16,7 +16,7 @@
/**
* @file reg.h
*
-* @brief Generic register defintions used in CSP
+* @brief Generic register definitions used in CSP
*/
/****************************************************************************/
diff --git a/arch/arm/mach-bcmring/include/mach/csp/dmacHw_priv.h b/arch/arm/mach-bcmring/include/mach/csp/dmacHw_priv.h
index 375066a..cbf334d 100644
--- a/arch/arm/mach-bcmring/include/mach/csp/dmacHw_priv.h
+++ b/arch/arm/mach-bcmring/include/mach/csp/dmacHw_priv.h
@@ -83,7 +83,7 @@ typedef struct {
* @brief Get next available transaction width
*
*
-* @return On sucess : Next avail able transaction width
+* @return On success : Next available transaction width
* On failure : dmacHw_TRANSACTION_WIDTH_8
*
* @note
diff --git a/arch/arm/mach-bcmring/include/mach/csp/mm_addr.h b/arch/arm/mach-bcmring/include/mach/csp/mm_addr.h
index 86bb58d..ad58cf8 100644
--- a/arch/arm/mach-bcmring/include/mach/csp/mm_addr.h
+++ b/arch/arm/mach-bcmring/include/mach/csp/mm_addr.h
@@ -16,7 +16,7 @@
/**
* @file mm_addr.h
*
-* @brief Memory Map address defintions
+* @brief Memory Map address definitions
*
* @note
* None
diff --git a/arch/arm/mach-bcmring/include/mach/dma.h b/arch/arm/mach-bcmring/include/mach/dma.h
index 847980c..1f2c531 100644
--- a/arch/arm/mach-bcmring/include/mach/dma.h
+++ b/arch/arm/mach-bcmring/include/mach/dma.h
@@ -651,7 +651,7 @@ int dma_map_add_region(DMA_MemMap_t *memMap, /* Stores state information about t
/**
* Creates a descriptor ring from a memory mapping.
*
-* @return 0 on sucess, error code otherwise.
+* @return 0 on success, error code otherwise.
*/
/****************************************************************************/
diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig
index 40866c6..033bfed 100644
--- a/arch/arm/mach-davinci/Kconfig
+++ b/arch/arm/mach-davinci/Kconfig
@@ -32,11 +32,13 @@ config ARCH_DAVINCI_DA830
bool "DA830/OMAP-L137 based system"
select CP_INTC
select ARCH_DAVINCI_DA8XX
+ select CPU_DCACHE_WRITETHROUGH # needed on silicon revs 1.0, 1.1
config ARCH_DAVINCI_DA850
bool "DA850/OMAP-L138 based system"
select CP_INTC
select ARCH_DAVINCI_DA8XX
+ select ARCH_HAS_CPUFREQ
config ARCH_DAVINCI_DA8XX
bool
@@ -63,6 +65,13 @@ config MACH_SFFSDR
Say Y here to select the Lyrtech Small Form Factor
Software Defined Radio (SFFSDR) board.
+config MACH_NEUROS_OSD2
+ bool "Neuros OSD2 Open Television Set Top Box"
+ depends on ARCH_DAVINCI_DM644x
+ help
+ Configure this option to specify the whether the board used
+ for development is a Neuros OSD2 Open Set Top Box.
+
config MACH_DAVINCI_DM355_EVM
bool "TI DM355 EVM"
default ARCH_DAVINCI_DM355
@@ -98,16 +107,66 @@ config MACH_DAVINCI_DA830_EVM
bool "TI DA830/OMAP-L137 Reference Platform"
default ARCH_DAVINCI_DA830
depends on ARCH_DAVINCI_DA830
+ select GPIO_PCF857X
help
Say Y here to select the TI DA830/OMAP-L137 Evaluation Module.
+choice
+ prompt "Select DA830/OMAP-L137 UI board peripheral"
+ depends on MACH_DAVINCI_DA830_EVM
+ help
+ The presence of UI card on the DA830/OMAP-L137 EVM is detected
+ automatically based on successful probe of the I2C based GPIO
+ expander on that board. This option selected in this menu has
+ an effect only in case of a successful UI card detection.
+
+config DA830_UI_LCD
+ bool "LCD"
+ help
+ Say Y here to use the LCD as a framebuffer or simple character
+ display.
+
+config DA830_UI_NAND
+ bool "NAND flash"
+ help
+ Say Y here to use the NAND flash. Do not forget to setup
+ the switch correctly.
+endchoice
+
config MACH_DAVINCI_DA850_EVM
bool "TI DA850/OMAP-L138 Reference Platform"
default ARCH_DAVINCI_DA850
depends on ARCH_DAVINCI_DA850
+ select GPIO_PCA953X
help
Say Y here to select the TI DA850/OMAP-L138 Evaluation Module.
+choice
+ prompt "Select peripherals connected to expander on UI board"
+ depends on MACH_DAVINCI_DA850_EVM
+ help
+ The presence of User Interface (UI) card on the DA850/OMAP-L138
+ EVM is detected automatically based on successful probe of the I2C
+ based GPIO expander on that card. This option selected in this
+ menu has an effect only in case of a successful UI card detection.
+
+config DA850_UI_NONE
+ bool "No peripheral is enabled"
+ help
+ Say Y if you do not want to enable any of the peripherals connected
+ to TCA6416 expander on DA850/OMAP-L138 EVM UI card
+
+config DA850_UI_RMII
+ bool "RMII Ethernet PHY"
+ help
+ Say Y if you want to use the RMII PHY on the DA850/OMAP-L138 EVM.
+ This PHY is found on the UI daughter card that is supplied with
+ the EVM.
+ NOTE: Please take care while choosing this option, MII PHY will
+ not be functional if RMII mode is selected.
+
+endchoice
+
config DAVINCI_MUX
bool "DAVINCI multiplexing support"
depends on ARCH_DAVINCI
diff --git a/arch/arm/mach-davinci/Makefile b/arch/arm/mach-davinci/Makefile
index 2e11e84..eeb9230 100644
--- a/arch/arm/mach-davinci/Makefile
+++ b/arch/arm/mach-davinci/Makefile
@@ -23,9 +23,14 @@ obj-$(CONFIG_CP_INTC) += cp_intc.o
# Board specific
obj-$(CONFIG_MACH_DAVINCI_EVM) += board-dm644x-evm.o
obj-$(CONFIG_MACH_SFFSDR) += board-sffsdr.o
+obj-$(CONFIG_MACH_NEUROS_OSD2) += board-neuros-osd2.o
obj-$(CONFIG_MACH_DAVINCI_DM355_EVM) += board-dm355-evm.o
obj-$(CONFIG_MACH_DM355_LEOPARD) += board-dm355-leopard.o
obj-$(CONFIG_MACH_DAVINCI_DM6467_EVM) += board-dm646x-evm.o
obj-$(CONFIG_MACH_DAVINCI_DM365_EVM) += board-dm365-evm.o
obj-$(CONFIG_MACH_DAVINCI_DA830_EVM) += board-da830-evm.o
obj-$(CONFIG_MACH_DAVINCI_DA850_EVM) += board-da850-evm.o
+
+# Power Management
+obj-$(CONFIG_CPU_FREQ) += cpufreq.o
+obj-$(CONFIG_CPU_IDLE) += cpuidle.o
diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c
index bfbb639..31dc990 100644
--- a/arch/arm/mach-davinci/board-da830-evm.c
+++ b/arch/arm/mach-davinci/board-da830-evm.c
@@ -10,51 +10,194 @@
* or implied.
*/
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/init.h>
#include <linux/console.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
#include <linux/i2c.h>
+#include <linux/i2c/pcf857x.h>
#include <linux/i2c/at24.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <mach/common.h>
-#include <mach/irqs.h>
#include <mach/cp_intc.h>
+#include <mach/mux.h>
+#include <mach/nand.h>
#include <mach/da8xx.h>
-#include <mach/asp.h>
+#include <mach/usb.h>
#define DA830_EVM_PHY_MASK 0x0
#define DA830_EVM_MDIO_FREQUENCY 2200000 /* PHY bus frequency */
-static struct at24_platform_data da830_evm_i2c_eeprom_info = {
- .byte_len = SZ_256K / 8,
- .page_size = 64,
- .flags = AT24_FLAG_ADDR16,
- .setup = davinci_get_mac_addr,
- .context = (void *)0x7f00,
-};
+#define DA830_EMIF25_ASYNC_DATA_CE3_BASE 0x62000000
+#define DA830_EMIF25_CONTROL_BASE 0x68000000
-static struct i2c_board_info __initdata da830_evm_i2c_devices[] = {
- {
- I2C_BOARD_INFO("24c256", 0x50),
- .platform_data = &da830_evm_i2c_eeprom_info,
- },
- {
- I2C_BOARD_INFO("tlv320aic3x", 0x18),
- }
+/*
+ * USB1 VBUS is controlled by GPIO1[15], over-current is reported on GPIO2[4].
+ */
+#define ON_BD_USB_DRV GPIO_TO_PIN(1, 15)
+#define ON_BD_USB_OVC GPIO_TO_PIN(2, 4)
+
+static const short da830_evm_usb11_pins[] = {
+ DA830_GPIO1_15, DA830_GPIO2_4,
+ -1
};
-static struct davinci_i2c_platform_data da830_evm_i2c_0_pdata = {
- .bus_freq = 100, /* kHz */
- .bus_delay = 0, /* usec */
+static da8xx_ocic_handler_t da830_evm_usb_ocic_handler;
+
+static int da830_evm_usb_set_power(unsigned port, int on)
+{
+ gpio_set_value(ON_BD_USB_DRV, on);
+ return 0;
+}
+
+static int da830_evm_usb_get_power(unsigned port)
+{
+ return gpio_get_value(ON_BD_USB_DRV);
+}
+
+static int da830_evm_usb_get_oci(unsigned port)
+{
+ return !gpio_get_value(ON_BD_USB_OVC);
+}
+
+static irqreturn_t da830_evm_usb_ocic_irq(int, void *);
+
+static int da830_evm_usb_ocic_notify(da8xx_ocic_handler_t handler)
+{
+ int irq = gpio_to_irq(ON_BD_USB_OVC);
+ int error = 0;
+
+ if (handler != NULL) {
+ da830_evm_usb_ocic_handler = handler;
+
+ error = request_irq(irq, da830_evm_usb_ocic_irq, IRQF_DISABLED |
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ "OHCI over-current indicator", NULL);
+ if (error)
+ printk(KERN_ERR "%s: could not request IRQ to watch "
+ "over-current indicator changes\n", __func__);
+ } else
+ free_irq(irq, NULL);
+
+ return error;
+}
+
+static struct da8xx_ohci_root_hub da830_evm_usb11_pdata = {
+ .set_power = da830_evm_usb_set_power,
+ .get_power = da830_evm_usb_get_power,
+ .get_oci = da830_evm_usb_get_oci,
+ .ocic_notify = da830_evm_usb_ocic_notify,
+
+ /* TPS2065 switch @ 5V */
+ .potpgt = (3 + 1) / 2, /* 3 ms max */
};
+static irqreturn_t da830_evm_usb_ocic_irq(int irq, void *dev_id)
+{
+ da830_evm_usb_ocic_handler(&da830_evm_usb11_pdata, 1);
+ return IRQ_HANDLED;
+}
+
+static __init void da830_evm_usb_init(void)
+{
+ u32 cfgchip2;
+ int ret;
+
+ /*
+ * Set up USB clock/mode in the CFGCHIP2 register.
+ * FYI: CFGCHIP2 is 0x0000ef00 initially.
+ */
+ cfgchip2 = __raw_readl(DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP2_REG));
+
+ /* USB2.0 PHY reference clock is 24 MHz */
+ cfgchip2 &= ~CFGCHIP2_REFFREQ;
+ cfgchip2 |= CFGCHIP2_REFFREQ_24MHZ;
+
+ /*
+ * Select internal reference clock for USB 2.0 PHY
+ * and use it as a clock source for USB 1.1 PHY
+ * (this is the default setting anyway).
+ */
+ cfgchip2 &= ~CFGCHIP2_USB1PHYCLKMUX;
+ cfgchip2 |= CFGCHIP2_USB2PHYCLKMUX;
+
+ /*
+ * We have to override VBUS/ID signals when MUSB is configured into the
+ * host-only mode -- ID pin will float if no cable is connected, so the
+ * controller won't be able to drive VBUS thinking that it's a B-device.
+ * Otherwise, we want to use the OTG mode and enable VBUS comparators.
+ */
+ cfgchip2 &= ~CFGCHIP2_OTGMODE;
+#ifdef CONFIG_USB_MUSB_HOST
+ cfgchip2 |= CFGCHIP2_FORCE_HOST;
+#else
+ cfgchip2 |= CFGCHIP2_SESENDEN | CFGCHIP2_VBDTCTEN;
+#endif
+
+ __raw_writel(cfgchip2, DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP2_REG));
+
+ /* USB_REFCLKIN is not used. */
+ ret = davinci_cfg_reg(DA830_USB0_DRVVBUS);
+ if (ret)
+ pr_warning("%s: USB 2.0 PinMux setup failed: %d\n",
+ __func__, ret);
+ else {
+ /*
+ * TPS2065 switch @ 5V supplies 1 A (sustains 1.5 A),
+ * with the power on to power good time of 3 ms.
+ */
+ ret = da8xx_register_usb20(1000, 3);
+ if (ret)
+ pr_warning("%s: USB 2.0 registration failed: %d\n",
+ __func__, ret);
+ }
+
+ ret = da8xx_pinmux_setup(da830_evm_usb11_pins);
+ if (ret) {
+ pr_warning("%s: USB 1.1 PinMux setup failed: %d\n",
+ __func__, ret);
+ return;
+ }
+
+ ret = gpio_request(ON_BD_USB_DRV, "ON_BD_USB_DRV");
+ if (ret) {
+ printk(KERN_ERR "%s: failed to request GPIO for USB 1.1 port "
+ "power control: %d\n", __func__, ret);
+ return;
+ }
+ gpio_direction_output(ON_BD_USB_DRV, 0);
+
+ ret = gpio_request(ON_BD_USB_OVC, "ON_BD_USB_OVC");
+ if (ret) {
+ printk(KERN_ERR "%s: failed to request GPIO for USB 1.1 port "
+ "over-current indicator: %d\n", __func__, ret);
+ return;
+ }
+ gpio_direction_input(ON_BD_USB_OVC);
+
+ ret = da8xx_register_usb11(&da830_evm_usb11_pdata);
+ if (ret)
+ pr_warning("%s: USB 1.1 registration failed: %d\n",
+ __func__, ret);
+}
+
static struct davinci_uart_config da830_evm_uart_config __initdata = {
.enabled_uarts = 0x7,
};
+static const short da830_evm_mcasp1_pins[] = {
+ DA830_AHCLKX1, DA830_ACLKX1, DA830_AFSX1, DA830_AHCLKR1, DA830_AFSR1,
+ DA830_AMUTE1, DA830_AXR1_0, DA830_AXR1_1, DA830_AXR1_2, DA830_AXR1_5,
+ DA830_ACLKR1, DA830_AXR1_6, DA830_AXR1_7, DA830_AXR1_8, DA830_AXR1_10,
+ DA830_AXR1_11,
+ -1
+};
+
static u8 da830_iis_serializer_direction[] = {
RX_MODE, INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE,
INACTIVE_MODE, TX_MODE, INACTIVE_MODE, INACTIVE_MODE,
@@ -74,6 +217,271 @@ static struct snd_platform_data da830_evm_snd_data = {
.rxnumevt = 1,
};
+/*
+ * GPIO2[1] is used as MMC_SD_WP and GPIO2[2] as MMC_SD_INS.
+ */
+static const short da830_evm_mmc_sd_pins[] = {
+ DA830_MMCSD_DAT_0, DA830_MMCSD_DAT_1, DA830_MMCSD_DAT_2,
+ DA830_MMCSD_DAT_3, DA830_MMCSD_DAT_4, DA830_MMCSD_DAT_5,
+ DA830_MMCSD_DAT_6, DA830_MMCSD_DAT_7, DA830_MMCSD_CLK,
+ DA830_MMCSD_CMD, DA830_GPIO2_1, DA830_GPIO2_2,
+ -1
+};
+
+#define DA830_MMCSD_WP_PIN GPIO_TO_PIN(2, 1)
+
+static int da830_evm_mmc_get_ro(int index)
+{
+ return gpio_get_value(DA830_MMCSD_WP_PIN);
+}
+
+static struct davinci_mmc_config da830_evm_mmc_config = {
+ .get_ro = da830_evm_mmc_get_ro,
+ .wires = 4,
+ .max_freq = 50000000,
+ .caps = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED,
+ .version = MMC_CTLR_VERSION_2,
+};
+
+static inline void da830_evm_init_mmc(void)
+{
+ int ret;
+
+ ret = da8xx_pinmux_setup(da830_evm_mmc_sd_pins);
+ if (ret) {
+ pr_warning("da830_evm_init: mmc/sd mux setup failed: %d\n",
+ ret);
+ return;
+ }
+
+ ret = gpio_request(DA830_MMCSD_WP_PIN, "MMC WP");
+ if (ret) {
+ pr_warning("da830_evm_init: can not open GPIO %d\n",
+ DA830_MMCSD_WP_PIN);
+ return;
+ }
+ gpio_direction_input(DA830_MMCSD_WP_PIN);
+
+ ret = da8xx_register_mmcsd0(&da830_evm_mmc_config);
+ if (ret) {
+ pr_warning("da830_evm_init: mmc/sd registration failed: %d\n",
+ ret);
+ gpio_free(DA830_MMCSD_WP_PIN);
+ }
+}
+
+/*
+ * UI board NAND/NOR flashes only use 8-bit data bus.
+ */
+static const short da830_evm_emif25_pins[] = {
+ DA830_EMA_D_0, DA830_EMA_D_1, DA830_EMA_D_2, DA830_EMA_D_3,
+ DA830_EMA_D_4, DA830_EMA_D_5, DA830_EMA_D_6, DA830_EMA_D_7,
+ DA830_EMA_A_0, DA830_EMA_A_1, DA830_EMA_A_2, DA830_EMA_A_3,
+ DA830_EMA_A_4, DA830_EMA_A_5, DA830_EMA_A_6, DA830_EMA_A_7,
+ DA830_EMA_A_8, DA830_EMA_A_9, DA830_EMA_A_10, DA830_EMA_A_11,
+ DA830_EMA_A_12, DA830_EMA_BA_0, DA830_EMA_BA_1, DA830_NEMA_WE,
+ DA830_NEMA_CS_2, DA830_NEMA_CS_3, DA830_NEMA_OE, DA830_EMA_WAIT_0,
+ -1
+};
+
+#if defined(CONFIG_MMC_DAVINCI) || defined(CONFIG_MMC_DAVINCI_MODULE)
+#define HAS_MMC 1
+#else
+#define HAS_MMC 0
+#endif
+
+#ifdef CONFIG_DA830_UI_NAND
+static struct mtd_partition da830_evm_nand_partitions[] = {
+ /* bootloader (U-Boot, etc) in first sector */
+ [0] = {
+ .name = "bootloader",
+ .offset = 0,
+ .size = SZ_128K,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ },
+ /* bootloader params in the next sector */
+ [1] = {
+ .name = "params",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_128K,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ },
+ /* kernel */
+ [2] = {
+ .name = "kernel",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_2M,
+ .mask_flags = 0,
+ },
+ /* file system */
+ [3] = {
+ .name = "filesystem",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL,
+ .mask_flags = 0,
+ }
+};
+
+/* flash bbt decriptors */
+static uint8_t da830_evm_nand_bbt_pattern[] = { 'B', 'b', 't', '0' };
+static uint8_t da830_evm_nand_mirror_pattern[] = { '1', 't', 'b', 'B' };
+
+static struct nand_bbt_descr da830_evm_nand_bbt_main_descr = {
+ .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE |
+ NAND_BBT_WRITE | NAND_BBT_2BIT |
+ NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+ .offs = 2,
+ .len = 4,
+ .veroffs = 16,
+ .maxblocks = 4,
+ .pattern = da830_evm_nand_bbt_pattern
+};
+
+static struct nand_bbt_descr da830_evm_nand_bbt_mirror_descr = {
+ .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE |
+ NAND_BBT_WRITE | NAND_BBT_2BIT |
+ NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+ .offs = 2,
+ .len = 4,
+ .veroffs = 16,
+ .maxblocks = 4,
+ .pattern = da830_evm_nand_mirror_pattern
+};
+
+static struct davinci_nand_pdata da830_evm_nand_pdata = {
+ .parts = da830_evm_nand_partitions,
+ .nr_parts = ARRAY_SIZE(da830_evm_nand_partitions),
+ .ecc_mode = NAND_ECC_HW,
+ .ecc_bits = 4,
+ .options = NAND_USE_FLASH_BBT,
+ .bbt_td = &da830_evm_nand_bbt_main_descr,
+ .bbt_md = &da830_evm_nand_bbt_mirror_descr,
+};
+
+static struct resource da830_evm_nand_resources[] = {
+ [0] = { /* First memory resource is NAND I/O window */
+ .start = DA830_EMIF25_ASYNC_DATA_CE3_BASE,
+ .end = DA830_EMIF25_ASYNC_DATA_CE3_BASE + PAGE_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = { /* Second memory resource is AEMIF control registers */
+ .start = DA830_EMIF25_CONTROL_BASE,
+ .end = DA830_EMIF25_CONTROL_BASE + SZ_32K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device da830_evm_nand_device = {
+ .name = "davinci_nand",
+ .id = 1,
+ .dev = {
+ .platform_data = &da830_evm_nand_pdata,
+ },
+ .num_resources = ARRAY_SIZE(da830_evm_nand_resources),
+ .resource = da830_evm_nand_resources,
+};
+
+static inline void da830_evm_init_nand(int mux_mode)
+{
+ int ret;
+
+ if (HAS_MMC) {
+ pr_warning("WARNING: both MMC/SD and NAND are "
+ "enabled, but they share AEMIF pins.\n"
+ "\tDisable MMC/SD for NAND support.\n");
+ return;
+ }
+
+ ret = da8xx_pinmux_setup(da830_evm_emif25_pins);
+ if (ret)
+ pr_warning("da830_evm_init: emif25 mux setup failed: %d\n",
+ ret);
+
+ ret = platform_device_register(&da830_evm_nand_device);
+ if (ret)
+ pr_warning("da830_evm_init: NAND device not registered.\n");
+
+ gpio_direction_output(mux_mode, 1);
+}
+#else
+static inline void da830_evm_init_nand(int mux_mode) { }
+#endif
+
+#ifdef CONFIG_DA830_UI_LCD
+static inline void da830_evm_init_lcdc(int mux_mode)
+{
+ int ret;
+
+ ret = da8xx_pinmux_setup(da830_lcdcntl_pins);
+ if (ret)
+ pr_warning("da830_evm_init: lcdcntl mux setup failed: %d\n",
+ ret);
+
+ ret = da8xx_register_lcdc(&sharp_lcd035q3dg01_pdata);
+ if (ret)
+ pr_warning("da830_evm_init: lcd setup failed: %d\n", ret);
+
+ gpio_direction_output(mux_mode, 0);
+}
+#else
+static inline void da830_evm_init_lcdc(int mux_mode) { }
+#endif
+
+static struct at24_platform_data da830_evm_i2c_eeprom_info = {
+ .byte_len = SZ_256K / 8,
+ .page_size = 64,
+ .flags = AT24_FLAG_ADDR16,
+ .setup = davinci_get_mac_addr,
+ .context = (void *)0x7f00,
+};
+
+static int __init da830_evm_ui_expander_setup(struct i2c_client *client,
+ int gpio, unsigned ngpio, void *context)
+{
+ gpio_request(gpio + 6, "UI MUX_MODE");
+
+ /* Drive mux mode low to match the default without UI card */
+ gpio_direction_output(gpio + 6, 0);
+
+ da830_evm_init_lcdc(gpio + 6);
+
+ da830_evm_init_nand(gpio + 6);
+
+ return 0;
+}
+
+static int da830_evm_ui_expander_teardown(struct i2c_client *client, int gpio,
+ unsigned ngpio, void *context)
+{
+ gpio_free(gpio + 6);
+ return 0;
+}
+
+static struct pcf857x_platform_data __initdata da830_evm_ui_expander_info = {
+ .gpio_base = DAVINCI_N_GPIO,
+ .setup = da830_evm_ui_expander_setup,
+ .teardown = da830_evm_ui_expander_teardown,
+};
+
+static struct i2c_board_info __initdata da830_evm_i2c_devices[] = {
+ {
+ I2C_BOARD_INFO("24c256", 0x50),
+ .platform_data = &da830_evm_i2c_eeprom_info,
+ },
+ {
+ I2C_BOARD_INFO("tlv320aic3x", 0x18),
+ },
+ {
+ I2C_BOARD_INFO("pcf8574", 0x3f),
+ .platform_data = &da830_evm_ui_expander_info,
+ },
+};
+
+static struct davinci_i2c_platform_data da830_evm_i2c_0_pdata = {
+ .bus_freq = 100, /* kHz */
+ .bus_delay = 0, /* usec */
+};
+
static __init void da830_evm_init(void)
{
struct davinci_soc_info *soc_info = &davinci_soc_info;
@@ -94,6 +502,8 @@ static __init void da830_evm_init(void)
pr_warning("da830_evm_init: i2c0 registration failed: %d\n",
ret);
+ da830_evm_usb_init();
+
soc_info->emac_pdata->phy_mask = DA830_EVM_PHY_MASK;
soc_info->emac_pdata->mdio_max_freq = DA830_EVM_MDIO_FREQUENCY;
soc_info->emac_pdata->rmii_en = 1;
@@ -117,12 +527,18 @@ static __init void da830_evm_init(void)
i2c_register_board_info(1, da830_evm_i2c_devices,
ARRAY_SIZE(da830_evm_i2c_devices));
- ret = da8xx_pinmux_setup(da830_mcasp1_pins);
+ ret = da8xx_pinmux_setup(da830_evm_mcasp1_pins);
if (ret)
pr_warning("da830_evm_init: mcasp1 mux setup failed: %d\n",
ret);
- da8xx_init_mcasp(1, &da830_evm_snd_data);
+ da8xx_register_mcasp(1, &da830_evm_snd_data);
+
+ da830_evm_init_mmc();
+
+ ret = da8xx_register_rtc();
+ if (ret)
+ pr_warning("da830_evm_init: rtc setup failed: %d\n", ret);
}
#ifdef CONFIG_SERIAL_8250_CONSOLE
@@ -146,7 +562,7 @@ static void __init da830_evm_map_io(void)
da830_init();
}
-MACHINE_START(DAVINCI_DA830_EVM, "DaVinci DA830/OMAP L137 EVM")
+MACHINE_START(DAVINCI_DA830_EVM, "DaVinci DA830/OMAP-L137 EVM")
.phys_io = IO_PHYS,
.io_pg_offst = (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc,
.boot_params = (DA8XX_DDR_BASE + 0x100),
diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
index c759d72..62b98bf 100644
--- a/arch/arm/mach-davinci/board-da850-evm.c
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -12,36 +12,38 @@
* or implied.
*/
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/i2c.h>
#include <linux/i2c/at24.h>
+#include <linux/i2c/pca953x.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/physmap.h>
+#include <linux/regulator/machine.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <mach/common.h>
-#include <mach/irqs.h>
#include <mach/cp_intc.h>
#include <mach/da8xx.h>
#include <mach/nand.h>
+#include <mach/mux.h>
#define DA850_EVM_PHY_MASK 0x1
#define DA850_EVM_MDIO_FREQUENCY 2200000 /* PHY bus frequency */
+#define DA850_LCD_PWR_PIN GPIO_TO_PIN(2, 8)
#define DA850_LCD_BL_PIN GPIO_TO_PIN(2, 15)
-#define DA850_LCD_PWR_PIN GPIO_TO_PIN(8, 10)
#define DA850_MMCSD_CD_PIN GPIO_TO_PIN(4, 0)
#define DA850_MMCSD_WP_PIN GPIO_TO_PIN(4, 1)
+#define DA850_MII_MDIO_CLKEN_PIN GPIO_TO_PIN(2, 6)
+
static struct mtd_partition da850_evm_norflash_partition[] = {
{
.name = "NOR filesystem",
@@ -143,10 +145,149 @@ static struct platform_device da850_evm_nandflash_device = {
.resource = da850_evm_nandflash_resource,
};
+static struct platform_device *da850_evm_devices[] __initdata = {
+ &da850_evm_nandflash_device,
+ &da850_evm_norflash_device,
+};
+
+#define DA8XX_AEMIF_CE2CFG_OFFSET 0x10
+#define DA8XX_AEMIF_ASIZE_16BIT 0x1
+
+static void __init da850_evm_init_nor(void)
+{
+ void __iomem *aemif_addr;
+
+ aemif_addr = ioremap(DA8XX_AEMIF_CTL_BASE, SZ_32K);
+
+ /* Configure data bus width of CS2 to 16 bit */
+ writel(readl(aemif_addr + DA8XX_AEMIF_CE2CFG_OFFSET) |
+ DA8XX_AEMIF_ASIZE_16BIT,
+ aemif_addr + DA8XX_AEMIF_CE2CFG_OFFSET);
+
+ iounmap(aemif_addr);
+}
+
+static u32 ui_card_detected;
+
+#if defined(CONFIG_MMC_DAVINCI) || \
+ defined(CONFIG_MMC_DAVINCI_MODULE)
+#define HAS_MMC 1
+#else
+#define HAS_MMC 0
+#endif
+
+static __init void da850_evm_setup_nor_nand(void)
+{
+ int ret = 0;
+
+ if (ui_card_detected & !HAS_MMC) {
+ ret = da8xx_pinmux_setup(da850_nand_pins);
+ if (ret)
+ pr_warning("da850_evm_init: nand mux setup failed: "
+ "%d\n", ret);
+
+ ret = da8xx_pinmux_setup(da850_nor_pins);
+ if (ret)
+ pr_warning("da850_evm_init: nor mux setup failed: %d\n",
+ ret);
+
+ da850_evm_init_nor();
+
+ platform_add_devices(da850_evm_devices,
+ ARRAY_SIZE(da850_evm_devices));
+ }
+}
+
+#ifdef CONFIG_DA850_UI_RMII
+static inline void da850_evm_setup_emac_rmii(int rmii_sel)
+{
+ struct davinci_soc_info *soc_info = &davinci_soc_info;
+
+ soc_info->emac_pdata->rmii_en = 1;
+ gpio_set_value(rmii_sel, 0);
+}
+#else
+static inline void da850_evm_setup_emac_rmii(int rmii_sel) { }
+#endif
+
+static int da850_evm_ui_expander_setup(struct i2c_client *client, unsigned gpio,
+ unsigned ngpio, void *c)
+{
+ int sel_a, sel_b, sel_c, ret;
+
+ sel_a = gpio + 7;
+ sel_b = gpio + 6;
+ sel_c = gpio + 5;
+
+ ret = gpio_request(sel_a, "sel_a");
+ if (ret) {
+ pr_warning("Cannot open UI expander pin %d\n", sel_a);
+ goto exp_setup_sela_fail;
+ }
+
+ ret = gpio_request(sel_b, "sel_b");
+ if (ret) {
+ pr_warning("Cannot open UI expander pin %d\n", sel_b);
+ goto exp_setup_selb_fail;
+ }
+
+ ret = gpio_request(sel_c, "sel_c");
+ if (ret) {
+ pr_warning("Cannot open UI expander pin %d\n", sel_c);
+ goto exp_setup_selc_fail;
+ }
+
+ /* deselect all functionalities */
+ gpio_direction_output(sel_a, 1);
+ gpio_direction_output(sel_b, 1);
+ gpio_direction_output(sel_c, 1);
+
+ ui_card_detected = 1;
+ pr_info("DA850/OMAP-L138 EVM UI card detected\n");
+
+ da850_evm_setup_nor_nand();
+
+ da850_evm_setup_emac_rmii(sel_a);
+
+ return 0;
+
+exp_setup_selc_fail:
+ gpio_free(sel_b);
+exp_setup_selb_fail:
+ gpio_free(sel_a);
+exp_setup_sela_fail:
+ return ret;
+}
+
+static int da850_evm_ui_expander_teardown(struct i2c_client *client,
+ unsigned gpio, unsigned ngpio, void *c)
+{
+ /* deselect all functionalities */
+ gpio_set_value(gpio + 5, 1);
+ gpio_set_value(gpio + 6, 1);
+ gpio_set_value(gpio + 7, 1);
+
+ gpio_free(gpio + 5);
+ gpio_free(gpio + 6);
+ gpio_free(gpio + 7);
+
+ return 0;
+}
+
+static struct pca953x_platform_data da850_evm_ui_expander_info = {
+ .gpio_base = DAVINCI_N_GPIO,
+ .setup = da850_evm_ui_expander_setup,
+ .teardown = da850_evm_ui_expander_teardown,
+};
+
static struct i2c_board_info __initdata da850_evm_i2c_devices[] = {
{
I2C_BOARD_INFO("tlv320aic3x", 0x18),
- }
+ },
+ {
+ I2C_BOARD_INFO("tca6416", 0x20),
+ .platform_data = &da850_evm_ui_expander_info,
+ },
};
static struct davinci_i2c_platform_data da850_evm_i2c_0_pdata = {
@@ -158,11 +299,6 @@ static struct davinci_uart_config da850_evm_uart_config __initdata = {
.enabled_uarts = 0x7,
};
-static struct platform_device *da850_evm_devices[] __initdata = {
- &da850_evm_nandflash_device,
- &da850_evm_norflash_device,
-};
-
/* davinci da850 evm audio machine driver */
static u8 da850_iis_serializer_direction[] = {
INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE,
@@ -198,6 +334,8 @@ static struct davinci_mmc_config da850_mmc_config = {
.get_ro = da850_evm_mmc_get_ro,
.get_cd = da850_evm_mmc_get_cd,
.wires = 4,
+ .max_freq = 50000000,
+ .caps = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED,
.version = MMC_CTLR_VERSION_2,
};
@@ -233,56 +371,227 @@ static int da850_lcd_hw_init(void)
return 0;
}
-#define DA8XX_AEMIF_CE2CFG_OFFSET 0x10
-#define DA8XX_AEMIF_ASIZE_16BIT 0x1
+/* TPS65070 voltage regulator support */
-static void __init da850_evm_init_nor(void)
-{
- void __iomem *aemif_addr;
+/* 3.3V */
+struct regulator_consumer_supply tps65070_dcdc1_consumers[] = {
+ {
+ .supply = "usb0_vdda33",
+ },
+ {
+ .supply = "usb1_vdda33",
+ },
+};
- aemif_addr = ioremap(DA8XX_AEMIF_CTL_BASE, SZ_32K);
+/* 3.3V or 1.8V */
+struct regulator_consumer_supply tps65070_dcdc2_consumers[] = {
+ {
+ .supply = "dvdd3318_a",
+ },
+ {
+ .supply = "dvdd3318_b",
+ },
+ {
+ .supply = "dvdd3318_c",
+ },
+};
- /* Configure data bus width of CS2 to 16 bit */
- writel(readl(aemif_addr + DA8XX_AEMIF_CE2CFG_OFFSET) |
- DA8XX_AEMIF_ASIZE_16BIT,
- aemif_addr + DA8XX_AEMIF_CE2CFG_OFFSET);
+/* 1.2V */
+struct regulator_consumer_supply tps65070_dcdc3_consumers[] = {
+ {
+ .supply = "cvdd",
+ },
+};
- iounmap(aemif_addr);
-}
+/* 1.8V LDO */
+struct regulator_consumer_supply tps65070_ldo1_consumers[] = {
+ {
+ .supply = "sata_vddr",
+ },
+ {
+ .supply = "usb0_vdda18",
+ },
+ {
+ .supply = "usb1_vdda18",
+ },
+ {
+ .supply = "ddr_dvdd18",
+ },
+};
-#if defined(CONFIG_MTD_PHYSMAP) || \
- defined(CONFIG_MTD_PHYSMAP_MODULE)
-#define HAS_NOR 1
-#else
-#define HAS_NOR 0
-#endif
+/* 1.2V LDO */
+struct regulator_consumer_supply tps65070_ldo2_consumers[] = {
+ {
+ .supply = "sata_vdd",
+ },
+ {
+ .supply = "pll0_vdda",
+ },
+ {
+ .supply = "pll1_vdda",
+ },
+ {
+ .supply = "usbs_cvdd",
+ },
+ {
+ .supply = "vddarnwa1",
+ },
+};
-#if defined(CONFIG_MMC_DAVINCI) || \
- defined(CONFIG_MMC_DAVINCI_MODULE)
-#define HAS_MMC 1
-#else
-#define HAS_MMC 0
-#endif
+struct regulator_init_data tps65070_regulator_data[] = {
+ /* dcdc1 */
+ {
+ .constraints = {
+ .min_uV = 3150000,
+ .max_uV = 3450000,
+ .valid_ops_mask = (REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS),
+ .boot_on = 1,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(tps65070_dcdc1_consumers),
+ .consumer_supplies = tps65070_dcdc1_consumers,
+ },
-static __init void da850_evm_init(void)
+ /* dcdc2 */
+ {
+ .constraints = {
+ .min_uV = 1710000,
+ .max_uV = 3450000,
+ .valid_ops_mask = (REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS),
+ .boot_on = 1,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(tps65070_dcdc2_consumers),
+ .consumer_supplies = tps65070_dcdc2_consumers,
+ },
+
+ /* dcdc3 */
+ {
+ .constraints = {
+ .min_uV = 950000,
+ .max_uV = 1320000,
+ .valid_ops_mask = (REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS),
+ .boot_on = 1,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(tps65070_dcdc3_consumers),
+ .consumer_supplies = tps65070_dcdc3_consumers,
+ },
+
+ /* ldo1 */
+ {
+ .constraints = {
+ .min_uV = 1710000,
+ .max_uV = 1890000,
+ .valid_ops_mask = (REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS),
+ .boot_on = 1,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(tps65070_ldo1_consumers),
+ .consumer_supplies = tps65070_ldo1_consumers,
+ },
+
+ /* ldo2 */
+ {
+ .constraints = {
+ .min_uV = 1140000,
+ .max_uV = 1320000,
+ .valid_ops_mask = (REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS),
+ .boot_on = 1,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(tps65070_ldo2_consumers),
+ .consumer_supplies = tps65070_ldo2_consumers,
+ },
+};
+
+static struct i2c_board_info __initdata da850evm_tps65070_info[] = {
+ {
+ I2C_BOARD_INFO("tps6507x", 0x48),
+ .platform_data = &tps65070_regulator_data[0],
+ },
+};
+
+static int __init pmic_tps65070_init(void)
{
- struct davinci_soc_info *soc_info = &davinci_soc_info;
+ return i2c_register_board_info(1, da850evm_tps65070_info,
+ ARRAY_SIZE(da850evm_tps65070_info));
+}
+
+static const short da850_evm_lcdc_pins[] = {
+ DA850_GPIO2_8, DA850_GPIO2_15,
+ -1
+};
+
+static int __init da850_evm_config_emac(void)
+{
+ void __iomem *cfg_chip3_base;
int ret;
+ u32 val;
+ struct davinci_soc_info *soc_info = &davinci_soc_info;
+ u8 rmii_en = soc_info->emac_pdata->rmii_en;
+
+ if (!machine_is_davinci_da850_evm())
+ return 0;
+
+ cfg_chip3_base = DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP3_REG);
+
+ val = __raw_readl(cfg_chip3_base);
+
+ if (rmii_en) {
+ val |= BIT(8);
+ ret = da8xx_pinmux_setup(da850_rmii_pins);
+ pr_info("EMAC: RMII PHY configured, MII PHY will not be"
+ " functional\n");
+ } else {
+ val &= ~BIT(8);
+ ret = da8xx_pinmux_setup(da850_cpgmac_pins);
+ pr_info("EMAC: MII PHY configured, RMII PHY will not be"
+ " functional\n");
+ }
- ret = da8xx_pinmux_setup(da850_nand_pins);
if (ret)
- pr_warning("da850_evm_init: nand mux setup failed: %d\n",
+ pr_warning("da850_evm_init: cpgmac/rmii mux setup failed: %d\n",
ret);
- ret = da8xx_pinmux_setup(da850_nor_pins);
+ /* configure the CFGCHIP3 register for RMII or MII */
+ __raw_writel(val, cfg_chip3_base);
+
+ ret = davinci_cfg_reg(DA850_GPIO2_6);
if (ret)
- pr_warning("da850_evm_init: nor mux setup failed: %d\n",
+ pr_warning("da850_evm_init:GPIO(2,6) mux setup "
+ "failed\n");
+
+ ret = gpio_request(DA850_MII_MDIO_CLKEN_PIN, "mdio_clk_en");
+ if (ret) {
+ pr_warning("Cannot open GPIO %d\n",
+ DA850_MII_MDIO_CLKEN_PIN);
+ return ret;
+ }
+
+ /* Enable/Disable MII MDIO clock */
+ gpio_direction_output(DA850_MII_MDIO_CLKEN_PIN, rmii_en);
+
+ soc_info->emac_pdata->phy_mask = DA850_EVM_PHY_MASK;
+ soc_info->emac_pdata->mdio_max_freq = DA850_EVM_MDIO_FREQUENCY;
+
+ ret = da8xx_register_emac();
+ if (ret)
+ pr_warning("da850_evm_init: emac registration failed: %d\n",
ret);
- da850_evm_init_nor();
+ return 0;
+}
+device_initcall(da850_evm_config_emac);
+
+static __init void da850_evm_init(void)
+{
+ int ret;
- platform_add_devices(da850_evm_devices,
- ARRAY_SIZE(da850_evm_devices));
+ ret = pmic_tps65070_init();
+ if (ret)
+ pr_warning("da850_evm_init: TPS65070 PMIC init failed: %d\n",
+ ret);
ret = da8xx_register_edma();
if (ret)
@@ -299,19 +608,6 @@ static __init void da850_evm_init(void)
pr_warning("da850_evm_init: i2c0 registration failed: %d\n",
ret);
- soc_info->emac_pdata->phy_mask = DA850_EVM_PHY_MASK;
- soc_info->emac_pdata->mdio_max_freq = DA850_EVM_MDIO_FREQUENCY;
- soc_info->emac_pdata->rmii_en = 0;
-
- ret = da8xx_pinmux_setup(da850_cpgmac_pins);
- if (ret)
- pr_warning("da850_evm_init: cpgmac mux setup failed: %d\n",
- ret);
-
- ret = da8xx_register_emac();
- if (ret)
- pr_warning("da850_evm_init: emac registration failed: %d\n",
- ret);
ret = da8xx_register_watchdog();
if (ret)
@@ -319,11 +615,6 @@ static __init void da850_evm_init(void)
ret);
if (HAS_MMC) {
- if (HAS_NOR)
- pr_warning("WARNING: both NOR Flash and MMC/SD are "
- "enabled, but they share AEMIF pins.\n"
- "\tDisable one of them.\n");
-
ret = da8xx_pinmux_setup(da850_mmcsd0_pins);
if (ret)
pr_warning("da850_evm_init: mmcsd0 mux setup failed:"
@@ -365,22 +656,42 @@ static __init void da850_evm_init(void)
pr_warning("da850_evm_init: mcasp mux setup failed: %d\n",
ret);
- da8xx_init_mcasp(0, &da850_evm_snd_data);
+ da8xx_register_mcasp(0, &da850_evm_snd_data);
ret = da8xx_pinmux_setup(da850_lcdcntl_pins);
if (ret)
pr_warning("da850_evm_init: lcdcntl mux setup failed: %d\n",
ret);
+ /* Handle board specific muxing for LCD here */
+ ret = da8xx_pinmux_setup(da850_evm_lcdc_pins);
+ if (ret)
+ pr_warning("da850_evm_init: evm specific lcd mux setup "
+ "failed: %d\n", ret);
+
ret = da850_lcd_hw_init();
if (ret)
pr_warning("da850_evm_init: lcd initialization failed: %d\n",
ret);
- ret = da8xx_register_lcdc();
+ ret = da8xx_register_lcdc(&sharp_lk043t1dg01_pdata);
if (ret)
pr_warning("da850_evm_init: lcdc registration failed: %d\n",
ret);
+
+ ret = da8xx_register_rtc();
+ if (ret)
+ pr_warning("da850_evm_init: rtc setup failed: %d\n", ret);
+
+ ret = da850_register_cpufreq();
+ if (ret)
+ pr_warning("da850_evm_init: cpufreq registration failed: %d\n",
+ ret);
+
+ ret = da8xx_register_cpuidle();
+ if (ret)
+ pr_warning("da850_evm_init: cpuidle registration failed: %d\n",
+ ret);
}
#ifdef CONFIG_SERIAL_8250_CONSOLE
diff --git a/arch/arm/mach-davinci/board-dm355-evm.c b/arch/arm/mach-davinci/board-dm355-evm.c
index 77e8067..a9b650d 100644
--- a/arch/arm/mach-davinci/board-dm355-evm.c
+++ b/arch/arm/mach-davinci/board-dm355-evm.c
@@ -9,15 +9,13 @@
* or implied.
*/
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/init.h>
-#include <linux/dma-mapping.h>
+#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/nand.h>
#include <linux/i2c.h>
-#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/clk.h>
#include <linux/videodev2.h>
@@ -25,20 +23,15 @@
#include <linux/spi/spi.h>
#include <linux/spi/eeprom.h>
-#include <asm/setup.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/flash.h>
-#include <mach/hardware.h>
#include <mach/dm355.h>
-#include <mach/psc.h>
-#include <mach/common.h>
#include <mach/i2c.h>
#include <mach/serial.h>
#include <mach/nand.h>
#include <mach/mmc.h>
+#include <mach/usb.h>
#define DAVINCI_ASYNC_EMIF_CONTROL_BASE 0x01e10000
#define DAVINCI_ASYNC_EMIF_DATA_CE0_BASE 0x02000000
@@ -86,8 +79,9 @@ static struct davinci_nand_pdata davinci_nand_data = {
.mask_chipsel = BIT(14),
.parts = davinci_nand_partitions,
.nr_parts = ARRAY_SIZE(davinci_nand_partitions),
- .ecc_mode = NAND_ECC_HW_SYNDROME,
+ .ecc_mode = NAND_ECC_HW,
.options = NAND_USE_FLASH_BBT,
+ .ecc_bits = 4,
};
static struct resource davinci_nand_resources[] = {
@@ -344,7 +338,7 @@ static __init void dm355_evm_init(void)
gpio_request(2, "usb_id_toggle");
gpio_direction_output(2, USB_ID_VALUE);
/* irlml6401 switches over 1A in under 8 msec */
- setup_usb(500, 8);
+ davinci_setup_usb(1000, 8);
davinci_setup_mmc(0, &dm355evm_mmc_config);
davinci_setup_mmc(1, &dm355evm_mmc_config);
diff --git a/arch/arm/mach-davinci/board-dm355-leopard.c b/arch/arm/mach-davinci/board-dm355-leopard.c
index 84ad5d1..21f32eb 100644
--- a/arch/arm/mach-davinci/board-dm355-leopard.c
+++ b/arch/arm/mach-davinci/board-dm355-leopard.c
@@ -8,34 +8,27 @@
* warranty of any kind, whether express or implied.
*/
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/init.h>
-#include <linux/dma-mapping.h>
+#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/nand.h>
#include <linux/i2c.h>
-#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/clk.h>
#include <linux/spi/spi.h>
#include <linux/spi/eeprom.h>
-#include <asm/setup.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/flash.h>
-#include <mach/hardware.h>
#include <mach/dm355.h>
-#include <mach/psc.h>
-#include <mach/common.h>
#include <mach/i2c.h>
#include <mach/serial.h>
#include <mach/nand.h>
#include <mach/mmc.h>
+#include <mach/usb.h>
#define DAVINCI_ASYNC_EMIF_CONTROL_BASE 0x01e10000
#define DAVINCI_ASYNC_EMIF_DATA_CE0_BASE 0x02000000
@@ -270,7 +263,7 @@ static __init void dm355_leopard_init(void)
gpio_request(2, "usb_id_toggle");
gpio_direction_output(2, USB_ID_VALUE);
/* irlml6401 switches over 1A in under 8 msec */
- setup_usb(500, 8);
+ davinci_setup_usb(1000, 8);
davinci_setup_mmc(0, &dm355leopard_mmc_config);
davinci_setup_mmc(1, &dm355leopard_mmc_config);
diff --git a/arch/arm/mach-davinci/board-dm365-evm.c b/arch/arm/mach-davinci/board-dm365-evm.c
index 52dd804..289fe1b 100644
--- a/arch/arm/mach-davinci/board-dm365-evm.c
+++ b/arch/arm/mach-davinci/board-dm365-evm.c
@@ -13,9 +13,8 @@
* GNU General Public License for more details.
*/
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/init.h>
-#include <linux/dma-mapping.h>
+#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/io.h>
#include <linux/clk.h>
@@ -24,20 +23,19 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/nand.h>
-#include <asm/setup.h>
+#include <linux/input.h>
+
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
+
#include <mach/mux.h>
-#include <mach/hardware.h>
#include <mach/dm365.h>
-#include <mach/psc.h>
#include <mach/common.h>
#include <mach/i2c.h>
#include <mach/serial.h>
#include <mach/mmc.h>
#include <mach/nand.h>
-
+#include <mach/keyscan.h>
static inline int have_imager(void)
{
@@ -144,6 +142,7 @@ static struct davinci_nand_pdata davinci_nand_data = {
.nr_parts = ARRAY_SIZE(davinci_nand_partitions),
.ecc_mode = NAND_ECC_HW,
.options = NAND_USE_FLASH_BBT,
+ .ecc_bits = 4,
};
static struct resource davinci_nand_resources[] = {
@@ -176,11 +175,16 @@ static struct at24_platform_data eeprom_info = {
.context = (void *)0x7f00,
};
+static struct snd_platform_data dm365_evm_snd_data;
+
static struct i2c_board_info i2c_info[] = {
{
I2C_BOARD_INFO("24c256", 0x50),
.platform_data = &eeprom_info,
},
+ {
+ I2C_BOARD_INFO("tlv320aic3x", 0x18),
+ },
};
static struct davinci_i2c_platform_data i2c_pdata = {
@@ -188,6 +192,38 @@ static struct davinci_i2c_platform_data i2c_pdata = {
.bus_delay = 0 /* usec */,
};
+#ifdef CONFIG_KEYBOARD_DAVINCI
+static unsigned short dm365evm_keymap[] = {
+ KEY_KP2,
+ KEY_LEFT,
+ KEY_EXIT,
+ KEY_DOWN,
+ KEY_ENTER,
+ KEY_UP,
+ KEY_KP1,
+ KEY_RIGHT,
+ KEY_MENU,
+ KEY_RECORD,
+ KEY_REWIND,
+ KEY_KPMINUS,
+ KEY_STOP,
+ KEY_FASTFORWARD,
+ KEY_KPPLUS,
+ KEY_PLAYPAUSE,
+ 0
+};
+
+static struct davinci_ks_platform_data dm365evm_ks_data = {
+ .keymap = dm365evm_keymap,
+ .keymapsize = ARRAY_SIZE(dm365evm_keymap),
+ .rep = 1,
+ /* Scan period = strobe + interval */
+ .strobe = 0x5,
+ .interval = 0x2,
+ .matrix_type = DAVINCI_KEYSCAN_MATRIX_4X4,
+};
+#endif
+
static int cpld_mmc_get_cd(int module)
{
if (!cpld)
@@ -472,6 +508,13 @@ static __init void dm365_evm_init(void)
/* maybe setup mmc1/etc ... _after_ mmc0 */
evm_init_cpld();
+
+ dm365_init_asp(&dm365_evm_snd_data);
+ dm365_init_rtc();
+
+#ifdef CONFIG_KEYBOARD_DAVINCI
+ dm365_init_ks(&dm365evm_ks_data);
+#endif
}
static __init void dm365_evm_irq_init(void)
diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c
index 1213a00..fd0398b 100644
--- a/arch/arm/mach-davinci/board-dm644x-evm.c
+++ b/arch/arm/mach-davinci/board-dm644x-evm.c
@@ -9,45 +9,34 @@
* or implied.
*/
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
-#include <linux/leds.h>
-#include <linux/memory.h>
-
#include <linux/i2c.h>
#include <linux/i2c/pcf857x.h>
#include <linux/i2c/at24.h>
-#include <linux/etherdevice.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/physmap.h>
-#include <linux/io.h>
#include <linux/phy.h>
#include <linux/clk.h>
#include <linux/videodev2.h>
#include <media/tvp514x.h>
-#include <asm/setup.h>
#include <asm/mach-types.h>
-
#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/flash.h>
#include <mach/dm644x.h>
#include <mach/common.h>
#include <mach/i2c.h>
#include <mach/serial.h>
#include <mach/mux.h>
-#include <mach/psc.h>
#include <mach/nand.h>
#include <mach/mmc.h>
-#include <mach/emac.h>
+#include <mach/usb.h>
#define DM644X_EVM_PHY_MASK (0x2)
#define DM644X_EVM_MDIO_FREQUENCY (2200000) /* PHY bus frequency */
@@ -477,7 +466,7 @@ evm_u35_setup(struct i2c_client *client, int gpio, unsigned ngpio, void *c)
/* irlml6401 switches over 1A, in under 8 msec;
* now it can be managed by nDRV_VBUS ...
*/
- setup_usb(500, 8);
+ davinci_setup_usb(1000, 8);
return 0;
}
diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c
index 24e0e13..8d0b0e0 100644
--- a/arch/arm/mach-davinci/board-dm646x-evm.c
+++ b/arch/arm/mach-davinci/board-dm646x-evm.c
@@ -17,38 +17,28 @@
**************************************************************************/
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/major.h>
-#include <linux/root_dev.h>
-#include <linux/dma-mapping.h>
-#include <linux/serial.h>
-#include <linux/serial_8250.h>
#include <linux/leds.h>
#include <linux/gpio.h>
-#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/i2c/at24.h>
#include <linux/i2c/pcf857x.h>
-#include <linux/etherdevice.h>
#include <media/tvp514x.h>
-#include <asm/setup.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/flash.h>
#include <mach/dm646x.h>
#include <mach/common.h>
-#include <mach/psc.h>
#include <mach/serial.h>
#include <mach/i2c.h>
-#include <mach/mmc.h>
-#include <mach/emac.h>
+#include <mach/nand.h>
#if defined(CONFIG_BLK_DEV_PALMCHIP_BK3710) || \
defined(CONFIG_BLK_DEV_PALMCHIP_BK3710_MODULE)
@@ -57,6 +47,11 @@
#define HAS_ATA 0
#endif
+#define DAVINCI_ASYNC_EMIF_CONTROL_BASE 0x20008000
+#define DAVINCI_ASYNC_EMIF_DATA_CE0_BASE 0x42000000
+
+#define NAND_BLOCK_SIZE SZ_128K
+
/* CPLD Register 0 bits to control ATA */
#define DM646X_EVM_ATA_RST BIT(0)
#define DM646X_EVM_ATA_PWD BIT(1)
@@ -92,6 +87,63 @@ static struct davinci_uart_config uart_config __initdata = {
.enabled_uarts = (1 << 0),
};
+/* Note: We are setting first partition as 'bootloader' constituting UBL, U-Boot
+ * and U-Boot environment this avoids dependency on any particular combination
+ * of UBL, U-Boot or flashing tools etc.
+ */
+static struct mtd_partition davinci_nand_partitions[] = {
+ {
+ /* UBL, U-Boot with environment */
+ .name = "bootloader",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 16 * NAND_BLOCK_SIZE,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ }, {
+ .name = "kernel",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_4M,
+ .mask_flags = 0,
+ }, {
+ .name = "filesystem",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL,
+ .mask_flags = 0,
+ }
+};
+
+static struct davinci_nand_pdata davinci_nand_data = {
+ .mask_cle = 0x80000,
+ .mask_ale = 0x40000,
+ .parts = davinci_nand_partitions,
+ .nr_parts = ARRAY_SIZE(davinci_nand_partitions),
+ .ecc_mode = NAND_ECC_HW,
+ .options = 0,
+};
+
+static struct resource davinci_nand_resources[] = {
+ {
+ .start = DAVINCI_ASYNC_EMIF_DATA_CE0_BASE,
+ .end = DAVINCI_ASYNC_EMIF_DATA_CE0_BASE + SZ_32M - 1,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = DAVINCI_ASYNC_EMIF_CONTROL_BASE,
+ .end = DAVINCI_ASYNC_EMIF_CONTROL_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device davinci_nand_device = {
+ .name = "davinci_nand",
+ .id = 0,
+
+ .num_resources = ARRAY_SIZE(davinci_nand_resources),
+ .resource = davinci_nand_resources,
+
+ .dev = {
+ .platform_data = &davinci_nand_data,
+ },
+};
+
/* CPLD Register 0 Client: used for I/O Control */
static int cpld_reg0_probe(struct i2c_client *client,
const struct i2c_device_id *id)
@@ -142,7 +194,7 @@ static struct gpio_led evm_leds[] = {
{ .name = "DS4", .active_low = 1, },
};
-static __initconst struct gpio_led_platform_data evm_led_data = {
+static const struct gpio_led_platform_data evm_led_data = {
.num_leds = ARRAY_SIZE(evm_leds),
.leds = evm_leds,
};
@@ -647,6 +699,8 @@ static __init void evm_init(void)
dm646x_init_mcasp0(&dm646x_evm_snd_data[0]);
dm646x_init_mcasp1(&dm646x_evm_snd_data[1]);
+ platform_device_register(&davinci_nand_device);
+
if (HAS_ATA)
dm646x_init_ide();
diff --git a/arch/arm/mach-davinci/board-neuros-osd2.c b/arch/arm/mach-davinci/board-neuros-osd2.c
new file mode 100644
index 0000000..bd9ca07
--- /dev/null
+++ b/arch/arm/mach-davinci/board-neuros-osd2.c
@@ -0,0 +1,323 @@
+/*
+ * Neuros Technologies OSD2 board support
+ *
+ * Modified from original 644X-EVM board support.
+ * 2008 (c) Neuros Technology, LLC.
+ * 2009 (c) Jorge Luis Zapata Muga <jorgeluis.zapata@gmail.com>
+ * 2009 (c) Andrey A. Porodko <Andrey.Porodko@gmail.com>
+ *
+ * The Neuros OSD 2.0 is the hardware component of the Neuros Open
+ * Internet Television Platform. Hardware is very close to TI
+ * DM644X-EVM board. It has:
+ * DM6446M02 module with 256MB NAND, 256MB RAM, TLV320AIC32 AIC,
+ * USB, Ethernet, SD/MMC, UART, THS8200, TVP7000 for video.
+ * Additionaly realtime clock, IR remote control receiver,
+ * IR Blaster based on MSP430 (firmware although is different
+ * from used in DM644X-EVM), internal ATA-6 3.5” HDD drive
+ * with PATA interface, two muxed red-green leds.
+ *
+ * For more information please refer to
+ * http://wiki.neurostechnology.com/index.php/OSD_2.0_HD
+ *
+ * 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/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <mach/dm644x.h>
+#include <mach/i2c.h>
+#include <mach/serial.h>
+#include <mach/mux.h>
+#include <mach/nand.h>
+#include <mach/mmc.h>
+#include <mach/usb.h>
+
+#define NEUROS_OSD2_PHY_MASK 0x2
+#define NEUROS_OSD2_MDIO_FREQUENCY 2200000 /* PHY bus frequency */
+
+#define DAVINCI_CFC_ATA_BASE 0x01C66000
+
+#define DAVINCI_ASYNC_EMIF_CONTROL_BASE 0x01e00000
+#define DAVINCI_ASYNC_EMIF_DATA_CE0_BASE 0x02000000
+
+#define LXT971_PHY_ID 0x001378e2
+#define LXT971_PHY_MASK 0xfffffff0
+
+#define NTOSD2_AUDIOSOC_I2C_ADDR 0x18
+#define NTOSD2_MSP430_I2C_ADDR 0x59
+#define NTOSD2_MSP430_IRQ 2
+
+/* Neuros OSD2 has a Samsung 256 MByte NAND flash (Dev ID of 0xAA,
+ * 2048 blocks in the device, 64 pages per block, 2048 bytes per
+ * page.
+ */
+
+#define NAND_BLOCK_SIZE SZ_128K
+
+struct mtd_partition davinci_ntosd2_nandflash_partition[] = {
+ {
+ /* UBL (a few copies) plus U-Boot */
+ .name = "bootloader",
+ .offset = 0,
+ .size = 15 * NAND_BLOCK_SIZE,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ }, {
+ /* U-Boot environment */
+ .name = "params",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 1 * NAND_BLOCK_SIZE,
+ .mask_flags = 0,
+ }, {
+ /* Kernel */
+ .name = "kernel",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_4M,
+ .mask_flags = 0,
+ }, {
+ /* File System */
+ .name = "filesystem",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL,
+ .mask_flags = 0,
+ }
+ /* A few blocks at end hold a flash Bad Block Table. */
+};
+
+static struct davinci_nand_pdata davinci_ntosd2_nandflash_data = {
+ .parts = davinci_ntosd2_nandflash_partition,
+ .nr_parts = ARRAY_SIZE(davinci_ntosd2_nandflash_partition),
+ .ecc_mode = NAND_ECC_HW,
+ .options = NAND_USE_FLASH_BBT,
+};
+
+static struct resource davinci_ntosd2_nandflash_resource[] = {
+ {
+ .start = DAVINCI_ASYNC_EMIF_DATA_CE0_BASE,
+ .end = DAVINCI_ASYNC_EMIF_DATA_CE0_BASE + SZ_16M - 1,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = DAVINCI_ASYNC_EMIF_CONTROL_BASE,
+ .end = DAVINCI_ASYNC_EMIF_CONTROL_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device davinci_ntosd2_nandflash_device = {
+ .name = "davinci_nand",
+ .id = 0,
+ .dev = {
+ .platform_data = &davinci_ntosd2_nandflash_data,
+ },
+ .num_resources = ARRAY_SIZE(davinci_ntosd2_nandflash_resource),
+ .resource = davinci_ntosd2_nandflash_resource,
+};
+
+static u64 davinci_fb_dma_mask = DMA_BIT_MASK(32);
+
+static struct platform_device davinci_fb_device = {
+ .name = "davincifb",
+ .id = -1,
+ .dev = {
+ .dma_mask = &davinci_fb_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+ .num_resources = 0,
+};
+
+static struct resource ide_resources[] = {
+ {
+ .start = DAVINCI_CFC_ATA_BASE,
+ .end = DAVINCI_CFC_ATA_BASE + 0x7ff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_IDE,
+ .end = IRQ_IDE,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static u64 ide_dma_mask = DMA_BIT_MASK(32);
+
+static struct platform_device ide_dev = {
+ .name = "palm_bk3710",
+ .id = -1,
+ .resource = ide_resources,
+ .num_resources = ARRAY_SIZE(ide_resources),
+ .dev = {
+ .dma_mask = &ide_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
+static struct snd_platform_data dm644x_ntosd2_snd_data;
+
+static struct gpio_led ntosd2_leds[] = {
+ { .name = "led1_green", .gpio = GPIO(10), },
+ { .name = "led1_red", .gpio = GPIO(11), },
+ { .name = "led2_green", .gpio = GPIO(12), },
+ { .name = "led2_red", .gpio = GPIO(13), },
+};
+
+static struct gpio_led_platform_data ntosd2_leds_data = {
+ .num_leds = ARRAY_SIZE(ntosd2_leds),
+ .leds = ntosd2_leds,
+};
+
+static struct platform_device ntosd2_leds_dev = {
+ .name = "leds-gpio",
+ .id = -1,
+ .dev = {
+ .platform_data = &ntosd2_leds_data,
+ },
+};
+
+
+static struct platform_device *davinci_ntosd2_devices[] __initdata = {
+ &davinci_fb_device,
+ &ntosd2_leds_dev,
+};
+
+static struct davinci_uart_config uart_config __initdata = {
+ .enabled_uarts = (1 << 0),
+};
+
+static void __init davinci_ntosd2_map_io(void)
+{
+ dm644x_init();
+}
+
+/*
+ I2C initialization
+*/
+static struct davinci_i2c_platform_data ntosd2_i2c_pdata = {
+ .bus_freq = 20 /* kHz */,
+ .bus_delay = 100 /* usec */,
+};
+
+static struct i2c_board_info __initdata ntosd2_i2c_info[] = {
+};
+
+static int ntosd2_init_i2c(void)
+{
+ int status;
+
+ davinci_init_i2c(&ntosd2_i2c_pdata);
+ status = gpio_request(NTOSD2_MSP430_IRQ, ntosd2_i2c_info[0].type);
+ if (status == 0) {
+ status = gpio_direction_input(NTOSD2_MSP430_IRQ);
+ if (status == 0) {
+ status = gpio_to_irq(NTOSD2_MSP430_IRQ);
+ if (status > 0) {
+ ntosd2_i2c_info[0].irq = status;
+ i2c_register_board_info(1,
+ ntosd2_i2c_info,
+ ARRAY_SIZE(ntosd2_i2c_info));
+ }
+ }
+ }
+ return status;
+}
+
+static struct davinci_mmc_config davinci_ntosd2_mmc_config = {
+ .wires = 4,
+ .version = MMC_CTLR_VERSION_1
+};
+
+
+#if defined(CONFIG_BLK_DEV_PALMCHIP_BK3710) || \
+ defined(CONFIG_BLK_DEV_PALMCHIP_BK3710_MODULE)
+#define HAS_ATA 1
+#else
+#define HAS_ATA 0
+#endif
+
+#if defined(CONFIG_MTD_NAND_DAVINCI) || \
+ defined(CONFIG_MTD_NAND_DAVINCI_MODULE)
+#define HAS_NAND 1
+#else
+#define HAS_NAND 0
+#endif
+
+static __init void davinci_ntosd2_init(void)
+{
+ struct clk *aemif_clk;
+ struct davinci_soc_info *soc_info = &davinci_soc_info;
+ int status;
+
+ aemif_clk = clk_get(NULL, "aemif");
+ clk_enable(aemif_clk);
+
+ if (HAS_ATA) {
+ if (HAS_NAND)
+ pr_warning("WARNING: both IDE and Flash are "
+ "enabled, but they share AEMIF pins.\n"
+ "\tDisable IDE for NAND/NOR support.\n");
+ davinci_cfg_reg(DM644X_HPIEN_DISABLE);
+ davinci_cfg_reg(DM644X_ATAEN);
+ davinci_cfg_reg(DM644X_HDIREN);
+ platform_device_register(&ide_dev);
+ } else if (HAS_NAND) {
+ davinci_cfg_reg(DM644X_HPIEN_DISABLE);
+ davinci_cfg_reg(DM644X_ATAEN_DISABLE);
+
+ /* only one device will be jumpered and detected */
+ if (HAS_NAND)
+ platform_device_register(
+ &davinci_ntosd2_nandflash_device);
+ }
+
+ platform_add_devices(davinci_ntosd2_devices,
+ ARRAY_SIZE(davinci_ntosd2_devices));
+
+ /* Initialize I2C interface specific for this board */
+ status = ntosd2_init_i2c();
+ if (status < 0)
+ pr_warning("davinci_ntosd2_init: msp430 irq setup failed:"
+ " %d\n", status);
+
+ davinci_serial_init(&uart_config);
+ dm644x_init_asp(&dm644x_ntosd2_snd_data);
+
+ soc_info->emac_pdata->phy_mask = NEUROS_OSD2_PHY_MASK;
+ soc_info->emac_pdata->mdio_max_freq = NEUROS_OSD2_MDIO_FREQUENCY;
+
+ davinci_setup_usb(1000, 8);
+ /*
+ * Mux the pins to be GPIOs, VLYNQEN is already done at startup.
+ * The AEAWx are five new AEAW pins that can be muxed by separately.
+ * They are a bitmask for GPIO management. According TI
+ * documentation (http://www.ti.com/lit/gpn/tms320dm6446) to employ
+ * gpio(10,11,12,13) for leds any combination of bits works except
+ * four last. So we are to reset all five.
+ */
+ davinci_cfg_reg(DM644X_AEAW0);
+ davinci_cfg_reg(DM644X_AEAW1);
+ davinci_cfg_reg(DM644X_AEAW2);
+ davinci_cfg_reg(DM644X_AEAW3);
+ davinci_cfg_reg(DM644X_AEAW4);
+
+ davinci_setup_mmc(0, &davinci_ntosd2_mmc_config);
+}
+
+static __init void davinci_ntosd2_irq_init(void)
+{
+ davinci_irq_init();
+}
+
+MACHINE_START(NEUROS_OSD2, "Neuros OSD2")
+ /* Maintainer: Neuros Technologies <neuros@groups.google.com> */
+ .phys_io = IO_PHYS,
+ .io_pg_offst = (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc,
+ .boot_params = (DAVINCI_DDR_BASE + 0x100),
+ .map_io = davinci_ntosd2_map_io,
+ .init_irq = davinci_ntosd2_irq_init,
+ .timer = &davinci_timer,
+ .init_machine = davinci_ntosd2_init,
+MACHINE_END
diff --git a/arch/arm/mach-davinci/board-sffsdr.c b/arch/arm/mach-davinci/board-sffsdr.c
index 7acdfd8..08d373b 100644
--- a/arch/arm/mach-davinci/board-sffsdr.c
+++ b/arch/arm/mach-davinci/board-sffsdr.c
@@ -23,35 +23,24 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/init.h>
-#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
-#include <linux/gpio.h>
-
#include <linux/i2c.h>
#include <linux/i2c/at24.h>
-#include <linux/etherdevice.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
-#include <linux/mtd/physmap.h>
-#include <linux/io.h>
-#include <asm/setup.h>
#include <asm/mach-types.h>
-
#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
#include <asm/mach/flash.h>
#include <mach/dm644x.h>
#include <mach/common.h>
#include <mach/i2c.h>
#include <mach/serial.h>
-#include <mach/psc.h>
#include <mach/mux.h>
+#include <mach/usb.h>
#define SFFSDR_PHY_MASK (0x2)
#define SFFSDR_MDIO_FREQUENCY (2200000) /* PHY bus frequency */
@@ -107,11 +96,6 @@ static struct platform_device davinci_sffsdr_nandflash_device = {
.resource = davinci_sffsdr_nandflash_resource,
};
-static struct emac_platform_data sffsdr_emac_pdata = {
- .phy_mask = SFFSDR_PHY_MASK,
- .mdio_max_freq = SFFSDR_MDIO_FREQUENCY,
-};
-
static struct at24_platform_data eeprom_info = {
.byte_len = (64*1024) / 8,
.page_size = 32,
@@ -164,7 +148,7 @@ static __init void davinci_sffsdr_init(void)
davinci_serial_init(&uart_config);
soc_info->emac_pdata->phy_mask = SFFSDR_PHY_MASK;
soc_info->emac_pdata->mdio_max_freq = SFFSDR_MDIO_FREQUENCY;
- setup_usb(0, 0); /* We support only peripheral mode. */
+ davinci_setup_usb(0, 0); /* We support only peripheral mode. */
/* mux VLYNQ pins */
davinci_cfg_reg(DM644X_VLYNQEN);
diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c
index 83d54d5..baece65 100644
--- a/arch/arm/mach-davinci/clock.c
+++ b/arch/arm/mach-davinci/clock.c
@@ -17,8 +17,8 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/mutex.h>
-#include <linux/platform_device.h>
#include <linux/io.h>
+#include <linux/delay.h>
#include <mach/hardware.h>
@@ -42,8 +42,7 @@ static void __clk_enable(struct clk *clk)
if (clk->parent)
__clk_enable(clk->parent);
if (clk->usecount++ == 0 && (clk->flags & CLK_PSC))
- davinci_psc_config(psc_domain(clk), clk->psc_ctlr,
- clk->lpsc, 1);
+ davinci_psc_config(psc_domain(clk), clk->gpsc, clk->lpsc, 1);
}
static void __clk_disable(struct clk *clk)
@@ -51,8 +50,7 @@ static void __clk_disable(struct clk *clk)
if (WARN_ON(clk->usecount == 0))
return;
if (--clk->usecount == 0 && !(clk->flags & CLK_PLL))
- davinci_psc_config(psc_domain(clk), clk->psc_ctlr,
- clk->lpsc, 0);
+ davinci_psc_config(psc_domain(clk), clk->gpsc, clk->lpsc, 0);
if (clk->parent)
__clk_disable(clk->parent);
}
@@ -99,20 +97,74 @@ long clk_round_rate(struct clk *clk, unsigned long rate)
if (clk == NULL || IS_ERR(clk))
return -EINVAL;
+ if (clk->round_rate)
+ return clk->round_rate(clk, rate);
+
return clk->rate;
}
EXPORT_SYMBOL(clk_round_rate);
+/* Propagate rate to children */
+static void propagate_rate(struct clk *root)
+{
+ struct clk *clk;
+
+ list_for_each_entry(clk, &root->children, childnode) {
+ if (clk->recalc)
+ clk->rate = clk->recalc(clk);
+ propagate_rate(clk);
+ }
+}
+
int clk_set_rate(struct clk *clk, unsigned long rate)
{
+ unsigned long flags;
+ int ret = -EINVAL;
+
if (clk == NULL || IS_ERR(clk))
- return -EINVAL;
+ return ret;
- /* changing the clk rate is not supported */
- return -EINVAL;
+ spin_lock_irqsave(&clockfw_lock, flags);
+ if (clk->set_rate)
+ ret = clk->set_rate(clk, rate);
+ if (ret == 0) {
+ if (clk->recalc)
+ clk->rate = clk->recalc(clk);
+ propagate_rate(clk);
+ }
+ spin_unlock_irqrestore(&clockfw_lock, flags);
+
+ return ret;
}
EXPORT_SYMBOL(clk_set_rate);
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ unsigned long flags;
+
+ if (clk == NULL || IS_ERR(clk))
+ return -EINVAL;
+
+ /* Cannot change parent on enabled clock */
+ if (WARN_ON(clk->usecount))
+ return -EINVAL;
+
+ mutex_lock(&clocks_mutex);
+ clk->parent = parent;
+ list_del_init(&clk->childnode);
+ list_add(&clk->childnode, &clk->parent->children);
+ mutex_unlock(&clocks_mutex);
+
+ spin_lock_irqsave(&clockfw_lock, flags);
+ if (clk->recalc)
+ clk->rate = clk->recalc(clk);
+ propagate_rate(clk);
+ spin_unlock_irqrestore(&clockfw_lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(clk_set_parent);
+
int clk_register(struct clk *clk)
{
if (clk == NULL || IS_ERR(clk))
@@ -123,16 +175,24 @@ int clk_register(struct clk *clk)
clk->name, clk->parent->name))
return -EINVAL;
+ INIT_LIST_HEAD(&clk->children);
+
mutex_lock(&clocks_mutex);
list_add_tail(&clk->node, &clocks);
+ if (clk->parent)
+ list_add_tail(&clk->childnode, &clk->parent->children);
mutex_unlock(&clocks_mutex);
/* If rate is already set, use it */
if (clk->rate)
return 0;
+ /* Else, see if there is a way to calculate it */
+ if (clk->recalc)
+ clk->rate = clk->recalc(clk);
+
/* Otherwise, default to parent rate */
- if (clk->parent)
+ else if (clk->parent)
clk->rate = clk->parent->rate;
return 0;
@@ -146,6 +206,7 @@ void clk_unregister(struct clk *clk)
mutex_lock(&clocks_mutex);
list_del(&clk->node);
+ list_del(&clk->childnode);
mutex_unlock(&clocks_mutex);
}
EXPORT_SYMBOL(clk_unregister);
@@ -166,11 +227,11 @@ static int __init clk_disable_unused(void)
continue;
/* ignore if in Disabled or SwRstDisable states */
- if (!davinci_psc_is_clk_active(ck->psc_ctlr, ck->lpsc))
+ if (!davinci_psc_is_clk_active(ck->gpsc, ck->lpsc))
continue;
pr_info("Clocks: disable unused %s\n", ck->name);
- davinci_psc_config(psc_domain(ck), ck->psc_ctlr, ck->lpsc, 0);
+ davinci_psc_config(psc_domain(ck), ck->gpsc, ck->lpsc, 0);
}
spin_unlock_irq(&clockfw_lock);
@@ -179,50 +240,62 @@ static int __init clk_disable_unused(void)
late_initcall(clk_disable_unused);
#endif
-static void clk_sysclk_recalc(struct clk *clk)
+static unsigned long clk_sysclk_recalc(struct clk *clk)
{
u32 v, plldiv;
struct pll_data *pll;
+ unsigned long rate = clk->rate;
/* If this is the PLL base clock, no more calculations needed */
if (clk->pll_data)
- return;
+ return rate;
if (WARN_ON(!clk->parent))
- return;
+ return rate;
- clk->rate = clk->parent->rate;
+ rate = clk->parent->rate;
/* Otherwise, the parent must be a PLL */
if (WARN_ON(!clk->parent->pll_data))
- return;
+ return rate;
pll = clk->parent->pll_data;
/* If pre-PLL, source clock is before the multiplier and divider(s) */
if (clk->flags & PRE_PLL)
- clk->rate = pll->input_rate;
+ rate = pll->input_rate;
if (!clk->div_reg)
- return;
+ return rate;
v = __raw_readl(pll->base + clk->div_reg);
if (v & PLLDIV_EN) {
plldiv = (v & PLLDIV_RATIO_MASK) + 1;
if (plldiv)
- clk->rate /= plldiv;
+ rate /= plldiv;
}
+
+ return rate;
+}
+
+static unsigned long clk_leafclk_recalc(struct clk *clk)
+{
+ if (WARN_ON(!clk->parent))
+ return clk->rate;
+
+ return clk->parent->rate;
}
-static void __init clk_pll_init(struct clk *clk)
+static unsigned long clk_pllclk_recalc(struct clk *clk)
{
u32 ctrl, mult = 1, prediv = 1, postdiv = 1;
u8 bypass;
struct pll_data *pll = clk->pll_data;
+ unsigned long rate = clk->rate;
pll->base = IO_ADDRESS(pll->phys_base);
ctrl = __raw_readl(pll->base + PLLCTL);
- clk->rate = pll->input_rate = clk->parent->rate;
+ rate = pll->input_rate = clk->parent->rate;
if (ctrl & PLLCTL_PLLEN) {
bypass = 0;
@@ -255,9 +328,9 @@ static void __init clk_pll_init(struct clk *clk)
}
if (!bypass) {
- clk->rate /= prediv;
- clk->rate *= mult;
- clk->rate /= postdiv;
+ rate /= prediv;
+ rate *= mult;
+ rate /= postdiv;
}
pr_debug("PLL%d: input = %lu MHz [ ",
@@ -270,8 +343,90 @@ static void __init clk_pll_init(struct clk *clk)
pr_debug("* %d ", mult);
if (postdiv > 1)
pr_debug("/ %d ", postdiv);
- pr_debug("] --> %lu MHz output.\n", clk->rate / 1000000);
+ pr_debug("] --> %lu MHz output.\n", rate / 1000000);
+
+ return rate;
+}
+
+/**
+ * davinci_set_pllrate - set the output rate of a given PLL.
+ *
+ * Note: Currently tested to work with OMAP-L138 only.
+ *
+ * @pll: pll whose rate needs to be changed.
+ * @prediv: The pre divider value. Passing 0 disables the pre-divider.
+ * @pllm: The multiplier value. Passing 0 leads to multiply-by-one.
+ * @postdiv: The post divider value. Passing 0 disables the post-divider.
+ */
+int davinci_set_pllrate(struct pll_data *pll, unsigned int prediv,
+ unsigned int mult, unsigned int postdiv)
+{
+ u32 ctrl;
+ unsigned int locktime;
+
+ if (pll->base == NULL)
+ return -EINVAL;
+
+ /*
+ * PLL lock time required per OMAP-L138 datasheet is
+ * (2000 * prediv)/sqrt(pllm) OSCIN cycles. We approximate sqrt(pllm)
+ * as 4 and OSCIN cycle as 25 MHz.
+ */
+ if (prediv) {
+ locktime = ((2000 * prediv) / 100);
+ prediv = (prediv - 1) | PLLDIV_EN;
+ } else {
+ locktime = 20;
+ }
+ if (postdiv)
+ postdiv = (postdiv - 1) | PLLDIV_EN;
+ if (mult)
+ mult = mult - 1;
+
+ ctrl = __raw_readl(pll->base + PLLCTL);
+
+ /* Switch the PLL to bypass mode */
+ ctrl &= ~(PLLCTL_PLLENSRC | PLLCTL_PLLEN);
+ __raw_writel(ctrl, pll->base + PLLCTL);
+
+ /*
+ * Wait for 4 OSCIN/CLKIN cycles to ensure that the PLLC has switched
+ * to bypass mode. Delay of 1us ensures we are good for all > 4MHz
+ * OSCIN/CLKIN inputs. Typically the input is ~25MHz.
+ */
+ udelay(1);
+
+ /* Reset and enable PLL */
+ ctrl &= ~(PLLCTL_PLLRST | PLLCTL_PLLDIS);
+ __raw_writel(ctrl, pll->base + PLLCTL);
+
+ if (pll->flags & PLL_HAS_PREDIV)
+ __raw_writel(prediv, pll->base + PREDIV);
+
+ __raw_writel(mult, pll->base + PLLM);
+
+ if (pll->flags & PLL_HAS_POSTDIV)
+ __raw_writel(postdiv, pll->base + POSTDIV);
+
+ /*
+ * Wait for PLL to reset properly, OMAP-L138 datasheet says
+ * 'min' time = 125ns
+ */
+ udelay(1);
+
+ /* Bring PLL out of reset */
+ ctrl |= PLLCTL_PLLRST;
+ __raw_writel(ctrl, pll->base + PLLCTL);
+
+ udelay(locktime);
+
+ /* Remove PLL from bypass mode */
+ ctrl |= PLLCTL_PLLEN;
+ __raw_writel(ctrl, pll->base + PLLCTL);
+
+ return 0;
}
+EXPORT_SYMBOL(davinci_set_pllrate);
int __init davinci_clk_init(struct davinci_clk *clocks)
{
@@ -281,12 +436,23 @@ int __init davinci_clk_init(struct davinci_clk *clocks)
for (c = clocks; c->lk.clk; c++) {
clk = c->lk.clk;
- if (clk->pll_data)
- clk_pll_init(clk);
+ if (!clk->recalc) {
+
+ /* Check if clock is a PLL */
+ if (clk->pll_data)
+ clk->recalc = clk_pllclk_recalc;
+
+ /* Else, if it is a PLL-derived clock */
+ else if (clk->flags & CLK_PLL)
+ clk->recalc = clk_sysclk_recalc;
+
+ /* Otherwise, it is a leaf clock (PSC clock) */
+ else if (clk->parent)
+ clk->recalc = clk_leafclk_recalc;
+ }
- /* Calculate rates for PLL-derived clocks */
- else if (clk->flags & CLK_PLL)
- clk_sysclk_recalc(clk);
+ if (clk->recalc)
+ clk->rate = clk->recalc(clk);
if (clk->lpsc)
clk->flags |= CLK_PSC;
@@ -352,9 +518,8 @@ dump_clock(struct seq_file *s, unsigned nest, struct clk *parent)
/* REVISIT show device associations too */
/* cost is now small, but not linear... */
- list_for_each_entry(clk, &clocks, node) {
- if (clk->parent == parent)
- dump_clock(s, nest + NEST_DELTA, clk);
+ list_for_each_entry(clk, &parent->children, childnode) {
+ dump_clock(s, nest + NEST_DELTA, clk);
}
}
diff --git a/arch/arm/mach-davinci/clock.h b/arch/arm/mach-davinci/clock.h
index 27233cb..c92d77a 100644
--- a/arch/arm/mach-davinci/clock.h
+++ b/arch/arm/mach-davinci/clock.h
@@ -22,6 +22,10 @@
/* PLL/Reset register offsets */
#define PLLCTL 0x100
#define PLLCTL_PLLEN BIT(0)
+#define PLLCTL_PLLPWRDN BIT(1)
+#define PLLCTL_PLLRST BIT(3)
+#define PLLCTL_PLLDIS BIT(4)
+#define PLLCTL_PLLENSRC BIT(5)
#define PLLCTL_CLKMODE BIT(8)
#define PLLM 0x110
@@ -65,15 +69,20 @@ struct clk {
const char *name;
unsigned long rate;
u8 usecount;
- u8 flags;
u8 lpsc;
- u8 psc_ctlr;
+ u8 gpsc;
+ u32 flags;
struct clk *parent;
+ struct list_head children; /* list of children */
+ struct list_head childnode; /* parent's child list node */
struct pll_data *pll_data;
u32 div_reg;
+ unsigned long (*recalc) (struct clk *);
+ int (*set_rate) (struct clk *clk, unsigned long rate);
+ int (*round_rate) (struct clk *clk, unsigned long rate);
};
-/* Clock flags */
+/* Clock flags: SoC-specific flags start at BIT(16) */
#define ALWAYS_ENABLED BIT(1)
#define CLK_PSC BIT(2)
#define PSC_DSP BIT(3) /* PSC uses DSP domain, not ARM */
@@ -94,6 +103,8 @@ struct davinci_clk {
}
int davinci_clk_init(struct davinci_clk *clocks);
+int davinci_set_pllrate(struct pll_data *pll, unsigned int prediv,
+ unsigned int mult, unsigned int postdiv);
extern struct platform_device davinci_wdt_device;
diff --git a/arch/arm/mach-davinci/common.c b/arch/arm/mach-davinci/common.c
index 61ede19..c2de94c 100644
--- a/arch/arm/mach-davinci/common.c
+++ b/arch/arm/mach-davinci/common.c
@@ -86,6 +86,8 @@ void __init davinci_common_init(struct davinci_soc_info *soc_info)
dip = davinci_get_id(davinci_soc_info.jtag_id);
if (!dip) {
ret = -EINVAL;
+ pr_err("Unknown DaVinci JTAG ID 0x%x\n",
+ davinci_soc_info.jtag_id);
goto err;
}
@@ -104,5 +106,5 @@ void __init davinci_common_init(struct davinci_soc_info *soc_info)
return;
err:
- pr_err("davinci_common_init: SoC Initialization failed\n");
+ panic("davinci_common_init: SoC Initialization failed\n");
}
diff --git a/arch/arm/mach-davinci/cp_intc.c b/arch/arm/mach-davinci/cp_intc.c
index 96c8e97..52b287c 100644
--- a/arch/arm/mach-davinci/cp_intc.c
+++ b/arch/arm/mach-davinci/cp_intc.c
@@ -10,9 +10,6 @@
*/
#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
#include <linux/irq.h>
#include <linux/io.h>
diff --git a/arch/arm/mach-davinci/cpufreq.c b/arch/arm/mach-davinci/cpufreq.c
new file mode 100644
index 0000000..d3fa6de
--- /dev/null
+++ b/arch/arm/mach-davinci/cpufreq.c
@@ -0,0 +1,226 @@
+/*
+ * CPU frequency scaling for DaVinci
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * Based on linux/arch/arm/plat-omap/cpu-omap.c. Original Copyright follows:
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Written by Tony Lindgren <tony@atomide.com>
+ *
+ * Based on cpu-sa1110.c, Copyright (C) 2001 Russell King
+ *
+ * Copyright (C) 2007-2008 Texas Instruments, Inc.
+ * Updated to support OMAP3
+ * Rajendra Nayak <rnayak@ti.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/types.h>
+#include <linux/cpufreq.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+#include <mach/hardware.h>
+#include <mach/cpufreq.h>
+#include <mach/common.h>
+
+#include "clock.h"
+
+struct davinci_cpufreq {
+ struct device *dev;
+ struct clk *armclk;
+};
+static struct davinci_cpufreq cpufreq;
+
+static int davinci_verify_speed(struct cpufreq_policy *policy)
+{
+ struct davinci_cpufreq_config *pdata = cpufreq.dev->platform_data;
+ struct cpufreq_frequency_table *freq_table = pdata->freq_table;
+ struct clk *armclk = cpufreq.armclk;
+
+ if (freq_table)
+ return cpufreq_frequency_table_verify(policy, freq_table);
+
+ if (policy->cpu)
+ return -EINVAL;
+
+ cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
+ policy->cpuinfo.max_freq);
+
+ policy->min = clk_round_rate(armclk, policy->min * 1000) / 1000;
+ policy->max = clk_round_rate(armclk, policy->max * 1000) / 1000;
+ cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
+ policy->cpuinfo.max_freq);
+ return 0;
+}
+
+static unsigned int davinci_getspeed(unsigned int cpu)
+{
+ if (cpu)
+ return 0;
+
+ return clk_get_rate(cpufreq.armclk) / 1000;
+}
+
+static int davinci_target(struct cpufreq_policy *policy,
+ unsigned int target_freq, unsigned int relation)
+{
+ int ret = 0;
+ unsigned int idx;
+ struct cpufreq_freqs freqs;
+ struct davinci_cpufreq_config *pdata = cpufreq.dev->platform_data;
+ struct clk *armclk = cpufreq.armclk;
+
+ /*
+ * Ensure desired rate is within allowed range. Some govenors
+ * (ondemand) will just pass target_freq=0 to get the minimum.
+ */
+ if (target_freq < policy->cpuinfo.min_freq)
+ target_freq = policy->cpuinfo.min_freq;
+ if (target_freq > policy->cpuinfo.max_freq)
+ target_freq = policy->cpuinfo.max_freq;
+
+ freqs.old = davinci_getspeed(0);
+ freqs.new = clk_round_rate(armclk, target_freq * 1000) / 1000;
+ freqs.cpu = 0;
+
+ if (freqs.old == freqs.new)
+ return ret;
+
+ cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER,
+ dev_driver_string(cpufreq.dev),
+ "transition: %u --> %u\n", freqs.old, freqs.new);
+
+ ret = cpufreq_frequency_table_target(policy, pdata->freq_table,
+ freqs.new, relation, &idx);
+ if (ret)
+ return -EINVAL;
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+ /* if moving to higher frequency, up the voltage beforehand */
+ if (pdata->set_voltage && freqs.new > freqs.old)
+ pdata->set_voltage(idx);
+
+ ret = clk_set_rate(armclk, idx);
+
+ /* if moving to lower freq, lower the voltage after lowering freq */
+ if (pdata->set_voltage && freqs.new < freqs.old)
+ pdata->set_voltage(idx);
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+ return ret;
+}
+
+static int __init davinci_cpu_init(struct cpufreq_policy *policy)
+{
+ int result = 0;
+ struct davinci_cpufreq_config *pdata = cpufreq.dev->platform_data;
+ struct cpufreq_frequency_table *freq_table = pdata->freq_table;
+
+ if (policy->cpu != 0)
+ return -EINVAL;
+
+ /* Finish platform specific initialization */
+ if (pdata->init) {
+ result = pdata->init();
+ if (result)
+ return result;
+ }
+
+ policy->cur = policy->min = policy->max = davinci_getspeed(0);
+
+ if (freq_table) {
+ result = cpufreq_frequency_table_cpuinfo(policy, freq_table);
+ if (!result)
+ cpufreq_frequency_table_get_attr(freq_table,
+ policy->cpu);
+ } else {
+ policy->cpuinfo.min_freq = policy->min;
+ policy->cpuinfo.max_freq = policy->max;
+ }
+
+ policy->min = policy->cpuinfo.min_freq;
+ policy->max = policy->cpuinfo.max_freq;
+ policy->cur = davinci_getspeed(0);
+
+ /*
+ * Time measurement across the target() function yields ~1500-1800us
+ * time taken with no drivers on notification list.
+ * Setting the latency to 2000 us to accomodate addition of drivers
+ * to pre/post change notification list.
+ */
+ policy->cpuinfo.transition_latency = 2000 * 1000;
+ return 0;
+}
+
+static int davinci_cpu_exit(struct cpufreq_policy *policy)
+{
+ cpufreq_frequency_table_put_attr(policy->cpu);
+ return 0;
+}
+
+static struct freq_attr *davinci_cpufreq_attr[] = {
+ &cpufreq_freq_attr_scaling_available_freqs,
+ NULL,
+};
+
+static struct cpufreq_driver davinci_driver = {
+ .flags = CPUFREQ_STICKY,
+ .verify = davinci_verify_speed,
+ .target = davinci_target,
+ .get = davinci_getspeed,
+ .init = davinci_cpu_init,
+ .exit = davinci_cpu_exit,
+ .name = "davinci",
+ .attr = davinci_cpufreq_attr,
+};
+
+static int __init davinci_cpufreq_probe(struct platform_device *pdev)
+{
+ struct davinci_cpufreq_config *pdata = pdev->dev.platform_data;
+
+ if (!pdata)
+ return -EINVAL;
+ if (!pdata->freq_table)
+ return -EINVAL;
+
+ cpufreq.dev = &pdev->dev;
+
+ cpufreq.armclk = clk_get(NULL, "arm");
+ if (IS_ERR(cpufreq.armclk)) {
+ dev_err(cpufreq.dev, "Unable to get ARM clock\n");
+ return PTR_ERR(cpufreq.armclk);
+ }
+
+ return cpufreq_register_driver(&davinci_driver);
+}
+
+static int __exit davinci_cpufreq_remove(struct platform_device *pdev)
+{
+ clk_put(cpufreq.armclk);
+
+ return cpufreq_unregister_driver(&davinci_driver);
+}
+
+static struct platform_driver davinci_cpufreq_driver = {
+ .driver = {
+ .name = "cpufreq-davinci",
+ .owner = THIS_MODULE,
+ },
+ .remove = __exit_p(davinci_cpufreq_remove),
+};
+
+static int __init davinci_cpufreq_init(void)
+{
+ return platform_driver_probe(&davinci_cpufreq_driver,
+ davinci_cpufreq_probe);
+}
+late_initcall(davinci_cpufreq_init);
+
diff --git a/arch/arm/mach-davinci/cpuidle.c b/arch/arm/mach-davinci/cpuidle.c
new file mode 100644
index 0000000..97a90f3
--- /dev/null
+++ b/arch/arm/mach-davinci/cpuidle.c
@@ -0,0 +1,197 @@
+/*
+ * CPU idle for DaVinci SoCs
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated. http://www.ti.com/
+ *
+ * Derived from Marvell Kirkwood CPU idle code
+ * (arch/arm/mach-kirkwood/cpuidle.c)
+ *
+ * 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/platform_device.h>
+#include <linux/cpuidle.h>
+#include <linux/io.h>
+#include <asm/proc-fns.h>
+
+#include <mach/cpuidle.h>
+
+#define DAVINCI_CPUIDLE_MAX_STATES 2
+
+struct davinci_ops {
+ void (*enter) (u32 flags);
+ void (*exit) (u32 flags);
+ u32 flags;
+};
+
+/* fields in davinci_ops.flags */
+#define DAVINCI_CPUIDLE_FLAGS_DDR2_PWDN BIT(0)
+
+static struct cpuidle_driver davinci_idle_driver = {
+ .name = "cpuidle-davinci",
+ .owner = THIS_MODULE,
+};
+
+static DEFINE_PER_CPU(struct cpuidle_device, davinci_cpuidle_device);
+static void __iomem *ddr2_reg_base;
+
+#define DDR2_SDRCR_OFFSET 0xc
+#define DDR2_SRPD_BIT BIT(23)
+#define DDR2_LPMODEN_BIT BIT(31)
+
+static void davinci_save_ddr_power(int enter, bool pdown)
+{
+ u32 val;
+
+ val = __raw_readl(ddr2_reg_base + DDR2_SDRCR_OFFSET);
+
+ if (enter) {
+ if (pdown)
+ val |= DDR2_SRPD_BIT;
+ else
+ val &= ~DDR2_SRPD_BIT;
+ val |= DDR2_LPMODEN_BIT;
+ } else {
+ val &= ~(DDR2_SRPD_BIT | DDR2_LPMODEN_BIT);
+ }
+
+ __raw_writel(val, ddr2_reg_base + DDR2_SDRCR_OFFSET);
+}
+
+static void davinci_c2state_enter(u32 flags)
+{
+ davinci_save_ddr_power(1, !!(flags & DAVINCI_CPUIDLE_FLAGS_DDR2_PWDN));
+}
+
+static void davinci_c2state_exit(u32 flags)
+{
+ davinci_save_ddr_power(0, !!(flags & DAVINCI_CPUIDLE_FLAGS_DDR2_PWDN));
+}
+
+static struct davinci_ops davinci_states[DAVINCI_CPUIDLE_MAX_STATES] = {
+ [1] = {
+ .enter = davinci_c2state_enter,
+ .exit = davinci_c2state_exit,
+ },
+};
+
+/* Actual code that puts the SoC in different idle states */
+static int davinci_enter_idle(struct cpuidle_device *dev,
+ struct cpuidle_state *state)
+{
+ struct davinci_ops *ops = cpuidle_get_statedata(state);
+ struct timeval before, after;
+ int idle_time;
+
+ local_irq_disable();
+ do_gettimeofday(&before);
+
+ if (ops && ops->enter)
+ ops->enter(ops->flags);
+ /* Wait for interrupt state */
+ cpu_do_idle();
+ if (ops && ops->exit)
+ ops->exit(ops->flags);
+
+ do_gettimeofday(&after);
+ local_irq_enable();
+ idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
+ (after.tv_usec - before.tv_usec);
+ return idle_time;
+}
+
+static int __init davinci_cpuidle_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct cpuidle_device *device;
+ struct davinci_cpuidle_config *pdata = pdev->dev.platform_data;
+ struct resource *ddr2_regs;
+ resource_size_t len;
+
+ device = &per_cpu(davinci_cpuidle_device, smp_processor_id());
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "cannot get platform data\n");
+ return -ENOENT;
+ }
+
+ ddr2_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!ddr2_regs) {
+ dev_err(&pdev->dev, "cannot get DDR2 controller register base");
+ return -ENODEV;
+ }
+
+ len = resource_size(ddr2_regs);
+
+ ddr2_regs = request_mem_region(ddr2_regs->start, len, ddr2_regs->name);
+ if (!ddr2_regs)
+ return -EBUSY;
+
+ ddr2_reg_base = ioremap(ddr2_regs->start, len);
+ if (!ddr2_reg_base) {
+ ret = -ENOMEM;
+ goto ioremap_fail;
+ }
+
+ ret = cpuidle_register_driver(&davinci_idle_driver);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register driver\n");
+ goto driver_register_fail;
+ }
+
+ /* Wait for interrupt state */
+ device->states[0].enter = davinci_enter_idle;
+ device->states[0].exit_latency = 1;
+ device->states[0].target_residency = 10000;
+ device->states[0].flags = CPUIDLE_FLAG_TIME_VALID;
+ strcpy(device->states[0].name, "WFI");
+ strcpy(device->states[0].desc, "Wait for interrupt");
+
+ /* Wait for interrupt and DDR self refresh state */
+ device->states[1].enter = davinci_enter_idle;
+ device->states[1].exit_latency = 10;
+ device->states[1].target_residency = 10000;
+ device->states[1].flags = CPUIDLE_FLAG_TIME_VALID;
+ strcpy(device->states[1].name, "DDR SR");
+ strcpy(device->states[1].desc, "WFI and DDR Self Refresh");
+ if (pdata->ddr2_pdown)
+ davinci_states[1].flags |= DAVINCI_CPUIDLE_FLAGS_DDR2_PWDN;
+ cpuidle_set_statedata(&device->states[1], &davinci_states[1]);
+
+ device->state_count = DAVINCI_CPUIDLE_MAX_STATES;
+
+ ret = cpuidle_register_device(device);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register device\n");
+ goto device_register_fail;
+ }
+
+ return 0;
+
+device_register_fail:
+ cpuidle_unregister_driver(&davinci_idle_driver);
+driver_register_fail:
+ iounmap(ddr2_reg_base);
+ioremap_fail:
+ release_mem_region(ddr2_regs->start, len);
+ return ret;
+}
+
+static struct platform_driver davinci_cpuidle_driver = {
+ .driver = {
+ .name = "cpuidle-davinci",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init davinci_cpuidle_init(void)
+{
+ return platform_driver_probe(&davinci_cpuidle_driver,
+ davinci_cpuidle_probe);
+}
+device_initcall(davinci_cpuidle_init);
+
diff --git a/arch/arm/mach-davinci/da830.c b/arch/arm/mach-davinci/da830.c
index 19b2748..b22b5cf 100644
--- a/arch/arm/mach-davinci/da830.c
+++ b/arch/arm/mach-davinci/da830.c
@@ -8,22 +8,17 @@
* is licensed "as is" without any warranty of any kind, whether express
* or implied.
*/
-#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/clk.h>
-#include <linux/platform_device.h>
#include <asm/mach/map.h>
-#include <mach/clock.h>
#include <mach/psc.h>
-#include <mach/mux.h>
#include <mach/irqs.h>
#include <mach/cputype.h>
#include <mach/common.h>
#include <mach/time.h>
#include <mach/da8xx.h>
-#include <mach/asp.h>
#include "clock.h"
#include "mux.h"
@@ -193,14 +188,14 @@ static struct clk uart1_clk = {
.name = "uart1",
.parent = &pll0_sysclk2,
.lpsc = DA8XX_LPSC1_UART1,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk uart2_clk = {
.name = "uart2",
.parent = &pll0_sysclk2,
.lpsc = DA8XX_LPSC1_UART2,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk spi0_clk = {
@@ -213,98 +208,98 @@ static struct clk spi1_clk = {
.name = "spi1",
.parent = &pll0_sysclk2,
.lpsc = DA8XX_LPSC1_SPI1,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk ecap0_clk = {
.name = "ecap0",
.parent = &pll0_sysclk2,
.lpsc = DA8XX_LPSC1_ECAP,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk ecap1_clk = {
.name = "ecap1",
.parent = &pll0_sysclk2,
.lpsc = DA8XX_LPSC1_ECAP,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk ecap2_clk = {
.name = "ecap2",
.parent = &pll0_sysclk2,
.lpsc = DA8XX_LPSC1_ECAP,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk pwm0_clk = {
.name = "pwm0",
.parent = &pll0_sysclk2,
.lpsc = DA8XX_LPSC1_PWM,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk pwm1_clk = {
.name = "pwm1",
.parent = &pll0_sysclk2,
.lpsc = DA8XX_LPSC1_PWM,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk pwm2_clk = {
.name = "pwm2",
.parent = &pll0_sysclk2,
.lpsc = DA8XX_LPSC1_PWM,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk eqep0_clk = {
.name = "eqep0",
.parent = &pll0_sysclk2,
.lpsc = DA830_LPSC1_EQEP,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk eqep1_clk = {
.name = "eqep1",
.parent = &pll0_sysclk2,
.lpsc = DA830_LPSC1_EQEP,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk lcdc_clk = {
.name = "lcdc",
.parent = &pll0_sysclk2,
.lpsc = DA8XX_LPSC1_LCDC,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk mcasp0_clk = {
.name = "mcasp0",
.parent = &pll0_sysclk2,
.lpsc = DA8XX_LPSC1_McASP0,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk mcasp1_clk = {
.name = "mcasp1",
.parent = &pll0_sysclk2,
.lpsc = DA830_LPSC1_McASP1,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk mcasp2_clk = {
.name = "mcasp2",
.parent = &pll0_sysclk2,
.lpsc = DA830_LPSC1_McASP2,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk usb20_clk = {
.name = "usb20",
.parent = &pll0_sysclk2,
.lpsc = DA8XX_LPSC1_USB20,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk aemif_clk = {
@@ -332,36 +327,36 @@ static struct clk emac_clk = {
.name = "emac",
.parent = &pll0_sysclk4,
.lpsc = DA8XX_LPSC1_CPGMAC,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk gpio_clk = {
.name = "gpio",
.parent = &pll0_sysclk4,
.lpsc = DA8XX_LPSC1_GPIO,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk i2c1_clk = {
.name = "i2c1",
.parent = &pll0_sysclk4,
.lpsc = DA8XX_LPSC1_I2C,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk usb11_clk = {
.name = "usb11",
.parent = &pll0_sysclk4,
.lpsc = DA8XX_LPSC1_USB11,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk emif3_clk = {
.name = "emif3",
.parent = &pll0_sysclk5,
.lpsc = DA8XX_LPSC1_EMIF3C,
+ .gpsc = 1,
.flags = ALWAYS_ENABLED,
- .psc_ctlr = 1,
};
static struct clk arm_clk = {
@@ -411,7 +406,7 @@ static struct davinci_clk da830_clks[] = {
CLK(NULL, "pwm2", &pwm2_clk),
CLK("eqep.0", NULL, &eqep0_clk),
CLK("eqep.1", NULL, &eqep1_clk),
- CLK("da830_lcdc", NULL, &lcdc_clk),
+ CLK("da8xx_lcdc.0", NULL, &lcdc_clk),
CLK("davinci-mcasp.0", NULL, &mcasp0_clk),
CLK("davinci-mcasp.1", NULL, &mcasp1_clk),
CLK("davinci-mcasp.2", NULL, &mcasp2_clk),
@@ -1143,7 +1138,21 @@ static struct davinci_id da830_ids[] = {
.part_no = 0xb7df,
.manufacturer = 0x017, /* 0x02f >> 1 */
.cpu_id = DAVINCI_CPU_ID_DA830,
- .name = "da830/omap l137",
+ .name = "da830/omap-l137 rev1.0",
+ },
+ {
+ .variant = 0x8,
+ .part_no = 0xb7df,
+ .manufacturer = 0x017,
+ .cpu_id = DAVINCI_CPU_ID_DA830,
+ .name = "da830/omap-l137 rev1.1",
+ },
+ {
+ .variant = 0x9,
+ .part_no = 0xb7df,
+ .manufacturer = 0x017,
+ .cpu_id = DAVINCI_CPU_ID_DA830,
+ .name = "da830/omap-l137 rev2.0",
},
};
@@ -1178,13 +1187,11 @@ static struct davinci_timer_info da830_timer_info = {
static struct davinci_soc_info davinci_soc_info_da830 = {
.io_desc = da830_io_desc,
.io_desc_num = ARRAY_SIZE(da830_io_desc),
- .jtag_id_base = IO_ADDRESS(DA8XX_JTAG_ID_REG),
.ids = da830_ids,
.ids_num = ARRAY_SIZE(da830_ids),
.cpu_clks = da830_clks,
.psc_bases = da830_psc_bases,
.psc_bases_num = ARRAY_SIZE(da830_psc_bases),
- .pinmux_base = IO_ADDRESS(DA8XX_BOOT_CFG_BASE + 0x120),
.pinmux_pins = da830_pins,
.pinmux_pins_num = ARRAY_SIZE(da830_pins),
.intc_base = (void __iomem *)DA8XX_CP_INTC_VIRT,
@@ -1201,5 +1208,13 @@ static struct davinci_soc_info davinci_soc_info_da830 = {
void __init da830_init(void)
{
+ da8xx_syscfg_base = ioremap(DA8XX_SYSCFG_BASE, SZ_4K);
+ if (WARN(!da8xx_syscfg_base, "Unable to map syscfg module"))
+ return;
+
+ davinci_soc_info_da830.jtag_id_base =
+ DA8XX_SYSCFG_VIRT(DA8XX_JTAG_ID_REG);
+ davinci_soc_info_da830.pinmux_base = DA8XX_SYSCFG_VIRT(0x120);
+
davinci_common_init(&davinci_soc_info_da830);
}
diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index 192d719..717806c 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -11,31 +11,41 @@
* is licensed "as is" without any warranty of any kind, whether express
* or implied.
*/
-#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
+#include <linux/cpufreq.h>
+#include <linux/regulator/consumer.h>
#include <asm/mach/map.h>
-#include <mach/clock.h>
#include <mach/psc.h>
-#include <mach/mux.h>
#include <mach/irqs.h>
#include <mach/cputype.h>
#include <mach/common.h>
#include <mach/time.h>
#include <mach/da8xx.h>
+#include <mach/cpufreq.h>
#include "clock.h"
#include "mux.h"
+/* SoC specific clock flags */
+#define DA850_CLK_ASYNC3 BIT(16)
+
#define DA850_PLL1_BASE 0x01e1a000
#define DA850_TIMER64P2_BASE 0x01f0c000
#define DA850_TIMER64P3_BASE 0x01f0d000
#define DA850_REF_FREQ 24000000
+#define CFGCHIP3_ASYNC3_CLKSRC BIT(4)
+#define CFGCHIP0_PLL_MASTER_LOCK BIT(4)
+
+static int da850_set_armrate(struct clk *clk, unsigned long rate);
+static int da850_round_armrate(struct clk *clk, unsigned long rate);
+static int da850_set_pll0rate(struct clk *clk, unsigned long armrate);
+
static struct pll_data pll0_data = {
.num = 1,
.phys_base = DA8XX_PLL0_BASE,
@@ -52,6 +62,7 @@ static struct clk pll0_clk = {
.parent = &ref_clk,
.pll_data = &pll0_data,
.flags = CLK_PLL,
+ .set_rate = da850_set_pll0rate,
};
static struct clk pll0_aux_clk = {
@@ -210,16 +221,16 @@ static struct clk tpcc1_clk = {
.name = "tpcc1",
.parent = &pll0_sysclk2,
.lpsc = DA850_LPSC1_TPCC1,
+ .gpsc = 1,
.flags = CLK_PSC | ALWAYS_ENABLED,
- .psc_ctlr = 1,
};
static struct clk tptc2_clk = {
.name = "tptc2",
.parent = &pll0_sysclk2,
.lpsc = DA850_LPSC1_TPTC2,
+ .gpsc = 1,
.flags = ALWAYS_ENABLED,
- .psc_ctlr = 1,
};
static struct clk uart0_clk = {
@@ -232,14 +243,16 @@ static struct clk uart1_clk = {
.name = "uart1",
.parent = &pll0_sysclk2,
.lpsc = DA8XX_LPSC1_UART1,
- .psc_ctlr = 1,
+ .gpsc = 1,
+ .flags = DA850_CLK_ASYNC3,
};
static struct clk uart2_clk = {
.name = "uart2",
.parent = &pll0_sysclk2,
.lpsc = DA8XX_LPSC1_UART2,
- .psc_ctlr = 1,
+ .gpsc = 1,
+ .flags = DA850_CLK_ASYNC3,
};
static struct clk aintc_clk = {
@@ -253,22 +266,22 @@ static struct clk gpio_clk = {
.name = "gpio",
.parent = &pll0_sysclk4,
.lpsc = DA8XX_LPSC1_GPIO,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk i2c1_clk = {
.name = "i2c1",
.parent = &pll0_sysclk4,
.lpsc = DA8XX_LPSC1_I2C,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk emif3_clk = {
.name = "emif3",
.parent = &pll0_sysclk5,
.lpsc = DA8XX_LPSC1_EMIF3C,
+ .gpsc = 1,
.flags = ALWAYS_ENABLED,
- .psc_ctlr = 1,
};
static struct clk arm_clk = {
@@ -276,6 +289,8 @@ static struct clk arm_clk = {
.parent = &pll0_sysclk6,
.lpsc = DA8XX_LPSC0_ARM,
.flags = ALWAYS_ENABLED,
+ .set_rate = da850_set_armrate,
+ .round_rate = da850_round_armrate,
};
static struct clk rmii_clk = {
@@ -287,21 +302,22 @@ static struct clk emac_clk = {
.name = "emac",
.parent = &pll0_sysclk4,
.lpsc = DA8XX_LPSC1_CPGMAC,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk mcasp_clk = {
.name = "mcasp",
.parent = &pll0_sysclk2,
.lpsc = DA8XX_LPSC1_McASP0,
- .psc_ctlr = 1,
+ .gpsc = 1,
+ .flags = DA850_CLK_ASYNC3,
};
static struct clk lcdc_clk = {
.name = "lcdc",
.parent = &pll0_sysclk2,
.lpsc = DA8XX_LPSC1_LCDC,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk mmcsd_clk = {
@@ -404,6 +420,14 @@ static const struct mux_config da850_pins[] = {
MUX_CFG(DA850, MII_RXD_0, 3, 28, 15, 8, false)
MUX_CFG(DA850, MDIO_CLK, 4, 0, 15, 8, false)
MUX_CFG(DA850, MDIO_D, 4, 4, 15, 8, false)
+ MUX_CFG(DA850, RMII_TXD_0, 14, 12, 15, 8, false)
+ MUX_CFG(DA850, RMII_TXD_1, 14, 8, 15, 8, false)
+ MUX_CFG(DA850, RMII_TXEN, 14, 16, 15, 8, false)
+ MUX_CFG(DA850, RMII_CRS_DV, 15, 4, 15, 8, false)
+ MUX_CFG(DA850, RMII_RXD_0, 14, 24, 15, 8, false)
+ MUX_CFG(DA850, RMII_RXD_1, 14, 20, 15, 8, false)
+ MUX_CFG(DA850, RMII_RXER, 14, 28, 15, 8, false)
+ MUX_CFG(DA850, RMII_MHZ_50_CLK, 15, 0, 15, 0, false)
/* McASP function */
MUX_CFG(DA850, ACLKR, 0, 0, 15, 1, false)
MUX_CFG(DA850, ACLKX, 0, 4, 15, 1, false)
@@ -506,8 +530,9 @@ static const struct mux_config da850_pins[] = {
MUX_CFG(DA850, EMA_WAIT_1, 6, 24, 15, 1, false)
MUX_CFG(DA850, NEMA_CS_2, 7, 0, 15, 1, false)
/* GPIO function */
+ MUX_CFG(DA850, GPIO2_6, 6, 4, 15, 8, false)
+ MUX_CFG(DA850, GPIO2_8, 5, 28, 15, 8, false)
MUX_CFG(DA850, GPIO2_15, 5, 0, 15, 8, false)
- MUX_CFG(DA850, GPIO8_10, 18, 28, 15, 8, false)
MUX_CFG(DA850, GPIO4_0, 10, 28, 15, 8, false)
MUX_CFG(DA850, GPIO4_1, 10, 24, 15, 8, false)
#endif
@@ -547,6 +572,14 @@ const short da850_cpgmac_pins[] __initdata = {
-1
};
+const short da850_rmii_pins[] __initdata = {
+ DA850_RMII_TXD_0, DA850_RMII_TXD_1, DA850_RMII_TXEN,
+ DA850_RMII_CRS_DV, DA850_RMII_RXD_0, DA850_RMII_RXD_1,
+ DA850_RMII_RXER, DA850_RMII_MHZ_50_CLK, DA850_MDIO_CLK,
+ DA850_MDIO_D,
+ -1
+};
+
const short da850_mcasp_pins[] __initdata = {
DA850_AHCLKX, DA850_ACLKX, DA850_AFSX,
DA850_AHCLKR, DA850_ACLKR, DA850_AFSR, DA850_AMUTE,
@@ -555,12 +588,11 @@ const short da850_mcasp_pins[] __initdata = {
};
const short da850_lcdcntl_pins[] __initdata = {
- DA850_LCD_D_1, DA850_LCD_D_2, DA850_LCD_D_3, DA850_LCD_D_4,
- DA850_LCD_D_5, DA850_LCD_D_6, DA850_LCD_D_7, DA850_LCD_D_8,
- DA850_LCD_D_9, DA850_LCD_D_10, DA850_LCD_D_11, DA850_LCD_D_12,
- DA850_LCD_D_13, DA850_LCD_D_14, DA850_LCD_D_15, DA850_LCD_PCLK,
- DA850_LCD_HSYNC, DA850_LCD_VSYNC, DA850_NLCD_AC_ENB_CS, DA850_GPIO2_15,
- DA850_GPIO8_10,
+ DA850_LCD_D_0, DA850_LCD_D_1, DA850_LCD_D_2, DA850_LCD_D_3,
+ DA850_LCD_D_4, DA850_LCD_D_5, DA850_LCD_D_6, DA850_LCD_D_7,
+ DA850_LCD_D_8, DA850_LCD_D_9, DA850_LCD_D_10, DA850_LCD_D_11,
+ DA850_LCD_D_12, DA850_LCD_D_13, DA850_LCD_D_14, DA850_LCD_D_15,
+ DA850_LCD_PCLK, DA850_LCD_HSYNC, DA850_LCD_VSYNC, DA850_NLCD_AC_ENB_CS,
-1
};
@@ -790,16 +822,221 @@ static struct davinci_timer_info da850_timer_info = {
.clocksource_id = T0_TOP,
};
+static void da850_set_async3_src(int pllnum)
+{
+ struct clk *clk, *newparent = pllnum ? &pll1_sysclk2 : &pll0_sysclk2;
+ struct davinci_clk *c;
+ unsigned int v;
+ int ret;
+
+ for (c = da850_clks; c->lk.clk; c++) {
+ clk = c->lk.clk;
+ if (clk->flags & DA850_CLK_ASYNC3) {
+ ret = clk_set_parent(clk, newparent);
+ WARN(ret, "DA850: unable to re-parent clock %s",
+ clk->name);
+ }
+ }
+
+ v = __raw_readl(DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP3_REG));
+ if (pllnum)
+ v |= CFGCHIP3_ASYNC3_CLKSRC;
+ else
+ v &= ~CFGCHIP3_ASYNC3_CLKSRC;
+ __raw_writel(v, DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP3_REG));
+}
+
+#ifdef CONFIG_CPU_FREQ
+/*
+ * Notes:
+ * According to the TRM, minimum PLLM results in maximum power savings.
+ * The OPP definitions below should keep the PLLM as low as possible.
+ *
+ * The output of the PLLM must be between 400 to 600 MHz.
+ * This rules out prediv of anything but divide-by-one for 24Mhz OSC input.
+ */
+struct da850_opp {
+ unsigned int freq; /* in KHz */
+ unsigned int prediv;
+ unsigned int mult;
+ unsigned int postdiv;
+ unsigned int cvdd_min; /* in uV */
+ unsigned int cvdd_max; /* in uV */
+};
+
+static const struct da850_opp da850_opp_300 = {
+ .freq = 300000,
+ .prediv = 1,
+ .mult = 25,
+ .postdiv = 2,
+ .cvdd_min = 1140000,
+ .cvdd_max = 1320000,
+};
+
+static const struct da850_opp da850_opp_200 = {
+ .freq = 200000,
+ .prediv = 1,
+ .mult = 25,
+ .postdiv = 3,
+ .cvdd_min = 1050000,
+ .cvdd_max = 1160000,
+};
+
+static const struct da850_opp da850_opp_96 = {
+ .freq = 96000,
+ .prediv = 1,
+ .mult = 20,
+ .postdiv = 5,
+ .cvdd_min = 950000,
+ .cvdd_max = 1050000,
+};
+
+#define OPP(freq) \
+ { \
+ .index = (unsigned int) &da850_opp_##freq, \
+ .frequency = freq * 1000, \
+ }
+
+static struct cpufreq_frequency_table da850_freq_table[] = {
+ OPP(300),
+ OPP(200),
+ OPP(96),
+ {
+ .index = 0,
+ .frequency = CPUFREQ_TABLE_END,
+ },
+};
+
+#ifdef CONFIG_REGULATOR
+static struct regulator *cvdd;
+
+static int da850_set_voltage(unsigned int index)
+{
+ struct da850_opp *opp;
+
+ if (!cvdd)
+ return -ENODEV;
+
+ opp = (struct da850_opp *) da850_freq_table[index].index;
+
+ return regulator_set_voltage(cvdd, opp->cvdd_min, opp->cvdd_max);
+}
+
+static int da850_regulator_init(void)
+{
+ cvdd = regulator_get(NULL, "cvdd");
+ if (WARN(IS_ERR(cvdd), "Unable to obtain voltage regulator for CVDD;"
+ " voltage scaling unsupported\n")) {
+ return PTR_ERR(cvdd);
+ }
+
+ return 0;
+}
+#endif
+
+static struct davinci_cpufreq_config cpufreq_info = {
+ .freq_table = &da850_freq_table[0],
+#ifdef CONFIG_REGULATOR
+ .init = da850_regulator_init,
+ .set_voltage = da850_set_voltage,
+#endif
+};
+
+static struct platform_device da850_cpufreq_device = {
+ .name = "cpufreq-davinci",
+ .dev = {
+ .platform_data = &cpufreq_info,
+ },
+};
+
+int __init da850_register_cpufreq(void)
+{
+ return platform_device_register(&da850_cpufreq_device);
+}
+
+static int da850_round_armrate(struct clk *clk, unsigned long rate)
+{
+ int i, ret = 0, diff;
+ unsigned int best = (unsigned int) -1;
+
+ rate /= 1000; /* convert to kHz */
+
+ for (i = 0; da850_freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
+ diff = da850_freq_table[i].frequency - rate;
+ if (diff < 0)
+ diff = -diff;
+
+ if (diff < best) {
+ best = diff;
+ ret = da850_freq_table[i].frequency;
+ }
+ }
+
+ return ret * 1000;
+}
+
+static int da850_set_armrate(struct clk *clk, unsigned long index)
+{
+ struct clk *pllclk = &pll0_clk;
+
+ return clk_set_rate(pllclk, index);
+}
+
+static int da850_set_pll0rate(struct clk *clk, unsigned long index)
+{
+ unsigned int prediv, mult, postdiv;
+ struct da850_opp *opp;
+ struct pll_data *pll = clk->pll_data;
+ unsigned int v;
+ int ret;
+
+ opp = (struct da850_opp *) da850_freq_table[index].index;
+ prediv = opp->prediv;
+ mult = opp->mult;
+ postdiv = opp->postdiv;
+
+ /* Unlock writing to PLL registers */
+ v = __raw_readl(DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP0_REG));
+ v &= ~CFGCHIP0_PLL_MASTER_LOCK;
+ __raw_writel(v, DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP0_REG));
+
+ ret = davinci_set_pllrate(pll, prediv, mult, postdiv);
+ if (WARN_ON(ret))
+ return ret;
+
+ return 0;
+}
+#else
+int __init da850_register_cpufreq(void)
+{
+ return 0;
+}
+
+static int da850_set_armrate(struct clk *clk, unsigned long rate)
+{
+ return -EINVAL;
+}
+
+static int da850_set_pll0rate(struct clk *clk, unsigned long armrate)
+{
+ return -EINVAL;
+}
+
+static int da850_round_armrate(struct clk *clk, unsigned long rate)
+{
+ return clk->rate;
+}
+#endif
+
+
static struct davinci_soc_info davinci_soc_info_da850 = {
.io_desc = da850_io_desc,
.io_desc_num = ARRAY_SIZE(da850_io_desc),
- .jtag_id_base = IO_ADDRESS(DA8XX_JTAG_ID_REG),
.ids = da850_ids,
.ids_num = ARRAY_SIZE(da850_ids),
.cpu_clks = da850_clks,
.psc_bases = da850_psc_bases,
.psc_bases_num = ARRAY_SIZE(da850_psc_bases),
- .pinmux_base = IO_ADDRESS(DA8XX_BOOT_CFG_BASE + 0x120),
.pinmux_pins = da850_pins,
.pinmux_pins_num = ARRAY_SIZE(da850_pins),
.intc_base = (void __iomem *)DA8XX_CP_INTC_VIRT,
@@ -816,5 +1053,22 @@ static struct davinci_soc_info davinci_soc_info_da850 = {
void __init da850_init(void)
{
+ da8xx_syscfg_base = ioremap(DA8XX_SYSCFG_BASE, SZ_4K);
+ if (WARN(!da8xx_syscfg_base, "Unable to map syscfg module"))
+ return;
+
+ davinci_soc_info_da850.jtag_id_base =
+ DA8XX_SYSCFG_VIRT(DA8XX_JTAG_ID_REG);
+ davinci_soc_info_da850.pinmux_base = DA8XX_SYSCFG_VIRT(0x120);
+
davinci_common_init(&davinci_soc_info_da850);
+
+ /*
+ * Move the clock source of Async3 domain to PLL1 SYSCLK2.
+ * This helps keeping the peripherals on this domain insulated
+ * from CPU frequency changes caused by DVFS. The firmware sets
+ * both PLL0 and PLL1 to the same frequency so, there should not
+ * be any noticible change even in non-DVFS use cases.
+ */
+ da850_set_async3_src(1);
}
diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c
index 58ad5b6..dd2d32c 100644
--- a/arch/arm/mach-davinci/devices-da8xx.c
+++ b/arch/arm/mach-davinci/devices-da8xx.c
@@ -10,8 +10,6 @@
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
-#include <linux/module.h>
-#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
@@ -21,7 +19,7 @@
#include <mach/common.h>
#include <mach/time.h>
#include <mach/da8xx.h>
-#include <video/da8xx-fb.h>
+#include <mach/cpuidle.h>
#include "clock.h"
@@ -30,6 +28,7 @@
#define DA8XX_TPTC1_BASE 0x01c08400
#define DA8XX_WDOG_BASE 0x01c21000 /* DA8XX_TIMER64P1_BASE */
#define DA8XX_I2C0_BASE 0x01c22000
+#define DA8XX_RTC_BASE 0x01C23000
#define DA8XX_EMAC_CPPI_PORT_BASE 0x01e20000
#define DA8XX_EMAC_CPGMACSS_BASE 0x01e22000
#define DA8XX_EMAC_CPGMAC_BASE 0x01e23000
@@ -43,6 +42,8 @@
#define DA8XX_MDIO_REG_OFFSET 0x4000
#define DA8XX_EMAC_CTRL_RAM_SIZE SZ_8K
+void __iomem *da8xx_syscfg_base;
+
static struct plat_serial8250_port da8xx_serial_pdata[] = {
{
.mapbase = DA8XX_UART0_BASE,
@@ -282,6 +283,11 @@ static struct platform_device da8xx_emac_device = {
.resource = da8xx_emac_resources,
};
+int __init da8xx_register_emac(void)
+{
+ return platform_device_register(&da8xx_emac_device);
+}
+
static struct resource da830_mcasp1_resources[] = {
{
.name = "mcasp1",
@@ -338,12 +344,7 @@ static struct platform_device da850_mcasp_device = {
.resource = da850_mcasp_resources,
};
-int __init da8xx_register_emac(void)
-{
- return platform_device_register(&da8xx_emac_device);
-}
-
-void __init da8xx_init_mcasp(int id, struct snd_platform_data *pdata)
+void __init da8xx_register_mcasp(int id, struct snd_platform_data *pdata)
{
/* DA830/OMAP-L137 has 3 instances of McASP */
if (cpu_is_davinci_da830() && id == 1) {
@@ -379,10 +380,16 @@ static struct lcd_ctrl_config lcd_cfg = {
.raster_order = 0,
};
-static struct da8xx_lcdc_platform_data da850_evm_lcdc_pdata = {
- .manu_name = "sharp",
- .controller_data = &lcd_cfg,
- .type = "Sharp_LK043T1DG01",
+struct da8xx_lcdc_platform_data sharp_lcd035q3dg01_pdata = {
+ .manu_name = "sharp",
+ .controller_data = &lcd_cfg,
+ .type = "Sharp_LCD035Q3DG01",
+};
+
+struct da8xx_lcdc_platform_data sharp_lk043t1dg01_pdata = {
+ .manu_name = "sharp",
+ .controller_data = &lcd_cfg,
+ .type = "Sharp_LK043T1DG01",
};
static struct resource da8xx_lcdc_resources[] = {
@@ -398,19 +405,17 @@ static struct resource da8xx_lcdc_resources[] = {
},
};
-static struct platform_device da850_lcdc_device = {
+static struct platform_device da8xx_lcdc_device = {
.name = "da8xx_lcdc",
.id = 0,
.num_resources = ARRAY_SIZE(da8xx_lcdc_resources),
.resource = da8xx_lcdc_resources,
- .dev = {
- .platform_data = &da850_evm_lcdc_pdata,
- }
};
-int __init da8xx_register_lcdc(void)
+int __init da8xx_register_lcdc(struct da8xx_lcdc_platform_data *pdata)
{
- return platform_device_register(&da850_lcdc_device);
+ da8xx_lcdc_device.dev.platform_data = pdata;
+ return platform_device_register(&da8xx_lcdc_device);
}
static struct resource da8xx_mmcsd0_resources[] = {
@@ -448,3 +453,66 @@ int __init da8xx_register_mmcsd0(struct davinci_mmc_config *config)
da8xx_mmcsd0_device.dev.platform_data = config;
return platform_device_register(&da8xx_mmcsd0_device);
}
+
+static struct resource da8xx_rtc_resources[] = {
+ {
+ .start = DA8XX_RTC_BASE,
+ .end = DA8XX_RTC_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ { /* timer irq */
+ .start = IRQ_DA8XX_RTC,
+ .end = IRQ_DA8XX_RTC,
+ .flags = IORESOURCE_IRQ,
+ },
+ { /* alarm irq */
+ .start = IRQ_DA8XX_RTC,
+ .end = IRQ_DA8XX_RTC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device da8xx_rtc_device = {
+ .name = "omap_rtc",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(da8xx_rtc_resources),
+ .resource = da8xx_rtc_resources,
+};
+
+int da8xx_register_rtc(void)
+{
+ /* Unlock the rtc's registers */
+ __raw_writel(0x83e70b13, IO_ADDRESS(DA8XX_RTC_BASE + 0x6c));
+ __raw_writel(0x95a4f1e0, IO_ADDRESS(DA8XX_RTC_BASE + 0x70));
+
+ return platform_device_register(&da8xx_rtc_device);
+}
+
+static struct resource da8xx_cpuidle_resources[] = {
+ {
+ .start = DA8XX_DDR2_CTL_BASE,
+ .end = DA8XX_DDR2_CTL_BASE + SZ_32K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+/* DA8XX devices support DDR2 power down */
+static struct davinci_cpuidle_config da8xx_cpuidle_pdata = {
+ .ddr2_pdown = 1,
+};
+
+
+static struct platform_device da8xx_cpuidle_device = {
+ .name = "cpuidle-davinci",
+ .num_resources = ARRAY_SIZE(da8xx_cpuidle_resources),
+ .resource = da8xx_cpuidle_resources,
+ .dev = {
+ .platform_data = &da8xx_cpuidle_pdata,
+ },
+};
+
+int __init da8xx_register_cpuidle(void)
+{
+ return platform_device_register(&da8xx_cpuidle_device);
+}
+
diff --git a/arch/arm/mach-davinci/devices.c b/arch/arm/mach-davinci/devices.c
index a55b650..1479496 100644
--- a/arch/arm/mach-davinci/devices.c
+++ b/arch/arm/mach-davinci/devices.c
@@ -9,15 +9,11 @@
* (at your option) any later version.
*/
-#include <linux/module.h>
-#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/io.h>
-#include <asm/mach/map.h>
-
#include <mach/hardware.h>
#include <mach/i2c.h>
#include <mach/irqs.h>
@@ -177,7 +173,7 @@ void __init davinci_setup_mmc(int module, struct davinci_mmc_config *config)
mmcsd1_resources[0].start = DM365_MMCSD1_BASE;
mmcsd1_resources[0].end = DM365_MMCSD1_BASE +
SZ_4K - 1;
- mmcsd0_resources[2].start = IRQ_DM365_SDIOINT1;
+ mmcsd1_resources[2].start = IRQ_DM365_SDIOINT1;
} else
break;
diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c
index 0596700..dedf4d4 100644
--- a/arch/arm/mach-davinci/dm355.c
+++ b/arch/arm/mach-davinci/dm355.c
@@ -8,7 +8,6 @@
* is licensed "as is" without any warranty of any kind, whether express
* or implied.
*/
-#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/clk.h>
#include <linux/serial_8250.h>
@@ -21,7 +20,6 @@
#include <asm/mach/map.h>
#include <mach/dm355.h>
-#include <mach/clock.h>
#include <mach/cputype.h>
#include <mach/edma.h>
#include <mach/psc.h>
diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c
index e815174..2ec619e 100644
--- a/arch/arm/mach-davinci/dm365.c
+++ b/arch/arm/mach-davinci/dm365.c
@@ -12,7 +12,6 @@
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/clk.h>
#include <linux/serial_8250.h>
@@ -23,7 +22,6 @@
#include <asm/mach/map.h>
#include <mach/dm365.h>
-#include <mach/clock.h>
#include <mach/cputype.h>
#include <mach/edma.h>
#include <mach/psc.h>
@@ -32,6 +30,8 @@
#include <mach/time.h>
#include <mach/serial.h>
#include <mach/common.h>
+#include <mach/asp.h>
+#include <mach/keyscan.h>
#include "clock.h"
#include "mux.h"
@@ -369,7 +369,7 @@ static struct clk timer3_clk = {
static struct clk usb_clk = {
.name = "usb",
- .parent = &pll2_sysclk1,
+ .parent = &pll1_aux_clk,
.lpsc = DAVINCI_LPSC_USB,
};
@@ -456,7 +456,7 @@ static struct davinci_clk dm365_clks[] = {
CLK(NULL, "usb", &usb_clk),
CLK("davinci_emac.1", NULL, &emac_clk),
CLK("voice_codec", NULL, &voicecodec_clk),
- CLK("soc-audio.0", NULL, &asp0_clk),
+ CLK("davinci-asp.0", NULL, &asp0_clk),
CLK(NULL, "rto", &rto_clk),
CLK(NULL, "mjcp", &mjcp_clk),
CLK(NULL, NULL, NULL),
@@ -531,7 +531,7 @@ MUX_CFG(DM365, EMAC_CRS, 3, 2, 1, 1, false)
MUX_CFG(DM365, EMAC_MDIO, 3, 1, 1, 1, false)
MUX_CFG(DM365, EMAC_MDCLK, 3, 0, 1, 1, false)
-MUX_CFG(DM365, KEYPAD, 2, 0, 0x3f, 0x3f, false)
+MUX_CFG(DM365, KEYSCAN, 2, 0, 0x3f, 0x3f, false)
MUX_CFG(DM365, PWM0, 1, 0, 3, 2, false)
MUX_CFG(DM365, PWM0_G23, 3, 26, 3, 3, false)
@@ -603,6 +603,9 @@ INT_CFG(DM365, INT_IMX1_ENABLE, 24, 1, 1, false)
INT_CFG(DM365, INT_IMX1_DISABLE, 24, 1, 0, false)
INT_CFG(DM365, INT_NSF_ENABLE, 25, 1, 1, false)
INT_CFG(DM365, INT_NSF_DISABLE, 25, 1, 0, false)
+
+EVT_CFG(DM365, EVT2_ASP_TX, 0, 1, 0, false)
+EVT_CFG(DM365, EVT3_ASP_RX, 1, 1, 0, false)
#endif
};
@@ -696,6 +699,7 @@ static u8 dm365_default_priorities[DAVINCI_N_AINTC_IRQ] = {
[IRQ_I2C] = 3,
[IRQ_UARTINT0] = 3,
[IRQ_UARTINT1] = 3,
+ [IRQ_DM365_RTCINT] = 3,
[IRQ_DM365_SPIINT0_0] = 3,
[IRQ_DM365_SPIINT3_0] = 3,
[IRQ_DM365_GPIO0] = 3,
@@ -806,6 +810,50 @@ static struct platform_device dm365_edma_device = {
.resource = edma_resources,
};
+static struct resource dm365_asp_resources[] = {
+ {
+ .start = DAVINCI_DM365_ASP0_BASE,
+ .end = DAVINCI_DM365_ASP0_BASE + SZ_8K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = DAVINCI_DMA_ASP0_TX,
+ .end = DAVINCI_DMA_ASP0_TX,
+ .flags = IORESOURCE_DMA,
+ },
+ {
+ .start = DAVINCI_DMA_ASP0_RX,
+ .end = DAVINCI_DMA_ASP0_RX,
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+static struct platform_device dm365_asp_device = {
+ .name = "davinci-asp",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(dm365_asp_resources),
+ .resource = dm365_asp_resources,
+};
+
+static struct resource dm365_rtc_resources[] = {
+ {
+ .start = DM365_RTC_BASE,
+ .end = DM365_RTC_BASE + SZ_1K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_DM365_RTCINT,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device dm365_rtc_device = {
+ .name = "rtc_davinci",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(dm365_rtc_resources),
+ .resource = dm365_rtc_resources,
+};
+
static struct map_desc dm365_io_desc[] = {
{
.virtual = IO_VIRT,
@@ -822,6 +870,28 @@ static struct map_desc dm365_io_desc[] = {
},
};
+static struct resource dm365_ks_resources[] = {
+ {
+ /* registers */
+ .start = DM365_KEYSCAN_BASE,
+ .end = DM365_KEYSCAN_BASE + SZ_1K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ /* interrupt */
+ .start = IRQ_DM365_KEYINT,
+ .end = IRQ_DM365_KEYINT,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device dm365_ks_device = {
+ .name = "davinci_keyscan",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(dm365_ks_resources),
+ .resource = dm365_ks_resources,
+};
+
/* Contents of JTAG ID register used to identify exact cpu type */
static struct davinci_id dm365_ids[] = {
{
@@ -907,6 +977,33 @@ static struct davinci_soc_info davinci_soc_info_dm365 = {
.sram_len = SZ_32K,
};
+void __init dm365_init_asp(struct snd_platform_data *pdata)
+{
+ davinci_cfg_reg(DM365_MCBSP0_BDX);
+ davinci_cfg_reg(DM365_MCBSP0_X);
+ davinci_cfg_reg(DM365_MCBSP0_BFSX);
+ davinci_cfg_reg(DM365_MCBSP0_BDR);
+ davinci_cfg_reg(DM365_MCBSP0_R);
+ davinci_cfg_reg(DM365_MCBSP0_BFSR);
+ davinci_cfg_reg(DM365_EVT2_ASP_TX);
+ davinci_cfg_reg(DM365_EVT3_ASP_RX);
+ dm365_asp_device.dev.platform_data = pdata;
+ platform_device_register(&dm365_asp_device);
+}
+
+void __init dm365_init_ks(struct davinci_ks_platform_data *pdata)
+{
+ davinci_cfg_reg(DM365_KEYSCAN);
+ dm365_ks_device.dev.platform_data = pdata;
+ platform_device_register(&dm365_ks_device);
+}
+
+void __init dm365_init_rtc(void)
+{
+ davinci_cfg_reg(DM365_INT_PRTCSS);
+ platform_device_register(&dm365_rtc_device);
+}
+
void __init dm365_init(void)
{
davinci_common_init(&davinci_soc_info_dm365);
diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c
index d6e0fa5..2cd0081 100644
--- a/arch/arm/mach-davinci/dm644x.c
+++ b/arch/arm/mach-davinci/dm644x.c
@@ -8,7 +8,6 @@
* is licensed "as is" without any warranty of any kind, whether express
* or implied.
*/
-#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/clk.h>
#include <linux/serial_8250.h>
@@ -18,7 +17,6 @@
#include <asm/mach/map.h>
#include <mach/dm644x.h>
-#include <mach/clock.h>
#include <mach/cputype.h>
#include <mach/edma.h>
#include <mach/irqs.h>
@@ -370,6 +368,11 @@ MUX_CFG(DM644X, ATAEN_DISABLE, 0, 17, 1, 0, true)
MUX_CFG(DM644X, HPIEN_DISABLE, 0, 29, 1, 0, true)
MUX_CFG(DM644X, AEAW, 0, 0, 31, 31, true)
+MUX_CFG(DM644X, AEAW0, 0, 0, 1, 0, true)
+MUX_CFG(DM644X, AEAW1, 0, 1, 1, 0, true)
+MUX_CFG(DM644X, AEAW2, 0, 2, 1, 0, true)
+MUX_CFG(DM644X, AEAW3, 0, 3, 1, 0, true)
+MUX_CFG(DM644X, AEAW4, 0, 4, 1, 0, true)
MUX_CFG(DM644X, MSTK, 1, 9, 1, 0, false)
diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c
index 0976049..829a44b 100644
--- a/arch/arm/mach-davinci/dm646x.c
+++ b/arch/arm/mach-davinci/dm646x.c
@@ -8,7 +8,6 @@
* is licensed "as is" without any warranty of any kind, whether express
* or implied.
*/
-#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/clk.h>
#include <linux/serial_8250.h>
@@ -18,7 +17,6 @@
#include <asm/mach/map.h>
#include <mach/dm646x.h>
-#include <mach/clock.h>
#include <mach/cputype.h>
#include <mach/edma.h>
#include <mach/irqs.h>
@@ -789,7 +787,14 @@ static struct davinci_id dm646x_ids[] = {
.part_no = 0xb770,
.manufacturer = 0x017,
.cpu_id = DAVINCI_CPU_ID_DM6467,
- .name = "dm6467",
+ .name = "dm6467_rev1.x",
+ },
+ {
+ .variant = 0x1,
+ .part_no = 0xb770,
+ .manufacturer = 0x017,
+ .cpu_id = DAVINCI_CPU_ID_DM6467,
+ .name = "dm6467_rev3.x",
},
};
diff --git a/arch/arm/mach-davinci/dma.c b/arch/arm/mach-davinci/dma.c
index f2e57d2..648fbb7 100644
--- a/arch/arm/mach-davinci/dma.c
+++ b/arch/arm/mach-davinci/dma.c
@@ -18,22 +18,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
-#include <linux/spinlock.h>
-#include <linux/compiler.h>
#include <linux/io.h>
-#include <mach/cputype.h>
-#include <mach/memory.h>
-#include <mach/hardware.h>
-#include <mach/irqs.h>
#include <mach/edma.h>
-#include <mach/mux.h>
-
/* Offsets matching "struct edmacc_param" */
#define PARM_OPT 0x00
@@ -509,43 +500,59 @@ static irqreturn_t dma_tc1err_handler(int irq, void *data)
return IRQ_HANDLED;
}
-static int reserve_contiguous_params(int ctlr, unsigned int id,
- unsigned int num_params,
- unsigned int start_param)
+static int reserve_contiguous_slots(int ctlr, unsigned int id,
+ unsigned int num_slots,
+ unsigned int start_slot)
{
int i, j;
- unsigned int count = num_params;
+ unsigned int count = num_slots;
+ int stop_slot = start_slot;
+ DECLARE_BITMAP(tmp_inuse, EDMA_MAX_PARAMENTRY);
- for (i = start_param; i < edma_info[ctlr]->num_slots; ++i) {
+ for (i = start_slot; i < edma_info[ctlr]->num_slots; ++i) {
j = EDMA_CHAN_SLOT(i);
- if (!test_and_set_bit(j, edma_info[ctlr]->edma_inuse))
+ if (!test_and_set_bit(j, edma_info[ctlr]->edma_inuse)) {
+ /* Record our current beginning slot */
+ if (count == num_slots)
+ stop_slot = i;
+
count--;
+ set_bit(j, tmp_inuse);
+
if (count == 0)
break;
- else if (id == EDMA_CONT_PARAMS_FIXED_EXACT)
- break;
- else
- count = num_params;
+ } else {
+ clear_bit(j, tmp_inuse);
+
+ if (id == EDMA_CONT_PARAMS_FIXED_EXACT) {
+ stop_slot = i;
+ break;
+ } else
+ count = num_slots;
+ }
}
/*
* We have to clear any bits that we set
- * if we run out parameter RAMs, i.e we do find a set
- * of contiguous parameter RAMs but do not find the exact number
- * requested as we may reach the total number of parameter RAMs
+ * if we run out parameter RAM slots, i.e we do find a set
+ * of contiguous parameter RAM slots but do not find the exact number
+ * requested as we may reach the total number of parameter RAM slots
*/
- if (count) {
- for (j = i - num_params + count + 1; j <= i ; ++j)
+ if (i == edma_info[ctlr]->num_slots)
+ stop_slot = i;
+
+ for (j = start_slot; j < stop_slot; j++)
+ if (test_bit(j, tmp_inuse))
clear_bit(j, edma_info[ctlr]->edma_inuse);
+ if (count)
return -EBUSY;
- }
- for (j = i - num_params + 1; j <= i; ++j)
+ for (j = i - num_slots + 1; j <= i; ++j)
memcpy_toio(edmacc_regs_base[ctlr] + PARM_OFFSET(j),
&dummy_paramset, PARM_SIZE);
- return EDMA_CTLR_CHAN(ctlr, i - num_params + 1);
+ return EDMA_CTLR_CHAN(ctlr, i - num_slots + 1);
}
/*-----------------------------------------------------------------------*/
@@ -743,26 +750,27 @@ EXPORT_SYMBOL(edma_free_slot);
/**
* edma_alloc_cont_slots- alloc contiguous parameter RAM slots
* The API will return the starting point of a set of
- * contiguous PARAM's that have been requested
+ * contiguous parameter RAM slots that have been requested
*
* @id: can only be EDMA_CONT_PARAMS_ANY or EDMA_CONT_PARAMS_FIXED_EXACT
* or EDMA_CONT_PARAMS_FIXED_NOT_EXACT
- * @count: number of contiguous Paramter RAM's
- * @param - the start value of Parameter RAM that should be passed if id
+ * @count: number of contiguous Paramter RAM slots
+ * @slot - the start value of Parameter RAM slot that should be passed if id
* is EDMA_CONT_PARAMS_FIXED_EXACT or EDMA_CONT_PARAMS_FIXED_NOT_EXACT
*
* If id is EDMA_CONT_PARAMS_ANY then the API starts looking for a set of
- * contiguous Parameter RAMs from parameter RAM 64 in the case of DaVinci SOCs
- * and 32 in the case of Primus
+ * contiguous Parameter RAM slots from parameter RAM 64 in the case of
+ * DaVinci SOCs and 32 in the case of DA8xx SOCs.
*
* If id is EDMA_CONT_PARAMS_FIXED_EXACT then the API starts looking for a
- * set of contiguous parameter RAMs from the "param" that is passed as an
+ * set of contiguous parameter RAM slots from the "slot" that is passed as an
* argument to the API.
*
* If id is EDMA_CONT_PARAMS_FIXED_NOT_EXACT then the API initially tries
- * starts looking for a set of contiguous parameter RAMs from the "param"
+ * starts looking for a set of contiguous parameter RAMs from the "slot"
* that is passed as an argument to the API. On failure the API will try to
- * find a set of contiguous Parameter RAMs in the remaining Parameter RAMs
+ * find a set of contiguous Parameter RAM slots from the remaining Parameter
+ * RAM slots
*/
int edma_alloc_cont_slots(unsigned ctlr, unsigned int id, int slot, int count)
{
@@ -771,12 +779,13 @@ int edma_alloc_cont_slots(unsigned ctlr, unsigned int id, int slot, int count)
* the number of channels and lesser than the total number
* of slots
*/
- if (slot < edma_info[ctlr]->num_channels ||
- slot >= edma_info[ctlr]->num_slots)
+ if ((id != EDMA_CONT_PARAMS_ANY) &&
+ (slot < edma_info[ctlr]->num_channels ||
+ slot >= edma_info[ctlr]->num_slots))
return -EINVAL;
/*
- * The number of parameter RAMs requested cannot be less than 1
+ * The number of parameter RAM slots requested cannot be less than 1
* and cannot be more than the number of slots minus the number of
* channels
*/
@@ -786,11 +795,11 @@ int edma_alloc_cont_slots(unsigned ctlr, unsigned int id, int slot, int count)
switch (id) {
case EDMA_CONT_PARAMS_ANY:
- return reserve_contiguous_params(ctlr, id, count,
+ return reserve_contiguous_slots(ctlr, id, count,
edma_info[ctlr]->num_channels);
case EDMA_CONT_PARAMS_FIXED_EXACT:
case EDMA_CONT_PARAMS_FIXED_NOT_EXACT:
- return reserve_contiguous_params(ctlr, id, count, slot);
+ return reserve_contiguous_slots(ctlr, id, count, slot);
default:
return -EINVAL;
}
@@ -799,21 +808,21 @@ int edma_alloc_cont_slots(unsigned ctlr, unsigned int id, int slot, int count)
EXPORT_SYMBOL(edma_alloc_cont_slots);
/**
- * edma_free_cont_slots - deallocate DMA parameter RAMs
- * @slot: first parameter RAM of a set of parameter RAMs to be freed
- * @count: the number of contiguous parameter RAMs to be freed
+ * edma_free_cont_slots - deallocate DMA parameter RAM slots
+ * @slot: first parameter RAM of a set of parameter RAM slots to be freed
+ * @count: the number of contiguous parameter RAM slots to be freed
*
* This deallocates the parameter RAM slots allocated by
* edma_alloc_cont_slots.
* Callers/applications need to keep track of sets of contiguous
- * parameter RAMs that have been allocated using the edma_alloc_cont_slots
+ * parameter RAM slots that have been allocated using the edma_alloc_cont_slots
* API.
* Callers are responsible for ensuring the slots are inactive, and will
* not be activated.
*/
int edma_free_cont_slots(unsigned slot, int count)
{
- unsigned ctlr;
+ unsigned ctlr, slot_to_free;
int i;
ctlr = EDMA_CTLR(slot);
@@ -826,11 +835,11 @@ int edma_free_cont_slots(unsigned slot, int count)
for (i = slot; i < slot + count; ++i) {
ctlr = EDMA_CTLR(i);
- slot = EDMA_CHAN_SLOT(i);
+ slot_to_free = EDMA_CHAN_SLOT(i);
- memcpy_toio(edmacc_regs_base[ctlr] + PARM_OFFSET(slot),
+ memcpy_toio(edmacc_regs_base[ctlr] + PARM_OFFSET(slot_to_free),
&dummy_paramset, PARM_SIZE);
- clear_bit(slot, edma_info[ctlr]->edma_inuse);
+ clear_bit(slot_to_free, edma_info[ctlr]->edma_inuse);
}
return 0;
diff --git a/arch/arm/mach-davinci/gpio.c b/arch/arm/mach-davinci/gpio.c
index f6ea9db..744755b 100644
--- a/arch/arm/mach-davinci/gpio.c
+++ b/arch/arm/mach-davinci/gpio.c
@@ -12,23 +12,14 @@
#include <linux/errno.h>
#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/module.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/bitops.h>
-#include <mach/cputype.h>
-#include <mach/irqs.h>
-#include <mach/hardware.h>
-#include <mach/common.h>
#include <mach/gpio.h>
#include <asm/mach/irq.h>
-
static DEFINE_SPINLOCK(gpio_lock);
struct davinci_gpio {
diff --git a/arch/arm/mach-davinci/include/mach/asp.h b/arch/arm/mach-davinci/include/mach/asp.h
index e07f70e..834725f 100644
--- a/arch/arm/mach-davinci/include/mach/asp.h
+++ b/arch/arm/mach-davinci/include/mach/asp.h
@@ -11,6 +11,9 @@
#define DAVINCI_ASP0_BASE 0x01E02000
#define DAVINCI_ASP1_BASE 0x01E04000
+/* Bases of dm365 register banks */
+#define DAVINCI_DM365_ASP0_BASE 0x01D02000
+
/* Bases of dm646x register banks */
#define DAVINCI_DM646X_MCASP0_REG_BASE 0x01D01000
#define DAVINCI_DM646X_MCASP1_REG_BASE 0x01D01800
diff --git a/arch/arm/mach-davinci/include/mach/common.h b/arch/arm/mach-davinci/include/mach/common.h
index 1fd3917..6ca2c9a 100644
--- a/arch/arm/mach-davinci/include/mach/common.h
+++ b/arch/arm/mach-davinci/include/mach/common.h
@@ -20,12 +20,6 @@ extern void davinci_irq_init(void);
extern void __iomem *davinci_intc_base;
extern int davinci_intc_type;
-/* parameters describe VBUS sourcing for host mode */
-extern void setup_usb(unsigned mA, unsigned potpgt_msec);
-
-/* parameters describe VBUS sourcing for host mode */
-extern void setup_usb(unsigned mA, unsigned potpgt_msec);
-
struct davinci_timer_instance {
void __iomem *base;
u32 bottom_irq;
diff --git a/arch/arm/mach-davinci/include/mach/cpufreq.h b/arch/arm/mach-davinci/include/mach/cpufreq.h
new file mode 100644
index 0000000..3c089cf
--- /dev/null
+++ b/arch/arm/mach-davinci/include/mach/cpufreq.h
@@ -0,0 +1,26 @@
+/*
+ * TI DaVinci CPUFreq platform support.
+ *
+ * Copyright (C) 2009 Texas Instruments, Inc. http://www.ti.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.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef _MACH_DAVINCI_CPUFREQ_H
+#define _MACH_DAVINCI_CPUFREQ_H
+
+#include <linux/cpufreq.h>
+
+struct davinci_cpufreq_config {
+ struct cpufreq_frequency_table *freq_table;
+ int (*set_voltage) (unsigned int index);
+ int (*init) (void);
+};
+
+#endif
diff --git a/arch/arm/mach-davinci/include/mach/cpuidle.h b/arch/arm/mach-davinci/include/mach/cpuidle.h
new file mode 100644
index 0000000..cbfc6a9
--- /dev/null
+++ b/arch/arm/mach-davinci/include/mach/cpuidle.h
@@ -0,0 +1,17 @@
+/*
+ * TI DaVinci cpuidle platform support
+ *
+ * 2009 (C) Texas Instruments, Inc. http://www.ti.com/
+ *
+ * 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 _MACH_DAVINCI_CPUIDLE_H
+#define _MACH_DAVINCI_CPUIDLE_H
+
+struct davinci_cpuidle_config {
+ u32 ddr2_pdown;
+};
+
+#endif
diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h
index d4095d0..9070491 100644
--- a/arch/arm/mach-davinci/include/mach/da8xx.h
+++ b/arch/arm/mach-davinci/include/mach/da8xx.h
@@ -11,12 +11,17 @@
#ifndef __ASM_ARCH_DAVINCI_DA8XX_H
#define __ASM_ARCH_DAVINCI_DA8XX_H
+#include <video/da8xx-fb.h>
+
#include <mach/serial.h>
#include <mach/edma.h>
#include <mach/i2c.h>
#include <mach/emac.h>
#include <mach/asp.h>
#include <mach/mmc.h>
+#include <mach/usb.h>
+
+extern void __iomem *da8xx_syscfg_base;
/*
* The cp_intc interrupt controller for the da8xx isn't in the same
@@ -29,11 +34,15 @@
#define DA8XX_CP_INTC_SIZE SZ_8K
#define DA8XX_CP_INTC_VIRT (IO_VIRT - DA8XX_CP_INTC_SIZE - SZ_4K)
-#define DA8XX_BOOT_CFG_BASE (IO_PHYS + 0x14000)
+#define DA8XX_SYSCFG_BASE (IO_PHYS + 0x14000)
+#define DA8XX_SYSCFG_VIRT(x) (da8xx_syscfg_base + (x))
+#define DA8XX_JTAG_ID_REG 0x18
+#define DA8XX_CFGCHIP0_REG 0x17c
+#define DA8XX_CFGCHIP2_REG 0x184
+#define DA8XX_CFGCHIP3_REG 0x188
#define DA8XX_PSC0_BASE 0x01c10000
#define DA8XX_PLL0_BASE 0x01c11000
-#define DA8XX_JTAG_ID_REG 0x01c14018
#define DA8XX_TIMER64P0_BASE 0x01c20000
#define DA8XX_TIMER64P1_BASE 0x01c21000
#define DA8XX_GPIO_BASE 0x01e26000
@@ -43,6 +52,7 @@
#define DA8XX_AEMIF_CS2_BASE 0x60000000
#define DA8XX_AEMIF_CS3_BASE 0x62000000
#define DA8XX_AEMIF_CTL_BASE 0x68000000
+#define DA8XX_DDR2_CTL_BASE 0xb0000000
#define PINMUX0 0x00
#define PINMUX1 0x04
@@ -71,13 +81,20 @@ void __init da850_init(void);
int da8xx_register_edma(void);
int da8xx_register_i2c(int instance, struct davinci_i2c_platform_data *pdata);
int da8xx_register_watchdog(void);
+int da8xx_register_usb20(unsigned mA, unsigned potpgt);
+int da8xx_register_usb11(struct da8xx_ohci_root_hub *pdata);
int da8xx_register_emac(void);
-int da8xx_register_lcdc(void);
+int da8xx_register_lcdc(struct da8xx_lcdc_platform_data *pdata);
int da8xx_register_mmcsd0(struct davinci_mmc_config *config);
-void __init da8xx_init_mcasp(int id, struct snd_platform_data *pdata);
+void __init da8xx_register_mcasp(int id, struct snd_platform_data *pdata);
+int da8xx_register_rtc(void);
+int da850_register_cpufreq(void);
+int da8xx_register_cpuidle(void);
extern struct platform_device da8xx_serial_device;
extern struct emac_platform_data da8xx_emac_pdata;
+extern struct da8xx_lcdc_platform_data sharp_lcd035q3dg01_pdata;
+extern struct da8xx_lcdc_platform_data sharp_lk043t1dg01_pdata;
extern const short da830_emif25_pins[];
extern const short da830_spi0_pins[];
@@ -110,6 +127,7 @@ extern const short da850_uart2_pins[];
extern const short da850_i2c0_pins[];
extern const short da850_i2c1_pins[];
extern const short da850_cpgmac_pins[];
+extern const short da850_rmii_pins[];
extern const short da850_mcasp_pins[];
extern const short da850_lcdcntl_pins[];
extern const short da850_mmcsd0_pins[];
diff --git a/arch/arm/mach-davinci/include/mach/dm365.h b/arch/arm/mach-davinci/include/mach/dm365.h
index 09db434..f1710a3 100644
--- a/arch/arm/mach-davinci/include/mach/dm365.h
+++ b/arch/arm/mach-davinci/include/mach/dm365.h
@@ -16,6 +16,8 @@
#include <linux/platform_device.h>
#include <mach/hardware.h>
#include <mach/emac.h>
+#include <mach/asp.h>
+#include <mach/keyscan.h>
#define DM365_EMAC_BASE (0x01D07000)
#define DM365_EMAC_CNTRL_OFFSET (0x0000)
@@ -24,6 +26,14 @@
#define DM365_EMAC_MDIO_OFFSET (0x4000)
#define DM365_EMAC_CNTRL_RAM_SIZE (0x2000)
+/* Base of key scan register bank */
+#define DM365_KEYSCAN_BASE (0x01C69400)
+
+#define DM365_RTC_BASE (0x01C69000)
+
void __init dm365_init(void);
+void __init dm365_init_asp(struct snd_platform_data *pdata);
+void __init dm365_init_ks(struct davinci_ks_platform_data *pdata);
+void __init dm365_init_rtc(void);
#endif /* __ASM_ARCH_DM365_H */
diff --git a/arch/arm/mach-davinci/include/mach/dm644x.h b/arch/arm/mach-davinci/include/mach/dm644x.h
index 0efb738..44e8f0f 100644
--- a/arch/arm/mach-davinci/include/mach/dm644x.h
+++ b/arch/arm/mach-davinci/include/mach/dm644x.h
@@ -22,7 +22,6 @@
#ifndef __ASM_ARCH_DM644X_H
#define __ASM_ARCH_DM644X_H
-#include <linux/platform_device.h>
#include <mach/hardware.h>
#include <mach/emac.h>
#include <mach/asp.h>
diff --git a/arch/arm/mach-davinci/include/mach/irqs.h b/arch/arm/mach-davinci/include/mach/irqs.h
index 3c918a7..354af71 100644
--- a/arch/arm/mach-davinci/include/mach/irqs.h
+++ b/arch/arm/mach-davinci/include/mach/irqs.h
@@ -217,6 +217,7 @@
#define IRQ_DM365_SDIOINT0 23
#define IRQ_DM365_MMCINT1 27
#define IRQ_DM365_PWMINT3 28
+#define IRQ_DM365_RTCINT 29
#define IRQ_DM365_SDIOINT1 31
#define IRQ_DM365_SPIINT0_0 42
#define IRQ_DM365_SPIINT3_0 43
diff --git a/arch/arm/mach-davinci/include/mach/mux.h b/arch/arm/mach-davinci/include/mach/mux.h
index bb84893..b60c693 100644
--- a/arch/arm/mach-davinci/include/mach/mux.h
+++ b/arch/arm/mach-davinci/include/mach/mux.h
@@ -40,6 +40,11 @@ enum davinci_dm644x_index {
/* AEAW functions */
DM644X_AEAW,
+ DM644X_AEAW0,
+ DM644X_AEAW1,
+ DM644X_AEAW2,
+ DM644X_AEAW3,
+ DM644X_AEAW4,
/* Memory Stick */
DM644X_MSTK,
@@ -237,8 +242,8 @@ enum davinci_dm365_index {
DM365_EMAC_MDIO,
DM365_EMAC_MDCLK,
- /* Keypad */
- DM365_KEYPAD,
+ /* Key Scan */
+ DM365_KEYSCAN,
/* PWM */
DM365_PWM0,
@@ -774,6 +779,14 @@ enum davinci_da850_index {
DA850_MII_RXD_0,
DA850_MDIO_CLK,
DA850_MDIO_D,
+ DA850_RMII_TXD_0,
+ DA850_RMII_TXD_1,
+ DA850_RMII_TXEN,
+ DA850_RMII_CRS_DV,
+ DA850_RMII_RXD_0,
+ DA850_RMII_RXD_1,
+ DA850_RMII_RXER,
+ DA850_RMII_MHZ_50_CLK,
/* McASP function */
DA850_ACLKR,
@@ -881,8 +894,9 @@ enum davinci_da850_index {
DA850_NEMA_CS_2,
/* GPIO function */
+ DA850_GPIO2_6,
+ DA850_GPIO2_8,
DA850_GPIO2_15,
- DA850_GPIO8_10,
DA850_GPIO4_0,
DA850_GPIO4_1,
};
diff --git a/arch/arm/mach-davinci/include/mach/system.h b/arch/arm/mach-davinci/include/mach/system.h
index 8e4f10f..5a7d758 100644
--- a/arch/arm/mach-davinci/include/mach/system.h
+++ b/arch/arm/mach-davinci/include/mach/system.h
@@ -11,9 +11,6 @@
#ifndef __ASM_ARCH_SYSTEM_H
#define __ASM_ARCH_SYSTEM_H
-#include <linux/io.h>
-#include <mach/hardware.h>
-
extern void davinci_watchdog_reset(void);
static inline void arch_idle(void)
diff --git a/arch/arm/mach-davinci/include/mach/usb.h b/arch/arm/mach-davinci/include/mach/usb.h
new file mode 100644
index 0000000..e0bc4ab
--- /dev/null
+++ b/arch/arm/mach-davinci/include/mach/usb.h
@@ -0,0 +1,59 @@
+/*
+ * USB related definitions
+ *
+ * Copyright (C) 2009 MontaVista Software, Inc. <source@mvista.com>
+ *
+ * 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_USB_H
+#define __ASM_ARCH_USB_H
+
+/* DA8xx CFGCHIP2 (USB 2.0 PHY Control) register bits */
+#define CFGCHIP2_PHYCLKGD (1 << 17)
+#define CFGCHIP2_VBUSSENSE (1 << 16)
+#define CFGCHIP2_RESET (1 << 15)
+#define CFGCHIP2_OTGMODE (3 << 13)
+#define CFGCHIP2_NO_OVERRIDE (0 << 13)
+#define CFGCHIP2_FORCE_HOST (1 << 13)
+#define CFGCHIP2_FORCE_DEVICE (2 << 13)
+#define CFGCHIP2_FORCE_HOST_VBUS_LOW (3 << 13)
+#define CFGCHIP2_USB1PHYCLKMUX (1 << 12)
+#define CFGCHIP2_USB2PHYCLKMUX (1 << 11)
+#define CFGCHIP2_PHYPWRDN (1 << 10)
+#define CFGCHIP2_OTGPWRDN (1 << 9)
+#define CFGCHIP2_DATPOL (1 << 8)
+#define CFGCHIP2_USB1SUSPENDM (1 << 7)
+#define CFGCHIP2_PHY_PLLON (1 << 6) /* override PLL suspend */
+#define CFGCHIP2_SESENDEN (1 << 5) /* Vsess_end comparator */
+#define CFGCHIP2_VBDTCTEN (1 << 4) /* Vbus comparator */
+#define CFGCHIP2_REFFREQ (0xf << 0)
+#define CFGCHIP2_REFFREQ_12MHZ (1 << 0)
+#define CFGCHIP2_REFFREQ_24MHZ (2 << 0)
+#define CFGCHIP2_REFFREQ_48MHZ (3 << 0)
+
+struct da8xx_ohci_root_hub;
+
+typedef void (*da8xx_ocic_handler_t)(struct da8xx_ohci_root_hub *hub,
+ unsigned port);
+
+/* Passed as the platform data to the OHCI driver */
+struct da8xx_ohci_root_hub {
+ /* Switch the port power on/off */
+ int (*set_power)(unsigned port, int on);
+ /* Read the port power status */
+ int (*get_power)(unsigned port);
+ /* Read the port over-current indicator */
+ int (*get_oci)(unsigned port);
+ /* Over-current indicator change notification (pass NULL to disable) */
+ int (*ocic_notify)(da8xx_ocic_handler_t handler);
+
+ /* Time from power on to power good (in 2 ms units) */
+ u8 potpgt;
+};
+
+void davinci_setup_usb(unsigned mA, unsigned potpgt_ms);
+
+#endif /* ifndef __ASM_ARCH_USB_H */
diff --git a/arch/arm/mach-davinci/mux.c b/arch/arm/mach-davinci/mux.c
index 898905e..f757e83 100644
--- a/arch/arm/mach-davinci/mux.c
+++ b/arch/arm/mach-davinci/mux.c
@@ -19,7 +19,6 @@
#include <linux/module.h>
#include <linux/spinlock.h>
-#include <mach/hardware.h>
#include <mach/mux.h>
#include <mach/common.h>
diff --git a/arch/arm/mach-davinci/psc.c b/arch/arm/mach-davinci/psc.c
index a78b657..04a3cb7 100644
--- a/arch/arm/mach-davinci/psc.c
+++ b/arch/arm/mach-davinci/psc.c
@@ -19,14 +19,11 @@
*
*/
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/init.h>
#include <linux/io.h>
#include <mach/cputype.h>
-#include <mach/hardware.h>
#include <mach/psc.h>
-#include <mach/mux.h>
/* PSC register offsets */
#define EPCPR 0x070
diff --git a/arch/arm/mach-davinci/serial.c b/arch/arm/mach-davinci/serial.c
index c530c73..7ce5ba0 100644
--- a/arch/arm/mach-davinci/serial.c
+++ b/arch/arm/mach-davinci/serial.c
@@ -28,14 +28,8 @@
#include <linux/clk.h>
#include <linux/io.h>
-#include <asm/irq.h>
-#include <mach/hardware.h>
#include <mach/serial.h>
-#include <mach/irqs.h>
#include <mach/cputype.h>
-#include <mach/common.h>
-
-#include "clock.h"
static inline unsigned int serial_read_reg(struct plat_serial8250_port *up,
int offset)
diff --git a/arch/arm/mach-davinci/sram.c b/arch/arm/mach-davinci/sram.c
index 4f1fc9b..db0f778 100644
--- a/arch/arm/mach-davinci/sram.c
+++ b/arch/arm/mach-davinci/sram.c
@@ -9,15 +9,12 @@
* (at your option) any later version.
*/
#include <linux/module.h>
-#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/genalloc.h>
#include <mach/common.h>
-#include <mach/memory.h>
#include <mach/sram.h>
-
static struct gen_pool *sram_pool;
void *sram_alloc(size_t len, dma_addr_t *dma)
diff --git a/arch/arm/mach-davinci/time.c b/arch/arm/mach-davinci/time.c
index 0d1b6d4..42d985b 100644
--- a/arch/arm/mach-davinci/time.c
+++ b/arch/arm/mach-davinci/time.c
@@ -14,20 +14,14 @@
#include <linux/interrupt.h>
#include <linux/clocksource.h>
#include <linux/clockchips.h>
-#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/err.h>
-#include <linux/device.h>
#include <linux/platform_device.h>
#include <mach/hardware.h>
-#include <asm/system.h>
-#include <asm/irq.h>
#include <asm/mach/irq.h>
#include <asm/mach/time.h>
-#include <asm/errno.h>
-#include <mach/io.h>
#include <mach/cputype.h>
#include <mach/time.h>
#include "clock.h"
diff --git a/arch/arm/mach-davinci/usb.c b/arch/arm/mach-davinci/usb.c
index 06f5593..31f0cbe 100644
--- a/arch/arm/mach-davinci/usb.c
+++ b/arch/arm/mach-davinci/usb.c
@@ -1,21 +1,21 @@
/*
* USB
*/
-#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/usb/musb.h>
-#include <linux/usb/otg.h>
#include <mach/common.h>
-#include <mach/hardware.h>
#include <mach/irqs.h>
#include <mach/cputype.h>
+#include <mach/usb.h>
-#define DAVINCI_USB_OTG_BASE 0x01C64000
+#define DAVINCI_USB_OTG_BASE 0x01c64000
+
+#define DA8XX_USB0_BASE 0x01e00000
+#define DA8XX_USB1_BASE 0x01e25000
#if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
static struct musb_hdrc_eps_bits musb_eps[] = {
@@ -85,10 +85,10 @@ static struct platform_device usb_dev = {
.num_resources = ARRAY_SIZE(usb_resources),
};
-void __init setup_usb(unsigned mA, unsigned potpgt_msec)
+void __init davinci_setup_usb(unsigned mA, unsigned potpgt_ms)
{
- usb_data.power = mA / 2;
- usb_data.potpgt = potpgt_msec / 2;
+ usb_data.power = mA > 510 ? 255 : mA / 2;
+ usb_data.potpgt = (potpgt_ms + 1) / 2;
if (cpu_is_davinci_dm646x()) {
/* Override the defaults as DM6467 uses different IRQs. */
@@ -100,11 +100,77 @@ void __init setup_usb(unsigned mA, unsigned potpgt_msec)
platform_device_register(&usb_dev);
}
+#ifdef CONFIG_ARCH_DAVINCI_DA8XX
+static struct resource da8xx_usb20_resources[] = {
+ {
+ .start = DA8XX_USB0_BASE,
+ .end = DA8XX_USB0_BASE + SZ_64K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_DA8XX_USB_INT,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+int __init da8xx_register_usb20(unsigned mA, unsigned potpgt)
+{
+ usb_data.clock = "usb20";
+ usb_data.power = mA > 510 ? 255 : mA / 2;
+ usb_data.potpgt = (potpgt + 1) / 2;
+
+ usb_dev.resource = da8xx_usb20_resources;
+ usb_dev.num_resources = ARRAY_SIZE(da8xx_usb20_resources);
+
+ return platform_device_register(&usb_dev);
+}
+#endif /* CONFIG_DAVINCI_DA8XX */
+
#else
-void __init setup_usb(unsigned mA, unsigned potpgt_msec)
+void __init davinci_setup_usb(unsigned mA, unsigned potpgt_ms)
{
}
+#ifdef CONFIG_ARCH_DAVINCI_DA8XX
+int __init da8xx_register_usb20(unsigned mA, unsigned potpgt)
+{
+ return 0;
+}
+#endif
+
#endif /* CONFIG_USB_MUSB_HDRC */
+#ifdef CONFIG_ARCH_DAVINCI_DA8XX
+static struct resource da8xx_usb11_resources[] = {
+ [0] = {
+ .start = DA8XX_USB1_BASE,
+ .end = DA8XX_USB1_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_DA8XX_IRQN,
+ .end = IRQ_DA8XX_IRQN,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static u64 da8xx_usb11_dma_mask = DMA_BIT_MASK(32);
+
+static struct platform_device da8xx_usb11_device = {
+ .name = "ohci",
+ .id = 0,
+ .dev = {
+ .dma_mask = &da8xx_usb11_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+ .num_resources = ARRAY_SIZE(da8xx_usb11_resources),
+ .resource = da8xx_usb11_resources,
+};
+
+int __init da8xx_register_usb11(struct da8xx_ohci_root_hub *pdata)
+{
+ da8xx_usb11_device.dev.platform_data = pdata;
+ return platform_device_register(&da8xx_usb11_device);
+}
+#endif /* CONFIG_DAVINCI_DA8XX */
diff --git a/arch/arm/mach-lh7a40x/include/mach/hardware.h b/arch/arm/mach-lh7a40x/include/mach/hardware.h
index 48e827d..59d2ace 100644
--- a/arch/arm/mach-lh7a40x/include/mach/hardware.h
+++ b/arch/arm/mach-lh7a40x/include/mach/hardware.h
@@ -31,7 +31,7 @@
/*
* This __REG() version gives the same results as the one above, except
* that we are fooling gcc somehow so it generates far better and smaller
- * assembly code for access to contigous registers. It's a shame that gcc
+ * assembly code for access to contiguous registers. It's a shame that gcc
* doesn't guess this by itself.
*/
#include <asm/types.h>
diff --git a/arch/arm/mach-orion5x/pci.c b/arch/arm/mach-orion5x/pci.c
index 36dc541..bdf96eb 100644
--- a/arch/arm/mach-orion5x/pci.c
+++ b/arch/arm/mach-orion5x/pci.c
@@ -463,7 +463,7 @@ static void __init orion5x_setup_pci_wins(struct mbus_dram_target_info *dram)
writel(win_enable, PCI_BAR_ENABLE);
/*
- * Disable automatic update of address remaping when writing to BARs.
+ * Disable automatic update of address remapping when writing to BARs.
*/
orion5x_setbits(PCI_ADDR_DECODE_CTRL, 1);
}
diff --git a/arch/arm/mach-pxa/include/mach/palmld.h b/arch/arm/mach-pxa/include/mach/palmld.h
index 8721b80..ae536e8 100644
--- a/arch/arm/mach-pxa/include/mach/palmld.h
+++ b/arch/arm/mach-pxa/include/mach/palmld.h
@@ -91,7 +91,7 @@
/* BATTERY */
#define PALMLD_BAT_MAX_VOLTAGE 4000 /* 4.00V maximum voltage */
#define PALMLD_BAT_MIN_VOLTAGE 3550 /* 3.55V critical voltage */
-#define PALMLD_BAT_MAX_CURRENT 0 /* unknokn */
+#define PALMLD_BAT_MAX_CURRENT 0 /* unknown */
#define PALMLD_BAT_MIN_CURRENT 0 /* unknown */
#define PALMLD_BAT_MAX_CHARGE 1 /* unknown */
#define PALMLD_BAT_MIN_CHARGE 1 /* unknown */
diff --git a/arch/arm/mach-pxa/include/mach/palmt5.h b/arch/arm/mach-pxa/include/mach/palmt5.h
index d15662a..6baf746 100644
--- a/arch/arm/mach-pxa/include/mach/palmt5.h
+++ b/arch/arm/mach-pxa/include/mach/palmt5.h
@@ -66,7 +66,7 @@
/* BATTERY */
#define PALMT5_BAT_MAX_VOLTAGE 4000 /* 4.00v current voltage */
#define PALMT5_BAT_MIN_VOLTAGE 3550 /* 3.55v critical voltage */
-#define PALMT5_BAT_MAX_CURRENT 0 /* unknokn */
+#define PALMT5_BAT_MAX_CURRENT 0 /* unknown */
#define PALMT5_BAT_MIN_CURRENT 0 /* unknown */
#define PALMT5_BAT_MAX_CHARGE 1 /* unknown */
#define PALMT5_BAT_MIN_CHARGE 1 /* unknown */
diff --git a/arch/arm/mach-pxa/include/mach/palmtc.h b/arch/arm/mach-pxa/include/mach/palmtc.h
index 3dc9b07..3f9dd3f 100644
--- a/arch/arm/mach-pxa/include/mach/palmtc.h
+++ b/arch/arm/mach-pxa/include/mach/palmtc.h
@@ -68,7 +68,7 @@
/* BATTERY */
#define PALMTC_BAT_MAX_VOLTAGE 4000 /* 4.00V maximum voltage */
#define PALMTC_BAT_MIN_VOLTAGE 3550 /* 3.55V critical voltage */
-#define PALMTC_BAT_MAX_CURRENT 0 /* unknokn */
+#define PALMTC_BAT_MAX_CURRENT 0 /* unknown */
#define PALMTC_BAT_MIN_CURRENT 0 /* unknown */
#define PALMTC_BAT_MAX_CHARGE 1 /* unknown */
#define PALMTC_BAT_MIN_CHARGE 1 /* unknown */
diff --git a/arch/arm/mach-pxa/include/mach/palmte2.h b/arch/arm/mach-pxa/include/mach/palmte2.h
index 1236134..f89e989 100644
--- a/arch/arm/mach-pxa/include/mach/palmte2.h
+++ b/arch/arm/mach-pxa/include/mach/palmte2.h
@@ -59,7 +59,7 @@
/* BATTERY */
#define PALMTE2_BAT_MAX_VOLTAGE 4000 /* 4.00v current voltage */
#define PALMTE2_BAT_MIN_VOLTAGE 3550 /* 3.55v critical voltage */
-#define PALMTE2_BAT_MAX_CURRENT 0 /* unknokn */
+#define PALMTE2_BAT_MAX_CURRENT 0 /* unknown */
#define PALMTE2_BAT_MIN_CURRENT 0 /* unknown */
#define PALMTE2_BAT_MAX_CHARGE 1 /* unknown */
#define PALMTE2_BAT_MIN_CHARGE 1 /* unknown */
diff --git a/arch/arm/mach-pxa/include/mach/palmtx.h b/arch/arm/mach-pxa/include/mach/palmtx.h
index 1be0db6..10abc4f 100644
--- a/arch/arm/mach-pxa/include/mach/palmtx.h
+++ b/arch/arm/mach-pxa/include/mach/palmtx.h
@@ -94,7 +94,7 @@
/* BATTERY */
#define PALMTX_BAT_MAX_VOLTAGE 4000 /* 4.00v current voltage */
#define PALMTX_BAT_MIN_VOLTAGE 3550 /* 3.55v critical voltage */
-#define PALMTX_BAT_MAX_CURRENT 0 /* unknokn */
+#define PALMTX_BAT_MAX_CURRENT 0 /* unknown */
#define PALMTX_BAT_MIN_CURRENT 0 /* unknown */
#define PALMTX_BAT_MAX_CHARGE 1 /* unknown */
#define PALMTX_BAT_MIN_CHARGE 1 /* unknown */
diff --git a/arch/arm/mach-pxa/include/mach/palmz72.h b/arch/arm/mach-pxa/include/mach/palmz72.h
index 2806ef6..2bbcf70 100644
--- a/arch/arm/mach-pxa/include/mach/palmz72.h
+++ b/arch/arm/mach-pxa/include/mach/palmz72.h
@@ -49,7 +49,7 @@
/* Battery */
#define PALMZ72_BAT_MAX_VOLTAGE 4000 /* 4.00v current voltage */
#define PALMZ72_BAT_MIN_VOLTAGE 3550 /* 3.55v critical voltage */
-#define PALMZ72_BAT_MAX_CURRENT 0 /* unknokn */
+#define PALMZ72_BAT_MAX_CURRENT 0 /* unknown */
#define PALMZ72_BAT_MIN_CURRENT 0 /* unknown */
#define PALMZ72_BAT_MAX_CHARGE 1 /* unknown */
#define PALMZ72_BAT_MIN_CHARGE 1 /* unknown */
diff --git a/arch/arm/mach-s3c2400/Kconfig b/arch/arm/mach-s3c2400/Kconfig
index deab072..fdd8f5e 100644
--- a/arch/arm/mach-s3c2400/Kconfig
+++ b/arch/arm/mach-s3c2400/Kconfig
@@ -1,13 +1,7 @@
-# arch/arm/mach-s3c2400/Kconfig
-#
# Copyright 2007 Simtec Electronics
#
# Licensed under GPLv2
-
-
menu "S3C2400 Machines"
-
endmenu
-
diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig
index dd1fcc7..5547318 100644
--- a/arch/arm/mach-s3c2410/Kconfig
+++ b/arch/arm/mach-s3c2410/Kconfig
@@ -1,5 +1,3 @@
-# arch/arm/mach-s3c2410/Kconfig
-#
# Copyright 2007 Simtec Electronics
#
# Licensed under GPLv2
diff --git a/arch/arm/mach-s3c2412/Kconfig b/arch/arm/mach-s3c2412/Kconfig
index c2bdc46..9a8c065 100644
--- a/arch/arm/mach-s3c2412/Kconfig
+++ b/arch/arm/mach-s3c2412/Kconfig
@@ -1,5 +1,3 @@
-# arch/arm/mach-s3c2412/Kconfig
-#
# Copyright 2007 Simtec Electronics
#
# Licensed under GPLv2
@@ -90,6 +88,4 @@ config MACH_VSTMS
help
Say Y here if you are using an VSTMS board
-
endmenu
-
diff --git a/arch/arm/mach-s3c2440/Kconfig b/arch/arm/mach-s3c2440/Kconfig
index cf10e14..8087935 100644
--- a/arch/arm/mach-s3c2440/Kconfig
+++ b/arch/arm/mach-s3c2440/Kconfig
@@ -1,5 +1,3 @@
-# arch/arm/mach-s3c2440/Kconfig
-#
# Copyright 2007 Simtec Electronics
#
# Licensed under GPLv2
@@ -122,4 +120,3 @@ config MACH_MINI2440
available via various sources. It can come with a 3.5" or 7" touch LCD.
endmenu
-
diff --git a/arch/arm/mach-s3c2442/Kconfig b/arch/arm/mach-s3c2442/Kconfig
index 103e913..8d38118 100644
--- a/arch/arm/mach-s3c2442/Kconfig
+++ b/arch/arm/mach-s3c2442/Kconfig
@@ -1,5 +1,3 @@
-# arch/arm/mach-s3c2442/Kconfig
-#
# Copyright 2007 Simtec Electronics
#
# Licensed under GPLv2
@@ -36,6 +34,4 @@ config MACH_NEO1973_GTA02
help
Say Y here if you are using the Openmoko GTA02 / Freerunner GSM Phone
-
endmenu
-
diff --git a/arch/arm/mach-s3c2443/Kconfig b/arch/arm/mach-s3c2443/Kconfig
index 212141b..4314c44 100644
--- a/arch/arm/mach-s3c2443/Kconfig
+++ b/arch/arm/mach-s3c2443/Kconfig
@@ -1,5 +1,3 @@
-# arch/arm/mach-s3c2443/Kconfig
-#
# Copyright 2007 Simtec Electronics
#
# Licensed under GPLv2
diff --git a/arch/arm/mach-s3c6400/Kconfig b/arch/arm/mach-s3c6400/Kconfig
index 770b720..a250bf6 100644
--- a/arch/arm/mach-s3c6400/Kconfig
+++ b/arch/arm/mach-s3c6400/Kconfig
@@ -1,5 +1,3 @@
-# arch/arm/mach-s3c6400/Kconfig
-#
# Copyright 2008 Openmoko, Inc.
# Simtec Electronics, Ben Dooks <ben@simtec.co.uk>
#
diff --git a/arch/arm/mach-s3c6400/setup-sdhci.c b/arch/arm/mach-s3c6400/setup-sdhci.c
index b93dafb..1039937 100644
--- a/arch/arm/mach-s3c6400/setup-sdhci.c
+++ b/arch/arm/mach-s3c6400/setup-sdhci.c
@@ -30,7 +30,7 @@ char *s3c6400_hsmmc_clksrcs[4] = {
[0] = "hsmmc",
[1] = "hsmmc",
[2] = "mmc_bus",
- /* [3] = "48m", - note not succesfully used yet */
+ /* [3] = "48m", - note not successfully used yet */
};
void s3c6400_setup_sdhci_cfg_card(struct platform_device *dev,
diff --git a/arch/arm/mach-s3c6410/Kconfig b/arch/arm/mach-s3c6410/Kconfig
index 72d4b11..162f456 100644
--- a/arch/arm/mach-s3c6410/Kconfig
+++ b/arch/arm/mach-s3c6410/Kconfig
@@ -1,5 +1,3 @@
-# arch/arm/mach-s3c6410/Kconfig
-#
# Copyright 2008 Openmoko, Inc.
# Copyright 2008 Simtec Electronics
#
diff --git a/arch/arm/mach-s3c6410/setup-sdhci.c b/arch/arm/mach-s3c6410/setup-sdhci.c
index 20666f3..816d2d9 100644
--- a/arch/arm/mach-s3c6410/setup-sdhci.c
+++ b/arch/arm/mach-s3c6410/setup-sdhci.c
@@ -30,7 +30,7 @@ char *s3c6410_hsmmc_clksrcs[4] = {
[0] = "hsmmc",
[1] = "hsmmc",
[2] = "mmc_bus",
- /* [3] = "48m", - note not succesfully used yet */
+ /* [3] = "48m", - note not successfully used yet */
};
diff --git a/arch/arm/mach-s5pc100/Kconfig b/arch/arm/mach-s5pc100/Kconfig
index 0dd2b8c..27ec167 100644
--- a/arch/arm/mach-s5pc100/Kconfig
+++ b/arch/arm/mach-s5pc100/Kconfig
@@ -1,5 +1,3 @@
-# arch/arm/mach-s5pc100/Kconfig
-#
# Copyright 2009 Samsung Electronics Co.
# Byungho Min <bhmin@samsung.com>
#
diff --git a/arch/arm/mach-sa1100/dma.c b/arch/arm/mach-sa1100/dma.c
index cb4521a..ad66035 100644
--- a/arch/arm/mach-sa1100/dma.c
+++ b/arch/arm/mach-sa1100/dma.c
@@ -65,7 +65,7 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id)
/**
- * sa1100_request_dma - allocate one of the SA11x0's DMA chanels
+ * sa1100_request_dma - allocate one of the SA11x0's DMA channels
* @device: The SA11x0 peripheral targeted by this request
* @device_id: An ascii name for the claiming device
* @callback: Function to be called when the DMA completes
diff --git a/arch/arm/mach-u300/include/mach/u300-regs.h b/arch/arm/mach-u300/include/mach/u300-regs.h
index 88333df..56721a0 100644
--- a/arch/arm/mach-u300/include/mach/u300-regs.h
+++ b/arch/arm/mach-u300/include/mach/u300-regs.h
@@ -6,7 +6,7 @@
* Copyright (C) 2006-2009 ST-Ericsson AB
* License terms: GNU General Public License (GPL) version 2
* Basic register address definitions in physical memory and
- * some block defintions for core devices like the timer.
+ * some block definitions for core devices like the timer.
* Author: Linus Walleij <linus.walleij@stericsson.com>
*/
diff --git a/arch/arm/plat-mxc/include/mach/iomux-mx3.h b/arch/arm/plat-mxc/include/mach/iomux-mx3.h
index eaabd4e..e1fc6da 100644
--- a/arch/arm/plat-mxc/include/mach/iomux-mx3.h
+++ b/arch/arm/plat-mxc/include/mach/iomux-mx3.h
@@ -112,7 +112,7 @@ enum iomux_gp_func {
* setups a single pin:
* - reserves the pin so that it is not claimed by another driver
* - setups the iomux according to the configuration
- * - if the pin is configured as a GPIO, we claim it throug kernel gpiolib
+ * - if the pin is configured as a GPIO, we claim it through kernel gpiolib
*/
int mxc_iomux_alloc_pin(const unsigned int pin, const char *label);
/*
diff --git a/arch/arm/plat-mxc/include/mach/iomux-mxc91231.h b/arch/arm/plat-mxc/include/mach/iomux-mxc91231.h
index 9f13061..3887f3f 100644
--- a/arch/arm/plat-mxc/include/mach/iomux-mxc91231.h
+++ b/arch/arm/plat-mxc/include/mach/iomux-mxc91231.h
@@ -48,7 +48,7 @@
* setups a single pin:
* - reserves the pin so that it is not claimed by another driver
* - setups the iomux according to the configuration
- * - if the pin is configured as a GPIO, we claim it throug kernel gpiolib
+ * - if the pin is configured as a GPIO, we claim it through kernel gpiolib
*/
int mxc_iomux_alloc_pin(const unsigned int pin_mode, const char *label);
/*
diff --git a/arch/arm/plat-mxc/pwm.c b/arch/arm/plat-mxc/pwm.c
index 5cdbd60..4ff6dfe 100644
--- a/arch/arm/plat-mxc/pwm.c
+++ b/arch/arm/plat-mxc/pwm.c
@@ -94,7 +94,7 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
* register to follow the ratio of duty_ns vs. period_ns
* accordingly.
*
- * This is good enought for programming the brightness of
+ * This is good enough for programming the brightness of
* the LCD backlight.
*
* The real implementation would divide PERCLK[0] first by
diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
index be4ce07..d17375e 100644
--- a/arch/arm/plat-omap/dma.c
+++ b/arch/arm/plat-omap/dma.c
@@ -1252,7 +1252,7 @@ static void create_dma_lch_chain(int lch_head, int lch_queue)
* OMAP_DMA_DYNAMIC_CHAIN
* @params - Channel parameters
*
- * @return - Succes : 0
+ * @return - Success : 0
* Failure: -EINVAL/-ENOMEM
*/
int omap_request_dma_chain(int dev_id, const char *dev_name,
diff --git a/arch/arm/plat-omap/include/plat/omap16xx.h b/arch/arm/plat-omap/include/plat/omap16xx.h
index 0e69b50..7560b4d 100644
--- a/arch/arm/plat-omap/include/plat/omap16xx.h
+++ b/arch/arm/plat-omap/include/plat/omap16xx.h
@@ -124,7 +124,7 @@
#define TIPB_SWITCH_BASE (0xfffbc800)
#define OMAP16XX_MMCSD2_SSW_MPU_CONF (TIPB_SWITCH_BASE + 0x160)
-/* UART3 Registers Maping through MPU bus */
+/* UART3 Registers Mapping through MPU bus */
#define UART3_RHR (OMAP_UART3_BASE + 0)
#define UART3_THR (OMAP_UART3_BASE + 0)
#define UART3_DLL (OMAP_UART3_BASE + 0)
diff --git a/arch/arm/plat-s3c/Kconfig b/arch/arm/plat-s3c/Kconfig
index e139a72..9e9d028 100644
--- a/arch/arm/plat-s3c/Kconfig
+++ b/arch/arm/plat-s3c/Kconfig
@@ -1,5 +1,3 @@
-# arch/arm/plat-s3c/Kconfig
-#
# Copyright 2007 Simtec Electronics
#
# Licensed under GPLv2
diff --git a/arch/arm/plat-s3c/pwm.c b/arch/arm/plat-s3c/pwm.c
index 4fdc5b3..ef019f2 100644
--- a/arch/arm/plat-s3c/pwm.c
+++ b/arch/arm/plat-s3c/pwm.c
@@ -368,7 +368,7 @@ static int s3c_pwm_probe(struct platform_device *pdev)
return ret;
}
-static int s3c_pwm_remove(struct platform_device *pdev)
+static int __devexit s3c_pwm_remove(struct platform_device *pdev)
{
struct pwm_device *pwm = platform_get_drvdata(pdev);
diff --git a/arch/arm/plat-s3c24xx/Kconfig b/arch/arm/plat-s3c24xx/Kconfig
index 20fbf93..342647e 100644
--- a/arch/arm/plat-s3c24xx/Kconfig
+++ b/arch/arm/plat-s3c24xx/Kconfig
@@ -1,5 +1,3 @@
-# arch/arm/plat-s3c24xx/Kconfig
-#
# Copyright 2007 Simtec Electronics
#
# Licensed under GPLv2
diff --git a/arch/arm/plat-s3c24xx/adc.c b/arch/arm/plat-s3c24xx/adc.c
index df47322..ce47627 100644
--- a/arch/arm/plat-s3c24xx/adc.c
+++ b/arch/arm/plat-s3c24xx/adc.c
@@ -365,7 +365,7 @@ static int s3c_adc_probe(struct platform_device *pdev)
return ret;
}
-static int s3c_adc_remove(struct platform_device *pdev)
+static int __devexit s3c_adc_remove(struct platform_device *pdev)
{
struct adc_device *adc = platform_get_drvdata(pdev);
diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c
index f65192d..f0ea794 100644
--- a/arch/arm/plat-s3c24xx/dma.c
+++ b/arch/arm/plat-s3c24xx/dma.c
@@ -1403,11 +1403,13 @@ static struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel)
ord = &dma_order->channels[channel];
for (ch = 0; ch < dma_channels; ch++) {
+ int tmp;
if (!is_channel_valid(ord->list[ch]))
continue;
- if (s3c2410_chans[ord->list[ch]].in_use == 0) {
- ch = ord->list[ch] & ~DMA_CH_VALID;
+ tmp = ord->list[ch] & ~DMA_CH_VALID;
+ if (s3c2410_chans[tmp].in_use == 0) {
+ ch = tmp;
goto found;
}
}
diff --git a/arch/arm/plat-s3c24xx/include/plat/map.h b/arch/arm/plat-s3c24xx/include/plat/map.h
index c4d1334..bd534d3 100644
--- a/arch/arm/plat-s3c24xx/include/plat/map.h
+++ b/arch/arm/plat-s3c24xx/include/plat/map.h
@@ -64,7 +64,7 @@
/* the calculation for the VA of this must ensure that
* it is the same distance apart from the UART in the
* phsyical address space, as the initial mapping for the IO
- * is done as a 1:1 maping. This puts it (currently) at
+ * is done as a 1:1 mapping. This puts it (currently) at
* 0xFA800000, which is not in the way of any current mapping
* by the base system.
*/
diff --git a/arch/arm/plat-s3c24xx/irq.c b/arch/arm/plat-s3c24xx/irq.c
index ef0f521..ad0d44e 100644
--- a/arch/arm/plat-s3c24xx/irq.c
+++ b/arch/arm/plat-s3c24xx/irq.c
@@ -522,6 +522,8 @@ int s3c24xx_set_fiq(unsigned int irq, bool on)
__raw_writel(intmod, S3C2410_INTMOD);
return 0;
}
+
+EXPORT_SYMBOL_GPL(s3c24xx_set_fiq);
#endif
diff --git a/arch/arm/plat-s3c64xx/Kconfig b/arch/arm/plat-s3c64xx/Kconfig
index bcfa778..e6da87a 100644
--- a/arch/arm/plat-s3c64xx/Kconfig
+++ b/arch/arm/plat-s3c64xx/Kconfig
@@ -1,5 +1,3 @@
-# arch/arm/plat-s3c64xx/Kconfig
-#
# Copyright 2008 Openmoko, Inc.
# Copyright 2008 Simtec Electronics
# Ben Dooks <ben@simtec.co.uk>
diff --git a/arch/arm/plat-s5pc1xx/Kconfig b/arch/arm/plat-s5pc1xx/Kconfig
index 1608e62..b7b9e91 100644
--- a/arch/arm/plat-s5pc1xx/Kconfig
+++ b/arch/arm/plat-s5pc1xx/Kconfig
@@ -1,5 +1,3 @@
-# arch/arm/plat-s5pc1xx/Kconfig
-#
# Copyright 2009 Samsung Electronics Co.
# Byungho Min <bhmin@samsung.com>
#
diff --git a/arch/avr32/boards/hammerhead/Kconfig b/arch/avr32/boards/hammerhead/Kconfig
index fda2331..5c13d78 100644
--- a/arch/avr32/boards/hammerhead/Kconfig
+++ b/arch/avr32/boards/hammerhead/Kconfig
@@ -24,7 +24,7 @@ config BOARD_HAMMERHEAD_SND
bool "Atmel AC97 Sound support"
help
This enables Sound support for the Hammerhead board. You may
- also go trough the ALSA settings to get it working.
+ also go through the ALSA settings to get it working.
Choose 'Y' here if you have ordered a Corona daugther board and
want to make your board funky.
diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c
index 5cc7e2e..4587642 100644
--- a/arch/blackfin/kernel/process.c
+++ b/arch/blackfin/kernel/process.c
@@ -215,22 +215,18 @@ copy_thread(unsigned long clone_flags,
/*
* sys_execve() executes a new program.
*/
-
asmlinkage int sys_execve(char __user *name, char __user * __user *argv, char __user * __user *envp)
{
int error;
char *filename;
struct pt_regs *regs = (struct pt_regs *)((&name) + 6);
- lock_kernel();
filename = getname(name);
error = PTR_ERR(filename);
if (IS_ERR(filename))
- goto out;
+ return error;
error = do_execve(filename, argv, envp, regs);
putname(filename);
- out:
- unlock_kernel();
return error;
}
diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c
index 6b7325d..78cb3d3 100644
--- a/arch/blackfin/kernel/traps.c
+++ b/arch/blackfin/kernel/traps.c
@@ -619,7 +619,7 @@ asmlinkage notrace void trap_c(struct pt_regs *fp)
/*
* Similar to get_user, do some address checking, then dereference
- * Return true on sucess, false on bad address
+ * Return true on success, false on bad address
*/
static bool get_instruction(unsigned short *val, unsigned short *address)
{
diff --git a/arch/blackfin/mach-bf518/include/mach/defBF51x_base.h b/arch/blackfin/mach-bf518/include/mach/defBF51x_base.h
index e06f411..f9fd2b2 100644
--- a/arch/blackfin/mach-bf518/include/mach/defBF51x_base.h
+++ b/arch/blackfin/mach-bf518/include/mach/defBF51x_base.h
@@ -542,7 +542,7 @@
#define HMDMA0_CONTROL 0xFFC03300 /* Handshake MDMA0 Control Register */
#define HMDMA0_ECINIT 0xFFC03304 /* HMDMA0 Initial Edge Count Register */
#define HMDMA0_BCINIT 0xFFC03308 /* HMDMA0 Initial Block Count Register */
-#define HMDMA0_ECURGENT 0xFFC0330C /* HMDMA0 Urgent Edge Count Threshhold Register */
+#define HMDMA0_ECURGENT 0xFFC0330C /* HMDMA0 Urgent Edge Count Threshold Register */
#define HMDMA0_ECOVERFLOW 0xFFC03310 /* HMDMA0 Edge Count Overflow Interrupt Register */
#define HMDMA0_ECOUNT 0xFFC03314 /* HMDMA0 Current Edge Count Register */
#define HMDMA0_BCOUNT 0xFFC03318 /* HMDMA0 Current Block Count Register */
@@ -550,7 +550,7 @@
#define HMDMA1_CONTROL 0xFFC03340 /* Handshake MDMA1 Control Register */
#define HMDMA1_ECINIT 0xFFC03344 /* HMDMA1 Initial Edge Count Register */
#define HMDMA1_BCINIT 0xFFC03348 /* HMDMA1 Initial Block Count Register */
-#define HMDMA1_ECURGENT 0xFFC0334C /* HMDMA1 Urgent Edge Count Threshhold Register */
+#define HMDMA1_ECURGENT 0xFFC0334C /* HMDMA1 Urgent Edge Count Threshold Register */
#define HMDMA1_ECOVERFLOW 0xFFC03350 /* HMDMA1 Edge Count Overflow Interrupt Register */
#define HMDMA1_ECOUNT 0xFFC03354 /* HMDMA1 Current Edge Count Register */
#define HMDMA1_BCOUNT 0xFFC03358 /* HMDMA1 Current Block Count Register */
diff --git a/arch/blackfin/mach-bf527/include/mach/defBF52x_base.h b/arch/blackfin/mach-bf527/include/mach/defBF52x_base.h
index f821700..b9dbb73 100644
--- a/arch/blackfin/mach-bf527/include/mach/defBF52x_base.h
+++ b/arch/blackfin/mach-bf527/include/mach/defBF52x_base.h
@@ -544,7 +544,7 @@
#define HMDMA0_CONTROL 0xFFC03300 /* Handshake MDMA0 Control Register */
#define HMDMA0_ECINIT 0xFFC03304 /* HMDMA0 Initial Edge Count Register */
#define HMDMA0_BCINIT 0xFFC03308 /* HMDMA0 Initial Block Count Register */
-#define HMDMA0_ECURGENT 0xFFC0330C /* HMDMA0 Urgent Edge Count Threshhold Register */
+#define HMDMA0_ECURGENT 0xFFC0330C /* HMDMA0 Urgent Edge Count Threshold Register */
#define HMDMA0_ECOVERFLOW 0xFFC03310 /* HMDMA0 Edge Count Overflow Interrupt Register */
#define HMDMA0_ECOUNT 0xFFC03314 /* HMDMA0 Current Edge Count Register */
#define HMDMA0_BCOUNT 0xFFC03318 /* HMDMA0 Current Block Count Register */
@@ -552,7 +552,7 @@
#define HMDMA1_CONTROL 0xFFC03340 /* Handshake MDMA1 Control Register */
#define HMDMA1_ECINIT 0xFFC03344 /* HMDMA1 Initial Edge Count Register */
#define HMDMA1_BCINIT 0xFFC03348 /* HMDMA1 Initial Block Count Register */
-#define HMDMA1_ECURGENT 0xFFC0334C /* HMDMA1 Urgent Edge Count Threshhold Register */
+#define HMDMA1_ECURGENT 0xFFC0334C /* HMDMA1 Urgent Edge Count Threshold Register */
#define HMDMA1_ECOVERFLOW 0xFFC03350 /* HMDMA1 Edge Count Overflow Interrupt Register */
#define HMDMA1_ECOUNT 0xFFC03354 /* HMDMA1 Current Edge Count Register */
#define HMDMA1_BCOUNT 0xFFC03358 /* HMDMA1 Current Block Count Register */
diff --git a/arch/blackfin/mach-bf537/include/mach/defBF534.h b/arch/blackfin/mach-bf537/include/mach/defBF534.h
index cebb14f..a6d20ca 100644
--- a/arch/blackfin/mach-bf537/include/mach/defBF534.h
+++ b/arch/blackfin/mach-bf537/include/mach/defBF534.h
@@ -934,7 +934,7 @@
#define HMDMA0_CONTROL 0xFFC03300 /* Handshake MDMA0 Control Register */
#define HMDMA0_ECINIT 0xFFC03304 /* HMDMA0 Initial Edge Count Register */
#define HMDMA0_BCINIT 0xFFC03308 /* HMDMA0 Initial Block Count Register */
-#define HMDMA0_ECURGENT 0xFFC0330C /* HMDMA0 Urgent Edge Count Threshhold Register */
+#define HMDMA0_ECURGENT 0xFFC0330C /* HMDMA0 Urgent Edge Count Threshold Register */
#define HMDMA0_ECOVERFLOW 0xFFC03310 /* HMDMA0 Edge Count Overflow Interrupt Register */
#define HMDMA0_ECOUNT 0xFFC03314 /* HMDMA0 Current Edge Count Register */
#define HMDMA0_BCOUNT 0xFFC03318 /* HMDMA0 Current Block Count Register */
@@ -942,7 +942,7 @@
#define HMDMA1_CONTROL 0xFFC03340 /* Handshake MDMA1 Control Register */
#define HMDMA1_ECINIT 0xFFC03344 /* HMDMA1 Initial Edge Count Register */
#define HMDMA1_BCINIT 0xFFC03348 /* HMDMA1 Initial Block Count Register */
-#define HMDMA1_ECURGENT 0xFFC0334C /* HMDMA1 Urgent Edge Count Threshhold Register */
+#define HMDMA1_ECURGENT 0xFFC0334C /* HMDMA1 Urgent Edge Count Threshold Register */
#define HMDMA1_ECOVERFLOW 0xFFC03350 /* HMDMA1 Edge Count Overflow Interrupt Register */
#define HMDMA1_ECOUNT 0xFFC03354 /* HMDMA1 Current Edge Count Register */
#define HMDMA1_BCOUNT 0xFFC03358 /* HMDMA1 Current Block Count Register */
diff --git a/arch/blackfin/mach-bf548/include/mach/defBF544.h b/arch/blackfin/mach-bf548/include/mach/defBF544.h
index dd414ae..39f588d 100644
--- a/arch/blackfin/mach-bf548/include/mach/defBF544.h
+++ b/arch/blackfin/mach-bf548/include/mach/defBF544.h
@@ -491,7 +491,7 @@
#define HMDMA0_CONTROL 0xffc04500 /* Handshake MDMA0 Control Register */
#define HMDMA0_ECINIT 0xffc04504 /* Handshake MDMA0 Initial Edge Count Register */
#define HMDMA0_BCINIT 0xffc04508 /* Handshake MDMA0 Initial Block Count Register */
-#define HMDMA0_ECURGENT 0xffc0450c /* Handshake MDMA0 Urgent Edge Count Threshhold Register */
+#define HMDMA0_ECURGENT 0xffc0450c /* Handshake MDMA0 Urgent Edge Count Threshold Register */
#define HMDMA0_ECOVERFLOW 0xffc04510 /* Handshake MDMA0 Edge Count Overflow Interrupt Register */
#define HMDMA0_ECOUNT 0xffc04514 /* Handshake MDMA0 Current Edge Count Register */
#define HMDMA0_BCOUNT 0xffc04518 /* Handshake MDMA0 Current Block Count Register */
@@ -501,7 +501,7 @@
#define HMDMA1_CONTROL 0xffc04540 /* Handshake MDMA1 Control Register */
#define HMDMA1_ECINIT 0xffc04544 /* Handshake MDMA1 Initial Edge Count Register */
#define HMDMA1_BCINIT 0xffc04548 /* Handshake MDMA1 Initial Block Count Register */
-#define HMDMA1_ECURGENT 0xffc0454c /* Handshake MDMA1 Urgent Edge Count Threshhold Register */
+#define HMDMA1_ECURGENT 0xffc0454c /* Handshake MDMA1 Urgent Edge Count Threshold Register */
#define HMDMA1_ECOVERFLOW 0xffc04550 /* Handshake MDMA1 Edge Count Overflow Interrupt Register */
#define HMDMA1_ECOUNT 0xffc04554 /* Handshake MDMA1 Current Edge Count Register */
#define HMDMA1_BCOUNT 0xffc04558 /* Handshake MDMA1 Current Block Count Register */
diff --git a/arch/blackfin/mach-bf548/include/mach/defBF547.h b/arch/blackfin/mach-bf548/include/mach/defBF547.h
index 5a9dbab..c4dcf30 100644
--- a/arch/blackfin/mach-bf548/include/mach/defBF547.h
+++ b/arch/blackfin/mach-bf548/include/mach/defBF547.h
@@ -470,7 +470,7 @@
#define HMDMA0_CONTROL 0xffc04500 /* Handshake MDMA0 Control Register */
#define HMDMA0_ECINIT 0xffc04504 /* Handshake MDMA0 Initial Edge Count Register */
#define HMDMA0_BCINIT 0xffc04508 /* Handshake MDMA0 Initial Block Count Register */
-#define HMDMA0_ECURGENT 0xffc0450c /* Handshake MDMA0 Urgent Edge Count Threshhold Register */
+#define HMDMA0_ECURGENT 0xffc0450c /* Handshake MDMA0 Urgent Edge Count Threshold Register */
#define HMDMA0_ECOVERFLOW 0xffc04510 /* Handshake MDMA0 Edge Count Overflow Interrupt Register */
#define HMDMA0_ECOUNT 0xffc04514 /* Handshake MDMA0 Current Edge Count Register */
#define HMDMA0_BCOUNT 0xffc04518 /* Handshake MDMA0 Current Block Count Register */
@@ -480,7 +480,7 @@
#define HMDMA1_CONTROL 0xffc04540 /* Handshake MDMA1 Control Register */
#define HMDMA1_ECINIT 0xffc04544 /* Handshake MDMA1 Initial Edge Count Register */
#define HMDMA1_BCINIT 0xffc04548 /* Handshake MDMA1 Initial Block Count Register */
-#define HMDMA1_ECURGENT 0xffc0454c /* Handshake MDMA1 Urgent Edge Count Threshhold Register */
+#define HMDMA1_ECURGENT 0xffc0454c /* Handshake MDMA1 Urgent Edge Count Threshold Register */
#define HMDMA1_ECOVERFLOW 0xffc04550 /* Handshake MDMA1 Edge Count Overflow Interrupt Register */
#define HMDMA1_ECOUNT 0xffc04554 /* Handshake MDMA1 Current Edge Count Register */
#define HMDMA1_BCOUNT 0xffc04558 /* Handshake MDMA1 Current Block Count Register */
diff --git a/arch/blackfin/mach-bf548/include/mach/defBF548.h b/arch/blackfin/mach-bf548/include/mach/defBF548.h
index 82cd593..a507998 100644
--- a/arch/blackfin/mach-bf548/include/mach/defBF548.h
+++ b/arch/blackfin/mach-bf548/include/mach/defBF548.h
@@ -853,7 +853,7 @@
#define HMDMA0_CONTROL 0xffc04500 /* Handshake MDMA0 Control Register */
#define HMDMA0_ECINIT 0xffc04504 /* Handshake MDMA0 Initial Edge Count Register */
#define HMDMA0_BCINIT 0xffc04508 /* Handshake MDMA0 Initial Block Count Register */
-#define HMDMA0_ECURGENT 0xffc0450c /* Handshake MDMA0 Urgent Edge Count Threshhold Register */
+#define HMDMA0_ECURGENT 0xffc0450c /* Handshake MDMA0 Urgent Edge Count Threshold Register */
#define HMDMA0_ECOVERFLOW 0xffc04510 /* Handshake MDMA0 Edge Count Overflow Interrupt Register */
#define HMDMA0_ECOUNT 0xffc04514 /* Handshake MDMA0 Current Edge Count Register */
#define HMDMA0_BCOUNT 0xffc04518 /* Handshake MDMA0 Current Block Count Register */
@@ -863,7 +863,7 @@
#define HMDMA1_CONTROL 0xffc04540 /* Handshake MDMA1 Control Register */
#define HMDMA1_ECINIT 0xffc04544 /* Handshake MDMA1 Initial Edge Count Register */
#define HMDMA1_BCINIT 0xffc04548 /* Handshake MDMA1 Initial Block Count Register */
-#define HMDMA1_ECURGENT 0xffc0454c /* Handshake MDMA1 Urgent Edge Count Threshhold Register */
+#define HMDMA1_ECURGENT 0xffc0454c /* Handshake MDMA1 Urgent Edge Count Threshold Register */
#define HMDMA1_ECOVERFLOW 0xffc04550 /* Handshake MDMA1 Edge Count Overflow Interrupt Register */
#define HMDMA1_ECOUNT 0xffc04554 /* Handshake MDMA1 Current Edge Count Register */
#define HMDMA1_BCOUNT 0xffc04558 /* Handshake MDMA1 Current Block Count Register */
diff --git a/arch/blackfin/mach-bf548/include/mach/defBF549.h b/arch/blackfin/mach-bf548/include/mach/defBF549.h
index 6fc6e39..f7f0435 100644
--- a/arch/blackfin/mach-bf548/include/mach/defBF549.h
+++ b/arch/blackfin/mach-bf548/include/mach/defBF549.h
@@ -1024,7 +1024,7 @@
#define HMDMA0_CONTROL 0xffc04500 /* Handshake MDMA0 Control Register */
#define HMDMA0_ECINIT 0xffc04504 /* Handshake MDMA0 Initial Edge Count Register */
#define HMDMA0_BCINIT 0xffc04508 /* Handshake MDMA0 Initial Block Count Register */
-#define HMDMA0_ECURGENT 0xffc0450c /* Handshake MDMA0 Urgent Edge Count Threshhold Register */
+#define HMDMA0_ECURGENT 0xffc0450c /* Handshake MDMA0 Urgent Edge Count Threshold Register */
#define HMDMA0_ECOVERFLOW 0xffc04510 /* Handshake MDMA0 Edge Count Overflow Interrupt Register */
#define HMDMA0_ECOUNT 0xffc04514 /* Handshake MDMA0 Current Edge Count Register */
#define HMDMA0_BCOUNT 0xffc04518 /* Handshake MDMA0 Current Block Count Register */
@@ -1034,7 +1034,7 @@
#define HMDMA1_CONTROL 0xffc04540 /* Handshake MDMA1 Control Register */
#define HMDMA1_ECINIT 0xffc04544 /* Handshake MDMA1 Initial Edge Count Register */
#define HMDMA1_BCINIT 0xffc04548 /* Handshake MDMA1 Initial Block Count Register */
-#define HMDMA1_ECURGENT 0xffc0454c /* Handshake MDMA1 Urgent Edge Count Threshhold Register */
+#define HMDMA1_ECURGENT 0xffc0454c /* Handshake MDMA1 Urgent Edge Count Threshold Register */
#define HMDMA1_ECOVERFLOW 0xffc04550 /* Handshake MDMA1 Edge Count Overflow Interrupt Register */
#define HMDMA1_ECOUNT 0xffc04554 /* Handshake MDMA1 Current Edge Count Register */
#define HMDMA1_BCOUNT 0xffc04558 /* Handshake MDMA1 Current Block Count Register */
diff --git a/arch/cris/arch-v10/mm/fault.c b/arch/cris/arch-v10/mm/fault.c
index 087a209..ed60588 100644
--- a/arch/cris/arch-v10/mm/fault.c
+++ b/arch/cris/arch-v10/mm/fault.c
@@ -80,8 +80,7 @@ handle_mmu_bus_fault(struct pt_regs *regs)
* do_page_fault may have flushed the TLB so we have to restore
* the MMU registers.
*/
- local_save_flags(flags);
- local_irq_disable();
+ local_irq_save(flags);
pmd = (pmd_t *)(pgd + pgd_index(address));
if (pmd_none(*pmd))
goto exit;
diff --git a/arch/cris/arch-v10/mm/tlb.c b/arch/cris/arch-v10/mm/tlb.c
index 4a496e4..21d78c5 100644
--- a/arch/cris/arch-v10/mm/tlb.c
+++ b/arch/cris/arch-v10/mm/tlb.c
@@ -134,28 +134,6 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
local_irq_restore(flags);
}
-/* dump the entire TLB for debug purposes */
-
-#if 0
-void
-dump_tlb_all(void)
-{
- int i;
- unsigned long flags;
-
- printk("TLB dump. LO is: pfn | reserved | global | valid | kernel | we |\n");
-
- local_save_flags(flags);
- local_irq_disable();
- for(i = 0; i < NUM_TLB_ENTRIES; i++) {
- *R_TLB_SELECT = ( IO_FIELD(R_TLB_SELECT, index, i) );
- printk("Entry %d: HI 0x%08lx, LO 0x%08lx\n",
- i, *R_TLB_HI, *R_TLB_LO);
- }
- local_irq_restore(flags);
-}
-#endif
-
/*
* Initialize the context related info for a new mm_struct
* instance.
diff --git a/arch/cris/mm/fault.c b/arch/cris/mm/fault.c
index 4a7cdd9..380df1a 100644
--- a/arch/cris/mm/fault.c
+++ b/arch/cris/mm/fault.c
@@ -209,7 +209,7 @@ do_page_fault(unsigned long address, struct pt_regs *regs,
/* Are we prepared to handle this kernel fault?
*
* (The kernel has valid exception-points in the source
- * when it acesses user-memory. When it fails in one
+ * when it accesses user-memory. When it fails in one
* of those points, we find it in a table and do a jump
* to some fixup code that loads an appropriate error
* code)
diff --git a/arch/frv/kernel/process.c b/arch/frv/kernel/process.c
index 9042559..21d0fd1 100644
--- a/arch/frv/kernel/process.c
+++ b/arch/frv/kernel/process.c
@@ -255,15 +255,12 @@ asmlinkage int sys_execve(char __user *name, char __user * __user *argv, char __
int error;
char * filename;
- lock_kernel();
filename = getname(name);
error = PTR_ERR(filename);
if (IS_ERR(filename))
- goto out;
+ return error;
error = do_execve(filename, argv, envp, __frame);
putname(filename);
- out:
- unlock_kernel();
return error;
}
diff --git a/arch/h8300/kernel/process.c b/arch/h8300/kernel/process.c
index e2f33d0..bd883fa 100644
--- a/arch/h8300/kernel/process.c
+++ b/arch/h8300/kernel/process.c
@@ -218,15 +218,12 @@ asmlinkage int sys_execve(char *name, char **argv, char **envp,int dummy,...)
char * filename;
struct pt_regs *regs = (struct pt_regs *) ((unsigned char *)&dummy-4);
- lock_kernel();
filename = getname(name);
error = PTR_ERR(filename);
if (IS_ERR(filename))
- goto out;
+ return error;
error = do_execve(filename, argv, envp, regs);
putname(filename);
-out:
- unlock_kernel();
return error;
}
diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c
index 674a837..f332e3f 100644
--- a/arch/ia64/hp/common/sba_iommu.c
+++ b/arch/ia64/hp/common/sba_iommu.c
@@ -1381,7 +1381,7 @@ sba_coalesce_chunks(struct ioc *ioc, struct device *dev,
#endif
/*
- ** Not virtually contigous.
+ ** Not virtually contiguous.
** Terminate prev chunk.
** Start a new chunk.
**
diff --git a/arch/ia64/ia32/ia32_entry.S b/arch/ia64/ia32/ia32_entry.S
index 10c3751..2fd7479 100644
--- a/arch/ia64/ia32/ia32_entry.S
+++ b/arch/ia64/ia32/ia32_entry.S
@@ -79,7 +79,7 @@ GLOBAL_ENTRY(ia32_ret_from_clone)
(p6) br.cond.spnt .ia32_strace_check_retval
;; // prevent RAW on r8
END(ia32_ret_from_clone)
- // fall thrugh
+ // fall through
GLOBAL_ENTRY(ia32_ret_from_syscall)
PT_REGS_UNWIND_INFO(0)
diff --git a/arch/ia64/include/asm/perfmon_default_smpl.h b/arch/ia64/include/asm/perfmon_default_smpl.h
index 48822c0..74724b2 100644
--- a/arch/ia64/include/asm/perfmon_default_smpl.h
+++ b/arch/ia64/include/asm/perfmon_default_smpl.h
@@ -67,7 +67,7 @@ typedef struct {
unsigned long ip; /* where did the overflow interrupt happened */
unsigned long tstamp; /* ar.itc when entering perfmon intr. handler */
- unsigned short cpu; /* cpu on which the overfow occured */
+ unsigned short cpu; /* cpu on which the overflow occured */
unsigned short set; /* event set active when overflow ocurred */
int tgid; /* thread group id (for NPTL, this is getpid()) */
} pfm_default_smpl_entry_t;
diff --git a/arch/ia64/include/asm/sn/shubio.h b/arch/ia64/include/asm/sn/shubio.h
index 22a6f18..6052422 100644
--- a/arch/ia64/include/asm/sn/shubio.h
+++ b/arch/ia64/include/asm/sn/shubio.h
@@ -3289,7 +3289,7 @@ typedef ii_icrb0_e_u_t icrbe_t;
#define IIO_IIDSR_LVL_SHIFT 0
#define IIO_IIDSR_LVL_MASK 0x000000ff
-/* Xtalk timeout threshhold register (IIO_IXTT) */
+/* Xtalk timeout threshold register (IIO_IXTT) */
#define IXTT_RRSP_TO_SHFT 55 /* read response timeout */
#define IXTT_RRSP_TO_MASK (0x1FULL << IXTT_RRSP_TO_SHFT)
#define IXTT_RRSP_PS_SHFT 32 /* read responsed TO prescalar */
diff --git a/arch/ia64/include/asm/unistd.h b/arch/ia64/include/asm/unistd.h
index 9c72e36..10a8f21 100644
--- a/arch/ia64/include/asm/unistd.h
+++ b/arch/ia64/include/asm/unistd.h
@@ -311,7 +311,7 @@
#define __NR_preadv 1319
#define __NR_pwritev 1320
#define __NR_rt_tgsigqueueinfo 1321
-#define __NR_rt_recvmmsg 1322
+#define __NR_recvmmsg 1322
#ifdef __KERNEL__
diff --git a/arch/ia64/kernel/esi.c b/arch/ia64/kernel/esi.c
index d5764a3..b091111 100644
--- a/arch/ia64/kernel/esi.c
+++ b/arch/ia64/kernel/esi.c
@@ -84,7 +84,7 @@ static int __init esi_init (void)
case ESI_DESC_ENTRY_POINT:
break;
default:
- printk(KERN_WARNING "Unkown table type %d found in "
+ printk(KERN_WARNING "Unknown table type %d found in "
"ESI table, ignoring rest of table\n", *p);
return -ENODEV;
}
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
index 402698b..599b233 100644
--- a/arch/ia64/kernel/perfmon.c
+++ b/arch/ia64/kernel/perfmon.c
@@ -3517,7 +3517,7 @@ pfm_use_debug_registers(struct task_struct *task)
* IA64_THREAD_DBG_VALID set. This indicates a task which was
* able to use the debug registers for debugging purposes via
* ptrace(). Therefore we know it was not using them for
- * perfmormance monitoring, so we only decrement the number
+ * performance monitoring, so we only decrement the number
* of "ptraced" debug register users to keep the count up to date
*/
int
diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
index 4990495..a35c661 100644
--- a/arch/ia64/kernel/time.c
+++ b/arch/ia64/kernel/time.c
@@ -473,7 +473,7 @@ void update_vsyscall_tz(void)
{
}
-void update_vsyscall(struct timespec *wall, struct clocksource *c)
+void update_vsyscall(struct timespec *wall, struct clocksource *c, u32 mult)
{
unsigned long flags;
@@ -481,7 +481,7 @@ void update_vsyscall(struct timespec *wall, struct clocksource *c)
/* copy fsyscall clock data */
fsyscall_gtod_data.clk_mask = c->mask;
- fsyscall_gtod_data.clk_mult = c->mult;
+ fsyscall_gtod_data.clk_mult = mult;
fsyscall_gtod_data.clk_shift = c->shift;
fsyscall_gtod_data.clk_fsys_mmio = c->fsys_mmio;
fsyscall_gtod_data.clk_cycle_last = c->cycle_last;
diff --git a/arch/m68k/ifpsp060/src/fpsp.S b/arch/m68k/ifpsp060/src/fpsp.S
index 6c1a9a2..73613b5 100644
--- a/arch/m68k/ifpsp060/src/fpsp.S
+++ b/arch/m68k/ifpsp060/src/fpsp.S
@@ -753,7 +753,7 @@ fovfl_ovfl_on:
bra.l _real_ovfl
-# overflow occurred but is disabled. meanwhile, inexact is enabled. therefore,
+# overflow occurred but is disabled. meanwhile, inexact is enabled. Therefore,
# we must jump to real_inex().
fovfl_inex_on:
@@ -1015,7 +1015,7 @@ funfl_unfl_on2:
bra.l _real_unfl
-# undeflow occurred but is disabled. meanwhile, inexact is enabled. therefore,
+# underflow occurred but is disabled. meanwhile, inexact is enabled. Therefore,
# we must jump to real_inex().
funfl_inex_on:
@@ -2963,7 +2963,7 @@ iea_disabled:
tst.w %d0 # is instr fmovm?
bmi.b iea_dis_fmovm # yes
-# instruction is using an extended precision immediate operand. therefore,
+# instruction is using an extended precision immediate operand. Therefore,
# the total instruction length is 16 bytes.
iea_dis_immed:
mov.l &0x10,%d0 # 16 bytes of instruction
@@ -9624,7 +9624,7 @@ sok_dnrm:
bge.b sok_norm2 # thank goodness no
# the multiply factor that we're trying to create should be a denorm
-# for the multiply to work. therefore, we're going to actually do a
+# for the multiply to work. Therefore, we're going to actually do a
# multiply with a denorm which will cause an unimplemented data type
# exception to be put into the machine which will be caught and corrected
# later. we don't do this with the DENORMs above because this method
@@ -12216,7 +12216,7 @@ fin_sd_unfl_dis:
#
# operand will underflow AND underflow or inexact is enabled.
-# therefore, we must return the result rounded to extended precision.
+# Therefore, we must return the result rounded to extended precision.
#
fin_sd_unfl_ena:
mov.l FP_SCR0_HI(%a6),FP_SCR1_HI(%a6)
@@ -12746,7 +12746,7 @@ fdiv_zero_load_p:
#
# The destination was In Range and the source was a ZERO. The result,
-# therefore, is an INF w/ the proper sign.
+# Therefore, is an INF w/ the proper sign.
# So, determine the sign and return a new INF (w/ the j-bit cleared).
#
global fdiv_inf_load # global for fsgldiv
@@ -12996,7 +12996,7 @@ fneg_sd_unfl_dis:
#
# operand will underflow AND underflow is enabled.
-# therefore, we must return the result rounded to extended precision.
+# Therefore, we must return the result rounded to extended precision.
#
fneg_sd_unfl_ena:
mov.l FP_SCR0_HI(%a6),FP_SCR1_HI(%a6)
@@ -13611,7 +13611,7 @@ fabs_sd_unfl_dis:
#
# operand will underflow AND underflow is enabled.
-# therefore, we must return the result rounded to extended precision.
+# Therefore, we must return the result rounded to extended precision.
#
fabs_sd_unfl_ena:
mov.l FP_SCR0_HI(%a6),FP_SCR1_HI(%a6)
@@ -14973,7 +14973,7 @@ fadd_zero_2:
#
# the ZEROes have opposite signs:
-# - therefore, we return +ZERO if the rounding modes are RN,RZ, or RP.
+# - Therefore, we return +ZERO if the rounding modes are RN,RZ, or RP.
# - -ZERO is returned in the case of RM.
#
fadd_zero_2_chk_rm:
@@ -15425,7 +15425,7 @@ fsub_zero_2:
#
# the ZEROes have the same signs:
-# - therefore, we return +ZERO if the rounding mode is RN,RZ, or RP
+# - Therefore, we return +ZERO if the rounding mode is RN,RZ, or RP
# - -ZERO is returned in the case of RM.
#
fsub_zero_2_chk_rm:
@@ -15693,7 +15693,7 @@ fsqrt_sd_unfl_dis:
#
# operand will underflow AND underflow is enabled.
-# therefore, we must return the result rounded to extended precision.
+# Therefore, we must return the result rounded to extended precision.
#
fsqrt_sd_unfl_ena:
mov.l FP_SCR0_HI(%a6),FP_SCR1_HI(%a6)
@@ -21000,7 +21000,7 @@ fout_pack_type:
tst.l %d0
bne.b fout_pack_set
# "mantissa" is all zero which means that the answer is zero. but, the '040
-# algorithm allows the exponent to be non-zero. the 881/2 do not. therefore,
+# algorithm allows the exponent to be non-zero. the 881/2 do not. Therefore,
# if the mantissa is zero, I will zero the exponent, too.
# the question now is whether the exponents sign bit is allowed to be non-zero
# for a zero, also...
@@ -21743,7 +21743,7 @@ denorm_set_stky:
rts
# #
-# dnrm_lp(): normalize exponent/mantissa to specified threshhold #
+# dnrm_lp(): normalize exponent/mantissa to specified threshold #
# #
# INPUT: #
# %a0 : points to the operand to be denormalized #
@@ -22402,7 +22402,7 @@ unnorm_shift:
bgt.b unnorm_nrm_zero # yes; denorm only until exp = 0
#
-# exponent would not go < 0. therefore, number stays normalized
+# exponent would not go < 0. Therefore, number stays normalized
#
sub.w %d0, %d1 # shift exponent value
mov.w FTEMP_EX(%a0), %d0 # load old exponent
diff --git a/arch/m68k/ifpsp060/src/pfpsp.S b/arch/m68k/ifpsp060/src/pfpsp.S
index 51b9f7d..e71ba0a 100644
--- a/arch/m68k/ifpsp060/src/pfpsp.S
+++ b/arch/m68k/ifpsp060/src/pfpsp.S
@@ -752,7 +752,7 @@ fovfl_ovfl_on:
bra.l _real_ovfl
-# overflow occurred but is disabled. meanwhile, inexact is enabled. therefore,
+# overflow occurred but is disabled. meanwhile, inexact is enabled. Therefore,
# we must jump to real_inex().
fovfl_inex_on:
@@ -1014,7 +1014,7 @@ funfl_unfl_on2:
bra.l _real_unfl
-# undeflow occurred but is disabled. meanwhile, inexact is enabled. therefore,
+# underflow occurred but is disabled. meanwhile, inexact is enabled. Therefore,
# we must jump to real_inex().
funfl_inex_on:
@@ -2962,7 +2962,7 @@ iea_disabled:
tst.w %d0 # is instr fmovm?
bmi.b iea_dis_fmovm # yes
-# instruction is using an extended precision immediate operand. therefore,
+# instruction is using an extended precision immediate operand. Therefore,
# the total instruction length is 16 bytes.
iea_dis_immed:
mov.l &0x10,%d0 # 16 bytes of instruction
@@ -5865,7 +5865,7 @@ denorm_set_stky:
rts
# #
-# dnrm_lp(): normalize exponent/mantissa to specified threshhold #
+# dnrm_lp(): normalize exponent/mantissa to specified threshold #
# #
# INPUT: #
# %a0 : points to the operand to be denormalized #
@@ -6524,7 +6524,7 @@ unnorm_shift:
bgt.b unnorm_nrm_zero # yes; denorm only until exp = 0
#
-# exponent would not go < 0. therefore, number stays normalized
+# exponent would not go < 0. Therefore, number stays normalized
#
sub.w %d0, %d1 # shift exponent value
mov.w FTEMP_EX(%a0), %d0 # load old exponent
@@ -7901,7 +7901,7 @@ fout_pack_type:
tst.l %d0
bne.b fout_pack_set
# "mantissa" is all zero which means that the answer is zero. but, the '040
-# algorithm allows the exponent to be non-zero. the 881/2 do not. therefore,
+# algorithm allows the exponent to be non-zero. the 881/2 do not. Therefore,
# if the mantissa is zero, I will zero the exponent, too.
# the question now is whether the exponents sign bit is allowed to be non-zero
# for a zero, also...
@@ -8647,7 +8647,7 @@ fin_sd_unfl_dis:
#
# operand will underflow AND underflow or inexact is enabled.
-# therefore, we must return the result rounded to extended precision.
+# Therefore, we must return the result rounded to extended precision.
#
fin_sd_unfl_ena:
mov.l FP_SCR0_HI(%a6),FP_SCR1_HI(%a6)
@@ -9177,7 +9177,7 @@ fdiv_zero_load_p:
#
# The destination was In Range and the source was a ZERO. The result,
-# therefore, is an INF w/ the proper sign.
+# Therefore, is an INF w/ the proper sign.
# So, determine the sign and return a new INF (w/ the j-bit cleared).
#
global fdiv_inf_load # global for fsgldiv
@@ -9427,7 +9427,7 @@ fneg_sd_unfl_dis:
#
# operand will underflow AND underflow is enabled.
-# therefore, we must return the result rounded to extended precision.
+# Therefore, we must return the result rounded to extended precision.
#
fneg_sd_unfl_ena:
mov.l FP_SCR0_HI(%a6),FP_SCR1_HI(%a6)
@@ -10042,7 +10042,7 @@ fabs_sd_unfl_dis:
#
# operand will underflow AND underflow is enabled.
-# therefore, we must return the result rounded to extended precision.
+# Therefore, we must return the result rounded to extended precision.
#
fabs_sd_unfl_ena:
mov.l FP_SCR0_HI(%a6),FP_SCR1_HI(%a6)
@@ -11404,7 +11404,7 @@ fadd_zero_2:
#
# the ZEROes have opposite signs:
-# - therefore, we return +ZERO if the rounding modes are RN,RZ, or RP.
+# - Therefore, we return +ZERO if the rounding modes are RN,RZ, or RP.
# - -ZERO is returned in the case of RM.
#
fadd_zero_2_chk_rm:
@@ -11856,7 +11856,7 @@ fsub_zero_2:
#
# the ZEROes have the same signs:
-# - therefore, we return +ZERO if the rounding mode is RN,RZ, or RP
+# - Therefore, we return +ZERO if the rounding mode is RN,RZ, or RP
# - -ZERO is returned in the case of RM.
#
fsub_zero_2_chk_rm:
@@ -12124,7 +12124,7 @@ fsqrt_sd_unfl_dis:
#
# operand will underflow AND underflow is enabled.
-# therefore, we must return the result rounded to extended precision.
+# Therefore, we must return the result rounded to extended precision.
#
fsqrt_sd_unfl_ena:
mov.l FP_SCR0_HI(%a6),FP_SCR1_HI(%a6)
diff --git a/arch/m68k/include/asm/bootinfo.h b/arch/m68k/include/asm/bootinfo.h
index fb8a06b..67e7a78 100644
--- a/arch/m68k/include/asm/bootinfo.h
+++ b/arch/m68k/include/asm/bootinfo.h
@@ -145,7 +145,7 @@ struct bi_record {
/*
* Macintosh hardware profile data - unused, see macintosh.h for
- * resonable type values
+ * reasonable type values
*/
#define BI_MAC_VIA1BASE 0x8010 /* Mac VIA1 base address (always present) */
diff --git a/arch/m68k/include/asm/processor.h b/arch/m68k/include/asm/processor.h
index 74fd674..cbd3d47 100644
--- a/arch/m68k/include/asm/processor.h
+++ b/arch/m68k/include/asm/processor.h
@@ -165,6 +165,8 @@ unsigned long get_wchan(struct task_struct *p);
eip; })
#define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->thread.usp)
+#define task_pt_regs(tsk) ((struct pt_regs *) ((tsk)->thread.esp0))
+
#define cpu_relax() barrier()
#endif
diff --git a/arch/m68k/include/asm/ptrace.h b/arch/m68k/include/asm/ptrace.h
index a6ab663..ee4011c 100644
--- a/arch/m68k/include/asm/ptrace.h
+++ b/arch/m68k/include/asm/ptrace.h
@@ -86,7 +86,7 @@ struct switch_stack {
extern void show_regs(struct pt_regs *);
/*
- * These are defined as per linux/ptrace.h, which see.
+ * These are defined as per linux/ptrace.h.
*/
struct task_struct;
diff --git a/arch/m68k/include/asm/thread_info_no.h b/arch/m68k/include/asm/thread_info_no.h
index c2bde5e..a6512bf 100644
--- a/arch/m68k/include/asm/thread_info_no.h
+++ b/arch/m68k/include/asm/thread_info_no.h
@@ -12,8 +12,6 @@
#ifdef __KERNEL__
-#ifndef __ASSEMBLY__
-
/*
* Size of kernel stack for each process. This must be a power of 2...
*/
@@ -28,6 +26,8 @@
*/
#define THREAD_SIZE (PAGE_SIZE<<THREAD_SIZE_ORDER)
+#ifndef __ASSEMBLY__
+
/*
* low level task data.
*/
diff --git a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig
index e2201b9..064f591 100644
--- a/arch/m68knommu/Kconfig
+++ b/arch/m68knommu/Kconfig
@@ -533,6 +533,13 @@ config AVNET
default y
depends on (AVNET5282)
+config UBOOT
+ bool "Support for U-Boot command line parameters"
+ help
+ If you say Y here kernel will try to collect command
+ line parameters from the initial u-boot stack.
+ default n
+
config 4KSTACKS
bool "Use 4Kb for kernel stacks instead of 8Kb"
default y
diff --git a/arch/m68knommu/kernel/process.c b/arch/m68knommu/kernel/process.c
index 8f8f4ab..5c9ecd4 100644
--- a/arch/m68knommu/kernel/process.c
+++ b/arch/m68knommu/kernel/process.c
@@ -352,15 +352,12 @@ asmlinkage int sys_execve(char *name, char **argv, char **envp)
char * filename;
struct pt_regs *regs = (struct pt_regs *) &name;
- lock_kernel();
filename = getname(name);
error = PTR_ERR(filename);
if (IS_ERR(filename))
- goto out;
+ return error;
error = do_execve(filename, argv, envp, regs);
putname(filename);
-out:
- unlock_kernel();
return error;
}
diff --git a/arch/m68knommu/kernel/setup.c b/arch/m68knommu/kernel/setup.c
index 5c2bb3e..ba92b90 100644
--- a/arch/m68knommu/kernel/setup.c
+++ b/arch/m68knommu/kernel/setup.c
@@ -29,6 +29,8 @@
#include <linux/bootmem.h>
#include <linux/seq_file.h>
#include <linux/init.h>
+#include <linux/initrd.h>
+#include <linux/root_dev.h>
#include <asm/setup.h>
#include <asm/irq.h>
@@ -52,7 +54,6 @@ void (*mach_reset)(void);
void (*mach_halt)(void);
void (*mach_power_off)(void);
-
#ifdef CONFIG_M68000
#define CPU "MC68000"
#endif
@@ -111,6 +112,69 @@ void (*mach_power_off)(void);
extern int _stext, _etext, _sdata, _edata, _sbss, _ebss, _end;
extern int _ramstart, _ramend;
+#if defined(CONFIG_UBOOT)
+/*
+ * parse_uboot_commandline
+ *
+ * Copies u-boot commandline arguments and store them in the proper linux
+ * variables.
+ *
+ * Assumes:
+ * _init_sp global contains the address in the stack pointer when the
+ * kernel starts (see head.S::_start)
+ *
+ * U-Boot calling convention:
+ * (*kernel) (kbd, initrd_start, initrd_end, cmd_start, cmd_end);
+ *
+ * _init_sp can be parsed as such
+ *
+ * _init_sp+00 = u-boot cmd after jsr into kernel (skip)
+ * _init_sp+04 = &kernel board_info (residual data)
+ * _init_sp+08 = &initrd_start
+ * _init_sp+12 = &initrd_end
+ * _init_sp+16 = &cmd_start
+ * _init_sp+20 = &cmd_end
+ *
+ * This also assumes that the memory locations pointed to are still
+ * unmodified. U-boot places them near the end of external SDRAM.
+ *
+ * Argument(s):
+ * commandp = the linux commandline arg container to fill.
+ * size = the sizeof commandp.
+ *
+ * Returns:
+ */
+void parse_uboot_commandline(char *commandp, int size)
+{
+ extern unsigned long _init_sp;
+ unsigned long *sp;
+ unsigned long uboot_kbd;
+ unsigned long uboot_initrd_start, uboot_initrd_end;
+ unsigned long uboot_cmd_start, uboot_cmd_end;
+
+
+ sp = (unsigned long *)_init_sp;
+ uboot_kbd = sp[1];
+ uboot_initrd_start = sp[2];
+ uboot_initrd_end = sp[3];
+ uboot_cmd_start = sp[4];
+ uboot_cmd_end = sp[5];
+
+ if (uboot_cmd_start && uboot_cmd_end)
+ strncpy(commandp, (const char *)uboot_cmd_start, size);
+#if defined(CONFIG_BLK_DEV_INITRD)
+ if (uboot_initrd_start && uboot_initrd_end &&
+ (uboot_initrd_end > uboot_initrd_start)) {
+ initrd_start = uboot_initrd_start;
+ initrd_end = uboot_initrd_end;
+ ROOT_DEV = Root_RAM0;
+ printk(KERN_INFO "initrd at 0x%lx:0x%lx\n",
+ initrd_start, initrd_end);
+ }
+#endif /* if defined(CONFIG_BLK_DEV_INITRD) */
+}
+#endif /* #if defined(CONFIG_UBOOT) */
+
void __init setup_arch(char **cmdline_p)
{
int bootmap_size;
@@ -128,7 +192,24 @@ void __init setup_arch(char **cmdline_p)
#if defined(CONFIG_BOOTPARAM)
strncpy(&command_line[0], CONFIG_BOOTPARAM_STRING, sizeof(command_line));
command_line[sizeof(command_line) - 1] = 0;
-#endif
+#endif /* CONFIG_BOOTPARAM */
+
+#if defined(CONFIG_UBOOT)
+ /* CONFIG_UBOOT and CONFIG_BOOTPARAM defined, concatenate cmdline */
+ #if defined(CONFIG_BOOTPARAM)
+ /* Add the whitespace separator */
+ command_line[strlen(CONFIG_BOOTPARAM_STRING)] = ' ';
+ /* Parse uboot command line into the rest of the buffer */
+ parse_uboot_commandline(
+ &command_line[(strlen(CONFIG_BOOTPARAM_STRING)+1)],
+ (sizeof(command_line) -
+ (strlen(CONFIG_BOOTPARAM_STRING)+1)));
+ /* Only CONFIG_UBOOT defined, create cmdline */
+ #else
+ parse_uboot_commandline(&command_line[0], sizeof(command_line));
+ #endif /* CONFIG_BOOTPARAM */
+ command_line[sizeof(command_line) - 1] = 0;
+#endif /* CONFIG_UBOOT */
printk(KERN_INFO "\x0F\r\n\nuClinux/" CPU "\n");
@@ -204,6 +285,13 @@ void __init setup_arch(char **cmdline_p)
free_bootmem(memory_start, memory_end - memory_start);
reserve_bootmem(memory_start, bootmap_size, BOOTMEM_DEFAULT);
+#if defined(CONFIG_UBOOT) && defined(CONFIG_BLK_DEV_INITRD)
+ if ((initrd_start > 0) && (initrd_start < initrd_end) &&
+ (initrd_end < memory_end))
+ reserve_bootmem(initrd_start, initrd_end - initrd_start,
+ BOOTMEM_DEFAULT);
+#endif /* if defined(CONFIG_BLK_DEV_INITRD) */
+
/*
* Get kmalloc into gear.
*/
diff --git a/arch/m68knommu/kernel/vmlinux.lds.S b/arch/m68knommu/kernel/vmlinux.lds.S
index 2736a5e..9f1784f 100644
--- a/arch/m68knommu/kernel/vmlinux.lds.S
+++ b/arch/m68knommu/kernel/vmlinux.lds.S
@@ -8,6 +8,8 @@
*/
#include <asm-generic/vmlinux.lds.h>
+#include <asm/page.h>
+#include <asm/thread_info.h>
#if defined(CONFIG_RAMKERNEL)
#define RAM_START CONFIG_KERNELBASE
@@ -15,7 +17,7 @@
#define TEXT ram
#define DATA ram
#define INIT ram
-#define BSS ram
+#define BSSS ram
#endif
#if defined(CONFIG_ROMKERNEL) || defined(CONFIG_HIMEMKERNEL)
#define RAM_START CONFIG_RAMBASE
@@ -27,7 +29,7 @@
#define TEXT rom
#define DATA ram
#define INIT ram
-#define BSS ram
+#define BSSS ram
#endif
#ifndef DATA_ADDR
@@ -147,40 +149,19 @@ SECTIONS {
. = ALIGN(4);
_sdata = . ;
DATA_DATA
- . = ALIGN(32);
- *(.data.cacheline_aligned)
- . = ALIGN(8192) ;
- *(.data.init_task)
+ CACHELINE_ALIGNED_DATA(32)
+ INIT_TASK_DATA(THREAD_SIZE)
_edata = . ;
} > DATA
- .init : {
- . = ALIGN(4096);
+ .init.text : {
+ . = ALIGN(PAGE_SIZE);
__init_begin = .;
- _sinittext = .;
- INIT_TEXT
- _einittext = .;
- INIT_DATA
- . = ALIGN(16);
- __setup_start = .;
- *(.init.setup)
- __setup_end = .;
- __initcall_start = .;
- INITCALLS
- __initcall_end = .;
- __con_initcall_start = .;
- *(.con_initcall.init)
- __con_initcall_end = .;
- __security_initcall_start = .;
- *(.security_initcall.init)
- __security_initcall_end = .;
-#ifdef CONFIG_BLK_DEV_INITRD
- . = ALIGN(4);
- __initramfs_start = .;
- *(.init.ramfs)
- __initramfs_end = .;
-#endif
- . = ALIGN(4096);
+ } > INIT
+ INIT_TEXT_SECTION(PAGE_SIZE) > INIT
+ INIT_DATA_SECTION(16) > INIT
+ .init.data : {
+ . = ALIGN(PAGE_SIZE);
__init_end = .;
} > INIT
@@ -192,7 +173,7 @@ SECTIONS {
. = ALIGN(4) ;
_ebss = . ;
_end = . ;
- } > BSS
+ } > BSSS
DISCARDS
}
diff --git a/arch/m68knommu/platform/523x/gpio.c b/arch/m68knommu/platform/523x/gpio.c
index f02840d..a8842dc 100644
--- a/arch/m68knommu/platform/523x/gpio.c
+++ b/arch/m68knommu/platform/523x/gpio.c
@@ -30,7 +30,8 @@ static struct mcf_gpio_chip mcf_gpio_chips[] = {
.direction_output = mcf_gpio_direction_output,
.get = mcf_gpio_get_value,
.set = mcf_gpio_set_value,
- .ngpio = 8,
+ .base = 1,
+ .ngpio = 7,
},
.pddr = MCFEPORT_EPDDR,
.podr = MCFEPORT_EPDR,
@@ -244,7 +245,7 @@ static struct mcf_gpio_chip mcf_gpio_chips[] = {
.get = mcf_gpio_get_value,
.set = mcf_gpio_set_value_fast,
.base = 96,
- .ngpio = 4,
+ .ngpio = 8,
},
.pddr = MCFGPIO_PDDR_TIMER,
.podr = MCFGPIO_PODR_TIMER,
diff --git a/arch/m68knommu/platform/527x/gpio.c b/arch/m68knommu/platform/527x/gpio.c
index 1028142..0b56e19 100644
--- a/arch/m68knommu/platform/527x/gpio.c
+++ b/arch/m68knommu/platform/527x/gpio.c
@@ -31,7 +31,8 @@ static struct mcf_gpio_chip mcf_gpio_chips[] = {
.direction_output = mcf_gpio_direction_output,
.get = mcf_gpio_get_value,
.set = mcf_gpio_set_value,
- .ngpio = 8,
+ .base = 1,
+ .ngpio = 7,
},
.pddr = MCFEPORT_EPDDR,
.podr = MCFEPORT_EPDR,
@@ -263,7 +264,8 @@ static struct mcf_gpio_chip mcf_gpio_chips[] = {
.direction_output = mcf_gpio_direction_output,
.get = mcf_gpio_get_value,
.set = mcf_gpio_set_value,
- .ngpio = 8,
+ .base = 1,
+ .ngpio = 7,
},
.pddr = MCFEPORT_EPDDR,
.podr = MCFEPORT_EPDR,
diff --git a/arch/m68knommu/platform/528x/gpio.c b/arch/m68knommu/platform/528x/gpio.c
index ec59395..eedaf0a 100644
--- a/arch/m68knommu/platform/528x/gpio.c
+++ b/arch/m68knommu/platform/528x/gpio.c
@@ -31,7 +31,7 @@ static struct mcf_gpio_chip mcf_gpio_chips[] = {
.get = mcf_gpio_get_value,
.set = mcf_gpio_set_value,
.base = 1,
- .ngpio = 8,
+ .ngpio = 7,
},
.pddr = MCFEPORT_EPDDR,
.podr = MCFEPORT_EPDR,
diff --git a/arch/m68knommu/platform/coldfire/clk.c b/arch/m68knommu/platform/coldfire/clk.c
index 7cdbf44..9f1260c 100644
--- a/arch/m68knommu/platform/coldfire/clk.c
+++ b/arch/m68knommu/platform/coldfire/clk.c
@@ -9,6 +9,7 @@
/***************************************************************************/
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/clk.h>
#include <asm/coldfire.h>
@@ -18,23 +19,27 @@ struct clk *clk_get(struct device *dev, const char *id)
{
return NULL;
}
+EXPORT_SYMBOL(clk_get);
int clk_enable(struct clk *clk)
{
return 0;
}
+EXPORT_SYMBOL(clk_enable);
void clk_disable(struct clk *clk)
{
}
+EXPORT_SYMBOL(clk_disable);
void clk_put(struct clk *clk)
{
}
+EXPORT_SYMBOL(clk_put);
unsigned long clk_get_rate(struct clk *clk)
{
return MCF_CLK;
}
-
+EXPORT_SYMBOL(clk_get_rate);
/***************************************************************************/
diff --git a/arch/m68knommu/platform/coldfire/head.S b/arch/m68knommu/platform/coldfire/head.S
index 2b0d73c..4b91aa2 100644
--- a/arch/m68knommu/platform/coldfire/head.S
+++ b/arch/m68knommu/platform/coldfire/head.S
@@ -106,6 +106,9 @@
.global _ramvec
.global _ramstart
.global _ramend
+#if defined(CONFIG_UBOOT)
+.global _init_sp
+#endif
/*****************************************************************************/
@@ -124,6 +127,10 @@ _ramstart:
.long 0
_ramend:
.long 0
+#if defined(CONFIG_UBOOT)
+_init_sp:
+.long 0
+#endif
/*****************************************************************************/
@@ -137,6 +144,9 @@ __HEAD
_start:
nop /* filler */
movew #0x2700, %sr /* no interrupts */
+#if defined(CONFIG_UBOOT)
+ movel %sp,_init_sp /* save initial stack pointer */
+#endif
/*
* Do any platform or board specific setup now. Most boards
diff --git a/arch/microblaze/lib/memcpy.c b/arch/microblaze/lib/memcpy.c
index 6a907c5..cc2108b 100644
--- a/arch/microblaze/lib/memcpy.c
+++ b/arch/microblaze/lib/memcpy.c
@@ -9,7 +9,7 @@
* It is based on demo code originally Copyright 2001 by Intel Corp, taken from
* http://www.embedded.com/showArticle.jhtml?articleID=19205567
*
- * Attempts were made, unsuccesfully, to contact the original
+ * Attempts were made, unsuccessfully, to contact the original
* author of this code (Michael Morrow, Intel). Below is the original
* copyright notice.
*
diff --git a/arch/microblaze/lib/memmove.c b/arch/microblaze/lib/memmove.c
index d4e9f49..0929198 100644
--- a/arch/microblaze/lib/memmove.c
+++ b/arch/microblaze/lib/memmove.c
@@ -9,7 +9,7 @@
* It is based on demo code originally Copyright 2001 by Intel Corp, taken from
* http://www.embedded.com/showArticle.jhtml?articleID=19205567
*
- * Attempts were made, unsuccesfully, to contact the original
+ * Attempts were made, unsuccessfully, to contact the original
* author of this code (Michael Morrow, Intel). Below is the original
* copyright notice.
*
diff --git a/arch/microblaze/lib/memset.c b/arch/microblaze/lib/memset.c
index 941dc8f..4df851d 100644
--- a/arch/microblaze/lib/memset.c
+++ b/arch/microblaze/lib/memset.c
@@ -9,7 +9,7 @@
* It is based on demo code originally Copyright 2001 by Intel Corp, taken from
* http://www.embedded.com/showArticle.jhtml?articleID=19205567
*
- * Attempts were made, unsuccesfully, to contact the original
+ * Attempts were made, unsuccessfully, to contact the original
* author of this code (Michael Morrow, Intel). Below is the original
* copyright notice.
*
diff --git a/arch/mips/include/asm/mach-pnx833x/gpio.h b/arch/mips/include/asm/mach-pnx833x/gpio.h
index 8de0eb9..ed3a88d 100644
--- a/arch/mips/include/asm/mach-pnx833x/gpio.h
+++ b/arch/mips/include/asm/mach-pnx833x/gpio.h
@@ -24,7 +24,7 @@
/* BIG FAT WARNING: races danger!
No protections exist here. Current users are only early init code,
- when locking is not needed because no cuncurency yet exists there,
+ when locking is not needed because no concurrency yet exists there,
and GPIO IRQ dispatcher, which does locking.
However, if many uses will ever happen, proper locking will be needed
- including locking between different uses
diff --git a/arch/mips/include/asm/sgi/ioc.h b/arch/mips/include/asm/sgi/ioc.h
index 343ed15..57a9719 100644
--- a/arch/mips/include/asm/sgi/ioc.h
+++ b/arch/mips/include/asm/sgi/ioc.h
@@ -164,7 +164,7 @@ struct sgioc_regs {
u32 _unused5;
u8 _write[3];
volatile u8 write;
-#define SGIOC_WRITE_NTHRESH 0x01 /* use 4.5db threshhold */
+#define SGIOC_WRITE_NTHRESH 0x01 /* use 4.5db threshold */
#define SGIOC_WRITE_TPSPEED 0x02 /* use 100ohm TP speed */
#define SGIOC_WRITE_EPSEL 0x04 /* force cable mode: 1=AUI 0=TP */
#define SGIOC_WRITE_EASEL 0x08 /* 1=autoselect 0=manual cable selection */
diff --git a/arch/mips/include/asm/sibyte/sb1250_mac.h b/arch/mips/include/asm/sibyte/sb1250_mac.h
index b6faf08..591b906 100644
--- a/arch/mips/include/asm/sibyte/sb1250_mac.h
+++ b/arch/mips/include/asm/sibyte/sb1250_mac.h
@@ -212,7 +212,7 @@
#define G_MAC_TXD_WEIGHT1(x) _SB_GETVALUE(x, S_MAC_TXD_WEIGHT1, M_MAC_TXD_WEIGHT1)
/*
- * MAC Fifo Threshhold registers (Table 9-14)
+ * MAC Fifo Threshold registers (Table 9-14)
* Register: MAC_THRSH_CFG_0
* Register: MAC_THRSH_CFG_1
* Register: MAC_THRSH_CFG_2
diff --git a/arch/mips/include/asm/sn/sn0/hubio.h b/arch/mips/include/asm/sn/sn0/hubio.h
index d0c29d4..31c76c0 100644
--- a/arch/mips/include/asm/sn/sn0/hubio.h
+++ b/arch/mips/include/asm/sn/sn0/hubio.h
@@ -825,7 +825,7 @@ typedef union iprb_u {
struct {
u64 rsvd1: 15,
error: 1, /* Widget rcvd wr resp pkt w/ error */
- ovflow: 5, /* Over flow count. perf measurement */
+ ovflow: 5, /* Overflow count. perf measurement */
fire_and_forget: 1, /* Launch Write without response */
mode: 2, /* Widget operation Mode */
rsvd2: 2,
diff --git a/arch/mips/include/asm/time.h b/arch/mips/include/asm/time.h
index df6a430..c7f1bfe 100644
--- a/arch/mips/include/asm/time.h
+++ b/arch/mips/include/asm/time.h
@@ -84,8 +84,16 @@ static inline int init_mips_clocksource(void)
#endif
}
-extern void clocksource_set_clock(struct clocksource *cs, unsigned int clock);
-extern void clockevent_set_clock(struct clock_event_device *cd,
- unsigned int clock);
+static inline void clocksource_set_clock(struct clocksource *cs,
+ unsigned int clock)
+{
+ clocksource_calc_mult_shift(cs, clock, 4);
+}
+
+static inline void clockevent_set_clock(struct clock_event_device *cd,
+ unsigned int clock)
+{
+ clockevents_calc_mult_shift(cd, clock, 4);
+}
#endif /* _ASM_TIME_H */
diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c
index 24630fd..a38e3ee 100644
--- a/arch/mips/kernel/smtc.c
+++ b/arch/mips/kernel/smtc.c
@@ -1331,7 +1331,7 @@ void smtc_get_new_mmu_context(struct mm_struct *mm, unsigned long cpu)
if (!((asid += ASID_INC) & ASID_MASK) ) {
if (cpu_has_vtag_icache)
flush_icache_all();
- /* Traverse all online CPUs (hack requires contigous range) */
+ /* Traverse all online CPUs (hack requires contiguous range) */
for_each_online_cpu(i) {
/*
* We don't need to worry about our own CPU, nor those of
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
index 1f467d5..fb74974 100644
--- a/arch/mips/kernel/time.c
+++ b/arch/mips/kernel/time.c
@@ -71,39 +71,6 @@ EXPORT_SYMBOL(perf_irq);
unsigned int mips_hpt_frequency;
-void __init clocksource_set_clock(struct clocksource *cs, unsigned int clock)
-{
- u64 temp;
- u32 shift;
-
- /* Find a shift value */
- for (shift = 32; shift > 0; shift--) {
- temp = (u64) NSEC_PER_SEC << shift;
- do_div(temp, clock);
- if ((temp >> 32) == 0)
- break;
- }
- cs->shift = shift;
- cs->mult = (u32) temp;
-}
-
-void __cpuinit clockevent_set_clock(struct clock_event_device *cd,
- unsigned int clock)
-{
- u64 temp;
- u32 shift;
-
- /* Find a shift value */
- for (shift = 32; shift > 0; shift--) {
- temp = (u64) clock << shift;
- do_div(temp, NSEC_PER_SEC);
- if ((temp >> 32) == 0)
- break;
- }
- cd->shift = shift;
- cd->mult = (u32) temp;
-}
-
/*
* This function exists in order to cause an error due to a duplicate
* definition if platform code should have its own implementation. The hook
diff --git a/arch/mips/math-emu/dp_sub.c b/arch/mips/math-emu/dp_sub.c
index b30c5b1..a2127d6 100644
--- a/arch/mips/math-emu/dp_sub.c
+++ b/arch/mips/math-emu/dp_sub.c
@@ -110,7 +110,7 @@ ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y)
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
DPDNORMX;
- /* FAAL THOROUGH */
+ /* FALL THROUGH */
case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
/* normalize ym,ye */
diff --git a/arch/mips/txx9/generic/smsc_fdc37m81x.c b/arch/mips/txx9/generic/smsc_fdc37m81x.c
index a2b2d62..8ebc384 100644
--- a/arch/mips/txx9/generic/smsc_fdc37m81x.c
+++ b/arch/mips/txx9/generic/smsc_fdc37m81x.c
@@ -117,7 +117,7 @@ unsigned long __init smsc_fdc37m81x_init(unsigned long port)
if (chip_id == SMSC_FDC37M81X_CHIP_ID)
smsc_fdc37m81x_config_end();
else {
- printk(KERN_WARNING "%s: unknow chip id 0x%02x\n", __func__,
+ printk(KERN_WARNING "%s: unknown chip id 0x%02x\n", __func__,
chip_id);
g_smsc_fdc37m81x_base = 0;
}
diff --git a/arch/mn10300/kernel/process.c b/arch/mn10300/kernel/process.c
index 892cce8..ec8a21d 100644
--- a/arch/mn10300/kernel/process.c
+++ b/arch/mn10300/kernel/process.c
@@ -275,16 +275,12 @@ asmlinkage long sys_execve(char __user *name,
char *filename;
int error;
- lock_kernel();
-
filename = getname(name);
error = PTR_ERR(filename);
- if (!IS_ERR(filename)) {
- error = do_execve(filename, argv, envp, __frame);
- putname(filename);
- }
-
- unlock_kernel();
+ if (IS_ERR(filename))
+ return error;
+ error = do_execve(filename, argv, envp, __frame);
+ putname(filename);
return error;
}
diff --git a/arch/parisc/kernel/perf.c b/arch/parisc/kernel/perf.c
index 75099ef..f9f6783 100644
--- a/arch/parisc/kernel/perf.c
+++ b/arch/parisc/kernel/perf.c
@@ -24,7 +24,7 @@
*
* This driver programs the PCX-U/PCX-W performance counters
* on the PA-RISC 2.0 chips. The driver keeps all images now
- * internally to the kernel to hopefully eliminate the possiblity
+ * internally to the kernel to hopefully eliminate the possibility
* of a bad image halting the CPU. Also, there are different
* images for the PCX-W and later chips vs the PCX-U chips.
*
diff --git a/arch/powerpc/include/asm/reg_fsl_emb.h b/arch/powerpc/include/asm/reg_fsl_emb.h
index 1e180a5..0de404d 100644
--- a/arch/powerpc/include/asm/reg_fsl_emb.h
+++ b/arch/powerpc/include/asm/reg_fsl_emb.h
@@ -39,7 +39,7 @@
#define PMRN_PMLCB2 0x112 /* PM Local Control B2 */
#define PMRN_PMLCB3 0x113 /* PM Local Control B3 */
-#define PMLCB_THRESHMUL_MASK 0x0700 /* Threshhold Multiple Field */
+#define PMLCB_THRESHMUL_MASK 0x0700 /* Threshold Multiple Field */
#define PMLCB_THRESHMUL_SHIFT 8
#define PMLCB_THRESHOLD_MASK 0x003f /* Threshold Field */
diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c
index 641c74b..b6bd1ea 100644
--- a/arch/powerpc/kernel/kgdb.c
+++ b/arch/powerpc/kernel/kgdb.c
@@ -52,7 +52,7 @@ static struct hard_trap_info
{ 0x2030, 0x08 /* SIGFPE */ }, /* spe fp data */
{ 0x2040, 0x08 /* SIGFPE */ }, /* spe fp data */
{ 0x2050, 0x08 /* SIGFPE */ }, /* spe fp round */
- { 0x2060, 0x0e /* SIGILL */ }, /* performace monitor */
+ { 0x2060, 0x0e /* SIGILL */ }, /* performance monitor */
{ 0x2900, 0x08 /* SIGFPE */ }, /* apu unavailable */
{ 0x3100, 0x0e /* SIGALRM */ }, /* fixed interval timer */
{ 0x3200, 0x02 /* SIGINT */ }, /* watchdog */
diff --git a/arch/powerpc/kernel/tau_6xx.c b/arch/powerpc/kernel/tau_6xx.c
index c3a56d6..a753b72 100644
--- a/arch/powerpc/kernel/tau_6xx.c
+++ b/arch/powerpc/kernel/tau_6xx.c
@@ -59,7 +59,7 @@ void set_thresholds(unsigned long cpu)
mtspr(SPRN_THRM1, THRM1_THRES(tau[cpu].low) | THRM1_V | THRM1_TIE | THRM1_TID);
/* setup THRM2,
- * threshold, valid bit, enable interrupts, interrupt when above threshhold
+ * threshold, valid bit, enable interrupts, interrupt when above threshold
*/
mtspr (SPRN_THRM2, THRM1_THRES(tau[cpu].high) | THRM1_V | THRM1_TIE);
#else
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index 36707de..674800b 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -834,7 +834,8 @@ static cycle_t timebase_read(struct clocksource *cs)
return (cycle_t)get_tb();
}
-void update_vsyscall(struct timespec *wall_time, struct clocksource *clock)
+void update_vsyscall(struct timespec *wall_time, struct clocksource *clock,
+ u32 mult)
{
u64 t2x, stamp_xsec;
@@ -847,7 +848,7 @@ void update_vsyscall(struct timespec *wall_time, struct clocksource *clock)
/* XXX this assumes clock->shift == 22 */
/* 4611686018 ~= 2^(20+64-22) / 1e9 */
- t2x = (u64) clock->mult * 4611686018ULL;
+ t2x = (u64) mult * 4611686018ULL;
stamp_xsec = (u64) xtime.tv_nsec * XSEC_PER_SEC;
do_div(stamp_xsec, 1000000000);
stamp_xsec += (u64) xtime.tv_sec * XSEC_PER_SEC;
@@ -924,7 +925,7 @@ static void register_decrementer_clockevent(int cpu)
*dec = decrementer_clockevent;
dec->cpumask = cpumask_of(cpu);
- printk(KERN_DEBUG "clockevent: %s mult[%lx] shift[%d] cpu[%d]\n",
+ printk(KERN_DEBUG "clockevent: %s mult[%x] shift[%d] cpu[%d]\n",
dec->name, dec->mult, dec->shift, cpu);
clockevents_register_device(dec);
diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c
index 137dc22..d84d192 100644
--- a/arch/powerpc/kernel/vdso.c
+++ b/arch/powerpc/kernel/vdso.c
@@ -721,7 +721,7 @@ static int __init vdso_init(void)
#ifdef CONFIG_PPC64
/*
- * Fill up the "systemcfg" stuff for backward compatiblity
+ * Fill up the "systemcfg" stuff for backward compatibility
*/
strcpy((char *)vdso_data->eye_catcher, "SYSTEMCFG:PPC64");
vdso_data->version.major = SYSTEMCFG_MAJOR;
diff --git a/arch/powerpc/oprofile/op_model_cell.c b/arch/powerpc/oprofile/op_model_cell.c
index ae06c62..2c9e522 100644
--- a/arch/powerpc/oprofile/op_model_cell.c
+++ b/arch/powerpc/oprofile/op_model_cell.c
@@ -248,7 +248,7 @@ static int pm_rtas_activate_signals(u32 node, u32 count)
* There is no debug setup required for the cycles event.
* Note that only events in the same group can be used.
* Otherwise, there will be conflicts in correctly routing
- * the signals on the debug bus. It is the responsiblity
+ * the signals on the debug bus. It is the responsibility
* of the OProfile user tool to check the events are in
* the same group.
*/
@@ -1594,7 +1594,7 @@ static void cell_handle_interrupt_spu(struct pt_regs *regs,
* to a latch. The new values (interrupt setting bits, reset
* counter value etc.) are not copied to the actual registers
* until the performance monitor is enabled. In order to get
- * this to work as desired, the permormance monitor needs to
+ * this to work as desired, the performance monitor needs to
* be disabled while writing to the latches. This is a
* HW design issue.
*/
@@ -1668,7 +1668,7 @@ static void cell_handle_interrupt_ppu(struct pt_regs *regs,
* to a latch. The new values (interrupt setting bits, reset
* counter value etc.) are not copied to the actual registers
* until the performance monitor is enabled. In order to get
- * this to work as desired, the permormance monitor needs to
+ * this to work as desired, the performance monitor needs to
* be disabled while writing to the latches. This is a
* HW design issue.
*/
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.c b/arch/powerpc/platforms/52xx/mpc52xx_pci.c
index dd43114..da110bd 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_pci.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_pci.c
@@ -100,7 +100,7 @@ const struct of_device_id mpc52xx_pci_ids[] __initdata = {
};
/* ======================================================================== */
-/* PCI configuration acess */
+/* PCI configuration access */
/* ======================================================================== */
static int
diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c
index e81403b..ab2027c 100644
--- a/arch/powerpc/platforms/powermac/pci.c
+++ b/arch/powerpc/platforms/powermac/pci.c
@@ -302,7 +302,7 @@ static void __init setup_chaos(struct pci_controller *hose,
* 1 -> Skip the device but act as if the access was successfull
* (return 0xff's on reads, eventually, cache config space
* accesses in a later version)
- * -1 -> Hide the device (unsuccessful acess)
+ * -1 -> Hide the device (unsuccessful access)
*/
static int u3_ht_skip_device(struct pci_controller *hose,
struct pci_bus *bus, unsigned int devfn)
diff --git a/arch/powerpc/sysdev/dart_iommu.c b/arch/powerpc/sysdev/dart_iommu.c
index ae3c4db..bafc3f8 100644
--- a/arch/powerpc/sysdev/dart_iommu.c
+++ b/arch/powerpc/sysdev/dart_iommu.c
@@ -160,7 +160,7 @@ static int dart_build(struct iommu_table *tbl, long index,
dp = ((unsigned int*)tbl->it_base) + index;
- /* On U3, all memory is contigous, so we can move this
+ /* On U3, all memory is contiguous, so we can move this
* out of the loop.
*/
l = npages;
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 16c6730..c802352 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -220,23 +220,8 @@ config AUDIT_ARCH
bool
default y
-config S390_SWITCH_AMODE
- bool "Switch kernel/user addressing modes"
- help
- This option allows to switch the addressing modes of kernel and user
- space. The kernel parameter switch_amode=on will enable this feature,
- default is disabled. Enabling this (via kernel parameter) on machines
- earlier than IBM System z9-109 EC/BC will reduce system performance.
-
- Note that this option will also be selected by selecting the execute
- protection option below. Enabling the execute protection via the
- noexec kernel parameter will also switch the addressing modes,
- independent of the switch_amode kernel parameter.
-
-
config S390_EXEC_PROTECT
bool "Data execute protection"
- select S390_SWITCH_AMODE
help
This option allows to enable a buffer overflow protection for user
space programs and it also selects the addressing mode option above.
diff --git a/arch/s390/crypto/prng.c b/arch/s390/crypto/prng.c
index b49c00c..a320990 100644
--- a/arch/s390/crypto/prng.c
+++ b/arch/s390/crypto/prng.c
@@ -6,7 +6,6 @@
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/smp_lock.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -49,7 +48,6 @@ static unsigned char parm_block[32] = {
static int prng_open(struct inode *inode, struct file *file)
{
- cycle_kernel_lock();
return nonseekable_open(inode, file);
}
diff --git a/arch/s390/defconfig b/arch/s390/defconfig
index ab44644..f4e53c6 100644
--- a/arch/s390/defconfig
+++ b/arch/s390/defconfig
@@ -185,7 +185,6 @@ CONFIG_HOTPLUG_CPU=y
CONFIG_COMPAT=y
CONFIG_SYSVIPC_COMPAT=y
CONFIG_AUDIT_ARCH=y
-CONFIG_S390_SWITCH_AMODE=y
CONFIG_S390_EXEC_PROTECT=y
#
diff --git a/arch/s390/include/asm/atomic.h b/arch/s390/include/asm/atomic.h
index ae7c8f9..2a113d6 100644
--- a/arch/s390/include/asm/atomic.h
+++ b/arch/s390/include/asm/atomic.h
@@ -21,7 +21,7 @@
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
#define __CS_LOOP(ptr, op_val, op_string) ({ \
- typeof(ptr->counter) old_val, new_val; \
+ int old_val, new_val; \
asm volatile( \
" l %0,%2\n" \
"0: lr %1,%0\n" \
@@ -38,7 +38,7 @@
#else /* __GNUC__ */
#define __CS_LOOP(ptr, op_val, op_string) ({ \
- typeof(ptr->counter) old_val, new_val; \
+ int old_val, new_val; \
asm volatile( \
" l %0,0(%3)\n" \
"0: lr %1,%0\n" \
@@ -143,7 +143,7 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u)
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
#define __CSG_LOOP(ptr, op_val, op_string) ({ \
- typeof(ptr->counter) old_val, new_val; \
+ long long old_val, new_val; \
asm volatile( \
" lg %0,%2\n" \
"0: lgr %1,%0\n" \
@@ -160,7 +160,7 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u)
#else /* __GNUC__ */
#define __CSG_LOOP(ptr, op_val, op_string) ({ \
- typeof(ptr->counter) old_val, new_val; \
+ long long old_val, new_val; \
asm volatile( \
" lg %0,0(%3)\n" \
"0: lgr %1,%0\n" \
diff --git a/arch/s390/include/asm/ccwdev.h b/arch/s390/include/asm/ccwdev.h
index 2a54195..f4bd346 100644
--- a/arch/s390/include/asm/ccwdev.h
+++ b/arch/s390/include/asm/ccwdev.h
@@ -142,6 +142,8 @@ struct ccw1;
extern int ccw_device_set_options_mask(struct ccw_device *, unsigned long);
extern int ccw_device_set_options(struct ccw_device *, unsigned long);
extern void ccw_device_clear_options(struct ccw_device *, unsigned long);
+int ccw_device_is_pathgroup(struct ccw_device *cdev);
+int ccw_device_is_multipath(struct ccw_device *cdev);
/* Allow for i/o completion notification after primary interrupt status. */
#define CCWDEV_EARLY_NOTIFICATION 0x0001
@@ -151,6 +153,8 @@ extern void ccw_device_clear_options(struct ccw_device *, unsigned long);
#define CCWDEV_DO_PATHGROUP 0x0004
/* Allow forced onlining of boxed devices. */
#define CCWDEV_ALLOW_FORCE 0x0008
+/* Try to use multipath mode. */
+#define CCWDEV_DO_MULTIPATH 0x0010
extern int ccw_device_start(struct ccw_device *, struct ccw1 *,
unsigned long, __u8, unsigned long);
diff --git a/arch/s390/include/asm/cputime.h b/arch/s390/include/asm/cputime.h
index f23961a..258ba88 100644
--- a/arch/s390/include/asm/cputime.h
+++ b/arch/s390/include/asm/cputime.h
@@ -183,6 +183,7 @@ struct s390_idle_data {
unsigned long long idle_count;
unsigned long long idle_enter;
unsigned long long idle_time;
+ int nohz_delay;
};
DECLARE_PER_CPU(struct s390_idle_data, s390_idle);
@@ -198,4 +199,11 @@ static inline void s390_idle_check(void)
vtime_start_cpu();
}
+static inline int s390_nohz_delay(int cpu)
+{
+ return per_cpu(s390_idle, cpu).nohz_delay != 0;
+}
+
+#define arch_needs_cpu(cpu) s390_nohz_delay(cpu)
+
#endif /* _S390_CPUTIME_H */
diff --git a/arch/s390/include/asm/mmu_context.h b/arch/s390/include/asm/mmu_context.h
index fc7edd6..976e273 100644
--- a/arch/s390/include/asm/mmu_context.h
+++ b/arch/s390/include/asm/mmu_context.h
@@ -36,7 +36,7 @@ static inline int init_new_context(struct task_struct *tsk,
mm->context.has_pgste = 1;
mm->context.alloc_pgste = 1;
} else {
- mm->context.noexec = s390_noexec;
+ mm->context.noexec = (user_mode == SECONDARY_SPACE_MODE);
mm->context.has_pgste = 0;
mm->context.alloc_pgste = 0;
}
@@ -58,7 +58,7 @@ static inline void update_mm(struct mm_struct *mm, struct task_struct *tsk)
pgd_t *pgd = mm->pgd;
S390_lowcore.user_asce = mm->context.asce_bits | __pa(pgd);
- if (switch_amode) {
+ if (user_mode != HOME_SPACE_MODE) {
/* Load primary space page table origin. */
pgd = mm->context.noexec ? get_shadow_table(pgd) : pgd;
S390_lowcore.user_exec_asce = mm->context.asce_bits | __pa(pgd);
diff --git a/arch/s390/include/asm/pgalloc.h b/arch/s390/include/asm/pgalloc.h
index ddad590..68940d0 100644
--- a/arch/s390/include/asm/pgalloc.h
+++ b/arch/s390/include/asm/pgalloc.h
@@ -143,7 +143,8 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
spin_lock_init(&mm->context.list_lock);
INIT_LIST_HEAD(&mm->context.crst_list);
INIT_LIST_HEAD(&mm->context.pgtable_list);
- return (pgd_t *) crst_table_alloc(mm, s390_noexec);
+ return (pgd_t *)
+ crst_table_alloc(mm, user_mode == SECONDARY_SPACE_MODE);
}
#define pgd_free(mm, pgd) crst_table_free(mm, (unsigned long *) pgd)
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index 60a7b1a..e2fa79c 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -169,12 +169,13 @@ extern unsigned long VMALLOC_START;
* STL Segment-Table-Length: Segment-table length (STL+1*16 entries -> up to 2048)
*
* A 64 bit pagetable entry of S390 has following format:
- * | PFRA |0IP0| OS |
+ * | PFRA |0IPC| OS |
* 0000000000111111111122222222223333333333444444444455555555556666
* 0123456789012345678901234567890123456789012345678901234567890123
*
* I Page-Invalid Bit: Page is not available for address-translation
* P Page-Protection Bit: Store access not possible for page
+ * C Change-bit override: HW is not required to set change bit
*
* A 64 bit segmenttable entry of S390 has following format:
* | P-table origin | TT
@@ -218,6 +219,7 @@ extern unsigned long VMALLOC_START;
*/
/* Hardware bits in the page table entry */
+#define _PAGE_CO 0x100 /* HW Change-bit override */
#define _PAGE_RO 0x200 /* HW read-only bit */
#define _PAGE_INVALID 0x400 /* HW invalid bit */
diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h
index e37478e..52a779c 100644
--- a/arch/s390/include/asm/setup.h
+++ b/arch/s390/include/asm/setup.h
@@ -49,17 +49,12 @@ extern unsigned long memory_end;
void detect_memory_layout(struct mem_chunk chunk[]);
-#ifdef CONFIG_S390_SWITCH_AMODE
-extern unsigned int switch_amode;
-#else
-#define switch_amode (0)
-#endif
-
-#ifdef CONFIG_S390_EXEC_PROTECT
-extern unsigned int s390_noexec;
-#else
-#define s390_noexec (0)
-#endif
+#define PRIMARY_SPACE_MODE 0
+#define ACCESS_REGISTER_MODE 1
+#define SECONDARY_SPACE_MODE 2
+#define HOME_SPACE_MODE 3
+
+extern unsigned int user_mode;
/*
* Machine features detected in head.S
diff --git a/arch/s390/include/asm/smp.h b/arch/s390/include/asm/smp.h
index a868b27..2ab1141 100644
--- a/arch/s390/include/asm/smp.h
+++ b/arch/s390/include/asm/smp.h
@@ -1,57 +1,22 @@
/*
- * include/asm-s390/smp.h
- *
- * S390 version
- * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
- * Martin Schwidefsky (schwidefsky@de.ibm.com)
- * Heiko Carstens (heiko.carstens@de.ibm.com)
+ * Copyright IBM Corp. 1999,2009
+ * Author(s): Denis Joseph Barrow,
+ * Martin Schwidefsky <schwidefsky@de.ibm.com>,
+ * Heiko Carstens <heiko.carstens@de.ibm.com>,
*/
#ifndef __ASM_SMP_H
#define __ASM_SMP_H
-#include <linux/threads.h>
-#include <linux/cpumask.h>
-#include <linux/bitops.h>
+#ifdef CONFIG_SMP
-#if defined(__KERNEL__) && defined(CONFIG_SMP) && !defined(__ASSEMBLY__)
-
-#include <asm/lowcore.h>
-#include <asm/sigp.h>
-#include <asm/ptrace.h>
#include <asm/system.h>
-
-/*
- s390 specific smp.c headers
- */
-typedef struct
-{
- int intresting;
- sigp_ccode ccode;
- __u32 status;
- __u16 cpu;
-} sigp_info;
+#include <asm/sigp.h>
extern void machine_restart_smp(char *);
extern void machine_halt_smp(void);
extern void machine_power_off_smp(void);
-#define NO_PROC_ID 0xFF /* No processor magic marker */
-
-/*
- * This magic constant controls our willingness to transfer
- * a process across CPUs. Such a transfer incurs misses on the L1
- * cache, and on a P6 or P5 with multiple L2 caches L2 hits. My
- * gut feeling is this will vary by board in value. For a board
- * with separate L2 cache it probably depends also on the RSS, and
- * for a board with shared L2 cache it ought to decay fast as other
- * processes are run.
- */
-
-#define PROC_CHANGE_PENALTY 20 /* Schedule penalty */
-
#define raw_smp_processor_id() (S390_lowcore.cpu_nr)
-#define cpu_logical_map(cpu) (cpu)
extern int __cpu_disable (void);
extern void __cpu_die (unsigned int cpu);
@@ -64,7 +29,9 @@ extern int smp_cpu_polarization[];
extern void arch_send_call_function_single_ipi(int cpu);
extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
-#endif
+extern union save_area *zfcpdump_save_areas[NR_CPUS + 1];
+
+#endif /* CONFIG_SMP */
#ifdef CONFIG_HOTPLUG_CPU
extern int smp_rescan_cpus(void);
@@ -72,5 +39,4 @@ extern int smp_rescan_cpus(void);
static inline int smp_rescan_cpus(void) { return 0; }
#endif
-extern union save_area *zfcpdump_save_areas[NR_CPUS + 1];
-#endif
+#endif /* __ASM_SMP_H */
diff --git a/arch/s390/include/asm/sockios.h b/arch/s390/include/asm/sockios.h
index f4fc16c..6f60eee 100644
--- a/arch/s390/include/asm/sockios.h
+++ b/arch/s390/include/asm/sockios.h
@@ -1,21 +1,6 @@
-/*
- * include/asm-s390/sockios.h
- *
- * S390 version
- *
- * Derived from "include/asm-i386/sockios.h"
- */
+#ifndef _ASM_S390_SOCKIOS_H
+#define _ASM_S390_SOCKIOS_H
-#ifndef __ARCH_S390_SOCKIOS__
-#define __ARCH_S390_SOCKIOS__
-
-/* Socket-level I/O control calls. */
-#define FIOSETOWN 0x8901
-#define SIOCSPGRP 0x8902
-#define FIOGETOWN 0x8903
-#define SIOCGPGRP 0x8904
-#define SIOCATMARK 0x8905
-#define SIOCGSTAMP 0x8906 /* Get stamp (timeval) */
-#define SIOCGSTAMPNS 0x8907 /* Get stamp (timespec) */
+#include <asm-generic/sockios.h>
#endif
diff --git a/arch/s390/include/asm/termbits.h b/arch/s390/include/asm/termbits.h
index 5873185..71bf6ac 100644
--- a/arch/s390/include/asm/termbits.h
+++ b/arch/s390/include/asm/termbits.h
@@ -1,206 +1,6 @@
-/*
- * include/asm-s390/termbits.h
- *
- * S390 version
- *
- * Derived from "include/asm-i386/termbits.h"
- */
+#ifndef _ASM_S390_TERMBITS_H
+#define _ASM_S390_TERMBITS_H
-#ifndef __ARCH_S390_TERMBITS_H__
-#define __ARCH_S390_TERMBITS_H__
-
-#include <linux/posix_types.h>
-
-typedef unsigned char cc_t;
-typedef unsigned int speed_t;
-typedef unsigned int tcflag_t;
-
-#define NCCS 19
-struct termios {
- tcflag_t c_iflag; /* input mode flags */
- tcflag_t c_oflag; /* output mode flags */
- tcflag_t c_cflag; /* control mode flags */
- tcflag_t c_lflag; /* local mode flags */
- cc_t c_line; /* line discipline */
- cc_t c_cc[NCCS]; /* control characters */
-};
-
-struct termios2 {
- tcflag_t c_iflag; /* input mode flags */
- tcflag_t c_oflag; /* output mode flags */
- tcflag_t c_cflag; /* control mode flags */
- tcflag_t c_lflag; /* local mode flags */
- cc_t c_line; /* line discipline */
- cc_t c_cc[NCCS]; /* control characters */
- speed_t c_ispeed; /* input speed */
- speed_t c_ospeed; /* output speed */
-};
-
-struct ktermios {
- tcflag_t c_iflag; /* input mode flags */
- tcflag_t c_oflag; /* output mode flags */
- tcflag_t c_cflag; /* control mode flags */
- tcflag_t c_lflag; /* local mode flags */
- cc_t c_line; /* line discipline */
- cc_t c_cc[NCCS]; /* control characters */
- speed_t c_ispeed; /* input speed */
- speed_t c_ospeed; /* output speed */
-};
-
-/* c_cc characters */
-#define VINTR 0
-#define VQUIT 1
-#define VERASE 2
-#define VKILL 3
-#define VEOF 4
-#define VTIME 5
-#define VMIN 6
-#define VSWTC 7
-#define VSTART 8
-#define VSTOP 9
-#define VSUSP 10
-#define VEOL 11
-#define VREPRINT 12
-#define VDISCARD 13
-#define VWERASE 14
-#define VLNEXT 15
-#define VEOL2 16
-
-/* c_iflag bits */
-#define IGNBRK 0000001
-#define BRKINT 0000002
-#define IGNPAR 0000004
-#define PARMRK 0000010
-#define INPCK 0000020
-#define ISTRIP 0000040
-#define INLCR 0000100
-#define IGNCR 0000200
-#define ICRNL 0000400
-#define IUCLC 0001000
-#define IXON 0002000
-#define IXANY 0004000
-#define IXOFF 0010000
-#define IMAXBEL 0020000
-#define IUTF8 0040000
-
-/* c_oflag bits */
-#define OPOST 0000001
-#define OLCUC 0000002
-#define ONLCR 0000004
-#define OCRNL 0000010
-#define ONOCR 0000020
-#define ONLRET 0000040
-#define OFILL 0000100
-#define OFDEL 0000200
-#define NLDLY 0000400
-#define NL0 0000000
-#define NL1 0000400
-#define CRDLY 0003000
-#define CR0 0000000
-#define CR1 0001000
-#define CR2 0002000
-#define CR3 0003000
-#define TABDLY 0014000
-#define TAB0 0000000
-#define TAB1 0004000
-#define TAB2 0010000
-#define TAB3 0014000
-#define XTABS 0014000
-#define BSDLY 0020000
-#define BS0 0000000
-#define BS1 0020000
-#define VTDLY 0040000
-#define VT0 0000000
-#define VT1 0040000
-#define FFDLY 0100000
-#define FF0 0000000
-#define FF1 0100000
-
-/* c_cflag bit meaning */
-#define CBAUD 0010017
-#define B0 0000000 /* hang up */
-#define B50 0000001
-#define B75 0000002
-#define B110 0000003
-#define B134 0000004
-#define B150 0000005
-#define B200 0000006
-#define B300 0000007
-#define B600 0000010
-#define B1200 0000011
-#define B1800 0000012
-#define B2400 0000013
-#define B4800 0000014
-#define B9600 0000015
-#define B19200 0000016
-#define B38400 0000017
-#define EXTA B19200
-#define EXTB B38400
-#define CSIZE 0000060
-#define CS5 0000000
-#define CS6 0000020
-#define CS7 0000040
-#define CS8 0000060
-#define CSTOPB 0000100
-#define CREAD 0000200
-#define PARENB 0000400
-#define PARODD 0001000
-#define HUPCL 0002000
-#define CLOCAL 0004000
-#define CBAUDEX 0010000
-#define BOTHER 0010000
-#define B57600 0010001
-#define B115200 0010002
-#define B230400 0010003
-#define B460800 0010004
-#define B500000 0010005
-#define B576000 0010006
-#define B921600 0010007
-#define B1000000 0010010
-#define B1152000 0010011
-#define B1500000 0010012
-#define B2000000 0010013
-#define B2500000 0010014
-#define B3000000 0010015
-#define B3500000 0010016
-#define B4000000 0010017
-#define CIBAUD 002003600000 /* input baud rate */
-#define CMSPAR 010000000000 /* mark or space (stick) parity */
-#define CRTSCTS 020000000000 /* flow control */
-
-#define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */
-
-/* c_lflag bits */
-#define ISIG 0000001
-#define ICANON 0000002
-#define XCASE 0000004
-#define ECHO 0000010
-#define ECHOE 0000020
-#define ECHOK 0000040
-#define ECHONL 0000100
-#define NOFLSH 0000200
-#define TOSTOP 0000400
-#define ECHOCTL 0001000
-#define ECHOPRT 0002000
-#define ECHOKE 0004000
-#define FLUSHO 0010000
-#define PENDIN 0040000
-#define IEXTEN 0100000
-
-/* tcflow() and TCXONC use these */
-#define TCOOFF 0
-#define TCOON 1
-#define TCIOFF 2
-#define TCION 3
-
-/* tcflush() and TCFLSH use these */
-#define TCIFLUSH 0
-#define TCOFLUSH 1
-#define TCIOFLUSH 2
-
-/* tcsetattr uses these */
-#define TCSANOW 0
-#define TCSADRAIN 1
-#define TCSAFLUSH 2
+#include <asm-generic/termbits.h>
#endif
diff --git a/arch/s390/include/asm/todclk.h b/arch/s390/include/asm/todclk.h
deleted file mode 100644
index c7f6205..0000000
--- a/arch/s390/include/asm/todclk.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * File...........: linux/include/asm/todclk.h
- * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- * Bugreports.to..: <Linux390@de.ibm.com>
- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
- *
- * History of changes (starts July 2000)
- */
-
-#ifndef __ASM_TODCLK_H
-#define __ASM_TODCLK_H
-
-#ifdef __KERNEL__
-
-#define TOD_uSEC (0x1000ULL)
-#define TOD_mSEC (1000 * TOD_uSEC)
-#define TOD_SEC (1000 * TOD_mSEC)
-#define TOD_MIN (60 * TOD_SEC)
-#define TOD_HOUR (60 * TOD_MIN)
-
-#endif
-
-#endif
diff --git a/arch/s390/include/asm/uaccess.h b/arch/s390/include/asm/uaccess.h
index 8377e91..cbf0a87 100644
--- a/arch/s390/include/asm/uaccess.h
+++ b/arch/s390/include/asm/uaccess.h
@@ -93,6 +93,8 @@ extern struct uaccess_ops uaccess_mvcos;
extern struct uaccess_ops uaccess_mvcos_switch;
extern struct uaccess_ops uaccess_pt;
+extern int __handle_fault(unsigned long, unsigned long, int);
+
static inline int __put_user_fn(size_t size, void __user *ptr, void *x)
{
size = uaccess.copy_to_user_small(size, ptr, x);
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
index c7be8e1..683f638 100644
--- a/arch/s390/kernel/Makefile
+++ b/arch/s390/kernel/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_KPROBES) += kprobes.o
obj-$(CONFIG_FUNCTION_TRACER) += $(if $(CONFIG_64BIT),mcount64.o,mcount.o)
obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
+obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o
# Kexec part
S390_KEXEC_OBJS := machine_kexec.o crash.o
diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c
index fda1a81..25c31d6 100644
--- a/arch/s390/kernel/compat_linux.c
+++ b/arch/s390/kernel/compat_linux.c
@@ -31,14 +31,8 @@
#include <linux/shm.h>
#include <linux/slab.h>
#include <linux/uio.h>
-#include <linux/nfs_fs.h>
#include <linux/quota.h>
#include <linux/module.h>
-#include <linux/sunrpc/svc.h>
-#include <linux/nfsd/nfsd.h>
-#include <linux/nfsd/cache.h>
-#include <linux/nfsd/xdr.h>
-#include <linux/nfsd/syscall.h>
#include <linux/poll.h>
#include <linux/personality.h>
#include <linux/stat.h>
diff --git a/arch/s390/kernel/compat_linux.h b/arch/s390/kernel/compat_linux.h
index 45e9092..cb97afc 100644
--- a/arch/s390/kernel/compat_linux.h
+++ b/arch/s390/kernel/compat_linux.h
@@ -4,10 +4,6 @@
#include <linux/compat.h>
#include <linux/socket.h>
#include <linux/syscalls.h>
-#include <linux/nfs_fs.h>
-#include <linux/sunrpc/svc.h>
-#include <linux/nfsd/nfsd.h>
-#include <linux/nfsd/export.h>
/* Macro that masks the high order bit of an 32 bit pointer and converts it*/
/* to a 64 bit pointer */
diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S
index 6a25080..d984a2a 100644
--- a/arch/s390/kernel/head64.S
+++ b/arch/s390/kernel/head64.S
@@ -83,6 +83,8 @@ startup_continue:
slr %r0,%r0 # set cpuid to zero
sigp %r1,%r0,0x12 # switch to esame mode
sam64 # switch to 64 bit mode
+ llgfr %r13,%r13 # clear high-order half of base reg
+ lmh %r0,%r15,.Lzero64-.LPG1(%r13) # clear high-order half
lctlg %c0,%c15,.Lctl-.LPG1(%r13) # load control registers
lg %r12,.Lparmaddr-.LPG1(%r13) # pointer to parameter area
# move IPL device to lowcore
@@ -127,6 +129,7 @@ startup_continue:
.L4malign:.quad 0xffffffffffc00000
.Lscan2g:.quad 0x80000000 + 0x20000 - 8 # 2GB + 128K - 8
.Lnop: .long 0x07000700
+.Lzero64:.fill 16,4,0x0
#ifdef CONFIG_ZFCPDUMP
.Lcurrent_cpu:
.long 0x0
diff --git a/arch/s390/kernel/s390_ext.c b/arch/s390/kernel/s390_ext.c
index 0de305b..59618bc 100644
--- a/arch/s390/kernel/s390_ext.c
+++ b/arch/s390/kernel/s390_ext.c
@@ -126,6 +126,8 @@ void __irq_entry do_extint(struct pt_regs *regs, unsigned short code)
/* Serve timer interrupts first. */
clock_comparator_work();
kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++;
+ if (code != 0x1004)
+ __get_cpu_var(s390_idle).nohz_delay = 1;
index = ext_hash(code);
for (p = ext_int_hash[index]; p; p = p->next) {
if (likely(p->code == code))
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 061479f..0663287 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -305,9 +305,8 @@ static int __init early_parse_mem(char *p)
}
early_param("mem", early_parse_mem);
-#ifdef CONFIG_S390_SWITCH_AMODE
-unsigned int switch_amode = 0;
-EXPORT_SYMBOL_GPL(switch_amode);
+unsigned int user_mode = HOME_SPACE_MODE;
+EXPORT_SYMBOL_GPL(user_mode);
static int set_amode_and_uaccess(unsigned long user_amode,
unsigned long user32_amode)
@@ -340,23 +339,29 @@ static int set_amode_and_uaccess(unsigned long user_amode,
*/
static int __init early_parse_switch_amode(char *p)
{
- switch_amode = 1;
+ if (user_mode != SECONDARY_SPACE_MODE)
+ user_mode = PRIMARY_SPACE_MODE;
return 0;
}
early_param("switch_amode", early_parse_switch_amode);
-#else /* CONFIG_S390_SWITCH_AMODE */
-static inline int set_amode_and_uaccess(unsigned long user_amode,
- unsigned long user32_amode)
+static int __init early_parse_user_mode(char *p)
{
+ if (p && strcmp(p, "primary") == 0)
+ user_mode = PRIMARY_SPACE_MODE;
+#ifdef CONFIG_S390_EXEC_PROTECT
+ else if (p && strcmp(p, "secondary") == 0)
+ user_mode = SECONDARY_SPACE_MODE;
+#endif
+ else if (!p || strcmp(p, "home") == 0)
+ user_mode = HOME_SPACE_MODE;
+ else
+ return 1;
return 0;
}
-#endif /* CONFIG_S390_SWITCH_AMODE */
+early_param("user_mode", early_parse_user_mode);
#ifdef CONFIG_S390_EXEC_PROTECT
-unsigned int s390_noexec = 0;
-EXPORT_SYMBOL_GPL(s390_noexec);
-
/*
* Enable execute protection?
*/
@@ -364,8 +369,7 @@ static int __init early_parse_noexec(char *p)
{
if (!strncmp(p, "off", 3))
return 0;
- switch_amode = 1;
- s390_noexec = 1;
+ user_mode = SECONDARY_SPACE_MODE;
return 0;
}
early_param("noexec", early_parse_noexec);
@@ -373,7 +377,7 @@ early_param("noexec", early_parse_noexec);
static void setup_addressing_mode(void)
{
- if (s390_noexec) {
+ if (user_mode == SECONDARY_SPACE_MODE) {
if (set_amode_and_uaccess(PSW_ASC_SECONDARY,
PSW32_ASC_SECONDARY))
pr_info("Execute protection active, "
@@ -381,7 +385,7 @@ static void setup_addressing_mode(void)
else
pr_info("Execute protection active, "
"mvcos not available\n");
- } else if (switch_amode) {
+ } else if (user_mode == PRIMARY_SPACE_MODE) {
if (set_amode_and_uaccess(PSW_ASC_PRIMARY, PSW32_ASC_PRIMARY))
pr_info("Address spaces switched, "
"mvcos available\n");
@@ -411,7 +415,7 @@ setup_lowcore(void)
lc->restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY;
lc->restart_psw.addr =
PSW_ADDR_AMODE | (unsigned long) restart_int_handler;
- if (switch_amode)
+ if (user_mode != HOME_SPACE_MODE)
lc->restart_psw.mask |= PSW_ASC_HOME;
lc->external_new_psw.mask = psw_kernel_bits;
lc->external_new_psw.addr =
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
index 34162a0..65065ac 100644
--- a/arch/s390/kernel/time.c
+++ b/arch/s390/kernel/time.c
@@ -214,7 +214,8 @@ struct clocksource * __init clocksource_default_clock(void)
return &clocksource_tod;
}
-void update_vsyscall(struct timespec *wall_time, struct clocksource *clock)
+void update_vsyscall(struct timespec *wall_time, struct clocksource *clock,
+ u32 mult)
{
if (clock != &clocksource_tod)
return;
@@ -334,7 +335,7 @@ int get_sync_clock(unsigned long long *clock)
sw0 = atomic_read(sw_ptr);
*clock = get_clock();
sw1 = atomic_read(sw_ptr);
- put_cpu_var(clock_sync_sync);
+ put_cpu_var(clock_sync_word);
if (sw0 == sw1 && (sw0 & 0x80000000U))
/* Success: time is in sync. */
return 0;
@@ -384,7 +385,7 @@ static inline int check_sync_clock(void)
sw_ptr = &get_cpu_var(clock_sync_word);
rc = (atomic_read(sw_ptr) & 0x80000000U) != 0;
- put_cpu_var(clock_sync_sync);
+ put_cpu_var(clock_sync_word);
return rc;
}
diff --git a/arch/s390/kernel/vdso.c b/arch/s390/kernel/vdso.c
index adfb32a..5f99e66 100644
--- a/arch/s390/kernel/vdso.c
+++ b/arch/s390/kernel/vdso.c
@@ -86,7 +86,8 @@ static void vdso_init_data(struct vdso_data *vd)
unsigned int facility_list;
facility_list = stfl();
- vd->ectg_available = switch_amode && (facility_list & 1);
+ vd->ectg_available =
+ user_mode != HOME_SPACE_MODE && (facility_list & 1);
}
#ifdef CONFIG_64BIT
@@ -114,7 +115,7 @@ int vdso_alloc_per_cpu(int cpu, struct _lowcore *lowcore)
lowcore->vdso_per_cpu_data = __LC_PASTE;
- if (!switch_amode || !vdso_enabled)
+ if (user_mode == HOME_SPACE_MODE || !vdso_enabled)
return 0;
segment_table = __get_free_pages(GFP_KERNEL, SEGMENT_ORDER);
@@ -160,7 +161,7 @@ void vdso_free_per_cpu(int cpu, struct _lowcore *lowcore)
unsigned long segment_table, page_table, page_frame;
u32 *psal, *aste;
- if (!switch_amode || !vdso_enabled)
+ if (user_mode == HOME_SPACE_MODE || !vdso_enabled)
return;
psal = (u32 *)(addr_t) lowcore->paste[4];
@@ -184,7 +185,7 @@ static void __vdso_init_cr5(void *dummy)
static void vdso_init_cr5(void)
{
- if (switch_amode && vdso_enabled)
+ if (user_mode != HOME_SPACE_MODE && vdso_enabled)
on_each_cpu(__vdso_init_cr5, NULL, 1);
}
#endif /* CONFIG_64BIT */
diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c
index c41bb0d..b59a812 100644
--- a/arch/s390/kernel/vtime.c
+++ b/arch/s390/kernel/vtime.c
@@ -167,6 +167,8 @@ void vtime_stop_cpu(void)
/* Wait for external, I/O or machine check interrupt. */
psw.mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_IO | PSW_MASK_EXT;
+ idle->nohz_delay = 0;
+
/* Check if the CPU timer needs to be reprogrammed. */
if (vq->do_spt) {
__u64 vmax = VTIMER_MAX_SLICE;
diff --git a/arch/s390/kvm/Kconfig b/arch/s390/kvm/Kconfig
index bf164fc..6ee55ae 100644
--- a/arch/s390/kvm/Kconfig
+++ b/arch/s390/kvm/Kconfig
@@ -20,7 +20,6 @@ config KVM
depends on HAVE_KVM && EXPERIMENTAL
select PREEMPT_NOTIFIERS
select ANON_INODES
- select S390_SWITCH_AMODE
---help---
Support hosting paravirtualized guest machines using the SIE
virtualization capability on the mainframe. This should work
diff --git a/arch/s390/lib/uaccess_mvcos.c b/arch/s390/lib/uaccess_mvcos.c
index 58da3f4..60455f1 100644
--- a/arch/s390/lib/uaccess_mvcos.c
+++ b/arch/s390/lib/uaccess_mvcos.c
@@ -162,7 +162,6 @@ static size_t clear_user_mvcos(size_t size, void __user *to)
return size;
}
-#ifdef CONFIG_S390_SWITCH_AMODE
static size_t strnlen_user_mvcos(size_t count, const char __user *src)
{
char buf[256];
@@ -200,7 +199,6 @@ static size_t strncpy_from_user_mvcos(size_t count, const char __user *src,
} while ((len_str == len) && (done < count));
return done;
}
-#endif /* CONFIG_S390_SWITCH_AMODE */
struct uaccess_ops uaccess_mvcos = {
.copy_from_user = copy_from_user_mvcos_check,
@@ -215,7 +213,6 @@ struct uaccess_ops uaccess_mvcos = {
.futex_atomic_cmpxchg = futex_atomic_cmpxchg_std,
};
-#ifdef CONFIG_S390_SWITCH_AMODE
struct uaccess_ops uaccess_mvcos_switch = {
.copy_from_user = copy_from_user_mvcos,
.copy_from_user_small = copy_from_user_mvcos,
@@ -228,4 +225,3 @@ struct uaccess_ops uaccess_mvcos_switch = {
.futex_atomic_op = futex_atomic_op_pt,
.futex_atomic_cmpxchg = futex_atomic_cmpxchg_pt,
};
-#endif
diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c
index cb5d59e..404f2de 100644
--- a/arch/s390/lib/uaccess_pt.c
+++ b/arch/s390/lib/uaccess_pt.c
@@ -23,86 +23,21 @@ static inline pte_t *follow_table(struct mm_struct *mm, unsigned long addr)
pgd = pgd_offset(mm, addr);
if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
- return NULL;
+ return (pte_t *) 0x3a;
pud = pud_offset(pgd, addr);
if (pud_none(*pud) || unlikely(pud_bad(*pud)))
- return NULL;
+ return (pte_t *) 0x3b;
pmd = pmd_offset(pud, addr);
if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
- return NULL;
+ return (pte_t *) 0x10;
return pte_offset_map(pmd, addr);
}
-static int __handle_fault(struct mm_struct *mm, unsigned long address,
- int write_access)
-{
- struct vm_area_struct *vma;
- int ret = -EFAULT;
- int fault;
-
- if (in_atomic())
- return ret;
- down_read(&mm->mmap_sem);
- vma = find_vma(mm, address);
- if (unlikely(!vma))
- goto out;
- if (unlikely(vma->vm_start > address)) {
- if (!(vma->vm_flags & VM_GROWSDOWN))
- goto out;
- if (expand_stack(vma, address))
- goto out;
- }
-
- if (!write_access) {
- /* page not present, check vm flags */
- if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
- goto out;
- } else {
- if (!(vma->vm_flags & VM_WRITE))
- goto out;
- }
-
-survive:
- fault = handle_mm_fault(mm, vma, address, write_access ? FAULT_FLAG_WRITE : 0);
- if (unlikely(fault & VM_FAULT_ERROR)) {
- if (fault & VM_FAULT_OOM)
- goto out_of_memory;
- else if (fault & VM_FAULT_SIGBUS)
- goto out_sigbus;
- BUG();
- }
- if (fault & VM_FAULT_MAJOR)
- current->maj_flt++;
- else
- current->min_flt++;
- ret = 0;
-out:
- up_read(&mm->mmap_sem);
- return ret;
-
-out_of_memory:
- up_read(&mm->mmap_sem);
- if (is_global_init(current)) {
- yield();
- down_read(&mm->mmap_sem);
- goto survive;
- }
- printk("VM: killing process %s\n", current->comm);
- return ret;
-
-out_sigbus:
- up_read(&mm->mmap_sem);
- current->thread.prot_addr = address;
- current->thread.trap_no = 0x11;
- force_sig(SIGBUS, current);
- return ret;
-}
-
-static size_t __user_copy_pt(unsigned long uaddr, void *kptr,
- size_t n, int write_user)
+static __always_inline size_t __user_copy_pt(unsigned long uaddr, void *kptr,
+ size_t n, int write_user)
{
struct mm_struct *mm = current->mm;
unsigned long offset, pfn, done, size;
@@ -114,12 +49,17 @@ retry:
spin_lock(&mm->page_table_lock);
do {
pte = follow_table(mm, uaddr);
- if (!pte || !pte_present(*pte) ||
- (write_user && !pte_write(*pte)))
+ if ((unsigned long) pte < 0x1000)
goto fault;
+ if (!pte_present(*pte)) {
+ pte = (pte_t *) 0x11;
+ goto fault;
+ } else if (write_user && !pte_write(*pte)) {
+ pte = (pte_t *) 0x04;
+ goto fault;
+ }
pfn = pte_pfn(*pte);
-
offset = uaddr & (PAGE_SIZE - 1);
size = min(n - done, PAGE_SIZE - offset);
if (write_user) {
@@ -137,7 +77,7 @@ retry:
return n - done;
fault:
spin_unlock(&mm->page_table_lock);
- if (__handle_fault(mm, uaddr, write_user))
+ if (__handle_fault(uaddr, (unsigned long) pte, write_user))
return n - done;
goto retry;
}
@@ -146,30 +86,31 @@ fault:
* Do DAT for user address by page table walk, return kernel address.
* This function needs to be called with current->mm->page_table_lock held.
*/
-static unsigned long __dat_user_addr(unsigned long uaddr)
+static __always_inline unsigned long __dat_user_addr(unsigned long uaddr)
{
struct mm_struct *mm = current->mm;
- unsigned long pfn, ret;
+ unsigned long pfn;
pte_t *pte;
int rc;
- ret = 0;
retry:
pte = follow_table(mm, uaddr);
- if (!pte || !pte_present(*pte))
+ if ((unsigned long) pte < 0x1000)
goto fault;
+ if (!pte_present(*pte)) {
+ pte = (pte_t *) 0x11;
+ goto fault;
+ }
pfn = pte_pfn(*pte);
- ret = (pfn << PAGE_SHIFT) + (uaddr & (PAGE_SIZE - 1));
-out:
- return ret;
+ return (pfn << PAGE_SHIFT) + (uaddr & (PAGE_SIZE - 1));
fault:
spin_unlock(&mm->page_table_lock);
- rc = __handle_fault(mm, uaddr, 0);
+ rc = __handle_fault(uaddr, (unsigned long) pte, 0);
spin_lock(&mm->page_table_lock);
- if (rc)
- goto out;
- goto retry;
+ if (!rc)
+ goto retry;
+ return 0;
}
size_t copy_from_user_pt(size_t n, const void __user *from, void *to)
@@ -234,8 +175,12 @@ retry:
spin_lock(&mm->page_table_lock);
do {
pte = follow_table(mm, uaddr);
- if (!pte || !pte_present(*pte))
+ if ((unsigned long) pte < 0x1000)
+ goto fault;
+ if (!pte_present(*pte)) {
+ pte = (pte_t *) 0x11;
goto fault;
+ }
pfn = pte_pfn(*pte);
offset = uaddr & (PAGE_SIZE-1);
@@ -249,9 +194,8 @@ retry:
return done + 1;
fault:
spin_unlock(&mm->page_table_lock);
- if (__handle_fault(mm, uaddr, 0)) {
+ if (__handle_fault(uaddr, (unsigned long) pte, 0))
return 0;
- }
goto retry;
}
@@ -284,7 +228,7 @@ static size_t copy_in_user_pt(size_t n, void __user *to,
{
struct mm_struct *mm = current->mm;
unsigned long offset_from, offset_to, offset_max, pfn_from, pfn_to,
- uaddr, done, size;
+ uaddr, done, size, error_code;
unsigned long uaddr_from = (unsigned long) from;
unsigned long uaddr_to = (unsigned long) to;
pte_t *pte_from, *pte_to;
@@ -298,17 +242,28 @@ static size_t copy_in_user_pt(size_t n, void __user *to,
retry:
spin_lock(&mm->page_table_lock);
do {
+ write_user = 0;
+ uaddr = uaddr_from;
pte_from = follow_table(mm, uaddr_from);
- if (!pte_from || !pte_present(*pte_from)) {
- uaddr = uaddr_from;
- write_user = 0;
+ error_code = (unsigned long) pte_from;
+ if (error_code < 0x1000)
+ goto fault;
+ if (!pte_present(*pte_from)) {
+ error_code = 0x11;
goto fault;
}
+ write_user = 1;
+ uaddr = uaddr_to;
pte_to = follow_table(mm, uaddr_to);
- if (!pte_to || !pte_present(*pte_to) || !pte_write(*pte_to)) {
- uaddr = uaddr_to;
- write_user = 1;
+ error_code = (unsigned long) pte_to;
+ if (error_code < 0x1000)
+ goto fault;
+ if (!pte_present(*pte_to)) {
+ error_code = 0x11;
+ goto fault;
+ } else if (!pte_write(*pte_to)) {
+ error_code = 0x04;
goto fault;
}
@@ -329,7 +284,7 @@ retry:
return n - done;
fault:
spin_unlock(&mm->page_table_lock);
- if (__handle_fault(mm, uaddr, write_user))
+ if (__handle_fault(uaddr, error_code, write_user))
return n - done;
goto retry;
}
diff --git a/arch/s390/math-emu/math.c b/arch/s390/math-emu/math.c
index 3ee78cc..cd4e9c1 100644
--- a/arch/s390/math-emu/math.c
+++ b/arch/s390/math-emu/math.c
@@ -2088,7 +2088,7 @@ int math_emu_ldr(__u8 *opcode) {
__u16 opc = *((__u16 *) opcode);
if ((opc & 0x90) == 0) { /* test if rx in {0,2,4,6} */
- /* we got an exception therfore ry can't be in {0,2,4,6} */
+ /* we got an exception therefore ry can't be in {0,2,4,6} */
asm volatile( /* load rx from fp_regs.fprs[ry] */
" bras 1,0f\n"
" ld 0,0(%1)\n"
@@ -2118,7 +2118,7 @@ int math_emu_ler(__u8 *opcode) {
__u16 opc = *((__u16 *) opcode);
if ((opc & 0x90) == 0) { /* test if rx in {0,2,4,6} */
- /* we got an exception therfore ry can't be in {0,2,4,6} */
+ /* we got an exception therefore ry can't be in {0,2,4,6} */
asm volatile( /* load rx from fp_regs.fprs[ry] */
" bras 1,0f\n"
" le 0,0(%1)\n"
diff --git a/arch/s390/mm/cmm.c b/arch/s390/mm/cmm.c
index ff58779..76a3637 100644
--- a/arch/s390/mm/cmm.c
+++ b/arch/s390/mm/cmm.c
@@ -18,6 +18,7 @@
#include <linux/swap.h>
#include <linux/kthread.h>
#include <linux/oom.h>
+#include <linux/suspend.h>
#include <asm/pgalloc.h>
#include <asm/uaccess.h>
@@ -44,6 +45,7 @@ static volatile long cmm_pages_target;
static volatile long cmm_timed_pages_target;
static long cmm_timeout_pages;
static long cmm_timeout_seconds;
+static int cmm_suspended;
static struct cmm_page_array *cmm_page_list;
static struct cmm_page_array *cmm_timed_page_list;
@@ -147,9 +149,9 @@ cmm_thread(void *dummy)
while (1) {
rc = wait_event_interruptible(cmm_thread_wait,
- (cmm_pages != cmm_pages_target ||
- cmm_timed_pages != cmm_timed_pages_target ||
- kthread_should_stop()));
+ (!cmm_suspended && (cmm_pages != cmm_pages_target ||
+ cmm_timed_pages != cmm_timed_pages_target)) ||
+ kthread_should_stop());
if (kthread_should_stop() || rc == -ERESTARTSYS) {
cmm_pages_target = cmm_pages;
cmm_timed_pages_target = cmm_timed_pages;
@@ -410,6 +412,38 @@ cmm_smsg_target(char *from, char *msg)
static struct ctl_table_header *cmm_sysctl_header;
+static int cmm_suspend(void)
+{
+ cmm_suspended = 1;
+ cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list);
+ cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list);
+ return 0;
+}
+
+static int cmm_resume(void)
+{
+ cmm_suspended = 0;
+ cmm_kick_thread();
+ return 0;
+}
+
+static int cmm_power_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ switch (event) {
+ case PM_POST_HIBERNATION:
+ return cmm_resume();
+ case PM_HIBERNATION_PREPARE:
+ return cmm_suspend();
+ default:
+ return NOTIFY_DONE;
+ }
+}
+
+static struct notifier_block cmm_power_notifier = {
+ .notifier_call = cmm_power_event,
+};
+
static int
cmm_init (void)
{
@@ -418,7 +452,7 @@ cmm_init (void)
#ifdef CONFIG_CMM_PROC
cmm_sysctl_header = register_sysctl_table(cmm_dir_table);
if (!cmm_sysctl_header)
- goto out;
+ goto out_sysctl;
#endif
#ifdef CONFIG_CMM_IUCV
rc = smsg_register_callback(SMSG_PREFIX, cmm_smsg_target);
@@ -428,17 +462,21 @@ cmm_init (void)
rc = register_oom_notifier(&cmm_oom_nb);
if (rc < 0)
goto out_oom_notify;
+ rc = register_pm_notifier(&cmm_power_notifier);
+ if (rc)
+ goto out_pm;
init_waitqueue_head(&cmm_thread_wait);
init_timer(&cmm_timer);
cmm_thread_ptr = kthread_run(cmm_thread, NULL, "cmmthread");
rc = IS_ERR(cmm_thread_ptr) ? PTR_ERR(cmm_thread_ptr) : 0;
- if (!rc)
- goto out;
- /*
- * kthread_create failed. undo all the stuff from above again.
- */
- unregister_oom_notifier(&cmm_oom_nb);
+ if (rc)
+ goto out_kthread;
+ return 0;
+out_kthread:
+ unregister_pm_notifier(&cmm_power_notifier);
+out_pm:
+ unregister_oom_notifier(&cmm_oom_nb);
out_oom_notify:
#ifdef CONFIG_CMM_IUCV
smsg_unregister_callback(SMSG_PREFIX, cmm_smsg_target);
@@ -446,8 +484,8 @@ out_smsg:
#endif
#ifdef CONFIG_CMM_PROC
unregister_sysctl_table(cmm_sysctl_header);
+out_sysctl:
#endif
-out:
return rc;
}
@@ -455,6 +493,7 @@ static void
cmm_exit(void)
{
kthread_stop(cmm_thread_ptr);
+ unregister_pm_notifier(&cmm_power_notifier);
unregister_oom_notifier(&cmm_oom_nb);
cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list);
cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list);
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index 6d50746..fc102e7 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -34,16 +34,15 @@
#include <asm/pgtable.h>
#include <asm/s390_ext.h>
#include <asm/mmu_context.h>
+#include <asm/compat.h>
#include "../kernel/entry.h"
#ifndef CONFIG_64BIT
#define __FAIL_ADDR_MASK 0x7ffff000
-#define __FIXUP_MASK 0x7fffffff
#define __SUBCODE_MASK 0x0200
#define __PF_RES_FIELD 0ULL
#else /* CONFIG_64BIT */
#define __FAIL_ADDR_MASK -4096L
-#define __FIXUP_MASK ~0L
#define __SUBCODE_MASK 0x0600
#define __PF_RES_FIELD 0x8000000000000000ULL
#endif /* CONFIG_64BIT */
@@ -52,11 +51,15 @@
extern int sysctl_userprocess_debug;
#endif
-#ifdef CONFIG_KPROBES
-static inline int notify_page_fault(struct pt_regs *regs, long err)
+#define VM_FAULT_BADCONTEXT 0x010000
+#define VM_FAULT_BADMAP 0x020000
+#define VM_FAULT_BADACCESS 0x040000
+
+static inline int notify_page_fault(struct pt_regs *regs)
{
int ret = 0;
+#ifdef CONFIG_KPROBES
/* kprobe_running() needs smp_processor_id() */
if (!user_mode(regs)) {
preempt_disable();
@@ -64,15 +67,9 @@ static inline int notify_page_fault(struct pt_regs *regs, long err)
ret = 1;
preempt_enable();
}
-
+#endif
return ret;
}
-#else
-static inline int notify_page_fault(struct pt_regs *regs, long err)
-{
- return 0;
-}
-#endif
/*
@@ -100,57 +97,50 @@ void bust_spinlocks(int yes)
/*
* Returns the address space associated with the fault.
- * Returns 0 for kernel space, 1 for user space and
- * 2 for code execution in user space with noexec=on.
+ * Returns 0 for kernel space and 1 for user space.
*/
-static inline int check_space(struct task_struct *tsk)
+static inline int user_space_fault(unsigned long trans_exc_code)
{
/*
- * The lowest two bits of S390_lowcore.trans_exc_code
- * indicate which paging table was used.
+ * The lowest two bits of the translation exception
+ * identification indicate which paging table was used.
*/
- int desc = S390_lowcore.trans_exc_code & 3;
-
- if (desc == 3) /* Home Segment Table Descriptor */
- return switch_amode == 0;
- if (desc == 2) /* Secondary Segment Table Descriptor */
- return tsk->thread.mm_segment.ar4;
-#ifdef CONFIG_S390_SWITCH_AMODE
- if (unlikely(desc == 1)) { /* STD determined via access register */
- /* %a0 always indicates primary space. */
- if (S390_lowcore.exc_access_id != 0) {
- save_access_regs(tsk->thread.acrs);
- /*
- * An alet of 0 indicates primary space.
- * An alet of 1 indicates secondary space.
- * Any other alet values generate an
- * alen-translation exception.
- */
- if (tsk->thread.acrs[S390_lowcore.exc_access_id])
- return tsk->thread.mm_segment.ar4;
- }
- }
-#endif
- /* Primary Segment Table Descriptor */
- return switch_amode << s390_noexec;
+ trans_exc_code &= 3;
+ if (trans_exc_code == 2)
+ /* Access via secondary space, set_fs setting decides */
+ return current->thread.mm_segment.ar4;
+ if (user_mode == HOME_SPACE_MODE)
+ /* User space if the access has been done via home space. */
+ return trans_exc_code == 3;
+ /*
+ * If the user space is not the home space the kernel runs in home
+ * space. Access via secondary space has already been covered,
+ * access via primary space or access register is from user space
+ * and access via home space is from the kernel.
+ */
+ return trans_exc_code != 3;
}
/*
* Send SIGSEGV to task. This is an external routine
* to keep the stack usage of do_page_fault small.
*/
-static void do_sigsegv(struct pt_regs *regs, unsigned long error_code,
- int si_code, unsigned long address)
+static noinline void do_sigsegv(struct pt_regs *regs, long int_code,
+ int si_code, unsigned long trans_exc_code)
{
struct siginfo si;
+ unsigned long address;
+ address = trans_exc_code & __FAIL_ADDR_MASK;
+ current->thread.prot_addr = address;
+ current->thread.trap_no = int_code;
#if defined(CONFIG_SYSCTL) || defined(CONFIG_PROCESS_DEBUG)
#if defined(CONFIG_SYSCTL)
if (sysctl_userprocess_debug)
#endif
{
printk("User process fault: interruption code 0x%lX\n",
- error_code);
+ int_code);
printk("failing address: %lX\n", address);
show_regs(regs);
}
@@ -161,13 +151,14 @@ static void do_sigsegv(struct pt_regs *regs, unsigned long error_code,
force_sig_info(SIGSEGV, &si, current);
}
-static void do_no_context(struct pt_regs *regs, unsigned long error_code,
- unsigned long address)
+static noinline void do_no_context(struct pt_regs *regs, long int_code,
+ unsigned long trans_exc_code)
{
const struct exception_table_entry *fixup;
+ unsigned long address;
/* Are we prepared to handle this kernel fault? */
- fixup = search_exception_tables(regs->psw.addr & __FIXUP_MASK);
+ fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN);
if (fixup) {
regs->psw.addr = fixup->fixup | PSW_ADDR_AMODE;
return;
@@ -177,129 +168,149 @@ static void do_no_context(struct pt_regs *regs, unsigned long error_code,
* Oops. The kernel tried to access some bad page. We'll have to
* terminate things with extreme prejudice.
*/
- if (check_space(current) == 0)
+ address = trans_exc_code & __FAIL_ADDR_MASK;
+ if (!user_space_fault(trans_exc_code))
printk(KERN_ALERT "Unable to handle kernel pointer dereference"
" at virtual kernel address %p\n", (void *)address);
else
printk(KERN_ALERT "Unable to handle kernel paging request"
" at virtual user address %p\n", (void *)address);
- die("Oops", regs, error_code);
+ die("Oops", regs, int_code);
do_exit(SIGKILL);
}
-static void do_low_address(struct pt_regs *regs, unsigned long error_code)
+static noinline void do_low_address(struct pt_regs *regs, long int_code,
+ unsigned long trans_exc_code)
{
/* Low-address protection hit in kernel mode means
NULL pointer write access in kernel mode. */
if (regs->psw.mask & PSW_MASK_PSTATE) {
/* Low-address protection hit in user mode 'cannot happen'. */
- die ("Low-address protection", regs, error_code);
+ die ("Low-address protection", regs, int_code);
do_exit(SIGKILL);
}
- do_no_context(regs, error_code, 0);
+ do_no_context(regs, int_code, trans_exc_code);
}
-static void do_sigbus(struct pt_regs *regs, unsigned long error_code,
- unsigned long address)
+static noinline void do_sigbus(struct pt_regs *regs, long int_code,
+ unsigned long trans_exc_code)
{
struct task_struct *tsk = current;
- struct mm_struct *mm = tsk->mm;
- up_read(&mm->mmap_sem);
/*
* Send a sigbus, regardless of whether we were in kernel
* or user mode.
*/
- tsk->thread.prot_addr = address;
- tsk->thread.trap_no = error_code;
+ tsk->thread.prot_addr = trans_exc_code & __FAIL_ADDR_MASK;
+ tsk->thread.trap_no = int_code;
force_sig(SIGBUS, tsk);
-
- /* Kernel mode? Handle exceptions or die */
- if (!(regs->psw.mask & PSW_MASK_PSTATE))
- do_no_context(regs, error_code, address);
}
#ifdef CONFIG_S390_EXEC_PROTECT
-static int signal_return(struct mm_struct *mm, struct pt_regs *regs,
- unsigned long address, unsigned long error_code)
+static noinline int signal_return(struct pt_regs *regs, long int_code,
+ unsigned long trans_exc_code)
{
u16 instruction;
int rc;
-#ifdef CONFIG_COMPAT
- int compat;
-#endif
- pagefault_disable();
rc = __get_user(instruction, (u16 __user *) regs->psw.addr);
- pagefault_enable();
- if (rc)
- return -EFAULT;
- up_read(&mm->mmap_sem);
- clear_tsk_thread_flag(current, TIF_SINGLE_STEP);
-#ifdef CONFIG_COMPAT
- compat = is_compat_task();
- if (compat && instruction == 0x0a77)
- sys32_sigreturn();
- else if (compat && instruction == 0x0aad)
- sys32_rt_sigreturn();
- else
-#endif
- if (instruction == 0x0a77)
- sys_sigreturn();
- else if (instruction == 0x0aad)
- sys_rt_sigreturn();
- else {
- current->thread.prot_addr = address;
- current->thread.trap_no = error_code;
- do_sigsegv(regs, error_code, SEGV_MAPERR, address);
- }
+ if (!rc && instruction == 0x0a77) {
+ clear_tsk_thread_flag(current, TIF_SINGLE_STEP);
+ if (is_compat_task())
+ sys32_sigreturn();
+ else
+ sys_sigreturn();
+ } else if (!rc && instruction == 0x0aad) {
+ clear_tsk_thread_flag(current, TIF_SINGLE_STEP);
+ if (is_compat_task())
+ sys32_rt_sigreturn();
+ else
+ sys_rt_sigreturn();
+ } else
+ do_sigsegv(regs, int_code, SEGV_MAPERR, trans_exc_code);
return 0;
}
#endif /* CONFIG_S390_EXEC_PROTECT */
+static noinline void do_fault_error(struct pt_regs *regs, long int_code,
+ unsigned long trans_exc_code, int fault)
+{
+ int si_code;
+
+ switch (fault) {
+ case VM_FAULT_BADACCESS:
+#ifdef CONFIG_S390_EXEC_PROTECT
+ if ((regs->psw.mask & PSW_MASK_ASC) == PSW_ASC_SECONDARY &&
+ (trans_exc_code & 3) == 0) {
+ signal_return(regs, int_code, trans_exc_code);
+ break;
+ }
+#endif /* CONFIG_S390_EXEC_PROTECT */
+ case VM_FAULT_BADMAP:
+ /* Bad memory access. Check if it is kernel or user space. */
+ if (regs->psw.mask & PSW_MASK_PSTATE) {
+ /* User mode accesses just cause a SIGSEGV */
+ si_code = (fault == VM_FAULT_BADMAP) ?
+ SEGV_MAPERR : SEGV_ACCERR;
+ do_sigsegv(regs, int_code, si_code, trans_exc_code);
+ return;
+ }
+ case VM_FAULT_BADCONTEXT:
+ do_no_context(regs, int_code, trans_exc_code);
+ break;
+ default: /* fault & VM_FAULT_ERROR */
+ if (fault & VM_FAULT_OOM)
+ pagefault_out_of_memory();
+ else if (fault & VM_FAULT_SIGBUS) {
+ do_sigbus(regs, int_code, trans_exc_code);
+ /* Kernel mode? Handle exceptions or die */
+ if (!(regs->psw.mask & PSW_MASK_PSTATE))
+ do_no_context(regs, int_code, trans_exc_code);
+ } else
+ BUG();
+ break;
+ }
+}
+
/*
* This routine handles page faults. It determines the address,
* and the problem, and then passes it off to one of the appropriate
* routines.
*
- * error_code:
+ * interruption code (int_code):
* 04 Protection -> Write-Protection (suprression)
* 10 Segment translation -> Not present (nullification)
* 11 Page translation -> Not present (nullification)
* 3b Region third trans. -> Not present (nullification)
*/
-static inline void
-do_exception(struct pt_regs *regs, unsigned long error_code, int write)
+static inline int do_exception(struct pt_regs *regs, int access,
+ unsigned long trans_exc_code)
{
struct task_struct *tsk;
struct mm_struct *mm;
struct vm_area_struct *vma;
unsigned long address;
- int space;
- int si_code;
int fault;
- if (notify_page_fault(regs, error_code))
- return;
+ if (notify_page_fault(regs))
+ return 0;
tsk = current;
mm = tsk->mm;
- /* get the failing address and the affected space */
- address = S390_lowcore.trans_exc_code & __FAIL_ADDR_MASK;
- space = check_space(tsk);
-
/*
* Verify that the fault happened in user space, that
* we are not in an interrupt and that there is a
* user context.
*/
- if (unlikely(space == 0 || in_atomic() || !mm))
- goto no_context;
+ fault = VM_FAULT_BADCONTEXT;
+ if (unlikely(!user_space_fault(trans_exc_code) || in_atomic() || !mm))
+ goto out;
+ address = trans_exc_code & __FAIL_ADDR_MASK;
/*
* When we get here, the fault happened in the current
* task's user address space, so we can switch on the
@@ -309,42 +320,26 @@ do_exception(struct pt_regs *regs, unsigned long error_code, int write)
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address);
down_read(&mm->mmap_sem);
- si_code = SEGV_MAPERR;
+ fault = VM_FAULT_BADMAP;
vma = find_vma(mm, address);
if (!vma)
- goto bad_area;
-
-#ifdef CONFIG_S390_EXEC_PROTECT
- if (unlikely((space == 2) && !(vma->vm_flags & VM_EXEC)))
- if (!signal_return(mm, regs, address, error_code))
- /*
- * signal_return() has done an up_read(&mm->mmap_sem)
- * if it returns 0.
- */
- return;
-#endif
+ goto out_up;
- if (vma->vm_start <= address)
- goto good_area;
- if (!(vma->vm_flags & VM_GROWSDOWN))
- goto bad_area;
- if (expand_stack(vma, address))
- goto bad_area;
-/*
- * Ok, we have a good vm_area for this memory access, so
- * we can handle it..
- */
-good_area:
- si_code = SEGV_ACCERR;
- if (!write) {
- /* page not present, check vm flags */
- if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
- goto bad_area;
- } else {
- if (!(vma->vm_flags & VM_WRITE))
- goto bad_area;
+ if (unlikely(vma->vm_start > address)) {
+ if (!(vma->vm_flags & VM_GROWSDOWN))
+ goto out_up;
+ if (expand_stack(vma, address))
+ goto out_up;
}
+ /*
+ * Ok, we have a good vm_area for this memory access, so
+ * we can handle it..
+ */
+ fault = VM_FAULT_BADACCESS;
+ if (unlikely(!(vma->vm_flags & access)))
+ goto out_up;
+
if (is_vm_hugetlb_page(vma))
address &= HPAGE_MASK;
/*
@@ -352,18 +347,11 @@ good_area:
* make sure we exit gracefully rather than endlessly redo
* the fault.
*/
- fault = handle_mm_fault(mm, vma, address, write ? FAULT_FLAG_WRITE : 0);
- if (unlikely(fault & VM_FAULT_ERROR)) {
- if (fault & VM_FAULT_OOM) {
- up_read(&mm->mmap_sem);
- pagefault_out_of_memory();
- return;
- } else if (fault & VM_FAULT_SIGBUS) {
- do_sigbus(regs, error_code, address);
- return;
- }
- BUG();
- }
+ fault = handle_mm_fault(mm, vma, address,
+ (access == VM_WRITE) ? FAULT_FLAG_WRITE : 0);
+ if (unlikely(fault & VM_FAULT_ERROR))
+ goto out_up;
+
if (fault & VM_FAULT_MAJOR) {
tsk->maj_flt++;
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0,
@@ -373,74 +361,69 @@ good_area:
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0,
regs, address);
}
- up_read(&mm->mmap_sem);
/*
* The instruction that caused the program check will
* be repeated. Don't signal single step via SIGTRAP.
*/
clear_tsk_thread_flag(tsk, TIF_SINGLE_STEP);
- return;
-
-/*
- * Something tried to access memory that isn't in our memory map..
- * Fix it, but check if it's kernel or user first..
- */
-bad_area:
+ fault = 0;
+out_up:
up_read(&mm->mmap_sem);
-
- /* User mode accesses just cause a SIGSEGV */
- if (regs->psw.mask & PSW_MASK_PSTATE) {
- tsk->thread.prot_addr = address;
- tsk->thread.trap_no = error_code;
- do_sigsegv(regs, error_code, si_code, address);
- return;
- }
-
-no_context:
- do_no_context(regs, error_code, address);
+out:
+ return fault;
}
-void __kprobes do_protection_exception(struct pt_regs *regs,
- long error_code)
+void __kprobes do_protection_exception(struct pt_regs *regs, long int_code)
{
+ unsigned long trans_exc_code = S390_lowcore.trans_exc_code;
+ int fault;
+
/* Protection exception is supressing, decrement psw address. */
- regs->psw.addr -= (error_code >> 16);
+ regs->psw.addr -= (int_code >> 16);
/*
* Check for low-address protection. This needs to be treated
* as a special case because the translation exception code
* field is not guaranteed to contain valid data in this case.
*/
- if (unlikely(!(S390_lowcore.trans_exc_code & 4))) {
- do_low_address(regs, error_code);
+ if (unlikely(!(trans_exc_code & 4))) {
+ do_low_address(regs, int_code, trans_exc_code);
return;
}
- do_exception(regs, 4, 1);
+ fault = do_exception(regs, VM_WRITE, trans_exc_code);
+ if (unlikely(fault))
+ do_fault_error(regs, 4, trans_exc_code, fault);
}
-void __kprobes do_dat_exception(struct pt_regs *regs, long error_code)
+void __kprobes do_dat_exception(struct pt_regs *regs, long int_code)
{
- do_exception(regs, error_code & 0xff, 0);
+ unsigned long trans_exc_code = S390_lowcore.trans_exc_code;
+ int access, fault;
+
+ access = VM_READ | VM_EXEC | VM_WRITE;
+#ifdef CONFIG_S390_EXEC_PROTECT
+ if ((regs->psw.mask & PSW_MASK_ASC) == PSW_ASC_SECONDARY &&
+ (trans_exc_code & 3) == 0)
+ access = VM_EXEC;
+#endif
+ fault = do_exception(regs, access, trans_exc_code);
+ if (unlikely(fault))
+ do_fault_error(regs, int_code & 255, trans_exc_code, fault);
}
#ifdef CONFIG_64BIT
-void __kprobes do_asce_exception(struct pt_regs *regs, unsigned long error_code)
+void __kprobes do_asce_exception(struct pt_regs *regs, long int_code)
{
- struct mm_struct *mm;
+ unsigned long trans_exc_code = S390_lowcore.trans_exc_code;
+ struct mm_struct *mm = current->mm;
struct vm_area_struct *vma;
- unsigned long address;
- int space;
-
- mm = current->mm;
- address = S390_lowcore.trans_exc_code & __FAIL_ADDR_MASK;
- space = check_space(current);
- if (unlikely(space == 0 || in_atomic() || !mm))
+ if (unlikely(!user_space_fault(trans_exc_code) || in_atomic() || !mm))
goto no_context;
local_irq_enable();
down_read(&mm->mmap_sem);
- vma = find_vma(mm, address);
+ vma = find_vma(mm, trans_exc_code & __FAIL_ADDR_MASK);
up_read(&mm->mmap_sem);
if (vma) {
@@ -450,17 +433,38 @@ void __kprobes do_asce_exception(struct pt_regs *regs, unsigned long error_code)
/* User mode accesses just cause a SIGSEGV */
if (regs->psw.mask & PSW_MASK_PSTATE) {
- current->thread.prot_addr = address;
- current->thread.trap_no = error_code;
- do_sigsegv(regs, error_code, SEGV_MAPERR, address);
+ do_sigsegv(regs, int_code, SEGV_MAPERR, trans_exc_code);
return;
}
no_context:
- do_no_context(regs, error_code, address);
+ do_no_context(regs, int_code, trans_exc_code);
}
#endif
+int __handle_fault(unsigned long uaddr, unsigned long int_code, int write_user)
+{
+ struct pt_regs regs;
+ int access, fault;
+
+ regs.psw.mask = psw_kernel_bits;
+ if (!irqs_disabled())
+ regs.psw.mask |= PSW_MASK_IO | PSW_MASK_EXT;
+ regs.psw.addr = (unsigned long) __builtin_return_address(0);
+ regs.psw.addr |= PSW_ADDR_AMODE;
+ uaddr &= PAGE_MASK;
+ access = write_user ? VM_WRITE : VM_READ;
+ fault = do_exception(&regs, access, uaddr | 2);
+ if (unlikely(fault)) {
+ if (fault & VM_FAULT_OOM) {
+ pagefault_out_of_memory();
+ fault = 0;
+ } else if (fault & VM_FAULT_SIGBUS)
+ do_sigbus(&regs, int_code, uaddr);
+ }
+ return fault ? -EFAULT : 0;
+}
+
#ifdef CONFIG_PFAULT
/*
* 'pfault' pseudo page faults routines.
@@ -522,7 +526,7 @@ void pfault_fini(void)
: : "a" (&refbk), "m" (refbk) : "cc");
}
-static void pfault_interrupt(__u16 error_code)
+static void pfault_interrupt(__u16 int_code)
{
struct task_struct *tsk;
__u16 subcode;
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c
index 2757c56..ad621e0 100644
--- a/arch/s390/mm/pgtable.c
+++ b/arch/s390/mm/pgtable.c
@@ -269,7 +269,7 @@ int s390_enable_sie(void)
struct mm_struct *mm, *old_mm;
/* Do we have switched amode? If no, we cannot do sie */
- if (!switch_amode)
+ if (user_mode == HOME_SPACE_MODE)
return -EINVAL;
/* Do we have pgstes? if yes, we are done */
diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c
index 5f91a38..300ab01 100644
--- a/arch/s390/mm/vmem.c
+++ b/arch/s390/mm/vmem.c
@@ -70,8 +70,12 @@ static pte_t __ref *vmem_pte_alloc(void)
pte = alloc_bootmem(PTRS_PER_PTE * sizeof(pte_t));
if (!pte)
return NULL;
- clear_table((unsigned long *) pte, _PAGE_TYPE_EMPTY,
- PTRS_PER_PTE * sizeof(pte_t));
+ if (MACHINE_HAS_HPAGE)
+ clear_table((unsigned long *) pte, _PAGE_TYPE_EMPTY | _PAGE_CO,
+ PTRS_PER_PTE * sizeof(pte_t));
+ else
+ clear_table((unsigned long *) pte, _PAGE_TYPE_EMPTY,
+ PTRS_PER_PTE * sizeof(pte_t));
return pte;
}
@@ -112,7 +116,8 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro)
if (MACHINE_HAS_HPAGE && !(address & ~HPAGE_MASK) &&
(address + HPAGE_SIZE <= start + size) &&
(address >= HPAGE_SIZE)) {
- pte_val(pte) |= _SEGMENT_ENTRY_LARGE;
+ pte_val(pte) |= _SEGMENT_ENTRY_LARGE |
+ _SEGMENT_ENTRY_CO;
pmd_val(*pm_dir) = pte_val(pte);
address += HPAGE_SIZE - PAGE_SIZE;
continue;
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 88cdeb9..0031a69 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -16,7 +16,9 @@ config SUPERH
select HAVE_IOREMAP_PROT if MMU
select HAVE_ARCH_TRACEHOOK
select HAVE_DMA_API_DEBUG
+ select HAVE_DMA_ATTRS
select HAVE_PERF_EVENTS
+ select PERF_USE_VMALLOC
select HAVE_KERNEL_GZIP
select HAVE_KERNEL_BZIP2
select HAVE_KERNEL_LZMA
@@ -37,6 +39,7 @@ config SUPERH32
select HAVE_FTRACE_MCOUNT_RECORD
select HAVE_DYNAMIC_FTRACE
select HAVE_FUNCTION_TRACE_MCOUNT_TEST
+ select HAVE_FTRACE_NMI_ENTER if DYNAMIC_FTRACE
select HAVE_FUNCTION_GRAPH_TRACER
select HAVE_ARCH_KGDB
select ARCH_HIBERNATION_POSSIBLE if MMU
@@ -170,6 +173,12 @@ config ARCH_HAS_CPU_IDLE_WAIT
config IO_TRAPPED
bool
+config DMA_COHERENT
+ bool
+
+config DMA_NONCOHERENT
+ def_bool !DMA_COHERENT
+
source "init/Kconfig"
source "kernel/Kconfig.freezer"
@@ -220,6 +229,7 @@ config CPU_SHX2
config CPU_SHX3
bool
+ select DMA_COHERENT
config ARCH_SHMOBILE
bool
@@ -761,17 +771,6 @@ config ENTRY_OFFSET
default "0x00010000" if PAGE_SIZE_64KB
default "0x00000000"
-config UBC_WAKEUP
- bool "Wakeup UBC on startup"
- depends on CPU_SH4 && !CPU_SH4A
- help
- Selecting this option will wakeup the User Break Controller (UBC) on
- startup. Although the UBC is left in an awake state when the processor
- comes up, some boot loaders misbehave by putting the UBC to sleep in a
- power saving state, which causes issues with things like ptrace().
-
- If unsure, say N.
-
choice
prompt "Kernel command line"
optional
@@ -818,7 +817,13 @@ config MAPLE
Dreamcast with a serial line terminal or a remote network
connection.
-source "arch/sh/drivers/pci/Kconfig"
+config PCI
+ bool "PCI support"
+ depends on SYS_SUPPORTS_PCI
+ 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
+ your box. If you have PCI, say Y, otherwise N.
source "drivers/pci/pcie/Kconfig"
diff --git a/arch/sh/Makefile b/arch/sh/Makefile
index 66e40aa..ac17c5a 100644
--- a/arch/sh/Makefile
+++ b/arch/sh/Makefile
@@ -78,6 +78,9 @@ defaultimage-$(CONFIG_SUPERH32) := zImage
defaultimage-$(CONFIG_SH_SH7785LCR) := uImage
defaultimage-$(CONFIG_SH_RSK) := uImage
defaultimage-$(CONFIG_SH_URQUELL) := uImage
+defaultimage-$(CONFIG_SH_MIGOR) := uImage
+defaultimage-$(CONFIG_SH_AP325RXA) := uImage
+defaultimage-$(CONFIG_SH_7724_SOLUTION_ENGINE) := uImage
defaultimage-$(CONFIG_SH_7206_SOLUTION_ENGINE) := vmlinux
defaultimage-$(CONFIG_SH_7619_SOLUTION_ENGINE) := vmlinux
@@ -136,6 +139,7 @@ machdir-$(CONFIG_SH_7751_SYSTEMH) += mach-systemh
machdir-$(CONFIG_SH_EDOSK7705) += mach-edosk7705
machdir-$(CONFIG_SH_HIGHLANDER) += mach-highlander
machdir-$(CONFIG_SH_MIGOR) += mach-migor
+machdir-$(CONFIG_SH_AP325RXA) += mach-ap325rxa
machdir-$(CONFIG_SH_KFR2R09) += mach-kfr2r09
machdir-$(CONFIG_SH_ECOVEC) += mach-ecovec24
machdir-$(CONFIG_SH_SDK7780) += mach-sdk7780
diff --git a/arch/sh/boards/Makefile b/arch/sh/boards/Makefile
index 7baa210..ce0f263 100644
--- a/arch/sh/boards/Makefile
+++ b/arch/sh/boards/Makefile
@@ -1,7 +1,6 @@
#
# Specific board support, not covered by a mach group.
#
-obj-$(CONFIG_SH_AP325RXA) += board-ap325rxa.o
obj-$(CONFIG_SH_MAGIC_PANEL_R2) += board-magicpanelr2.o
obj-$(CONFIG_SH_SH7785LCR) += board-sh7785lcr.o
obj-$(CONFIG_SH_URQUELL) += board-urquell.o
diff --git a/arch/sh/boards/mach-ap325rxa/Makefile b/arch/sh/boards/mach-ap325rxa/Makefile
new file mode 100644
index 0000000..4cf1774
--- /dev/null
+++ b/arch/sh/boards/mach-ap325rxa/Makefile
@@ -0,0 +1,2 @@
+obj-y := setup.o sdram.o
+
diff --git a/arch/sh/boards/mach-ap325rxa/sdram.S b/arch/sh/boards/mach-ap325rxa/sdram.S
new file mode 100644
index 0000000..db24fbe
--- /dev/null
+++ b/arch/sh/boards/mach-ap325rxa/sdram.S
@@ -0,0 +1,69 @@
+/*
+ * AP325RXA sdram self/auto-refresh setup code
+ *
+ * Copyright (C) 2009 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/sys.h>
+#include <linux/errno.h>
+#include <linux/linkage.h>
+#include <asm/asm-offsets.h>
+#include <asm/suspend.h>
+#include <asm/romimage-macros.h>
+
+/* code to enter and leave self-refresh. must be self-contained.
+ * this code will be copied to on-chip memory and executed from there.
+ */
+ .balign 4
+ENTRY(ap325rxa_sdram_enter_start)
+
+ /* SBSC: disable power down and put in self-refresh mode */
+ mov.l 1f, r4
+ mov.l 2f, r1
+ mov.l @r4, r2
+ or r1, r2
+ mov.l 3f, r3
+ and r3, r2
+ mov.l r2, @r4
+
+ rts
+ nop
+
+ .balign 4
+1: .long 0xfe400008 /* SDCR0 */
+2: .long 0x00000400
+3: .long 0xffff7fff
+ENTRY(ap325rxa_sdram_enter_end)
+
+ .balign 4
+ENTRY(ap325rxa_sdram_leave_start)
+
+ /* SBSC: set auto-refresh mode */
+ mov.l 1f, r4
+ mov.l @r4, r0
+ mov.l 4f, r1
+ and r1, r0
+ mov.l r0, @r4
+ mov.l 6f, r4
+ mov.l 8f, r0
+ mov.l @r4, r1
+ mov #-1, r4
+ add r4, r1
+ or r1, r0
+ mov.l 7f, r1
+ mov.l r0, @r1
+
+ rts
+ nop
+
+ .balign 4
+1: .long 0xfe400008 /* SDCR0 */
+4: .long 0xfffffbff
+6: .long 0xfe40001c /* RTCOR */
+7: .long 0xfe400018 /* RTCNT */
+8: .long 0xa55a0000
+ENTRY(ap325rxa_sdram_leave_end)
diff --git a/arch/sh/boards/board-ap325rxa.c b/arch/sh/boards/mach-ap325rxa/setup.c
index 2d08073..cf9dc12 100644
--- a/arch/sh/boards/board-ap325rxa.c
+++ b/arch/sh/boards/mach-ap325rxa/setup.c
@@ -20,8 +20,6 @@
#include <linux/i2c.h>
#include <linux/smsc911x.h>
#include <linux/gpio.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/spi_gpio.h>
#include <media/ov772x.h>
#include <media/soc_camera.h>
#include <media/soc_camera_platform.h>
@@ -29,6 +27,7 @@
#include <video/sh_mobile_lcdc.h>
#include <asm/io.h>
#include <asm/clock.h>
+#include <asm/suspend.h>
#include <cpu/sh7723.h>
static struct smsc911x_platform_config smsc911x_config = {
@@ -409,17 +408,49 @@ static struct platform_device ceu_device = {
},
};
-struct spi_gpio_platform_data sdcard_cn3_platform_data = {
- .sck = GPIO_PTD0,
- .mosi = GPIO_PTD1,
- .miso = GPIO_PTD2,
- .num_chipselect = 1,
+static struct resource sdhi0_cn3_resources[] = {
+ [0] = {
+ .name = "SDHI0",
+ .start = 0x04ce0000,
+ .end = 0x04ce01ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 101,
+ .flags = IORESOURCE_IRQ,
+ },
};
-static struct platform_device sdcard_cn3_device = {
- .name = "spi_gpio",
- .dev = {
- .platform_data = &sdcard_cn3_platform_data,
+static struct platform_device sdhi0_cn3_device = {
+ .name = "sh_mobile_sdhi",
+ .id = 0, /* "sdhi0" clock */
+ .num_resources = ARRAY_SIZE(sdhi0_cn3_resources),
+ .resource = sdhi0_cn3_resources,
+ .archdata = {
+ .hwblk_id = HWBLK_SDHI0,
+ },
+};
+
+static struct resource sdhi1_cn7_resources[] = {
+ [0] = {
+ .name = "SDHI1",
+ .start = 0x04cf0000,
+ .end = 0x04cf01ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 24,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device sdhi1_cn7_device = {
+ .name = "sh_mobile_sdhi",
+ .id = 1, /* "sdhi1" clock */
+ .num_resources = ARRAY_SIZE(sdhi1_cn7_resources),
+ .resource = sdhi1_cn7_resources,
+ .archdata = {
+ .hwblk_id = HWBLK_SDHI1,
},
};
@@ -470,22 +501,26 @@ static struct platform_device *ap325rxa_devices[] __initdata = {
&lcdc_device,
&ceu_device,
&nand_flash_device,
- &sdcard_cn3_device,
+ &sdhi0_cn3_device,
+ &sdhi1_cn7_device,
&ap325rxa_camera[0],
&ap325rxa_camera[1],
};
-static struct spi_board_info ap325rxa_spi_devices[] = {
- {
- .modalias = "mmc_spi",
- .max_speed_hz = 5000000,
- .chip_select = 0,
- .controller_data = (void *) GPIO_PTD5,
- },
-};
+extern char ap325rxa_sdram_enter_start;
+extern char ap325rxa_sdram_enter_end;
+extern char ap325rxa_sdram_leave_start;
+extern char ap325rxa_sdram_leave_end;
static int __init ap325rxa_devices_setup(void)
{
+ /* register board specific self-refresh code */
+ sh_mobile_register_self_refresh(SUSP_SH_STANDBY | SUSP_SH_SF,
+ &ap325rxa_sdram_enter_start,
+ &ap325rxa_sdram_enter_end,
+ &ap325rxa_sdram_leave_start,
+ &ap325rxa_sdram_leave_end);
+
/* LD3 and LD4 LEDs */
gpio_request(GPIO_PTX5, NULL); /* RUN */
gpio_direction_output(GPIO_PTX5, 1);
@@ -578,12 +613,28 @@ static int __init ap325rxa_devices_setup(void)
platform_resource_setup_memory(&ceu_device, "ceu", 4 << 20);
+ /* SDHI0 - CN3 - SD CARD */
+ gpio_request(GPIO_FN_SDHI0CD_PTD, NULL);
+ gpio_request(GPIO_FN_SDHI0WP_PTD, NULL);
+ gpio_request(GPIO_FN_SDHI0D3_PTD, NULL);
+ gpio_request(GPIO_FN_SDHI0D2_PTD, NULL);
+ gpio_request(GPIO_FN_SDHI0D1_PTD, NULL);
+ gpio_request(GPIO_FN_SDHI0D0_PTD, NULL);
+ gpio_request(GPIO_FN_SDHI0CMD_PTD, NULL);
+ gpio_request(GPIO_FN_SDHI0CLK_PTD, NULL);
+
+ /* SDHI1 - CN7 - MICRO SD CARD */
+ gpio_request(GPIO_FN_SDHI1CD, NULL);
+ gpio_request(GPIO_FN_SDHI1D3, NULL);
+ gpio_request(GPIO_FN_SDHI1D2, NULL);
+ gpio_request(GPIO_FN_SDHI1D1, NULL);
+ gpio_request(GPIO_FN_SDHI1D0, NULL);
+ gpio_request(GPIO_FN_SDHI1CMD, NULL);
+ gpio_request(GPIO_FN_SDHI1CLK, NULL);
+
i2c_register_board_info(0, ap325rxa_i2c_devices,
ARRAY_SIZE(ap325rxa_i2c_devices));
- spi_register_board_info(ap325rxa_spi_devices,
- ARRAY_SIZE(ap325rxa_spi_devices));
-
return platform_add_devices(ap325rxa_devices,
ARRAY_SIZE(ap325rxa_devices));
}
diff --git a/arch/sh/boards/mach-ecovec24/Makefile b/arch/sh/boards/mach-ecovec24/Makefile
index 51f8521..e69bc82 100644
--- a/arch/sh/boards/mach-ecovec24/Makefile
+++ b/arch/sh/boards/mach-ecovec24/Makefile
@@ -6,4 +6,4 @@
# for more details.
#
-obj-y := setup.o \ No newline at end of file
+obj-y := setup.o sdram.o \ No newline at end of file
diff --git a/arch/sh/boards/mach-ecovec24/sdram.S b/arch/sh/boards/mach-ecovec24/sdram.S
new file mode 100644
index 0000000..8334400
--- /dev/null
+++ b/arch/sh/boards/mach-ecovec24/sdram.S
@@ -0,0 +1,52 @@
+/*
+ * Ecovec24 sdram self/auto-refresh setup code
+ *
+ * Copyright (C) 2009 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/sys.h>
+#include <linux/errno.h>
+#include <linux/linkage.h>
+#include <asm/asm-offsets.h>
+#include <asm/suspend.h>
+#include <asm/romimage-macros.h>
+
+/* code to enter and leave self-refresh. must be self-contained.
+ * this code will be copied to on-chip memory and executed from there.
+ */
+ .balign 4
+ENTRY(ecovec24_sdram_enter_start)
+
+ /* DBSC: put memory in self-refresh mode */
+
+ ED 0xFD000010, 0x00000000 /* DBEN */
+ ED 0xFD000040, 0x00000000 /* DBRFPDN0 */
+ ED 0xFD000014, 0x00000002 /* DBCMDCNT (PALL) */
+ ED 0xFD000014, 0x00000004 /* DBCMDCNT (REF) */
+ ED 0xFD000040, 0x00000001 /* DBRFPDN0 */
+
+ rts
+ nop
+
+ENTRY(ecovec24_sdram_enter_end)
+
+ .balign 4
+ENTRY(ecovec24_sdram_leave_start)
+
+ /* DBSC: put memory in auto-refresh mode */
+
+ ED 0xFD000040, 0x00000000 /* DBRFPDN0 */
+ WAIT 1
+ ED 0xFD000014, 0x00000002 /* DBCMDCNT (PALL) */
+ ED 0xFD000014, 0x00000004 /* DBCMDCNT (REF) */
+ ED 0xFD000010, 0x00000001 /* DBEN */
+ ED 0xFD000040, 0x00010000 /* DBRFPDN0 */
+
+ rts
+ nop
+
+ENTRY(ecovec24_sdram_leave_end)
diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c
index 3b1ceb4..826e623 100644
--- a/arch/sh/boards/mach-ecovec24/setup.c
+++ b/arch/sh/boards/mach-ecovec24/setup.c
@@ -20,12 +20,14 @@
#include <linux/i2c.h>
#include <linux/i2c/tsc2007.h>
#include <linux/input.h>
+#include <linux/input/sh_keysc.h>
+#include <linux/mfd/sh_mobile_sdhi.h>
#include <video/sh_mobile_lcdc.h>
#include <media/sh_mobile_ceu.h>
#include <asm/heartbeat.h>
#include <asm/sh_eth.h>
-#include <asm/sh_keysc.h>
#include <asm/clock.h>
+#include <asm/suspend.h>
#include <cpu/sh7724.h>
/*
@@ -147,6 +149,9 @@ static struct platform_device sh_eth_device = {
},
.num_resources = ARRAY_SIZE(sh_eth_resources),
.resource = sh_eth_resources,
+ .archdata = {
+ .hwblk_id = HWBLK_ETHER,
+ },
};
/* USB0 host */
@@ -185,30 +190,18 @@ static struct platform_device usb0_host_device = {
.resource = usb0_host_resources,
};
-/*
- * USB1
- *
- * CN5 can use both host/function,
- * and we can determine it by checking PTB[3]
- *
- * This time only USB1 host is supported.
- */
+/* USB1 host/function */
void usb1_port_power(int port, int power)
{
- if (!gpio_get_value(GPIO_PTB3)) {
- printk(KERN_ERR "USB1 function is not supported\n");
- return;
- }
-
gpio_set_value(GPIO_PTB5, power);
}
-static struct r8a66597_platdata usb1_host_data = {
+static struct r8a66597_platdata usb1_common_data = {
.on_chip = 1,
.port_power = usb1_port_power,
};
-static struct resource usb1_host_resources[] = {
+static struct resource usb1_common_resources[] = {
[0] = {
.start = 0xa4d90000,
.end = 0xa4d90124 - 1,
@@ -221,16 +214,16 @@ static struct resource usb1_host_resources[] = {
},
};
-static struct platform_device usb1_host_device = {
- .name = "r8a66597_hcd",
+static struct platform_device usb1_common_device = {
+ /* .name will be added in arch_setup */
.id = 1,
.dev = {
.dma_mask = NULL, /* not use dma */
.coherent_dma_mask = 0xffffffff,
- .platform_data = &usb1_host_data,
+ .platform_data = &usb1_common_data,
},
- .num_resources = ARRAY_SIZE(usb1_host_resources),
- .resource = usb1_host_resources,
+ .num_resources = ARRAY_SIZE(usb1_common_resources),
+ .resource = usb1_common_resources,
};
/* LCDC */
@@ -428,16 +421,90 @@ static struct i2c_board_info ts_i2c_clients = {
.irq = IRQ0,
};
+/* SHDI0 */
+static void sdhi0_set_pwr(struct platform_device *pdev, int state)
+{
+ gpio_set_value(GPIO_PTB6, state);
+}
+
+static struct sh_mobile_sdhi_info sdhi0_info = {
+ .set_pwr = sdhi0_set_pwr,
+};
+
+static struct resource sdhi0_resources[] = {
+ [0] = {
+ .name = "SDHI0",
+ .start = 0x04ce0000,
+ .end = 0x04ce01ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 101,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device sdhi0_device = {
+ .name = "sh_mobile_sdhi",
+ .num_resources = ARRAY_SIZE(sdhi0_resources),
+ .resource = sdhi0_resources,
+ .id = 0,
+ .dev = {
+ .platform_data = &sdhi0_info,
+ },
+ .archdata = {
+ .hwblk_id = HWBLK_SDHI0,
+ },
+};
+
+/* SHDI1 */
+static void sdhi1_set_pwr(struct platform_device *pdev, int state)
+{
+ gpio_set_value(GPIO_PTB7, state);
+}
+
+static struct sh_mobile_sdhi_info sdhi1_info = {
+ .set_pwr = sdhi1_set_pwr,
+};
+
+static struct resource sdhi1_resources[] = {
+ [0] = {
+ .name = "SDHI1",
+ .start = 0x04cf0000,
+ .end = 0x04cf01ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 24,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device sdhi1_device = {
+ .name = "sh_mobile_sdhi",
+ .num_resources = ARRAY_SIZE(sdhi1_resources),
+ .resource = sdhi1_resources,
+ .id = 1,
+ .dev = {
+ .platform_data = &sdhi1_info,
+ },
+ .archdata = {
+ .hwblk_id = HWBLK_SDHI1,
+ },
+};
+
static struct platform_device *ecovec_devices[] __initdata = {
&heartbeat_device,
&nor_flash_device,
&sh_eth_device,
&usb0_host_device,
- &usb1_host_device, /* USB1 host support */
+ &usb1_common_device,
&lcdc_device,
&ceu0_device,
&ceu1_device,
&keysc_device,
+ &sdhi0_device,
+ &sdhi1_device,
};
#define EEPROM_ADDR 0x50
@@ -466,12 +533,9 @@ static u8 mac_read(struct i2c_adapter *a, u8 command)
return buf;
}
-#define MAC_LEN 6
-static void __init sh_eth_init(void)
+static void __init sh_eth_init(struct sh_eth_plat_data *pd)
{
struct i2c_adapter *a = i2c_get_adapter(1);
- struct clk *eth_clk;
- u8 mac[MAC_LEN];
int i;
if (!a) {
@@ -479,39 +543,30 @@ static void __init sh_eth_init(void)
return;
}
- eth_clk = clk_get(NULL, "eth0");
- if (!eth_clk) {
- pr_err("can not get eth0 clk\n");
- return;
- }
-
/* read MAC address frome EEPROM */
- for (i = 0; i < MAC_LEN; i++) {
- mac[i] = mac_read(a, 0x10 + i);
+ for (i = 0; i < sizeof(pd->mac_addr); i++) {
+ pd->mac_addr[i] = mac_read(a, 0x10 + i);
msleep(10);
}
-
- /* clock enable */
- clk_enable(eth_clk);
-
- /* reset sh-eth */
- ctrl_outl(0x1, SH_ETH_ADDR + 0x0);
-
- /* set MAC addr */
- ctrl_outl((mac[0] << 24) |
- (mac[1] << 16) |
- (mac[2] << 8) |
- (mac[3] << 0), SH_ETH_MAHR);
- ctrl_outl((mac[4] << 8) |
- (mac[5] << 0), SH_ETH_MALR);
-
- clk_put(eth_clk);
}
#define PORT_HIZA 0xA4050158
#define IODRIVEA 0xA405018A
+
+extern char ecovec24_sdram_enter_start;
+extern char ecovec24_sdram_enter_end;
+extern char ecovec24_sdram_leave_start;
+extern char ecovec24_sdram_leave_end;
+
static int __init arch_setup(void)
{
+ /* register board specific self-refresh code */
+ sh_mobile_register_self_refresh(SUSP_SH_STANDBY | SUSP_SH_SF,
+ &ecovec24_sdram_enter_start,
+ &ecovec24_sdram_enter_end,
+ &ecovec24_sdram_leave_start,
+ &ecovec24_sdram_leave_end);
+
/* enable STATUS0, STATUS2 and PDSTATUS */
gpio_request(GPIO_FN_STATUS0, NULL);
gpio_request(GPIO_FN_STATUS2, NULL);
@@ -561,6 +616,14 @@ static int __init arch_setup(void)
ctrl_outw(0x0600, 0xa40501d4);
ctrl_outw(0x0600, 0xa4050192);
+ if (gpio_get_value(GPIO_PTB3)) {
+ printk(KERN_INFO "USB1 function is selected\n");
+ usb1_common_device.name = "r8a66597_udc";
+ } else {
+ printk(KERN_INFO "USB1 host is selected\n");
+ usb1_common_device.name = "r8a66597_hcd";
+ }
+
/* enable LCDC */
gpio_request(GPIO_FN_LCDD23, NULL);
gpio_request(GPIO_FN_LCDD22, NULL);
@@ -603,8 +666,8 @@ static int __init arch_setup(void)
gpio_direction_output(GPIO_PTR1, 0);
gpio_direction_output(GPIO_PTA2, 0);
- /* I/O buffer drive ability is low */
- ctrl_outw((ctrl_inw(IODRIVEA) & ~0x00c0) | 0x0040 , IODRIVEA);
+ /* I/O buffer drive ability is high */
+ ctrl_outw((ctrl_inw(IODRIVEA) & ~0x00c0) | 0x0080 , IODRIVEA);
if (gpio_get_value(GPIO_PTE6)) {
/* DVI */
@@ -710,6 +773,33 @@ static int __init arch_setup(void)
gpio_direction_input(GPIO_PTR5);
gpio_direction_input(GPIO_PTR6);
+ /* enable SDHI0 (needs DS2.4 set to ON) */
+ gpio_request(GPIO_FN_SDHI0CD, NULL);
+ gpio_request(GPIO_FN_SDHI0WP, NULL);
+ gpio_request(GPIO_FN_SDHI0CMD, NULL);
+ gpio_request(GPIO_FN_SDHI0CLK, NULL);
+ gpio_request(GPIO_FN_SDHI0D3, NULL);
+ gpio_request(GPIO_FN_SDHI0D2, NULL);
+ gpio_request(GPIO_FN_SDHI0D1, NULL);
+ gpio_request(GPIO_FN_SDHI0D0, NULL);
+ gpio_request(GPIO_PTB6, NULL);
+ gpio_direction_output(GPIO_PTB6, 0);
+
+ /* enable SDHI1 (needs DS2.6,7 set to ON,OFF) */
+ gpio_request(GPIO_FN_SDHI1CD, NULL);
+ gpio_request(GPIO_FN_SDHI1WP, NULL);
+ gpio_request(GPIO_FN_SDHI1CMD, NULL);
+ gpio_request(GPIO_FN_SDHI1CLK, NULL);
+ gpio_request(GPIO_FN_SDHI1D3, NULL);
+ gpio_request(GPIO_FN_SDHI1D2, NULL);
+ gpio_request(GPIO_FN_SDHI1D1, NULL);
+ gpio_request(GPIO_FN_SDHI1D0, NULL);
+ gpio_request(GPIO_PTB7, NULL);
+ gpio_direction_output(GPIO_PTB7, 0);
+
+ /* I/O buffer drive ability is high for SDHI1 */
+ ctrl_outw((ctrl_inw(IODRIVEA) & ~0x3000) | 0x2000 , IODRIVEA);
+
/* enable I2C device */
i2c_register_board_info(1, i2c1_devices,
ARRAY_SIZE(i2c1_devices));
@@ -721,12 +811,11 @@ arch_initcall(arch_setup);
static int __init devices_setup(void)
{
- sh_eth_init();
+ sh_eth_init(&sh_eth_plat);
return 0;
}
device_initcall(devices_setup);
-
static struct sh_machine_vector mv_ecovec __initmv = {
.mv_name = "R0P7724 (EcoVec)",
};
diff --git a/arch/sh/boards/mach-highlander/setup.c b/arch/sh/boards/mach-highlander/setup.c
index 566e69d..f663c14 100644
--- a/arch/sh/boards/mach-highlander/setup.c
+++ b/arch/sh/boards/mach-highlander/setup.c
@@ -384,7 +384,7 @@ static unsigned char irl2irq[HL_NR_IRL];
static int highlander_irq_demux(int irq)
{
- if (irq >= HL_NR_IRL || !irl2irq[irq])
+ if (irq >= HL_NR_IRL || irq < 0 || !irl2irq[irq])
return irq;
return irl2irq[irq];
diff --git a/arch/sh/boards/mach-kfr2r09/Makefile b/arch/sh/boards/mach-kfr2r09/Makefile
index 5d58678..4e577a3 100644
--- a/arch/sh/boards/mach-kfr2r09/Makefile
+++ b/arch/sh/boards/mach-kfr2r09/Makefile
@@ -1,2 +1,2 @@
-obj-y := setup.o
+obj-y := setup.o sdram.o
obj-$(CONFIG_FB_SH_MOBILE_LCDC) += lcd_wqvga.o
diff --git a/arch/sh/boards/mach-kfr2r09/sdram.S b/arch/sh/boards/mach-kfr2r09/sdram.S
new file mode 100644
index 0000000..0c9f55b
--- /dev/null
+++ b/arch/sh/boards/mach-kfr2r09/sdram.S
@@ -0,0 +1,80 @@
+/*
+ * KFR2R09 sdram self/auto-refresh setup code
+ *
+ * Copyright (C) 2009 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/sys.h>
+#include <linux/errno.h>
+#include <linux/linkage.h>
+#include <asm/asm-offsets.h>
+#include <asm/suspend.h>
+#include <asm/romimage-macros.h>
+
+/* code to enter and leave self-refresh. must be self-contained.
+ * this code will be copied to on-chip memory and executed from there.
+ */
+ .balign 4
+ENTRY(kfr2r09_sdram_enter_start)
+
+ /* DBSC: put memory in self-refresh mode */
+
+ ED 0xFD000010, 0x00000000 /* DBEN */
+ ED 0xFD000040, 0x00000000 /* DBRFPDN0 */
+ ED 0xFD000014, 0x00000002 /* DBCMDCNT (PALL) */
+ ED 0xFD000014, 0x00000004 /* DBCMDCNT (REF) */
+ ED 0xFD000040, 0x00000001 /* DBRFPDN0 */
+
+ rts
+ nop
+
+ENTRY(kfr2r09_sdram_enter_end)
+
+ .balign 4
+ENTRY(kfr2r09_sdram_leave_start)
+
+ /* DBSC: put memory in auto-refresh mode */
+
+ mov.l @(SH_SLEEP_MODE, r5), r0
+ tst #SUSP_SH_RSTANDBY, r0
+ bf resume_rstandby
+
+ ED 0xFD000040, 0x00000000 /* DBRFPDN0 */
+ WAIT 1
+ ED 0xFD000014, 0x00000002 /* DBCMDCNT (PALL) */
+ ED 0xFD000014, 0x00000004 /* DBCMDCNT (REF) */
+ ED 0xFD000010, 0x00000001 /* DBEN */
+ ED 0xFD000040, 0x00010000 /* DBRFPDN0 */
+
+ rts
+ nop
+
+resume_rstandby:
+
+ /* DBSC: re-initialize and put in auto-refresh */
+
+ ED 0xFD000108, 0x40000301 /* DBPDCNT0 */
+ ED 0xFD000020, 0x011B0002 /* DBCONF */
+ ED 0xFD000030, 0x03060E02 /* DBTR0 */
+ ED 0xFD000034, 0x01020102 /* DBTR1 */
+ ED 0xFD000038, 0x01090406 /* DBTR2 */
+ ED 0xFD000008, 0x00000004 /* DBKIND */
+ ED 0xFD000040, 0x00000001 /* DBRFPDN0 */
+ ED 0xFD000040, 0x00000000 /* DBRFPDN0 */
+ ED 0xFD000018, 0x00000001 /* DBCKECNT */
+ WAIT 1
+ ED 0xFD000010, 0x00000001 /* DBEN */
+ ED 0xFD000044, 0x000004AF /* DBRFPDN1 */
+ ED 0xFD000048, 0x20CF0037 /* DBRFPDN2 */
+ ED 0xFD000014, 0x00000004 /* DBCMDCNT (REF) */
+ ED 0xFD000108, 0x40000300 /* DBPDCNT0 */
+ ED 0xFD000040, 0x00010000 /* DBRFPDN0 */
+
+ rts
+ nop
+
+ENTRY(kfr2r09_sdram_leave_end)
diff --git a/arch/sh/boards/mach-kfr2r09/setup.c b/arch/sh/boards/mach-kfr2r09/setup.c
index c08d33f..87438d6 100644
--- a/arch/sh/boards/mach-kfr2r09/setup.c
+++ b/arch/sh/boards/mach-kfr2r09/setup.c
@@ -16,13 +16,16 @@
#include <linux/clk.h>
#include <linux/gpio.h>
#include <linux/input.h>
+#include <linux/input/sh_keysc.h>
#include <linux/i2c.h>
#include <linux/usb/r8a66597.h>
+#include <media/soc_camera.h>
+#include <media/sh_mobile_ceu.h>
#include <video/sh_mobile_lcdc.h>
+#include <asm/suspend.h>
#include <asm/clock.h>
#include <asm/machvec.h>
#include <asm/io.h>
-#include <asm/sh_keysc.h>
#include <cpu/sh7724.h>
#include <mach/kfr2r09.h>
@@ -212,11 +215,154 @@ static struct platform_device kfr2r09_usb0_gadget_device = {
.resource = kfr2r09_usb0_gadget_resources,
};
+static struct sh_mobile_ceu_info sh_mobile_ceu_info = {
+ .flags = SH_CEU_FLAG_USE_8BIT_BUS,
+};
+
+static struct resource kfr2r09_ceu_resources[] = {
+ [0] = {
+ .name = "CEU",
+ .start = 0xfe910000,
+ .end = 0xfe91009f,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 52,
+ .end = 52,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ /* place holder for contiguous memory */
+ },
+};
+
+static struct platform_device kfr2r09_ceu_device = {
+ .name = "sh_mobile_ceu",
+ .id = 0, /* "ceu0" clock */
+ .num_resources = ARRAY_SIZE(kfr2r09_ceu_resources),
+ .resource = kfr2r09_ceu_resources,
+ .dev = {
+ .platform_data = &sh_mobile_ceu_info,
+ },
+ .archdata = {
+ .hwblk_id = HWBLK_CEU0,
+ },
+};
+
+static struct i2c_board_info kfr2r09_i2c_camera = {
+ I2C_BOARD_INFO("rj54n1cb0c", 0x50),
+};
+
+static struct clk *camera_clk;
+
+#define DRVCRB 0xA405018C
+static int camera_power(struct device *dev, int mode)
+{
+ int ret;
+
+ if (mode) {
+ long rate;
+
+ camera_clk = clk_get(NULL, "video_clk");
+ if (IS_ERR(camera_clk))
+ return PTR_ERR(camera_clk);
+
+ /* set VIO_CKO clock to 25MHz */
+ rate = clk_round_rate(camera_clk, 25000000);
+ ret = clk_set_rate(camera_clk, rate);
+ if (ret < 0)
+ goto eclkrate;
+
+ /* set DRVCRB
+ *
+ * use 1.8 V for VccQ_VIO
+ * use 2.85V for VccQ_SR
+ */
+ ctrl_outw((ctrl_inw(DRVCRB) & ~0x0003) | 0x0001, DRVCRB);
+
+ /* reset clear */
+ ret = gpio_request(GPIO_PTB4, NULL);
+ if (ret < 0)
+ goto eptb4;
+ ret = gpio_request(GPIO_PTB7, NULL);
+ if (ret < 0)
+ goto eptb7;
+
+ ret = gpio_direction_output(GPIO_PTB4, 1);
+ if (!ret)
+ ret = gpio_direction_output(GPIO_PTB7, 1);
+ if (ret < 0)
+ goto egpioout;
+ msleep(1);
+
+ ret = clk_enable(camera_clk); /* start VIO_CKO */
+ if (ret < 0)
+ goto eclkon;
+
+ return 0;
+ }
+
+ ret = 0;
+
+ clk_disable(camera_clk);
+eclkon:
+ gpio_set_value(GPIO_PTB7, 0);
+egpioout:
+ gpio_set_value(GPIO_PTB4, 0);
+ gpio_free(GPIO_PTB7);
+eptb7:
+ gpio_free(GPIO_PTB4);
+eptb4:
+eclkrate:
+ clk_put(camera_clk);
+ return ret;
+}
+
+static struct soc_camera_link rj54n1_link = {
+ .power = camera_power,
+ .board_info = &kfr2r09_i2c_camera,
+ .i2c_adapter_id = 1,
+ .module_name = "rj54n1cb0c",
+};
+
+static struct platform_device kfr2r09_camera = {
+ .name = "soc-camera-pdrv",
+ .id = 0,
+ .dev = {
+ .platform_data = &rj54n1_link,
+ },
+};
+
+static struct resource kfr2r09_sh_sdhi0_resources[] = {
+ [0] = {
+ .name = "SDHI0",
+ .start = 0x04ce0000,
+ .end = 0x04ce01ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 101,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device kfr2r09_sh_sdhi0_device = {
+ .name = "sh_mobile_sdhi",
+ .num_resources = ARRAY_SIZE(kfr2r09_sh_sdhi0_resources),
+ .resource = kfr2r09_sh_sdhi0_resources,
+ .archdata = {
+ .hwblk_id = HWBLK_SDHI0,
+ },
+};
+
static struct platform_device *kfr2r09_devices[] __initdata = {
&kfr2r09_nor_flash_device,
&kfr2r09_nand_flash_device,
&kfr2r09_sh_keysc_device,
&kfr2r09_sh_lcdc_device,
+ &kfr2r09_ceu_device,
+ &kfr2r09_camera,
+ &kfr2r09_sh_sdhi0_device,
};
#define BSC_CS0BCR 0xfec10004
@@ -268,11 +414,59 @@ static int kfr2r09_usb0_gadget_i2c_setup(void)
return 0;
}
+
+static int kfr2r09_serial_i2c_setup(void)
+{
+ struct i2c_adapter *a;
+ struct i2c_msg msg;
+ unsigned char buf[2];
+ int ret;
+
+ a = i2c_get_adapter(0);
+ if (!a)
+ return -ENODEV;
+
+ /* set bit 6 (the 7th bit) of chip at 0x09, register 0x13 */
+ buf[0] = 0x13;
+ msg.addr = 0x09;
+ msg.buf = buf;
+ msg.len = 1;
+ msg.flags = 0;
+ ret = i2c_transfer(a, &msg, 1);
+ if (ret != 1)
+ return -ENODEV;
+
+ buf[0] = 0;
+ msg.addr = 0x09;
+ msg.buf = buf;
+ msg.len = 1;
+ msg.flags = I2C_M_RD;
+ ret = i2c_transfer(a, &msg, 1);
+ if (ret != 1)
+ return -ENODEV;
+
+ buf[1] = buf[0] | (1 << 6);
+ buf[0] = 0x13;
+ msg.addr = 0x09;
+ msg.buf = buf;
+ msg.len = 2;
+ msg.flags = 0;
+ ret = i2c_transfer(a, &msg, 1);
+ if (ret != 1)
+ return -ENODEV;
+
+ return 0;
+}
#else
static int kfr2r09_usb0_gadget_i2c_setup(void)
{
return -ENODEV;
}
+
+static int kfr2r09_serial_i2c_setup(void)
+{
+ return -ENODEV;
+}
#endif
static int kfr2r09_usb0_gadget_setup(void)
@@ -299,11 +493,27 @@ static int kfr2r09_usb0_gadget_setup(void)
return 0;
}
+extern char kfr2r09_sdram_enter_start;
+extern char kfr2r09_sdram_enter_end;
+extern char kfr2r09_sdram_leave_start;
+extern char kfr2r09_sdram_leave_end;
+
static int __init kfr2r09_devices_setup(void)
{
+ /* register board specific self-refresh code */
+ sh_mobile_register_self_refresh(SUSP_SH_STANDBY | SUSP_SH_SF |
+ SUSP_SH_RSTANDBY,
+ &kfr2r09_sdram_enter_start,
+ &kfr2r09_sdram_enter_end,
+ &kfr2r09_sdram_leave_start,
+ &kfr2r09_sdram_leave_end);
+
/* enable SCIF1 serial port for YC401 console support */
gpio_request(GPIO_FN_SCIF1_RXD, NULL);
gpio_request(GPIO_FN_SCIF1_TXD, NULL);
+ kfr2r09_serial_i2c_setup(); /* ECONTMSK(bit6=L10ONEN) set 1 */
+ gpio_request(GPIO_PTG3, NULL); /* HPON_ON */
+ gpio_direction_output(GPIO_PTG3, 1); /* HPON_ON = H */
/* setup NOR flash at CS0 */
ctrl_outl(0x36db0400, BSC_CS0BCR);
@@ -361,6 +571,32 @@ static int __init kfr2r09_devices_setup(void)
if (kfr2r09_usb0_gadget_setup() == 0)
platform_device_register(&kfr2r09_usb0_gadget_device);
+ /* CEU */
+ gpio_request(GPIO_FN_VIO_CKO, NULL);
+ gpio_request(GPIO_FN_VIO0_CLK, NULL);
+ gpio_request(GPIO_FN_VIO0_VD, NULL);
+ gpio_request(GPIO_FN_VIO0_HD, NULL);
+ gpio_request(GPIO_FN_VIO0_FLD, NULL);
+ gpio_request(GPIO_FN_VIO0_D7, NULL);
+ gpio_request(GPIO_FN_VIO0_D6, NULL);
+ gpio_request(GPIO_FN_VIO0_D5, NULL);
+ gpio_request(GPIO_FN_VIO0_D4, NULL);
+ gpio_request(GPIO_FN_VIO0_D3, NULL);
+ gpio_request(GPIO_FN_VIO0_D2, NULL);
+ gpio_request(GPIO_FN_VIO0_D1, NULL);
+ gpio_request(GPIO_FN_VIO0_D0, NULL);
+
+ platform_resource_setup_memory(&kfr2r09_ceu_device, "ceu", 4 << 20);
+
+ /* SDHI0 connected to yc304 */
+ gpio_request(GPIO_FN_SDHI0CD, NULL);
+ gpio_request(GPIO_FN_SDHI0D3, NULL);
+ gpio_request(GPIO_FN_SDHI0D2, NULL);
+ gpio_request(GPIO_FN_SDHI0D1, NULL);
+ gpio_request(GPIO_FN_SDHI0D0, NULL);
+ gpio_request(GPIO_FN_SDHI0CMD, NULL);
+ gpio_request(GPIO_FN_SDHI0CLK, NULL);
+
return platform_add_devices(kfr2r09_devices,
ARRAY_SIZE(kfr2r09_devices));
}
diff --git a/arch/sh/boards/mach-migor/Makefile b/arch/sh/boards/mach-migor/Makefile
index 5f231dd..4601a89 100644
--- a/arch/sh/boards/mach-migor/Makefile
+++ b/arch/sh/boards/mach-migor/Makefile
@@ -1,2 +1,2 @@
-obj-y := setup.o
+obj-y := setup.o sdram.o
obj-$(CONFIG_SH_MIGOR_QVGA) += lcd_qvga.o
diff --git a/arch/sh/boards/mach-migor/sdram.S b/arch/sh/boards/mach-migor/sdram.S
new file mode 100644
index 0000000..614aa3a
--- /dev/null
+++ b/arch/sh/boards/mach-migor/sdram.S
@@ -0,0 +1,69 @@
+/*
+ * Migo-R sdram self/auto-refresh setup code
+ *
+ * Copyright (C) 2009 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/sys.h>
+#include <linux/errno.h>
+#include <linux/linkage.h>
+#include <asm/asm-offsets.h>
+#include <asm/suspend.h>
+#include <asm/romimage-macros.h>
+
+/* code to enter and leave self-refresh. must be self-contained.
+ * this code will be copied to on-chip memory and executed from there.
+ */
+ .balign 4
+ENTRY(migor_sdram_enter_start)
+
+ /* SBSC: disable power down and put in self-refresh mode */
+ mov.l 1f, r4
+ mov.l 2f, r1
+ mov.l @r4, r2
+ or r1, r2
+ mov.l 3f, r3
+ and r3, r2
+ mov.l r2, @r4
+
+ rts
+ nop
+
+ .balign 4
+1: .long 0xfe400008 /* SDCR0 */
+2: .long 0x00000400
+3: .long 0xffff7fff
+ENTRY(migor_sdram_enter_end)
+
+ .balign 4
+ENTRY(migor_sdram_leave_start)
+
+ /* SBSC: set auto-refresh mode */
+ mov.l 1f, r4
+ mov.l @r4, r0
+ mov.l 4f, r1
+ and r1, r0
+ mov.l r0, @r4
+ mov.l 6f, r4
+ mov.l 8f, r0
+ mov.l @r4, r1
+ mov #-1, r4
+ add r4, r1
+ or r1, r0
+ mov.l 7f, r1
+ mov.l r0, @r1
+
+ rts
+ nop
+
+ .balign 4
+1: .long 0xfe400008 /* SDCR0 */
+4: .long 0xfffffbff
+6: .long 0xfe40001c /* RTCOR */
+7: .long 0xfe400018 /* RTCNT */
+8: .long 0xa55a0000
+ENTRY(migor_sdram_leave_end)
diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c
index 6ed1fd3..9099b6d 100644
--- a/arch/sh/boards/mach-migor/setup.c
+++ b/arch/sh/boards/mach-migor/setup.c
@@ -11,6 +11,7 @@
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/input.h>
+#include <linux/input/sh_keysc.h>
#include <linux/mtd/physmap.h>
#include <linux/mtd/nand.h>
#include <linux/i2c.h>
@@ -18,8 +19,6 @@
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/gpio.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/spi_gpio.h>
#include <video/sh_mobile_lcdc.h>
#include <media/sh_mobile_ceu.h>
#include <media/ov772x.h>
@@ -27,7 +26,7 @@
#include <asm/clock.h>
#include <asm/machvec.h>
#include <asm/io.h>
-#include <asm/sh_keysc.h>
+#include <asm/suspend.h>
#include <mach/migor.h>
#include <cpu/sh7722.h>
@@ -390,17 +389,25 @@ static struct platform_device migor_ceu_device = {
},
};
-struct spi_gpio_platform_data sdcard_cn9_platform_data = {
- .sck = GPIO_PTD0,
- .mosi = GPIO_PTD1,
- .miso = GPIO_PTD2,
- .num_chipselect = 1,
+static struct resource sdhi_cn9_resources[] = {
+ [0] = {
+ .name = "SDHI",
+ .start = 0x04ce0000,
+ .end = 0x04ce01ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 101,
+ .flags = IORESOURCE_IRQ,
+ },
};
-static struct platform_device sdcard_cn9_device = {
- .name = "spi_gpio",
- .dev = {
- .platform_data = &sdcard_cn9_platform_data,
+static struct platform_device sdhi_cn9_device = {
+ .name = "sh_mobile_sdhi",
+ .num_resources = ARRAY_SIZE(sdhi_cn9_resources),
+ .resource = sdhi_cn9_resources,
+ .archdata = {
+ .hwblk_id = HWBLK_SDHI,
},
};
@@ -467,23 +474,24 @@ static struct platform_device *migor_devices[] __initdata = {
&migor_ceu_device,
&migor_nor_flash_device,
&migor_nand_flash_device,
- &sdcard_cn9_device,
+ &sdhi_cn9_device,
&migor_camera[0],
&migor_camera[1],
};
-static struct spi_board_info migor_spi_devices[] = {
- {
- .modalias = "mmc_spi",
- .max_speed_hz = 5000000,
- .chip_select = 0,
- .controller_data = (void *) GPIO_PTD5,
- },
-};
+extern char migor_sdram_enter_start;
+extern char migor_sdram_enter_end;
+extern char migor_sdram_leave_start;
+extern char migor_sdram_leave_end;
static int __init migor_devices_setup(void)
{
-
+ /* register board specific self-refresh code */
+ sh_mobile_register_self_refresh(SUSP_SH_STANDBY | SUSP_SH_SF,
+ &migor_sdram_enter_start,
+ &migor_sdram_enter_end,
+ &migor_sdram_leave_start,
+ &migor_sdram_leave_end);
#ifdef CONFIG_PM
/* Let D11 LED show STATUS0 */
gpio_request(GPIO_FN_STATUS0, NULL);
@@ -525,6 +533,16 @@ static int __init migor_devices_setup(void)
gpio_request(GPIO_PTA1, NULL);
gpio_direction_input(GPIO_PTA1);
+ /* SDHI */
+ gpio_request(GPIO_FN_SDHICD, NULL);
+ gpio_request(GPIO_FN_SDHIWP, NULL);
+ gpio_request(GPIO_FN_SDHID3, NULL);
+ gpio_request(GPIO_FN_SDHID2, NULL);
+ gpio_request(GPIO_FN_SDHID1, NULL);
+ gpio_request(GPIO_FN_SDHID0, NULL);
+ gpio_request(GPIO_FN_SDHICMD, NULL);
+ gpio_request(GPIO_FN_SDHICLK, NULL);
+
/* Touch Panel */
gpio_request(GPIO_FN_IRQ6, NULL);
@@ -612,9 +630,6 @@ static int __init migor_devices_setup(void)
i2c_register_board_info(0, migor_i2c_devices,
ARRAY_SIZE(migor_i2c_devices));
- spi_register_board_info(migor_spi_devices,
- ARRAY_SIZE(migor_spi_devices));
-
return platform_add_devices(migor_devices, ARRAY_SIZE(migor_devices));
}
arch_initcall(migor_devices_setup);
diff --git a/arch/sh/boards/mach-r2d/irq.c b/arch/sh/boards/mach-r2d/irq.c
index c70fece..78d7b27 100644
--- a/arch/sh/boards/mach-r2d/irq.c
+++ b/arch/sh/boards/mach-r2d/irq.c
@@ -116,7 +116,7 @@ static unsigned char irl2irq[R2D_NR_IRL];
int rts7751r2d_irq_demux(int irq)
{
- if (irq >= R2D_NR_IRL || !irl2irq[irq])
+ if (irq >= R2D_NR_IRL || irq < 0 || !irl2irq[irq])
return irq;
return irl2irq[irq];
diff --git a/arch/sh/boards/mach-se/7722/irq.c b/arch/sh/boards/mach-se/7722/irq.c
index 02d21a3..4eb31ac 100644
--- a/arch/sh/boards/mach-se/7722/irq.c
+++ b/arch/sh/boards/mach-se/7722/irq.c
@@ -16,15 +16,17 @@
#include <asm/io.h>
#include <mach-se/mach/se7722.h>
+unsigned int se7722_fpga_irq[SE7722_FPGA_IRQ_NR] = { 0, };
+
static void disable_se7722_irq(unsigned int irq)
{
- unsigned int bit = irq - SE7722_FPGA_IRQ_BASE;
+ unsigned int bit = (unsigned int)get_irq_chip_data(irq);
ctrl_outw(ctrl_inw(IRQ01_MASK) | 1 << bit, IRQ01_MASK);
}
static void enable_se7722_irq(unsigned int irq)
{
- unsigned int bit = irq - SE7722_FPGA_IRQ_BASE;
+ unsigned int bit = (unsigned int)get_irq_chip_data(irq);
ctrl_outw(ctrl_inw(IRQ01_MASK) & ~(1 << bit), IRQ01_MASK);
}
@@ -38,18 +40,15 @@ static struct irq_chip se7722_irq_chip __read_mostly = {
static void se7722_irq_demux(unsigned int irq, struct irq_desc *desc)
{
unsigned short intv = ctrl_inw(IRQ01_STS);
- struct irq_desc *ext_desc;
- unsigned int ext_irq = SE7722_FPGA_IRQ_BASE;
+ unsigned int ext_irq = 0;
intv &= (1 << SE7722_FPGA_IRQ_NR) - 1;
- while (intv) {
- if (intv & 1) {
- ext_desc = irq_desc + ext_irq;
- handle_level_irq(ext_irq, ext_desc);
- }
- intv >>= 1;
- ext_irq++;
+ for (; intv; intv >>= 1, ext_irq++) {
+ if (!(intv & 1))
+ continue;
+
+ generic_handle_irq(se7722_fpga_irq[ext_irq]);
}
}
@@ -63,11 +62,18 @@ void __init init_se7722_IRQ(void)
ctrl_outw(0, IRQ01_MASK); /* disable all irqs */
ctrl_outw(0x2000, 0xb03fffec); /* mrshpc irq enable */
- for (i = 0; i < SE7722_FPGA_IRQ_NR; i++)
- set_irq_chip_and_handler_name(SE7722_FPGA_IRQ_BASE + i,
+ for (i = 0; i < SE7722_FPGA_IRQ_NR; i++) {
+ se7722_fpga_irq[i] = create_irq();
+ if (se7722_fpga_irq[i] < 0)
+ return;
+
+ set_irq_chip_and_handler_name(se7722_fpga_irq[i],
&se7722_irq_chip,
handle_level_irq, "level");
+ set_irq_chip_data(se7722_fpga_irq[i], (void *)i);
+ }
+
set_irq_chained_handler(IRQ0_IRQ, se7722_irq_demux);
set_irq_type(IRQ0_IRQ, IRQ_TYPE_LEVEL_LOW);
diff --git a/arch/sh/boards/mach-se/7722/setup.c b/arch/sh/boards/mach-se/7722/setup.c
index 3637407..b1cb942 100644
--- a/arch/sh/boards/mach-se/7722/setup.c
+++ b/arch/sh/boards/mach-se/7722/setup.c
@@ -14,6 +14,7 @@
#include <linux/platform_device.h>
#include <linux/ata_platform.h>
#include <linux/input.h>
+#include <linux/input/sh_keysc.h>
#include <linux/smc91x.h>
#include <mach-se/mach/se7722.h>
#include <mach-se/mach/mrshpc.h>
@@ -21,7 +22,6 @@
#include <asm/clock.h>
#include <asm/io.h>
#include <asm/heartbeat.h>
-#include <asm/sh_keysc.h>
#include <cpu/sh7722.h>
/* Heartbeat */
@@ -60,8 +60,7 @@ static struct resource smc91x_eth_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = SMC_IRQ,
- .end = SMC_IRQ,
+ /* Filled in later */
.flags = IORESOURCE_IRQ,
},
};
@@ -90,8 +89,7 @@ static struct resource cf_ide_resources[] = {
.flags = IORESOURCE_IO,
},
[2] = {
- .start = MRSHPC_IRQ0,
- .end = MRSHPC_IRQ0,
+ /* Filled in later */
.flags = IORESOURCE_IRQ,
},
};
@@ -153,6 +151,14 @@ static struct platform_device *se7722_devices[] __initdata = {
static int __init se7722_devices_setup(void)
{
mrshpc_setup_windows();
+
+ /* Wire-up dynamic vectors */
+ cf_ide_resources[2].start = cf_ide_resources[2].end =
+ se7722_fpga_irq[SE7722_FPGA_IRQ_MRSHPC0];
+
+ smc91x_eth_resources[1].start = smc91x_eth_resources[1].end =
+ se7722_fpga_irq[SE7722_FPGA_IRQ_SMC];
+
return platform_add_devices(se7722_devices, ARRAY_SIZE(se7722_devices));
}
device_initcall(se7722_devices_setup);
@@ -193,6 +199,5 @@ static void __init se7722_setup(char **cmdline_p)
static struct sh_machine_vector mv_se7722 __initmv = {
.mv_name = "Solution Engine 7722" ,
.mv_setup = se7722_setup ,
- .mv_nr_irqs = SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_NR,
.mv_init_irq = init_se7722_IRQ,
};
diff --git a/arch/sh/boards/mach-se/7724/Makefile b/arch/sh/boards/mach-se/7724/Makefile
index 349cbd6..a08b368 100644
--- a/arch/sh/boards/mach-se/7724/Makefile
+++ b/arch/sh/boards/mach-se/7724/Makefile
@@ -7,4 +7,4 @@
#
#
-obj-y := setup.o irq.o \ No newline at end of file
+obj-y := setup.o irq.o sdram.o
diff --git a/arch/sh/boards/mach-se/7724/sdram.S b/arch/sh/boards/mach-se/7724/sdram.S
new file mode 100644
index 0000000..9040167
--- /dev/null
+++ b/arch/sh/boards/mach-se/7724/sdram.S
@@ -0,0 +1,52 @@
+/*
+ * MS7724SE sdram self/auto-refresh setup code
+ *
+ * Copyright (C) 2009 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/sys.h>
+#include <linux/errno.h>
+#include <linux/linkage.h>
+#include <asm/asm-offsets.h>
+#include <asm/suspend.h>
+#include <asm/romimage-macros.h>
+
+/* code to enter and leave self-refresh. must be self-contained.
+ * this code will be copied to on-chip memory and executed from there.
+ */
+ .balign 4
+ENTRY(ms7724se_sdram_enter_start)
+
+ /* DBSC: put memory in self-refresh mode */
+
+ ED 0xFD000010, 0x00000000 /* DBEN */
+ ED 0xFD000040, 0x00000000 /* DBRFPDN0 */
+ ED 0xFD000014, 0x00000002 /* DBCMDCNT (PALL) */
+ ED 0xFD000014, 0x00000004 /* DBCMDCNT (REF) */
+ ED 0xFD000040, 0x00000001 /* DBRFPDN0 */
+
+ rts
+ nop
+
+ENTRY(ms7724se_sdram_enter_end)
+
+ .balign 4
+ENTRY(ms7724se_sdram_leave_start)
+
+ /* DBSC: put memory in auto-refresh mode */
+
+ ED 0xFD000040, 0x00000000 /* DBRFPDN0 */
+ WAIT 1
+ ED 0xFD000014, 0x00000002 /* DBCMDCNT (PALL) */
+ ED 0xFD000014, 0x00000004 /* DBCMDCNT (REF) */
+ ED 0xFD000010, 0x00000001 /* DBEN */
+ ED 0xFD000040, 0x00010000 /* DBRFPDN0 */
+
+ rts
+ nop
+
+ENTRY(ms7724se_sdram_leave_end)
diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c
index 0894bba..4b0f0c0 100644
--- a/arch/sh/boards/mach-se/7724/setup.c
+++ b/arch/sh/boards/mach-se/7724/setup.c
@@ -19,6 +19,7 @@
#include <linux/smc91x.h>
#include <linux/gpio.h>
#include <linux/input.h>
+#include <linux/input/sh_keysc.h>
#include <linux/usb/r8a66597.h>
#include <video/sh_mobile_lcdc.h>
#include <media/sh_mobile_ceu.h>
@@ -27,7 +28,7 @@
#include <asm/heartbeat.h>
#include <asm/sh_eth.h>
#include <asm/clock.h>
-#include <asm/sh_keysc.h>
+#include <asm/suspend.h>
#include <cpu/sh7724.h>
#include <mach-se/mach/se7724.h>
@@ -451,6 +452,52 @@ static struct platform_device sh7724_usb1_gadget_device = {
.resource = sh7724_usb1_gadget_resources,
};
+static struct resource sdhi0_cn7_resources[] = {
+ [0] = {
+ .name = "SDHI0",
+ .start = 0x04ce0000,
+ .end = 0x04ce01ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 101,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device sdhi0_cn7_device = {
+ .name = "sh_mobile_sdhi",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(sdhi0_cn7_resources),
+ .resource = sdhi0_cn7_resources,
+ .archdata = {
+ .hwblk_id = HWBLK_SDHI0,
+ },
+};
+
+static struct resource sdhi1_cn8_resources[] = {
+ [0] = {
+ .name = "SDHI1",
+ .start = 0x04cf0000,
+ .end = 0x04cf01ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 24,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device sdhi1_cn8_device = {
+ .name = "sh_mobile_sdhi",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(sdhi1_cn8_resources),
+ .resource = sdhi1_cn8_resources,
+ .archdata = {
+ .hwblk_id = HWBLK_SDHI1,
+ },
+};
+
static struct platform_device *ms7724se_devices[] __initdata = {
&heartbeat_device,
&smc91x_eth_device,
@@ -463,6 +510,8 @@ static struct platform_device *ms7724se_devices[] __initdata = {
&sh7724_usb0_host_device,
&sh7724_usb1_gadget_device,
&fsi_device,
+ &sdhi0_cn7_device,
+ &sdhi1_cn8_device,
};
#define EEPROM_OP 0xBA206000
@@ -487,7 +536,7 @@ static int __init sh_eth_is_eeprom_ready(void)
static void __init sh_eth_init(void)
{
int i;
- u16 mac[3];
+ u16 mac;
/* check EEPROM status */
if (!sh_eth_is_eeprom_ready())
@@ -501,16 +550,10 @@ static void __init sh_eth_init(void)
if (!sh_eth_is_eeprom_ready())
return;
- mac[i] = ctrl_inw(EEPROM_DATA);
- mac[i] = ((mac[i] & 0xFF) << 8) | (mac[i] >> 8); /* swap */
+ mac = ctrl_inw(EEPROM_DATA);
+ sh_eth_plat.mac_addr[i << 1] = mac & 0xff;
+ sh_eth_plat.mac_addr[(i << 1) + 1] = mac >> 8;
}
-
- /* reset sh-eth */
- ctrl_outl(0x1, SH_ETH_ADDR + 0x0);
-
- /* set MAC addr */
- ctrl_outl(((mac[0] << 16) | (mac[1])), SH_ETH_MAHR);
- ctrl_outl((mac[2]), SH_ETH_MALR);
}
#define SW4140 0xBA201000
@@ -527,11 +570,22 @@ static void __init sh_eth_init(void)
#define SW41_G 0x4000
#define SW41_H 0x8000
+extern char ms7724se_sdram_enter_start;
+extern char ms7724se_sdram_enter_end;
+extern char ms7724se_sdram_leave_start;
+extern char ms7724se_sdram_leave_end;
+
static int __init devices_setup(void)
{
u16 sw = ctrl_inw(SW4140); /* select camera, monitor */
struct clk *fsia_clk;
+ /* register board specific self-refresh code */
+ sh_mobile_register_self_refresh(SUSP_SH_STANDBY | SUSP_SH_SF,
+ &ms7724se_sdram_enter_start,
+ &ms7724se_sdram_enter_end,
+ &ms7724se_sdram_leave_start,
+ &ms7724se_sdram_leave_end);
/* Reset Release */
ctrl_outw(ctrl_inw(FPGA_OUT) &
~((1 << 1) | /* LAN */
@@ -701,6 +755,26 @@ static int __init devices_setup(void)
clk_set_rate(&fsimcka_clk, 11000);
clk_put(fsia_clk);
+ /* SDHI0 connected to cn7 */
+ gpio_request(GPIO_FN_SDHI0CD, NULL);
+ gpio_request(GPIO_FN_SDHI0WP, NULL);
+ gpio_request(GPIO_FN_SDHI0D3, NULL);
+ gpio_request(GPIO_FN_SDHI0D2, NULL);
+ gpio_request(GPIO_FN_SDHI0D1, NULL);
+ gpio_request(GPIO_FN_SDHI0D0, NULL);
+ gpio_request(GPIO_FN_SDHI0CMD, NULL);
+ gpio_request(GPIO_FN_SDHI0CLK, NULL);
+
+ /* SDHI1 connected to cn8 */
+ gpio_request(GPIO_FN_SDHI1CD, NULL);
+ gpio_request(GPIO_FN_SDHI1WP, NULL);
+ gpio_request(GPIO_FN_SDHI1D3, NULL);
+ gpio_request(GPIO_FN_SDHI1D2, NULL);
+ gpio_request(GPIO_FN_SDHI1D1, NULL);
+ gpio_request(GPIO_FN_SDHI1D0, NULL);
+ gpio_request(GPIO_FN_SDHI1CMD, NULL);
+ gpio_request(GPIO_FN_SDHI1CLK, NULL);
+
/*
* enable SH-Eth
*
diff --git a/arch/sh/boot/compressed/misc.c b/arch/sh/boot/compressed/misc.c
index fd56a71..b51b1fc 100644
--- a/arch/sh/boot/compressed/misc.c
+++ b/arch/sh/boot/compressed/misc.c
@@ -131,7 +131,7 @@ void decompress_kernel(void)
#ifdef CONFIG_SUPERH64
output_addr = (CONFIG_MEMORY_START + 0x2000);
#else
- output_addr = PHYSADDR((unsigned long)&_text+PAGE_SIZE);
+ output_addr = __pa((unsigned long)&_text+PAGE_SIZE);
#ifdef CONFIG_29BIT
output_addr |= P2SEG;
#endif
diff --git a/arch/sh/boot/romimage/Makefile b/arch/sh/boot/romimage/Makefile
index 5806eee..f473a24 100644
--- a/arch/sh/boot/romimage/Makefile
+++ b/arch/sh/boot/romimage/Makefile
@@ -4,16 +4,22 @@
# create an image suitable for burning to flash from zImage
#
-targets := vmlinux head.o
+targets := vmlinux head.o zeropage.bin piggy.o
OBJECTS = $(obj)/head.o
-LDFLAGS_vmlinux := --oformat $(ld-bfd) -Ttext 0 -e romstart
+LDFLAGS_vmlinux := --oformat $(ld-bfd) -Ttext 0 -e romstart \
+ -T $(obj)/../../kernel/vmlinux.lds
$(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o FORCE
$(call if_changed,ld)
@:
+OBJCOPYFLAGS += -j .empty_zero_page
+
+$(obj)/zeropage.bin: vmlinux FORCE
+ $(call if_changed,objcopy)
+
LDFLAGS_piggy.o := -r --format binary --oformat $(ld-bfd) -T
-$(obj)/piggy.o: $(obj)/vmlinux.scr arch/sh/boot/zImage FORCE
+$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/zeropage.bin arch/sh/boot/zImage FORCE
$(call if_changed,ld)
diff --git a/arch/sh/boot/romimage/head.S b/arch/sh/boot/romimage/head.S
index 219bc62..93e779a 100644
--- a/arch/sh/boot/romimage/head.S
+++ b/arch/sh/boot/romimage/head.S
@@ -5,6 +5,44 @@
*/
.text
+ #include <asm/page.h>
+
.global romstart
romstart:
+ /* include board specific setup code */
#include <mach/romimage.h>
+
+ /* copy the empty_zero_page contents to where vmlinux expects it */
+ mova empty_zero_page_src, r0
+ mov.l empty_zero_page_dst, r1
+ mov #(PAGE_SHIFT - 4), r4
+ mov #1, r3
+ shld r4, r3 /* r3 = PAGE_SIZE / 16 */
+
+1:
+ mov.l @r0, r4
+ mov.l @(4, r0), r5
+ mov.l @(8, r0), r6
+ mov.l @(12, r0), r7
+ add #16,r0
+ mov.l r4, @r1
+ mov.l r5, @(4, r1)
+ mov.l r6, @(8, r1)
+ mov.l r7, @(12, r1)
+ dt r3
+ add #16,r1
+ bf 1b
+
+ /* jump to the zImage entry point located after the zero page data */
+ mov #PAGE_SHIFT, r4
+ mov #1, r1
+ shld r4, r1
+ mova empty_zero_page_src, r0
+ add r1, r0
+ jmp @r0
+ nop
+
+ .align 2
+empty_zero_page_dst:
+ .long _text
+empty_zero_page_src:
diff --git a/arch/sh/drivers/dma/dma-sysfs.c b/arch/sh/drivers/dma/dma-sysfs.c
index 347ee11..1ee631d 100644
--- a/arch/sh/drivers/dma/dma-sysfs.c
+++ b/arch/sh/drivers/dma/dma-sysfs.c
@@ -13,7 +13,6 @@
#include <linux/init.h>
#include <linux/sysdev.h>
#include <linux/platform_device.h>
-#include <linux/module.h>
#include <linux/err.h>
#include <linux/string.h>
#include <asm/dma.h>
@@ -21,7 +20,6 @@
static struct sysdev_class dma_sysclass = {
.name = "dma",
};
-EXPORT_SYMBOL(dma_sysclass);
static ssize_t dma_show_devices(struct sys_device *dev,
struct sysdev_attribute *attr, char *buf)
diff --git a/arch/sh/drivers/pci/Kconfig b/arch/sh/drivers/pci/Kconfig
deleted file mode 100644
index e8db585..0000000
--- a/arch/sh/drivers/pci/Kconfig
+++ /dev/null
@@ -1,19 +0,0 @@
-config PCI
- bool "PCI support"
- depends on SYS_SUPPORTS_PCI
- 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
- your box. If you have PCI, say Y, otherwise N.
-
-config SH_PCIDMA_NONCOHERENT
- bool "Cache and PCI noncoherent"
- depends on PCI
- default y
- help
- Enable this option if your platform does not have a CPU cache which
- remains coherent with PCI DMA. It is safest to say 'Y', although you
- will see better performance if you can say 'N', because the PCI DMA
- code will not have to flush the CPU's caches. If you have a PCI host
- bridge integrated with your SH CPU, refer carefully to the chip specs
- to see if you can say 'N' here. Otherwise, leave it as 'Y'.
diff --git a/arch/sh/include/asm/addrspace.h b/arch/sh/include/asm/addrspace.h
index 80d4081..99d6b3e 100644
--- a/arch/sh/include/asm/addrspace.h
+++ b/arch/sh/include/asm/addrspace.h
@@ -28,9 +28,6 @@
/* Returns the privileged segment base of a given address */
#define PXSEG(a) (((unsigned long)(a)) & 0xe0000000)
-/* Returns the physical address of a PnSEG (n=1,2) address */
-#define PHYSADDR(a) (((unsigned long)(a)) & 0x1fffffff)
-
#if defined(CONFIG_29BIT) || defined(CONFIG_PMB_FIXED)
/*
* Map an address to a certain privileged segment
@@ -60,5 +57,11 @@
#define P3_ADDR_MAX P4SEG
#endif
+#ifndef __ASSEMBLY__
+#ifdef CONFIG_PMB
+extern int __in_29bit_mode(void);
+#endif /* CONFIG_PMB */
+#endif /* __ASSEMBLY__ */
+
#endif /* __KERNEL__ */
#endif /* __ASM_SH_ADDRSPACE_H */
diff --git a/arch/sh/include/asm/atomic.h b/arch/sh/include/asm/atomic.h
index e8e7813..b16388d 100644
--- a/arch/sh/include/asm/atomic.h
+++ b/arch/sh/include/asm/atomic.h
@@ -78,11 +78,10 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u)
#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
-/* Atomic operations are already serializing on SH */
-#define smp_mb__before_atomic_dec() barrier()
-#define smp_mb__after_atomic_dec() barrier()
-#define smp_mb__before_atomic_inc() barrier()
-#define smp_mb__after_atomic_inc() barrier()
+#define smp_mb__before_atomic_dec() smp_mb()
+#define smp_mb__after_atomic_dec() smp_mb()
+#define smp_mb__before_atomic_inc() smp_mb()
+#define smp_mb__after_atomic_inc() smp_mb()
#include <asm-generic/atomic-long.h>
#include <asm-generic/atomic64.h>
diff --git a/arch/sh/include/asm/bitops.h b/arch/sh/include/asm/bitops.h
index ebe595b..98511e4 100644
--- a/arch/sh/include/asm/bitops.h
+++ b/arch/sh/include/asm/bitops.h
@@ -26,8 +26,8 @@
/*
* clear_bit() doesn't provide any barrier for the compiler.
*/
-#define smp_mb__before_clear_bit() barrier()
-#define smp_mb__after_clear_bit() barrier()
+#define smp_mb__before_clear_bit() smp_mb()
+#define smp_mb__after_clear_bit() smp_mb()
#ifdef CONFIG_SUPERH32
static inline unsigned long ffz(unsigned long word)
diff --git a/arch/sh/include/asm/bugs.h b/arch/sh/include/asm/bugs.h
index 46260fc..02a19a1 100644
--- a/arch/sh/include/asm/bugs.h
+++ b/arch/sh/include/asm/bugs.h
@@ -14,11 +14,15 @@
#include <asm/processor.h>
+extern void select_idle_routine(void);
+
static void __init check_bugs(void)
{
extern unsigned long loops_per_jiffy;
char *p = &init_utsname()->machine[2]; /* "sh" */
+ select_idle_routine();
+
current_cpu_data.loops_per_jiffy = loops_per_jiffy;
switch (current_cpu_data.family) {
diff --git a/arch/sh/include/asm/dma-mapping.h b/arch/sh/include/asm/dma-mapping.h
index 69d56dd..87ced13 100644
--- a/arch/sh/include/asm/dma-mapping.h
+++ b/arch/sh/include/asm/dma-mapping.h
@@ -1,219 +1,108 @@
#ifndef __ASM_SH_DMA_MAPPING_H
#define __ASM_SH_DMA_MAPPING_H
-#include <linux/mm.h>
-#include <linux/scatterlist.h>
-#include <linux/dma-debug.h>
-#include <asm/cacheflush.h>
-#include <asm/io.h>
+extern struct dma_map_ops *dma_ops;
+extern void no_iommu_init(void);
+
+static inline struct dma_map_ops *get_dma_ops(struct device *dev)
+{
+ return dma_ops;
+}
+
#include <asm-generic/dma-coherent.h>
+#include <asm-generic/dma-mapping-common.h>
+
+static inline int dma_supported(struct device *dev, u64 mask)
+{
+ struct dma_map_ops *ops = get_dma_ops(dev);
-extern struct bus_type pci_bus_type;
+ if (ops->dma_supported)
+ return ops->dma_supported(dev, mask);
-#define dma_supported(dev, mask) (1)
+ return 1;
+}
static inline int dma_set_mask(struct device *dev, u64 mask)
{
+ struct dma_map_ops *ops = get_dma_ops(dev);
+
if (!dev->dma_mask || !dma_supported(dev, mask))
return -EIO;
+ if (ops->set_dma_mask)
+ return ops->set_dma_mask(dev, mask);
*dev->dma_mask = mask;
return 0;
}
-void *dma_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t flag);
-
-void dma_free_coherent(struct device *dev, size_t size,
- void *vaddr, dma_addr_t dma_handle);
-
void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
enum dma_data_direction dir);
#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
-#define dma_is_consistent(d, h) (1)
-
-static inline dma_addr_t dma_map_single(struct device *dev,
- void *ptr, size_t size,
- enum dma_data_direction dir)
-{
- dma_addr_t addr = virt_to_phys(ptr);
-
-#if defined(CONFIG_PCI) && !defined(CONFIG_SH_PCIDMA_NONCOHERENT)
- if (dev->bus == &pci_bus_type)
- return addr;
-#endif
- dma_cache_sync(dev, ptr, size, dir);
-
- debug_dma_map_page(dev, virt_to_page(ptr),
- (unsigned long)ptr & ~PAGE_MASK, size,
- dir, addr, true);
-
- return addr;
-}
-
-static inline void dma_unmap_single(struct device *dev, dma_addr_t addr,
- size_t size, enum dma_data_direction dir)
-{
- debug_dma_unmap_page(dev, addr, size, dir, true);
-}
-static inline int dma_map_sg(struct device *dev, struct scatterlist *sg,
- int nents, enum dma_data_direction dir)
-{
- int i;
-
- for (i = 0; i < nents; i++) {
-#if !defined(CONFIG_PCI) || defined(CONFIG_SH_PCIDMA_NONCOHERENT)
- dma_cache_sync(dev, sg_virt(&sg[i]), sg[i].length, dir);
+#ifdef CONFIG_DMA_COHERENT
+#define dma_is_consistent(d, h) (1)
+#else
+#define dma_is_consistent(d, h) (0)
#endif
- sg[i].dma_address = sg_phys(&sg[i]);
- sg[i].dma_length = sg[i].length;
- }
- debug_dma_map_sg(dev, sg, nents, i, dir);
-
- return nents;
-}
-
-static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
- int nents, enum dma_data_direction dir)
-{
- debug_dma_unmap_sg(dev, sg, nents, dir);
-}
-
-static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
- unsigned long offset, size_t size,
- enum dma_data_direction dir)
-{
- return dma_map_single(dev, page_address(page) + offset, size, dir);
-}
-
-static inline void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
- size_t size, enum dma_data_direction dir)
-{
- dma_unmap_single(dev, dma_address, size, dir);
-}
-
-static inline void __dma_sync_single(struct device *dev, dma_addr_t dma_handle,
- size_t size, enum dma_data_direction dir)
+static inline int dma_get_cache_alignment(void)
{
-#if defined(CONFIG_PCI) && !defined(CONFIG_SH_PCIDMA_NONCOHERENT)
- if (dev->bus == &pci_bus_type)
- return;
-#endif
- dma_cache_sync(dev, phys_to_virt(dma_handle), size, dir);
+ /*
+ * Each processor family will define its own L1_CACHE_SHIFT,
+ * L1_CACHE_BYTES wraps to this, so this is always safe.
+ */
+ return L1_CACHE_BYTES;
}
-static inline void dma_sync_single_range(struct device *dev,
- dma_addr_t dma_handle,
- unsigned long offset, size_t size,
- enum dma_data_direction dir)
+static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
{
-#if defined(CONFIG_PCI) && !defined(CONFIG_SH_PCIDMA_NONCOHERENT)
- if (dev->bus == &pci_bus_type)
- return;
-#endif
- dma_cache_sync(dev, phys_to_virt(dma_handle) + offset, size, dir);
-}
+ struct dma_map_ops *ops = get_dma_ops(dev);
-static inline void __dma_sync_sg(struct device *dev, struct scatterlist *sg,
- int nelems, enum dma_data_direction dir)
-{
- int i;
+ if (ops->mapping_error)
+ return ops->mapping_error(dev, dma_addr);
- for (i = 0; i < nelems; i++) {
-#if !defined(CONFIG_PCI) || defined(CONFIG_SH_PCIDMA_NONCOHERENT)
- dma_cache_sync(dev, sg_virt(&sg[i]), sg[i].length, dir);
-#endif
- sg[i].dma_address = sg_phys(&sg[i]);
- sg[i].dma_length = sg[i].length;
- }
+ return dma_addr == 0;
}
-static inline void dma_sync_single_for_cpu(struct device *dev,
- dma_addr_t dma_handle, size_t size,
- enum dma_data_direction dir)
+static inline void *dma_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t gfp)
{
- __dma_sync_single(dev, dma_handle, size, dir);
- debug_dma_sync_single_for_cpu(dev, dma_handle, size, dir);
-}
+ struct dma_map_ops *ops = get_dma_ops(dev);
+ void *memory;
-static inline void dma_sync_single_for_device(struct device *dev,
- dma_addr_t dma_handle,
- size_t size,
- enum dma_data_direction dir)
-{
- __dma_sync_single(dev, dma_handle, size, dir);
- debug_dma_sync_single_for_device(dev, dma_handle, size, dir);
-}
+ if (dma_alloc_from_coherent(dev, size, dma_handle, &memory))
+ return memory;
+ if (!ops->alloc_coherent)
+ return NULL;
-static inline void dma_sync_single_range_for_cpu(struct device *dev,
- dma_addr_t dma_handle,
- unsigned long offset,
- size_t size,
- enum dma_data_direction direction)
-{
- dma_sync_single_for_cpu(dev, dma_handle+offset, size, direction);
- debug_dma_sync_single_range_for_cpu(dev, dma_handle,
- offset, size, direction);
-}
+ memory = ops->alloc_coherent(dev, size, dma_handle, gfp);
+ debug_dma_alloc_coherent(dev, size, *dma_handle, memory);
-static inline void dma_sync_single_range_for_device(struct device *dev,
- dma_addr_t dma_handle,
- unsigned long offset,
- size_t size,
- enum dma_data_direction direction)
-{
- dma_sync_single_for_device(dev, dma_handle+offset, size, direction);
- debug_dma_sync_single_range_for_device(dev, dma_handle,
- offset, size, direction);
+ return memory;
}
-
-static inline void dma_sync_sg_for_cpu(struct device *dev,
- struct scatterlist *sg, int nelems,
- enum dma_data_direction dir)
+static inline void dma_free_coherent(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle)
{
- __dma_sync_sg(dev, sg, nelems, dir);
- debug_dma_sync_sg_for_cpu(dev, sg, nelems, dir);
-}
+ struct dma_map_ops *ops = get_dma_ops(dev);
-static inline void dma_sync_sg_for_device(struct device *dev,
- struct scatterlist *sg, int nelems,
- enum dma_data_direction dir)
-{
- __dma_sync_sg(dev, sg, nelems, dir);
- debug_dma_sync_sg_for_device(dev, sg, nelems, dir);
-}
+ WARN_ON(irqs_disabled()); /* for portability */
-static inline int dma_get_cache_alignment(void)
-{
- /*
- * Each processor family will define its own L1_CACHE_SHIFT,
- * L1_CACHE_BYTES wraps to this, so this is always safe.
- */
- return L1_CACHE_BYTES;
-}
+ if (dma_release_from_coherent(dev, get_order(size), vaddr))
+ return;
-static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
-{
- return dma_addr == 0;
+ debug_dma_free_coherent(dev, size, vaddr, dma_handle);
+ if (ops->free_coherent)
+ ops->free_coherent(dev, size, vaddr, dma_handle);
}
-#define ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY
-
-extern int
-dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
- dma_addr_t device_addr, size_t size, int flags);
-
-extern void
-dma_release_declared_memory(struct device *dev);
-
-extern void *
-dma_mark_declared_memory_occupied(struct device *dev,
- dma_addr_t device_addr, size_t size);
+/* arch/sh/mm/consistent.c */
+extern void *dma_generic_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_addr, gfp_t flag);
+extern void dma_generic_free_coherent(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle);
#endif /* __ASM_SH_DMA_MAPPING_H */
diff --git a/arch/sh/include/asm/dwarf.h b/arch/sh/include/asm/dwarf.h
index ced6795..bdccbbf 100644
--- a/arch/sh/include/asm/dwarf.h
+++ b/arch/sh/include/asm/dwarf.h
@@ -194,6 +194,12 @@
#define DWARF_ARCH_RA_REG 17
#ifndef __ASSEMBLY__
+
+#include <linux/compiler.h>
+#include <linux/bug.h>
+#include <linux/list.h>
+#include <linux/module.h>
+
/*
* Read either the frame pointer (r14) or the stack pointer (r15).
* NOTE: this MUST be inlined.
@@ -241,6 +247,12 @@ struct dwarf_cie {
unsigned long flags;
#define DWARF_CIE_Z_AUGMENTATION (1 << 0)
+
+ /*
+ * 'mod' will be non-NULL if this CIE came from a module's
+ * .eh_frame section.
+ */
+ struct module *mod;
};
/**
@@ -255,6 +267,12 @@ struct dwarf_fde {
unsigned char *instructions;
unsigned char *end;
struct list_head link;
+
+ /*
+ * 'mod' will be non-NULL if this FDE came from a module's
+ * .eh_frame section.
+ */
+ struct module *mod;
};
/**
@@ -364,6 +382,12 @@ static inline unsigned int DW_CFA_operand(unsigned long insn)
extern struct dwarf_frame *dwarf_unwind_stack(unsigned long,
struct dwarf_frame *);
+extern void dwarf_free_frame(struct dwarf_frame *);
+
+extern int module_dwarf_finalize(const Elf_Ehdr *, const Elf_Shdr *,
+ struct module *);
+extern void module_dwarf_cleanup(struct module *);
+
#endif /* !__ASSEMBLY__ */
#define CFI_STARTPROC .cfi_startproc
@@ -391,6 +415,10 @@ extern struct dwarf_frame *dwarf_unwind_stack(unsigned long,
static inline void dwarf_unwinder_init(void)
{
}
+
+#define module_dwarf_finalize(hdr, sechdrs, me) (0)
+#define module_dwarf_cleanup(mod) do { } while (0)
+
#endif
#endif /* CONFIG_DWARF_UNWINDER */
diff --git a/arch/sh/include/asm/fixmap.h b/arch/sh/include/asm/fixmap.h
index 721fcc4..5ac1e40 100644
--- a/arch/sh/include/asm/fixmap.h
+++ b/arch/sh/include/asm/fixmap.h
@@ -14,9 +14,9 @@
#define _ASM_FIXMAP_H
#include <linux/kernel.h>
+#include <linux/threads.h>
#include <asm/page.h>
#ifdef CONFIG_HIGHMEM
-#include <linux/threads.h>
#include <asm/kmap_types.h>
#endif
@@ -46,9 +46,15 @@
* fix-mapped?
*/
enum fixed_addresses {
-#define FIX_N_COLOURS 16
+ /*
+ * The FIX_CMAP entries are used by kmap_coherent() to get virtual
+ * addresses which are of a known color, and so their values are
+ * important. __fix_to_virt(FIX_CMAP_END - n) must give an address
+ * which is the same color as a page (n<<PAGE_SHIFT).
+ */
+#define FIX_N_COLOURS 8
FIX_CMAP_BEGIN,
- FIX_CMAP_END = FIX_CMAP_BEGIN + FIX_N_COLOURS,
+ FIX_CMAP_END = FIX_CMAP_BEGIN + (FIX_N_COLOURS * NR_CPUS) - 1,
FIX_UNCACHED,
#ifdef CONFIG_HIGHMEM
FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */
diff --git a/arch/sh/include/asm/fpu.h b/arch/sh/include/asm/fpu.h
index 1d3aee0..fb6bbb9 100644
--- a/arch/sh/include/asm/fpu.h
+++ b/arch/sh/include/asm/fpu.h
@@ -18,16 +18,15 @@ static inline void grab_fpu(struct pt_regs *regs)
struct task_struct;
-extern void save_fpu(struct task_struct *__tsk, struct pt_regs *regs);
+extern void save_fpu(struct task_struct *__tsk);
+void fpu_state_restore(struct pt_regs *regs);
#else
+#define save_fpu(tsk) do { } while (0)
#define release_fpu(regs) do { } while (0)
#define grab_fpu(regs) do { } while (0)
+#define fpu_state_restore(regs) do { } while (0)
-static inline void save_fpu(struct task_struct *tsk, struct pt_regs *regs)
-{
- clear_tsk_thread_flag(tsk, TIF_USEDFPU);
-}
#endif
struct user_regset;
@@ -39,19 +38,28 @@ extern int fpregs_get(struct task_struct *target,
unsigned int pos, unsigned int count,
void *kbuf, void __user *ubuf);
+static inline void __unlazy_fpu(struct task_struct *tsk, struct pt_regs *regs)
+{
+ if (task_thread_info(tsk)->status & TS_USEDFPU) {
+ task_thread_info(tsk)->status &= ~TS_USEDFPU;
+ save_fpu(tsk);
+ release_fpu(regs);
+ } else
+ tsk->fpu_counter = 0;
+}
+
static inline void unlazy_fpu(struct task_struct *tsk, struct pt_regs *regs)
{
preempt_disable();
- if (test_tsk_thread_flag(tsk, TIF_USEDFPU))
- save_fpu(tsk, regs);
+ __unlazy_fpu(tsk, regs);
preempt_enable();
}
static inline void clear_fpu(struct task_struct *tsk, struct pt_regs *regs)
{
preempt_disable();
- if (test_tsk_thread_flag(tsk, TIF_USEDFPU)) {
- clear_tsk_thread_flag(tsk, TIF_USEDFPU);
+ if (task_thread_info(tsk)->status & TS_USEDFPU) {
+ task_thread_info(tsk)->status &= ~TS_USEDFPU;
release_fpu(regs);
}
preempt_enable();
diff --git a/arch/sh/include/asm/ftrace.h b/arch/sh/include/asm/ftrace.h
index 12f3a31..13e9966 100644
--- a/arch/sh/include/asm/ftrace.h
+++ b/arch/sh/include/asm/ftrace.h
@@ -35,4 +35,21 @@ static inline unsigned long ftrace_call_adjust(unsigned long addr)
#endif /* __ASSEMBLY__ */
#endif /* CONFIG_FUNCTION_TRACER */
+#ifndef __ASSEMBLY__
+
+/* arch/sh/kernel/return_address.c */
+extern void *return_address(unsigned int);
+
+#define HAVE_ARCH_CALLER_ADDR
+
+#define CALLER_ADDR0 ((unsigned long)__builtin_return_address(0))
+#define CALLER_ADDR1 ((unsigned long)return_address(1))
+#define CALLER_ADDR2 ((unsigned long)return_address(2))
+#define CALLER_ADDR3 ((unsigned long)return_address(3))
+#define CALLER_ADDR4 ((unsigned long)return_address(4))
+#define CALLER_ADDR5 ((unsigned long)return_address(5))
+#define CALLER_ADDR6 ((unsigned long)return_address(6))
+
+#endif /* __ASSEMBLY__ */
+
#endif /* __ASM_SH_FTRACE_H */
diff --git a/arch/sh/include/asm/gpio.h b/arch/sh/include/asm/gpio.h
index 61f93da..f8d9a73 100644
--- a/arch/sh/include/asm/gpio.h
+++ b/arch/sh/include/asm/gpio.h
@@ -20,7 +20,7 @@
#endif
#define ARCH_NR_GPIOS 512
-#include <asm-generic/gpio.h>
+#include <linux/sh_pfc.h>
#ifdef CONFIG_GPIOLIB
@@ -53,84 +53,4 @@ static inline int irq_to_gpio(unsigned int irq)
#endif /* CONFIG_GPIOLIB */
-typedef unsigned short pinmux_enum_t;
-typedef unsigned short pinmux_flag_t;
-
-#define PINMUX_TYPE_NONE 0
-#define PINMUX_TYPE_FUNCTION 1
-#define PINMUX_TYPE_GPIO 2
-#define PINMUX_TYPE_OUTPUT 3
-#define PINMUX_TYPE_INPUT 4
-#define PINMUX_TYPE_INPUT_PULLUP 5
-#define PINMUX_TYPE_INPUT_PULLDOWN 6
-
-#define PINMUX_FLAG_TYPE (0x7)
-#define PINMUX_FLAG_WANT_PULLUP (1 << 3)
-#define PINMUX_FLAG_WANT_PULLDOWN (1 << 4)
-
-#define PINMUX_FLAG_DBIT_SHIFT 5
-#define PINMUX_FLAG_DBIT (0x1f << PINMUX_FLAG_DBIT_SHIFT)
-#define PINMUX_FLAG_DREG_SHIFT 10
-#define PINMUX_FLAG_DREG (0x3f << PINMUX_FLAG_DREG_SHIFT)
-
-struct pinmux_gpio {
- pinmux_enum_t enum_id;
- pinmux_flag_t flags;
-};
-
-#define PINMUX_GPIO(gpio, data_or_mark) [gpio] = { data_or_mark }
-#define PINMUX_DATA(data_or_mark, ids...) data_or_mark, ids, 0
-
-struct pinmux_cfg_reg {
- unsigned long reg, reg_width, field_width;
- unsigned long *cnt;
- pinmux_enum_t *enum_ids;
-};
-
-#define PINMUX_CFG_REG(name, r, r_width, f_width) \
- .reg = r, .reg_width = r_width, .field_width = f_width, \
- .cnt = (unsigned long [r_width / f_width]) {}, \
- .enum_ids = (pinmux_enum_t [(r_width / f_width) * (1 << f_width)]) \
-
-struct pinmux_data_reg {
- unsigned long reg, reg_width, reg_shadow;
- pinmux_enum_t *enum_ids;
-};
-
-#define PINMUX_DATA_REG(name, r, r_width) \
- .reg = r, .reg_width = r_width, \
- .enum_ids = (pinmux_enum_t [r_width]) \
-
-struct pinmux_range {
- pinmux_enum_t begin;
- pinmux_enum_t end;
- pinmux_enum_t force;
-};
-
-struct pinmux_info {
- char *name;
- pinmux_enum_t reserved_id;
- struct pinmux_range data;
- struct pinmux_range input;
- struct pinmux_range input_pd;
- struct pinmux_range input_pu;
- struct pinmux_range output;
- struct pinmux_range mark;
- struct pinmux_range function;
-
- unsigned first_gpio, last_gpio;
-
- struct pinmux_gpio *gpios;
- struct pinmux_cfg_reg *cfg_regs;
- struct pinmux_data_reg *data_regs;
-
- pinmux_enum_t *gpio_data;
- unsigned int gpio_data_size;
-
- unsigned long *gpio_in_use;
- struct gpio_chip chip;
-};
-
-int register_pinmux(struct pinmux_info *pip);
-
#endif /* __ASM_SH_GPIO_H */
diff --git a/arch/sh/include/asm/hardirq.h b/arch/sh/include/asm/hardirq.h
index a5be4af..48b1913 100644
--- a/arch/sh/include/asm/hardirq.h
+++ b/arch/sh/include/asm/hardirq.h
@@ -1,9 +1,16 @@
#ifndef __ASM_SH_HARDIRQ_H
#define __ASM_SH_HARDIRQ_H
-extern void ack_bad_irq(unsigned int irq);
-#define ack_bad_irq ack_bad_irq
+#include <linux/threads.h>
+#include <linux/irq.h>
+
+typedef struct {
+ unsigned int __softirq_pending;
+ unsigned int __nmi_count; /* arch dependent */
+} ____cacheline_aligned irq_cpustat_t;
-#include <asm-generic/hardirq.h>
+#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
+
+extern void ack_bad_irq(unsigned int irq);
#endif /* __ASM_SH_HARDIRQ_H */
diff --git a/arch/sh/include/asm/io.h b/arch/sh/include/asm/io.h
index 5be45ea..512cd3e 100644
--- a/arch/sh/include/asm/io.h
+++ b/arch/sh/include/asm/io.h
@@ -90,15 +90,11 @@
#define ctrl_outl __raw_writel
#define ctrl_outq __raw_writeq
+extern unsigned long generic_io_base;
+
static inline void ctrl_delay(void)
{
-#ifdef CONFIG_CPU_SH4
- __raw_readw(CCN_PVR);
-#elif defined(P2SEG)
- __raw_readw(P2SEG);
-#else
-#error "Need a dummy address for delay"
-#endif
+ __raw_readw(generic_io_base);
}
#define __BUILD_MEMORY_STRING(bwlq, type) \
@@ -186,8 +182,6 @@ __BUILD_MEMORY_STRING(q, u64)
#define IO_SPACE_LIMIT 0xffffffff
-extern unsigned long generic_io_base;
-
/*
* This function provides a method for the generic case where a
* board-specific ioport_map simply needs to return the port + some
@@ -246,7 +240,7 @@ void __iounmap(void __iomem *addr);
static inline void __iomem *
__ioremap_mode(unsigned long offset, unsigned long size, unsigned long flags)
{
-#if defined(CONFIG_SUPERH32) && !defined(CONFIG_PMB_FIXED)
+#if defined(CONFIG_SUPERH32) && !defined(CONFIG_PMB_FIXED) && !defined(CONFIG_PMB)
unsigned long last_addr = offset + size - 1;
#endif
void __iomem *ret;
@@ -255,7 +249,7 @@ __ioremap_mode(unsigned long offset, unsigned long size, unsigned long flags)
if (ret)
return ret;
-#if defined(CONFIG_SUPERH32) && !defined(CONFIG_PMB_FIXED)
+#if defined(CONFIG_SUPERH32) && !defined(CONFIG_PMB_FIXED) && !defined(CONFIG_PMB)
/*
* For P1 and P2 space this is trivial, as everything is already
* mapped. Uncached access for P1 addresses are done through P2.
diff --git a/arch/sh/include/asm/irqflags.h b/arch/sh/include/asm/irqflags.h
index 46e71da..a741153 100644
--- a/arch/sh/include/asm/irqflags.h
+++ b/arch/sh/include/asm/irqflags.h
@@ -1,34 +1,9 @@
#ifndef __ASM_SH_IRQFLAGS_H
#define __ASM_SH_IRQFLAGS_H
-#ifdef CONFIG_SUPERH32
-#include "irqflags_32.h"
-#else
-#include "irqflags_64.h"
-#endif
+#define RAW_IRQ_DISABLED 0xf0
+#define RAW_IRQ_ENABLED 0x00
-#define raw_local_save_flags(flags) \
- do { (flags) = __raw_local_save_flags(); } while (0)
-
-static inline int raw_irqs_disabled_flags(unsigned long flags)
-{
- return (flags != 0);
-}
-
-static inline int raw_irqs_disabled(void)
-{
- unsigned long flags = __raw_local_save_flags();
-
- return raw_irqs_disabled_flags(flags);
-}
-
-#define raw_local_irq_save(flags) \
- do { (flags) = __raw_local_irq_save(); } while (0)
-
-static inline void raw_local_irq_restore(unsigned long flags)
-{
- if ((flags & 0xf0) != 0xf0)
- raw_local_irq_enable();
-}
+#include <asm-generic/irqflags.h>
#endif /* __ASM_SH_IRQFLAGS_H */
diff --git a/arch/sh/include/asm/irqflags_32.h b/arch/sh/include/asm/irqflags_32.h
deleted file mode 100644
index 60218f5..0000000
--- a/arch/sh/include/asm/irqflags_32.h
+++ /dev/null
@@ -1,99 +0,0 @@
-#ifndef __ASM_SH_IRQFLAGS_32_H
-#define __ASM_SH_IRQFLAGS_32_H
-
-static inline void raw_local_irq_enable(void)
-{
- unsigned long __dummy0, __dummy1;
-
- __asm__ __volatile__ (
- "stc sr, %0\n\t"
- "and %1, %0\n\t"
-#ifdef CONFIG_CPU_HAS_SR_RB
- "stc r6_bank, %1\n\t"
- "or %1, %0\n\t"
-#endif
- "ldc %0, sr\n\t"
- : "=&r" (__dummy0), "=r" (__dummy1)
- : "1" (~0x000000f0)
- : "memory"
- );
-}
-
-static inline void raw_local_irq_disable(void)
-{
- unsigned long flags;
-
- __asm__ __volatile__ (
- "stc sr, %0\n\t"
- "or #0xf0, %0\n\t"
- "ldc %0, sr\n\t"
- : "=&z" (flags)
- : /* no inputs */
- : "memory"
- );
-}
-
-static inline void set_bl_bit(void)
-{
- unsigned long __dummy0, __dummy1;
-
- __asm__ __volatile__ (
- "stc sr, %0\n\t"
- "or %2, %0\n\t"
- "and %3, %0\n\t"
- "ldc %0, sr\n\t"
- : "=&r" (__dummy0), "=r" (__dummy1)
- : "r" (0x10000000), "r" (0xffffff0f)
- : "memory"
- );
-}
-
-static inline void clear_bl_bit(void)
-{
- unsigned long __dummy0, __dummy1;
-
- __asm__ __volatile__ (
- "stc sr, %0\n\t"
- "and %2, %0\n\t"
- "ldc %0, sr\n\t"
- : "=&r" (__dummy0), "=r" (__dummy1)
- : "1" (~0x10000000)
- : "memory"
- );
-}
-
-static inline unsigned long __raw_local_save_flags(void)
-{
- unsigned long flags;
-
- __asm__ __volatile__ (
- "stc sr, %0\n\t"
- "and #0xf0, %0\n\t"
- : "=&z" (flags)
- : /* no inputs */
- : "memory"
- );
-
- return flags;
-}
-
-static inline unsigned long __raw_local_irq_save(void)
-{
- unsigned long flags, __dummy;
-
- __asm__ __volatile__ (
- "stc sr, %1\n\t"
- "mov %1, %0\n\t"
- "or #0xf0, %0\n\t"
- "ldc %0, sr\n\t"
- "mov %1, %0\n\t"
- "and #0xf0, %0\n\t"
- : "=&z" (flags), "=&r" (__dummy)
- : /* no inputs */
- : "memory"
- );
-
- return flags;
-}
-
-#endif /* __ASM_SH_IRQFLAGS_32_H */
diff --git a/arch/sh/include/asm/irqflags_64.h b/arch/sh/include/asm/irqflags_64.h
deleted file mode 100644
index 88f6522..0000000
--- a/arch/sh/include/asm/irqflags_64.h
+++ /dev/null
@@ -1,85 +0,0 @@
-#ifndef __ASM_SH_IRQFLAGS_64_H
-#define __ASM_SH_IRQFLAGS_64_H
-
-#include <cpu/registers.h>
-
-#define SR_MASK_LL 0x00000000000000f0LL
-#define SR_BL_LL 0x0000000010000000LL
-
-static inline void raw_local_irq_enable(void)
-{
- unsigned long long __dummy0, __dummy1 = ~SR_MASK_LL;
-
- __asm__ __volatile__("getcon " __SR ", %0\n\t"
- "and %0, %1, %0\n\t"
- "putcon %0, " __SR "\n\t"
- : "=&r" (__dummy0)
- : "r" (__dummy1));
-}
-
-static inline void raw_local_irq_disable(void)
-{
- unsigned long long __dummy0, __dummy1 = SR_MASK_LL;
-
- __asm__ __volatile__("getcon " __SR ", %0\n\t"
- "or %0, %1, %0\n\t"
- "putcon %0, " __SR "\n\t"
- : "=&r" (__dummy0)
- : "r" (__dummy1));
-}
-
-static inline void set_bl_bit(void)
-{
- unsigned long long __dummy0, __dummy1 = SR_BL_LL;
-
- __asm__ __volatile__("getcon " __SR ", %0\n\t"
- "or %0, %1, %0\n\t"
- "putcon %0, " __SR "\n\t"
- : "=&r" (__dummy0)
- : "r" (__dummy1));
-
-}
-
-static inline void clear_bl_bit(void)
-{
- unsigned long long __dummy0, __dummy1 = ~SR_BL_LL;
-
- __asm__ __volatile__("getcon " __SR ", %0\n\t"
- "and %0, %1, %0\n\t"
- "putcon %0, " __SR "\n\t"
- : "=&r" (__dummy0)
- : "r" (__dummy1));
-}
-
-static inline unsigned long __raw_local_save_flags(void)
-{
- unsigned long long __dummy = SR_MASK_LL;
- unsigned long flags;
-
- __asm__ __volatile__ (
- "getcon " __SR ", %0\n\t"
- "and %0, %1, %0"
- : "=&r" (flags)
- : "r" (__dummy));
-
- return flags;
-}
-
-static inline unsigned long __raw_local_irq_save(void)
-{
- unsigned long long __dummy0, __dummy1 = SR_MASK_LL;
- unsigned long flags;
-
- __asm__ __volatile__ (
- "getcon " __SR ", %1\n\t"
- "or %1, r63, %0\n\t"
- "or %1, %2, %1\n\t"
- "putcon %1, " __SR "\n\t"
- "and %0, %2, %0"
- : "=&r" (flags), "=&r" (__dummy0)
- : "r" (__dummy1));
-
- return flags;
-}
-
-#endif /* __ASM_SH_IRQFLAGS_64_H */
diff --git a/arch/sh/include/asm/mmu.h b/arch/sh/include/asm/mmu.h
index f596303..c7426ad 100644
--- a/arch/sh/include/asm/mmu.h
+++ b/arch/sh/include/asm/mmu.h
@@ -7,12 +7,16 @@
#define PMB_PASCR 0xff000070
#define PMB_IRMCR 0xff000078
+#define PASCR_SE 0x80000000
+
#define PMB_ADDR 0xf6100000
#define PMB_DATA 0xf7100000
#define PMB_ENTRY_MAX 16
#define PMB_E_MASK 0x0000000f
#define PMB_E_SHIFT 8
+#define PMB_PFN_MASK 0xff000000
+
#define PMB_SZ_16M 0x00000000
#define PMB_SZ_64M 0x00000010
#define PMB_SZ_128M 0x00000080
@@ -62,17 +66,10 @@ struct pmb_entry {
};
/* arch/sh/mm/pmb.c */
-int __set_pmb_entry(unsigned long vpn, unsigned long ppn,
- unsigned long flags, int *entry);
-int set_pmb_entry(struct pmb_entry *pmbe);
-void clear_pmb_entry(struct pmb_entry *pmbe);
-struct pmb_entry *pmb_alloc(unsigned long vpn, unsigned long ppn,
- unsigned long flags);
-void pmb_free(struct pmb_entry *pmbe);
long pmb_remap(unsigned long virt, unsigned long phys,
unsigned long size, unsigned long flags);
void pmb_unmap(unsigned long addr);
+int pmb_init(void);
#endif /* __ASSEMBLY__ */
#endif /* __MMU_H */
-
diff --git a/arch/sh/include/asm/pci.h b/arch/sh/include/asm/pci.h
index 4163950..67f3999 100644
--- a/arch/sh/include/asm/pci.h
+++ b/arch/sh/include/asm/pci.h
@@ -3,8 +3,6 @@
#ifdef __KERNEL__
-#include <linux/dma-mapping.h>
-
/* 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 */
@@ -54,30 +52,18 @@ static inline void pcibios_penalize_isa_irq(int irq, int active)
* address space. The networking and block device layers use
* this boolean for bounce buffer decisions.
*/
-#define PCI_DMA_BUS_IS_PHYS (1)
-
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <asm/scatterlist.h>
-#include <linux/string.h>
-#include <asm/io.h>
+#define PCI_DMA_BUS_IS_PHYS (dma_ops->is_phys)
/* pci_unmap_{single,page} being a nop depends upon the
* configuration.
*/
-#ifdef CONFIG_SH_PCIDMA_NONCOHERENT
-#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \
- dma_addr_t ADDR_NAME;
-#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) \
- __u32 LEN_NAME;
-#define pci_unmap_addr(PTR, ADDR_NAME) \
- ((PTR)->ADDR_NAME)
-#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) \
- (((PTR)->ADDR_NAME) = (VAL))
-#define pci_unmap_len(PTR, LEN_NAME) \
- ((PTR)->LEN_NAME)
-#define pci_unmap_len_set(PTR, LEN_NAME, VAL) \
- (((PTR)->LEN_NAME) = (VAL))
+#ifdef CONFIG_DMA_NONCOHERENT
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) dma_addr_t ADDR_NAME;
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) __u32 LEN_NAME;
+#define pci_unmap_addr(PTR, ADDR_NAME) ((PTR)->ADDR_NAME)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) (((PTR)->ADDR_NAME) = (VAL))
+#define pci_unmap_len(PTR, LEN_NAME) ((PTR)->LEN_NAME)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL) (((PTR)->LEN_NAME) = (VAL))
#else
#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
diff --git a/arch/sh/include/asm/perf_event.h b/arch/sh/include/asm/perf_event.h
index 11a3022..3d0c9f3 100644
--- a/arch/sh/include/asm/perf_event.h
+++ b/arch/sh/include/asm/perf_event.h
@@ -1,8 +1,35 @@
#ifndef __ASM_SH_PERF_EVENT_H
#define __ASM_SH_PERF_EVENT_H
-/* SH only supports software events through this interface. */
-static inline void set_perf_event_pending(void) {}
+struct hw_perf_event;
+
+#define MAX_HWEVENTS 2
+
+struct sh_pmu {
+ const char *name;
+ unsigned int num_events;
+ void (*disable_all)(void);
+ void (*enable_all)(void);
+ void (*enable)(struct hw_perf_event *, int);
+ void (*disable)(struct hw_perf_event *, int);
+ u64 (*read)(int);
+ int (*event_map)(int);
+ unsigned int max_events;
+ unsigned long raw_event_mask;
+ const int (*cache_events)[PERF_COUNT_HW_CACHE_MAX]
+ [PERF_COUNT_HW_CACHE_OP_MAX]
+ [PERF_COUNT_HW_CACHE_RESULT_MAX];
+};
+
+/* arch/sh/kernel/perf_event.c */
+extern int register_sh_pmu(struct sh_pmu *);
+extern int reserve_pmc_hardware(void);
+extern void release_pmc_hardware(void);
+
+static inline void set_perf_event_pending(void)
+{
+ /* Nothing to see here, move along. */
+}
#define PERF_EVENT_INDEX_OFFSET 0
diff --git a/arch/sh/include/asm/pgtable.h b/arch/sh/include/asm/pgtable.h
index 4f3efa7..ba3046e 100644
--- a/arch/sh/include/asm/pgtable.h
+++ b/arch/sh/include/asm/pgtable.h
@@ -75,13 +75,31 @@ static inline unsigned long long neff_sign_extend(unsigned long val)
#define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE)
#define FIRST_USER_ADDRESS 0
-#ifdef CONFIG_32BIT
-#define PHYS_ADDR_MASK 0xffffffff
+#define PHYS_ADDR_MASK29 0x1fffffff
+#define PHYS_ADDR_MASK32 0xffffffff
+
+#ifdef CONFIG_PMB
+static inline unsigned long phys_addr_mask(void)
+{
+ /* Is the MMU in 29bit mode? */
+ if (__in_29bit_mode())
+ return PHYS_ADDR_MASK29;
+
+ return PHYS_ADDR_MASK32;
+}
+#elif defined(CONFIG_32BIT)
+static inline unsigned long phys_addr_mask(void)
+{
+ return PHYS_ADDR_MASK32;
+}
#else
-#define PHYS_ADDR_MASK 0x1fffffff
+static inline unsigned long phys_addr_mask(void)
+{
+ return PHYS_ADDR_MASK29;
+}
#endif
-#define PTE_PHYS_MASK (PHYS_ADDR_MASK & PAGE_MASK)
+#define PTE_PHYS_MASK (phys_addr_mask() & PAGE_MASK)
#define PTE_FLAGS_MASK (~(PTE_PHYS_MASK) << PAGE_SHIFT)
#ifdef CONFIG_SUPERH32
diff --git a/arch/sh/include/asm/pgtable_32.h b/arch/sh/include/asm/pgtable_32.h
index c0d359c..b354355 100644
--- a/arch/sh/include/asm/pgtable_32.h
+++ b/arch/sh/include/asm/pgtable_32.h
@@ -108,7 +108,7 @@ static inline unsigned long copy_ptea_attributes(unsigned long x)
#define _PAGE_CLEAR_FLAGS (_PAGE_PROTNONE | _PAGE_ACCESSED | _PAGE_FILE)
#endif
-#define _PAGE_FLAGS_HARDWARE_MASK (PHYS_ADDR_MASK & ~(_PAGE_CLEAR_FLAGS))
+#define _PAGE_FLAGS_HARDWARE_MASK (phys_addr_mask() & ~(_PAGE_CLEAR_FLAGS))
/* Hardware flags, page size encoding */
#if !defined(CONFIG_MMU)
diff --git a/arch/sh/include/asm/processor_32.h b/arch/sh/include/asm/processor_32.h
index 9a87149..1f3d6fa 100644
--- a/arch/sh/include/asm/processor_32.h
+++ b/arch/sh/include/asm/processor_32.h
@@ -56,6 +56,7 @@ asmlinkage void __init sh_cpu_init(void);
#define SR_DSP 0x00001000
#define SR_IMASK 0x000000f0
#define SR_FD 0x00008000
+#define SR_MD 0x40000000
/*
* DSP structure and data
@@ -136,7 +137,7 @@ struct mm_struct;
extern void release_thread(struct task_struct *);
/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk) do { } while (0)
+void prepare_to_copy(struct task_struct *tsk);
/*
* create a kernel thread without removing it from tasklists
diff --git a/arch/sh/include/asm/scatterlist.h b/arch/sh/include/asm/scatterlist.h
index 327cc2e..e38d1d4 100644
--- a/arch/sh/include/asm/scatterlist.h
+++ b/arch/sh/include/asm/scatterlist.h
@@ -1,7 +1,7 @@
#ifndef __ASM_SH_SCATTERLIST_H
#define __ASM_SH_SCATTERLIST_H
-#define ISA_DMA_THRESHOLD PHYS_ADDR_MASK
+#define ISA_DMA_THRESHOLD phys_addr_mask()
#include <asm-generic/scatterlist.h>
diff --git a/arch/sh/include/asm/suspend.h b/arch/sh/include/asm/suspend.h
index 5c8ea28..fe9c2a1 100644
--- a/arch/sh/include/asm/suspend.h
+++ b/arch/sh/include/asm/suspend.h
@@ -2,6 +2,7 @@
#define _ASM_SH_SUSPEND_H
#ifndef __ASSEMBLY__
+#include <linux/notifier.h>
static inline int arch_prepare_suspend(void) { return 0; }
#include <asm/ptrace.h>
@@ -19,6 +20,69 @@ void sh_mobile_setup_cpuidle(void);
static inline void sh_mobile_setup_cpuidle(void) {}
#endif
+/* notifier chains for pre/post sleep hooks */
+extern struct atomic_notifier_head sh_mobile_pre_sleep_notifier_list;
+extern struct atomic_notifier_head sh_mobile_post_sleep_notifier_list;
+
+/* priority levels for notifiers */
+#define SH_MOBILE_SLEEP_BOARD 0
+#define SH_MOBILE_SLEEP_CPU 1
+#define SH_MOBILE_PRE(x) (x)
+#define SH_MOBILE_POST(x) (-(x))
+
+/* board code registration function for self-refresh assembly snippets */
+void sh_mobile_register_self_refresh(unsigned long flags,
+ void *pre_start, void *pre_end,
+ void *post_start, void *post_end);
+
+/* register structure for address/data information */
+struct sh_sleep_regs {
+ unsigned long stbcr;
+ unsigned long bar;
+
+ /* MMU */
+ unsigned long pteh;
+ unsigned long ptel;
+ unsigned long ttb;
+ unsigned long tea;
+ unsigned long mmucr;
+ unsigned long ptea;
+ unsigned long pascr;
+ unsigned long irmcr;
+
+ /* Cache */
+ unsigned long ccr;
+ unsigned long ramcr;
+};
+
+/* data area for low-level sleep code */
+struct sh_sleep_data {
+ /* current sleep mode (SUSP_SH_...) */
+ unsigned long mode;
+
+ /* addresses of board specific self-refresh snippets */
+ unsigned long sf_pre;
+ unsigned long sf_post;
+
+ /* address of resume code */
+ unsigned long resume;
+
+ /* register state saved and restored by the assembly code */
+ unsigned long vbr;
+ unsigned long spc;
+ unsigned long sr;
+ unsigned long sp;
+
+ /* structure for keeping register addresses */
+ struct sh_sleep_regs addr;
+
+ /* structure for saving/restoring register state */
+ struct sh_sleep_regs data;
+};
+
+/* a bitmap of supported sleep modes (SUSP_SH..) */
+extern unsigned long sh_mobile_sleep_supported;
+
#endif
/* flags passed to assembly suspend code */
@@ -27,5 +91,6 @@ static inline void sh_mobile_setup_cpuidle(void) {}
#define SUSP_SH_RSTANDBY (1 << 2) /* SH-Mobile R-standby mode */
#define SUSP_SH_USTANDBY (1 << 3) /* SH-Mobile U-standby mode */
#define SUSP_SH_SF (1 << 4) /* Enable self-refresh */
+#define SUSP_SH_MMU (1 << 5) /* Save/restore MMU and cache */
#endif /* _ASM_SH_SUSPEND_H */
diff --git a/arch/sh/include/asm/system.h b/arch/sh/include/asm/system.h
index b5c5acd..c15415b 100644
--- a/arch/sh/include/asm/system.h
+++ b/arch/sh/include/asm/system.h
@@ -171,10 +171,6 @@ BUILD_TRAP_HANDLER(fpu_error);
BUILD_TRAP_HANDLER(fpu_state_restore);
BUILD_TRAP_HANDLER(nmi);
-#ifdef CONFIG_BUG
-extern void handle_BUG(struct pt_regs *);
-#endif
-
#define arch_align_stack(x) (x)
struct mem_access {
diff --git a/arch/sh/include/asm/system_32.h b/arch/sh/include/asm/system_32.h
index 607d413..06814f5 100644
--- a/arch/sh/include/asm/system_32.h
+++ b/arch/sh/include/asm/system_32.h
@@ -232,4 +232,33 @@ asmlinkage void do_exception_error(unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7,
struct pt_regs __regs);
+static inline void set_bl_bit(void)
+{
+ unsigned long __dummy0, __dummy1;
+
+ __asm__ __volatile__ (
+ "stc sr, %0\n\t"
+ "or %2, %0\n\t"
+ "and %3, %0\n\t"
+ "ldc %0, sr\n\t"
+ : "=&r" (__dummy0), "=r" (__dummy1)
+ : "r" (0x10000000), "r" (0xffffff0f)
+ : "memory"
+ );
+}
+
+static inline void clear_bl_bit(void)
+{
+ unsigned long __dummy0, __dummy1;
+
+ __asm__ __volatile__ (
+ "stc sr, %0\n\t"
+ "and %2, %0\n\t"
+ "ldc %0, sr\n\t"
+ : "=&r" (__dummy0), "=r" (__dummy1)
+ : "1" (~0x10000000)
+ : "memory"
+ );
+}
+
#endif /* __ASM_SH_SYSTEM_32_H */
diff --git a/arch/sh/include/asm/system_64.h b/arch/sh/include/asm/system_64.h
index 8e4a03e..ab1dd91 100644
--- a/arch/sh/include/asm/system_64.h
+++ b/arch/sh/include/asm/system_64.h
@@ -12,6 +12,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
+#include <cpu/registers.h>
#include <asm/processor.h>
/*
@@ -47,4 +48,29 @@ static inline reg_size_t register_align(void *val)
return (unsigned long long)(signed long long)(signed long)val;
}
+#define SR_BL_LL 0x0000000010000000LL
+
+static inline void set_bl_bit(void)
+{
+ unsigned long long __dummy0, __dummy1 = SR_BL_LL;
+
+ __asm__ __volatile__("getcon " __SR ", %0\n\t"
+ "or %0, %1, %0\n\t"
+ "putcon %0, " __SR "\n\t"
+ : "=&r" (__dummy0)
+ : "r" (__dummy1));
+
+}
+
+static inline void clear_bl_bit(void)
+{
+ unsigned long long __dummy0, __dummy1 = ~SR_BL_LL;
+
+ __asm__ __volatile__("getcon " __SR ", %0\n\t"
+ "and %0, %1, %0\n\t"
+ "putcon %0, " __SR "\n\t"
+ : "=&r" (__dummy0)
+ : "r" (__dummy1));
+}
+
#endif /* __ASM_SH_SYSTEM_64_H */
diff --git a/arch/sh/include/asm/thread_info.h b/arch/sh/include/asm/thread_info.h
index bdeb9d4..1f3d927 100644
--- a/arch/sh/include/asm/thread_info.h
+++ b/arch/sh/include/asm/thread_info.h
@@ -19,6 +19,7 @@ struct thread_info {
struct task_struct *task; /* main task structure */
struct exec_domain *exec_domain; /* execution domain */
unsigned long flags; /* low level flags */
+ __u32 status; /* thread synchronous flags */
__u32 cpu;
int preempt_count; /* 0 => preemptable, <0 => BUG */
mm_segment_t addr_limit; /* thread address space */
@@ -50,6 +51,7 @@ struct thread_info {
.task = &tsk, \
.exec_domain = &default_exec_domain, \
.flags = 0, \
+ .status = 0, \
.cpu = 0, \
.preempt_count = INIT_PREEMPT_COUNT, \
.addr_limit = KERNEL_DS, \
@@ -111,13 +113,11 @@ extern void free_thread_info(struct thread_info *ti);
#define TIF_SYSCALL_TRACE 0 /* syscall trace active */
#define TIF_SIGPENDING 1 /* signal pending */
#define TIF_NEED_RESCHED 2 /* rescheduling necessary */
-#define TIF_RESTORE_SIGMASK 3 /* restore signal mask in do_signal() */
#define TIF_SINGLESTEP 4 /* singlestepping active */
#define TIF_SYSCALL_AUDIT 5 /* syscall auditing active */
#define TIF_SECCOMP 6 /* secure computing */
#define TIF_NOTIFY_RESUME 7 /* callback before returning to user */
#define TIF_SYSCALL_TRACEPOINT 8 /* for ftrace syscall instrumentation */
-#define TIF_USEDFPU 16 /* FPU was used by this task this quantum (SMP) */
#define TIF_POLLING_NRFLAG 17 /* true if poll_idle() is polling TIF_NEED_RESCHED */
#define TIF_MEMDIE 18
#define TIF_FREEZE 19 /* Freezing for suspend */
@@ -125,13 +125,11 @@ extern void free_thread_info(struct thread_info *ti);
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
-#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK)
#define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP)
#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
#define _TIF_SECCOMP (1 << TIF_SECCOMP)
#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
#define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT)
-#define _TIF_USEDFPU (1 << TIF_USEDFPU)
#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
#define _TIF_FREEZE (1 << TIF_FREEZE)
@@ -149,13 +147,33 @@ extern void free_thread_info(struct thread_info *ti);
/* work to do on any return to u-space */
#define _TIF_ALLWORK_MASK (_TIF_SYSCALL_TRACE | _TIF_SIGPENDING | \
_TIF_NEED_RESCHED | _TIF_SYSCALL_AUDIT | \
- _TIF_SINGLESTEP | _TIF_RESTORE_SIGMASK | \
- _TIF_NOTIFY_RESUME | _TIF_SYSCALL_TRACEPOINT)
+ _TIF_SINGLESTEP | _TIF_NOTIFY_RESUME | \
+ _TIF_SYSCALL_TRACEPOINT)
/* work to do on interrupt/exception return */
#define _TIF_WORK_MASK (_TIF_ALLWORK_MASK & ~(_TIF_SYSCALL_TRACE | \
_TIF_SYSCALL_AUDIT | _TIF_SINGLESTEP))
+/*
+ * Thread-synchronous status.
+ *
+ * This is different from the flags in that nobody else
+ * ever touches our thread-synchronous status, so we don't
+ * have to worry about atomic accesses.
+ */
+#define TS_RESTORE_SIGMASK 0x0001 /* restore signal mask in do_signal() */
+#define TS_USEDFPU 0x0002 /* FPU used by this task this quantum */
+
+#ifndef __ASSEMBLY__
+#define HAVE_SET_RESTORE_SIGMASK 1
+static inline void set_restore_sigmask(void)
+{
+ struct thread_info *ti = current_thread_info();
+ ti->status |= TS_RESTORE_SIGMASK;
+ set_bit(TIF_SIGPENDING, (unsigned long *)&ti->flags);
+}
+#endif /* !__ASSEMBLY__ */
+
#endif /* __KERNEL__ */
#endif /* __ASM_SH_THREAD_INFO_H */
diff --git a/arch/sh/include/asm/topology.h b/arch/sh/include/asm/topology.h
index 65e7bd2..37cdadd 100644
--- a/arch/sh/include/asm/topology.h
+++ b/arch/sh/include/asm/topology.h
@@ -40,6 +40,14 @@
#endif
+#define mc_capable() (1)
+
+const struct cpumask *cpu_coregroup_mask(unsigned int cpu);
+
+extern cpumask_t cpu_core_map[NR_CPUS];
+
+#define topology_core_cpumask(cpu) (&cpu_core_map[cpu])
+
#include <asm-generic/topology.h>
#endif /* _ASM_SH_TOPOLOGY_H */
diff --git a/arch/sh/include/asm/ubc.h b/arch/sh/include/asm/ubc.h
index 4ca4b77..9bf9616 100644
--- a/arch/sh/include/asm/ubc.h
+++ b/arch/sh/include/asm/ubc.h
@@ -60,16 +60,5 @@
#define BRCR_UBDE (1 << 0)
#endif
-#ifndef __ASSEMBLY__
-/* arch/sh/kernel/cpu/ubc.S */
-extern void ubc_sleep(void);
-
-#ifdef CONFIG_UBC_WAKEUP
-extern void ubc_wakeup(void);
-#else
-#define ubc_wakeup() do { } while (0)
-#endif
-#endif
-
#endif /* __KERNEL__ */
#endif /* __ASM_SH_UBC_H */
diff --git a/arch/sh/include/asm/watchdog.h b/arch/sh/include/asm/watchdog.h
index 2fe7cee..19dfff5 100644
--- a/arch/sh/include/asm/watchdog.h
+++ b/arch/sh/include/asm/watchdog.h
@@ -2,6 +2,8 @@
* include/asm-sh/watchdog.h
*
* Copyright (C) 2002, 2003 Paul Mundt
+ * Copyright (C) 2009 Siemens AG
+ * Copyright (C) 2009 Valentin Sitdikov
*
* 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
@@ -61,6 +63,61 @@
#define WTCSR_CKS_2048 0x06
#define WTCSR_CKS_4096 0x07
+#if defined(CONFIG_CPU_SUBTYPE_SH7785) || defined(CONFIG_CPU_SUBTYPE_SH7780)
+/**
+ * sh_wdt_read_cnt - Read from Counter
+ * Reads back the WTCNT value.
+ */
+static inline __u32 sh_wdt_read_cnt(void)
+{
+ return ctrl_inl(WTCNT_R);
+}
+
+/**
+ * sh_wdt_write_cnt - Write to Counter
+ * @val: Value to write
+ *
+ * Writes the given value @val to the lower byte of the timer counter.
+ * The upper byte is set manually on each write.
+ */
+static inline void sh_wdt_write_cnt(__u32 val)
+{
+ ctrl_outl((WTCNT_HIGH << 24) | (__u32)val, WTCNT);
+}
+
+/**
+ * sh_wdt_write_bst - Write to Counter
+ * @val: Value to write
+ *
+ * Writes the given value @val to the lower byte of the timer counter.
+ * The upper byte is set manually on each write.
+ */
+static inline void sh_wdt_write_bst(__u32 val)
+{
+ ctrl_outl((WTBST_HIGH << 24) | (__u32)val, WTBST);
+}
+/**
+ * sh_wdt_read_csr - Read from Control/Status Register
+ *
+ * Reads back the WTCSR value.
+ */
+static inline __u32 sh_wdt_read_csr(void)
+{
+ return ctrl_inl(WTCSR_R);
+}
+
+/**
+ * sh_wdt_write_csr - Write to Control/Status Register
+ * @val: Value to write
+ *
+ * Writes the given value @val to the lower byte of the control/status
+ * register. The upper byte is set manually on each write.
+ */
+static inline void sh_wdt_write_csr(__u32 val)
+{
+ ctrl_outl((WTCSR_HIGH << 24) | (__u32)val, WTCSR);
+}
+#else
/**
* sh_wdt_read_cnt - Read from Counter
* Reads back the WTCNT value.
@@ -103,6 +160,6 @@ static inline void sh_wdt_write_csr(__u8 val)
{
ctrl_outw((WTCSR_HIGH << 8) | (__u16)val, WTCSR);
}
-
+#endif /* CONFIG_CPU_SUBTYPE_SH7785 || CONFIG_CPU_SUBTYPE_SH7780 */
#endif /* __KERNEL__ */
#endif /* __ASM_SH_WATCHDOG_H */
diff --git a/arch/sh/include/cpu-sh4/cpu/watchdog.h b/arch/sh/include/cpu-sh4/cpu/watchdog.h
index 259f6a0..7672301 100644
--- a/arch/sh/include/cpu-sh4/cpu/watchdog.h
+++ b/arch/sh/include/cpu-sh4/cpu/watchdog.h
@@ -2,6 +2,8 @@
* include/asm-sh/cpu-sh4/watchdog.h
*
* Copyright (C) 2002, 2003 Paul Mundt
+ * Copyright (C) 2009 Siemens AG
+ * Copyright (C) 2009 Sitdikov Valentin
*
* 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
@@ -10,9 +12,20 @@
#ifndef __ASM_CPU_SH4_WATCHDOG_H
#define __ASM_CPU_SH4_WATCHDOG_H
+#if defined(CONFIG_CPU_SUBTYPE_SH7785) || defined(CONFIG_CPU_SUBTYPE_SH7780)
+/* Prefix definition */
+#define WTBST_HIGH 0x55
+/* Register definitions */
+#define WTCNT_R 0xffcc0010 /*WDTCNT*/
+#define WTCSR 0xffcc0004 /*WDTCSR*/
+#define WTCNT 0xffcc0000 /*WDTST*/
+#define WTST WTCNT
+#define WTBST 0xffcc0008 /*WDTBST*/
+#else
/* Register definitions */
#define WTCNT 0xffc00008
#define WTCSR 0xffc0000c
+#endif
/* Bit definitions */
#define WTCSR_TME 0x80
diff --git a/arch/sh/include/mach-common/mach/titan.h b/arch/sh/include/mach-common/mach/titan.h
index 03f3583..4a674d2 100644
--- a/arch/sh/include/mach-common/mach/titan.h
+++ b/arch/sh/include/mach-common/mach/titan.h
@@ -1,5 +1,5 @@
/*
- * Platform defintions for Titan
+ * Platform definitions for Titan
*/
#ifndef _ASM_SH_TITAN_H
#define _ASM_SH_TITAN_H
diff --git a/arch/sh/include/mach-ecovec24/mach/partner-jet-setup.txt b/arch/sh/include/mach-ecovec24/mach/partner-jet-setup.txt
index 8b8e4fa..cc737b8 100644
--- a/arch/sh/include/mach-ecovec24/mach/partner-jet-setup.txt
+++ b/arch/sh/include/mach-ecovec24/mach/partner-jet-setup.txt
@@ -22,13 +22,12 @@ ED 0xff000010, 0x00000004
LIST "setup clocks"
ED 0xa4150024, 0x00004000
ED 0xa4150000, 0x8E003508
-ED 0xa4150004, 0x00000000
WAIT 1
LIST "BSC"
ED 0xff800020, 0xa5a50000
-ED 0xfec10000, 0x00000013
+ED 0xfec10000, 0x00001013
ED 0xfec10004, 0x11110400
ED 0xfec10024, 0x00000440
diff --git a/arch/sh/include/mach-se/mach/se7722.h b/arch/sh/include/mach-se/mach/se7722.h
index e971d9a..16505bf 100644
--- a/arch/sh/include/mach-se/mach/se7722.h
+++ b/arch/sh/include/mach-se/mach/se7722.h
@@ -92,18 +92,11 @@
#define SE7722_FPGA_IRQ_MRSHPC1 3 /* IRQ1 */
#define SE7722_FPGA_IRQ_MRSHPC2 4 /* IRQ1 */
#define SE7722_FPGA_IRQ_MRSHPC3 5 /* IRQ1 */
-
#define SE7722_FPGA_IRQ_NR 6
-#define SE7722_FPGA_IRQ_BASE 110
-
-#define MRSHPC_IRQ3 (SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_MRSHPC3)
-#define MRSHPC_IRQ2 (SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_MRSHPC2)
-#define MRSHPC_IRQ1 (SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_MRSHPC1)
-#define MRSHPC_IRQ0 (SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_MRSHPC0)
-#define SMC_IRQ (SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_SMC)
-#define USB_IRQ (SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_USB)
/* arch/sh/boards/se/7722/irq.c */
+extern unsigned int se7722_fpga_irq[];
+
void init_se7722_IRQ(void);
#define __IO_PREFIX se7722
diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile
index a2d0a40..0471a3e 100644
--- a/arch/sh/kernel/Makefile
+++ b/arch/sh/kernel/Makefile
@@ -9,8 +9,12 @@ ifdef CONFIG_FUNCTION_TRACER
CFLAGS_REMOVE_ftrace.o = -pg
endif
-obj-y := debugtraps.o dumpstack.o idle.o io.o io_generic.o irq.o \
- machvec.o nmi_debug.o process_$(BITS).o ptrace_$(BITS).o \
+CFLAGS_REMOVE_return_address.o = -pg
+
+obj-y := debugtraps.o dma-nommu.o dumpstack.o \
+ idle.o io.o io_generic.o irq.o \
+ irq_$(BITS).o machvec.o nmi_debug.o process_$(BITS).o \
+ ptrace_$(BITS).o return_address.o \
setup.o signal_$(BITS).o sys_sh.o sys_sh$(BITS).o \
syscalls_$(BITS).o time.o topology.o traps.o \
traps_$(BITS).o unwinder.o
@@ -28,13 +32,13 @@ obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-$(CONFIG_IO_TRAPPED) += io_trapped.o
obj-$(CONFIG_KPROBES) += kprobes.o
-obj-$(CONFIG_GENERIC_GPIO) += gpio.o
obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o
obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
obj-$(CONFIG_DUMP_CODE) += disassemble.o
obj-$(CONFIG_HIBERNATION) += swsusp.o
obj-$(CONFIG_DWARF_UNWINDER) += dwarf.o
+obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_callchain.o
obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) += localtimer.o
diff --git a/arch/sh/kernel/asm-offsets.c b/arch/sh/kernel/asm-offsets.c
index d218e80..08a2be7 100644
--- a/arch/sh/kernel/asm-offsets.c
+++ b/arch/sh/kernel/asm-offsets.c
@@ -34,5 +34,28 @@ int main(void)
DEFINE(PBE_NEXT, offsetof(struct pbe, next));
DEFINE(SWSUSP_ARCH_REGS_SIZE, sizeof(struct swsusp_arch_regs));
#endif
+
+ DEFINE(SH_SLEEP_MODE, offsetof(struct sh_sleep_data, mode));
+ DEFINE(SH_SLEEP_SF_PRE, offsetof(struct sh_sleep_data, sf_pre));
+ DEFINE(SH_SLEEP_SF_POST, offsetof(struct sh_sleep_data, sf_post));
+ DEFINE(SH_SLEEP_RESUME, offsetof(struct sh_sleep_data, resume));
+ DEFINE(SH_SLEEP_VBR, offsetof(struct sh_sleep_data, vbr));
+ DEFINE(SH_SLEEP_SPC, offsetof(struct sh_sleep_data, spc));
+ DEFINE(SH_SLEEP_SR, offsetof(struct sh_sleep_data, sr));
+ DEFINE(SH_SLEEP_SP, offsetof(struct sh_sleep_data, sp));
+ DEFINE(SH_SLEEP_BASE_ADDR, offsetof(struct sh_sleep_data, addr));
+ DEFINE(SH_SLEEP_BASE_DATA, offsetof(struct sh_sleep_data, data));
+ DEFINE(SH_SLEEP_REG_STBCR, offsetof(struct sh_sleep_regs, stbcr));
+ DEFINE(SH_SLEEP_REG_BAR, offsetof(struct sh_sleep_regs, bar));
+ DEFINE(SH_SLEEP_REG_PTEH, offsetof(struct sh_sleep_regs, pteh));
+ DEFINE(SH_SLEEP_REG_PTEL, offsetof(struct sh_sleep_regs, ptel));
+ DEFINE(SH_SLEEP_REG_TTB, offsetof(struct sh_sleep_regs, ttb));
+ DEFINE(SH_SLEEP_REG_TEA, offsetof(struct sh_sleep_regs, tea));
+ DEFINE(SH_SLEEP_REG_MMUCR, offsetof(struct sh_sleep_regs, mmucr));
+ DEFINE(SH_SLEEP_REG_PTEA, offsetof(struct sh_sleep_regs, ptea));
+ DEFINE(SH_SLEEP_REG_PASCR, offsetof(struct sh_sleep_regs, pascr));
+ DEFINE(SH_SLEEP_REG_IRMCR, offsetof(struct sh_sleep_regs, irmcr));
+ DEFINE(SH_SLEEP_REG_CCR, offsetof(struct sh_sleep_regs, ccr));
+ DEFINE(SH_SLEEP_REG_RAMCR, offsetof(struct sh_sleep_regs, ramcr));
return 0;
}
diff --git a/arch/sh/kernel/cpu/Makefile b/arch/sh/kernel/cpu/Makefile
index 3d6b931..d97c803 100644
--- a/arch/sh/kernel/cpu/Makefile
+++ b/arch/sh/kernel/cpu/Makefile
@@ -15,7 +15,6 @@ obj-$(CONFIG_ARCH_SHMOBILE) += shmobile/
# Common interfaces.
-obj-$(CONFIG_UBC_WAKEUP) += ubc.o
obj-$(CONFIG_SH_ADC) += adc.o
obj-$(CONFIG_SH_CLK_CPG) += clock-cpg.o
diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c
index e932ebe..89b4b76 100644
--- a/arch/sh/kernel/cpu/init.c
+++ b/arch/sh/kernel/cpu/init.c
@@ -75,16 +75,11 @@ static void __init expmask_init(void)
/*
* Future proofing.
*
- * Disable support for slottable sleep instruction
- * and non-nop instructions in the rte delay slot.
+ * Disable support for slottable sleep instruction, non-nop
+ * instructions in the rte delay slot, and associative writes to
+ * the memory-mapped cache array.
*/
- expmask &= ~(EXPMASK_RTEDS | EXPMASK_BRDSSLP);
-
- /*
- * Enable associative writes to the memory-mapped cache array
- * until the cache flush ops have been rewritten.
- */
- expmask |= EXPMASK_MMCAW;
+ expmask &= ~(EXPMASK_RTEDS | EXPMASK_BRDSSLP | EXPMASK_MMCAW);
__raw_writel(expmask, EXPMASK);
ctrl_barrier();
@@ -311,12 +306,12 @@ asmlinkage void __init sh_cpu_init(void)
if (fpu_disabled) {
printk("FPU Disabled\n");
current_cpu_data.flags &= ~CPU_HAS_FPU;
- disable_fpu();
}
/* FPU initialization */
+ disable_fpu();
if ((current_cpu_data.flags & CPU_HAS_FPU)) {
- clear_thread_flag(TIF_USEDFPU);
+ current_thread_info()->status &= ~TS_USEDFPU;
clear_used_math();
}
@@ -338,17 +333,6 @@ asmlinkage void __init sh_cpu_init(void)
}
#endif
- /*
- * Some brain-damaged loaders decided it would be a good idea to put
- * the UBC to sleep. This causes some issues when it comes to things
- * like PTRACE_SINGLESTEP or doing hardware watchpoints in GDB. So ..
- * we wake it up and hope that all is well.
- */
-#ifdef CONFIG_SUPERH32
- if (raw_smp_processor_id() == 0)
- ubc_wakeup();
-#endif
-
speculative_execution_init();
expmask_init();
}
diff --git a/arch/sh/kernel/cpu/sh2a/fpu.c b/arch/sh/kernel/cpu/sh2a/fpu.c
index 6df2fb9..d395ce5 100644
--- a/arch/sh/kernel/cpu/sh2a/fpu.c
+++ b/arch/sh/kernel/cpu/sh2a/fpu.c
@@ -25,14 +25,12 @@
/*
* Save FPU registers onto task structure.
- * Assume called with FPU enabled (SR.FD=0).
*/
void
-save_fpu(struct task_struct *tsk, struct pt_regs *regs)
+save_fpu(struct task_struct *tsk)
{
unsigned long dummy;
- clear_tsk_thread_flag(tsk, TIF_USEDFPU);
enable_fpu();
asm volatile("sts.l fpul, @-%0\n\t"
"sts.l fpscr, @-%0\n\t"
@@ -60,7 +58,6 @@ save_fpu(struct task_struct *tsk, struct pt_regs *regs)
: "memory");
disable_fpu();
- release_fpu(regs);
}
static void
@@ -598,31 +595,31 @@ BUILD_TRAP_HANDLER(fpu_error)
struct task_struct *tsk = current;
TRAP_HANDLER_DECL;
- save_fpu(tsk, regs);
+ __unlazy_fpu(tsk, regs);
if (ieee_fpe_handler(regs)) {
tsk->thread.fpu.hard.fpscr &=
~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK);
grab_fpu(regs);
restore_fpu(tsk);
- set_tsk_thread_flag(tsk, TIF_USEDFPU);
+ task_thread_info(tsk)->status |= TS_USEDFPU;
return;
}
force_sig(SIGFPE, tsk);
}
-BUILD_TRAP_HANDLER(fpu_state_restore)
+void fpu_state_restore(struct pt_regs *regs)
{
struct task_struct *tsk = current;
- TRAP_HANDLER_DECL;
grab_fpu(regs);
- if (!user_mode(regs)) {
+ if (unlikely(!user_mode(regs))) {
printk(KERN_ERR "BUG: FPU is used in kernel mode.\n");
+ BUG();
return;
}
- if (used_math()) {
+ if (likely(used_math())) {
/* Using the FPU again. */
restore_fpu(tsk);
} else {
@@ -630,5 +627,13 @@ BUILD_TRAP_HANDLER(fpu_state_restore)
fpu_init();
set_used_math();
}
- set_tsk_thread_flag(tsk, TIF_USEDFPU);
+ task_thread_info(tsk)->status |= TS_USEDFPU;
+ tsk->fpu_counter++;
+}
+
+BUILD_TRAP_HANDLER(fpu_state_restore)
+{
+ TRAP_HANDLER_DECL;
+
+ fpu_state_restore(regs);
}
diff --git a/arch/sh/kernel/cpu/sh3/entry.S b/arch/sh/kernel/cpu/sh3/entry.S
index bb407ef..3f7e2a2 100644
--- a/arch/sh/kernel/cpu/sh3/entry.S
+++ b/arch/sh/kernel/cpu/sh3/entry.S
@@ -297,41 +297,8 @@ ENTRY(vbr_base)
!
.balign 256,0,256
general_exception:
-#ifndef CONFIG_CPU_SUBTYPE_SHX3
bra handle_exception
sts pr, k3 ! save original pr value in k3
-#else
- mov.l 1f, k4
- mov.l @k4, k4
-
- ! Is EXPEVT larger than 0x800?
- mov #0x8, k0
- shll8 k0
- cmp/hs k0, k4
- bf 0f
-
- ! then add 0x580 (k2 is 0xd80 or 0xda0)
- mov #0x58, k0
- shll2 k0
- shll2 k0
- add k0, k4
-0:
- ! Setup stack and save DSP context (k0 contains original r15 on return)
- bsr prepare_stack
- nop
-
- ! Save registers / Switch to bank 0
- mov k4, k2 ! keep vector in k2
- mov.l 1f, k4 ! SR bits to clear in k4
- bsr save_regs ! needs original pr value in k3
- nop
-
- bra handle_exception_special
- nop
-
- .align 2
-1: .long EXPEVT
-#endif
! prepare_stack()
! - roll back gRB
diff --git a/arch/sh/kernel/cpu/sh4/Makefile b/arch/sh/kernel/cpu/sh4/Makefile
index 203b183..3a1dbc7 100644
--- a/arch/sh/kernel/cpu/sh4/Makefile
+++ b/arch/sh/kernel/cpu/sh4/Makefile
@@ -9,6 +9,11 @@ obj-$(CONFIG_HIBERNATION) += $(addprefix ../sh3/, swsusp.o)
obj-$(CONFIG_SH_FPU) += fpu.o softfloat.o
obj-$(CONFIG_SH_STORE_QUEUES) += sq.o
+# Perf events
+perf-$(CONFIG_CPU_SUBTYPE_SH7750) := perf_event.o
+perf-$(CONFIG_CPU_SUBTYPE_SH7750S) := perf_event.o
+perf-$(CONFIG_CPU_SUBTYPE_SH7091) := perf_event.o
+
# CPU subtype setup
obj-$(CONFIG_CPU_SUBTYPE_SH7750) += setup-sh7750.o
obj-$(CONFIG_CPU_SUBTYPE_SH7750R) += setup-sh7750.o
@@ -27,4 +32,5 @@ endif
# Additional clocks by subtype
clock-$(CONFIG_CPU_SUBTYPE_SH4_202) += clock-sh4-202.o
-obj-y += $(clock-y)
+obj-y += $(clock-y)
+obj-$(CONFIG_PERF_EVENTS) += $(perf-y)
diff --git a/arch/sh/kernel/cpu/sh4/fpu.c b/arch/sh/kernel/cpu/sh4/fpu.c
index e3ea541..e97857a 100644
--- a/arch/sh/kernel/cpu/sh4/fpu.c
+++ b/arch/sh/kernel/cpu/sh4/fpu.c
@@ -41,13 +41,11 @@ static unsigned int fpu_exception_flags;
/*
* Save FPU registers onto task structure.
- * Assume called with FPU enabled (SR.FD=0).
*/
-void save_fpu(struct task_struct *tsk, struct pt_regs *regs)
+void save_fpu(struct task_struct *tsk)
{
unsigned long dummy;
- clear_tsk_thread_flag(tsk, TIF_USEDFPU);
enable_fpu();
asm volatile ("sts.l fpul, @-%0\n\t"
"sts.l fpscr, @-%0\n\t"
@@ -92,7 +90,6 @@ void save_fpu(struct task_struct *tsk, struct pt_regs *regs)
:"memory");
disable_fpu();
- release_fpu(regs);
}
static void restore_fpu(struct task_struct *tsk)
@@ -285,7 +282,6 @@ static int ieee_fpe_handler(struct pt_regs *regs)
/* fcnvsd */
struct task_struct *tsk = current;
- save_fpu(tsk, regs);
if ((tsk->thread.fpu.hard.fpscr & FPSCR_CAUSE_ERROR))
/* FPU error */
denormal_to_double(&tsk->thread.fpu.hard,
@@ -462,7 +458,7 @@ BUILD_TRAP_HANDLER(fpu_error)
struct task_struct *tsk = current;
TRAP_HANDLER_DECL;
- save_fpu(tsk, regs);
+ __unlazy_fpu(tsk, regs);
fpu_exception_flags = 0;
if (ieee_fpe_handler(regs)) {
tsk->thread.fpu.hard.fpscr &=
@@ -473,7 +469,7 @@ BUILD_TRAP_HANDLER(fpu_error)
tsk->thread.fpu.hard.fpscr |= (fpu_exception_flags >> 10);
grab_fpu(regs);
restore_fpu(tsk);
- set_tsk_thread_flag(tsk, TIF_USEDFPU);
+ task_thread_info(tsk)->status |= TS_USEDFPU;
if ((((tsk->thread.fpu.hard.fpscr & FPSCR_ENABLE_MASK) >> 7) &
(fpu_exception_flags >> 2)) == 0) {
return;
@@ -483,18 +479,18 @@ BUILD_TRAP_HANDLER(fpu_error)
force_sig(SIGFPE, tsk);
}
-BUILD_TRAP_HANDLER(fpu_state_restore)
+void fpu_state_restore(struct pt_regs *regs)
{
struct task_struct *tsk = current;
- TRAP_HANDLER_DECL;
grab_fpu(regs);
- if (!user_mode(regs)) {
+ if (unlikely(!user_mode(regs))) {
printk(KERN_ERR "BUG: FPU is used in kernel mode.\n");
+ BUG();
return;
}
- if (used_math()) {
+ if (likely(used_math())) {
/* Using the FPU again. */
restore_fpu(tsk);
} else {
@@ -502,5 +498,13 @@ BUILD_TRAP_HANDLER(fpu_state_restore)
fpu_init();
set_used_math();
}
- set_tsk_thread_flag(tsk, TIF_USEDFPU);
+ task_thread_info(tsk)->status |= TS_USEDFPU;
+ tsk->fpu_counter++;
+}
+
+BUILD_TRAP_HANDLER(fpu_state_restore)
+{
+ TRAP_HANDLER_DECL;
+
+ fpu_state_restore(regs);
}
diff --git a/arch/sh/kernel/cpu/sh4/perf_event.c b/arch/sh/kernel/cpu/sh4/perf_event.c
new file mode 100644
index 0000000..7f9ecc9
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4/perf_event.c
@@ -0,0 +1,253 @@
+/*
+ * Performance events support for SH7750-style performance counters
+ *
+ * Copyright (C) 2009 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/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/perf_event.h>
+#include <asm/processor.h>
+
+#define PM_CR_BASE 0xff000084 /* 16-bit */
+#define PM_CTR_BASE 0xff100004 /* 32-bit */
+
+#define PMCR(n) (PM_CR_BASE + ((n) * 0x04))
+#define PMCTRH(n) (PM_CTR_BASE + 0x00 + ((n) * 0x08))
+#define PMCTRL(n) (PM_CTR_BASE + 0x04 + ((n) * 0x08))
+
+#define PMCR_PMM_MASK 0x0000003f
+
+#define PMCR_CLKF 0x00000100
+#define PMCR_PMCLR 0x00002000
+#define PMCR_PMST 0x00004000
+#define PMCR_PMEN 0x00008000
+
+static struct sh_pmu sh7750_pmu;
+
+/*
+ * There are a number of events supported by each counter (33 in total).
+ * Since we have 2 counters, each counter will take the event code as it
+ * corresponds to the PMCR PMM setting. Each counter can be configured
+ * independently.
+ *
+ * Event Code Description
+ * ---------- -----------
+ *
+ * 0x01 Operand read access
+ * 0x02 Operand write access
+ * 0x03 UTLB miss
+ * 0x04 Operand cache read miss
+ * 0x05 Operand cache write miss
+ * 0x06 Instruction fetch (w/ cache)
+ * 0x07 Instruction TLB miss
+ * 0x08 Instruction cache miss
+ * 0x09 All operand accesses
+ * 0x0a All instruction accesses
+ * 0x0b OC RAM operand access
+ * 0x0d On-chip I/O space access
+ * 0x0e Operand access (r/w)
+ * 0x0f Operand cache miss (r/w)
+ * 0x10 Branch instruction
+ * 0x11 Branch taken
+ * 0x12 BSR/BSRF/JSR
+ * 0x13 Instruction execution
+ * 0x14 Instruction execution in parallel
+ * 0x15 FPU Instruction execution
+ * 0x16 Interrupt
+ * 0x17 NMI
+ * 0x18 trapa instruction execution
+ * 0x19 UBCA match
+ * 0x1a UBCB match
+ * 0x21 Instruction cache fill
+ * 0x22 Operand cache fill
+ * 0x23 Elapsed time
+ * 0x24 Pipeline freeze by I-cache miss
+ * 0x25 Pipeline freeze by D-cache miss
+ * 0x27 Pipeline freeze by branch instruction
+ * 0x28 Pipeline freeze by CPU register
+ * 0x29 Pipeline freeze by FPU
+ */
+
+static const int sh7750_general_events[] = {
+ [PERF_COUNT_HW_CPU_CYCLES] = 0x0023,
+ [PERF_COUNT_HW_INSTRUCTIONS] = 0x000a,
+ [PERF_COUNT_HW_CACHE_REFERENCES] = 0x0006, /* I-cache */
+ [PERF_COUNT_HW_CACHE_MISSES] = 0x0008, /* I-cache */
+ [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x0010,
+ [PERF_COUNT_HW_BRANCH_MISSES] = -1,
+ [PERF_COUNT_HW_BUS_CYCLES] = -1,
+};
+
+#define C(x) PERF_COUNT_HW_CACHE_##x
+
+static const int sh7750_cache_events
+ [PERF_COUNT_HW_CACHE_MAX]
+ [PERF_COUNT_HW_CACHE_OP_MAX]
+ [PERF_COUNT_HW_CACHE_RESULT_MAX] =
+{
+ [ C(L1D) ] = {
+ [ C(OP_READ) ] = {
+ [ C(RESULT_ACCESS) ] = 0x0001,
+ [ C(RESULT_MISS) ] = 0x0004,
+ },
+ [ C(OP_WRITE) ] = {
+ [ C(RESULT_ACCESS) ] = 0x0002,
+ [ C(RESULT_MISS) ] = 0x0005,
+ },
+ [ C(OP_PREFETCH) ] = {
+ [ C(RESULT_ACCESS) ] = 0,
+ [ C(RESULT_MISS) ] = 0,
+ },
+ },
+
+ [ C(L1I) ] = {
+ [ C(OP_READ) ] = {
+ [ C(RESULT_ACCESS) ] = 0x0006,
+ [ C(RESULT_MISS) ] = 0x0008,
+ },
+ [ C(OP_WRITE) ] = {
+ [ C(RESULT_ACCESS) ] = -1,
+ [ C(RESULT_MISS) ] = -1,
+ },
+ [ C(OP_PREFETCH) ] = {
+ [ C(RESULT_ACCESS) ] = 0,
+ [ C(RESULT_MISS) ] = 0,
+ },
+ },
+
+ [ C(LL) ] = {
+ [ C(OP_READ) ] = {
+ [ C(RESULT_ACCESS) ] = 0,
+ [ C(RESULT_MISS) ] = 0,
+ },
+ [ C(OP_WRITE) ] = {
+ [ C(RESULT_ACCESS) ] = 0,
+ [ C(RESULT_MISS) ] = 0,
+ },
+ [ C(OP_PREFETCH) ] = {
+ [ C(RESULT_ACCESS) ] = 0,
+ [ C(RESULT_MISS) ] = 0,
+ },
+ },
+
+ [ C(DTLB) ] = {
+ [ C(OP_READ) ] = {
+ [ C(RESULT_ACCESS) ] = 0,
+ [ C(RESULT_MISS) ] = 0x0003,
+ },
+ [ C(OP_WRITE) ] = {
+ [ C(RESULT_ACCESS) ] = 0,
+ [ C(RESULT_MISS) ] = 0,
+ },
+ [ C(OP_PREFETCH) ] = {
+ [ C(RESULT_ACCESS) ] = 0,
+ [ C(RESULT_MISS) ] = 0,
+ },
+ },
+
+ [ C(ITLB) ] = {
+ [ C(OP_READ) ] = {
+ [ C(RESULT_ACCESS) ] = 0,
+ [ C(RESULT_MISS) ] = 0x0007,
+ },
+ [ C(OP_WRITE) ] = {
+ [ C(RESULT_ACCESS) ] = -1,
+ [ C(RESULT_MISS) ] = -1,
+ },
+ [ C(OP_PREFETCH) ] = {
+ [ C(RESULT_ACCESS) ] = -1,
+ [ C(RESULT_MISS) ] = -1,
+ },
+ },
+
+ [ C(BPU) ] = {
+ [ C(OP_READ) ] = {
+ [ C(RESULT_ACCESS) ] = -1,
+ [ C(RESULT_MISS) ] = -1,
+ },
+ [ C(OP_WRITE) ] = {
+ [ C(RESULT_ACCESS) ] = -1,
+ [ C(RESULT_MISS) ] = -1,
+ },
+ [ C(OP_PREFETCH) ] = {
+ [ C(RESULT_ACCESS) ] = -1,
+ [ C(RESULT_MISS) ] = -1,
+ },
+ },
+};
+
+static int sh7750_event_map(int event)
+{
+ return sh7750_general_events[event];
+}
+
+static u64 sh7750_pmu_read(int idx)
+{
+ return (u64)((u64)(__raw_readl(PMCTRH(idx)) & 0xffff) << 32) |
+ __raw_readl(PMCTRL(idx));
+}
+
+static void sh7750_pmu_disable(struct hw_perf_event *hwc, int idx)
+{
+ unsigned int tmp;
+
+ tmp = __raw_readw(PMCR(idx));
+ tmp &= ~(PMCR_PMM_MASK | PMCR_PMEN);
+ __raw_writew(tmp, PMCR(idx));
+}
+
+static void sh7750_pmu_enable(struct hw_perf_event *hwc, int idx)
+{
+ __raw_writew(__raw_readw(PMCR(idx)) | PMCR_PMCLR, PMCR(idx));
+ __raw_writew(hwc->config | PMCR_PMEN | PMCR_PMST, PMCR(idx));
+}
+
+static void sh7750_pmu_disable_all(void)
+{
+ int i;
+
+ for (i = 0; i < sh7750_pmu.num_events; i++)
+ __raw_writew(__raw_readw(PMCR(i)) & ~PMCR_PMEN, PMCR(i));
+}
+
+static void sh7750_pmu_enable_all(void)
+{
+ int i;
+
+ for (i = 0; i < sh7750_pmu.num_events; i++)
+ __raw_writew(__raw_readw(PMCR(i)) | PMCR_PMEN, PMCR(i));
+}
+
+static struct sh_pmu sh7750_pmu = {
+ .name = "SH7750",
+ .num_events = 2,
+ .event_map = sh7750_event_map,
+ .max_events = ARRAY_SIZE(sh7750_general_events),
+ .raw_event_mask = PMCR_PMM_MASK,
+ .cache_events = &sh7750_cache_events,
+ .read = sh7750_pmu_read,
+ .disable = sh7750_pmu_disable,
+ .enable = sh7750_pmu_enable,
+ .disable_all = sh7750_pmu_disable_all,
+ .enable_all = sh7750_pmu_enable_all,
+};
+
+static int __init sh7750_pmu_init(void)
+{
+ /*
+ * Make sure this CPU actually has perf counters.
+ */
+ if (!(boot_cpu_data.flags & CPU_HAS_PERF_COUNTER)) {
+ pr_notice("HW perf events unsupported, software events only.\n");
+ return -ENODEV;
+ }
+
+ return register_sh_pmu(&sh7750_pmu);
+}
+arch_initcall(sh7750_pmu_init);
diff --git a/arch/sh/kernel/cpu/sh4a/Makefile b/arch/sh/kernel/cpu/sh4a/Makefile
index 490d5dc..33bab47 100644
--- a/arch/sh/kernel/cpu/sh4a/Makefile
+++ b/arch/sh/kernel/cpu/sh4a/Makefile
@@ -44,3 +44,4 @@ pinmux-$(CONFIG_CPU_SUBTYPE_SH7786) := pinmux-sh7786.o
obj-y += $(clock-y)
obj-$(CONFIG_SMP) += $(smp-y)
obj-$(CONFIG_GENERIC_GPIO) += $(pinmux-y)
+obj-$(CONFIG_PERF_EVENTS) += perf_event.o
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7724.c b/arch/sh/kernel/cpu/sh4a/clock-sh7724.c
index dfe9192..9db7438 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7724.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7724.c
@@ -152,7 +152,7 @@ struct clk div6_clks[] = {
SH_CLK_DIV6("fsia_clk", &div3_clk, FCLKACR, 0),
SH_CLK_DIV6("fsib_clk", &div3_clk, FCLKBCR, 0),
SH_CLK_DIV6("irda_clk", &div3_clk, IRDACLKCR, 0),
- SH_CLK_DIV6("spu_clk", &div3_clk, SPUCLKCR, 0),
+ SH_CLK_DIV6("spu_clk", &div3_clk, SPUCLKCR, CLK_ENABLE_ON_INIT),
};
#define R_CLK (&r_clk)
diff --git a/arch/sh/kernel/cpu/sh4a/perf_event.c b/arch/sh/kernel/cpu/sh4a/perf_event.c
new file mode 100644
index 0000000..eddc219
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4a/perf_event.c
@@ -0,0 +1,269 @@
+/*
+ * Performance events support for SH-4A performance counters
+ *
+ * Copyright (C) 2009 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/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/perf_event.h>
+#include <asm/processor.h>
+
+#define PPC_CCBR(idx) (0xff200800 + (sizeof(u32) * idx))
+#define PPC_PMCTR(idx) (0xfc100000 + (sizeof(u32) * idx))
+
+#define CCBR_CIT_MASK (0x7ff << 6)
+#define CCBR_DUC (1 << 3)
+#define CCBR_CMDS (1 << 1)
+#define CCBR_PPCE (1 << 0)
+
+#define PPC_PMCAT 0xfc100080
+
+#define PMCAT_OVF3 (1 << 27)
+#define PMCAT_CNN3 (1 << 26)
+#define PMCAT_CLR3 (1 << 25)
+#define PMCAT_OVF2 (1 << 19)
+#define PMCAT_CLR2 (1 << 17)
+#define PMCAT_OVF1 (1 << 11)
+#define PMCAT_CNN1 (1 << 10)
+#define PMCAT_CLR1 (1 << 9)
+#define PMCAT_OVF0 (1 << 3)
+#define PMCAT_CLR0 (1 << 1)
+
+static struct sh_pmu sh4a_pmu;
+
+/*
+ * Supported raw event codes:
+ *
+ * Event Code Description
+ * ---------- -----------
+ *
+ * 0x0000 number of elapsed cycles
+ * 0x0200 number of elapsed cycles in privileged mode
+ * 0x0280 number of elapsed cycles while SR.BL is asserted
+ * 0x0202 instruction execution
+ * 0x0203 instruction execution in parallel
+ * 0x0204 number of unconditional branches
+ * 0x0208 number of exceptions
+ * 0x0209 number of interrupts
+ * 0x0220 UTLB miss caused by instruction fetch
+ * 0x0222 UTLB miss caused by operand access
+ * 0x02a0 number of ITLB misses
+ * 0x0028 number of accesses to instruction memories
+ * 0x0029 number of accesses to instruction cache
+ * 0x002a instruction cache miss
+ * 0x022e number of access to instruction X/Y memory
+ * 0x0030 number of reads to operand memories
+ * 0x0038 number of writes to operand memories
+ * 0x0031 number of operand cache read accesses
+ * 0x0039 number of operand cache write accesses
+ * 0x0032 operand cache read miss
+ * 0x003a operand cache write miss
+ * 0x0236 number of reads to operand X/Y memory
+ * 0x023e number of writes to operand X/Y memory
+ * 0x0237 number of reads to operand U memory
+ * 0x023f number of writes to operand U memory
+ * 0x0337 number of U memory read buffer misses
+ * 0x02b4 number of wait cycles due to operand read access
+ * 0x02bc number of wait cycles due to operand write access
+ * 0x0033 number of wait cycles due to operand cache read miss
+ * 0x003b number of wait cycles due to operand cache write miss
+ */
+
+/*
+ * Special reserved bits used by hardware emulators, read values will
+ * vary, but writes must always be 0.
+ */
+#define PMCAT_EMU_CLR_MASK ((1 << 24) | (1 << 16) | (1 << 8) | (1 << 0))
+
+static const int sh4a_general_events[] = {
+ [PERF_COUNT_HW_CPU_CYCLES] = 0x0000,
+ [PERF_COUNT_HW_INSTRUCTIONS] = 0x0202,
+ [PERF_COUNT_HW_CACHE_REFERENCES] = 0x0029, /* I-cache */
+ [PERF_COUNT_HW_CACHE_MISSES] = 0x002a, /* I-cache */
+ [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x0204,
+ [PERF_COUNT_HW_BRANCH_MISSES] = -1,
+ [PERF_COUNT_HW_BUS_CYCLES] = -1,
+};
+
+#define C(x) PERF_COUNT_HW_CACHE_##x
+
+static const int sh4a_cache_events
+ [PERF_COUNT_HW_CACHE_MAX]
+ [PERF_COUNT_HW_CACHE_OP_MAX]
+ [PERF_COUNT_HW_CACHE_RESULT_MAX] =
+{
+ [ C(L1D) ] = {
+ [ C(OP_READ) ] = {
+ [ C(RESULT_ACCESS) ] = 0x0031,
+ [ C(RESULT_MISS) ] = 0x0032,
+ },
+ [ C(OP_WRITE) ] = {
+ [ C(RESULT_ACCESS) ] = 0x0039,
+ [ C(RESULT_MISS) ] = 0x003a,
+ },
+ [ C(OP_PREFETCH) ] = {
+ [ C(RESULT_ACCESS) ] = 0,
+ [ C(RESULT_MISS) ] = 0,
+ },
+ },
+
+ [ C(L1I) ] = {
+ [ C(OP_READ) ] = {
+ [ C(RESULT_ACCESS) ] = 0x0029,
+ [ C(RESULT_MISS) ] = 0x002a,
+ },
+ [ C(OP_WRITE) ] = {
+ [ C(RESULT_ACCESS) ] = -1,
+ [ C(RESULT_MISS) ] = -1,
+ },
+ [ C(OP_PREFETCH) ] = {
+ [ C(RESULT_ACCESS) ] = 0,
+ [ C(RESULT_MISS) ] = 0,
+ },
+ },
+
+ [ C(LL) ] = {
+ [ C(OP_READ) ] = {
+ [ C(RESULT_ACCESS) ] = 0x0030,
+ [ C(RESULT_MISS) ] = 0,
+ },
+ [ C(OP_WRITE) ] = {
+ [ C(RESULT_ACCESS) ] = 0x0038,
+ [ C(RESULT_MISS) ] = 0,
+ },
+ [ C(OP_PREFETCH) ] = {
+ [ C(RESULT_ACCESS) ] = 0,
+ [ C(RESULT_MISS) ] = 0,
+ },
+ },
+
+ [ C(DTLB) ] = {
+ [ C(OP_READ) ] = {
+ [ C(RESULT_ACCESS) ] = 0x0222,
+ [ C(RESULT_MISS) ] = 0x0220,
+ },
+ [ C(OP_WRITE) ] = {
+ [ C(RESULT_ACCESS) ] = 0,
+ [ C(RESULT_MISS) ] = 0,
+ },
+ [ C(OP_PREFETCH) ] = {
+ [ C(RESULT_ACCESS) ] = 0,
+ [ C(RESULT_MISS) ] = 0,
+ },
+ },
+
+ [ C(ITLB) ] = {
+ [ C(OP_READ) ] = {
+ [ C(RESULT_ACCESS) ] = 0,
+ [ C(RESULT_MISS) ] = 0x02a0,
+ },
+ [ C(OP_WRITE) ] = {
+ [ C(RESULT_ACCESS) ] = -1,
+ [ C(RESULT_MISS) ] = -1,
+ },
+ [ C(OP_PREFETCH) ] = {
+ [ C(RESULT_ACCESS) ] = -1,
+ [ C(RESULT_MISS) ] = -1,
+ },
+ },
+
+ [ C(BPU) ] = {
+ [ C(OP_READ) ] = {
+ [ C(RESULT_ACCESS) ] = -1,
+ [ C(RESULT_MISS) ] = -1,
+ },
+ [ C(OP_WRITE) ] = {
+ [ C(RESULT_ACCESS) ] = -1,
+ [ C(RESULT_MISS) ] = -1,
+ },
+ [ C(OP_PREFETCH) ] = {
+ [ C(RESULT_ACCESS) ] = -1,
+ [ C(RESULT_MISS) ] = -1,
+ },
+ },
+};
+
+static int sh4a_event_map(int event)
+{
+ return sh4a_general_events[event];
+}
+
+static u64 sh4a_pmu_read(int idx)
+{
+ return __raw_readl(PPC_PMCTR(idx));
+}
+
+static void sh4a_pmu_disable(struct hw_perf_event *hwc, int idx)
+{
+ unsigned int tmp;
+
+ tmp = __raw_readl(PPC_CCBR(idx));
+ tmp &= ~(CCBR_CIT_MASK | CCBR_DUC);
+ __raw_writel(tmp, PPC_CCBR(idx));
+}
+
+static void sh4a_pmu_enable(struct hw_perf_event *hwc, int idx)
+{
+ unsigned int tmp;
+
+ tmp = __raw_readl(PPC_PMCAT);
+ tmp &= ~PMCAT_EMU_CLR_MASK;
+ tmp |= idx ? PMCAT_CLR1 : PMCAT_CLR0;
+ __raw_writel(tmp, PPC_PMCAT);
+
+ tmp = __raw_readl(PPC_CCBR(idx));
+ tmp |= (hwc->config << 6) | CCBR_CMDS | CCBR_PPCE;
+ __raw_writel(tmp, PPC_CCBR(idx));
+
+ __raw_writel(__raw_readl(PPC_CCBR(idx)) | CCBR_DUC, PPC_CCBR(idx));
+}
+
+static void sh4a_pmu_disable_all(void)
+{
+ int i;
+
+ for (i = 0; i < sh4a_pmu.num_events; i++)
+ __raw_writel(__raw_readl(PPC_CCBR(i)) & ~CCBR_DUC, PPC_CCBR(i));
+}
+
+static void sh4a_pmu_enable_all(void)
+{
+ int i;
+
+ for (i = 0; i < sh4a_pmu.num_events; i++)
+ __raw_writel(__raw_readl(PPC_CCBR(i)) | CCBR_DUC, PPC_CCBR(i));
+}
+
+static struct sh_pmu sh4a_pmu = {
+ .name = "SH-4A",
+ .num_events = 2,
+ .event_map = sh4a_event_map,
+ .max_events = ARRAY_SIZE(sh4a_general_events),
+ .raw_event_mask = 0x3ff,
+ .cache_events = &sh4a_cache_events,
+ .read = sh4a_pmu_read,
+ .disable = sh4a_pmu_disable,
+ .enable = sh4a_pmu_enable,
+ .disable_all = sh4a_pmu_disable_all,
+ .enable_all = sh4a_pmu_enable_all,
+};
+
+static int __init sh4a_pmu_init(void)
+{
+ /*
+ * Make sure this CPU actually has perf counters.
+ */
+ if (!(boot_cpu_data.flags & CPU_HAS_PERF_COUNTER)) {
+ pr_notice("HW perf events unsupported, software events only.\n");
+ return -ENODEV;
+ }
+
+ return register_sh_pmu(&sh4a_pmu);
+}
+arch_initcall(sh4a_pmu_init);
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c
index f3851fd..845e89c 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c
@@ -20,6 +20,8 @@
#include <linux/uio_driver.h>
#include <linux/sh_timer.h>
#include <linux/io.h>
+#include <linux/notifier.h>
+#include <asm/suspend.h>
#include <asm/clock.h>
#include <asm/mmzone.h>
#include <cpu/sh7724.h>
@@ -202,7 +204,7 @@ static struct resource veu0_resources[] = {
[0] = {
.name = "VEU3F0",
.start = 0xfe920000,
- .end = 0xfe9200cb - 1,
+ .end = 0xfe9200cb,
.flags = IORESOURCE_MEM,
},
[1] = {
@@ -234,7 +236,7 @@ static struct resource veu1_resources[] = {
[0] = {
.name = "VEU3F1",
.start = 0xfe924000,
- .end = 0xfe9240cb - 1,
+ .end = 0xfe9240cb,
.flags = IORESOURCE_MEM,
},
[1] = {
@@ -523,6 +525,70 @@ static struct platform_device jpu_device = {
},
};
+/* SPU2DSP0 */
+static struct uio_info spu0_platform_data = {
+ .name = "SPU2DSP0",
+ .version = "0",
+ .irq = 86,
+};
+
+static struct resource spu0_resources[] = {
+ [0] = {
+ .name = "SPU2DSP0",
+ .start = 0xFE200000,
+ .end = 0xFE2FFFFF,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ /* place holder for contiguous memory */
+ },
+};
+
+static struct platform_device spu0_device = {
+ .name = "uio_pdrv_genirq",
+ .id = 4,
+ .dev = {
+ .platform_data = &spu0_platform_data,
+ },
+ .resource = spu0_resources,
+ .num_resources = ARRAY_SIZE(spu0_resources),
+ .archdata = {
+ .hwblk_id = HWBLK_SPU,
+ },
+};
+
+/* SPU2DSP1 */
+static struct uio_info spu1_platform_data = {
+ .name = "SPU2DSP1",
+ .version = "0",
+ .irq = 87,
+};
+
+static struct resource spu1_resources[] = {
+ [0] = {
+ .name = "SPU2DSP1",
+ .start = 0xFE300000,
+ .end = 0xFE3FFFFF,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ /* place holder for contiguous memory */
+ },
+};
+
+static struct platform_device spu1_device = {
+ .name = "uio_pdrv_genirq",
+ .id = 5,
+ .dev = {
+ .platform_data = &spu1_platform_data,
+ },
+ .resource = spu1_resources,
+ .num_resources = ARRAY_SIZE(spu1_resources),
+ .archdata = {
+ .hwblk_id = HWBLK_SPU,
+ },
+};
+
static struct platform_device *sh7724_devices[] __initdata = {
&cmt_device,
&tmu0_device,
@@ -539,6 +605,8 @@ static struct platform_device *sh7724_devices[] __initdata = {
&veu0_device,
&veu1_device,
&jpu_device,
+ &spu0_device,
+ &spu1_device,
};
static int __init sh7724_devices_setup(void)
@@ -547,6 +615,8 @@ static int __init sh7724_devices_setup(void)
platform_resource_setup_memory(&veu0_device, "veu0", 2 << 20);
platform_resource_setup_memory(&veu1_device, "veu1", 2 << 20);
platform_resource_setup_memory(&jpu_device, "jpu", 2 << 20);
+ platform_resource_setup_memory(&spu0_device, "spu0", 2 << 20);
+ platform_resource_setup_memory(&spu1_device, "spu1", 2 << 20);
return platform_add_devices(sh7724_devices,
ARRAY_SIZE(sh7724_devices));
@@ -827,3 +897,193 @@ void __init plat_irq_setup(void)
{
register_intc_controller(&intc_desc);
}
+
+static struct {
+ /* BSC */
+ unsigned long mmselr;
+ unsigned long cs0bcr;
+ unsigned long cs4bcr;
+ unsigned long cs5abcr;
+ unsigned long cs5bbcr;
+ unsigned long cs6abcr;
+ unsigned long cs6bbcr;
+ unsigned long cs4wcr;
+ unsigned long cs5awcr;
+ unsigned long cs5bwcr;
+ unsigned long cs6awcr;
+ unsigned long cs6bwcr;
+ /* INTC */
+ unsigned short ipra;
+ unsigned short iprb;
+ unsigned short iprc;
+ unsigned short iprd;
+ unsigned short ipre;
+ unsigned short iprf;
+ unsigned short iprg;
+ unsigned short iprh;
+ unsigned short ipri;
+ unsigned short iprj;
+ unsigned short iprk;
+ unsigned short iprl;
+ unsigned char imr0;
+ unsigned char imr1;
+ unsigned char imr2;
+ unsigned char imr3;
+ unsigned char imr4;
+ unsigned char imr5;
+ unsigned char imr6;
+ unsigned char imr7;
+ unsigned char imr8;
+ unsigned char imr9;
+ unsigned char imr10;
+ unsigned char imr11;
+ unsigned char imr12;
+ /* RWDT */
+ unsigned short rwtcnt;
+ unsigned short rwtcsr;
+ /* CPG */
+ unsigned long irdaclk;
+ unsigned long spuclk;
+} sh7724_rstandby_state;
+
+static int sh7724_pre_sleep_notifier_call(struct notifier_block *nb,
+ unsigned long flags, void *unused)
+{
+ if (!(flags & SUSP_SH_RSTANDBY))
+ return NOTIFY_DONE;
+
+ /* BCR */
+ sh7724_rstandby_state.mmselr = __raw_readl(0xff800020); /* MMSELR */
+ sh7724_rstandby_state.mmselr |= 0xa5a50000;
+ sh7724_rstandby_state.cs0bcr = __raw_readl(0xfec10004); /* CS0BCR */
+ sh7724_rstandby_state.cs4bcr = __raw_readl(0xfec10010); /* CS4BCR */
+ sh7724_rstandby_state.cs5abcr = __raw_readl(0xfec10014); /* CS5ABCR */
+ sh7724_rstandby_state.cs5bbcr = __raw_readl(0xfec10018); /* CS5BBCR */
+ sh7724_rstandby_state.cs6abcr = __raw_readl(0xfec1001c); /* CS6ABCR */
+ sh7724_rstandby_state.cs6bbcr = __raw_readl(0xfec10020); /* CS6BBCR */
+ sh7724_rstandby_state.cs4wcr = __raw_readl(0xfec10030); /* CS4WCR */
+ sh7724_rstandby_state.cs5awcr = __raw_readl(0xfec10034); /* CS5AWCR */
+ sh7724_rstandby_state.cs5bwcr = __raw_readl(0xfec10038); /* CS5BWCR */
+ sh7724_rstandby_state.cs6awcr = __raw_readl(0xfec1003c); /* CS6AWCR */
+ sh7724_rstandby_state.cs6bwcr = __raw_readl(0xfec10040); /* CS6BWCR */
+
+ /* INTC */
+ sh7724_rstandby_state.ipra = __raw_readw(0xa4080000); /* IPRA */
+ sh7724_rstandby_state.iprb = __raw_readw(0xa4080004); /* IPRB */
+ sh7724_rstandby_state.iprc = __raw_readw(0xa4080008); /* IPRC */
+ sh7724_rstandby_state.iprd = __raw_readw(0xa408000c); /* IPRD */
+ sh7724_rstandby_state.ipre = __raw_readw(0xa4080010); /* IPRE */
+ sh7724_rstandby_state.iprf = __raw_readw(0xa4080014); /* IPRF */
+ sh7724_rstandby_state.iprg = __raw_readw(0xa4080018); /* IPRG */
+ sh7724_rstandby_state.iprh = __raw_readw(0xa408001c); /* IPRH */
+ sh7724_rstandby_state.ipri = __raw_readw(0xa4080020); /* IPRI */
+ sh7724_rstandby_state.iprj = __raw_readw(0xa4080024); /* IPRJ */
+ sh7724_rstandby_state.iprk = __raw_readw(0xa4080028); /* IPRK */
+ sh7724_rstandby_state.iprl = __raw_readw(0xa408002c); /* IPRL */
+ sh7724_rstandby_state.imr0 = __raw_readb(0xa4080080); /* IMR0 */
+ sh7724_rstandby_state.imr1 = __raw_readb(0xa4080084); /* IMR1 */
+ sh7724_rstandby_state.imr2 = __raw_readb(0xa4080088); /* IMR2 */
+ sh7724_rstandby_state.imr3 = __raw_readb(0xa408008c); /* IMR3 */
+ sh7724_rstandby_state.imr4 = __raw_readb(0xa4080090); /* IMR4 */
+ sh7724_rstandby_state.imr5 = __raw_readb(0xa4080094); /* IMR5 */
+ sh7724_rstandby_state.imr6 = __raw_readb(0xa4080098); /* IMR6 */
+ sh7724_rstandby_state.imr7 = __raw_readb(0xa408009c); /* IMR7 */
+ sh7724_rstandby_state.imr8 = __raw_readb(0xa40800a0); /* IMR8 */
+ sh7724_rstandby_state.imr9 = __raw_readb(0xa40800a4); /* IMR9 */
+ sh7724_rstandby_state.imr10 = __raw_readb(0xa40800a8); /* IMR10 */
+ sh7724_rstandby_state.imr11 = __raw_readb(0xa40800ac); /* IMR11 */
+ sh7724_rstandby_state.imr12 = __raw_readb(0xa40800b0); /* IMR12 */
+
+ /* RWDT */
+ sh7724_rstandby_state.rwtcnt = __raw_readb(0xa4520000); /* RWTCNT */
+ sh7724_rstandby_state.rwtcnt |= 0x5a00;
+ sh7724_rstandby_state.rwtcsr = __raw_readb(0xa4520004); /* RWTCSR */
+ sh7724_rstandby_state.rwtcsr |= 0xa500;
+ __raw_writew(sh7724_rstandby_state.rwtcsr & 0x07, 0xa4520004);
+
+ /* CPG */
+ sh7724_rstandby_state.irdaclk = __raw_readl(0xa4150018); /* IRDACLKCR */
+ sh7724_rstandby_state.spuclk = __raw_readl(0xa415003c); /* SPUCLKCR */
+
+ return NOTIFY_DONE;
+}
+
+static int sh7724_post_sleep_notifier_call(struct notifier_block *nb,
+ unsigned long flags, void *unused)
+{
+ if (!(flags & SUSP_SH_RSTANDBY))
+ return NOTIFY_DONE;
+
+ /* BCR */
+ __raw_writel(sh7724_rstandby_state.mmselr, 0xff800020); /* MMSELR */
+ __raw_writel(sh7724_rstandby_state.cs0bcr, 0xfec10004); /* CS0BCR */
+ __raw_writel(sh7724_rstandby_state.cs4bcr, 0xfec10010); /* CS4BCR */
+ __raw_writel(sh7724_rstandby_state.cs5abcr, 0xfec10014); /* CS5ABCR */
+ __raw_writel(sh7724_rstandby_state.cs5bbcr, 0xfec10018); /* CS5BBCR */
+ __raw_writel(sh7724_rstandby_state.cs6abcr, 0xfec1001c); /* CS6ABCR */
+ __raw_writel(sh7724_rstandby_state.cs6bbcr, 0xfec10020); /* CS6BBCR */
+ __raw_writel(sh7724_rstandby_state.cs4wcr, 0xfec10030); /* CS4WCR */
+ __raw_writel(sh7724_rstandby_state.cs5awcr, 0xfec10034); /* CS5AWCR */
+ __raw_writel(sh7724_rstandby_state.cs5bwcr, 0xfec10038); /* CS5BWCR */
+ __raw_writel(sh7724_rstandby_state.cs6awcr, 0xfec1003c); /* CS6AWCR */
+ __raw_writel(sh7724_rstandby_state.cs6bwcr, 0xfec10040); /* CS6BWCR */
+
+ /* INTC */
+ __raw_writew(sh7724_rstandby_state.ipra, 0xa4080000); /* IPRA */
+ __raw_writew(sh7724_rstandby_state.iprb, 0xa4080004); /* IPRB */
+ __raw_writew(sh7724_rstandby_state.iprc, 0xa4080008); /* IPRC */
+ __raw_writew(sh7724_rstandby_state.iprd, 0xa408000c); /* IPRD */
+ __raw_writew(sh7724_rstandby_state.ipre, 0xa4080010); /* IPRE */
+ __raw_writew(sh7724_rstandby_state.iprf, 0xa4080014); /* IPRF */
+ __raw_writew(sh7724_rstandby_state.iprg, 0xa4080018); /* IPRG */
+ __raw_writew(sh7724_rstandby_state.iprh, 0xa408001c); /* IPRH */
+ __raw_writew(sh7724_rstandby_state.ipri, 0xa4080020); /* IPRI */
+ __raw_writew(sh7724_rstandby_state.iprj, 0xa4080024); /* IPRJ */
+ __raw_writew(sh7724_rstandby_state.iprk, 0xa4080028); /* IPRK */
+ __raw_writew(sh7724_rstandby_state.iprl, 0xa408002c); /* IPRL */
+ __raw_writeb(sh7724_rstandby_state.imr0, 0xa4080080); /* IMR0 */
+ __raw_writeb(sh7724_rstandby_state.imr1, 0xa4080084); /* IMR1 */
+ __raw_writeb(sh7724_rstandby_state.imr2, 0xa4080088); /* IMR2 */
+ __raw_writeb(sh7724_rstandby_state.imr3, 0xa408008c); /* IMR3 */
+ __raw_writeb(sh7724_rstandby_state.imr4, 0xa4080090); /* IMR4 */
+ __raw_writeb(sh7724_rstandby_state.imr5, 0xa4080094); /* IMR5 */
+ __raw_writeb(sh7724_rstandby_state.imr6, 0xa4080098); /* IMR6 */
+ __raw_writeb(sh7724_rstandby_state.imr7, 0xa408009c); /* IMR7 */
+ __raw_writeb(sh7724_rstandby_state.imr8, 0xa40800a0); /* IMR8 */
+ __raw_writeb(sh7724_rstandby_state.imr9, 0xa40800a4); /* IMR9 */
+ __raw_writeb(sh7724_rstandby_state.imr10, 0xa40800a8); /* IMR10 */
+ __raw_writeb(sh7724_rstandby_state.imr11, 0xa40800ac); /* IMR11 */
+ __raw_writeb(sh7724_rstandby_state.imr12, 0xa40800b0); /* IMR12 */
+
+ /* RWDT */
+ __raw_writew(sh7724_rstandby_state.rwtcnt, 0xa4520000); /* RWTCNT */
+ __raw_writew(sh7724_rstandby_state.rwtcsr, 0xa4520004); /* RWTCSR */
+
+ /* CPG */
+ __raw_writel(sh7724_rstandby_state.irdaclk, 0xa4150018); /* IRDACLKCR */
+ __raw_writel(sh7724_rstandby_state.spuclk, 0xa415003c); /* SPUCLKCR */
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block sh7724_pre_sleep_notifier = {
+ .notifier_call = sh7724_pre_sleep_notifier_call,
+ .priority = SH_MOBILE_PRE(SH_MOBILE_SLEEP_CPU),
+};
+
+static struct notifier_block sh7724_post_sleep_notifier = {
+ .notifier_call = sh7724_post_sleep_notifier_call,
+ .priority = SH_MOBILE_POST(SH_MOBILE_SLEEP_CPU),
+};
+
+static int __init sh7724_sleep_setup(void)
+{
+ atomic_notifier_chain_register(&sh_mobile_pre_sleep_notifier_list,
+ &sh7724_pre_sleep_notifier);
+
+ atomic_notifier_chain_register(&sh_mobile_post_sleep_notifier_list,
+ &sh7724_post_sleep_notifier);
+ return 0;
+}
+arch_initcall(sh7724_sleep_setup);
+
diff --git a/arch/sh/kernel/cpu/sh4a/setup-shx3.c b/arch/sh/kernel/cpu/sh4a/setup-shx3.c
index e848443..c7ba916 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-shx3.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-shx3.c
@@ -15,6 +15,15 @@
#include <linux/sh_timer.h>
#include <asm/mmzone.h>
+/*
+ * This intentionally only registers SCIF ports 0, 1, and 3. SCIF 2
+ * INTEVT values overlap with the FPU EXPEVT ones, requiring special
+ * demuxing in the exception dispatch path.
+ *
+ * As this overlap is something that never should have made it in to
+ * silicon in the first place, we just refuse to deal with the port at
+ * all rather than adding infrastructure to hack around it.
+ */
static struct plat_sci_port sci_platform_data[] = {
{
.mapbase = 0xffc30000,
@@ -27,11 +36,6 @@ static struct plat_sci_port sci_platform_data[] = {
.type = PORT_SCIF,
.irqs = { 44, 45, 47, 46 },
}, {
- .mapbase = 0xffc50000,
- .flags = UPF_BOOT_AUTOCONF,
- .type = PORT_SCIF,
- .irqs = { 48, 49, 51, 50 },
- }, {
.mapbase = 0xffc60000,
.flags = UPF_BOOT_AUTOCONF,
.type = PORT_SCIF,
@@ -268,7 +272,11 @@ enum {
UNUSED = 0,
/* interrupt sources */
- IRL, IRQ0, IRQ1, IRQ2, IRQ3,
+ 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,
@@ -291,7 +299,7 @@ enum {
INTICI4, INTICI5, INTICI6, INTICI7,
/* interrupt groups */
- PCII56789, SCIF0, SCIF1, SCIF2, SCIF3,
+ IRL, PCII56789, SCIF0, SCIF1, SCIF2, SCIF3,
DMAC0, DMAC1,
};
@@ -309,8 +317,6 @@ static struct intc_vect vectors[] __initdata = {
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),
@@ -344,10 +350,13 @@ static struct intc_vect vectors[] __initdata = {
};
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),
@@ -419,14 +428,14 @@ static DECLARE_INTC_DESC(intc_desc_irq, "shx3-irq", vectors_irq, groups,
/* External interrupt pins in IRL mode */
static struct intc_vect vectors_irl[] __initdata = {
- INTC_VECT(IRL, 0x200), INTC_VECT(IRL, 0x220),
- INTC_VECT(IRL, 0x240), INTC_VECT(IRL, 0x260),
- INTC_VECT(IRL, 0x280), INTC_VECT(IRL, 0x2a0),
- INTC_VECT(IRL, 0x2c0), INTC_VECT(IRL, 0x2e0),
- INTC_VECT(IRL, 0x300), INTC_VECT(IRL, 0x320),
- INTC_VECT(IRL, 0x340), INTC_VECT(IRL, 0x360),
- INTC_VECT(IRL, 0x380), INTC_VECT(IRL, 0x3a0),
- INTC_VECT(IRL, 0x3c0),
+ 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,
diff --git a/arch/sh/kernel/cpu/sh4a/smp-shx3.c b/arch/sh/kernel/cpu/sh4a/smp-shx3.c
index 185ec39..5863e0c 100644
--- a/arch/sh/kernel/cpu/sh4a/smp-shx3.c
+++ b/arch/sh/kernel/cpu/sh4a/smp-shx3.c
@@ -14,6 +14,13 @@
#include <linux/interrupt.h>
#include <linux/io.h>
+#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
+
static irqreturn_t ipi_interrupt_handler(int irq, void *arg)
{
unsigned int message = (unsigned int)(long)arg;
@@ -21,9 +28,9 @@ static irqreturn_t ipi_interrupt_handler(int irq, void *arg)
unsigned int offs = 4 * cpu;
unsigned int x;
- x = ctrl_inl(0xfe410070 + offs); /* C0INITICI..CnINTICI */
+ x = __raw_readl(0xfe410070 + offs); /* C0INITICI..CnINTICI */
x &= (1 << (message << 2));
- ctrl_outl(x, 0xfe410080 + offs); /* C0INTICICLR..CnINTICICLR */
+ __raw_writel(x, 0xfe410080 + offs); /* C0INTICICLR..CnINTICICLR */
smp_message_recv(message);
@@ -37,6 +44,9 @@ void __init plat_smp_setup(void)
init_cpu_possible(cpumask_of(cpu));
+ /* Enable light sleep for the boot CPU */
+ __raw_writel(__raw_readl(STBCR_REG(cpu)) | STBCR_LTSLP, STBCR_REG(cpu));
+
__cpu_number_map[0] = 0;
__cpu_logical_map[0] = 0;
@@ -66,32 +76,23 @@ void __init plat_prepare_cpus(unsigned int max_cpus)
"IPI", (void *)(long)i);
}
-#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));
+ __raw_writel(entry_point, RESET_REG(cpu));
- if (!(ctrl_inl(STBCR_REG(cpu)) & STBCR_MSTP))
- ctrl_outl(STBCR_MSTP, STBCR_REG(cpu));
+ if (!(__raw_readl(STBCR_REG(cpu)) & STBCR_MSTP))
+ __raw_writel(STBCR_MSTP, STBCR_REG(cpu));
- while (!(ctrl_inl(STBCR_REG(cpu)) & STBCR_MSTP))
+ while (!(__raw_readl(STBCR_REG(cpu)) & STBCR_MSTP))
cpu_relax();
/* Start up secondary processor by sending a reset */
- ctrl_outl(STBCR_AP_VAL, STBCR_REG(cpu));
+ __raw_writel(STBCR_RESET | STBCR_LTSLP, STBCR_REG(cpu));
}
int plat_smp_processor_id(void)
{
- return ctrl_inl(0xff000048); /* CPIDR */
+ return __raw_readl(0xff000048); /* CPIDR */
}
void plat_send_ipi(unsigned int cpu, unsigned int message)
@@ -100,5 +101,5 @@ void plat_send_ipi(unsigned int cpu, unsigned int message)
BUG_ON(cpu >= 4);
- ctrl_outl(1 << (message << 2), addr); /* C0INTICI..CnINTICI */
+ __raw_writel(1 << (message << 2), addr); /* C0INTICI..CnINTICI */
}
diff --git a/arch/sh/kernel/cpu/sh5/entry.S b/arch/sh/kernel/cpu/sh5/entry.S
index b0aacf6..8f13f73 100644
--- a/arch/sh/kernel/cpu/sh5/entry.S
+++ b/arch/sh/kernel/cpu/sh5/entry.S
@@ -933,7 +933,7 @@ ret_with_reschedule:
pta restore_all, tr1
- movi (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), r8
+ movi _TIF_SIGPENDING, r8
and r8, r7, r8
pta work_notifysig, tr0
bne r8, ZERO, tr0
diff --git a/arch/sh/kernel/cpu/shmobile/cpuidle.c b/arch/sh/kernel/cpu/shmobile/cpuidle.c
index 1c504bd..83972aa 100644
--- a/arch/sh/kernel/cpu/shmobile/cpuidle.c
+++ b/arch/sh/kernel/cpu/shmobile/cpuidle.c
@@ -87,25 +87,31 @@ void sh_mobile_setup_cpuidle(void)
dev->safe_state = state;
- state = &dev->states[i++];
- snprintf(state->name, CPUIDLE_NAME_LEN, "C1");
- strncpy(state->desc, "SuperH Sleep Mode [SF]", CPUIDLE_DESC_LEN);
- state->exit_latency = 100;
- state->target_residency = 1 * 2;
- state->power_usage = 1;
- state->flags = 0;
- state->flags |= CPUIDLE_FLAG_TIME_VALID;
- state->enter = cpuidle_sleep_enter;
+ if (sh_mobile_sleep_supported & SUSP_SH_SF) {
+ state = &dev->states[i++];
+ snprintf(state->name, CPUIDLE_NAME_LEN, "C1");
+ strncpy(state->desc, "SuperH Sleep Mode [SF]",
+ CPUIDLE_DESC_LEN);
+ state->exit_latency = 100;
+ state->target_residency = 1 * 2;
+ state->power_usage = 1;
+ state->flags = 0;
+ state->flags |= CPUIDLE_FLAG_TIME_VALID;
+ state->enter = cpuidle_sleep_enter;
+ }
- state = &dev->states[i++];
- snprintf(state->name, CPUIDLE_NAME_LEN, "C2");
- strncpy(state->desc, "SuperH Mobile Standby Mode [SF]", CPUIDLE_DESC_LEN);
- state->exit_latency = 2300;
- state->target_residency = 1 * 2;
- state->power_usage = 1;
- state->flags = 0;
- state->flags |= CPUIDLE_FLAG_TIME_VALID;
- state->enter = cpuidle_sleep_enter;
+ if (sh_mobile_sleep_supported & SUSP_SH_STANDBY) {
+ state = &dev->states[i++];
+ snprintf(state->name, CPUIDLE_NAME_LEN, "C2");
+ strncpy(state->desc, "SuperH Mobile Standby Mode [SF]",
+ CPUIDLE_DESC_LEN);
+ state->exit_latency = 2300;
+ state->target_residency = 1 * 2;
+ state->power_usage = 1;
+ state->flags = 0;
+ state->flags |= CPUIDLE_FLAG_TIME_VALID;
+ state->enter = cpuidle_sleep_enter;
+ }
dev->state_count = i;
diff --git a/arch/sh/kernel/cpu/shmobile/pm.c b/arch/sh/kernel/cpu/shmobile/pm.c
index ee3c2aa..ca029a4 100644
--- a/arch/sh/kernel/cpu/shmobile/pm.c
+++ b/arch/sh/kernel/cpu/shmobile/pm.c
@@ -15,6 +15,13 @@
#include <linux/suspend.h>
#include <asm/suspend.h>
#include <asm/uaccess.h>
+#include <asm/cacheflush.h>
+
+/*
+ * Notifier lists for pre/post sleep notification
+ */
+ATOMIC_NOTIFIER_HEAD(sh_mobile_pre_sleep_notifier_list);
+ATOMIC_NOTIFIER_HEAD(sh_mobile_post_sleep_notifier_list);
/*
* Sleep modes available on SuperH Mobile:
@@ -26,30 +33,105 @@
#define SUSP_MODE_SLEEP (SUSP_SH_SLEEP)
#define SUSP_MODE_SLEEP_SF (SUSP_SH_SLEEP | SUSP_SH_SF)
#define SUSP_MODE_STANDBY_SF (SUSP_SH_STANDBY | SUSP_SH_SF)
+#define SUSP_MODE_RSTANDBY (SUSP_SH_RSTANDBY | SUSP_SH_MMU | SUSP_SH_SF)
+ /*
+ * U-standby mode is unsupported since it needs bootloader hacks
+ */
-/*
- * The following modes are not there yet:
- *
- * R-standby mode is unsupported, but will be added in the future
- * U-standby mode is low priority since it needs bootloader hacks
- */
-
-#define ILRAM_BASE 0xe5200000
-
-extern const unsigned char sh_mobile_standby[];
-extern const unsigned int sh_mobile_standby_size;
+#ifdef CONFIG_CPU_SUBTYPE_SH7724
+#define RAM_BASE 0xfd800000 /* RSMEM */
+#else
+#define RAM_BASE 0xe5200000 /* ILRAM */
+#endif
void sh_mobile_call_standby(unsigned long mode)
{
- void *onchip_mem = (void *)ILRAM_BASE;
- void (*standby_onchip_mem)(unsigned long, unsigned long) = onchip_mem;
+ void *onchip_mem = (void *)RAM_BASE;
+ struct sh_sleep_data *sdp = onchip_mem;
+ void (*standby_onchip_mem)(unsigned long, unsigned long);
+
+ /* code located directly after data structure */
+ standby_onchip_mem = (void *)(sdp + 1);
+
+ atomic_notifier_call_chain(&sh_mobile_pre_sleep_notifier_list,
+ mode, NULL);
+
+ /* flush the caches if MMU flag is set */
+ if (mode & SUSP_SH_MMU)
+ flush_cache_all();
/* Let assembly snippet in on-chip memory handle the rest */
- standby_onchip_mem(mode, ILRAM_BASE);
+ standby_onchip_mem(mode, RAM_BASE);
+
+ atomic_notifier_call_chain(&sh_mobile_post_sleep_notifier_list,
+ mode, NULL);
+}
+
+extern char sh_mobile_sleep_enter_start;
+extern char sh_mobile_sleep_enter_end;
+
+extern char sh_mobile_sleep_resume_start;
+extern char sh_mobile_sleep_resume_end;
+
+unsigned long sh_mobile_sleep_supported = SUSP_SH_SLEEP;
+
+void sh_mobile_register_self_refresh(unsigned long flags,
+ void *pre_start, void *pre_end,
+ void *post_start, void *post_end)
+{
+ void *onchip_mem = (void *)RAM_BASE;
+ void *vp;
+ struct sh_sleep_data *sdp;
+ int n;
+
+ /* part 0: data area */
+ sdp = onchip_mem;
+ sdp->addr.stbcr = 0xa4150020; /* STBCR */
+ sdp->addr.bar = 0xa4150040; /* BAR */
+ sdp->addr.pteh = 0xff000000; /* PTEH */
+ sdp->addr.ptel = 0xff000004; /* PTEL */
+ sdp->addr.ttb = 0xff000008; /* TTB */
+ sdp->addr.tea = 0xff00000c; /* TEA */
+ sdp->addr.mmucr = 0xff000010; /* MMUCR */
+ sdp->addr.ptea = 0xff000034; /* PTEA */
+ sdp->addr.pascr = 0xff000070; /* PASCR */
+ sdp->addr.irmcr = 0xff000078; /* IRMCR */
+ sdp->addr.ccr = 0xff00001c; /* CCR */
+ sdp->addr.ramcr = 0xff000074; /* RAMCR */
+ vp = sdp + 1;
+
+ /* part 1: common code to enter sleep mode */
+ n = &sh_mobile_sleep_enter_end - &sh_mobile_sleep_enter_start;
+ memcpy(vp, &sh_mobile_sleep_enter_start, n);
+ vp += roundup(n, 4);
+
+ /* part 2: board specific code to enter self-refresh mode */
+ n = pre_end - pre_start;
+ memcpy(vp, pre_start, n);
+ sdp->sf_pre = (unsigned long)vp;
+ vp += roundup(n, 4);
+
+ /* part 3: board specific code to resume from self-refresh mode */
+ n = post_end - post_start;
+ memcpy(vp, post_start, n);
+ sdp->sf_post = (unsigned long)vp;
+ vp += roundup(n, 4);
+
+ /* part 4: common code to resume from sleep mode */
+ WARN_ON(vp > (onchip_mem + 0x600));
+ vp = onchip_mem + 0x600; /* located at interrupt vector */
+ n = &sh_mobile_sleep_resume_end - &sh_mobile_sleep_resume_start;
+ memcpy(vp, &sh_mobile_sleep_resume_start, n);
+ sdp->resume = (unsigned long)vp;
+
+ sh_mobile_sleep_supported |= flags;
}
static int sh_pm_enter(suspend_state_t state)
{
+ if (!(sh_mobile_sleep_supported & SUSP_MODE_STANDBY_SF))
+ return -ENXIO;
+
local_irq_disable();
set_bl_bit();
sh_mobile_call_standby(SUSP_MODE_STANDBY_SF);
@@ -65,13 +147,6 @@ static struct platform_suspend_ops sh_pm_ops = {
static int __init sh_pm_init(void)
{
- void *onchip_mem = (void *)ILRAM_BASE;
-
- /* Copy the assembly snippet to the otherwise ununsed ILRAM */
- memcpy(onchip_mem, sh_mobile_standby, sh_mobile_standby_size);
- wmb();
- ctrl_barrier();
-
suspend_set_ops(&sh_pm_ops);
sh_mobile_setup_cpuidle();
return 0;
diff --git a/arch/sh/kernel/cpu/shmobile/pm_runtime.c b/arch/sh/kernel/cpu/shmobile/pm_runtime.c
index 7c615b1..6dcb816 100644
--- a/arch/sh/kernel/cpu/shmobile/pm_runtime.c
+++ b/arch/sh/kernel/cpu/shmobile/pm_runtime.c
@@ -45,12 +45,14 @@ static int __platform_pm_runtime_resume(struct platform_device *pdev)
dev_dbg(d, "__platform_pm_runtime_resume() [%d]\n", hwblk);
- if (d->driver && d->driver->pm && d->driver->pm->runtime_resume) {
+ if (d->driver) {
hwblk_enable(hwblk_info, hwblk);
ret = 0;
if (test_bit(PDEV_ARCHDATA_FLAG_SUSP, &ad->flags)) {
- ret = d->driver->pm->runtime_resume(d);
+ if (d->driver->pm && d->driver->pm->runtime_resume)
+ ret = d->driver->pm->runtime_resume(d);
+
if (!ret)
clear_bit(PDEV_ARCHDATA_FLAG_SUSP, &ad->flags);
else
@@ -73,12 +75,15 @@ static int __platform_pm_runtime_suspend(struct platform_device *pdev)
dev_dbg(d, "__platform_pm_runtime_suspend() [%d]\n", hwblk);
- if (d->driver && d->driver->pm && d->driver->pm->runtime_suspend) {
+ if (d->driver) {
BUG_ON(!test_bit(PDEV_ARCHDATA_FLAG_IDLE, &ad->flags));
+ ret = 0;
- hwblk_enable(hwblk_info, hwblk);
- ret = d->driver->pm->runtime_suspend(d);
- hwblk_disable(hwblk_info, hwblk);
+ if (d->driver->pm && d->driver->pm->runtime_suspend) {
+ hwblk_enable(hwblk_info, hwblk);
+ ret = d->driver->pm->runtime_suspend(d);
+ hwblk_disable(hwblk_info, hwblk);
+ }
if (!ret) {
set_bit(PDEV_ARCHDATA_FLAG_SUSP, &ad->flags);
diff --git a/arch/sh/kernel/cpu/shmobile/sleep.S b/arch/sh/kernel/cpu/shmobile/sleep.S
index a439e6c..e9dd7fa 100644
--- a/arch/sh/kernel/cpu/shmobile/sleep.S
+++ b/arch/sh/kernel/cpu/shmobile/sleep.S
@@ -20,79 +20,103 @@
* Kernel mode register usage, see entry.S:
* k0 scratch
* k1 scratch
- * k4 scratch
*/
#define k0 r0
#define k1 r1
-#define k4 r4
-/* manage self-refresh and enter standby mode.
+/* manage self-refresh and enter standby mode. must be self-contained.
* this code will be copied to on-chip memory and executed from there.
*/
+ .balign 4
+ENTRY(sh_mobile_sleep_enter_start)
- .balign 4096,0,4096
-ENTRY(sh_mobile_standby)
+ /* save mode flags */
+ mov.l r4, @(SH_SLEEP_MODE, r5)
/* save original vbr */
- stc vbr, r1
- mova saved_vbr, r0
- mov.l r1, @r0
+ stc vbr, r0
+ mov.l r0, @(SH_SLEEP_VBR, r5)
/* point vbr to our on-chip memory page */
ldc r5, vbr
/* save return address */
- mova saved_spc, r0
- sts pr, r5
- mov.l r5, @r0
+ sts pr, r0
+ mov.l r0, @(SH_SLEEP_SPC, r5)
/* save sr */
- mova saved_sr, r0
- stc sr, r5
- mov.l r5, @r0
+ stc sr, r0
+ mov.l r0, @(SH_SLEEP_SR, r5)
- /* save mode flags */
- mova saved_mode, r0
- mov.l r4, @r0
+ /* save sp */
+ mov.l r15, @(SH_SLEEP_SP, r5)
+
+ /* save stbcr */
+ bsr save_register
+ mov #SH_SLEEP_REG_STBCR, r0
+
+ /* save mmu and cache context if needed */
+ mov.l @(SH_SLEEP_MODE, r5), r0
+ tst #SUSP_SH_MMU, r0
+ bt skip_mmu_save_disable
+
+ /* save mmu state */
+ bsr save_register
+ mov #SH_SLEEP_REG_PTEH, r0
+
+ bsr save_register
+ mov #SH_SLEEP_REG_PTEL, r0
+
+ bsr save_register
+ mov #SH_SLEEP_REG_TTB, r0
+
+ bsr save_register
+ mov #SH_SLEEP_REG_TEA, r0
+
+ bsr save_register
+ mov #SH_SLEEP_REG_MMUCR, r0
+
+ bsr save_register
+ mov #SH_SLEEP_REG_PTEA, r0
+
+ bsr save_register
+ mov #SH_SLEEP_REG_PASCR, r0
- /* put mode flags in r0 */
- mov r4, r0
+ bsr save_register
+ mov #SH_SLEEP_REG_IRMCR, r0
+ /* invalidate TLBs and disable the MMU */
+ bsr get_register
+ mov #SH_SLEEP_REG_MMUCR, r0
+ mov #4, r1
+ mov.l r1, @r0
+ icbi @r0
+
+ /* save cache registers and disable caches */
+ bsr save_register
+ mov #SH_SLEEP_REG_CCR, r0
+
+ bsr save_register
+ mov #SH_SLEEP_REG_RAMCR, r0
+
+ bsr get_register
+ mov #SH_SLEEP_REG_CCR, r0
+ mov #0, r1
+ mov.l r1, @r0
+ icbi @r0
+
+skip_mmu_save_disable:
+ /* call self-refresh entering code if needed */
+ mov.l @(SH_SLEEP_MODE, r5), r0
tst #SUSP_SH_SF, r0
bt skip_set_sf
-#ifdef CONFIG_CPU_SUBTYPE_SH7724
- /* DBSC: put memory in self-refresh mode */
- mov.l dben_reg, r4
- mov.l dben_data0, r1
- mov.l r1, @r4
-
- mov.l dbrfpdn0_reg, r4
- mov.l dbrfpdn0_data0, r1
- mov.l r1, @r4
-
- mov.l dbcmdcnt_reg, r4
- mov.l dbcmdcnt_data0, r1
- mov.l r1, @r4
-
- mov.l dbcmdcnt_reg, r4
- mov.l dbcmdcnt_data1, r1
- mov.l r1, @r4
-
- mov.l dbrfpdn0_reg, r4
- mov.l dbrfpdn0_data1, r1
- mov.l r1, @r4
-#else
- /* SBSC: disable power down and put in self-refresh mode */
- mov.l 1f, r4
- mov.l 2f, r1
- mov.l @r4, r2
- or r1, r2
- mov.l 3f, r3
- and r3, r2
- mov.l r2, @r4
-#endif
+
+ mov.l @(SH_SLEEP_SF_PRE, r5), r0
+ jsr @r0
+ nop
skip_set_sf:
+ mov.l @(SH_SLEEP_MODE, r5), r0
tst #SUSP_SH_STANDBY, r0
bt test_rstandby
@@ -104,6 +128,12 @@ test_rstandby:
tst #SUSP_SH_RSTANDBY, r0
bt test_ustandby
+ /* setup BAR register */
+ bsr get_register
+ mov #SH_SLEEP_REG_BAR, r0
+ mov.l @(SH_SLEEP_RESUME, r5), r1
+ mov.l r1, @r0
+
/* set mode to "r-standby mode" */
bra do_sleep
mov #0x20, r1
@@ -123,124 +153,136 @@ force_sleep:
do_sleep:
/* setup and enter selected standby mode */
- mov.l 5f, r4
- mov.l r1, @r4
+ bsr get_register
+ mov #SH_SLEEP_REG_STBCR, r0
+ mov.l r1, @r0
again:
sleep
bra again
nop
-restore_jump_vbr:
+save_register:
+ add #SH_SLEEP_BASE_ADDR, r0
+ mov.l @(r0, r5), r1
+ add #-SH_SLEEP_BASE_ADDR, r0
+ mov.l @r1, r1
+ add #SH_SLEEP_BASE_DATA, r0
+ mov.l r1, @(r0, r5)
+ add #-SH_SLEEP_BASE_DATA, r0
+ rts
+ nop
+
+get_register:
+ add #SH_SLEEP_BASE_ADDR, r0
+ mov.l @(r0, r5), r0
+ rts
+ nop
+ENTRY(sh_mobile_sleep_enter_end)
+
+ .balign 4
+ENTRY(sh_mobile_sleep_resume_start)
+
+ /* figure out start address */
+ bsr 0f
+ nop
+0:
+ sts pr, k1
+ mov.l 1f, k0
+ and k0, k1
+
+ /* store pointer to data area in VBR */
+ ldc k1, vbr
+
+ /* setup sr with saved sr */
+ mov.l @(SH_SLEEP_SR, k1), k0
+ ldc k0, sr
+
+ /* now: user register set! */
+ stc vbr, r5
+
/* setup spc with return address to c code */
- mov.l saved_spc, k0
- ldc k0, spc
+ mov.l @(SH_SLEEP_SPC, r5), r0
+ ldc r0, spc
/* restore vbr */
- mov.l saved_vbr, k0
- ldc k0, vbr
+ mov.l @(SH_SLEEP_VBR, r5), r0
+ ldc r0, vbr
/* setup ssr with saved sr */
- mov.l saved_sr, k0
- ldc k0, ssr
+ mov.l @(SH_SLEEP_SR, r5), r0
+ ldc r0, ssr
- /* get mode flags */
- mov.l saved_mode, k0
+ /* restore sp */
+ mov.l @(SH_SLEEP_SP, r5), r15
-done_sleep:
- /* reset standby mode to sleep mode */
- mov.l 5f, k4
- mov #0x00, k1
- mov.l k1, @k4
+ /* restore sleep mode register */
+ bsr restore_register
+ mov #SH_SLEEP_REG_STBCR, r0
- tst #SUSP_SH_SF, k0
+ /* call self-refresh resume code if needed */
+ mov.l @(SH_SLEEP_MODE, r5), r0
+ tst #SUSP_SH_SF, r0
bt skip_restore_sf
-#ifdef CONFIG_CPU_SUBTYPE_SH7724
- /* DBSC: put memory in auto-refresh mode */
- mov.l dbrfpdn0_reg, k4
- mov.l dbrfpdn0_data0, k1
- mov.l k1, @k4
-
- nop /* sleep 140 ns */
- nop
- nop
- nop
-
- mov.l dbcmdcnt_reg, k4
- mov.l dbcmdcnt_data0, k1
- mov.l k1, @k4
-
- mov.l dbcmdcnt_reg, k4
- mov.l dbcmdcnt_data1, k1
- mov.l k1, @k4
-
- mov.l dben_reg, k4
- mov.l dben_data1, k1
- mov.l k1, @k4
-
- mov.l dbrfpdn0_reg, k4
- mov.l dbrfpdn0_data2, k1
- mov.l k1, @k4
-#else
- /* SBSC: set auto-refresh mode */
- mov.l 1f, k4
- mov.l @k4, k0
- mov.l 4f, k1
- and k1, k0
- mov.l k0, @k4
- mov.l 6f, k4
- mov.l 8f, k0
- mov.l @k4, k1
- mov #-1, k4
- add k4, k1
- or k1, k0
- mov.l 7f, k1
- mov.l k0, @k1
-#endif
+ mov.l @(SH_SLEEP_SF_POST, r5), r0
+ jsr @r0
+ nop
+
skip_restore_sf:
- /* jump to vbr vector */
- mov.l saved_vbr, k0
- mov.l offset_vbr, k4
- add k4, k0
- jmp @k0
+ /* restore mmu and cache state if needed */
+ mov.l @(SH_SLEEP_MODE, r5), r0
+ tst #SUSP_SH_MMU, r0
+ bt skip_restore_mmu
+
+ /* restore mmu state */
+ bsr restore_register
+ mov #SH_SLEEP_REG_PTEH, r0
+
+ bsr restore_register
+ mov #SH_SLEEP_REG_PTEL, r0
+
+ bsr restore_register
+ mov #SH_SLEEP_REG_TTB, r0
+
+ bsr restore_register
+ mov #SH_SLEEP_REG_TEA, r0
+
+ bsr restore_register
+ mov #SH_SLEEP_REG_PTEA, r0
+
+ bsr restore_register
+ mov #SH_SLEEP_REG_PASCR, r0
+
+ bsr restore_register
+ mov #SH_SLEEP_REG_IRMCR, r0
+
+ bsr restore_register
+ mov #SH_SLEEP_REG_MMUCR, r0
+ icbi @r0
+
+ /* restore cache settings */
+ bsr restore_register
+ mov #SH_SLEEP_REG_RAMCR, r0
+ icbi @r0
+
+ bsr restore_register
+ mov #SH_SLEEP_REG_CCR, r0
+ icbi @r0
+
+skip_restore_mmu:
+ rte
nop
- .balign 4
-saved_mode: .long 0
-saved_spc: .long 0
-saved_sr: .long 0
-saved_vbr: .long 0
-offset_vbr: .long 0x600
-#ifdef CONFIG_CPU_SUBTYPE_SH7724
-dben_reg: .long 0xfd000010 /* DBEN */
-dben_data0: .long 0
-dben_data1: .long 1
-dbrfpdn0_reg: .long 0xfd000040 /* DBRFPDN0 */
-dbrfpdn0_data0: .long 0
-dbrfpdn0_data1: .long 1
-dbrfpdn0_data2: .long 0x00010000
-dbcmdcnt_reg: .long 0xfd000014 /* DBCMDCNT */
-dbcmdcnt_data0: .long 2
-dbcmdcnt_data1: .long 4
-#else
-1: .long 0xfe400008 /* SDCR0 */
-2: .long 0x00000400
-3: .long 0xffff7fff
-4: .long 0xfffffbff
-#endif
-5: .long 0xa4150020 /* STBCR */
-6: .long 0xfe40001c /* RTCOR */
-7: .long 0xfe400018 /* RTCNT */
-8: .long 0xa55a0000
-
-
-/* interrupt vector @ 0x600 */
- .balign 0x400,0,0x400
- .long 0xdeadbeef
- .balign 0x200,0,0x200
- bra restore_jump_vbr
+restore_register:
+ add #SH_SLEEP_BASE_DATA, r0
+ mov.l @(r0, r5), r1
+ add #-SH_SLEEP_BASE_DATA, r0
+ add #SH_SLEEP_BASE_ADDR, r0
+ mov.l @(r0, r5), r0
+ mov.l r1, @r0
+ rts
nop
-sh_mobile_standby_end:
-ENTRY(sh_mobile_standby_size)
- .long sh_mobile_standby_end - sh_mobile_standby
+ .balign 4
+1: .long ~0x7ff
+ENTRY(sh_mobile_sleep_resume_end)
diff --git a/arch/sh/kernel/cpu/ubc.S b/arch/sh/kernel/cpu/ubc.S
deleted file mode 100644
index 8192307..0000000
--- a/arch/sh/kernel/cpu/ubc.S
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * arch/sh/kernel/cpu/ubc.S
- *
- * Set of management routines for the User Break Controller (UBC)
- *
- * Copyright (C) 2002 Paul Mundt
- *
- * 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.
- */
-#include <linux/linkage.h>
-#include <asm/ubc.h>
-
-#define STBCR2 0xffc00010
-
-ENTRY(ubc_sleep)
- mov #0, r0
-
- mov.l 1f, r1 ! Zero out UBC_BBRA ..
- mov.w r0, @r1
-
- mov.l 2f, r1 ! .. same for BBRB ..
- mov.w r0, @r1
-
- mov.l 3f, r1 ! .. and again for BRCR.
- mov.w r0, @r1
-
- mov.w @r1, r0 ! Dummy read BRCR
-
- mov.l 4f, r1 ! Set MSTP5 in STBCR2
- mov.b @r1, r0
- or #0x01, r0
- mov.b r0, @r1
-
- mov.b @r1, r0 ! Two dummy reads ..
- mov.b @r1, r0
-
- rts
- nop
-
-ENTRY(ubc_wakeup)
- mov.l 4f, r1 ! Clear MSTP5
- mov.b @r1, r0
- and #0xfe, r0
- mov.b r0, @r1
-
- mov.b @r1, r0 ! Two more dummy reads ..
- mov.b @r1, r0
-
- rts
- nop
-
-1: .long UBC_BBRA
-2: .long UBC_BBRB
-3: .long UBC_BRCR
-4: .long STBCR2
-
diff --git a/arch/sh/kernel/dma-nommu.c b/arch/sh/kernel/dma-nommu.c
new file mode 100644
index 0000000..3c55b87
--- /dev/null
+++ b/arch/sh/kernel/dma-nommu.c
@@ -0,0 +1,82 @@
+/*
+ * DMA mapping support for platforms lacking IOMMUs.
+ *
+ * Copyright (C) 2009 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/dma-mapping.h>
+#include <linux/io.h>
+
+static dma_addr_t nommu_map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size,
+ enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ dma_addr_t addr = page_to_phys(page) + offset;
+
+ WARN_ON(size == 0);
+ dma_cache_sync(dev, page_address(page) + offset, size, dir);
+
+ return addr;
+}
+
+static int nommu_map_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ struct scatterlist *s;
+ int i;
+
+ WARN_ON(nents == 0 || sg[0].length == 0);
+
+ for_each_sg(sg, s, nents, i) {
+ BUG_ON(!sg_page(s));
+
+ dma_cache_sync(dev, sg_virt(s), s->length, dir);
+
+ s->dma_address = sg_phys(s);
+ s->dma_length = s->length;
+ }
+
+ return nents;
+}
+
+#ifdef CONFIG_DMA_NONCOHERENT
+static void nommu_sync_single(struct device *dev, dma_addr_t addr,
+ size_t size, enum dma_data_direction dir)
+{
+ dma_cache_sync(dev, phys_to_virt(addr), size, dir);
+}
+
+static void nommu_sync_sg(struct device *dev, struct scatterlist *sg,
+ int nelems, enum dma_data_direction dir)
+{
+ struct scatterlist *s;
+ int i;
+
+ for_each_sg(sg, s, nelems, i)
+ dma_cache_sync(dev, sg_virt(s), s->length, dir);
+}
+#endif
+
+struct dma_map_ops nommu_dma_ops = {
+ .alloc_coherent = dma_generic_alloc_coherent,
+ .free_coherent = dma_generic_free_coherent,
+ .map_page = nommu_map_page,
+ .map_sg = nommu_map_sg,
+#ifdef CONFIG_DMA_NONCOHERENT
+ .sync_single_for_device = nommu_sync_single,
+ .sync_sg_for_device = nommu_sync_sg,
+#endif
+ .is_phys = 1,
+};
+
+void __init no_iommu_init(void)
+{
+ if (dma_ops)
+ return;
+ dma_ops = &nommu_dma_ops;
+}
diff --git a/arch/sh/kernel/dwarf.c b/arch/sh/kernel/dwarf.c
index d76a231..3576b70 100644
--- a/arch/sh/kernel/dwarf.c
+++ b/arch/sh/kernel/dwarf.c
@@ -20,6 +20,7 @@
#include <linux/list.h>
#include <linux/mempool.h>
#include <linux/mm.h>
+#include <linux/elf.h>
#include <linux/ftrace.h>
#include <asm/dwarf.h>
#include <asm/unwinder.h>
@@ -530,7 +531,18 @@ static int dwarf_cfa_execute_insns(unsigned char *insn_start,
}
/**
- * dwarf_unwind_stack - recursively unwind the stack
+ * dwarf_free_frame - free the memory allocated for @frame
+ * @frame: the frame to free
+ */
+void dwarf_free_frame(struct dwarf_frame *frame)
+{
+ dwarf_frame_free_regs(frame);
+ mempool_free(frame, dwarf_frame_pool);
+}
+
+/**
+ * dwarf_unwind_stack - unwind the stack
+ *
* @pc: address of the function to unwind
* @prev: struct dwarf_frame of the previous stackframe on the callstack
*
@@ -548,9 +560,9 @@ struct dwarf_frame * dwarf_unwind_stack(unsigned long pc,
unsigned long addr;
/*
- * If this is the first invocation of this recursive function we
- * need get the contents of a physical register to get the CFA
- * in order to begin the virtual unwinding of the stack.
+ * If we're starting at the top of the stack we need get the
+ * contents of a physical register to get the CFA in order to
+ * begin the virtual unwinding of the stack.
*
* NOTE: the return address is guaranteed to be setup by the
* time this function makes its first function call.
@@ -593,9 +605,8 @@ struct dwarf_frame * dwarf_unwind_stack(unsigned long pc,
fde = dwarf_lookup_fde(pc);
if (!fde) {
/*
- * This is our normal exit path - the one that stops the
- * recursion. There's two reasons why we might exit
- * here,
+ * This is our normal exit path. There are two reasons
+ * why we might exit here,
*
* a) pc has no asscociated DWARF frame info and so
* we don't know how to unwind this frame. This is
@@ -637,10 +648,10 @@ struct dwarf_frame * dwarf_unwind_stack(unsigned long pc,
} else {
/*
- * Again, this is the first invocation of this
- * recurisve function. We need to physically
- * read the contents of a register in order to
- * get the Canonical Frame Address for this
+ * Again, we're starting from the top of the
+ * stack. We need to physically read
+ * the contents of a register in order to get
+ * the Canonical Frame Address for this
* function.
*/
frame->cfa = dwarf_read_arch_reg(frame->cfa_register);
@@ -670,13 +681,12 @@ struct dwarf_frame * dwarf_unwind_stack(unsigned long pc,
return frame;
bail:
- dwarf_frame_free_regs(frame);
- mempool_free(frame, dwarf_frame_pool);
+ dwarf_free_frame(frame);
return NULL;
}
static int dwarf_parse_cie(void *entry, void *p, unsigned long len,
- unsigned char *end)
+ unsigned char *end, struct module *mod)
{
struct dwarf_cie *cie;
unsigned long flags;
@@ -772,6 +782,8 @@ static int dwarf_parse_cie(void *entry, void *p, unsigned long len,
cie->initial_instructions = p;
cie->instructions_end = end;
+ cie->mod = mod;
+
/* Add to list */
spin_lock_irqsave(&dwarf_cie_lock, flags);
list_add_tail(&cie->link, &dwarf_cie_list);
@@ -782,7 +794,7 @@ static int dwarf_parse_cie(void *entry, void *p, unsigned long len,
static int dwarf_parse_fde(void *entry, u32 entry_type,
void *start, unsigned long len,
- unsigned char *end)
+ unsigned char *end, struct module *mod)
{
struct dwarf_fde *fde;
struct dwarf_cie *cie;
@@ -831,6 +843,8 @@ static int dwarf_parse_fde(void *entry, u32 entry_type,
fde->instructions = p;
fde->end = end;
+ fde->mod = mod;
+
/* Add to list. */
spin_lock_irqsave(&dwarf_fde_lock, flags);
list_add_tail(&fde->link, &dwarf_fde_list);
@@ -854,10 +868,8 @@ static void dwarf_unwinder_dump(struct task_struct *task,
while (1) {
frame = dwarf_unwind_stack(return_addr, _frame);
- if (_frame) {
- dwarf_frame_free_regs(_frame);
- mempool_free(_frame, dwarf_frame_pool);
- }
+ if (_frame)
+ dwarf_free_frame(_frame);
_frame = frame;
@@ -867,6 +879,9 @@ static void dwarf_unwinder_dump(struct task_struct *task,
return_addr = frame->return_addr;
ops->address(data, return_addr, 1);
}
+
+ if (frame)
+ dwarf_free_frame(frame);
}
static struct unwinder dwarf_unwinder = {
@@ -896,48 +911,28 @@ static void dwarf_unwinder_cleanup(void)
}
/**
- * dwarf_unwinder_init - initialise the dwarf unwinder
+ * dwarf_parse_section - parse DWARF section
+ * @eh_frame_start: start address of the .eh_frame section
+ * @eh_frame_end: end address of the .eh_frame section
+ * @mod: the kernel module containing the .eh_frame section
*
- * Build the data structures describing the .dwarf_frame section to
- * make it easier to lookup CIE and FDE entries. Because the
- * .eh_frame section is packed as tightly as possible it is not
- * easy to lookup the FDE for a given PC, so we build a list of FDE
- * and CIE entries that make it easier.
+ * Parse the information in a .eh_frame section.
*/
-static int __init dwarf_unwinder_init(void)
+static int dwarf_parse_section(char *eh_frame_start, char *eh_frame_end,
+ struct module *mod)
{
u32 entry_type;
void *p, *entry;
int count, err = 0;
- unsigned long len;
+ unsigned long len = 0;
unsigned int c_entries, f_entries;
unsigned char *end;
- INIT_LIST_HEAD(&dwarf_cie_list);
- INIT_LIST_HEAD(&dwarf_fde_list);
c_entries = 0;
f_entries = 0;
- entry = &__start_eh_frame;
-
- dwarf_frame_cachep = kmem_cache_create("dwarf_frames",
- sizeof(struct dwarf_frame), 0,
- SLAB_PANIC | SLAB_HWCACHE_ALIGN | SLAB_NOTRACK, NULL);
-
- dwarf_reg_cachep = kmem_cache_create("dwarf_regs",
- sizeof(struct dwarf_reg), 0,
- SLAB_PANIC | SLAB_HWCACHE_ALIGN | SLAB_NOTRACK, NULL);
+ entry = eh_frame_start;
- dwarf_frame_pool = mempool_create(DWARF_FRAME_MIN_REQ,
- mempool_alloc_slab,
- mempool_free_slab,
- dwarf_frame_cachep);
-
- dwarf_reg_pool = mempool_create(DWARF_REG_MIN_REQ,
- mempool_alloc_slab,
- mempool_free_slab,
- dwarf_reg_cachep);
-
- while ((char *)entry < __stop_eh_frame) {
+ while ((char *)entry < eh_frame_end) {
p = entry;
count = dwarf_entry_len(p, &len);
@@ -949,6 +944,7 @@ static int __init dwarf_unwinder_init(void)
* entry and move to the next one because 'len'
* tells us where our next entry is.
*/
+ err = -EINVAL;
goto out;
} else
p += count;
@@ -960,13 +956,14 @@ static int __init dwarf_unwinder_init(void)
p += 4;
if (entry_type == DW_EH_FRAME_CIE) {
- err = dwarf_parse_cie(entry, p, len, end);
+ err = dwarf_parse_cie(entry, p, len, end, mod);
if (err < 0)
goto out;
else
c_entries++;
} else {
- err = dwarf_parse_fde(entry, entry_type, p, len, end);
+ err = dwarf_parse_fde(entry, entry_type, p, len,
+ end, mod);
if (err < 0)
goto out;
else
@@ -979,6 +976,129 @@ static int __init dwarf_unwinder_init(void)
printk(KERN_INFO "DWARF unwinder initialised: read %u CIEs, %u FDEs\n",
c_entries, f_entries);
+ return 0;
+
+out:
+ return err;
+}
+
+#ifdef CONFIG_MODULES
+int module_dwarf_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
+ struct module *me)
+{
+ unsigned int i, err;
+ unsigned long start, end;
+ char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+
+ start = end = 0;
+
+ for (i = 1; i < hdr->e_shnum; i++) {
+ /* Alloc bit cleared means "ignore it." */
+ if ((sechdrs[i].sh_flags & SHF_ALLOC)
+ && !strcmp(secstrings+sechdrs[i].sh_name, ".eh_frame")) {
+ start = sechdrs[i].sh_addr;
+ end = start + sechdrs[i].sh_size;
+ break;
+ }
+ }
+
+ /* Did we find the .eh_frame section? */
+ if (i != hdr->e_shnum) {
+ err = dwarf_parse_section((char *)start, (char *)end, me);
+ if (err) {
+ printk(KERN_WARNING "%s: failed to parse DWARF info\n",
+ me->name);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * module_dwarf_cleanup - remove FDE/CIEs associated with @mod
+ * @mod: the module that is being unloaded
+ *
+ * Remove any FDEs and CIEs from the global lists that came from
+ * @mod's .eh_frame section because @mod is being unloaded.
+ */
+void module_dwarf_cleanup(struct module *mod)
+{
+ struct dwarf_fde *fde;
+ struct dwarf_cie *cie;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dwarf_cie_lock, flags);
+
+again_cie:
+ list_for_each_entry(cie, &dwarf_cie_list, link) {
+ if (cie->mod == mod)
+ break;
+ }
+
+ if (&cie->link != &dwarf_cie_list) {
+ list_del(&cie->link);
+ kfree(cie);
+ goto again_cie;
+ }
+
+ spin_unlock_irqrestore(&dwarf_cie_lock, flags);
+
+ spin_lock_irqsave(&dwarf_fde_lock, flags);
+
+again_fde:
+ list_for_each_entry(fde, &dwarf_fde_list, link) {
+ if (fde->mod == mod)
+ break;
+ }
+
+ if (&fde->link != &dwarf_fde_list) {
+ list_del(&fde->link);
+ kfree(fde);
+ goto again_fde;
+ }
+
+ spin_unlock_irqrestore(&dwarf_fde_lock, flags);
+}
+#endif /* CONFIG_MODULES */
+
+/**
+ * dwarf_unwinder_init - initialise the dwarf unwinder
+ *
+ * Build the data structures describing the .dwarf_frame section to
+ * make it easier to lookup CIE and FDE entries. Because the
+ * .eh_frame section is packed as tightly as possible it is not
+ * easy to lookup the FDE for a given PC, so we build a list of FDE
+ * and CIE entries that make it easier.
+ */
+static int __init dwarf_unwinder_init(void)
+{
+ int err;
+ INIT_LIST_HEAD(&dwarf_cie_list);
+ INIT_LIST_HEAD(&dwarf_fde_list);
+
+ dwarf_frame_cachep = kmem_cache_create("dwarf_frames",
+ sizeof(struct dwarf_frame), 0,
+ SLAB_PANIC | SLAB_HWCACHE_ALIGN | SLAB_NOTRACK, NULL);
+
+ dwarf_reg_cachep = kmem_cache_create("dwarf_regs",
+ sizeof(struct dwarf_reg), 0,
+ SLAB_PANIC | SLAB_HWCACHE_ALIGN | SLAB_NOTRACK, NULL);
+
+ dwarf_frame_pool = mempool_create(DWARF_FRAME_MIN_REQ,
+ mempool_alloc_slab,
+ mempool_free_slab,
+ dwarf_frame_cachep);
+
+ dwarf_reg_pool = mempool_create(DWARF_REG_MIN_REQ,
+ mempool_alloc_slab,
+ mempool_free_slab,
+ dwarf_reg_cachep);
+
+ err = dwarf_parse_section(__start_eh_frame, __stop_eh_frame, NULL);
+ if (err)
+ goto out;
+
err = unwinder_register(&dwarf_unwinder);
if (err)
goto out;
diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S
index 3eb8493..f0abd58 100644
--- a/arch/sh/kernel/entry-common.S
+++ b/arch/sh/kernel/entry-common.S
@@ -133,7 +133,7 @@ work_pending:
! r8: current_thread_info
! t: result of "tst #_TIF_NEED_RESCHED, r0"
bf/s work_resched
- tst #(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), r0
+ tst #_TIF_SIGPENDING, r0
work_notifysig:
bt/s __restore_all
mov r15, r4
diff --git a/arch/sh/kernel/ftrace.c b/arch/sh/kernel/ftrace.c
index 2c48e26..b6f41c1 100644
--- a/arch/sh/kernel/ftrace.c
+++ b/arch/sh/kernel/ftrace.c
@@ -62,6 +62,150 @@ static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
return ftrace_replaced_code;
}
+/*
+ * Modifying code must take extra care. On an SMP machine, if
+ * the code being modified is also being executed on another CPU
+ * that CPU will have undefined results and possibly take a GPF.
+ * We use kstop_machine to stop other CPUS from exectuing code.
+ * But this does not stop NMIs from happening. We still need
+ * to protect against that. We separate out the modification of
+ * the code to take care of this.
+ *
+ * Two buffers are added: An IP buffer and a "code" buffer.
+ *
+ * 1) Put the instruction pointer into the IP buffer
+ * and the new code into the "code" buffer.
+ * 2) Wait for any running NMIs to finish and set a flag that says
+ * we are modifying code, it is done in an atomic operation.
+ * 3) Write the code
+ * 4) clear the flag.
+ * 5) Wait for any running NMIs to finish.
+ *
+ * If an NMI is executed, the first thing it does is to call
+ * "ftrace_nmi_enter". This will check if the flag is set to write
+ * and if it is, it will write what is in the IP and "code" buffers.
+ *
+ * The trick is, it does not matter if everyone is writing the same
+ * content to the code location. Also, if a CPU is executing code
+ * it is OK to write to that code location if the contents being written
+ * are the same as what exists.
+ */
+#define MOD_CODE_WRITE_FLAG (1 << 31) /* set when NMI should do the write */
+static atomic_t nmi_running = ATOMIC_INIT(0);
+static int mod_code_status; /* holds return value of text write */
+static void *mod_code_ip; /* holds the IP to write to */
+static void *mod_code_newcode; /* holds the text to write to the IP */
+
+static unsigned nmi_wait_count;
+static atomic_t nmi_update_count = ATOMIC_INIT(0);
+
+int ftrace_arch_read_dyn_info(char *buf, int size)
+{
+ int r;
+
+ r = snprintf(buf, size, "%u %u",
+ nmi_wait_count,
+ atomic_read(&nmi_update_count));
+ return r;
+}
+
+static void clear_mod_flag(void)
+{
+ int old = atomic_read(&nmi_running);
+
+ for (;;) {
+ int new = old & ~MOD_CODE_WRITE_FLAG;
+
+ if (old == new)
+ break;
+
+ old = atomic_cmpxchg(&nmi_running, old, new);
+ }
+}
+
+static void ftrace_mod_code(void)
+{
+ /*
+ * Yes, more than one CPU process can be writing to mod_code_status.
+ * (and the code itself)
+ * But if one were to fail, then they all should, and if one were
+ * to succeed, then they all should.
+ */
+ mod_code_status = probe_kernel_write(mod_code_ip, mod_code_newcode,
+ MCOUNT_INSN_SIZE);
+
+ /* if we fail, then kill any new writers */
+ if (mod_code_status)
+ clear_mod_flag();
+}
+
+void ftrace_nmi_enter(void)
+{
+ if (atomic_inc_return(&nmi_running) & MOD_CODE_WRITE_FLAG) {
+ smp_rmb();
+ ftrace_mod_code();
+ atomic_inc(&nmi_update_count);
+ }
+ /* Must have previous changes seen before executions */
+ smp_mb();
+}
+
+void ftrace_nmi_exit(void)
+{
+ /* Finish all executions before clearing nmi_running */
+ smp_mb();
+ atomic_dec(&nmi_running);
+}
+
+static void wait_for_nmi_and_set_mod_flag(void)
+{
+ if (!atomic_cmpxchg(&nmi_running, 0, MOD_CODE_WRITE_FLAG))
+ return;
+
+ do {
+ cpu_relax();
+ } while (atomic_cmpxchg(&nmi_running, 0, MOD_CODE_WRITE_FLAG));
+
+ nmi_wait_count++;
+}
+
+static void wait_for_nmi(void)
+{
+ if (!atomic_read(&nmi_running))
+ return;
+
+ do {
+ cpu_relax();
+ } while (atomic_read(&nmi_running));
+
+ nmi_wait_count++;
+}
+
+static int
+do_ftrace_mod_code(unsigned long ip, void *new_code)
+{
+ mod_code_ip = (void *)ip;
+ mod_code_newcode = new_code;
+
+ /* The buffers need to be visible before we let NMIs write them */
+ smp_mb();
+
+ wait_for_nmi_and_set_mod_flag();
+
+ /* Make sure all running NMIs have finished before we write the code */
+ smp_mb();
+
+ ftrace_mod_code();
+
+ /* Make sure the write happens before clearing the bit */
+ smp_mb();
+
+ clear_mod_flag();
+ wait_for_nmi();
+
+ return mod_code_status;
+}
+
static int ftrace_modify_code(unsigned long ip, unsigned char *old_code,
unsigned char *new_code)
{
@@ -86,7 +230,7 @@ static int ftrace_modify_code(unsigned long ip, unsigned char *old_code,
return -EINVAL;
/* replace the text with the new text */
- if (probe_kernel_write((void *)ip, new_code, MCOUNT_INSN_SIZE))
+ if (do_ftrace_mod_code(ip, new_code))
return -EPERM;
flush_icache_range(ip, ip + MCOUNT_INSN_SIZE);
diff --git a/arch/sh/kernel/head_32.S b/arch/sh/kernel/head_32.S
index a78be74..1151ecd 100644
--- a/arch/sh/kernel/head_32.S
+++ b/arch/sh/kernel/head_32.S
@@ -33,7 +33,7 @@ ENTRY(empty_zero_page)
.long 1 /* LOADER_TYPE */
.long 0x00000000 /* INITRD_START */
.long 0x00000000 /* INITRD_SIZE */
-#ifdef CONFIG_32BIT
+#if defined(CONFIG_32BIT) && defined(CONFIG_PMB_FIXED)
.long 0x53453f00 + 32 /* "SE?" = 32 bit */
#else
.long 0x53453f00 + 29 /* "SE?" = 29 bit */
diff --git a/arch/sh/kernel/idle.c b/arch/sh/kernel/idle.c
index 27ff2dc..aaff003 100644
--- a/arch/sh/kernel/idle.c
+++ b/arch/sh/kernel/idle.c
@@ -21,7 +21,7 @@
#include <asm/atomic.h>
static int hlt_counter;
-void (*pm_idle)(void);
+void (*pm_idle)(void) = NULL;
void (*pm_power_off)(void);
EXPORT_SYMBOL(pm_power_off);
@@ -39,48 +39,92 @@ static int __init hlt_setup(char *__unused)
}
__setup("hlt", hlt_setup);
+static inline int hlt_works(void)
+{
+ return !hlt_counter;
+}
+
+/*
+ * On SMP it's slightly faster (but much more power-consuming!)
+ * to poll the ->work.need_resched flag instead of waiting for the
+ * cross-CPU IPI to arrive. Use this option with caution.
+ */
+static void poll_idle(void)
+{
+ local_irq_enable();
+ while (!need_resched())
+ cpu_relax();
+}
+
void default_idle(void)
{
- if (!hlt_counter) {
+ if (hlt_works()) {
clear_thread_flag(TIF_POLLING_NRFLAG);
smp_mb__after_clear_bit();
- set_bl_bit();
- stop_critical_timings();
- while (!need_resched())
+ if (!need_resched()) {
+ local_irq_enable();
cpu_sleep();
+ } else
+ local_irq_enable();
- start_critical_timings();
- clear_bl_bit();
set_thread_flag(TIF_POLLING_NRFLAG);
} else
- while (!need_resched())
- cpu_relax();
+ poll_idle();
}
+/*
+ * The idle thread. There's no useful work to be done, so just try to conserve
+ * power and have a low exit latency (ie sit in a loop waiting for somebody to
+ * say that they'd like to reschedule)
+ */
void cpu_idle(void)
{
+ unsigned int cpu = smp_processor_id();
+
set_thread_flag(TIF_POLLING_NRFLAG);
/* endless idle loop with no priority at all */
while (1) {
- void (*idle)(void) = pm_idle;
+ tick_nohz_stop_sched_tick(1);
- if (!idle)
- idle = default_idle;
+ while (!need_resched() && cpu_online(cpu)) {
+ check_pgt_cache();
+ rmb();
- tick_nohz_stop_sched_tick(1);
- while (!need_resched())
- idle();
- tick_nohz_restart_sched_tick();
+ local_irq_disable();
+ /* Don't trace irqs off for idle */
+ stop_critical_timings();
+ pm_idle();
+ /*
+ * Sanity check to ensure that pm_idle() returns
+ * with IRQs enabled
+ */
+ WARN_ON(irqs_disabled());
+ start_critical_timings();
+ }
+ tick_nohz_restart_sched_tick();
preempt_enable_no_resched();
schedule();
preempt_disable();
- check_pgt_cache();
}
}
+void __cpuinit select_idle_routine(void)
+{
+ /*
+ * If a platform has set its own idle routine, leave it alone.
+ */
+ if (pm_idle)
+ return;
+
+ if (hlt_works())
+ pm_idle = default_idle;
+ else
+ pm_idle = poll_idle;
+}
+
static void do_nothing(void *unused)
{
}
diff --git a/arch/sh/kernel/io_generic.c b/arch/sh/kernel/io_generic.c
index b8fa652..e1e1dbd 100644
--- a/arch/sh/kernel/io_generic.c
+++ b/arch/sh/kernel/io_generic.c
@@ -24,7 +24,7 @@
#define dummy_read()
#endif
-unsigned long generic_io_base;
+unsigned long generic_io_base = 0;
u8 generic_inb(unsigned long port)
{
@@ -147,8 +147,10 @@ void generic_outsl(unsigned long port, const void *src, unsigned long count)
void __iomem *generic_ioport_map(unsigned long addr, unsigned int size)
{
+#ifdef P1SEG
if (PXSEG(addr) >= P1SEG)
return (void __iomem *)addr;
+#endif
return (void __iomem *)(addr + generic_io_base);
}
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c
index eac7da7..e1913f2 100644
--- a/arch/sh/kernel/irq.c
+++ b/arch/sh/kernel/irq.c
@@ -37,7 +37,15 @@ void ack_bad_irq(unsigned int irq)
*/
static int show_other_interrupts(struct seq_file *p, int prec)
{
+ int j;
+
+ seq_printf(p, "%*s: ", prec, "NMI");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", irq_stat[j].__nmi_count);
+ seq_printf(p, " Non-maskable interrupts\n");
+
seq_printf(p, "%*s: %10u\n", prec, "ERR", atomic_read(&irq_err_count));
+
return 0;
}
@@ -255,6 +263,12 @@ void __init init_IRQ(void)
{
plat_irq_setup();
+ /*
+ * Pin any of the legacy IRQ vectors that haven't already been
+ * grabbed by the platform
+ */
+ reserve_irq_legacy();
+
/* Perform the machine specific initialisation */
if (sh_mv.mv_init_irq)
sh_mv.mv_init_irq();
diff --git a/arch/sh/kernel/irq_32.c b/arch/sh/kernel/irq_32.c
new file mode 100644
index 0000000..e33ab15
--- /dev/null
+++ b/arch/sh/kernel/irq_32.c
@@ -0,0 +1,57 @@
+/*
+ * SHcompact irqflags support
+ *
+ * Copyright (C) 2006 - 2009 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/irqflags.h>
+#include <linux/module.h>
+
+void notrace raw_local_irq_restore(unsigned long flags)
+{
+ unsigned long __dummy0, __dummy1;
+
+ if (flags == RAW_IRQ_DISABLED) {
+ __asm__ __volatile__ (
+ "stc sr, %0\n\t"
+ "or #0xf0, %0\n\t"
+ "ldc %0, sr\n\t"
+ : "=&z" (__dummy0)
+ : /* no inputs */
+ : "memory"
+ );
+ } else {
+ __asm__ __volatile__ (
+ "stc sr, %0\n\t"
+ "and %1, %0\n\t"
+#ifdef CONFIG_CPU_HAS_SR_RB
+ "stc r6_bank, %1\n\t"
+ "or %1, %0\n\t"
+#endif
+ "ldc %0, sr\n\t"
+ : "=&r" (__dummy0), "=r" (__dummy1)
+ : "1" (~RAW_IRQ_DISABLED)
+ : "memory"
+ );
+ }
+}
+EXPORT_SYMBOL(raw_local_irq_restore);
+
+unsigned long notrace __raw_local_save_flags(void)
+{
+ unsigned long flags;
+
+ __asm__ __volatile__ (
+ "stc sr, %0\n\t"
+ "and #0xf0, %0\n\t"
+ : "=&z" (flags)
+ : /* no inputs */
+ : "memory"
+ );
+
+ return flags;
+}
+EXPORT_SYMBOL(__raw_local_save_flags);
diff --git a/arch/sh/kernel/irq_64.c b/arch/sh/kernel/irq_64.c
new file mode 100644
index 0000000..32365ba
--- /dev/null
+++ b/arch/sh/kernel/irq_64.c
@@ -0,0 +1,51 @@
+/*
+ * SHmedia irqflags support
+ *
+ * Copyright (C) 2006 - 2009 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/irqflags.h>
+#include <linux/module.h>
+#include <cpu/registers.h>
+
+void notrace raw_local_irq_restore(unsigned long flags)
+{
+ unsigned long long __dummy;
+
+ if (flags == RAW_IRQ_DISABLED) {
+ __asm__ __volatile__ (
+ "getcon " __SR ", %0\n\t"
+ "or %0, %1, %0\n\t"
+ "putcon %0, " __SR "\n\t"
+ : "=&r" (__dummy)
+ : "r" (RAW_IRQ_DISABLED)
+ );
+ } else {
+ __asm__ __volatile__ (
+ "getcon " __SR ", %0\n\t"
+ "and %0, %1, %0\n\t"
+ "putcon %0, " __SR "\n\t"
+ : "=&r" (__dummy)
+ : "r" (~RAW_IRQ_DISABLED)
+ );
+ }
+}
+EXPORT_SYMBOL(raw_local_irq_restore);
+
+unsigned long notrace __raw_local_save_flags(void)
+{
+ unsigned long flags;
+
+ __asm__ __volatile__ (
+ "getcon " __SR ", %0\n\t"
+ "and %0, %1, %0"
+ : "=&r" (flags)
+ : "r" (RAW_IRQ_DISABLED)
+ );
+
+ return flags;
+}
+EXPORT_SYMBOL(__raw_local_save_flags);
diff --git a/arch/sh/kernel/machine_kexec.c b/arch/sh/kernel/machine_kexec.c
index 7ea2704..76f2802 100644
--- a/arch/sh/kernel/machine_kexec.c
+++ b/arch/sh/kernel/machine_kexec.c
@@ -46,12 +46,6 @@ void machine_crash_shutdown(struct pt_regs *regs)
*/
int machine_kexec_prepare(struct kimage *image)
{
- /* older versions of kexec-tools are passing
- * the zImage entry point as a virtual address.
- */
- if (image->start != PHYSADDR(image->start))
- return -EINVAL; /* upgrade your kexec-tools */
-
return 0;
}
diff --git a/arch/sh/kernel/machvec.c b/arch/sh/kernel/machvec.c
index cbce639..1652340 100644
--- a/arch/sh/kernel/machvec.c
+++ b/arch/sh/kernel/machvec.c
@@ -135,5 +135,9 @@ void __init sh_mv_setup(void)
if (!sh_mv.mv_nr_irqs)
sh_mv.mv_nr_irqs = NR_IRQS;
+#ifdef P2SEG
__set_io_port_base(P2SEG);
+#else
+ __set_io_port_base(0);
+#endif
}
diff --git a/arch/sh/kernel/module.c b/arch/sh/kernel/module.c
index c2efdcd..43adddf 100644
--- a/arch/sh/kernel/module.c
+++ b/arch/sh/kernel/module.c
@@ -32,6 +32,7 @@
#include <linux/string.h>
#include <linux/kernel.h>
#include <asm/unaligned.h>
+#include <asm/dwarf.h>
void *module_alloc(unsigned long size)
{
@@ -145,10 +146,16 @@ int module_finalize(const Elf_Ehdr *hdr,
const Elf_Shdr *sechdrs,
struct module *me)
{
- return module_bug_finalize(hdr, sechdrs, me);
+ int ret = 0;
+
+ ret |= module_dwarf_finalize(hdr, sechdrs, me);
+ ret |= module_bug_finalize(hdr, sechdrs, me);
+
+ return ret;
}
void module_arch_cleanup(struct module *mod)
{
module_bug_cleanup(mod);
+ module_dwarf_cleanup(mod);
}
diff --git a/arch/sh/kernel/perf_callchain.c b/arch/sh/kernel/perf_callchain.c
new file mode 100644
index 0000000..24ea837
--- /dev/null
+++ b/arch/sh/kernel/perf_callchain.c
@@ -0,0 +1,98 @@
+/*
+ * Performance event callchain support - SuperH architecture code
+ *
+ * Copyright (C) 2009 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/kernel.h>
+#include <linux/sched.h>
+#include <linux/perf_event.h>
+#include <linux/percpu.h>
+#include <asm/unwinder.h>
+#include <asm/ptrace.h>
+
+static inline void callchain_store(struct perf_callchain_entry *entry, u64 ip)
+{
+ if (entry->nr < PERF_MAX_STACK_DEPTH)
+ entry->ip[entry->nr++] = ip;
+}
+
+static void callchain_warning(void *data, char *msg)
+{
+}
+
+static void
+callchain_warning_symbol(void *data, char *msg, unsigned long symbol)
+{
+}
+
+static int callchain_stack(void *data, char *name)
+{
+ return 0;
+}
+
+static void callchain_address(void *data, unsigned long addr, int reliable)
+{
+ struct perf_callchain_entry *entry = data;
+
+ if (reliable)
+ callchain_store(entry, addr);
+}
+
+static const struct stacktrace_ops callchain_ops = {
+ .warning = callchain_warning,
+ .warning_symbol = callchain_warning_symbol,
+ .stack = callchain_stack,
+ .address = callchain_address,
+};
+
+static void
+perf_callchain_kernel(struct pt_regs *regs, struct perf_callchain_entry *entry)
+{
+ callchain_store(entry, PERF_CONTEXT_KERNEL);
+ callchain_store(entry, regs->pc);
+
+ unwind_stack(NULL, regs, NULL, &callchain_ops, entry);
+}
+
+static void
+perf_do_callchain(struct pt_regs *regs, struct perf_callchain_entry *entry)
+{
+ int is_user;
+
+ if (!regs)
+ return;
+
+ is_user = user_mode(regs);
+
+ if (!current || current->pid == 0)
+ return;
+
+ if (is_user && current->state != TASK_RUNNING)
+ return;
+
+ /*
+ * Only the kernel side is implemented for now.
+ */
+ if (!is_user)
+ perf_callchain_kernel(regs, entry);
+}
+
+/*
+ * No need for separate IRQ and NMI entries.
+ */
+static DEFINE_PER_CPU(struct perf_callchain_entry, callchain);
+
+struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
+{
+ struct perf_callchain_entry *entry = &__get_cpu_var(callchain);
+
+ entry->nr = 0;
+
+ perf_do_callchain(regs, entry);
+
+ return entry;
+}
diff --git a/arch/sh/kernel/perf_event.c b/arch/sh/kernel/perf_event.c
new file mode 100644
index 0000000..7ff0943
--- /dev/null
+++ b/arch/sh/kernel/perf_event.c
@@ -0,0 +1,312 @@
+/*
+ * Performance event support framework for SuperH hardware counters.
+ *
+ * Copyright (C) 2009 Paul Mundt
+ *
+ * Heavily based on the x86 and PowerPC implementations.
+ *
+ * x86:
+ * Copyright (C) 2008 Thomas Gleixner <tglx@linutronix.de>
+ * Copyright (C) 2008-2009 Red Hat, Inc., Ingo Molnar
+ * Copyright (C) 2009 Jaswinder Singh Rajput
+ * Copyright (C) 2009 Advanced Micro Devices, Inc., Robert Richter
+ * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ * Copyright (C) 2009 Intel Corporation, <markus.t.metzger@intel.com>
+ *
+ * ppc:
+ * Copyright 2008-2009 Paul Mackerras, IBM Corporation.
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/perf_event.h>
+#include <asm/processor.h>
+
+struct cpu_hw_events {
+ struct perf_event *events[MAX_HWEVENTS];
+ unsigned long used_mask[BITS_TO_LONGS(MAX_HWEVENTS)];
+ unsigned long active_mask[BITS_TO_LONGS(MAX_HWEVENTS)];
+};
+
+DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
+
+static struct sh_pmu *sh_pmu __read_mostly;
+
+/* Number of perf_events counting hardware events */
+static atomic_t num_events;
+/* Used to avoid races in calling reserve/release_pmc_hardware */
+static DEFINE_MUTEX(pmc_reserve_mutex);
+
+/*
+ * Stub these out for now, do something more profound later.
+ */
+int reserve_pmc_hardware(void)
+{
+ return 0;
+}
+
+void release_pmc_hardware(void)
+{
+}
+
+static inline int sh_pmu_initialized(void)
+{
+ return !!sh_pmu;
+}
+
+/*
+ * Release the PMU if this is the last perf_event.
+ */
+static void hw_perf_event_destroy(struct perf_event *event)
+{
+ if (!atomic_add_unless(&num_events, -1, 1)) {
+ mutex_lock(&pmc_reserve_mutex);
+ if (atomic_dec_return(&num_events) == 0)
+ release_pmc_hardware();
+ mutex_unlock(&pmc_reserve_mutex);
+ }
+}
+
+static int hw_perf_cache_event(int config, int *evp)
+{
+ unsigned long type, op, result;
+ int ev;
+
+ if (!sh_pmu->cache_events)
+ return -EINVAL;
+
+ /* unpack config */
+ type = config & 0xff;
+ op = (config >> 8) & 0xff;
+ result = (config >> 16) & 0xff;
+
+ if (type >= PERF_COUNT_HW_CACHE_MAX ||
+ op >= PERF_COUNT_HW_CACHE_OP_MAX ||
+ result >= PERF_COUNT_HW_CACHE_RESULT_MAX)
+ return -EINVAL;
+
+ ev = (*sh_pmu->cache_events)[type][op][result];
+ if (ev == 0)
+ return -EOPNOTSUPP;
+ if (ev == -1)
+ return -EINVAL;
+ *evp = ev;
+ return 0;
+}
+
+static int __hw_perf_event_init(struct perf_event *event)
+{
+ struct perf_event_attr *attr = &event->attr;
+ struct hw_perf_event *hwc = &event->hw;
+ int config = -1;
+ int err;
+
+ if (!sh_pmu_initialized())
+ return -ENODEV;
+
+ /*
+ * All of the on-chip counters are "limited", in that they have
+ * no interrupts, and are therefore unable to do sampling without
+ * further work and timer assistance.
+ */
+ if (hwc->sample_period)
+ return -EINVAL;
+
+ /*
+ * See if we need to reserve the counter.
+ *
+ * If no events are currently in use, then we have to take a
+ * mutex to ensure that we don't race with another task doing
+ * reserve_pmc_hardware or release_pmc_hardware.
+ */
+ err = 0;
+ if (!atomic_inc_not_zero(&num_events)) {
+ mutex_lock(&pmc_reserve_mutex);
+ if (atomic_read(&num_events) == 0 &&
+ reserve_pmc_hardware())
+ err = -EBUSY;
+ else
+ atomic_inc(&num_events);
+ mutex_unlock(&pmc_reserve_mutex);
+ }
+
+ if (err)
+ return err;
+
+ event->destroy = hw_perf_event_destroy;
+
+ switch (attr->type) {
+ case PERF_TYPE_RAW:
+ config = attr->config & sh_pmu->raw_event_mask;
+ break;
+ case PERF_TYPE_HW_CACHE:
+ err = hw_perf_cache_event(attr->config, &config);
+ if (err)
+ return err;
+ break;
+ case PERF_TYPE_HARDWARE:
+ if (attr->config >= sh_pmu->max_events)
+ return -EINVAL;
+
+ config = sh_pmu->event_map(attr->config);
+ break;
+ }
+
+ if (config == -1)
+ return -EINVAL;
+
+ hwc->config |= config;
+
+ return 0;
+}
+
+static void sh_perf_event_update(struct perf_event *event,
+ struct hw_perf_event *hwc, int idx)
+{
+ u64 prev_raw_count, new_raw_count;
+ s64 delta;
+ int shift = 0;
+
+ /*
+ * Depending on the counter configuration, they may or may not
+ * be chained, in which case the previous counter value can be
+ * updated underneath us if the lower-half overflows.
+ *
+ * Our tactic to handle this is to first atomically read and
+ * exchange a new raw count - then add that new-prev delta
+ * count to the generic counter atomically.
+ *
+ * As there is no interrupt associated with the overflow events,
+ * this is the simplest approach for maintaining consistency.
+ */
+again:
+ prev_raw_count = atomic64_read(&hwc->prev_count);
+ new_raw_count = sh_pmu->read(idx);
+
+ if (atomic64_cmpxchg(&hwc->prev_count, prev_raw_count,
+ new_raw_count) != prev_raw_count)
+ goto again;
+
+ /*
+ * Now we have the new raw value and have updated the prev
+ * timestamp already. We can now calculate the elapsed delta
+ * (counter-)time and add that to the generic counter.
+ *
+ * Careful, not all hw sign-extends above the physical width
+ * of the count.
+ */
+ delta = (new_raw_count << shift) - (prev_raw_count << shift);
+ delta >>= shift;
+
+ atomic64_add(delta, &event->count);
+}
+
+static void sh_pmu_disable(struct perf_event *event)
+{
+ struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+ struct hw_perf_event *hwc = &event->hw;
+ int idx = hwc->idx;
+
+ clear_bit(idx, cpuc->active_mask);
+ sh_pmu->disable(hwc, idx);
+
+ barrier();
+
+ sh_perf_event_update(event, &event->hw, idx);
+
+ cpuc->events[idx] = NULL;
+ clear_bit(idx, cpuc->used_mask);
+
+ perf_event_update_userpage(event);
+}
+
+static int sh_pmu_enable(struct perf_event *event)
+{
+ struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+ struct hw_perf_event *hwc = &event->hw;
+ int idx = hwc->idx;
+
+ if (test_and_set_bit(idx, cpuc->used_mask)) {
+ idx = find_first_zero_bit(cpuc->used_mask, sh_pmu->num_events);
+ if (idx == sh_pmu->num_events)
+ return -EAGAIN;
+
+ set_bit(idx, cpuc->used_mask);
+ hwc->idx = idx;
+ }
+
+ sh_pmu->disable(hwc, idx);
+
+ cpuc->events[idx] = event;
+ set_bit(idx, cpuc->active_mask);
+
+ sh_pmu->enable(hwc, idx);
+
+ perf_event_update_userpage(event);
+
+ return 0;
+}
+
+static void sh_pmu_read(struct perf_event *event)
+{
+ sh_perf_event_update(event, &event->hw, event->hw.idx);
+}
+
+static const struct pmu pmu = {
+ .enable = sh_pmu_enable,
+ .disable = sh_pmu_disable,
+ .read = sh_pmu_read,
+};
+
+const struct pmu *hw_perf_event_init(struct perf_event *event)
+{
+ int err = __hw_perf_event_init(event);
+ if (unlikely(err)) {
+ if (event->destroy)
+ event->destroy(event);
+ return ERR_PTR(err);
+ }
+
+ return &pmu;
+}
+
+void hw_perf_event_setup(int cpu)
+{
+ struct cpu_hw_events *cpuhw = &per_cpu(cpu_hw_events, cpu);
+
+ memset(cpuhw, 0, sizeof(struct cpu_hw_events));
+}
+
+void hw_perf_enable(void)
+{
+ if (!sh_pmu_initialized())
+ return;
+
+ sh_pmu->enable_all();
+}
+
+void hw_perf_disable(void)
+{
+ if (!sh_pmu_initialized())
+ return;
+
+ sh_pmu->disable_all();
+}
+
+int register_sh_pmu(struct sh_pmu *pmu)
+{
+ if (sh_pmu)
+ return -EBUSY;
+ sh_pmu = pmu;
+
+ pr_info("Performance Events: %s support registered\n", pmu->name);
+
+ WARN_ON(pmu->num_events > MAX_HWEVENTS);
+
+ return 0;
+}
diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c
index 0673c47..d8af889 100644
--- a/arch/sh/kernel/process_32.c
+++ b/arch/sh/kernel/process_32.c
@@ -134,7 +134,10 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
regs.regs[5] = (unsigned long)fn;
regs.pc = (unsigned long)kernel_thread_helper;
- regs.sr = (1 << 30);
+ regs.sr = SR_MD;
+#if defined(CONFIG_SH_FPU)
+ regs.sr |= SR_FD;
+#endif
/* Ok, create the new process.. */
pid = do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
@@ -142,6 +145,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
return pid;
}
+EXPORT_SYMBOL(kernel_thread);
/*
* Free current thread data structures etc..
@@ -186,6 +190,16 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
return fpvalid;
}
+EXPORT_SYMBOL(dump_fpu);
+
+/*
+ * This gets called before we allocate a new thread and copy
+ * the current task into it.
+ */
+void prepare_to_copy(struct task_struct *tsk)
+{
+ unlazy_fpu(tsk, task_pt_regs(tsk));
+}
asmlinkage void ret_from_fork(void);
@@ -195,16 +209,10 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
{
struct thread_info *ti = task_thread_info(p);
struct pt_regs *childregs;
-#if defined(CONFIG_SH_FPU) || defined(CONFIG_SH_DSP)
+#if defined(CONFIG_SH_DSP)
struct task_struct *tsk = current;
#endif
-#if defined(CONFIG_SH_FPU)
- unlazy_fpu(tsk, regs);
- p->thread.fpu = tsk->thread.fpu;
- copy_to_stopped_child_used_math(p);
-#endif
-
#if defined(CONFIG_SH_DSP)
if (is_dsp_enabled(tsk)) {
/* We can use the __save_dsp or just copy the struct:
@@ -224,6 +232,8 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
} else {
childregs->regs[15] = (unsigned long)childregs;
ti->addr_limit = KERNEL_DS;
+ ti->status &= ~TS_USEDFPU;
+ p->fpu_counter = 0;
}
if (clone_flags & CLONE_SETTLS)
@@ -288,9 +298,13 @@ static void ubc_set_tracing(int asid, unsigned long pc)
__notrace_funcgraph struct task_struct *
__switch_to(struct task_struct *prev, struct task_struct *next)
{
-#if defined(CONFIG_SH_FPU)
+ struct thread_struct *next_t = &next->thread;
+
unlazy_fpu(prev, task_pt_regs(prev));
-#endif
+
+ /* we're going to use this soon, after a few expensive things */
+ if (next->fpu_counter > 5)
+ prefetch(&next_t->fpu.hard);
#ifdef CONFIG_MMU
/*
@@ -321,6 +335,14 @@ __switch_to(struct task_struct *prev, struct task_struct *next)
#endif
}
+ /*
+ * If the task has used fpu the last 5 timeslices, just do a full
+ * restore of the math state immediately to avoid the trap; the
+ * chances of needing FPU soon are obviously high now
+ */
+ if (next->fpu_counter > 5)
+ fpu_state_restore(task_pt_regs(next));
+
return prev;
}
diff --git a/arch/sh/kernel/process_64.c b/arch/sh/kernel/process_64.c
index 1192398..359b8a2 100644
--- a/arch/sh/kernel/process_64.c
+++ b/arch/sh/kernel/process_64.c
@@ -335,6 +335,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
&regs, 0, NULL, NULL);
}
+EXPORT_SYMBOL(kernel_thread);
/*
* Free current thread data structures etc..
@@ -417,6 +418,7 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
return 0; /* Task didn't use the fpu at all. */
#endif
}
+EXPORT_SYMBOL(dump_fpu);
asmlinkage void ret_from_fork(void);
diff --git a/arch/sh/kernel/return_address.c b/arch/sh/kernel/return_address.c
new file mode 100644
index 0000000..df3ab58
--- /dev/null
+++ b/arch/sh/kernel/return_address.c
@@ -0,0 +1,54 @@
+/*
+ * arch/sh/kernel/return_address.c
+ *
+ * Copyright (C) 2009 Matt Fleming
+ * Copyright (C) 2009 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/kernel.h>
+#include <asm/dwarf.h>
+
+#ifdef CONFIG_DWARF_UNWINDER
+
+void *return_address(unsigned int depth)
+{
+ struct dwarf_frame *frame;
+ unsigned long ra;
+ int i;
+
+ for (i = 0, frame = NULL, ra = 0; i <= depth; i++) {
+ struct dwarf_frame *tmp;
+
+ tmp = dwarf_unwind_stack(ra, frame);
+
+ if (frame)
+ dwarf_free_frame(frame);
+
+ frame = tmp;
+
+ if (!frame || !frame->return_addr)
+ break;
+
+ ra = frame->return_addr;
+ }
+
+ /* Failed to unwind the stack to the specified depth. */
+ WARN_ON(i != depth + 1);
+
+ if (frame)
+ dwarf_free_frame(frame);
+
+ return (void *)ra;
+}
+
+#else
+
+void *return_address(unsigned int depth)
+{
+ return NULL;
+}
+
+#endif
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
index 99b4fb5..5a947a2 100644
--- a/arch/sh/kernel/setup.c
+++ b/arch/sh/kernel/setup.c
@@ -453,6 +453,10 @@ void __init setup_arch(char **cmdline_p)
paging_init();
+#ifdef CONFIG_PMB_ENABLE
+ pmb_init();
+#endif
+
#ifdef CONFIG_SMP
plat_smp_setup();
#endif
diff --git a/arch/sh/kernel/sh_ksyms_32.c b/arch/sh/kernel/sh_ksyms_32.c
index 444cce3..3896f26 100644
--- a/arch/sh/kernel/sh_ksyms_32.c
+++ b/arch/sh/kernel/sh_ksyms_32.c
@@ -1,37 +1,11 @@
#include <linux/module.h>
-#include <linux/smp.h>
-#include <linux/user.h>
-#include <linux/elfcore.h>
-#include <linux/sched.h>
-#include <linux/in6.h>
-#include <linux/interrupt.h>
-#include <linux/vmalloc.h>
-#include <linux/pci.h>
-#include <linux/irq.h>
-#include <asm/sections.h>
-#include <asm/processor.h>
-#include <asm/uaccess.h>
+#include <linux/string.h>
+#include <linux/uaccess.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
#include <asm/checksum.h>
-#include <asm/io.h>
-#include <asm/delay.h>
-#include <asm/tlbflush.h>
-#include <asm/cacheflush.h>
-#include <asm/ftrace.h>
-
-extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
-
-/* platform dependent support */
-EXPORT_SYMBOL(dump_fpu);
-EXPORT_SYMBOL(kernel_thread);
-EXPORT_SYMBOL(strlen);
-
-/* PCI exports */
-#ifdef CONFIG_PCI
-EXPORT_SYMBOL(pci_alloc_consistent);
-EXPORT_SYMBOL(pci_free_consistent);
-#endif
+#include <asm/sections.h>
-/* mem exports */
EXPORT_SYMBOL(memchr);
EXPORT_SYMBOL(memcpy);
EXPORT_SYMBOL(memset);
@@ -40,6 +14,13 @@ EXPORT_SYMBOL(__copy_user);
EXPORT_SYMBOL(__udelay);
EXPORT_SYMBOL(__ndelay);
EXPORT_SYMBOL(__const_udelay);
+EXPORT_SYMBOL(strlen);
+EXPORT_SYMBOL(csum_partial);
+EXPORT_SYMBOL(csum_partial_copy_generic);
+EXPORT_SYMBOL(copy_page);
+EXPORT_SYMBOL(__clear_user);
+EXPORT_SYMBOL(_ebss);
+EXPORT_SYMBOL(empty_zero_page);
#define DECLARE_EXPORT(name) \
extern void name(void);EXPORT_SYMBOL(name)
@@ -107,30 +88,6 @@ DECLARE_EXPORT(__sdivsi3_i4);
DECLARE_EXPORT(__udivsi3_i4);
DECLARE_EXPORT(__sdivsi3_i4i);
DECLARE_EXPORT(__udivsi3_i4i);
-
-#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);
-EXPORT_SYMBOL(flush_dcache_page);
-#endif
-
#ifdef CONFIG_MCOUNT
DECLARE_EXPORT(mcount);
#endif
-EXPORT_SYMBOL(csum_partial);
-EXPORT_SYMBOL(csum_partial_copy_generic);
-#ifdef CONFIG_IPV6
-EXPORT_SYMBOL(csum_ipv6_magic);
-#endif
-EXPORT_SYMBOL(copy_page);
-EXPORT_SYMBOL(__clear_user);
-EXPORT_SYMBOL(_ebss);
-EXPORT_SYMBOL(empty_zero_page);
-
-#ifndef CONFIG_CACHE_OFF
-EXPORT_SYMBOL(__flush_purge_region);
-EXPORT_SYMBOL(__flush_wback_region);
-EXPORT_SYMBOL(__flush_invalidate_region);
-#endif
diff --git a/arch/sh/kernel/sh_ksyms_64.c b/arch/sh/kernel/sh_ksyms_64.c
index d008e17..45afa5c 100644
--- a/arch/sh/kernel/sh_ksyms_64.c
+++ b/arch/sh/kernel/sh_ksyms_64.c
@@ -24,16 +24,6 @@
#include <asm/delay.h>
#include <asm/irq.h>
-extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
-
-/* platform dependent support */
-EXPORT_SYMBOL(dump_fpu);
-EXPORT_SYMBOL(kernel_thread);
-
-#ifdef CONFIG_VT
-EXPORT_SYMBOL(screen_info);
-#endif
-
EXPORT_SYMBOL(__put_user_asm_b);
EXPORT_SYMBOL(__put_user_asm_w);
EXPORT_SYMBOL(__put_user_asm_l);
diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c
index 3db3742..12815ce 100644
--- a/arch/sh/kernel/signal_32.c
+++ b/arch/sh/kernel/signal_32.c
@@ -67,7 +67,8 @@ sys_sigsuspend(old_sigset_t mask,
current->state = TASK_INTERRUPTIBLE;
schedule();
- set_thread_flag(TIF_RESTORE_SIGMASK);
+ set_restore_sigmask();
+
return -ERESTARTNOHAND;
}
@@ -590,7 +591,7 @@ static void do_signal(struct pt_regs *regs, unsigned int save_r0)
if (try_to_freeze())
goto no_signal;
- if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ if (current_thread_info()->status & TS_RESTORE_SIGMASK)
oldset = &current->saved_sigmask;
else
oldset = &current->blocked;
@@ -602,12 +603,13 @@ static void do_signal(struct pt_regs *regs, unsigned int save_r0)
/* Whee! Actually deliver the signal. */
if (handle_signal(signr, &ka, &info, oldset,
regs, save_r0) == 0) {
- /* a signal was successfully delivered; the saved
+ /*
+ * A signal was successfully delivered; the saved
* sigmask will have been stored in the signal frame,
* and will be restored by sigreturn, so we can simply
- * clear the TIF_RESTORE_SIGMASK flag */
- if (test_thread_flag(TIF_RESTORE_SIGMASK))
- clear_thread_flag(TIF_RESTORE_SIGMASK);
+ * clear the TS_RESTORE_SIGMASK flag
+ */
+ current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
tracehook_signal_handler(signr, &info, &ka, regs,
test_thread_flag(TIF_SINGLESTEP));
@@ -631,10 +633,12 @@ no_signal:
}
}
- /* if there's no signal to deliver, we just put the saved sigmask
- * back */
- if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
- clear_thread_flag(TIF_RESTORE_SIGMASK);
+ /*
+ * If there's no signal to deliver, we just put the saved sigmask
+ * back.
+ */
+ if (current_thread_info()->status & TS_RESTORE_SIGMASK) {
+ current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
}
}
diff --git a/arch/sh/kernel/signal_64.c b/arch/sh/kernel/signal_64.c
index 74793c8..feb3ddd 100644
--- a/arch/sh/kernel/signal_64.c
+++ b/arch/sh/kernel/signal_64.c
@@ -101,7 +101,7 @@ static int do_signal(struct pt_regs *regs, sigset_t *oldset)
if (try_to_freeze())
goto no_signal;
- if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ if (current_thread_info()->status & TS_RESTORE_SIGMASK)
oldset = &current->saved_sigmask;
else if (!oldset)
oldset = &current->blocked;
@@ -115,11 +115,9 @@ static int do_signal(struct pt_regs *regs, sigset_t *oldset)
/*
* If a signal was successfully delivered, the
* saved sigmask is in its frame, and we can
- * clear the TIF_RESTORE_SIGMASK flag.
+ * clear the TS_RESTORE_SIGMASK flag.
*/
- if (test_thread_flag(TIF_RESTORE_SIGMASK))
- clear_thread_flag(TIF_RESTORE_SIGMASK);
-
+ current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
tracehook_signal_handler(signr, &info, &ka, regs, 0);
return 1;
}
@@ -146,8 +144,8 @@ no_signal:
}
/* No signal to deliver -- put the saved sigmask back */
- if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
- clear_thread_flag(TIF_RESTORE_SIGMASK);
+ if (current_thread_info()->status & TS_RESTORE_SIGMASK) {
+ current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
}
@@ -176,6 +174,7 @@ sys_sigsuspend(old_sigset_t mask,
while (1) {
current->state = TASK_INTERRUPTIBLE;
schedule();
+ set_restore_sigmask();
regs->pc += 4; /* because sys_sigreturn decrements the pc */
if (do_signal(regs, &saveset)) {
/* pc now points at signal handler. Need to decrement
diff --git a/arch/sh/kernel/smp.c b/arch/sh/kernel/smp.c
index 160db10..983e079 100644
--- a/arch/sh/kernel/smp.c
+++ b/arch/sh/kernel/smp.c
@@ -122,7 +122,9 @@ int __cpuinit __cpu_up(unsigned int cpu)
stack_start.bss_start = 0; /* don't clear bss for secondary cpus */
stack_start.start_kernel_fn = start_secondary;
- flush_cache_all();
+ flush_icache_range((unsigned long)&stack_start,
+ (unsigned long)&stack_start + sizeof(stack_start));
+ wmb();
plat_start_cpu(cpu, (unsigned long)_stext);
diff --git a/arch/sh/kernel/topology.c b/arch/sh/kernel/topology.c
index 0838942..9b0b633 100644
--- a/arch/sh/kernel/topology.c
+++ b/arch/sh/kernel/topology.c
@@ -16,6 +16,32 @@
static DEFINE_PER_CPU(struct cpu, cpu_devices);
+cpumask_t cpu_core_map[NR_CPUS];
+
+static cpumask_t cpu_coregroup_map(unsigned int cpu)
+{
+ /*
+ * Presently all SH-X3 SMP cores are multi-cores, so just keep it
+ * simple until we have a method for determining topology..
+ */
+ return cpu_possible_map;
+}
+
+const struct cpumask *cpu_coregroup_mask(unsigned int cpu)
+{
+ return &cpu_core_map[cpu];
+}
+
+int arch_update_cpu_topology(void)
+{
+ unsigned int cpu;
+
+ for_each_possible_cpu(cpu)
+ cpu_core_map[cpu] = cpu_coregroup_map(cpu);
+
+ return 0;
+}
+
static int __init topology_init(void)
{
int i, ret;
diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c
index a8396f3..7b03633 100644
--- a/arch/sh/kernel/traps.c
+++ b/arch/sh/kernel/traps.c
@@ -9,8 +9,8 @@
#include <asm/unwinder.h>
#include <asm/system.h>
-#ifdef CONFIG_BUG
-void handle_BUG(struct pt_regs *regs)
+#ifdef CONFIG_GENERIC_BUG
+static void handle_BUG(struct pt_regs *regs)
{
const struct bug_entry *bug;
unsigned long bugaddr = regs->pc;
@@ -81,7 +81,7 @@ BUILD_TRAP_HANDLER(bug)
SIGTRAP) == NOTIFY_STOP)
return;
-#ifdef CONFIG_BUG
+#ifdef CONFIG_GENERIC_BUG
if (__kernel_text_address(instruction_pointer(regs))) {
insn_size_t insn = *(insn_size_t *)instruction_pointer(regs);
if (insn == TRAPA_BUG_OPCODE)
@@ -95,9 +95,11 @@ BUILD_TRAP_HANDLER(bug)
BUILD_TRAP_HANDLER(nmi)
{
+ unsigned int cpu = smp_processor_id();
TRAP_HANDLER_DECL;
nmi_enter();
+ nmi_count(cpu)++;
switch (notify_die(DIE_NMI, "NMI", regs, 0, vec & 0xff, SIGINT)) {
case NOTIFY_OK:
diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c
index 7a2ee3a..3da5a12 100644
--- a/arch/sh/kernel/traps_32.c
+++ b/arch/sh/kernel/traps_32.c
@@ -25,6 +25,7 @@
#include <linux/kexec.h>
#include <linux/limits.h>
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/sysfs.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -68,61 +69,49 @@ static const char *se_usermode_action[] = {
"signal+warn"
};
-static int
-proc_alignment_read(char *page, char **start, off_t off, int count, int *eof,
- void *data)
+static int alignment_proc_show(struct seq_file *m, void *v)
{
- char *p = page;
- int len;
-
- p += sprintf(p, "User:\t\t%lu\n", se_user);
- p += sprintf(p, "System:\t\t%lu\n", se_sys);
- p += sprintf(p, "Half:\t\t%lu\n", se_half);
- p += sprintf(p, "Word:\t\t%lu\n", se_word);
- p += sprintf(p, "DWord:\t\t%lu\n", se_dword);
- p += sprintf(p, "Multi:\t\t%lu\n", se_multi);
- p += sprintf(p, "User faults:\t%i (%s)\n", se_usermode,
+ seq_printf(m, "User:\t\t%lu\n", se_user);
+ seq_printf(m, "System:\t\t%lu\n", se_sys);
+ seq_printf(m, "Half:\t\t%lu\n", se_half);
+ seq_printf(m, "Word:\t\t%lu\n", se_word);
+ seq_printf(m, "DWord:\t\t%lu\n", se_dword);
+ seq_printf(m, "Multi:\t\t%lu\n", se_multi);
+ seq_printf(m, "User faults:\t%i (%s)\n", se_usermode,
se_usermode_action[se_usermode]);
- p += sprintf(p, "Kernel faults:\t%i (fixup%s)\n", se_kernmode_warn,
+ seq_printf(m, "Kernel faults:\t%i (fixup%s)\n", se_kernmode_warn,
se_kernmode_warn ? "+warn" : "");
-
- len = (p - page) - off;
- if (len < 0)
- len = 0;
-
- *eof = (len <= count) ? 1 : 0;
- *start = page + off;
-
- return len;
+ return 0;
}
-static int proc_alignment_write(struct file *file, const char __user *buffer,
- unsigned long count, void *data)
+static int alignment_proc_open(struct inode *inode, struct file *file)
{
- char mode;
-
- if (count > 0) {
- if (get_user(mode, buffer))
- return -EFAULT;
- if (mode >= '0' && mode <= '5')
- se_usermode = mode - '0';
- }
- return count;
+ return single_open(file, alignment_proc_show, NULL);
}
-static int proc_alignment_kern_write(struct file *file, const char __user *buffer,
- unsigned long count, void *data)
+static ssize_t alignment_proc_write(struct file *file,
+ const char __user *buffer, size_t count, loff_t *pos)
{
+ int *data = PDE(file->f_path.dentry->d_inode)->data;
char mode;
if (count > 0) {
if (get_user(mode, buffer))
return -EFAULT;
- if (mode >= '0' && mode <= '1')
- se_kernmode_warn = mode - '0';
+ if (mode >= '0' && mode <= '5')
+ *data = mode - '0';
}
return count;
}
+
+static const struct file_operations alignment_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = alignment_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = alignment_proc_write,
+};
#endif
static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
@@ -945,14 +934,9 @@ void __init trap_init(void)
set_exception_table_evt(0x800, do_reserved_inst);
set_exception_table_evt(0x820, do_illegal_slot_inst);
#elif defined(CONFIG_SH_FPU)
-#ifdef CONFIG_CPU_SUBTYPE_SHX3
- set_exception_table_evt(0xd80, fpu_state_restore_trap_handler);
- set_exception_table_evt(0xda0, fpu_state_restore_trap_handler);
-#else
set_exception_table_evt(0x800, fpu_state_restore_trap_handler);
set_exception_table_evt(0x820, fpu_state_restore_trap_handler);
#endif
-#endif
#ifdef CONFIG_CPU_SH2
set_exception_table_vec(TRAP_ADDRESS_ERROR, address_error_trap_handler);
@@ -1011,20 +995,16 @@ static int __init alignment_init(void)
if (!dir)
return -ENOMEM;
- res = create_proc_entry("alignment", S_IWUSR | S_IRUGO, dir);
+ res = proc_create_data("alignment", S_IWUSR | S_IRUGO, dir,
+ &alignment_proc_fops, &se_usermode);
if (!res)
return -ENOMEM;
- res->read_proc = proc_alignment_read;
- res->write_proc = proc_alignment_write;
-
- res = create_proc_entry("kernel_alignment", S_IWUSR | S_IRUGO, dir);
+ res = proc_create_data("kernel_alignment", S_IWUSR | S_IRUGO, dir,
+ &alignment_proc_fops, &se_kernmode_warn);
if (!res)
return -ENOMEM;
- res->read_proc = proc_alignment_read;
- res->write_proc = proc_alignment_kern_write;
-
return 0;
}
diff --git a/arch/sh/lib/Makefile b/arch/sh/lib/Makefile
index a969b47..dab4d21 100644
--- a/arch/sh/lib/Makefile
+++ b/arch/sh/lib/Makefile
@@ -2,7 +2,7 @@
# Makefile for SuperH-specific library files..
#
-lib-y = delay.o memset.o memmove.o memchr.o \
+lib-y = delay.o memmove.o memchr.o \
checksum.o strlen.o div64.o div64-generic.o
# Extracted from libgcc
@@ -23,8 +23,11 @@ obj-y += io.o
memcpy-y := memcpy.o
memcpy-$(CONFIG_CPU_SH4) := memcpy-sh4.o
+memset-y := memset.o
+memset-$(CONFIG_CPU_SH4) := memset-sh4.o
+
lib-$(CONFIG_MMU) += copy_page.o __clear_user.o
lib-$(CONFIG_MCOUNT) += mcount.o
-lib-y += $(memcpy-y) $(udivsi3-y)
+lib-y += $(memcpy-y) $(memset-y) $(udivsi3-y)
EXTRA_CFLAGS += -Werror
diff --git a/arch/sh/lib/memset-sh4.S b/arch/sh/lib/memset-sh4.S
new file mode 100644
index 0000000..1a6e32c
--- /dev/null
+++ b/arch/sh/lib/memset-sh4.S
@@ -0,0 +1,107 @@
+/*
+ * "memset" implementation for SH4
+ *
+ * Copyright (C) 1999 Niibe Yutaka
+ * Copyright (c) 2009 STMicroelectronics Limited
+ * Author: Stuart Menefy <stuart.menefy:st.com>
+ */
+
+/*
+ * void *memset(void *s, int c, size_t n);
+ */
+
+#include <linux/linkage.h>
+
+ENTRY(memset)
+ mov #12,r0
+ add r6,r4
+ cmp/gt r6,r0
+ bt/s 40f ! if it's too small, set a byte at once
+ mov r4,r0
+ and #3,r0
+ cmp/eq #0,r0
+ bt/s 2f ! It's aligned
+ sub r0,r6
+1:
+ dt r0
+ bf/s 1b
+ mov.b r5,@-r4
+2: ! make VVVV
+ extu.b r5,r5
+ swap.b r5,r0 ! V0
+ or r0,r5 ! VV
+ swap.w r5,r0 ! VV00
+ or r0,r5 ! VVVV
+
+ ! Check if enough bytes need to be copied to be worth the big loop
+ mov #0x40, r0 ! (MT)
+ cmp/gt r6,r0 ! (MT) 64 > len => slow loop
+
+ bt/s 22f
+ mov r6,r0
+
+ ! align the dst to the cache block size if necessary
+ mov r4, r3
+ mov #~(0x1f), r1
+
+ and r3, r1
+ cmp/eq r3, r1
+
+ bt/s 11f ! dst is already aligned
+ sub r1, r3 ! r3-r1 -> r3
+ shlr2 r3 ! number of loops
+
+10: mov.l r5,@-r4
+ dt r3
+ bf/s 10b
+ add #-4, r6
+
+11: ! dst is 32byte aligned
+ mov r6,r2
+ mov #-5,r0
+ shld r0,r2 ! number of loops
+
+ add #-32, r4
+ mov r5, r0
+12:
+ movca.l r0,@r4
+ mov.l r5,@(4, r4)
+ mov.l r5,@(8, r4)
+ mov.l r5,@(12,r4)
+ mov.l r5,@(16,r4)
+ mov.l r5,@(20,r4)
+ add #-0x20, r6
+ mov.l r5,@(24,r4)
+ dt r2
+ mov.l r5,@(28,r4)
+ bf/s 12b
+ add #-32, r4
+
+ add #32, r4
+ mov #8, r0
+ cmp/ge r0, r6
+ bf 40f
+
+ mov r6,r0
+22:
+ shlr2 r0
+ shlr r0 ! r0 = r6 >> 3
+3:
+ dt r0
+ mov.l r5,@-r4 ! set 8-byte at once
+ bf/s 3b
+ mov.l r5,@-r4
+ !
+ mov #7,r0
+ and r0,r6
+
+ ! fill bytes (length may be zero)
+40: tst r6,r6
+ bt 5f
+4:
+ dt r6
+ bf/s 4b
+ mov.b r5,@-r4
+5:
+ rts
+ mov r4,r0
diff --git a/arch/sh/math-emu/math.c b/arch/sh/math-emu/math.c
index ac2d7ab..d6c15ca 100644
--- a/arch/sh/math-emu/math.c
+++ b/arch/sh/math-emu/math.c
@@ -558,7 +558,7 @@ static int ieee_fpe_handler(struct pt_regs *regs)
(finsn >> 8) & 0xf);
tsk->thread.fpu.hard.fpscr &=
~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK);
- set_tsk_thread_flag(tsk, TIF_USEDFPU);
+ task_thread_info(tsk)->status |= TS_USEDFPU;
} else {
info.si_signo = SIGFPE;
info.si_errno = 0;
@@ -619,10 +619,10 @@ int do_fpu_inst(unsigned short inst, struct pt_regs *regs)
struct task_struct *tsk = current;
struct sh_fpu_soft_struct *fpu = &(tsk->thread.fpu.soft);
- if (!test_tsk_thread_flag(tsk, TIF_USEDFPU)) {
+ if (!(task_thread_info(tsk)->status & TS_USEDFPU)) {
/* initialize once. */
fpu_init(fpu);
- set_tsk_thread_flag(tsk, TIF_USEDFPU);
+ task_thread_info(tsk)->status |= TS_USEDFPU;
}
return fpu_emulate(inst, fpu, regs);
diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig
index 7f7b52f..0e7ba8e 100644
--- a/arch/sh/mm/Kconfig
+++ b/arch/sh/mm/Kconfig
@@ -82,8 +82,7 @@ config 32BIT
config PMB_ENABLE
bool "Support 32-bit physical addressing through PMB"
- depends on MMU && EXPERIMENTAL && (CPU_SUBTYPE_SH7757 || CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785)
- select 32BIT
+ depends on MMU && EXPERIMENTAL && CPU_SH4A
default y
help
If you say Y here, physical addressing will be extended to
@@ -97,8 +96,7 @@ choice
config PMB
bool "PMB"
- depends on MMU && EXPERIMENTAL && (CPU_SUBTYPE_SH7757 || CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785)
- select 32BIT
+ depends on MMU && EXPERIMENTAL && CPU_SH4A
help
If you say Y here, physical addressing will be extended to
32-bits through the SH-4A PMB. If this is not set, legacy
@@ -106,9 +104,7 @@ config PMB
config PMB_FIXED
bool "fixed PMB"
- depends on MMU && EXPERIMENTAL && (CPU_SUBTYPE_SH7757 || \
- CPU_SUBTYPE_SH7780 || \
- CPU_SUBTYPE_SH7785)
+ depends on MMU && EXPERIMENTAL && CPU_SH4A
select 32BIT
help
If this option is enabled, fixed PMB mappings are inherited
@@ -258,6 +254,15 @@ endchoice
source "mm/Kconfig"
+config SCHED_MC
+ bool "Multi-core scheduler support"
+ depends on SMP
+ default y
+ help
+ Multi-core scheduler support improves the CPU scheduler's decision
+ making when dealing with multi-core CPU chips at a cost of slightly
+ increased overhead in some places. If unsure say N here.
+
endmenu
menu "Cache configuration"
diff --git a/arch/sh/mm/Makefile b/arch/sh/mm/Makefile
index 3759bf8..8a70535 100644
--- a/arch/sh/mm/Makefile
+++ b/arch/sh/mm/Makefile
@@ -33,8 +33,7 @@ obj-y += $(tlb-y)
endif
obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
-obj-$(CONFIG_PMB) += pmb.o
-obj-$(CONFIG_PMB_FIXED) += pmb-fixed.o
+obj-$(CONFIG_PMB_ENABLE) += pmb.o
obj-$(CONFIG_NUMA) += numa.o
# Special flags for fault_64.o. This puts restrictions on the number of
diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c
index b7f235c..f36a08b 100644
--- a/arch/sh/mm/cache-sh4.c
+++ b/arch/sh/mm/cache-sh4.c
@@ -2,7 +2,7 @@
* arch/sh/mm/cache-sh4.c
*
* Copyright (C) 1999, 2000, 2002 Niibe Yutaka
- * Copyright (C) 2001 - 2007 Paul Mundt
+ * Copyright (C) 2001 - 2009 Paul Mundt
* Copyright (C) 2003 Richard Curnow
* Copyright (c) 2007 STMicroelectronics (R&D) Ltd.
*
@@ -15,6 +15,8 @@
#include <linux/io.h>
#include <linux/mutex.h>
#include <linux/fs.h>
+#include <linux/highmem.h>
+#include <asm/pgtable.h>
#include <asm/mmu_context.h>
#include <asm/cacheflush.h>
@@ -23,21 +25,12 @@
* flushing. Anything exceeding this will simply flush the dcache in its
* entirety.
*/
-#define MAX_DCACHE_PAGES 64 /* XXX: Tune for ways */
#define MAX_ICACHE_PAGES 32
static void __flush_cache_one(unsigned long addr, unsigned long phys,
unsigned long exec_offset);
/*
- * This is initialised here to ensure that it is not placed in the BSS. If
- * that were to happen, note that cache_init gets called before the BSS is
- * cleared, so this would get nulled out which would be hopeless.
- */
-static void (*__flush_dcache_segment_fn)(unsigned long, unsigned long) =
- (void (*)(unsigned long, unsigned long))0xdeadbeef;
-
-/*
* Write back the range of D-cache, and purge the I-cache.
*
* Called from kernel/module.c:sys_init_module and routine for a.out format,
@@ -97,15 +90,15 @@ static inline void flush_cache_one(unsigned long start, unsigned long phys)
unsigned long flags, exec_offset = 0;
/*
- * 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.
+ * All types of SH-4 require PC to be uncached to operate on the I-cache.
+ * Some types of SH-4 require PC to be uncached to operate on the D-cache.
*/
if ((boot_cpu_data.flags & CPU_HAS_P2_FLUSH_BUG) ||
(start < CACHE_OC_ADDRESS_ARRAY))
- exec_offset = 0x20000000;
+ exec_offset = cached_to_uncached;
local_irq_save(flags);
- __flush_cache_one(start | SH_CACHE_ASSOC, P1SEGADDR(phys), exec_offset);
+ __flush_cache_one(start, phys, exec_offset);
local_irq_restore(flags);
}
@@ -124,7 +117,7 @@ static void sh4_flush_dcache_page(void *arg)
else
#endif
{
- unsigned long phys = PHYSADDR(page_address(page));
+ unsigned long phys = page_to_phys(page);
unsigned long addr = CACHE_OC_ADDRESS_ARRAY;
int i, n;
@@ -159,10 +152,27 @@ static void __uses_jump_to_uncached flush_icache_all(void)
local_irq_restore(flags);
}
-static inline void flush_dcache_all(void)
+static void flush_dcache_all(void)
{
- (*__flush_dcache_segment_fn)(0UL, boot_cpu_data.dcache.way_size);
- wmb();
+ unsigned long addr, end_addr, entry_offset;
+
+ end_addr = CACHE_OC_ADDRESS_ARRAY +
+ (current_cpu_data.dcache.sets <<
+ current_cpu_data.dcache.entry_shift) *
+ current_cpu_data.dcache.ways;
+
+ entry_offset = 1 << current_cpu_data.dcache.entry_shift;
+
+ for (addr = CACHE_OC_ADDRESS_ARRAY; addr < end_addr; ) {
+ __raw_writel(0, addr); addr += entry_offset;
+ __raw_writel(0, addr); addr += entry_offset;
+ __raw_writel(0, addr); addr += entry_offset;
+ __raw_writel(0, addr); addr += entry_offset;
+ __raw_writel(0, addr); addr += entry_offset;
+ __raw_writel(0, addr); addr += entry_offset;
+ __raw_writel(0, addr); addr += entry_offset;
+ __raw_writel(0, addr); addr += entry_offset;
+ }
}
static void sh4_flush_cache_all(void *unused)
@@ -171,89 +181,13 @@ static void sh4_flush_cache_all(void *unused)
flush_icache_all();
}
-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 = 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;
- pgd_t *dir;
- pmd_t *pmd;
- pud_t *pud;
- pte_t *pte;
- int i;
-
- dir = pgd_offset(mm, p);
- pud = pud_offset(dir, p);
- pmd = pmd_offset(pud, p);
- end = PAGE_ALIGN(end);
-
- all_aliases_mask = (1 << n_aliases) - 1;
-
- do {
- if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) {
- p &= PMD_MASK;
- p += PMD_SIZE;
- pmd++;
-
- continue;
- }
-
- pte = pte_offset_kernel(pmd, p);
-
- do {
- unsigned long phys;
- pte_t entry = *pte;
-
- if (!(pte_val(entry) & _PAGE_PRESENT)) {
- pte++;
- p += PAGE_SIZE;
- continue;
- }
-
- phys = pte_val(entry) & PTE_PHYS_MASK;
-
- if ((p ^ phys) & alias_mask) {
- d |= 1 << ((p & alias_mask) >> PAGE_SHIFT);
- d |= 1 << ((phys & alias_mask) >> PAGE_SHIFT);
-
- if (d == all_aliases_mask)
- goto loop_exit;
- }
-
- pte++;
- p += PAGE_SIZE;
- } while (p < end && ((unsigned long)pte & ~PAGE_MASK));
- pmd++;
- } while (p < end);
-
-loop_exit:
- addr_offset = 0;
- select_bit = 1;
-
- for (i = 0; i < n_aliases; i++) {
- if (d & select_bit) {
- (*__flush_dcache_segment_fn)(addr_offset, PAGE_SIZE);
- wmb();
- }
-
- select_bit <<= 1;
- addr_offset += PAGE_SIZE;
- }
-}
-
/*
* Note : (RPC) since the caches are physically tagged, the only point
* of flush_cache_mm for SH-4 is to get rid of aliases from the
* D-cache. The assumption elsewhere, e.g. flush_cache_range, is that
* lines can stay resident so long as the virtual address they were
* accessed with (hence cache set) is in accord with the physical
- * address (i.e. tag). It's no different here. So I reckon we don't
- * need to flush the I-cache, since aliases don't matter for that. We
- * should try that.
+ * address (i.e. tag). It's no different here.
*
* Caller takes mm->mmap_sem.
*/
@@ -264,33 +198,7 @@ static void sh4_flush_cache_mm(void *arg)
if (cpu_context(smp_processor_id(), mm) == NO_CONTEXT)
return;
- /*
- * 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 (boot_cpu_data.dcache.n_aliases == 0)
- return;
-
- /*
- * Don't bother groveling around the dcache for the VMA ranges
- * if there are too many PTEs to make it worthwhile.
- */
- if (mm->nr_ptes >= MAX_DCACHE_PAGES)
- flush_dcache_all();
- else {
- struct vm_area_struct *vma;
-
- /*
- * In this case there are reasonably sized ranges to flush,
- * iterate through the VMA list and take care of any aliases.
- */
- for (vma = mm->mmap; vma; vma = vma->vm_next)
- __flush_cache_mm(mm, vma->vm_start, vma->vm_end);
- }
-
- /* Only touch the icache if one of the VMAs has VM_EXEC set. */
- if (mm->exec_vm)
- flush_icache_all();
+ flush_dcache_all();
}
/*
@@ -303,44 +211,63 @@ static void sh4_flush_cache_page(void *args)
{
struct flusher_data *data = args;
struct vm_area_struct *vma;
+ struct page *page;
unsigned long address, pfn, phys;
- unsigned int alias_mask;
+ int map_coherent = 0;
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+ void *vaddr;
vma = data->vma;
- address = data->addr1;
+ address = data->addr1 & PAGE_MASK;
pfn = data->addr2;
phys = pfn << PAGE_SHIFT;
+ page = pfn_to_page(pfn);
if (cpu_context(smp_processor_id(), vma->vm_mm) == NO_CONTEXT)
return;
- alias_mask = boot_cpu_data.dcache.alias_mask;
-
- /* We only need to flush D-cache when we have alias */
- if ((address^phys) & alias_mask) {
- /* Loop 4K of the D-cache */
- flush_cache_one(
- CACHE_OC_ADDRESS_ARRAY | (address & alias_mask),
- phys);
- /* Loop another 4K of the D-cache */
- flush_cache_one(
- CACHE_OC_ADDRESS_ARRAY | (phys & alias_mask),
- phys);
- }
+ pgd = pgd_offset(vma->vm_mm, address);
+ pud = pud_offset(pgd, address);
+ pmd = pmd_offset(pud, address);
+ pte = pte_offset_kernel(pmd, address);
+
+ /* If the page isn't present, there is nothing to do here. */
+ if (!(pte_val(*pte) & _PAGE_PRESENT))
+ return;
- alias_mask = boot_cpu_data.icache.alias_mask;
- if (vma->vm_flags & VM_EXEC) {
+ if ((vma->vm_mm == current->active_mm))
+ vaddr = NULL;
+ else {
/*
- * Evict entries from the portion of the cache from which code
- * may have been executed at this address (virtual). There's
- * no need to evict from the portion corresponding to the
- * physical address as for the D-cache, because we know the
- * kernel has never executed the code through its identity
- * translation.
+ * Use kmap_coherent or kmap_atomic to do flushes for
+ * another ASID than the current one.
*/
- flush_cache_one(
- CACHE_IC_ADDRESS_ARRAY | (address & alias_mask),
- phys);
+ map_coherent = (current_cpu_data.dcache.n_aliases &&
+ !test_bit(PG_dcache_dirty, &page->flags) &&
+ page_mapped(page));
+ if (map_coherent)
+ vaddr = kmap_coherent(page, address);
+ else
+ vaddr = kmap_atomic(page, KM_USER0);
+
+ address = (unsigned long)vaddr;
+ }
+
+ if (pages_do_alias(address, phys))
+ flush_cache_one(CACHE_OC_ADDRESS_ARRAY |
+ (address & shm_align_mask), phys);
+
+ if (vma->vm_flags & VM_EXEC)
+ flush_icache_all();
+
+ if (vaddr) {
+ if (map_coherent)
+ kunmap_coherent(vaddr);
+ else
+ kunmap_atomic(vaddr, KM_USER0);
}
}
@@ -373,24 +300,10 @@ static void sh4_flush_cache_range(void *args)
if (boot_cpu_data.dcache.n_aliases == 0)
return;
- /*
- * Don't bother with the lookup and alias check if we have a
- * wide range to cover, just blow away the dcache in its
- * entirety instead. -- PFM.
- */
- if (((end - start) >> PAGE_SHIFT) >= MAX_DCACHE_PAGES)
- flush_dcache_all();
- else
- __flush_cache_mm(vma->vm_mm, start, end);
+ flush_dcache_all();
- if (vma->vm_flags & VM_EXEC) {
- /*
- * TODO: Is this required??? Need to look at how I-cache
- * coherency is assured when new programs are loaded to see if
- * this matters.
- */
+ if (vma->vm_flags & VM_EXEC)
flush_icache_all();
- }
}
/**
@@ -464,245 +377,6 @@ static void __flush_cache_one(unsigned long addr, unsigned long phys,
} while (--way_count != 0);
}
-/*
- * Break the 1, 2 and 4 way variants of this out into separate functions to
- * avoid nearly all the overhead of having the conditional stuff in the function
- * bodies (+ the 1 and 2 way cases avoid saving any registers too).
- *
- * We want to eliminate unnecessary bus transactions, so this code uses
- * a non-obvious technique.
- *
- * Loop over a cache way sized block of, one cache line at a time. For each
- * line, use movca.a to cause the current cache line contents to be written
- * back, but without reading anything from main memory. However this has the
- * side effect that the cache is now caching that memory location. So follow
- * this with a cache invalidate to mark the cache line invalid. And do all
- * this with interrupts disabled, to avoid the cache line being accidently
- * evicted while it is holding garbage.
- *
- * This also breaks in a number of circumstances:
- * - if there are modifications to the region of memory just above
- * empty_zero_page (for example because a breakpoint has been placed
- * there), then these can be lost.
- *
- * This is because the the memory address which the cache temporarily
- * caches in the above description is empty_zero_page. So the
- * movca.l hits the cache (it is assumed that it misses, or at least
- * isn't dirty), modifies the line and then invalidates it, losing the
- * required change.
- *
- * - If caches are disabled or configured in write-through mode, then
- * the movca.l writes garbage directly into memory.
- */
-static void __flush_dcache_segment_writethrough(unsigned long start,
- unsigned long extent_per_way)
-{
- unsigned long addr;
- int i;
-
- addr = CACHE_OC_ADDRESS_ARRAY | (start & cpu_data->dcache.entry_mask);
-
- while (extent_per_way) {
- for (i = 0; i < cpu_data->dcache.ways; i++)
- __raw_writel(0, addr + cpu_data->dcache.way_incr * i);
-
- addr += cpu_data->dcache.linesz;
- extent_per_way -= cpu_data->dcache.linesz;
- }
-}
-
-static void __flush_dcache_segment_1way(unsigned long start,
- unsigned long extent_per_way)
-{
- unsigned long orig_sr, sr_with_bl;
- unsigned long base_addr;
- unsigned long way_incr, linesz, way_size;
- struct cache_info *dcache;
- register unsigned long a0, a0e;
-
- asm volatile("stc sr, %0" : "=r" (orig_sr));
- sr_with_bl = orig_sr | (1<<28);
- base_addr = ((unsigned long)&empty_zero_page[0]);
-
- /*
- * The previous code aligned base_addr to 16k, i.e. the way_size of all
- * existing SH-4 D-caches. Whilst I don't see a need to have this
- * aligned to any better than the cache line size (which it will be
- * anyway by construction), let's align it to at least the way_size of
- * any existing or conceivable SH-4 D-cache. -- RPC
- */
- base_addr = ((base_addr >> 16) << 16);
- base_addr |= start;
-
- dcache = &boot_cpu_data.dcache;
- linesz = dcache->linesz;
- way_incr = dcache->way_incr;
- way_size = dcache->way_size;
-
- a0 = base_addr;
- a0e = base_addr + extent_per_way;
- do {
- asm volatile("ldc %0, sr" : : "r" (sr_with_bl));
- asm volatile("movca.l r0, @%0\n\t"
- "ocbi @%0" : : "r" (a0));
- a0 += linesz;
- asm volatile("movca.l r0, @%0\n\t"
- "ocbi @%0" : : "r" (a0));
- a0 += linesz;
- asm volatile("movca.l r0, @%0\n\t"
- "ocbi @%0" : : "r" (a0));
- a0 += linesz;
- asm volatile("movca.l r0, @%0\n\t"
- "ocbi @%0" : : "r" (a0));
- asm volatile("ldc %0, sr" : : "r" (orig_sr));
- a0 += linesz;
- } while (a0 < a0e);
-}
-
-static void __flush_dcache_segment_2way(unsigned long start,
- unsigned long extent_per_way)
-{
- unsigned long orig_sr, sr_with_bl;
- unsigned long base_addr;
- unsigned long way_incr, linesz, way_size;
- struct cache_info *dcache;
- register unsigned long a0, a1, a0e;
-
- asm volatile("stc sr, %0" : "=r" (orig_sr));
- sr_with_bl = orig_sr | (1<<28);
- base_addr = ((unsigned long)&empty_zero_page[0]);
-
- /* See comment under 1-way above */
- base_addr = ((base_addr >> 16) << 16);
- base_addr |= start;
-
- dcache = &boot_cpu_data.dcache;
- linesz = dcache->linesz;
- way_incr = dcache->way_incr;
- way_size = dcache->way_size;
-
- a0 = base_addr;
- a1 = a0 + way_incr;
- a0e = base_addr + extent_per_way;
- do {
- asm volatile("ldc %0, sr" : : "r" (sr_with_bl));
- asm volatile("movca.l r0, @%0\n\t"
- "movca.l r0, @%1\n\t"
- "ocbi @%0\n\t"
- "ocbi @%1" : :
- "r" (a0), "r" (a1));
- a0 += linesz;
- a1 += linesz;
- asm volatile("movca.l r0, @%0\n\t"
- "movca.l r0, @%1\n\t"
- "ocbi @%0\n\t"
- "ocbi @%1" : :
- "r" (a0), "r" (a1));
- a0 += linesz;
- a1 += linesz;
- asm volatile("movca.l r0, @%0\n\t"
- "movca.l r0, @%1\n\t"
- "ocbi @%0\n\t"
- "ocbi @%1" : :
- "r" (a0), "r" (a1));
- a0 += linesz;
- a1 += linesz;
- asm volatile("movca.l r0, @%0\n\t"
- "movca.l r0, @%1\n\t"
- "ocbi @%0\n\t"
- "ocbi @%1" : :
- "r" (a0), "r" (a1));
- asm volatile("ldc %0, sr" : : "r" (orig_sr));
- a0 += linesz;
- a1 += linesz;
- } while (a0 < a0e);
-}
-
-static void __flush_dcache_segment_4way(unsigned long start,
- unsigned long extent_per_way)
-{
- unsigned long orig_sr, sr_with_bl;
- unsigned long base_addr;
- unsigned long way_incr, linesz, way_size;
- struct cache_info *dcache;
- register unsigned long a0, a1, a2, a3, a0e;
-
- asm volatile("stc sr, %0" : "=r" (orig_sr));
- sr_with_bl = orig_sr | (1<<28);
- base_addr = ((unsigned long)&empty_zero_page[0]);
-
- /* See comment under 1-way above */
- base_addr = ((base_addr >> 16) << 16);
- base_addr |= start;
-
- dcache = &boot_cpu_data.dcache;
- linesz = dcache->linesz;
- way_incr = dcache->way_incr;
- way_size = dcache->way_size;
-
- a0 = base_addr;
- a1 = a0 + way_incr;
- a2 = a1 + way_incr;
- a3 = a2 + way_incr;
- a0e = base_addr + extent_per_way;
- do {
- asm volatile("ldc %0, sr" : : "r" (sr_with_bl));
- asm volatile("movca.l r0, @%0\n\t"
- "movca.l r0, @%1\n\t"
- "movca.l r0, @%2\n\t"
- "movca.l r0, @%3\n\t"
- "ocbi @%0\n\t"
- "ocbi @%1\n\t"
- "ocbi @%2\n\t"
- "ocbi @%3\n\t" : :
- "r" (a0), "r" (a1), "r" (a2), "r" (a3));
- a0 += linesz;
- a1 += linesz;
- a2 += linesz;
- a3 += linesz;
- asm volatile("movca.l r0, @%0\n\t"
- "movca.l r0, @%1\n\t"
- "movca.l r0, @%2\n\t"
- "movca.l r0, @%3\n\t"
- "ocbi @%0\n\t"
- "ocbi @%1\n\t"
- "ocbi @%2\n\t"
- "ocbi @%3\n\t" : :
- "r" (a0), "r" (a1), "r" (a2), "r" (a3));
- a0 += linesz;
- a1 += linesz;
- a2 += linesz;
- a3 += linesz;
- asm volatile("movca.l r0, @%0\n\t"
- "movca.l r0, @%1\n\t"
- "movca.l r0, @%2\n\t"
- "movca.l r0, @%3\n\t"
- "ocbi @%0\n\t"
- "ocbi @%1\n\t"
- "ocbi @%2\n\t"
- "ocbi @%3\n\t" : :
- "r" (a0), "r" (a1), "r" (a2), "r" (a3));
- a0 += linesz;
- a1 += linesz;
- a2 += linesz;
- a3 += linesz;
- asm volatile("movca.l r0, @%0\n\t"
- "movca.l r0, @%1\n\t"
- "movca.l r0, @%2\n\t"
- "movca.l r0, @%3\n\t"
- "ocbi @%0\n\t"
- "ocbi @%1\n\t"
- "ocbi @%2\n\t"
- "ocbi @%3\n\t" : :
- "r" (a0), "r" (a1), "r" (a2), "r" (a3));
- asm volatile("ldc %0, sr" : : "r" (orig_sr));
- a0 += linesz;
- a1 += linesz;
- a2 += linesz;
- a3 += linesz;
- } while (a0 < a0e);
-}
-
extern void __weak sh4__flush_region_init(void);
/*
@@ -710,32 +384,11 @@ extern void __weak sh4__flush_region_init(void);
*/
void __init sh4_cache_init(void)
{
- unsigned int wt_enabled = !!(__raw_readl(CCR) & CCR_CACHE_WT);
-
printk("PVR=%08x CVR=%08x PRR=%08x\n",
ctrl_inl(CCN_PVR),
ctrl_inl(CCN_CVR),
ctrl_inl(CCN_PRR));
- if (wt_enabled)
- __flush_dcache_segment_fn = __flush_dcache_segment_writethrough;
- else {
- switch (boot_cpu_data.dcache.ways) {
- case 1:
- __flush_dcache_segment_fn = __flush_dcache_segment_1way;
- break;
- case 2:
- __flush_dcache_segment_fn = __flush_dcache_segment_2way;
- break;
- case 4:
- __flush_dcache_segment_fn = __flush_dcache_segment_4way;
- break;
- default:
- panic("unknown number of cache ways\n");
- break;
- }
- }
-
local_flush_icache_range = sh4_flush_icache_range;
local_flush_dcache_page = sh4_flush_dcache_page;
local_flush_cache_all = sh4_flush_cache_all;
diff --git a/arch/sh/mm/cache-sh5.c b/arch/sh/mm/cache-sh5.c
index 467ff8e..eb4cc4e 100644
--- a/arch/sh/mm/cache-sh5.c
+++ b/arch/sh/mm/cache-sh5.c
@@ -563,7 +563,7 @@ static void sh5_flush_cache_page(void *args)
static void sh5_flush_dcache_page(void *page)
{
- sh64_dcache_purge_phy_page(page_to_phys(page));
+ sh64_dcache_purge_phy_page(page_to_phys((struct page *)page));
wmb();
}
diff --git a/arch/sh/mm/cache-sh7705.c b/arch/sh/mm/cache-sh7705.c
index 2601935..f527fb7 100644
--- a/arch/sh/mm/cache-sh7705.c
+++ b/arch/sh/mm/cache-sh7705.c
@@ -141,7 +141,7 @@ static void sh7705_flush_dcache_page(void *arg)
if (mapping && !mapping_mapped(mapping))
set_bit(PG_dcache_dirty, &page->flags);
else
- __flush_dcache_page(PHYSADDR(page_address(page)));
+ __flush_dcache_page(__pa(page_address(page)));
}
static void __uses_jump_to_uncached sh7705_flush_cache_all(void *args)
diff --git a/arch/sh/mm/cache.c b/arch/sh/mm/cache.c
index a2dc7f9..e9415d3 100644
--- a/arch/sh/mm/cache.c
+++ b/arch/sh/mm/cache.c
@@ -27,8 +27,11 @@ void (*local_flush_icache_page)(void *args) = cache_noop;
void (*local_flush_cache_sigtramp)(void *args) = cache_noop;
void (*__flush_wback_region)(void *start, int size);
+EXPORT_SYMBOL(__flush_wback_region);
void (*__flush_purge_region)(void *start, int size);
+EXPORT_SYMBOL(__flush_purge_region);
void (*__flush_invalidate_region)(void *start, int size);
+EXPORT_SYMBOL(__flush_invalidate_region);
static inline void noop__flush_region(void *start, int size)
{
@@ -161,14 +164,21 @@ void flush_cache_all(void)
{
cacheop_on_each_cpu(local_flush_cache_all, NULL, 1);
}
+EXPORT_SYMBOL(flush_cache_all);
void flush_cache_mm(struct mm_struct *mm)
{
+ if (boot_cpu_data.dcache.n_aliases == 0)
+ return;
+
cacheop_on_each_cpu(local_flush_cache_mm, mm, 1);
}
void flush_cache_dup_mm(struct mm_struct *mm)
{
+ if (boot_cpu_data.dcache.n_aliases == 0)
+ return;
+
cacheop_on_each_cpu(local_flush_cache_dup_mm, mm, 1);
}
@@ -195,11 +205,13 @@ void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
cacheop_on_each_cpu(local_flush_cache_range, (void *)&data, 1);
}
+EXPORT_SYMBOL(flush_cache_range);
void flush_dcache_page(struct page *page)
{
cacheop_on_each_cpu(local_flush_dcache_page, page, 1);
}
+EXPORT_SYMBOL(flush_dcache_page);
void flush_icache_range(unsigned long start, unsigned long end)
{
@@ -265,7 +277,11 @@ static void __init emit_cache_params(void)
void __init cpu_cache_init(void)
{
- unsigned int cache_disabled = !(__raw_readl(CCR) & CCR_CACHE_ENABLE);
+ unsigned int cache_disabled = 0;
+
+#ifdef CCR
+ cache_disabled = !(__raw_readl(CCR) & CCR_CACHE_ENABLE);
+#endif
compute_alias(&boot_cpu_data.icache);
compute_alias(&boot_cpu_data.dcache);
diff --git a/arch/sh/mm/consistent.c b/arch/sh/mm/consistent.c
index e098ec1..902967e 100644
--- a/arch/sh/mm/consistent.c
+++ b/arch/sh/mm/consistent.c
@@ -15,11 +15,15 @@
#include <linux/dma-mapping.h>
#include <linux/dma-debug.h>
#include <linux/io.h>
+#include <linux/module.h>
#include <asm/cacheflush.h>
#include <asm/addrspace.h>
#define PREALLOC_DMA_DEBUG_ENTRIES 4096
+struct dma_map_ops *dma_ops;
+EXPORT_SYMBOL(dma_ops);
+
static int __init dma_init(void)
{
dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES);
@@ -27,15 +31,12 @@ static int __init dma_init(void)
}
fs_initcall(dma_init);
-void *dma_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t gfp)
+void *dma_generic_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t gfp)
{
void *ret, *ret_nocache;
int order = get_order(size);
- if (dma_alloc_from_coherent(dev, size, dma_handle, &ret))
- return ret;
-
ret = (void *)__get_free_pages(gfp, order);
if (!ret)
return NULL;
@@ -57,35 +58,26 @@ void *dma_alloc_coherent(struct device *dev, size_t size,
*dma_handle = virt_to_phys(ret);
- debug_dma_alloc_coherent(dev, size, *dma_handle, ret_nocache);
-
return ret_nocache;
}
-EXPORT_SYMBOL(dma_alloc_coherent);
-void dma_free_coherent(struct device *dev, size_t size,
- void *vaddr, dma_addr_t dma_handle)
+void dma_generic_free_coherent(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle)
{
int order = get_order(size);
unsigned long pfn = dma_handle >> PAGE_SHIFT;
int k;
- WARN_ON(irqs_disabled()); /* for portability */
-
- if (dma_release_from_coherent(dev, order, vaddr))
- return;
-
- debug_dma_free_coherent(dev, size, vaddr, dma_handle);
for (k = 0; k < (1 << order); k++)
__free_pages(pfn_to_page(pfn + k), 0);
+
iounmap(vaddr);
}
-EXPORT_SYMBOL(dma_free_coherent);
void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
enum dma_data_direction direction)
{
-#ifdef CONFIG_CPU_SH5
+#if defined(CONFIG_CPU_SH5) || defined(CONFIG_PMB)
void *p1addr = vaddr;
#else
void *p1addr = (void*) P1SEGADDR((unsigned long)vaddr);
diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c
index 8173e38..432acd0 100644
--- a/arch/sh/mm/init.c
+++ b/arch/sh/mm/init.c
@@ -15,6 +15,7 @@
#include <linux/pagemap.h>
#include <linux/percpu.h>
#include <linux/io.h>
+#include <linux/dma-mapping.h>
#include <asm/mmu_context.h>
#include <asm/tlb.h>
#include <asm/cacheflush.h>
@@ -186,11 +187,21 @@ void __init paging_init(void)
set_fixmap_nocache(FIX_UNCACHED, __pa(&__uncached_start));
}
+/*
+ * Early initialization for any I/O MMUs we might have.
+ */
+static void __init iommu_init(void)
+{
+ no_iommu_init();
+}
+
void __init mem_init(void)
{
int codesize, datasize, initsize;
int nid;
+ iommu_init();
+
num_physpages = 0;
high_memory = NULL;
@@ -323,4 +334,12 @@ int memory_add_physaddr_to_nid(u64 addr)
}
EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
#endif
+
#endif /* CONFIG_MEMORY_HOTPLUG */
+
+#ifdef CONFIG_PMB
+int __in_29bit_mode(void)
+{
+ return !(ctrl_inl(PMB_PASCR) & PASCR_SE);
+}
+#endif /* CONFIG_PMB */
diff --git a/arch/sh/mm/kmap.c b/arch/sh/mm/kmap.c
index 16e01b5..15d74ea 100644
--- a/arch/sh/mm/kmap.c
+++ b/arch/sh/mm/kmap.c
@@ -39,7 +39,9 @@ void *kmap_coherent(struct page *page, unsigned long addr)
pagefault_disable();
idx = FIX_CMAP_END -
- ((addr & current_cpu_data.dcache.alias_mask) >> PAGE_SHIFT);
+ (((addr >> PAGE_SHIFT) & (FIX_N_COLOURS - 1)) +
+ (FIX_N_COLOURS * smp_processor_id()));
+
vaddr = __fix_to_virt(idx);
BUG_ON(!pte_none(*(kmap_coherent_pte - idx)));
diff --git a/arch/sh/mm/numa.c b/arch/sh/mm/numa.c
index 9b784fd..6c52444 100644
--- a/arch/sh/mm/numa.c
+++ b/arch/sh/mm/numa.c
@@ -60,7 +60,7 @@ void __init setup_bootmem_node(int nid, unsigned long start, unsigned long end)
unsigned long bootmem_paddr;
/* Don't allow bogus node assignment */
- BUG_ON(nid > MAX_NUMNODES || nid == 0);
+ BUG_ON(nid > MAX_NUMNODES || nid <= 0);
start_pfn = start >> PAGE_SHIFT;
end_pfn = end >> PAGE_SHIFT;
diff --git a/arch/sh/mm/pmb-fixed.c b/arch/sh/mm/pmb-fixed.c
deleted file mode 100644
index 43c8eac..0000000
--- a/arch/sh/mm/pmb-fixed.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * arch/sh/mm/fixed_pmb.c
- *
- * Copyright (C) 2009 Renesas Solutions Corp.
- *
- * 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/mm.h>
-#include <linux/io.h>
-#include <asm/mmu.h>
-#include <asm/mmu_context.h>
-
-static int __uses_jump_to_uncached fixed_pmb_init(void)
-{
- int i;
- unsigned long addr, data;
-
- jump_to_uncached();
-
- for (i = 0; i < PMB_ENTRY_MAX; i++) {
- addr = PMB_DATA + (i << PMB_E_SHIFT);
- data = ctrl_inl(addr);
- if (!(data & PMB_V))
- continue;
-
- if (data & PMB_C) {
-#if defined(CONFIG_CACHE_WRITETHROUGH)
- data |= PMB_WT;
-#elif defined(CONFIG_CACHE_WRITEBACK)
- data &= ~PMB_WT;
-#else
- data &= ~(PMB_C | PMB_WT);
-#endif
- }
- ctrl_outl(data, addr);
- }
-
- back_to_cached();
-
- return 0;
-}
-arch_initcall(fixed_pmb_init);
diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c
index aade311..280f6a1 100644
--- a/arch/sh/mm/pmb.c
+++ b/arch/sh/mm/pmb.c
@@ -35,29 +35,9 @@
static void __pmb_unmap(struct pmb_entry *);
-static struct kmem_cache *pmb_cache;
+static struct pmb_entry pmb_entry_list[NR_PMB_ENTRIES];
static unsigned long pmb_map;
-static struct pmb_entry pmb_init_map[] = {
- /* vpn ppn flags (ub/sz/c/wt) */
-
- /* P1 Section Mappings */
- { 0x80000000, 0x00000000, PMB_SZ_64M | PMB_C, },
- { 0x84000000, 0x04000000, PMB_SZ_64M | PMB_C, },
- { 0x88000000, 0x08000000, PMB_SZ_128M | PMB_C, },
- { 0x90000000, 0x10000000, PMB_SZ_64M | PMB_C, },
- { 0x94000000, 0x14000000, PMB_SZ_64M | PMB_C, },
- { 0x98000000, 0x18000000, PMB_SZ_64M | PMB_C, },
-
- /* P2 Section Mappings */
- { 0xa0000000, 0x00000000, PMB_UB | PMB_SZ_64M | PMB_WT, },
- { 0xa4000000, 0x04000000, PMB_UB | PMB_SZ_64M | PMB_WT, },
- { 0xa8000000, 0x08000000, PMB_UB | PMB_SZ_128M | PMB_WT, },
- { 0xb0000000, 0x10000000, PMB_UB | PMB_SZ_64M | PMB_WT, },
- { 0xb4000000, 0x14000000, PMB_UB | PMB_SZ_64M | PMB_WT, },
- { 0xb8000000, 0x18000000, PMB_UB | PMB_SZ_64M | PMB_WT, },
-};
-
static inline unsigned long mk_pmb_entry(unsigned int entry)
{
return (entry & PMB_E_MASK) << PMB_E_SHIFT;
@@ -73,81 +53,68 @@ static inline unsigned long mk_pmb_data(unsigned int entry)
return mk_pmb_entry(entry) | PMB_DATA;
}
-static DEFINE_SPINLOCK(pmb_list_lock);
-static struct pmb_entry *pmb_list;
-
-static inline void pmb_list_add(struct pmb_entry *pmbe)
+static int pmb_alloc_entry(void)
{
- struct pmb_entry **p, *tmp;
+ unsigned int pos;
- p = &pmb_list;
- while ((tmp = *p) != NULL)
- p = &tmp->next;
+repeat:
+ pos = find_first_zero_bit(&pmb_map, NR_PMB_ENTRIES);
- pmbe->next = tmp;
- *p = pmbe;
-}
+ if (unlikely(pos > NR_PMB_ENTRIES))
+ return -ENOSPC;
-static inline void pmb_list_del(struct pmb_entry *pmbe)
-{
- struct pmb_entry **p, *tmp;
+ if (test_and_set_bit(pos, &pmb_map))
+ goto repeat;
- for (p = &pmb_list; (tmp = *p); p = &tmp->next)
- if (tmp == pmbe) {
- *p = tmp->next;
- return;
- }
+ return pos;
}
-struct pmb_entry *pmb_alloc(unsigned long vpn, unsigned long ppn,
- unsigned long flags)
+static struct pmb_entry *pmb_alloc(unsigned long vpn, unsigned long ppn,
+ unsigned long flags, int entry)
{
struct pmb_entry *pmbe;
+ int pos;
+
+ if (entry == PMB_NO_ENTRY) {
+ pos = pmb_alloc_entry();
+ if (pos < 0)
+ return ERR_PTR(pos);
+ } else {
+ if (test_bit(entry, &pmb_map))
+ return ERR_PTR(-ENOSPC);
+ pos = entry;
+ }
- pmbe = kmem_cache_alloc(pmb_cache, GFP_KERNEL);
+ pmbe = &pmb_entry_list[pos];
if (!pmbe)
return ERR_PTR(-ENOMEM);
pmbe->vpn = vpn;
pmbe->ppn = ppn;
pmbe->flags = flags;
-
- spin_lock_irq(&pmb_list_lock);
- pmb_list_add(pmbe);
- spin_unlock_irq(&pmb_list_lock);
+ pmbe->entry = pos;
return pmbe;
}
-void pmb_free(struct pmb_entry *pmbe)
+static void pmb_free(struct pmb_entry *pmbe)
{
- spin_lock_irq(&pmb_list_lock);
- pmb_list_del(pmbe);
- spin_unlock_irq(&pmb_list_lock);
+ int pos = pmbe->entry;
- kmem_cache_free(pmb_cache, pmbe);
+ pmbe->vpn = 0;
+ pmbe->ppn = 0;
+ pmbe->flags = 0;
+ pmbe->entry = 0;
+
+ clear_bit(pos, &pmb_map);
}
/*
* Must be in P2 for __set_pmb_entry()
*/
-int __set_pmb_entry(unsigned long vpn, unsigned long ppn,
- unsigned long flags, int *entry)
+static void __set_pmb_entry(unsigned long vpn, unsigned long ppn,
+ unsigned long flags, int pos)
{
- unsigned int pos = *entry;
-
- if (unlikely(pos == PMB_NO_ENTRY))
- pos = find_first_zero_bit(&pmb_map, NR_PMB_ENTRIES);
-
-repeat:
- if (unlikely(pos > NR_PMB_ENTRIES))
- return -ENOSPC;
-
- if (test_and_set_bit(pos, &pmb_map)) {
- pos = find_first_zero_bit(&pmb_map, NR_PMB_ENTRIES);
- goto repeat;
- }
-
ctrl_outl(vpn | PMB_V, mk_pmb_addr(pos));
#ifdef CONFIG_CACHE_WRITETHROUGH
@@ -161,35 +128,21 @@ repeat:
#endif
ctrl_outl(ppn | flags | PMB_V, mk_pmb_data(pos));
-
- *entry = pos;
-
- return 0;
}
-int __uses_jump_to_uncached set_pmb_entry(struct pmb_entry *pmbe)
+static void __uses_jump_to_uncached set_pmb_entry(struct pmb_entry *pmbe)
{
- int ret;
-
jump_to_uncached();
- ret = __set_pmb_entry(pmbe->vpn, pmbe->ppn, pmbe->flags, &pmbe->entry);
+ __set_pmb_entry(pmbe->vpn, pmbe->ppn, pmbe->flags, pmbe->entry);
back_to_cached();
-
- return ret;
}
-void __uses_jump_to_uncached clear_pmb_entry(struct pmb_entry *pmbe)
+static void __uses_jump_to_uncached clear_pmb_entry(struct pmb_entry *pmbe)
{
unsigned int entry = pmbe->entry;
unsigned long addr;
- /*
- * Don't allow clearing of wired init entries, P1 or P2 access
- * without a corresponding mapping in the PMB will lead to reset
- * by the TLB.
- */
- if (unlikely(entry < ARRAY_SIZE(pmb_init_map) ||
- entry >= NR_PMB_ENTRIES))
+ if (unlikely(entry >= NR_PMB_ENTRIES))
return;
jump_to_uncached();
@@ -202,8 +155,6 @@ void __uses_jump_to_uncached clear_pmb_entry(struct pmb_entry *pmbe)
ctrl_outl(ctrl_inl(addr) & ~PMB_V, addr);
back_to_cached();
-
- clear_bit(entry, &pmb_map);
}
@@ -239,23 +190,17 @@ long pmb_remap(unsigned long vaddr, unsigned long phys,
again:
for (i = 0; i < ARRAY_SIZE(pmb_sizes); i++) {
- int ret;
-
if (size < pmb_sizes[i].size)
continue;
- pmbe = pmb_alloc(vaddr, phys, pmb_flags | pmb_sizes[i].flag);
+ pmbe = pmb_alloc(vaddr, phys, pmb_flags | pmb_sizes[i].flag,
+ PMB_NO_ENTRY);
if (IS_ERR(pmbe)) {
err = PTR_ERR(pmbe);
goto out;
}
- ret = set_pmb_entry(pmbe);
- if (ret != 0) {
- pmb_free(pmbe);
- err = -EBUSY;
- goto out;
- }
+ set_pmb_entry(pmbe);
phys += pmb_sizes[i].size;
vaddr += pmb_sizes[i].size;
@@ -292,11 +237,16 @@ out:
void pmb_unmap(unsigned long addr)
{
- struct pmb_entry **p, *pmbe;
+ struct pmb_entry *pmbe = NULL;
+ int i;
- for (p = &pmb_list; (pmbe = *p); p = &pmbe->next)
- if (pmbe->vpn == addr)
- break;
+ for (i = 0; i < ARRAY_SIZE(pmb_entry_list); i++) {
+ if (test_bit(i, &pmb_map)) {
+ pmbe = &pmb_entry_list[i];
+ if (pmbe->vpn == addr)
+ break;
+ }
+ }
if (unlikely(!pmbe))
return;
@@ -306,13 +256,22 @@ void pmb_unmap(unsigned long addr)
static void __pmb_unmap(struct pmb_entry *pmbe)
{
- WARN_ON(!test_bit(pmbe->entry, &pmb_map));
+ BUG_ON(!test_bit(pmbe->entry, &pmb_map));
do {
struct pmb_entry *pmblink = pmbe;
- if (pmbe->entry != PMB_NO_ENTRY)
- clear_pmb_entry(pmbe);
+ /*
+ * We may be called before this pmb_entry has been
+ * entered into the PMB table via set_pmb_entry(), but
+ * that's OK because we've allocated a unique slot for
+ * this entry in pmb_alloc() (even if we haven't filled
+ * it yet).
+ *
+ * Therefore, calling clear_pmb_entry() is safe as no
+ * other mapping can be using that slot.
+ */
+ clear_pmb_entry(pmbe);
pmbe = pmblink->link;
@@ -320,42 +279,34 @@ static void __pmb_unmap(struct pmb_entry *pmbe)
} while (pmbe);
}
-static void pmb_cache_ctor(void *pmb)
+#ifdef CONFIG_PMB
+int __uses_jump_to_uncached pmb_init(void)
{
- struct pmb_entry *pmbe = pmb;
-
- memset(pmb, 0, sizeof(struct pmb_entry));
-
- pmbe->entry = PMB_NO_ENTRY;
-}
-
-static int __uses_jump_to_uncached pmb_init(void)
-{
- unsigned int nr_entries = ARRAY_SIZE(pmb_init_map);
- unsigned int entry, i;
-
- BUG_ON(unlikely(nr_entries >= NR_PMB_ENTRIES));
-
- pmb_cache = kmem_cache_create("pmb", sizeof(struct pmb_entry), 0,
- SLAB_PANIC, pmb_cache_ctor);
+ unsigned int i;
+ long size, ret;
jump_to_uncached();
/*
- * Ordering is important, P2 must be mapped in the PMB before we
- * can set PMB.SE, and P1 must be mapped before we jump back to
- * P1 space.
+ * Insert PMB entries for the P1 and P2 areas so that, after
+ * we've switched the MMU to 32-bit mode, the semantics of P1
+ * and P2 are the same as in 29-bit mode, e.g.
+ *
+ * P1 - provides a cached window onto physical memory
+ * P2 - provides an uncached window onto physical memory
*/
- for (entry = 0; entry < nr_entries; entry++) {
- struct pmb_entry *pmbe = pmb_init_map + entry;
+ size = __MEMORY_START + __MEMORY_SIZE;
- __set_pmb_entry(pmbe->vpn, pmbe->ppn, pmbe->flags, &entry);
- }
+ ret = pmb_remap(P1SEG, 0x00000000, size, PMB_C);
+ BUG_ON(ret != size);
+
+ ret = pmb_remap(P2SEG, 0x00000000, size, PMB_WT | PMB_UB);
+ BUG_ON(ret != size);
ctrl_outl(0, PMB_IRMCR);
/* PMB.SE and UB[7] */
- ctrl_outl((1 << 31) | (1 << 7), PMB_PASCR);
+ ctrl_outl(PASCR_SE | (1 << 7), PMB_PASCR);
/* Flush out the TLB */
i = ctrl_inl(MMUCR);
@@ -366,7 +317,53 @@ static int __uses_jump_to_uncached pmb_init(void)
return 0;
}
-arch_initcall(pmb_init);
+#else
+int __uses_jump_to_uncached pmb_init(void)
+{
+ int i;
+ unsigned long addr, data;
+
+ jump_to_uncached();
+
+ for (i = 0; i < PMB_ENTRY_MAX; i++) {
+ struct pmb_entry *pmbe;
+ unsigned long vpn, ppn, flags;
+
+ addr = PMB_DATA + (i << PMB_E_SHIFT);
+ data = ctrl_inl(addr);
+ if (!(data & PMB_V))
+ continue;
+
+ if (data & PMB_C) {
+#if defined(CONFIG_CACHE_WRITETHROUGH)
+ data |= PMB_WT;
+#elif defined(CONFIG_CACHE_WRITEBACK)
+ data &= ~PMB_WT;
+#else
+ data &= ~(PMB_C | PMB_WT);
+#endif
+ }
+ ctrl_outl(data, addr);
+
+ ppn = data & PMB_PFN_MASK;
+
+ flags = data & (PMB_C | PMB_WT | PMB_UB);
+ flags |= data & PMB_SZ_MASK;
+
+ addr = PMB_ADDR + (i << PMB_E_SHIFT);
+ data = ctrl_inl(addr);
+
+ vpn = data & PMB_PFN_MASK;
+
+ pmbe = pmb_alloc(vpn, ppn, flags, i);
+ WARN_ON(IS_ERR(pmbe));
+ }
+
+ back_to_cached();
+
+ return 0;
+}
+#endif /* CONFIG_PMB */
static int pmb_seq_show(struct seq_file *file, void *iter)
{
@@ -434,15 +431,18 @@ postcore_initcall(pmb_debugfs_init);
static int pmb_sysdev_suspend(struct sys_device *dev, pm_message_t state)
{
static pm_message_t prev_state;
+ int i;
/* Restore the PMB after a resume from hibernation */
if (state.event == PM_EVENT_ON &&
prev_state.event == PM_EVENT_FREEZE) {
struct pmb_entry *pmbe;
- spin_lock_irq(&pmb_list_lock);
- for (pmbe = pmb_list; pmbe; pmbe = pmbe->next)
- set_pmb_entry(pmbe);
- spin_unlock_irq(&pmb_list_lock);
+ for (i = 0; i < ARRAY_SIZE(pmb_entry_list); i++) {
+ if (test_bit(i, &pmb_map)) {
+ pmbe = &pmb_entry_list[i];
+ set_pmb_entry(pmbe);
+ }
+ }
}
prev_state = state;
return 0;
diff --git a/arch/sh/oprofile/Makefile b/arch/sh/oprofile/Makefile
index 8e6eec9..4886c5c 100644
--- a/arch/sh/oprofile/Makefile
+++ b/arch/sh/oprofile/Makefile
@@ -7,7 +7,3 @@ DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
timer_int.o )
oprofile-y := $(DRIVER_OBJS) common.o backtrace.o
-
-oprofile-$(CONFIG_CPU_SUBTYPE_SH7750S) += op_model_sh7750.o
-oprofile-$(CONFIG_CPU_SUBTYPE_SH7750) += op_model_sh7750.o
-oprofile-$(CONFIG_CPU_SUBTYPE_SH7091) += op_model_sh7750.o
diff --git a/arch/sh/oprofile/common.c b/arch/sh/oprofile/common.c
index 44f4e31..ac60493 100644
--- a/arch/sh/oprofile/common.c
+++ b/arch/sh/oprofile/common.c
@@ -20,9 +20,6 @@
#include <asm/processor.h>
#include "op_impl.h"
-extern struct op_sh_model op_model_sh7750_ops __weak;
-extern struct op_sh_model op_model_sh4a_ops __weak;
-
static struct op_sh_model *model;
static struct op_counter_config ctr[20];
@@ -94,33 +91,14 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
*/
ops->backtrace = sh_backtrace;
- switch (current_cpu_data.type) {
- /* SH-4 types */
- case CPU_SH7750:
- case CPU_SH7750S:
- lmodel = &op_model_sh7750_ops;
- break;
-
- /* SH-4A types */
- case CPU_SH7763:
- case CPU_SH7770:
- case CPU_SH7780:
- case CPU_SH7781:
- case CPU_SH7785:
- case CPU_SH7786:
- case CPU_SH7723:
- case CPU_SH7724:
- case CPU_SHX3:
- lmodel = &op_model_sh4a_ops;
- break;
-
- /* SH4AL-DSP types */
- case CPU_SH7343:
- case CPU_SH7722:
- case CPU_SH7366:
- lmodel = &op_model_sh4a_ops;
- break;
- }
+ /*
+ * XXX
+ *
+ * All of the SH7750/SH-4A counters have been converted to perf,
+ * this infrastructure hook is left for other users until they've
+ * had a chance to convert over, at which point all of this
+ * will be deleted.
+ */
if (!lmodel)
return -ENODEV;
diff --git a/arch/sh/oprofile/op_impl.h b/arch/sh/oprofile/op_impl.h
index 4d50997..1244479 100644
--- a/arch/sh/oprofile/op_impl.h
+++ b/arch/sh/oprofile/op_impl.h
@@ -6,7 +6,7 @@ struct op_counter_config {
unsigned long enabled;
unsigned long event;
- unsigned long long count;
+ unsigned long count;
/* Dummy values for userspace tool compliance */
unsigned long kernel;
diff --git a/arch/sh/oprofile/op_model_sh7750.c b/arch/sh/oprofile/op_model_sh7750.c
deleted file mode 100644
index c892c7c..0000000
--- a/arch/sh/oprofile/op_model_sh7750.c
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * arch/sh/oprofile/op_model_sh7750.c
- *
- * OProfile support for SH7750/SH7750S Performance Counters
- *
- * Copyright (C) 2003 - 2008 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/kernel.h>
-#include <linux/oprofile.h>
-#include <linux/profile.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/fs.h>
-#include "op_impl.h"
-
-#define PM_CR_BASE 0xff000084 /* 16-bit */
-#define PM_CTR_BASE 0xff100004 /* 32-bit */
-
-#define PMCR(n) (PM_CR_BASE + ((n) * 0x04))
-#define PMCTRH(n) (PM_CTR_BASE + 0x00 + ((n) * 0x08))
-#define PMCTRL(n) (PM_CTR_BASE + 0x04 + ((n) * 0x08))
-
-#define PMCR_PMM_MASK 0x0000003f
-
-#define PMCR_CLKF 0x00000100
-#define PMCR_PMCLR 0x00002000
-#define PMCR_PMST 0x00004000
-#define PMCR_PMEN 0x00008000
-
-struct op_sh_model op_model_sh7750_ops;
-
-#define NR_CNTRS 2
-
-static struct sh7750_ppc_register_config {
- unsigned int ctrl;
- unsigned long cnt_hi;
- unsigned long cnt_lo;
-} regcache[NR_CNTRS];
-
-/*
- * There are a number of events supported by each counter (33 in total).
- * Since we have 2 counters, each counter will take the event code as it
- * corresponds to the PMCR PMM setting. Each counter can be configured
- * independently.
- *
- * Event Code Description
- * ---------- -----------
- *
- * 0x01 Operand read access
- * 0x02 Operand write access
- * 0x03 UTLB miss
- * 0x04 Operand cache read miss
- * 0x05 Operand cache write miss
- * 0x06 Instruction fetch (w/ cache)
- * 0x07 Instruction TLB miss
- * 0x08 Instruction cache miss
- * 0x09 All operand accesses
- * 0x0a All instruction accesses
- * 0x0b OC RAM operand access
- * 0x0d On-chip I/O space access
- * 0x0e Operand access (r/w)
- * 0x0f Operand cache miss (r/w)
- * 0x10 Branch instruction
- * 0x11 Branch taken
- * 0x12 BSR/BSRF/JSR
- * 0x13 Instruction execution
- * 0x14 Instruction execution in parallel
- * 0x15 FPU Instruction execution
- * 0x16 Interrupt
- * 0x17 NMI
- * 0x18 trapa instruction execution
- * 0x19 UBCA match
- * 0x1a UBCB match
- * 0x21 Instruction cache fill
- * 0x22 Operand cache fill
- * 0x23 Elapsed time
- * 0x24 Pipeline freeze by I-cache miss
- * 0x25 Pipeline freeze by D-cache miss
- * 0x27 Pipeline freeze by branch instruction
- * 0x28 Pipeline freeze by CPU register
- * 0x29 Pipeline freeze by FPU
- *
- * Unfortunately we don't have a native exception or interrupt for counter
- * overflow (although since these counters can run for 16.3 days without
- * overflowing, it's not really necessary).
- *
- * OProfile on the other hand likes to have samples taken periodically, so
- * for now we just piggyback the timer interrupt to get the expected
- * behavior.
- */
-
-static int sh7750_timer_notify(struct pt_regs *regs)
-{
- oprofile_add_sample(regs, 0);
- return 0;
-}
-
-static u64 sh7750_read_counter(int counter)
-{
- return (u64)((u64)(__raw_readl(PMCTRH(counter)) & 0xffff) << 32) |
- __raw_readl(PMCTRL(counter));
-}
-
-/*
- * Files will be in a path like:
- *
- * /<oprofilefs mount point>/<counter number>/<file>
- *
- * So when dealing with <file>, we look to the parent dentry for the counter
- * number.
- */
-static inline int to_counter(struct file *file)
-{
- const unsigned char *name = file->f_path.dentry->d_parent->d_name.name;
-
- return (int)simple_strtol(name, NULL, 10);
-}
-
-/*
- * XXX: We have 48-bit counters, so we're probably going to want something
- * more along the lines of oprofilefs_ullong_to_user().. Truncating to
- * unsigned long works fine for now though, as long as we don't attempt to
- * profile for too horribly long.
- */
-static ssize_t sh7750_read_count(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- int counter = to_counter(file);
- u64 val = sh7750_read_counter(counter);
-
- return oprofilefs_ulong_to_user((unsigned long)val, buf, count, ppos);
-}
-
-static ssize_t sh7750_write_count(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
-{
- int counter = to_counter(file);
- unsigned long val;
-
- if (oprofilefs_ulong_from_user(&val, buf, count))
- return -EFAULT;
-
- /*
- * Any write will clear the counter, although only 0 should be
- * written for this purpose, as we do not support setting the
- * counter to an arbitrary value.
- */
- WARN_ON(val != 0);
-
- __raw_writew(__raw_readw(PMCR(counter)) | PMCR_PMCLR, PMCR(counter));
-
- return count;
-}
-
-static const struct file_operations count_fops = {
- .read = sh7750_read_count,
- .write = sh7750_write_count,
-};
-
-static int sh7750_ppc_create_files(struct super_block *sb, struct dentry *dir)
-{
- return oprofilefs_create_file(sb, dir, "count", &count_fops);
-}
-
-static void sh7750_ppc_reg_setup(struct op_counter_config *ctr)
-{
- unsigned int counters = op_model_sh7750_ops.num_counters;
- int i;
-
- for (i = 0; i < counters; i++) {
- regcache[i].ctrl = 0;
- regcache[i].cnt_hi = 0;
- regcache[i].cnt_lo = 0;
-
- if (!ctr[i].enabled)
- continue;
-
- regcache[i].ctrl |= ctr[i].event | PMCR_PMEN | PMCR_PMST;
- regcache[i].cnt_hi = (unsigned long)((ctr->count >> 32) & 0xffff);
- regcache[i].cnt_lo = (unsigned long)(ctr->count & 0xffffffff);
- }
-}
-
-static void sh7750_ppc_cpu_setup(void *args)
-{
- unsigned int counters = op_model_sh7750_ops.num_counters;
- int i;
-
- for (i = 0; i < counters; i++) {
- __raw_writew(0, PMCR(i));
- __raw_writel(regcache[i].cnt_hi, PMCTRH(i));
- __raw_writel(regcache[i].cnt_lo, PMCTRL(i));
- }
-}
-
-static void sh7750_ppc_cpu_start(void *args)
-{
- unsigned int counters = op_model_sh7750_ops.num_counters;
- int i;
-
- for (i = 0; i < counters; i++)
- __raw_writew(regcache[i].ctrl, PMCR(i));
-}
-
-static void sh7750_ppc_cpu_stop(void *args)
-{
- unsigned int counters = op_model_sh7750_ops.num_counters;
- int i;
-
- /* Disable the counters */
- for (i = 0; i < counters; i++)
- __raw_writew(__raw_readw(PMCR(i)) & ~PMCR_PMEN, PMCR(i));
-}
-
-static inline void sh7750_ppc_reset(void)
-{
- unsigned int counters = op_model_sh7750_ops.num_counters;
- int i;
-
- /* Clear the counters */
- for (i = 0; i < counters; i++)
- __raw_writew(__raw_readw(PMCR(i)) | PMCR_PMCLR, PMCR(i));
-}
-
-static int sh7750_ppc_init(void)
-{
- sh7750_ppc_reset();
-
- return register_timer_hook(sh7750_timer_notify);
-}
-
-static void sh7750_ppc_exit(void)
-{
- unregister_timer_hook(sh7750_timer_notify);
-
- sh7750_ppc_reset();
-}
-
-struct op_sh_model op_model_sh7750_ops = {
- .cpu_type = "sh/sh7750",
- .num_counters = NR_CNTRS,
- .reg_setup = sh7750_ppc_reg_setup,
- .cpu_setup = sh7750_ppc_cpu_setup,
- .cpu_start = sh7750_ppc_cpu_start,
- .cpu_stop = sh7750_ppc_cpu_stop,
- .init = sh7750_ppc_init,
- .exit = sh7750_ppc_exit,
- .create_files = sh7750_ppc_create_files,
-};
diff --git a/arch/sparc/kernel/time_64.c b/arch/sparc/kernel/time_64.c
index da1218e..63f73ae 100644
--- a/arch/sparc/kernel/time_64.c
+++ b/arch/sparc/kernel/time_64.c
@@ -847,7 +847,7 @@ void __init time_init(void)
sparc64_clockevent.min_delta_ns =
clockevent_delta2ns(0xF, &sparc64_clockevent);
- printk("clockevent: mult[%lx] shift[%d]\n",
+ printk("clockevent: mult[%ux] shift[%d]\n",
sparc64_clockevent.mult, sparc64_clockevent.shift);
setup_sparc64_timer();
diff --git a/arch/um/drivers/mmapper_kern.c b/arch/um/drivers/mmapper_kern.c
index eb24032..d22f9e5 100644
--- a/arch/um/drivers/mmapper_kern.c
+++ b/arch/um/drivers/mmapper_kern.c
@@ -16,7 +16,7 @@
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/mm.h>
-#include <linux/smp_lock.h>
+
#include <asm/uaccess.h>
#include "mem_user.h"
@@ -78,7 +78,6 @@ out:
static int mmapper_open(struct inode *inode, struct file *file)
{
- cycle_kernel_lock();
return 0;
}
@@ -115,18 +114,16 @@ static int __init mmapper_init(void)
v_buf = (char *) find_iomem("mmapper", &mmapper_size);
if (mmapper_size == 0) {
printk(KERN_ERR "mmapper_init - find_iomem failed\n");
- goto out;
+ return -ENODEV;
}
+ p_buf = __pa(v_buf);
err = misc_register(&mmapper_dev);
if (err) {
printk(KERN_ERR "mmapper - misc_register failed, err = %d\n",
err);
- goto out;
+ return err;;
}
-
- p_buf = __pa(v_buf);
-out:
return 0;
}
diff --git a/arch/um/drivers/random.c b/arch/um/drivers/random.c
index 6eabb70..4949044 100644
--- a/arch/um/drivers/random.c
+++ b/arch/um/drivers/random.c
@@ -7,7 +7,6 @@
* of the GNU General Public License, incorporated herein by reference.
*/
#include <linux/sched.h>
-#include <linux/smp_lock.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
@@ -34,8 +33,6 @@ static DECLARE_WAIT_QUEUE_HEAD(host_read_wait);
static int rng_dev_open (struct inode *inode, struct file *filp)
{
- cycle_kernel_lock();
-
/* enforce read-only access to this chrdev */
if ((filp->f_mode & FMODE_READ) == 0)
return -EINVAL;
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 1b2182b..32a1918 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1332,7 +1332,9 @@ config MATH_EMULATION
kernel, it won't hurt.
config MTRR
- bool "MTRR (Memory Type Range Register) support"
+ bool
+ default y
+ prompt "MTRR (Memory Type Range Register) support" if EMBEDDED
---help---
On Intel P6 family processors (Pentium Pro, Pentium II and later)
the Memory Type Range Registers (MTRRs) may be used to control
@@ -1398,7 +1400,8 @@ config MTRR_SANITIZER_SPARE_REG_NR_DEFAULT
config X86_PAT
bool
- prompt "x86 PAT support"
+ default y
+ prompt "x86 PAT support" if EMBEDDED
depends on MTRR
---help---
Use PAT attributes to setup page level cache control.
@@ -1604,7 +1607,7 @@ config COMPAT_VDSO
depends on X86_32 || IA32_EMULATION
---help---
Map the 32-bit VDSO to the predictable old-style address too.
- ---help---
+
Say N here if you are running a sufficiently recent glibc
version (2.3.3 or later), to remove the high-mapped
VDSO mapping and to exclusively use the randomized VDSO.
diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu
index 5e99762..08e442b 100644
--- a/arch/x86/Kconfig.cpu
+++ b/arch/x86/Kconfig.cpu
@@ -301,15 +301,11 @@ config X86_CPU
#
# Define implied options from the CPU selection here
-config X86_L1_CACHE_BYTES
+config X86_INTERNODE_CACHE_SHIFT
int
- default "128" if MPSC
- default "64" if GENERIC_CPU || MK8 || MCORE2 || MATOM || X86_32
-
-config X86_INTERNODE_CACHE_BYTES
- int
- default "4096" if X86_VSMP
- default X86_L1_CACHE_BYTES if !X86_VSMP
+ default "12" if X86_VSMP
+ default "7" if NUMA
+ default X86_L1_CACHE_SHIFT
config X86_CMPXCHG
def_bool X86_64 || (X86_32 && !M386)
@@ -317,9 +313,9 @@ config X86_CMPXCHG
config X86_L1_CACHE_SHIFT
int
default "7" if MPENTIUM4 || MPSC
+ default "6" if MK7 || MK8 || MPENTIUMM || MCORE2 || MATOM || MVIAC7 || X86_GENERIC || GENERIC_CPU
default "4" if X86_ELAN || M486 || M386 || MGEODEGX1
default "5" if MWINCHIP3D || MWINCHIPC6 || MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODE_LX
- default "6" if MK7 || MK8 || MPENTIUMM || MCORE2 || MATOM || MVIAC7 || X86_GENERIC || GENERIC_CPU
config X86_XADD
def_bool y
diff --git a/arch/x86/Makefile_32.cpu b/arch/x86/Makefile_32.cpu
index cbf0776..1255d95 100644
--- a/arch/x86/Makefile_32.cpu
+++ b/arch/x86/Makefile_32.cpu
@@ -46,6 +46,13 @@ cflags-$(CONFIG_MGEODE_LX) += $(call cc-option,-march=geode,-march=pentium-mmx)
# cpu entries
cflags-$(CONFIG_X86_GENERIC) += $(call tune,generic,$(call tune,i686))
+# Work around the pentium-mmx code generator madness of gcc4.4.x which
+# does stack alignment by generating horrible code _before_ the mcount
+# prologue (push %ebp, mov %esp, %ebp) which breaks the function graph
+# tracer assumptions. For i686, generic, core2 this is set by the
+# compiler anyway
+cflags-$(CONFIG_FUNCTION_GRAPH_TRACER) += $(call cc-option,-maccumulate-outgoing-args)
+
# Bug fix for binutils: this option is required in order to keep
# binutils from generating NOPL instructions against our will.
ifneq ($(CONFIG_X86_P6_NOP),y)
diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
index 077e1b6..faff0dc 100644
--- a/arch/x86/boot/compressed/head_64.S
+++ b/arch/x86/boot/compressed/head_64.S
@@ -107,8 +107,7 @@ ENTRY(startup_32)
lgdt gdt(%ebp)
/* Enable PAE mode */
- xorl %eax, %eax
- orl $(X86_CR4_PAE), %eax
+ movl $(X86_CR4_PAE), %eax
movl %eax, %cr4
/*
diff --git a/arch/x86/boot/compressed/vmlinux.lds.S b/arch/x86/boot/compressed/vmlinux.lds.S
index f4193bb..a6f1a59 100644
--- a/arch/x86/boot/compressed/vmlinux.lds.S
+++ b/arch/x86/boot/compressed/vmlinux.lds.S
@@ -4,6 +4,7 @@ OUTPUT_FORMAT(CONFIG_OUTPUT_FORMAT, CONFIG_OUTPUT_FORMAT, CONFIG_OUTPUT_FORMAT)
#undef i386
+#include <asm/cache.h>
#include <asm/page_types.h>
#ifdef CONFIG_X86_64
@@ -46,7 +47,7 @@ SECTIONS
*(.data.*)
_edata = . ;
}
- . = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
+ . = ALIGN(L1_CACHE_BYTES);
.bss : {
_bss = . ;
*(.bss)
diff --git a/arch/x86/boot/video.c b/arch/x86/boot/video.c
index d42da38..f767164 100644
--- a/arch/x86/boot/video.c
+++ b/arch/x86/boot/video.c
@@ -27,6 +27,12 @@ static void store_cursor_position(void)
boot_params.screen_info.orig_x = oreg.dl;
boot_params.screen_info.orig_y = oreg.dh;
+
+ if (oreg.ch & 0x20)
+ boot_params.screen_info.flags |= VIDEO_FLAGS_NOCURSOR;
+
+ if ((oreg.ch & 0x1f) > (oreg.cl & 0x1f))
+ boot_params.screen_info.flags |= VIDEO_FLAGS_NOCURSOR;
}
static void store_video_mode(void)
diff --git a/arch/x86/crypto/Makefile b/arch/x86/crypto/Makefile
index cfb0010..1a58ad8 100644
--- a/arch/x86/crypto/Makefile
+++ b/arch/x86/crypto/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_CRYPTO_AES_X86_64) += aes-x86_64.o
obj-$(CONFIG_CRYPTO_TWOFISH_X86_64) += twofish-x86_64.o
obj-$(CONFIG_CRYPTO_SALSA20_X86_64) += salsa20-x86_64.o
obj-$(CONFIG_CRYPTO_AES_NI_INTEL) += aesni-intel.o
+obj-$(CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL) += ghash-clmulni-intel.o
obj-$(CONFIG_CRYPTO_CRC32C_INTEL) += crc32c-intel.o
@@ -24,3 +25,5 @@ twofish-x86_64-y := twofish-x86_64-asm_64.o twofish_glue.o
salsa20-x86_64-y := salsa20-x86_64-asm_64.o salsa20_glue.o
aesni-intel-y := aesni-intel_asm.o aesni-intel_glue.o
+
+ghash-clmulni-intel-y := ghash-clmulni-intel_asm.o ghash-clmulni-intel_glue.o
diff --git a/arch/x86/crypto/aesni-intel_asm.S b/arch/x86/crypto/aesni-intel_asm.S
index eb0566e..20bb0e1 100644
--- a/arch/x86/crypto/aesni-intel_asm.S
+++ b/arch/x86/crypto/aesni-intel_asm.S
@@ -16,6 +16,7 @@
*/
#include <linux/linkage.h>
+#include <asm/inst.h>
.text
@@ -122,103 +123,72 @@ ENTRY(aesni_set_key)
movups 0x10(%rsi), %xmm2 # other user key
movaps %xmm2, (%rcx)
add $0x10, %rcx
- # aeskeygenassist $0x1, %xmm2, %xmm1 # round 1
- .byte 0x66, 0x0f, 0x3a, 0xdf, 0xca, 0x01
+ AESKEYGENASSIST 0x1 %xmm2 %xmm1 # round 1
call _key_expansion_256a
- # aeskeygenassist $0x1, %xmm0, %xmm1
- .byte 0x66, 0x0f, 0x3a, 0xdf, 0xc8, 0x01
+ AESKEYGENASSIST 0x1 %xmm0 %xmm1
call _key_expansion_256b
- # aeskeygenassist $0x2, %xmm2, %xmm1 # round 2
- .byte 0x66, 0x0f, 0x3a, 0xdf, 0xca, 0x02
+ AESKEYGENASSIST 0x2 %xmm2 %xmm1 # round 2
call _key_expansion_256a
- # aeskeygenassist $0x2, %xmm0, %xmm1
- .byte 0x66, 0x0f, 0x3a, 0xdf, 0xc8, 0x02
+ AESKEYGENASSIST 0x2 %xmm0 %xmm1
call _key_expansion_256b
- # aeskeygenassist $0x4, %xmm2, %xmm1 # round 3
- .byte 0x66, 0x0f, 0x3a, 0xdf, 0xca, 0x04
+ AESKEYGENASSIST 0x4 %xmm2 %xmm1 # round 3
call _key_expansion_256a
- # aeskeygenassist $0x4, %xmm0, %xmm1
- .byte 0x66, 0x0f, 0x3a, 0xdf, 0xc8, 0x04
+ AESKEYGENASSIST 0x4 %xmm0 %xmm1
call _key_expansion_256b
- # aeskeygenassist $0x8, %xmm2, %xmm1 # round 4
- .byte 0x66, 0x0f, 0x3a, 0xdf, 0xca, 0x08
+ AESKEYGENASSIST 0x8 %xmm2 %xmm1 # round 4
call _key_expansion_256a
- # aeskeygenassist $0x8, %xmm0, %xmm1
- .byte 0x66, 0x0f, 0x3a, 0xdf, 0xc8, 0x08
+ AESKEYGENASSIST 0x8 %xmm0 %xmm1
call _key_expansion_256b
- # aeskeygenassist $0x10, %xmm2, %xmm1 # round 5
- .byte 0x66, 0x0f, 0x3a, 0xdf, 0xca, 0x10
+ AESKEYGENASSIST 0x10 %xmm2 %xmm1 # round 5
call _key_expansion_256a
- # aeskeygenassist $0x10, %xmm0, %xmm1
- .byte 0x66, 0x0f, 0x3a, 0xdf, 0xc8, 0x10
+ AESKEYGENASSIST 0x10 %xmm0 %xmm1
call _key_expansion_256b
- # aeskeygenassist $0x20, %xmm2, %xmm1 # round 6
- .byte 0x66, 0x0f, 0x3a, 0xdf, 0xca, 0x20
+ AESKEYGENASSIST 0x20 %xmm2 %xmm1 # round 6
call _key_expansion_256a
- # aeskeygenassist $0x20, %xmm0, %xmm1
- .byte 0x66, 0x0f, 0x3a, 0xdf, 0xc8, 0x20
+ AESKEYGENASSIST 0x20 %xmm0 %xmm1
call _key_expansion_256b
- # aeskeygenassist $0x40, %xmm2, %xmm1 # round 7
- .byte 0x66, 0x0f, 0x3a, 0xdf, 0xca, 0x40
+ AESKEYGENASSIST 0x40 %xmm2 %xmm1 # round 7
call _key_expansion_256a
jmp .Ldec_key
.Lenc_key192:
movq 0x10(%rsi), %xmm2 # other user key
- # aeskeygenassist $0x1, %xmm2, %xmm1 # round 1
- .byte 0x66, 0x0f, 0x3a, 0xdf, 0xca, 0x01
+ AESKEYGENASSIST 0x1 %xmm2 %xmm1 # round 1
call _key_expansion_192a
- # aeskeygenassist $0x2, %xmm2, %xmm1 # round 2
- .byte 0x66, 0x0f, 0x3a, 0xdf, 0xca, 0x02
+ AESKEYGENASSIST 0x2 %xmm2 %xmm1 # round 2
call _key_expansion_192b
- # aeskeygenassist $0x4, %xmm2, %xmm1 # round 3
- .byte 0x66, 0x0f, 0x3a, 0xdf, 0xca, 0x04
+ AESKEYGENASSIST 0x4 %xmm2 %xmm1 # round 3
call _key_expansion_192a
- # aeskeygenassist $0x8, %xmm2, %xmm1 # round 4
- .byte 0x66, 0x0f, 0x3a, 0xdf, 0xca, 0x08
+ AESKEYGENASSIST 0x8 %xmm2 %xmm1 # round 4
call _key_expansion_192b
- # aeskeygenassist $0x10, %xmm2, %xmm1 # round 5
- .byte 0x66, 0x0f, 0x3a, 0xdf, 0xca, 0x10
+ AESKEYGENASSIST 0x10 %xmm2 %xmm1 # round 5
call _key_expansion_192a
- # aeskeygenassist $0x20, %xmm2, %xmm1 # round 6
- .byte 0x66, 0x0f, 0x3a, 0xdf, 0xca, 0x20
+ AESKEYGENASSIST 0x20 %xmm2 %xmm1 # round 6
call _key_expansion_192b
- # aeskeygenassist $0x40, %xmm2, %xmm1 # round 7
- .byte 0x66, 0x0f, 0x3a, 0xdf, 0xca, 0x40
+ AESKEYGENASSIST 0x40 %xmm2 %xmm1 # round 7
call _key_expansion_192a
- # aeskeygenassist $0x80, %xmm2, %xmm1 # round 8
- .byte 0x66, 0x0f, 0x3a, 0xdf, 0xca, 0x80
+ AESKEYGENASSIST 0x80 %xmm2 %xmm1 # round 8
call _key_expansion_192b
jmp .Ldec_key
.Lenc_key128:
- # aeskeygenassist $0x1, %xmm0, %xmm1 # round 1
- .byte 0x66, 0x0f, 0x3a, 0xdf, 0xc8, 0x01
+ AESKEYGENASSIST 0x1 %xmm0 %xmm1 # round 1
call _key_expansion_128
- # aeskeygenassist $0x2, %xmm0, %xmm1 # round 2
- .byte 0x66, 0x0f, 0x3a, 0xdf, 0xc8, 0x02
+ AESKEYGENASSIST 0x2 %xmm0 %xmm1 # round 2
call _key_expansion_128
- # aeskeygenassist $0x4, %xmm0, %xmm1 # round 3
- .byte 0x66, 0x0f, 0x3a, 0xdf, 0xc8, 0x04
+ AESKEYGENASSIST 0x4 %xmm0 %xmm1 # round 3
call _key_expansion_128
- # aeskeygenassist $0x8, %xmm0, %xmm1 # round 4
- .byte 0x66, 0x0f, 0x3a, 0xdf, 0xc8, 0x08
+ AESKEYGENASSIST 0x8 %xmm0 %xmm1 # round 4
call _key_expansion_128
- # aeskeygenassist $0x10, %xmm0, %xmm1 # round 5
- .byte 0x66, 0x0f, 0x3a, 0xdf, 0xc8, 0x10
+ AESKEYGENASSIST 0x10 %xmm0 %xmm1 # round 5
call _key_expansion_128
- # aeskeygenassist $0x20, %xmm0, %xmm1 # round 6
- .byte 0x66, 0x0f, 0x3a, 0xdf, 0xc8, 0x20
+ AESKEYGENASSIST 0x20 %xmm0 %xmm1 # round 6
call _key_expansion_128
- # aeskeygenassist $0x40, %xmm0, %xmm1 # round 7
- .byte 0x66, 0x0f, 0x3a, 0xdf, 0xc8, 0x40
+ AESKEYGENASSIST 0x40 %xmm0 %xmm1 # round 7
call _key_expansion_128
- # aeskeygenassist $0x80, %xmm0, %xmm1 # round 8
- .byte 0x66, 0x0f, 0x3a, 0xdf, 0xc8, 0x80
+ AESKEYGENASSIST 0x80 %xmm0 %xmm1 # round 8
call _key_expansion_128
- # aeskeygenassist $0x1b, %xmm0, %xmm1 # round 9
- .byte 0x66, 0x0f, 0x3a, 0xdf, 0xc8, 0x1b
+ AESKEYGENASSIST 0x1b %xmm0 %xmm1 # round 9
call _key_expansion_128
- # aeskeygenassist $0x36, %xmm0, %xmm1 # round 10
- .byte 0x66, 0x0f, 0x3a, 0xdf, 0xc8, 0x36
+ AESKEYGENASSIST 0x36 %xmm0 %xmm1 # round 10
call _key_expansion_128
.Ldec_key:
sub $0x10, %rcx
@@ -231,8 +201,7 @@ ENTRY(aesni_set_key)
.align 4
.Ldec_key_loop:
movaps (%rdi), %xmm0
- # aesimc %xmm0, %xmm1
- .byte 0x66, 0x0f, 0x38, 0xdb, 0xc8
+ AESIMC %xmm0 %xmm1
movaps %xmm1, (%rsi)
add $0x10, %rdi
sub $0x10, %rsi
@@ -274,51 +243,37 @@ _aesni_enc1:
je .Lenc192
add $0x20, TKEYP
movaps -0x60(TKEYP), KEY
- # aesenc KEY, STATE
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+ AESENC KEY STATE
movaps -0x50(TKEYP), KEY
- # aesenc KEY, STATE
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+ AESENC KEY STATE
.align 4
.Lenc192:
movaps -0x40(TKEYP), KEY
- # aesenc KEY, STATE
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+ AESENC KEY STATE
movaps -0x30(TKEYP), KEY
- # aesenc KEY, STATE
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+ AESENC KEY STATE
.align 4
.Lenc128:
movaps -0x20(TKEYP), KEY
- # aesenc KEY, STATE
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+ AESENC KEY STATE
movaps -0x10(TKEYP), KEY
- # aesenc KEY, STATE
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+ AESENC KEY STATE
movaps (TKEYP), KEY
- # aesenc KEY, STATE
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+ AESENC KEY STATE
movaps 0x10(TKEYP), KEY
- # aesenc KEY, STATE
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+ AESENC KEY STATE
movaps 0x20(TKEYP), KEY
- # aesenc KEY, STATE
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+ AESENC KEY STATE
movaps 0x30(TKEYP), KEY
- # aesenc KEY, STATE
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+ AESENC KEY STATE
movaps 0x40(TKEYP), KEY
- # aesenc KEY, STATE
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+ AESENC KEY STATE
movaps 0x50(TKEYP), KEY
- # aesenc KEY, STATE
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+ AESENC KEY STATE
movaps 0x60(TKEYP), KEY
- # aesenc KEY, STATE
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
+ AESENC KEY STATE
movaps 0x70(TKEYP), KEY
- # aesenclast KEY, STATE # last round
- .byte 0x66, 0x0f, 0x38, 0xdd, 0xc2
+ AESENCLAST KEY STATE
ret
/*
@@ -353,135 +308,79 @@ _aesni_enc4:
je .L4enc192
add $0x20, TKEYP
movaps -0x60(TKEYP), KEY
- # aesenc KEY, STATE1
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
- # aesenc KEY, STATE2
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xe2
- # aesenc KEY, STATE3
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xea
- # aesenc KEY, STATE4
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xf2
+ AESENC KEY STATE1
+ AESENC KEY STATE2
+ AESENC KEY STATE3
+ AESENC KEY STATE4
movaps -0x50(TKEYP), KEY
- # aesenc KEY, STATE1
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
- # aesenc KEY, STATE2
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xe2
- # aesenc KEY, STATE3
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xea
- # aesenc KEY, STATE4
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xf2
+ AESENC KEY STATE1
+ AESENC KEY STATE2
+ AESENC KEY STATE3
+ AESENC KEY STATE4
#.align 4
.L4enc192:
movaps -0x40(TKEYP), KEY
- # aesenc KEY, STATE1
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
- # aesenc KEY, STATE2
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xe2
- # aesenc KEY, STATE3
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xea
- # aesenc KEY, STATE4
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xf2
+ AESENC KEY STATE1
+ AESENC KEY STATE2
+ AESENC KEY STATE3
+ AESENC KEY STATE4
movaps -0x30(TKEYP), KEY
- # aesenc KEY, STATE1
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
- # aesenc KEY, STATE2
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xe2
- # aesenc KEY, STATE3
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xea
- # aesenc KEY, STATE4
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xf2
+ AESENC KEY STATE1
+ AESENC KEY STATE2
+ AESENC KEY STATE3
+ AESENC KEY STATE4
#.align 4
.L4enc128:
movaps -0x20(TKEYP), KEY
- # aesenc KEY, STATE1
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
- # aesenc KEY, STATE2
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xe2
- # aesenc KEY, STATE3
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xea
- # aesenc KEY, STATE4
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xf2
+ AESENC KEY STATE1
+ AESENC KEY STATE2
+ AESENC KEY STATE3
+ AESENC KEY STATE4
movaps -0x10(TKEYP), KEY
- # aesenc KEY, STATE1
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
- # aesenc KEY, STATE2
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xe2
- # aesenc KEY, STATE3
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xea
- # aesenc KEY, STATE4
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xf2
+ AESENC KEY STATE1
+ AESENC KEY STATE2
+ AESENC KEY STATE3
+ AESENC KEY STATE4
movaps (TKEYP), KEY
- # aesenc KEY, STATE1
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
- # aesenc KEY, STATE2
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xe2
- # aesenc KEY, STATE3
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xea
- # aesenc KEY, STATE4
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xf2
+ AESENC KEY STATE1
+ AESENC KEY STATE2
+ AESENC KEY STATE3
+ AESENC KEY STATE4
movaps 0x10(TKEYP), KEY
- # aesenc KEY, STATE1
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
- # aesenc KEY, STATE2
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xe2
- # aesenc KEY, STATE3
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xea
- # aesenc KEY, STATE4
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xf2
+ AESENC KEY STATE1
+ AESENC KEY STATE2
+ AESENC KEY STATE3
+ AESENC KEY STATE4
movaps 0x20(TKEYP), KEY
- # aesenc KEY, STATE1
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
- # aesenc KEY, STATE2
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xe2
- # aesenc KEY, STATE3
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xea
- # aesenc KEY, STATE4
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xf2
+ AESENC KEY STATE1
+ AESENC KEY STATE2
+ AESENC KEY STATE3
+ AESENC KEY STATE4
movaps 0x30(TKEYP), KEY
- # aesenc KEY, STATE1
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
- # aesenc KEY, STATE2
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xe2
- # aesenc KEY, STATE3
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xea
- # aesenc KEY, STATE4
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xf2
+ AESENC KEY STATE1
+ AESENC KEY STATE2
+ AESENC KEY STATE3
+ AESENC KEY STATE4
movaps 0x40(TKEYP), KEY
- # aesenc KEY, STATE1
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
- # aesenc KEY, STATE2
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xe2
- # aesenc KEY, STATE3
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xea
- # aesenc KEY, STATE4
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xf2
+ AESENC KEY STATE1
+ AESENC KEY STATE2
+ AESENC KEY STATE3
+ AESENC KEY STATE4
movaps 0x50(TKEYP), KEY
- # aesenc KEY, STATE1
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
- # aesenc KEY, STATE2
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xe2
- # aesenc KEY, STATE3
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xea
- # aesenc KEY, STATE4
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xf2
+ AESENC KEY STATE1
+ AESENC KEY STATE2
+ AESENC KEY STATE3
+ AESENC KEY STATE4
movaps 0x60(TKEYP), KEY
- # aesenc KEY, STATE1
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xc2
- # aesenc KEY, STATE2
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xe2
- # aesenc KEY, STATE3
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xea
- # aesenc KEY, STATE4
- .byte 0x66, 0x0f, 0x38, 0xdc, 0xf2
+ AESENC KEY STATE1
+ AESENC KEY STATE2
+ AESENC KEY STATE3
+ AESENC KEY STATE4
movaps 0x70(TKEYP), KEY
- # aesenclast KEY, STATE1 # last round
- .byte 0x66, 0x0f, 0x38, 0xdd, 0xc2
- # aesenclast KEY, STATE2
- .byte 0x66, 0x0f, 0x38, 0xdd, 0xe2
- # aesenclast KEY, STATE3
- .byte 0x66, 0x0f, 0x38, 0xdd, 0xea
- # aesenclast KEY, STATE4
- .byte 0x66, 0x0f, 0x38, 0xdd, 0xf2
+ AESENCLAST KEY STATE1 # last round
+ AESENCLAST KEY STATE2
+ AESENCLAST KEY STATE3
+ AESENCLAST KEY STATE4
ret
/*
@@ -518,51 +417,37 @@ _aesni_dec1:
je .Ldec192
add $0x20, TKEYP
movaps -0x60(TKEYP), KEY
- # aesdec KEY, STATE
- .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+ AESDEC KEY STATE
movaps -0x50(TKEYP), KEY
- # aesdec KEY, STATE
- .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+ AESDEC KEY STATE
.align 4
.Ldec192:
movaps -0x40(TKEYP), KEY
- # aesdec KEY, STATE
- .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+ AESDEC KEY STATE
movaps -0x30(TKEYP), KEY
- # aesdec KEY, STATE
- .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+ AESDEC KEY STATE
.align 4
.Ldec128:
movaps -0x20(TKEYP), KEY
- # aesdec KEY, STATE
- .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+ AESDEC KEY STATE
movaps -0x10(TKEYP), KEY
- # aesdec KEY, STATE
- .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+ AESDEC KEY STATE
movaps (TKEYP), KEY
- # aesdec KEY, STATE
- .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+ AESDEC KEY STATE
movaps 0x10(TKEYP), KEY
- # aesdec KEY, STATE
- .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+ AESDEC KEY STATE
movaps 0x20(TKEYP), KEY
- # aesdec KEY, STATE
- .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+ AESDEC KEY STATE
movaps 0x30(TKEYP), KEY
- # aesdec KEY, STATE
- .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+ AESDEC KEY STATE
movaps 0x40(TKEYP), KEY
- # aesdec KEY, STATE
- .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+ AESDEC KEY STATE
movaps 0x50(TKEYP), KEY
- # aesdec KEY, STATE
- .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+ AESDEC KEY STATE
movaps 0x60(TKEYP), KEY
- # aesdec KEY, STATE
- .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
+ AESDEC KEY STATE
movaps 0x70(TKEYP), KEY
- # aesdeclast KEY, STATE # last round
- .byte 0x66, 0x0f, 0x38, 0xdf, 0xc2
+ AESDECLAST KEY STATE
ret
/*
@@ -597,135 +482,79 @@ _aesni_dec4:
je .L4dec192
add $0x20, TKEYP
movaps -0x60(TKEYP), KEY
- # aesdec KEY, STATE1
- .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
- # aesdec KEY, STATE2
- .byte 0x66, 0x0f, 0x38, 0xde, 0xe2
- # aesdec KEY, STATE3
- .byte 0x66, 0x0f, 0x38, 0xde, 0xea
- # aesdec KEY, STATE4
- .byte 0x66, 0x0f, 0x38, 0xde, 0xf2
+ AESDEC KEY STATE1
+ AESDEC KEY STATE2
+ AESDEC KEY STATE3
+ AESDEC KEY STATE4
movaps -0x50(TKEYP), KEY
- # aesdec KEY, STATE1
- .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
- # aesdec KEY, STATE2
- .byte 0x66, 0x0f, 0x38, 0xde, 0xe2
- # aesdec KEY, STATE3
- .byte 0x66, 0x0f, 0x38, 0xde, 0xea
- # aesdec KEY, STATE4
- .byte 0x66, 0x0f, 0x38, 0xde, 0xf2
+ AESDEC KEY STATE1
+ AESDEC KEY STATE2
+ AESDEC KEY STATE3
+ AESDEC KEY STATE4
.align 4
.L4dec192:
movaps -0x40(TKEYP), KEY
- # aesdec KEY, STATE1
- .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
- # aesdec KEY, STATE2
- .byte 0x66, 0x0f, 0x38, 0xde, 0xe2
- # aesdec KEY, STATE3
- .byte 0x66, 0x0f, 0x38, 0xde, 0xea
- # aesdec KEY, STATE4
- .byte 0x66, 0x0f, 0x38, 0xde, 0xf2
+ AESDEC KEY STATE1
+ AESDEC KEY STATE2
+ AESDEC KEY STATE3
+ AESDEC KEY STATE4
movaps -0x30(TKEYP), KEY
- # aesdec KEY, STATE1
- .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
- # aesdec KEY, STATE2
- .byte 0x66, 0x0f, 0x38, 0xde, 0xe2
- # aesdec KEY, STATE3
- .byte 0x66, 0x0f, 0x38, 0xde, 0xea
- # aesdec KEY, STATE4
- .byte 0x66, 0x0f, 0x38, 0xde, 0xf2
+ AESDEC KEY STATE1
+ AESDEC KEY STATE2
+ AESDEC KEY STATE3
+ AESDEC KEY STATE4
.align 4
.L4dec128:
movaps -0x20(TKEYP), KEY
- # aesdec KEY, STATE1
- .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
- # aesdec KEY, STATE2
- .byte 0x66, 0x0f, 0x38, 0xde, 0xe2
- # aesdec KEY, STATE3
- .byte 0x66, 0x0f, 0x38, 0xde, 0xea
- # aesdec KEY, STATE4
- .byte 0x66, 0x0f, 0x38, 0xde, 0xf2
+ AESDEC KEY STATE1
+ AESDEC KEY STATE2
+ AESDEC KEY STATE3
+ AESDEC KEY STATE4
movaps -0x10(TKEYP), KEY
- # aesdec KEY, STATE1
- .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
- # aesdec KEY, STATE2
- .byte 0x66, 0x0f, 0x38, 0xde, 0xe2
- # aesdec KEY, STATE3
- .byte 0x66, 0x0f, 0x38, 0xde, 0xea
- # aesdec KEY, STATE4
- .byte 0x66, 0x0f, 0x38, 0xde, 0xf2
+ AESDEC KEY STATE1
+ AESDEC KEY STATE2
+ AESDEC KEY STATE3
+ AESDEC KEY STATE4
movaps (TKEYP), KEY
- # aesdec KEY, STATE1
- .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
- # aesdec KEY, STATE2
- .byte 0x66, 0x0f, 0x38, 0xde, 0xe2
- # aesdec KEY, STATE3
- .byte 0x66, 0x0f, 0x38, 0xde, 0xea
- # aesdec KEY, STATE4
- .byte 0x66, 0x0f, 0x38, 0xde, 0xf2
+ AESDEC KEY STATE1
+ AESDEC KEY STATE2
+ AESDEC KEY STATE3
+ AESDEC KEY STATE4
movaps 0x10(TKEYP), KEY
- # aesdec KEY, STATE1
- .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
- # aesdec KEY, STATE2
- .byte 0x66, 0x0f, 0x38, 0xde, 0xe2
- # aesdec KEY, STATE3
- .byte 0x66, 0x0f, 0x38, 0xde, 0xea
- # aesdec KEY, STATE4
- .byte 0x66, 0x0f, 0x38, 0xde, 0xf2
+ AESDEC KEY STATE1
+ AESDEC KEY STATE2
+ AESDEC KEY STATE3
+ AESDEC KEY STATE4
movaps 0x20(TKEYP), KEY
- # aesdec KEY, STATE1
- .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
- # aesdec KEY, STATE2
- .byte 0x66, 0x0f, 0x38, 0xde, 0xe2
- # aesdec KEY, STATE3
- .byte 0x66, 0x0f, 0x38, 0xde, 0xea
- # aesdec KEY, STATE4
- .byte 0x66, 0x0f, 0x38, 0xde, 0xf2
+ AESDEC KEY STATE1
+ AESDEC KEY STATE2
+ AESDEC KEY STATE3
+ AESDEC KEY STATE4
movaps 0x30(TKEYP), KEY
- # aesdec KEY, STATE1
- .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
- # aesdec KEY, STATE2
- .byte 0x66, 0x0f, 0x38, 0xde, 0xe2
- # aesdec KEY, STATE3
- .byte 0x66, 0x0f, 0x38, 0xde, 0xea
- # aesdec KEY, STATE4
- .byte 0x66, 0x0f, 0x38, 0xde, 0xf2
+ AESDEC KEY STATE1
+ AESDEC KEY STATE2
+ AESDEC KEY STATE3
+ AESDEC KEY STATE4
movaps 0x40(TKEYP), KEY
- # aesdec KEY, STATE1
- .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
- # aesdec KEY, STATE2
- .byte 0x66, 0x0f, 0x38, 0xde, 0xe2
- # aesdec KEY, STATE3
- .byte 0x66, 0x0f, 0x38, 0xde, 0xea
- # aesdec KEY, STATE4
- .byte 0x66, 0x0f, 0x38, 0xde, 0xf2
+ AESDEC KEY STATE1
+ AESDEC KEY STATE2
+ AESDEC KEY STATE3
+ AESDEC KEY STATE4
movaps 0x50(TKEYP), KEY
- # aesdec KEY, STATE1
- .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
- # aesdec KEY, STATE2
- .byte 0x66, 0x0f, 0x38, 0xde, 0xe2
- # aesdec KEY, STATE3
- .byte 0x66, 0x0f, 0x38, 0xde, 0xea
- # aesdec KEY, STATE4
- .byte 0x66, 0x0f, 0x38, 0xde, 0xf2
+ AESDEC KEY STATE1
+ AESDEC KEY STATE2
+ AESDEC KEY STATE3
+ AESDEC KEY STATE4
movaps 0x60(TKEYP), KEY
- # aesdec KEY, STATE1
- .byte 0x66, 0x0f, 0x38, 0xde, 0xc2
- # aesdec KEY, STATE2
- .byte 0x66, 0x0f, 0x38, 0xde, 0xe2
- # aesdec KEY, STATE3
- .byte 0x66, 0x0f, 0x38, 0xde, 0xea
- # aesdec KEY, STATE4
- .byte 0x66, 0x0f, 0x38, 0xde, 0xf2
+ AESDEC KEY STATE1
+ AESDEC KEY STATE2
+ AESDEC KEY STATE3
+ AESDEC KEY STATE4
movaps 0x70(TKEYP), KEY
- # aesdeclast KEY, STATE1 # last round
- .byte 0x66, 0x0f, 0x38, 0xdf, 0xc2
- # aesdeclast KEY, STATE2
- .byte 0x66, 0x0f, 0x38, 0xdf, 0xe2
- # aesdeclast KEY, STATE3
- .byte 0x66, 0x0f, 0x38, 0xdf, 0xea
- # aesdeclast KEY, STATE4
- .byte 0x66, 0x0f, 0x38, 0xdf, 0xf2
+ AESDECLAST KEY STATE1 # last round
+ AESDECLAST KEY STATE2
+ AESDECLAST KEY STATE3
+ AESDECLAST KEY STATE4
ret
/*
diff --git a/arch/x86/crypto/ghash-clmulni-intel_asm.S b/arch/x86/crypto/ghash-clmulni-intel_asm.S
new file mode 100644
index 0000000..1eb7f90
--- /dev/null
+++ b/arch/x86/crypto/ghash-clmulni-intel_asm.S
@@ -0,0 +1,157 @@
+/*
+ * Accelerated GHASH implementation with Intel PCLMULQDQ-NI
+ * instructions. This file contains accelerated part of ghash
+ * implementation. More information about PCLMULQDQ can be found at:
+ *
+ * http://software.intel.com/en-us/articles/carry-less-multiplication-and-its-usage-for-computing-the-gcm-mode/
+ *
+ * Copyright (c) 2009 Intel Corp.
+ * Author: Huang Ying <ying.huang@intel.com>
+ * Vinodh Gopal
+ * Erdinc Ozturk
+ * Deniz Karakoyunlu
+ *
+ * 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/linkage.h>
+#include <asm/inst.h>
+
+.data
+
+.align 16
+.Lbswap_mask:
+ .octa 0x000102030405060708090a0b0c0d0e0f
+.Lpoly:
+ .octa 0xc2000000000000000000000000000001
+.Ltwo_one:
+ .octa 0x00000001000000000000000000000001
+
+#define DATA %xmm0
+#define SHASH %xmm1
+#define T1 %xmm2
+#define T2 %xmm3
+#define T3 %xmm4
+#define BSWAP %xmm5
+#define IN1 %xmm6
+
+.text
+
+/*
+ * __clmul_gf128mul_ble: internal ABI
+ * input:
+ * DATA: operand1
+ * SHASH: operand2, hash_key << 1 mod poly
+ * output:
+ * DATA: operand1 * operand2 mod poly
+ * changed:
+ * T1
+ * T2
+ * T3
+ */
+__clmul_gf128mul_ble:
+ movaps DATA, T1
+ pshufd $0b01001110, DATA, T2
+ pshufd $0b01001110, SHASH, T3
+ pxor DATA, T2
+ pxor SHASH, T3
+
+ PCLMULQDQ 0x00 SHASH DATA # DATA = a0 * b0
+ PCLMULQDQ 0x11 SHASH T1 # T1 = a1 * b1
+ PCLMULQDQ 0x00 T3 T2 # T2 = (a1 + a0) * (b1 + b0)
+ pxor DATA, T2
+ pxor T1, T2 # T2 = a0 * b1 + a1 * b0
+
+ movaps T2, T3
+ pslldq $8, T3
+ psrldq $8, T2
+ pxor T3, DATA
+ pxor T2, T1 # <T1:DATA> is result of
+ # carry-less multiplication
+
+ # first phase of the reduction
+ movaps DATA, T3
+ psllq $1, T3
+ pxor DATA, T3
+ psllq $5, T3
+ pxor DATA, T3
+ psllq $57, T3
+ movaps T3, T2
+ pslldq $8, T2
+ psrldq $8, T3
+ pxor T2, DATA
+ pxor T3, T1
+
+ # second phase of the reduction
+ movaps DATA, T2
+ psrlq $5, T2
+ pxor DATA, T2
+ psrlq $1, T2
+ pxor DATA, T2
+ psrlq $1, T2
+ pxor T2, T1
+ pxor T1, DATA
+ ret
+
+/* void clmul_ghash_mul(char *dst, const be128 *shash) */
+ENTRY(clmul_ghash_mul)
+ movups (%rdi), DATA
+ movups (%rsi), SHASH
+ movaps .Lbswap_mask, BSWAP
+ PSHUFB_XMM BSWAP DATA
+ call __clmul_gf128mul_ble
+ PSHUFB_XMM BSWAP DATA
+ movups DATA, (%rdi)
+ ret
+
+/*
+ * void clmul_ghash_update(char *dst, const char *src, unsigned int srclen,
+ * const be128 *shash);
+ */
+ENTRY(clmul_ghash_update)
+ cmp $16, %rdx
+ jb .Lupdate_just_ret # check length
+ movaps .Lbswap_mask, BSWAP
+ movups (%rdi), DATA
+ movups (%rcx), SHASH
+ PSHUFB_XMM BSWAP DATA
+.align 4
+.Lupdate_loop:
+ movups (%rsi), IN1
+ PSHUFB_XMM BSWAP IN1
+ pxor IN1, DATA
+ call __clmul_gf128mul_ble
+ sub $16, %rdx
+ add $16, %rsi
+ cmp $16, %rdx
+ jge .Lupdate_loop
+ PSHUFB_XMM BSWAP DATA
+ movups DATA, (%rdi)
+.Lupdate_just_ret:
+ ret
+
+/*
+ * void clmul_ghash_setkey(be128 *shash, const u8 *key);
+ *
+ * Calculate hash_key << 1 mod poly
+ */
+ENTRY(clmul_ghash_setkey)
+ movaps .Lbswap_mask, BSWAP
+ movups (%rsi), %xmm0
+ PSHUFB_XMM BSWAP %xmm0
+ movaps %xmm0, %xmm1
+ psllq $1, %xmm0
+ psrlq $63, %xmm1
+ movaps %xmm1, %xmm2
+ pslldq $8, %xmm1
+ psrldq $8, %xmm2
+ por %xmm1, %xmm0
+ # reduction
+ pshufd $0b00100100, %xmm2, %xmm1
+ pcmpeqd .Ltwo_one, %xmm1
+ pand .Lpoly, %xmm1
+ pxor %xmm1, %xmm0
+ movups %xmm0, (%rdi)
+ ret
diff --git a/arch/x86/crypto/ghash-clmulni-intel_glue.c b/arch/x86/crypto/ghash-clmulni-intel_glue.c
new file mode 100644
index 0000000..cbcc8d8
--- /dev/null
+++ b/arch/x86/crypto/ghash-clmulni-intel_glue.c
@@ -0,0 +1,333 @@
+/*
+ * Accelerated GHASH implementation with Intel PCLMULQDQ-NI
+ * instructions. This file contains glue code.
+ *
+ * Copyright (c) 2009 Intel Corp.
+ * Author: Huang Ying <ying.huang@intel.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/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/crypto.h>
+#include <crypto/algapi.h>
+#include <crypto/cryptd.h>
+#include <crypto/gf128mul.h>
+#include <crypto/internal/hash.h>
+#include <asm/i387.h>
+
+#define GHASH_BLOCK_SIZE 16
+#define GHASH_DIGEST_SIZE 16
+
+void clmul_ghash_mul(char *dst, const be128 *shash);
+
+void clmul_ghash_update(char *dst, const char *src, unsigned int srclen,
+ const be128 *shash);
+
+void clmul_ghash_setkey(be128 *shash, const u8 *key);
+
+struct ghash_async_ctx {
+ struct cryptd_ahash *cryptd_tfm;
+};
+
+struct ghash_ctx {
+ be128 shash;
+};
+
+struct ghash_desc_ctx {
+ u8 buffer[GHASH_BLOCK_SIZE];
+ u32 bytes;
+};
+
+static int ghash_init(struct shash_desc *desc)
+{
+ struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
+
+ memset(dctx, 0, sizeof(*dctx));
+
+ return 0;
+}
+
+static int ghash_setkey(struct crypto_shash *tfm,
+ const u8 *key, unsigned int keylen)
+{
+ struct ghash_ctx *ctx = crypto_shash_ctx(tfm);
+
+ if (keylen != GHASH_BLOCK_SIZE) {
+ crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ return -EINVAL;
+ }
+
+ clmul_ghash_setkey(&ctx->shash, key);
+
+ return 0;
+}
+
+static int ghash_update(struct shash_desc *desc,
+ const u8 *src, unsigned int srclen)
+{
+ struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
+ struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);
+ u8 *dst = dctx->buffer;
+
+ kernel_fpu_begin();
+ if (dctx->bytes) {
+ int n = min(srclen, dctx->bytes);
+ u8 *pos = dst + (GHASH_BLOCK_SIZE - dctx->bytes);
+
+ dctx->bytes -= n;
+ srclen -= n;
+
+ while (n--)
+ *pos++ ^= *src++;
+
+ if (!dctx->bytes)
+ clmul_ghash_mul(dst, &ctx->shash);
+ }
+
+ clmul_ghash_update(dst, src, srclen, &ctx->shash);
+ kernel_fpu_end();
+
+ if (srclen & 0xf) {
+ src += srclen - (srclen & 0xf);
+ srclen &= 0xf;
+ dctx->bytes = GHASH_BLOCK_SIZE - srclen;
+ while (srclen--)
+ *dst++ ^= *src++;
+ }
+
+ return 0;
+}
+
+static void ghash_flush(struct ghash_ctx *ctx, struct ghash_desc_ctx *dctx)
+{
+ u8 *dst = dctx->buffer;
+
+ if (dctx->bytes) {
+ u8 *tmp = dst + (GHASH_BLOCK_SIZE - dctx->bytes);
+
+ while (dctx->bytes--)
+ *tmp++ ^= 0;
+
+ kernel_fpu_begin();
+ clmul_ghash_mul(dst, &ctx->shash);
+ kernel_fpu_end();
+ }
+
+ dctx->bytes = 0;
+}
+
+static int ghash_final(struct shash_desc *desc, u8 *dst)
+{
+ struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
+ struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);
+ u8 *buf = dctx->buffer;
+
+ ghash_flush(ctx, dctx);
+ memcpy(dst, buf, GHASH_BLOCK_SIZE);
+
+ return 0;
+}
+
+static struct shash_alg ghash_alg = {
+ .digestsize = GHASH_DIGEST_SIZE,
+ .init = ghash_init,
+ .update = ghash_update,
+ .final = ghash_final,
+ .setkey = ghash_setkey,
+ .descsize = sizeof(struct ghash_desc_ctx),
+ .base = {
+ .cra_name = "__ghash",
+ .cra_driver_name = "__ghash-pclmulqdqni",
+ .cra_priority = 0,
+ .cra_flags = CRYPTO_ALG_TYPE_SHASH,
+ .cra_blocksize = GHASH_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct ghash_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(ghash_alg.base.cra_list),
+ },
+};
+
+static int ghash_async_init(struct ahash_request *req)
+{
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm);
+ struct ahash_request *cryptd_req = ahash_request_ctx(req);
+ struct cryptd_ahash *cryptd_tfm = ctx->cryptd_tfm;
+
+ if (!irq_fpu_usable()) {
+ memcpy(cryptd_req, req, sizeof(*req));
+ ahash_request_set_tfm(cryptd_req, &cryptd_tfm->base);
+ return crypto_ahash_init(cryptd_req);
+ } else {
+ struct shash_desc *desc = cryptd_shash_desc(cryptd_req);
+ struct crypto_shash *child = cryptd_ahash_child(cryptd_tfm);
+
+ desc->tfm = child;
+ desc->flags = req->base.flags;
+ return crypto_shash_init(desc);
+ }
+}
+
+static int ghash_async_update(struct ahash_request *req)
+{
+ struct ahash_request *cryptd_req = ahash_request_ctx(req);
+
+ if (!irq_fpu_usable()) {
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm);
+ struct cryptd_ahash *cryptd_tfm = ctx->cryptd_tfm;
+
+ memcpy(cryptd_req, req, sizeof(*req));
+ ahash_request_set_tfm(cryptd_req, &cryptd_tfm->base);
+ return crypto_ahash_update(cryptd_req);
+ } else {
+ struct shash_desc *desc = cryptd_shash_desc(cryptd_req);
+ return shash_ahash_update(req, desc);
+ }
+}
+
+static int ghash_async_final(struct ahash_request *req)
+{
+ struct ahash_request *cryptd_req = ahash_request_ctx(req);
+
+ if (!irq_fpu_usable()) {
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm);
+ struct cryptd_ahash *cryptd_tfm = ctx->cryptd_tfm;
+
+ memcpy(cryptd_req, req, sizeof(*req));
+ ahash_request_set_tfm(cryptd_req, &cryptd_tfm->base);
+ return crypto_ahash_final(cryptd_req);
+ } else {
+ struct shash_desc *desc = cryptd_shash_desc(cryptd_req);
+ return crypto_shash_final(desc, req->result);
+ }
+}
+
+static int ghash_async_digest(struct ahash_request *req)
+{
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm);
+ struct ahash_request *cryptd_req = ahash_request_ctx(req);
+ struct cryptd_ahash *cryptd_tfm = ctx->cryptd_tfm;
+
+ if (!irq_fpu_usable()) {
+ memcpy(cryptd_req, req, sizeof(*req));
+ ahash_request_set_tfm(cryptd_req, &cryptd_tfm->base);
+ return crypto_ahash_digest(cryptd_req);
+ } else {
+ struct shash_desc *desc = cryptd_shash_desc(cryptd_req);
+ struct crypto_shash *child = cryptd_ahash_child(cryptd_tfm);
+
+ desc->tfm = child;
+ desc->flags = req->base.flags;
+ return shash_ahash_digest(req, desc);
+ }
+}
+
+static int ghash_async_setkey(struct crypto_ahash *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm);
+ struct crypto_ahash *child = &ctx->cryptd_tfm->base;
+ int err;
+
+ crypto_ahash_clear_flags(child, CRYPTO_TFM_REQ_MASK);
+ crypto_ahash_set_flags(child, crypto_ahash_get_flags(tfm)
+ & CRYPTO_TFM_REQ_MASK);
+ err = crypto_ahash_setkey(child, key, keylen);
+ crypto_ahash_set_flags(tfm, crypto_ahash_get_flags(child)
+ & CRYPTO_TFM_RES_MASK);
+
+ return 0;
+}
+
+static int ghash_async_init_tfm(struct crypto_tfm *tfm)
+{
+ struct cryptd_ahash *cryptd_tfm;
+ struct ghash_async_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ cryptd_tfm = cryptd_alloc_ahash("__ghash-pclmulqdqni", 0, 0);
+ if (IS_ERR(cryptd_tfm))
+ return PTR_ERR(cryptd_tfm);
+ ctx->cryptd_tfm = cryptd_tfm;
+ crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
+ sizeof(struct ahash_request) +
+ crypto_ahash_reqsize(&cryptd_tfm->base));
+
+ return 0;
+}
+
+static void ghash_async_exit_tfm(struct crypto_tfm *tfm)
+{
+ struct ghash_async_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ cryptd_free_ahash(ctx->cryptd_tfm);
+}
+
+static struct ahash_alg ghash_async_alg = {
+ .init = ghash_async_init,
+ .update = ghash_async_update,
+ .final = ghash_async_final,
+ .setkey = ghash_async_setkey,
+ .digest = ghash_async_digest,
+ .halg = {
+ .digestsize = GHASH_DIGEST_SIZE,
+ .base = {
+ .cra_name = "ghash",
+ .cra_driver_name = "ghash-clmulni",
+ .cra_priority = 400,
+ .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = GHASH_BLOCK_SIZE,
+ .cra_type = &crypto_ahash_type,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(ghash_async_alg.halg.base.cra_list),
+ .cra_init = ghash_async_init_tfm,
+ .cra_exit = ghash_async_exit_tfm,
+ },
+ },
+};
+
+static int __init ghash_pclmulqdqni_mod_init(void)
+{
+ int err;
+
+ if (!cpu_has_pclmulqdq) {
+ printk(KERN_INFO "Intel PCLMULQDQ-NI instructions are not"
+ " detected.\n");
+ return -ENODEV;
+ }
+
+ err = crypto_register_shash(&ghash_alg);
+ if (err)
+ goto err_out;
+ err = crypto_register_ahash(&ghash_async_alg);
+ if (err)
+ goto err_shash;
+
+ return 0;
+
+err_shash:
+ crypto_unregister_shash(&ghash_alg);
+err_out:
+ return err;
+}
+
+static void __exit ghash_pclmulqdqni_mod_exit(void)
+{
+ crypto_unregister_ahash(&ghash_async_alg);
+ crypto_unregister_shash(&ghash_alg);
+}
+
+module_init(ghash_pclmulqdqni_mod_init);
+module_exit(ghash_pclmulqdqni_mod_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("GHASH Message Digest Algorithm, "
+ "acclerated by PCLMULQDQ-NI");
+MODULE_ALIAS("ghash");
diff --git a/arch/x86/include/asm/acpi.h b/arch/x86/include/asm/acpi.h
index 4518dc5..60d2b2d 100644
--- a/arch/x86/include/asm/acpi.h
+++ b/arch/x86/include/asm/acpi.h
@@ -118,7 +118,7 @@ extern void acpi_restore_state_mem(void);
extern unsigned long acpi_wakeup_address;
/* early initialization routine */
-extern void acpi_reserve_bootmem(void);
+extern void acpi_reserve_wakeup_memory(void);
/*
* Check if the CPU can handle C2 and deeper
@@ -158,6 +158,7 @@ struct bootnode;
#ifdef CONFIG_ACPI_NUMA
extern int acpi_numa;
+extern int acpi_get_nodes(struct bootnode *physnodes);
extern int acpi_scan_nodes(unsigned long start, unsigned long end);
#define NR_NODE_MEMBLKS (MAX_NUMNODES*2)
extern void acpi_fake_nodes(const struct bootnode *fake_nodes,
diff --git a/arch/x86/include/asm/cache.h b/arch/x86/include/asm/cache.h
index 549860d..2f9047c 100644
--- a/arch/x86/include/asm/cache.h
+++ b/arch/x86/include/asm/cache.h
@@ -9,12 +9,13 @@
#define __read_mostly __attribute__((__section__(".data.read_mostly")))
+#define INTERNODE_CACHE_SHIFT CONFIG_X86_INTERNODE_CACHE_SHIFT
+#define INTERNODE_CACHE_BYTES (1 << INTERNODE_CACHE_SHIFT)
+
#ifdef CONFIG_X86_VSMP
-/* vSMP Internode cacheline shift */
-#define INTERNODE_CACHE_SHIFT (12)
#ifdef CONFIG_SMP
#define __cacheline_aligned_in_smp \
- __attribute__((__aligned__(1 << (INTERNODE_CACHE_SHIFT)))) \
+ __attribute__((__aligned__(INTERNODE_CACHE_BYTES))) \
__page_aligned_data
#endif
#endif
diff --git a/arch/x86/include/asm/cacheflush.h b/arch/x86/include/asm/cacheflush.h
index 9076add..634c40a 100644
--- a/arch/x86/include/asm/cacheflush.h
+++ b/arch/x86/include/asm/cacheflush.h
@@ -177,6 +177,7 @@ void clflush_cache_range(void *addr, unsigned int size);
#ifdef CONFIG_DEBUG_RODATA
void mark_rodata_ro(void);
extern const int rodata_test_data;
+extern int kernel_set_to_readonly;
void set_kernel_text_rw(void);
void set_kernel_text_ro(void);
#else
diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
index 9cfc88b..613700f 100644
--- a/arch/x86/include/asm/cpufeature.h
+++ b/arch/x86/include/asm/cpufeature.h
@@ -248,6 +248,7 @@ extern const char * const x86_power_flags[32];
#define cpu_has_x2apic boot_cpu_has(X86_FEATURE_X2APIC)
#define cpu_has_xsave boot_cpu_has(X86_FEATURE_XSAVE)
#define cpu_has_hypervisor boot_cpu_has(X86_FEATURE_HYPERVISOR)
+#define cpu_has_pclmulqdq boot_cpu_has(X86_FEATURE_PCLMULQDQ)
#if defined(CONFIG_X86_INVLPG) || defined(CONFIG_X86_64)
# define cpu_has_invlpg 1
diff --git a/arch/x86/include/asm/desc_defs.h b/arch/x86/include/asm/desc_defs.h
index 9d66848..278441f 100644
--- a/arch/x86/include/asm/desc_defs.h
+++ b/arch/x86/include/asm/desc_defs.h
@@ -12,9 +12,9 @@
#include <linux/types.h>
/*
- * FIXME: Acessing the desc_struct through its fields is more elegant,
+ * FIXME: Accessing the desc_struct through its fields is more elegant,
* and should be the one valid thing to do. However, a lot of open code
- * still touches the a and b acessors, and doing this allow us to do it
+ * still touches the a and b accessors, and doing this allow us to do it
* incrementally. We keep the signature as a struct, rather than an union,
* so we can get rid of it transparently in the future -- glommer
*/
diff --git a/arch/x86/include/asm/e820.h b/arch/x86/include/asm/e820.h
index 40b4e61..761249e 100644
--- a/arch/x86/include/asm/e820.h
+++ b/arch/x86/include/asm/e820.h
@@ -61,6 +61,12 @@ struct e820map {
struct e820entry map[E820_X_MAX];
};
+#define ISA_START_ADDRESS 0xa0000
+#define ISA_END_ADDRESS 0x100000
+
+#define BIOS_BEGIN 0x000a0000
+#define BIOS_END 0x00100000
+
#ifdef __KERNEL__
/* see comment in arch/x86/kernel/e820.c */
extern struct e820map e820;
@@ -126,15 +132,18 @@ extern void e820_reserve_resources(void);
extern void e820_reserve_resources_late(void);
extern void setup_memory_map(void);
extern char *default_machine_specific_memory_setup(void);
-#endif /* __KERNEL__ */
-#endif /* __ASSEMBLY__ */
-#define ISA_START_ADDRESS 0xa0000
-#define ISA_END_ADDRESS 0x100000
-#define is_ISA_range(s, e) ((s) >= ISA_START_ADDRESS && (e) < ISA_END_ADDRESS)
+/*
+ * Returns true iff the specified range [s,e) is completely contained inside
+ * the ISA region.
+ */
+static inline bool is_ISA_range(u64 s, u64 e)
+{
+ return s >= ISA_START_ADDRESS && e <= ISA_END_ADDRESS;
+}
-#define BIOS_BEGIN 0x000a0000
-#define BIOS_END 0x00100000
+#endif /* __KERNEL__ */
+#endif /* __ASSEMBLY__ */
#ifdef __KERNEL__
#include <linux/ioport.h>
diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h
index 456a304..8a024ba 100644
--- a/arch/x86/include/asm/elf.h
+++ b/arch/x86/include/asm/elf.h
@@ -157,19 +157,6 @@ do { \
#define compat_elf_check_arch(x) elf_check_arch_ia32(x)
-static inline void start_ia32_thread(struct pt_regs *regs, u32 ip, u32 sp)
-{
- loadsegment(fs, 0);
- loadsegment(ds, __USER32_DS);
- loadsegment(es, __USER32_DS);
- load_gs_index(0);
- regs->ip = ip;
- regs->sp = sp;
- regs->flags = X86_EFLAGS_IF;
- regs->cs = __USER32_CS;
- regs->ss = __USER32_DS;
-}
-
static inline void elf_common_init(struct thread_struct *t,
struct pt_regs *regs, const u16 ds)
{
@@ -191,11 +178,8 @@ do { \
#define COMPAT_ELF_PLAT_INIT(regs, load_addr) \
elf_common_init(&current->thread, regs, __USER_DS)
-#define compat_start_thread(regs, ip, sp) \
-do { \
- start_ia32_thread(regs, ip, sp); \
- set_fs(USER_DS); \
-} while (0)
+void start_thread_ia32(struct pt_regs *regs, u32 new_ip, u32 new_sp);
+#define compat_start_thread start_thread_ia32
#define COMPAT_SET_PERSONALITY(ex) \
do { \
diff --git a/arch/x86/include/asm/entry_arch.h b/arch/x86/include/asm/entry_arch.h
index f5693c8..8e8ec66 100644
--- a/arch/x86/include/asm/entry_arch.h
+++ b/arch/x86/include/asm/entry_arch.h
@@ -34,7 +34,7 @@ BUILD_INTERRUPT3(invalidate_interrupt7,INVALIDATE_TLB_VECTOR_START+7,
smp_invalidate_interrupt)
#endif
-BUILD_INTERRUPT(generic_interrupt, GENERIC_INTERRUPT_VECTOR)
+BUILD_INTERRUPT(x86_platform_ipi, X86_PLATFORM_IPI_VECTOR)
/*
* every pentium local APIC has two 'local interrupts', with a
diff --git a/arch/x86/include/asm/hardirq.h b/arch/x86/include/asm/hardirq.h
index 108eb6f..0f85764 100644
--- a/arch/x86/include/asm/hardirq.h
+++ b/arch/x86/include/asm/hardirq.h
@@ -12,7 +12,7 @@ typedef struct {
unsigned int apic_timer_irqs; /* arch dependent */
unsigned int irq_spurious_count;
#endif
- unsigned int generic_irqs; /* arch dependent */
+ unsigned int x86_platform_ipis; /* arch dependent */
unsigned int apic_perf_irqs;
unsigned int apic_pending_irqs;
#ifdef CONFIG_SMP
diff --git a/arch/x86/include/asm/hpet.h b/arch/x86/include/asm/hpet.h
index 1c22cb0..5d89fd2 100644
--- a/arch/x86/include/asm/hpet.h
+++ b/arch/x86/include/asm/hpet.h
@@ -65,11 +65,12 @@
/* hpet memory map physical address */
extern unsigned long hpet_address;
extern unsigned long force_hpet_address;
+extern u8 hpet_blockid;
extern int hpet_force_user;
extern int is_hpet_enabled(void);
extern int hpet_enable(void);
extern void hpet_disable(void);
-extern unsigned long hpet_readl(unsigned long a);
+extern unsigned int hpet_readl(unsigned int a);
extern void force_hpet_resume(void);
extern void hpet_msi_unmask(unsigned int irq);
@@ -78,9 +79,9 @@ extern void hpet_msi_write(unsigned int irq, struct msi_msg *msg);
extern void hpet_msi_read(unsigned int irq, struct msi_msg *msg);
#ifdef CONFIG_PCI_MSI
-extern int arch_setup_hpet_msi(unsigned int irq);
+extern int arch_setup_hpet_msi(unsigned int irq, unsigned int id);
#else
-static inline int arch_setup_hpet_msi(unsigned int irq)
+static inline int arch_setup_hpet_msi(unsigned int irq, unsigned int id)
{
return -EINVAL;
}
diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h
index 6e12426..08c48a8 100644
--- a/arch/x86/include/asm/hw_irq.h
+++ b/arch/x86/include/asm/hw_irq.h
@@ -27,7 +27,7 @@
/* Interrupt handlers registered during init_IRQ */
extern void apic_timer_interrupt(void);
-extern void generic_interrupt(void);
+extern void x86_platform_ipi(void);
extern void error_interrupt(void);
extern void perf_pending_interrupt(void);
@@ -119,7 +119,7 @@ extern void eisa_set_level_irq(unsigned int irq);
/* SMP */
extern void smp_apic_timer_interrupt(struct pt_regs *);
extern void smp_spurious_interrupt(struct pt_regs *);
-extern void smp_generic_interrupt(struct pt_regs *);
+extern void smp_x86_platform_ipi(struct pt_regs *);
extern void smp_error_interrupt(struct pt_regs *);
#ifdef CONFIG_X86_IO_APIC
extern asmlinkage void smp_irq_move_cleanup_interrupt(void);
diff --git a/arch/x86/include/asm/i387.h b/arch/x86/include/asm/i387.h
index 0b20bbb..ebfb8a9 100644
--- a/arch/x86/include/asm/i387.h
+++ b/arch/x86/include/asm/i387.h
@@ -10,6 +10,8 @@
#ifndef _ASM_X86_I387_H
#define _ASM_X86_I387_H
+#ifndef __ASSEMBLY__
+
#include <linux/sched.h>
#include <linux/kernel_stat.h>
#include <linux/regset.h>
@@ -411,4 +413,9 @@ static inline unsigned short get_fpu_mxcsr(struct task_struct *tsk)
}
}
+#endif /* __ASSEMBLY__ */
+
+#define PSHUFB_XMM5_XMM0 .byte 0x66, 0x0f, 0x38, 0x00, 0xc5
+#define PSHUFB_XMM5_XMM6 .byte 0x66, 0x0f, 0x38, 0x00, 0xf5
+
#endif /* _ASM_X86_I387_H */
diff --git a/arch/x86/include/asm/inst.h b/arch/x86/include/asm/inst.h
new file mode 100644
index 0000000..14cf526
--- /dev/null
+++ b/arch/x86/include/asm/inst.h
@@ -0,0 +1,150 @@
+/*
+ * Generate .byte code for some instructions not supported by old
+ * binutils.
+ */
+#ifndef X86_ASM_INST_H
+#define X86_ASM_INST_H
+
+#ifdef __ASSEMBLY__
+
+ .macro XMM_NUM opd xmm
+ .ifc \xmm,%xmm0
+ \opd = 0
+ .endif
+ .ifc \xmm,%xmm1
+ \opd = 1
+ .endif
+ .ifc \xmm,%xmm2
+ \opd = 2
+ .endif
+ .ifc \xmm,%xmm3
+ \opd = 3
+ .endif
+ .ifc \xmm,%xmm4
+ \opd = 4
+ .endif
+ .ifc \xmm,%xmm5
+ \opd = 5
+ .endif
+ .ifc \xmm,%xmm6
+ \opd = 6
+ .endif
+ .ifc \xmm,%xmm7
+ \opd = 7
+ .endif
+ .ifc \xmm,%xmm8
+ \opd = 8
+ .endif
+ .ifc \xmm,%xmm9
+ \opd = 9
+ .endif
+ .ifc \xmm,%xmm10
+ \opd = 10
+ .endif
+ .ifc \xmm,%xmm11
+ \opd = 11
+ .endif
+ .ifc \xmm,%xmm12
+ \opd = 12
+ .endif
+ .ifc \xmm,%xmm13
+ \opd = 13
+ .endif
+ .ifc \xmm,%xmm14
+ \opd = 14
+ .endif
+ .ifc \xmm,%xmm15
+ \opd = 15
+ .endif
+ .endm
+
+ .macro PFX_OPD_SIZE
+ .byte 0x66
+ .endm
+
+ .macro PFX_REX opd1 opd2
+ .if (\opd1 | \opd2) & 8
+ .byte 0x40 | ((\opd1 & 8) >> 3) | ((\opd2 & 8) >> 1)
+ .endif
+ .endm
+
+ .macro MODRM mod opd1 opd2
+ .byte \mod | (\opd1 & 7) | ((\opd2 & 7) << 3)
+ .endm
+
+ .macro PSHUFB_XMM xmm1 xmm2
+ XMM_NUM pshufb_opd1 \xmm1
+ XMM_NUM pshufb_opd2 \xmm2
+ PFX_OPD_SIZE
+ PFX_REX pshufb_opd1 pshufb_opd2
+ .byte 0x0f, 0x38, 0x00
+ MODRM 0xc0 pshufb_opd1 pshufb_opd2
+ .endm
+
+ .macro PCLMULQDQ imm8 xmm1 xmm2
+ XMM_NUM clmul_opd1 \xmm1
+ XMM_NUM clmul_opd2 \xmm2
+ PFX_OPD_SIZE
+ PFX_REX clmul_opd1 clmul_opd2
+ .byte 0x0f, 0x3a, 0x44
+ MODRM 0xc0 clmul_opd1 clmul_opd2
+ .byte \imm8
+ .endm
+
+ .macro AESKEYGENASSIST rcon xmm1 xmm2
+ XMM_NUM aeskeygen_opd1 \xmm1
+ XMM_NUM aeskeygen_opd2 \xmm2
+ PFX_OPD_SIZE
+ PFX_REX aeskeygen_opd1 aeskeygen_opd2
+ .byte 0x0f, 0x3a, 0xdf
+ MODRM 0xc0 aeskeygen_opd1 aeskeygen_opd2
+ .byte \rcon
+ .endm
+
+ .macro AESIMC xmm1 xmm2
+ XMM_NUM aesimc_opd1 \xmm1
+ XMM_NUM aesimc_opd2 \xmm2
+ PFX_OPD_SIZE
+ PFX_REX aesimc_opd1 aesimc_opd2
+ .byte 0x0f, 0x38, 0xdb
+ MODRM 0xc0 aesimc_opd1 aesimc_opd2
+ .endm
+
+ .macro AESENC xmm1 xmm2
+ XMM_NUM aesenc_opd1 \xmm1
+ XMM_NUM aesenc_opd2 \xmm2
+ PFX_OPD_SIZE
+ PFX_REX aesenc_opd1 aesenc_opd2
+ .byte 0x0f, 0x38, 0xdc
+ MODRM 0xc0 aesenc_opd1 aesenc_opd2
+ .endm
+
+ .macro AESENCLAST xmm1 xmm2
+ XMM_NUM aesenclast_opd1 \xmm1
+ XMM_NUM aesenclast_opd2 \xmm2
+ PFX_OPD_SIZE
+ PFX_REX aesenclast_opd1 aesenclast_opd2
+ .byte 0x0f, 0x38, 0xdd
+ MODRM 0xc0 aesenclast_opd1 aesenclast_opd2
+ .endm
+
+ .macro AESDEC xmm1 xmm2
+ XMM_NUM aesdec_opd1 \xmm1
+ XMM_NUM aesdec_opd2 \xmm2
+ PFX_OPD_SIZE
+ PFX_REX aesdec_opd1 aesdec_opd2
+ .byte 0x0f, 0x38, 0xde
+ MODRM 0xc0 aesdec_opd1 aesdec_opd2
+ .endm
+
+ .macro AESDECLAST xmm1 xmm2
+ XMM_NUM aesdeclast_opd1 \xmm1
+ XMM_NUM aesdeclast_opd2 \xmm2
+ PFX_OPD_SIZE
+ PFX_REX aesdeclast_opd1 aesdeclast_opd2
+ .byte 0x0f, 0x38, 0xdf
+ MODRM 0xc0 aesdeclast_opd1 aesdeclast_opd2
+ .endm
+#endif
+
+#endif
diff --git a/arch/x86/include/asm/irq.h b/arch/x86/include/asm/irq.h
index ffd700f..5458380 100644
--- a/arch/x86/include/asm/irq.h
+++ b/arch/x86/include/asm/irq.h
@@ -37,7 +37,7 @@ extern void fixup_irqs(void);
extern void irq_force_complete_move(int);
#endif
-extern void (*generic_interrupt_extension)(void);
+extern void (*x86_platform_ipi_callback)(void);
extern void native_init_IRQ(void);
extern bool handle_irq(unsigned irq, struct pt_regs *regs);
diff --git a/arch/x86/include/asm/irq_vectors.h b/arch/x86/include/asm/irq_vectors.h
index 5b21f0e..6a635bd 100644
--- a/arch/x86/include/asm/irq_vectors.h
+++ b/arch/x86/include/asm/irq_vectors.h
@@ -106,7 +106,7 @@
/*
* Generic system vector for platform specific use
*/
-#define GENERIC_INTERRUPT_VECTOR 0xed
+#define X86_PLATFORM_IPI_VECTOR 0xed
/*
* Performance monitoring pending work vector:
diff --git a/arch/x86/include/asm/k8.h b/arch/x86/include/asm/k8.h
index c2d1f3b..f70e600 100644
--- a/arch/x86/include/asm/k8.h
+++ b/arch/x86/include/asm/k8.h
@@ -4,13 +4,16 @@
#include <linux/pci.h>
extern struct pci_device_id k8_nb_ids[];
+struct bootnode;
extern int early_is_k8_nb(u32 value);
extern struct pci_dev **k8_northbridges;
extern int num_k8_northbridges;
extern int cache_k8_northbridges(void);
extern void k8_flush_garts(void);
-extern int k8_scan_nodes(unsigned long start, unsigned long end);
+extern int k8_get_nodes(struct bootnode *nodes);
+extern int k8_numa_init(unsigned long start_pfn, unsigned long end_pfn);
+extern int k8_scan_nodes(void);
#ifdef CONFIG_K8_NB
static inline struct pci_dev *node_to_k8_nb_misc(int node)
diff --git a/arch/x86/include/asm/microcode.h b/arch/x86/include/asm/microcode.h
index ef51b50..c24ca9a 100644
--- a/arch/x86/include/asm/microcode.h
+++ b/arch/x86/include/asm/microcode.h
@@ -12,6 +12,8 @@ struct device;
enum ucode_state { UCODE_ERROR, UCODE_OK, UCODE_NFOUND };
struct microcode_ops {
+ void (*init)(struct device *device);
+ void (*fini)(void);
enum ucode_state (*request_microcode_user) (int cpu,
const void __user *buf, size_t size);
diff --git a/arch/x86/include/asm/mmzone_32.h b/arch/x86/include/asm/mmzone_32.h
index ede6998..91df7c5 100644
--- a/arch/x86/include/asm/mmzone_32.h
+++ b/arch/x86/include/asm/mmzone_32.h
@@ -47,7 +47,7 @@ static inline void resume_map_numa_kva(pgd_t *pgd) {}
/*
* generic node memory support, the following assumptions apply:
*
- * 1) memory comes in 64Mb contigious chunks which are either present or not
+ * 1) memory comes in 64Mb contiguous chunks which are either present or not
* 2) we will not have more than 64Gb in total
*
* for now assume that 64Gb is max amount of RAM for whole system
diff --git a/arch/x86/include/asm/mpspec.h b/arch/x86/include/asm/mpspec.h
index 61d90b1..d8bf23a 100644
--- a/arch/x86/include/asm/mpspec.h
+++ b/arch/x86/include/asm/mpspec.h
@@ -71,12 +71,7 @@ static inline void early_get_smp_config(void)
static inline void find_smp_config(void)
{
- x86_init.mpparse.find_smp_config(1);
-}
-
-static inline void early_find_smp_config(void)
-{
- x86_init.mpparse.find_smp_config(0);
+ x86_init.mpparse.find_smp_config();
}
#ifdef CONFIG_X86_MPPARSE
@@ -89,7 +84,7 @@ extern void default_mpc_oem_bus_info(struct mpc_bus *m, char *str);
# else
# define default_mpc_oem_bus_info NULL
# endif
-extern void default_find_smp_config(unsigned int reserve);
+extern void default_find_smp_config(void);
extern void default_get_smp_config(unsigned int early);
#else
static inline void early_reserve_e820_mpc_new(void) { }
@@ -97,7 +92,7 @@ static inline void early_reserve_e820_mpc_new(void) { }
#define default_mpc_apic_id NULL
#define default_smp_read_mpc_oem NULL
#define default_mpc_oem_bus_info NULL
-#define default_find_smp_config x86_init_uint_noop
+#define default_find_smp_config x86_init_noop
#define default_get_smp_config x86_init_uint_noop
#endif
diff --git a/arch/x86/include/asm/page_types.h b/arch/x86/include/asm/page_types.h
index 6473f5c..642fe34 100644
--- a/arch/x86/include/asm/page_types.h
+++ b/arch/x86/include/asm/page_types.h
@@ -49,7 +49,8 @@ extern unsigned long max_pfn_mapped;
extern unsigned long init_memory_mapping(unsigned long start,
unsigned long end);
-extern void initmem_init(unsigned long start_pfn, unsigned long end_pfn);
+extern void initmem_init(unsigned long start_pfn, unsigned long end_pfn,
+ int acpi, int k8);
extern void free_initmem(void);
#endif /* !__ASSEMBLY__ */
diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h
index af6fd36..a34c785 100644
--- a/arch/x86/include/asm/pgtable.h
+++ b/arch/x86/include/asm/pgtable.h
@@ -16,6 +16,8 @@
#ifndef __ASSEMBLY__
+#include <asm/x86_init.h>
+
/*
* ZERO_PAGE is a global shared page that is always zero: used
* for zero-mapped memory areas etc..
@@ -270,9 +272,9 @@ static inline int is_new_memtype_allowed(u64 paddr, unsigned long size,
unsigned long new_flags)
{
/*
- * PAT type is always WB for ISA. So no need to check.
+ * PAT type is always WB for untracked ranges, so no need to check.
*/
- if (is_ISA_range(paddr, paddr + size - 1))
+ if (x86_platform.is_untracked_pat_range(paddr, paddr + size))
return 1;
/*
diff --git a/arch/x86/include/asm/proto.h b/arch/x86/include/asm/proto.h
index 621f56d..4009f65 100644
--- a/arch/x86/include/asm/proto.h
+++ b/arch/x86/include/asm/proto.h
@@ -5,18 +5,19 @@
/* misc architecture specific prototypes */
-extern void early_idt_handler(void);
+void early_idt_handler(void);
-extern void system_call(void);
-extern void syscall_init(void);
+void system_call(void);
+void syscall_init(void);
-extern void ia32_syscall(void);
-extern void ia32_cstar_target(void);
-extern void ia32_sysenter_target(void);
+void ia32_syscall(void);
+void ia32_cstar_target(void);
+void ia32_sysenter_target(void);
-extern void syscall32_cpu_init(void);
+void syscall32_cpu_init(void);
-extern void check_efer(void);
+void x86_configure_nx(void);
+void x86_report_nx(void);
extern int reboot_force;
diff --git a/arch/x86/include/asm/sections.h b/arch/x86/include/asm/sections.h
index 1b7ee5d..0a52424 100644
--- a/arch/x86/include/asm/sections.h
+++ b/arch/x86/include/asm/sections.h
@@ -2,7 +2,13 @@
#define _ASM_X86_SECTIONS_H
#include <asm-generic/sections.h>
+#include <asm/uaccess.h>
extern char __brk_base[], __brk_limit[];
+extern struct exception_table_entry __stop___ex_table[];
+
+#if defined(CONFIG_X86_64) && defined(CONFIG_DEBUG_RODATA)
+extern char __end_rodata_hpage_align[];
+#endif
#endif /* _ASM_X86_SECTIONS_H */
diff --git a/arch/x86/include/asm/sigcontext.h b/arch/x86/include/asm/sigcontext.h
index 72e5a44..04459d2 100644
--- a/arch/x86/include/asm/sigcontext.h
+++ b/arch/x86/include/asm/sigcontext.h
@@ -124,7 +124,7 @@ struct sigcontext {
* fpstate is really (struct _fpstate *) or (struct _xstate *)
* depending on the FP_XSTATE_MAGIC1 encoded in the SW reserved
* bytes of (struct _fpstate) and FP_XSTATE_MAGIC2 present at the end
- * of extended memory layout. See comments at the defintion of
+ * of extended memory layout. See comments at the definition of
* (struct _fpx_sw_bytes)
*/
void __user *fpstate; /* zero when no FPU/extended context */
@@ -219,7 +219,7 @@ struct sigcontext {
* fpstate is really (struct _fpstate *) or (struct _xstate *)
* depending on the FP_XSTATE_MAGIC1 encoded in the SW reserved
* bytes of (struct _fpstate) and FP_XSTATE_MAGIC2 present at the end
- * of extended memory layout. See comments at the defintion of
+ * of extended memory layout. See comments at the definition of
* (struct _fpx_sw_bytes)
*/
void __user *fpstate; /* zero when no FPU/extended context */
diff --git a/arch/x86/include/asm/uv/uv_bau.h b/arch/x86/include/asm/uv/uv_bau.h
index 80e2984..b414d2b 100644
--- a/arch/x86/include/asm/uv/uv_bau.h
+++ b/arch/x86/include/asm/uv/uv_bau.h
@@ -55,7 +55,7 @@
#define DESC_STATUS_SOURCE_TIMEOUT 3
/*
- * source side threshholds at which message retries print a warning
+ * source side thresholds at which message retries print a warning
*/
#define SOURCE_TIMEOUT_LIMIT 20
#define DESTINATION_TIMEOUT_LIMIT 20
diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h
index d8e7145..ea0e8ea 100644
--- a/arch/x86/include/asm/x86_init.h
+++ b/arch/x86/include/asm/x86_init.h
@@ -26,7 +26,7 @@ struct x86_init_mpparse {
void (*smp_read_mpc_oem)(struct mpc_table *mpc);
void (*mpc_oem_pci_bus)(struct mpc_bus *m);
void (*mpc_oem_bus_info)(struct mpc_bus *m, char *name);
- void (*find_smp_config)(unsigned int reserve);
+ void (*find_smp_config)(void);
void (*get_smp_config)(unsigned int early);
};
@@ -125,12 +125,14 @@ struct x86_cpuinit_ops {
* @calibrate_tsc: calibrate TSC
* @get_wallclock: get time from HW clock like RTC etc.
* @set_wallclock: set time back to HW clock
+ * @is_untracked_pat_range exclude from PAT logic
*/
struct x86_platform_ops {
unsigned long (*calibrate_tsc)(void);
unsigned long (*get_wallclock)(void);
int (*set_wallclock)(unsigned long nowtime);
void (*iommu_shutdown)(void);
+ bool (*is_untracked_pat_range)(u64 start, u64 end);
};
extern struct x86_init_ops x86_init;
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index 67e929b..fb1035c 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -624,6 +624,7 @@ static int __init acpi_parse_hpet(struct acpi_table_header *table)
}
hpet_address = hpet_tbl->address.address;
+ hpet_blockid = hpet_tbl->sequence;
/*
* Some broken BIOSes advertise HPET at 0x0. We really do not
@@ -1122,7 +1123,7 @@ static int __init acpi_parse_madt_ioapic_entries(void)
if (!acpi_sci_override_gsi)
acpi_sci_ioapic_setup(acpi_gbl_FADT.sci_interrupt, 0, 0);
- /* Fill in identity legacy mapings where no override */
+ /* Fill in identity legacy mappings where no override */
mp_config_acpi_legacy_irqs();
count =
diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c
index ca93638..82e5086 100644
--- a/arch/x86/kernel/acpi/sleep.c
+++ b/arch/x86/kernel/acpi/sleep.c
@@ -78,12 +78,9 @@ int acpi_save_state_mem(void)
#ifndef CONFIG_64BIT
store_gdt((struct desc_ptr *)&header->pmode_gdt);
- header->pmode_efer_low = nx_enabled;
- if (header->pmode_efer_low & 1) {
- /* This is strange, why not save efer, always? */
- rdmsr(MSR_EFER, header->pmode_efer_low,
- header->pmode_efer_high);
- }
+ if (rdmsr_safe(MSR_EFER, &header->pmode_efer_low,
+ &header->pmode_efer_high))
+ header->pmode_efer_low = header->pmode_efer_high = 0;
#endif /* !CONFIG_64BIT */
header->pmode_cr0 = read_cr0();
@@ -119,29 +116,32 @@ void acpi_restore_state_mem(void)
/**
- * acpi_reserve_bootmem - do _very_ early ACPI initialisation
+ * acpi_reserve_wakeup_memory - do _very_ early ACPI initialisation
*
* We allocate a page from the first 1MB of memory for the wakeup
* routine for when we come back from a sleep state. The
* runtime allocator allows specification of <16MB pages, but not
* <1MB pages.
*/
-void __init acpi_reserve_bootmem(void)
+void __init acpi_reserve_wakeup_memory(void)
{
+ unsigned long mem;
+
if ((&wakeup_code_end - &wakeup_code_start) > WAKEUP_SIZE) {
printk(KERN_ERR
"ACPI: Wakeup code way too big, S3 disabled.\n");
return;
}
- acpi_realmode = (unsigned long)alloc_bootmem_low(WAKEUP_SIZE);
+ mem = find_e820_area(0, 1<<20, WAKEUP_SIZE, PAGE_SIZE);
- if (!acpi_realmode) {
+ if (mem == -1L) {
printk(KERN_ERR "ACPI: Cannot allocate lowmem, S3 disabled.\n");
return;
}
-
- acpi_wakeup_address = virt_to_phys((void *)acpi_realmode);
+ acpi_realmode = (unsigned long) phys_to_virt(mem);
+ acpi_wakeup_address = mem;
+ reserve_early(mem, mem + WAKEUP_SIZE, "ACPI WAKEUP");
}
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c
index 32fb091..1c0fb4d 100644
--- a/arch/x86/kernel/amd_iommu.c
+++ b/arch/x86/kernel/amd_iommu.c
@@ -1783,7 +1783,7 @@ retry:
goto out;
/*
- * aperture was sucessfully enlarged by 128 MB, try
+ * aperture was successfully enlarged by 128 MB, try
* allocation again
*/
goto retry;
@@ -2490,7 +2490,7 @@ int __init amd_iommu_init_passthrough(void)
struct pci_dev *dev = NULL;
u16 devid;
- /* allocate passthroug domain */
+ /* allocate passthrough domain */
pt_domain = protection_domain_alloc();
if (!pt_domain)
return -ENOMEM;
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index ad8c75b..efb2b9c 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -647,7 +647,7 @@ static int __init calibrate_APIC_clock(void)
calibration_result = (delta * APIC_DIVISOR) / LAPIC_CAL_LOOPS;
apic_printk(APIC_VERBOSE, "..... delta %ld\n", delta);
- apic_printk(APIC_VERBOSE, "..... mult: %ld\n", lapic_clockevent.mult);
+ apic_printk(APIC_VERBOSE, "..... mult: %u\n", lapic_clockevent.mult);
apic_printk(APIC_VERBOSE, "..... calibration result: %u\n",
calibration_result);
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index c0b4468..d5d498f 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -3267,7 +3267,8 @@ void destroy_irq(unsigned int irq)
* MSI message composition
*/
#ifdef CONFIG_PCI_MSI
-static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
+static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq,
+ struct msi_msg *msg, u8 hpet_id)
{
struct irq_cfg *cfg;
int err;
@@ -3301,7 +3302,10 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_ms
irte.dest_id = IRTE_DEST(dest);
/* Set source-id of interrupt request */
- set_msi_sid(&irte, pdev);
+ if (pdev)
+ set_msi_sid(&irte, pdev);
+ else
+ set_hpet_sid(&irte, hpet_id);
modify_irte(irq, &irte);
@@ -3466,7 +3470,7 @@ static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int irq)
int ret;
struct msi_msg msg;
- ret = msi_compose_msg(dev, irq, &msg);
+ ret = msi_compose_msg(dev, irq, &msg, -1);
if (ret < 0)
return ret;
@@ -3599,7 +3603,7 @@ int arch_setup_dmar_msi(unsigned int irq)
int ret;
struct msi_msg msg;
- ret = msi_compose_msg(NULL, irq, &msg);
+ ret = msi_compose_msg(NULL, irq, &msg, -1);
if (ret < 0)
return ret;
dmar_msi_write(irq, &msg);
@@ -3639,6 +3643,19 @@ static int hpet_msi_set_affinity(unsigned int irq, const struct cpumask *mask)
#endif /* CONFIG_SMP */
+static struct irq_chip ir_hpet_msi_type = {
+ .name = "IR-HPET_MSI",
+ .unmask = hpet_msi_unmask,
+ .mask = hpet_msi_mask,
+#ifdef CONFIG_INTR_REMAP
+ .ack = ir_ack_apic_edge,
+#ifdef CONFIG_SMP
+ .set_affinity = ir_set_msi_irq_affinity,
+#endif
+#endif
+ .retrigger = ioapic_retrigger_irq,
+};
+
static struct irq_chip hpet_msi_type = {
.name = "HPET_MSI",
.unmask = hpet_msi_unmask,
@@ -3650,20 +3667,36 @@ static struct irq_chip hpet_msi_type = {
.retrigger = ioapic_retrigger_irq,
};
-int arch_setup_hpet_msi(unsigned int irq)
+int arch_setup_hpet_msi(unsigned int irq, unsigned int id)
{
int ret;
struct msi_msg msg;
struct irq_desc *desc = irq_to_desc(irq);
- ret = msi_compose_msg(NULL, irq, &msg);
+ if (intr_remapping_enabled) {
+ struct intel_iommu *iommu = map_hpet_to_ir(id);
+ int index;
+
+ if (!iommu)
+ return -1;
+
+ index = alloc_irte(iommu, irq, 1);
+ if (index < 0)
+ return -1;
+ }
+
+ ret = msi_compose_msg(NULL, irq, &msg, id);
if (ret < 0)
return ret;
hpet_msi_write(irq, &msg);
desc->status |= IRQ_MOVE_PCNTXT;
- set_irq_chip_and_handler_name(irq, &hpet_msi_type, handle_edge_irq,
- "edge");
+ if (irq_remapped(irq))
+ set_irq_chip_and_handler_name(irq, &ir_hpet_msi_type,
+ handle_edge_irq, "edge");
+ else
+ set_irq_chip_and_handler_name(irq, &hpet_msi_type,
+ handle_edge_irq, "edge");
return 0;
}
diff --git a/arch/x86/kernel/apic/numaq_32.c b/arch/x86/kernel/apic/numaq_32.c
index 07cdbdc..98c4665 100644
--- a/arch/x86/kernel/apic/numaq_32.c
+++ b/arch/x86/kernel/apic/numaq_32.c
@@ -264,11 +264,6 @@ static void __init smp_read_mpc_oem(struct mpc_table *mpc)
static __init void early_check_numaq(void)
{
/*
- * Find possible boot-time SMP configuration:
- */
- early_find_smp_config();
-
- /*
* get boot-time SMP configuration:
*/
if (smp_found_config)
diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c
index 130c4b9..b684bb3 100644
--- a/arch/x86/kernel/apic/x2apic_uv_x.c
+++ b/arch/x86/kernel/apic/x2apic_uv_x.c
@@ -30,10 +30,22 @@
#include <asm/apic.h>
#include <asm/ipi.h>
#include <asm/smp.h>
+#include <asm/x86_init.h>
DEFINE_PER_CPU(int, x2apic_extra_bits);
static enum uv_system_type uv_system_type;
+static u64 gru_start_paddr, gru_end_paddr;
+
+static inline bool is_GRU_range(u64 start, u64 end)
+{
+ return start >= gru_start_paddr && end <= gru_end_paddr;
+}
+
+static bool uv_is_untracked_pat_range(u64 start, u64 end)
+{
+ return is_ISA_range(start, end) || is_GRU_range(start, end);
+}
static int early_get_nodeid(void)
{
@@ -49,6 +61,7 @@ static int early_get_nodeid(void)
static int __init uv_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
{
if (!strcmp(oem_id, "SGI")) {
+ x86_platform.is_untracked_pat_range = uv_is_untracked_pat_range;
if (!strcmp(oem_table_id, "UVL"))
uv_system_type = UV_LEGACY_APIC;
else if (!strcmp(oem_table_id, "UVX"))
@@ -385,8 +398,12 @@ static __init void map_gru_high(int max_pnode)
int shift = UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_SHFT;
gru.v = uv_read_local_mmr(UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR);
- if (gru.s.enable)
+ if (gru.s.enable) {
map_high("GRU", gru.s.base, shift, max_pnode, map_wb);
+ gru_start_paddr = ((u64)gru.s.base << shift);
+ gru_end_paddr = gru_start_paddr + (1UL << shift) * (max_pnode + 1);
+
+ }
}
static __init void map_mmr_high(int max_pnode)
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index a4ec8b6..c1afa99 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -1136,7 +1136,7 @@ void __cpuinit cpu_init(void)
wrmsrl(MSR_KERNEL_GS_BASE, 0);
barrier();
- check_efer();
+ x86_configure_nx();
if (cpu != 0)
enable_x2apic();
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
index 40e1835..c900b73 100644
--- a/arch/x86/kernel/cpu/intel.c
+++ b/arch/x86/kernel/cpu/intel.c
@@ -263,8 +263,12 @@ static void __cpuinit srat_detect_node(struct cpuinfo_x86 *c)
/* Don't do the funky fallback heuristics the AMD version employs
for now. */
node = apicid_to_node[apicid];
- if (node == NUMA_NO_NODE || !node_online(node))
+ if (node == NUMA_NO_NODE)
node = first_node(node_online_map);
+ else if (!node_online(node)) {
+ /* reuse the value from init_cpu_to_node() */
+ node = cpu_to_node(cpu);
+ }
numa_set_node(cpu, node);
printk(KERN_INFO "CPU %d/0x%x -> Node %d\n", cpu, apicid, node);
diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c
index 0df4c2b..6c40f6b 100644
--- a/arch/x86/kernel/cpu/intel_cacheinfo.c
+++ b/arch/x86/kernel/cpu/intel_cacheinfo.c
@@ -94,7 +94,7 @@ static const struct _cache_table __cpuinitconst cache_table[] =
{ 0xd1, LVL_3, 1024 }, /* 4-way set assoc, 64 byte line size */
{ 0xd2, LVL_3, 2048 }, /* 4-way set assoc, 64 byte line size */
{ 0xd6, LVL_3, 1024 }, /* 8-way set assoc, 64 byte line size */
- { 0xd7, LVL_3, 2038 }, /* 8-way set assoc, 64 byte line size */
+ { 0xd7, LVL_3, 2048 }, /* 8-way set assoc, 64 byte line size */
{ 0xd8, LVL_3, 4096 }, /* 12-way set assoc, 64 byte line size */
{ 0xdc, LVL_3, 2048 }, /* 12-way set assoc, 64 byte line size */
{ 0xdd, LVL_3, 4096 }, /* 12-way set assoc, 64 byte line size */
@@ -102,6 +102,9 @@ static const struct _cache_table __cpuinitconst cache_table[] =
{ 0xe2, LVL_3, 2048 }, /* 16-way set assoc, 64 byte line size */
{ 0xe3, LVL_3, 4096 }, /* 16-way set assoc, 64 byte line size */
{ 0xe4, LVL_3, 8192 }, /* 16-way set assoc, 64 byte line size */
+ { 0xea, LVL_3, 12288 }, /* 24-way set assoc, 64 byte line size */
+ { 0xeb, LVL_3, 18432 }, /* 24-way set assoc, 64 byte line size */
+ { 0xec, LVL_3, 24576 }, /* 24-way set assoc, 64 byte line size */
{ 0x00, 0, 0}
};
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index 0bcaa38..d7ebf25 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -2016,9 +2016,11 @@ mce_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
break;
case CPU_DOWN_FAILED:
case CPU_DOWN_FAILED_FROZEN:
- t->expires = round_jiffies(jiffies +
+ if (!mce_ignore_ce && check_interval) {
+ t->expires = round_jiffies(jiffies +
__get_cpu_var(mce_next_interval));
- add_timer_on(t, cpu);
+ add_timer_on(t, cpu);
+ }
smp_call_function_single(cpu, mce_reenable_cpu, &action, 1);
break;
case CPU_POST_DEAD:
diff --git a/arch/x86/kernel/cpu/mtrr/cleanup.c b/arch/x86/kernel/cpu/mtrr/cleanup.c
index 73c86db..09b1698 100644
--- a/arch/x86/kernel/cpu/mtrr/cleanup.c
+++ b/arch/x86/kernel/cpu/mtrr/cleanup.c
@@ -170,6 +170,41 @@ static int __init cmp_range(const void *x1, const void *x2)
return start1 - start2;
}
+static int __init clean_sort_range(struct res_range *range, int az)
+{
+ int i, j, k = az - 1, nr_range = 0;
+
+ for (i = 0; i < k; i++) {
+ if (range[i].end)
+ continue;
+ for (j = k; j > i; j--) {
+ if (range[j].end) {
+ k = j;
+ break;
+ }
+ }
+ if (j == i)
+ break;
+ range[i].start = range[k].start;
+ range[i].end = range[k].end;
+ range[k].start = 0;
+ range[k].end = 0;
+ k--;
+ }
+ /* count it */
+ for (i = 0; i < az; i++) {
+ if (!range[i].end) {
+ nr_range = i;
+ break;
+ }
+ }
+
+ /* sort them */
+ sort(range, nr_range, sizeof(struct res_range), cmp_range, NULL);
+
+ return nr_range;
+}
+
#define BIOS_BUG_MSG KERN_WARNING \
"WARNING: BIOS bug: VAR MTRR %d contains strange UC entry under 1M, check with your system vendor!\n"
@@ -223,22 +258,18 @@ x86_get_mtrr_mem_range(struct res_range *range, int nr_range,
subtract_range(range, extra_remove_base,
extra_remove_base + extra_remove_size - 1);
- /* get new range num */
- nr_range = 0;
- for (i = 0; i < RANGE_NUM; i++) {
- if (!range[i].end)
- continue;
- nr_range++;
- }
if (debug_print) {
printk(KERN_DEBUG "After UC checking\n");
- for (i = 0; i < nr_range; i++)
+ for (i = 0; i < RANGE_NUM; i++) {
+ if (!range[i].end)
+ continue;
printk(KERN_DEBUG "MTRR MAP PFN: %016lx - %016lx\n",
range[i].start, range[i].end + 1);
+ }
}
/* sort the ranges */
- sort(range, nr_range, sizeof(struct res_range), cmp_range, NULL);
+ nr_range = clean_sort_range(range, RANGE_NUM);
if (debug_print) {
printk(KERN_DEBUG "After sorting\n");
for (i = 0; i < nr_range; i++)
@@ -689,8 +720,6 @@ static int __init mtrr_need_cleanup(void)
continue;
if (!size)
type = MTRR_NUM_TYPES;
- if (type == MTRR_TYPE_WRPROT)
- type = MTRR_TYPE_UNCACHABLE;
num[type]++;
}
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index c1bbed1..ab1a8a8 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -1286,7 +1286,7 @@ x86_perf_event_set_period(struct perf_event *event,
return 0;
/*
- * If we are way outside a reasoable range then just skip forward:
+ * If we are way outside a reasonable range then just skip forward:
*/
if (unlikely(left <= -period)) {
left = period;
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index 4deb8fc..63bca79 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -977,8 +977,8 @@ apicinterrupt UV_BAU_MESSAGE \
#endif
apicinterrupt LOCAL_TIMER_VECTOR \
apic_timer_interrupt smp_apic_timer_interrupt
-apicinterrupt GENERIC_INTERRUPT_VECTOR \
- generic_interrupt smp_generic_interrupt
+apicinterrupt X86_PLATFORM_IPI_VECTOR \
+ x86_platform_ipi smp_x86_platform_ipi
#ifdef CONFIG_SMP
apicinterrupt INVALIDATE_TLB_VECTOR_START+0 \
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c
index 5a1b975..3096892 100644
--- a/arch/x86/kernel/ftrace.c
+++ b/arch/x86/kernel/ftrace.c
@@ -189,9 +189,26 @@ static void wait_for_nmi(void)
nmi_wait_count++;
}
+static inline int
+within(unsigned long addr, unsigned long start, unsigned long end)
+{
+ return addr >= start && addr < end;
+}
+
static int
do_ftrace_mod_code(unsigned long ip, void *new_code)
{
+ /*
+ * On x86_64, kernel text mappings are mapped read-only with
+ * CONFIG_DEBUG_RODATA. So we use the kernel identity mapping instead
+ * of the kernel text mapping to modify the kernel text.
+ *
+ * For 32bit kernels, these mappings are same and we can use
+ * kernel identity mapping to modify code.
+ */
+ if (within(ip, (unsigned long)_text, (unsigned long)_etext))
+ ip = (unsigned long)__va(__pa(ip));
+
mod_code_ip = (void *)ip;
mod_code_newcode = new_code;
diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S
index 050c278..7fd318b 100644
--- a/arch/x86/kernel/head_32.S
+++ b/arch/x86/kernel/head_32.S
@@ -18,6 +18,8 @@
#include <asm/asm-offsets.h>
#include <asm/setup.h>
#include <asm/processor-flags.h>
+#include <asm/msr-index.h>
+#include <asm/cpufeature.h>
#include <asm/percpu.h>
/* Physical address */
@@ -297,25 +299,27 @@ ENTRY(startup_32_smp)
orl %edx,%eax
movl %eax,%cr4
- btl $5, %eax # check if PAE is enabled
- jnc 6f
+ testb $X86_CR4_PAE, %al # check if PAE is enabled
+ jz 6f
/* Check if extended functions are implemented */
movl $0x80000000, %eax
cpuid
- cmpl $0x80000000, %eax
- jbe 6f
+ /* Value must be in the range 0x80000001 to 0x8000ffff */
+ subl $0x80000001, %eax
+ cmpl $(0x8000ffff-0x80000001), %eax
+ ja 6f
mov $0x80000001, %eax
cpuid
/* Execute Disable bit supported? */
- btl $20, %edx
+ btl $(X86_FEATURE_NX & 31), %edx
jnc 6f
/* Setup EFER (Extended Feature Enable Register) */
- movl $0xc0000080, %ecx
+ movl $MSR_EFER, %ecx
rdmsr
- btsl $11, %eax
+ btsl $_EFER_NX, %eax
/* Make changes effective */
wrmsr
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
index 22db86a..2d8b503 100644
--- a/arch/x86/kernel/head_64.S
+++ b/arch/x86/kernel/head_64.S
@@ -262,11 +262,11 @@ ENTRY(secondary_startup_64)
.quad x86_64_start_kernel
ENTRY(initial_gs)
.quad INIT_PER_CPU_VAR(irq_stack_union)
- __FINITDATA
ENTRY(stack_start)
.quad init_thread_union+THREAD_SIZE-8
.word 0
+ __FINITDATA
bad_address:
jmp bad_address
@@ -340,6 +340,7 @@ ENTRY(name)
i = i + 1 ; \
.endr
+ .data
/*
* This default setting generates an ident mapping at address 0x100000
* and a mapping for the kernel that precisely maps virtual address
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c
index dedc2bd..ba6e658 100644
--- a/arch/x86/kernel/hpet.c
+++ b/arch/x86/kernel/hpet.c
@@ -33,6 +33,7 @@
* HPET address is set in acpi/boot.c, when an ACPI entry exists
*/
unsigned long hpet_address;
+u8 hpet_blockid; /* OS timer block num */
#ifdef CONFIG_PCI_MSI
static unsigned long hpet_num_timers;
#endif
@@ -47,12 +48,12 @@ struct hpet_dev {
char name[10];
};
-unsigned long hpet_readl(unsigned long a)
+inline unsigned int hpet_readl(unsigned int a)
{
return readl(hpet_virt_address + a);
}
-static inline void hpet_writel(unsigned long d, unsigned long a)
+static inline void hpet_writel(unsigned int d, unsigned int a)
{
writel(d, hpet_virt_address + a);
}
@@ -167,7 +168,7 @@ do { \
static void hpet_reserve_msi_timers(struct hpet_data *hd);
-static void hpet_reserve_platform_timers(unsigned long id)
+static void hpet_reserve_platform_timers(unsigned int id)
{
struct hpet __iomem *hpet = hpet_virt_address;
struct hpet_timer __iomem *timer = &hpet->hpet_timers[2];
@@ -205,7 +206,7 @@ static void hpet_reserve_platform_timers(unsigned long id)
}
#else
-static void hpet_reserve_platform_timers(unsigned long id) { }
+static void hpet_reserve_platform_timers(unsigned int id) { }
#endif
/*
@@ -246,7 +247,7 @@ static void hpet_reset_counter(void)
static void hpet_start_counter(void)
{
- unsigned long cfg = hpet_readl(HPET_CFG);
+ unsigned int cfg = hpet_readl(HPET_CFG);
cfg |= HPET_CFG_ENABLE;
hpet_writel(cfg, HPET_CFG);
}
@@ -271,7 +272,7 @@ static void hpet_resume_counter(void)
static void hpet_enable_legacy_int(void)
{
- unsigned long cfg = hpet_readl(HPET_CFG);
+ unsigned int cfg = hpet_readl(HPET_CFG);
cfg |= HPET_CFG_LEGACY;
hpet_writel(cfg, HPET_CFG);
@@ -314,7 +315,7 @@ static int hpet_setup_msi_irq(unsigned int irq);
static void hpet_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt, int timer)
{
- unsigned long cfg, cmp, now;
+ unsigned int cfg, cmp, now;
uint64_t delta;
switch (mode) {
@@ -323,7 +324,7 @@ static void hpet_set_mode(enum clock_event_mode mode,
delta = ((uint64_t)(NSEC_PER_SEC/HZ)) * evt->mult;
delta >>= evt->shift;
now = hpet_readl(HPET_COUNTER);
- cmp = now + (unsigned long) delta;
+ cmp = now + (unsigned int) delta;
cfg = hpet_readl(HPET_Tn_CFG(timer));
/* Make sure we use edge triggered interrupts */
cfg &= ~HPET_TN_LEVEL;
@@ -339,7 +340,7 @@ static void hpet_set_mode(enum clock_event_mode mode,
* (See AMD-8111 HyperTransport I/O Hub Data Sheet,
* Publication # 24674)
*/
- hpet_writel((unsigned long) delta, HPET_Tn_CMP(timer));
+ hpet_writel((unsigned int) delta, HPET_Tn_CMP(timer));
hpet_start_counter();
hpet_print_config();
break;
@@ -383,13 +384,24 @@ static int hpet_next_event(unsigned long delta,
hpet_writel(cnt, HPET_Tn_CMP(timer));
/*
- * We need to read back the CMP register to make sure that
- * what we wrote hit the chip before we compare it to the
- * counter.
+ * We need to read back the CMP register on certain HPET
+ * implementations (ATI chipsets) which seem to delay the
+ * transfer of the compare register into the internal compare
+ * logic. With small deltas this might actually be too late as
+ * the counter could already be higher than the compare value
+ * at that point and we would wait for the next hpet interrupt
+ * forever. We found out that reading the CMP register back
+ * forces the transfer so we can rely on the comparison with
+ * the counter register below. If the read back from the
+ * compare register does not match the value we programmed
+ * then we might have a real hardware problem. We can not do
+ * much about it here, but at least alert the user/admin with
+ * a prominent warning.
*/
- WARN_ON_ONCE((u32)hpet_readl(HPET_Tn_CMP(timer)) != cnt);
+ WARN_ONCE(hpet_readl(HPET_Tn_CMP(timer)) != cnt,
+ KERN_WARNING "hpet: compare register read back failed.\n");
- return (s32)((u32)hpet_readl(HPET_COUNTER) - cnt) >= 0 ? -ETIME : 0;
+ return (s32)(hpet_readl(HPET_COUNTER) - cnt) >= 0 ? -ETIME : 0;
}
static void hpet_legacy_set_mode(enum clock_event_mode mode,
@@ -415,7 +427,7 @@ static struct hpet_dev *hpet_devs;
void hpet_msi_unmask(unsigned int irq)
{
struct hpet_dev *hdev = get_irq_data(irq);
- unsigned long cfg;
+ unsigned int cfg;
/* unmask it */
cfg = hpet_readl(HPET_Tn_CFG(hdev->num));
@@ -425,7 +437,7 @@ void hpet_msi_unmask(unsigned int irq)
void hpet_msi_mask(unsigned int irq)
{
- unsigned long cfg;
+ unsigned int cfg;
struct hpet_dev *hdev = get_irq_data(irq);
/* mask it */
@@ -467,7 +479,7 @@ static int hpet_msi_next_event(unsigned long delta,
static int hpet_setup_msi_irq(unsigned int irq)
{
- if (arch_setup_hpet_msi(irq)) {
+ if (arch_setup_hpet_msi(irq, hpet_blockid)) {
destroy_irq(irq);
return -EINVAL;
}
@@ -584,6 +596,8 @@ static void hpet_msi_capability_lookup(unsigned int start_timer)
unsigned int num_timers_used = 0;
int i;
+ if (boot_cpu_has(X86_FEATURE_ARAT))
+ return;
id = hpet_readl(HPET_ID);
num_timers = ((id & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT);
@@ -598,7 +612,7 @@ static void hpet_msi_capability_lookup(unsigned int start_timer)
for (i = start_timer; i < num_timers - RESERVE_TIMERS; i++) {
struct hpet_dev *hdev = &hpet_devs[num_timers_used];
- unsigned long cfg = hpet_readl(HPET_Tn_CFG(i));
+ unsigned int cfg = hpet_readl(HPET_Tn_CFG(i));
/* Only consider HPET timer with MSI support */
if (!(cfg & HPET_TN_FSB_CAP))
@@ -813,7 +827,7 @@ static int hpet_clocksource_register(void)
*/
int __init hpet_enable(void)
{
- unsigned long id;
+ unsigned int id;
int i;
if (!is_hpet_capable())
@@ -872,10 +886,8 @@ int __init hpet_enable(void)
if (id & HPET_ID_LEGSUP) {
hpet_legacy_clockevent_register();
- hpet_msi_capability_lookup(2);
return 1;
}
- hpet_msi_capability_lookup(0);
return 0;
out_nohpet:
@@ -908,9 +920,17 @@ static __init int hpet_late_init(void)
if (!hpet_virt_address)
return -ENODEV;
+ if (hpet_readl(HPET_ID) & HPET_ID_LEGSUP)
+ hpet_msi_capability_lookup(2);
+ else
+ hpet_msi_capability_lookup(0);
+
hpet_reserve_platform_timers(hpet_readl(HPET_ID));
hpet_print_config();
+ if (boot_cpu_has(X86_FEATURE_ARAT))
+ return 0;
+
for_each_online_cpu(cpu) {
hpet_cpuhp_notify(NULL, CPU_ONLINE, (void *)(long)cpu);
}
@@ -925,7 +945,7 @@ fs_initcall(hpet_late_init);
void hpet_disable(void)
{
if (is_hpet_capable()) {
- unsigned long cfg = hpet_readl(HPET_CFG);
+ unsigned int cfg = hpet_readl(HPET_CFG);
if (hpet_legacy_int_enabled) {
cfg &= ~HPET_CFG_LEGACY;
@@ -965,8 +985,8 @@ static int hpet_prev_update_sec;
static struct rtc_time hpet_alarm_time;
static unsigned long hpet_pie_count;
static u32 hpet_t1_cmp;
-static unsigned long hpet_default_delta;
-static unsigned long hpet_pie_delta;
+static u32 hpet_default_delta;
+static u32 hpet_pie_delta;
static unsigned long hpet_pie_limit;
static rtc_irq_handler irq_handler;
@@ -1017,7 +1037,8 @@ EXPORT_SYMBOL_GPL(hpet_unregister_irq_handler);
*/
int hpet_rtc_timer_init(void)
{
- unsigned long cfg, cnt, delta, flags;
+ unsigned int cfg, cnt, delta;
+ unsigned long flags;
if (!is_hpet_enabled())
return 0;
@@ -1027,7 +1048,7 @@ int hpet_rtc_timer_init(void)
clc = (uint64_t) hpet_clockevent.mult * NSEC_PER_SEC;
clc >>= hpet_clockevent.shift + DEFAULT_RTC_SHIFT;
- hpet_default_delta = (unsigned long) clc;
+ hpet_default_delta = clc;
}
if (!(hpet_rtc_flags & RTC_PIE) || hpet_pie_limit)
@@ -1113,7 +1134,7 @@ int hpet_set_periodic_freq(unsigned long freq)
clc = (uint64_t) hpet_clockevent.mult * NSEC_PER_SEC;
do_div(clc, freq);
clc >>= hpet_clockevent.shift;
- hpet_pie_delta = (unsigned long) clc;
+ hpet_pie_delta = clc;
}
return 1;
}
@@ -1127,7 +1148,7 @@ EXPORT_SYMBOL_GPL(hpet_rtc_dropped_irq);
static void hpet_rtc_timer_reinit(void)
{
- unsigned long cfg, delta;
+ unsigned int cfg, delta;
int lost_ints = -1;
if (unlikely(!hpet_rtc_flags)) {
diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c
index fee6cc2..664bcb7 100644
--- a/arch/x86/kernel/irq.c
+++ b/arch/x86/kernel/irq.c
@@ -18,7 +18,7 @@
atomic_t irq_err_count;
/* Function pointer for generic interrupt vector handling */
-void (*generic_interrupt_extension)(void) = NULL;
+void (*x86_platform_ipi_callback)(void) = NULL;
/*
* 'what should we do if we get a hw irq event on an illegal vector'.
@@ -72,10 +72,10 @@ static int show_other_interrupts(struct seq_file *p, int prec)
seq_printf(p, "%10u ", irq_stats(j)->apic_pending_irqs);
seq_printf(p, " Performance pending work\n");
#endif
- if (generic_interrupt_extension) {
+ if (x86_platform_ipi_callback) {
seq_printf(p, "%*s: ", prec, "PLT");
for_each_online_cpu(j)
- seq_printf(p, "%10u ", irq_stats(j)->generic_irqs);
+ seq_printf(p, "%10u ", irq_stats(j)->x86_platform_ipis);
seq_printf(p, " Platform interrupts\n");
}
#ifdef CONFIG_SMP
@@ -187,8 +187,8 @@ u64 arch_irq_stat_cpu(unsigned int cpu)
sum += irq_stats(cpu)->apic_perf_irqs;
sum += irq_stats(cpu)->apic_pending_irqs;
#endif
- if (generic_interrupt_extension)
- sum += irq_stats(cpu)->generic_irqs;
+ if (x86_platform_ipi_callback)
+ sum += irq_stats(cpu)->x86_platform_ipis;
#ifdef CONFIG_SMP
sum += irq_stats(cpu)->irq_resched_count;
sum += irq_stats(cpu)->irq_call_count;
@@ -251,9 +251,9 @@ unsigned int __irq_entry do_IRQ(struct pt_regs *regs)
}
/*
- * Handler for GENERIC_INTERRUPT_VECTOR.
+ * Handler for X86_PLATFORM_IPI_VECTOR.
*/
-void smp_generic_interrupt(struct pt_regs *regs)
+void smp_x86_platform_ipi(struct pt_regs *regs)
{
struct pt_regs *old_regs = set_irq_regs(regs);
@@ -263,10 +263,10 @@ void smp_generic_interrupt(struct pt_regs *regs)
irq_enter();
- inc_irq_stat(generic_irqs);
+ inc_irq_stat(x86_platform_ipis);
- if (generic_interrupt_extension)
- generic_interrupt_extension();
+ if (x86_platform_ipi_callback)
+ x86_platform_ipi_callback();
irq_exit();
diff --git a/arch/x86/kernel/irqinit.c b/arch/x86/kernel/irqinit.c
index 40f3077..d593222 100644
--- a/arch/x86/kernel/irqinit.c
+++ b/arch/x86/kernel/irqinit.c
@@ -200,8 +200,8 @@ static void __init apic_intr_init(void)
/* self generated IPI for local APIC timer */
alloc_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt);
- /* generic IPI for platform specific use */
- alloc_intr_gate(GENERIC_INTERRUPT_VECTOR, generic_interrupt);
+ /* IPI for X86 platform specific use */
+ alloc_intr_gate(X86_PLATFORM_IPI_VECTOR, x86_platform_ipi);
/* IPI vectors for APIC spurious and error interrupts */
alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes.c
index 1f3186c..5b8c750 100644
--- a/arch/x86/kernel/kprobes.c
+++ b/arch/x86/kernel/kprobes.c
@@ -481,7 +481,7 @@ static int __kprobes reenter_kprobe(struct kprobe *p, struct pt_regs *regs,
/*
* Interrupts are disabled on entry as trap3 is an interrupt gate and they
- * remain disabled thorough out this function.
+ * remain disabled throughout this function.
*/
static int __kprobes kprobe_handler(struct pt_regs *regs)
{
@@ -818,7 +818,7 @@ no_change:
/*
* Interrupts are disabled on entry as trap1 is an interrupt gate and they
- * remain disabled thoroughout this function.
+ * remain disabled throughout this function.
*/
static int __kprobes post_kprobe_handler(struct pt_regs *regs)
{
diff --git a/arch/x86/kernel/machine_kexec_32.c b/arch/x86/kernel/machine_kexec_32.c
index c843f84..a3fa43b 100644
--- a/arch/x86/kernel/machine_kexec_32.c
+++ b/arch/x86/kernel/machine_kexec_32.c
@@ -158,8 +158,7 @@ int machine_kexec_prepare(struct kimage *image)
{
int error;
- if (nx_enabled)
- set_pages_x(image->control_code_page, 1);
+ set_pages_x(image->control_code_page, 1);
error = machine_kexec_alloc_page_tables(image);
if (error)
return error;
@@ -173,8 +172,7 @@ int machine_kexec_prepare(struct kimage *image)
*/
void machine_kexec_cleanup(struct kimage *image)
{
- if (nx_enabled)
- set_pages_nx(image->control_code_page, 1);
+ set_pages_nx(image->control_code_page, 1);
machine_kexec_free_page_tables(image);
}
diff --git a/arch/x86/kernel/microcode_amd.c b/arch/x86/kernel/microcode_amd.c
index f4c538b..63123d9 100644
--- a/arch/x86/kernel/microcode_amd.c
+++ b/arch/x86/kernel/microcode_amd.c
@@ -33,6 +33,9 @@ MODULE_LICENSE("GPL v2");
#define UCODE_EQUIV_CPU_TABLE_TYPE 0x00000000
#define UCODE_UCODE_TYPE 0x00000001
+const struct firmware *firmware;
+static int supported_cpu;
+
struct equiv_cpu_entry {
u32 installed_cpu;
u32 fixed_errata_mask;
@@ -71,17 +74,14 @@ static struct equiv_cpu_entry *equiv_cpu_table;
static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig)
{
- struct cpuinfo_x86 *c = &cpu_data(cpu);
u32 dummy;
- memset(csig, 0, sizeof(*csig));
- if (c->x86_vendor != X86_VENDOR_AMD || c->x86 < 0x10) {
- printk(KERN_WARNING "microcode: CPU%d: AMD CPU family 0x%x not "
- "supported\n", cpu, c->x86);
+ if (!supported_cpu)
return -1;
- }
+
+ memset(csig, 0, sizeof(*csig));
rdmsr(MSR_AMD64_PATCH_LEVEL, csig->rev, dummy);
- printk(KERN_INFO "microcode: CPU%d: patch_level=0x%x\n", cpu, csig->rev);
+ pr_info("microcode: CPU%d: patch_level=0x%x\n", cpu, csig->rev);
return 0;
}
@@ -103,22 +103,15 @@ static int get_matching_microcode(int cpu, void *mc, int rev)
i++;
}
- if (!equiv_cpu_id) {
- printk(KERN_WARNING "microcode: CPU%d: cpu revision "
- "not listed in equivalent cpu table\n", cpu);
+ if (!equiv_cpu_id)
return 0;
- }
- if (mc_header->processor_rev_id != equiv_cpu_id) {
- printk(KERN_ERR "microcode: CPU%d: patch mismatch "
- "(processor_rev_id: %x, equiv_cpu_id: %x)\n",
- cpu, mc_header->processor_rev_id, equiv_cpu_id);
+ if (mc_header->processor_rev_id != equiv_cpu_id)
return 0;
- }
/* ucode might be chipset specific -- currently we don't support this */
if (mc_header->nb_dev_id || mc_header->sb_dev_id) {
- printk(KERN_ERR "microcode: CPU%d: loading of chipset "
+ pr_err(KERN_ERR "microcode: CPU%d: loading of chipset "
"specific code not yet supported\n", cpu);
return 0;
}
@@ -148,14 +141,12 @@ static int apply_microcode_amd(int cpu)
/* check current patch id and patch's id for match */
if (rev != mc_amd->hdr.patch_id) {
- printk(KERN_ERR "microcode: CPU%d: update failed "
+ pr_err("microcode: CPU%d: update failed "
"(for patch_level=0x%x)\n", cpu, mc_amd->hdr.patch_id);
return -1;
}
- printk(KERN_INFO "microcode: CPU%d: updated (new patch_level=0x%x)\n",
- cpu, rev);
-
+ pr_info("microcode: CPU%d: updated (new patch_level=0x%x)\n", cpu, rev);
uci->cpu_sig.rev = rev;
return 0;
@@ -178,18 +169,15 @@ get_next_ucode(const u8 *buf, unsigned int size, unsigned int *mc_size)
return NULL;
if (section_hdr[0] != UCODE_UCODE_TYPE) {
- printk(KERN_ERR "microcode: error: invalid type field in "
+ pr_err("microcode: error: invalid type field in "
"container file section header\n");
return NULL;
}
total_size = (unsigned long) (section_hdr[4] + (section_hdr[5] << 8));
- printk(KERN_DEBUG "microcode: size %u, total_size %u\n",
- size, total_size);
-
if (total_size > size || total_size > UCODE_MAX_SIZE) {
- printk(KERN_ERR "microcode: error: size mismatch\n");
+ pr_err("microcode: error: size mismatch\n");
return NULL;
}
@@ -218,15 +206,14 @@ static int install_equiv_cpu_table(const u8 *buf)
size = buf_pos[2];
if (buf_pos[1] != UCODE_EQUIV_CPU_TABLE_TYPE || !size) {
- printk(KERN_ERR "microcode: error: invalid type field in "
+ pr_err("microcode: error: invalid type field in "
"container file section header\n");
return 0;
}
equiv_cpu_table = (struct equiv_cpu_entry *) vmalloc(size);
if (!equiv_cpu_table) {
- printk(KERN_ERR "microcode: failed to allocate "
- "equivalent CPU table\n");
+ pr_err("microcode: failed to allocate equivalent CPU table\n");
return 0;
}
@@ -259,8 +246,7 @@ generic_load_microcode(int cpu, const u8 *data, size_t size)
offset = install_equiv_cpu_table(ucode_ptr);
if (!offset) {
- printk(KERN_ERR "microcode: failed to create "
- "equivalent cpu table\n");
+ pr_err("microcode: failed to create equivalent cpu table\n");
return UCODE_ERROR;
}
@@ -308,33 +294,27 @@ generic_load_microcode(int cpu, const u8 *data, size_t size)
static enum ucode_state request_microcode_fw(int cpu, struct device *device)
{
- const char *fw_name = "amd-ucode/microcode_amd.bin";
- const struct firmware *firmware;
enum ucode_state ret;
- if (request_firmware(&firmware, fw_name, device)) {
- printk(KERN_ERR "microcode: failed to load file %s\n", fw_name);
+ if (firmware == NULL)
return UCODE_NFOUND;
- }
if (*(u32 *)firmware->data != UCODE_MAGIC) {
- printk(KERN_ERR "microcode: invalid UCODE_MAGIC (0x%08x)\n",
+ pr_err("microcode: invalid UCODE_MAGIC (0x%08x)\n",
*(u32 *)firmware->data);
return UCODE_ERROR;
}
ret = generic_load_microcode(cpu, firmware->data, firmware->size);
- release_firmware(firmware);
-
return ret;
}
static enum ucode_state
request_microcode_user(int cpu, const void __user *buf, size_t size)
{
- printk(KERN_INFO "microcode: AMD microcode update via "
- "/dev/cpu/microcode not supported\n");
+ pr_info("microcode: AMD microcode update via "
+ "/dev/cpu/microcode not supported\n");
return UCODE_ERROR;
}
@@ -346,7 +326,32 @@ static void microcode_fini_cpu_amd(int cpu)
uci->mc = NULL;
}
+void init_microcode_amd(struct device *device)
+{
+ const char *fw_name = "amd-ucode/microcode_amd.bin";
+ struct cpuinfo_x86 *c = &boot_cpu_data;
+
+ WARN_ON(c->x86_vendor != X86_VENDOR_AMD);
+
+ if (c->x86 < 0x10) {
+ pr_warning("microcode: AMD CPU family 0x%x not supported\n",
+ c->x86);
+ return;
+ }
+ supported_cpu = 1;
+
+ if (request_firmware(&firmware, fw_name, device))
+ pr_err("microcode: failed to load file %s\n", fw_name);
+}
+
+void fini_microcode_amd(void)
+{
+ release_firmware(firmware);
+}
+
static struct microcode_ops microcode_amd_ops = {
+ .init = init_microcode_amd,
+ .fini = fini_microcode_amd,
.request_microcode_user = request_microcode_user,
.request_microcode_fw = request_microcode_fw,
.collect_cpu_info = collect_cpu_info_amd,
diff --git a/arch/x86/kernel/microcode_core.c b/arch/x86/kernel/microcode_core.c
index 2bcad39..e68aae3 100644
--- a/arch/x86/kernel/microcode_core.c
+++ b/arch/x86/kernel/microcode_core.c
@@ -391,7 +391,7 @@ static enum ucode_state microcode_update_cpu(int cpu)
struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
enum ucode_state ustate;
- if (uci->valid)
+ if (uci->valid && uci->mc)
ustate = microcode_resume_cpu(cpu);
else
ustate = microcode_init_cpu(cpu);
@@ -518,6 +518,9 @@ static int __init microcode_init(void)
return PTR_ERR(microcode_pdev);
}
+ if (microcode_ops->init)
+ microcode_ops->init(&microcode_pdev->dev);
+
get_online_cpus();
mutex_lock(&microcode_mutex);
@@ -561,6 +564,9 @@ static void __exit microcode_exit(void)
platform_device_unregister(microcode_pdev);
+ if (microcode_ops->fini)
+ microcode_ops->fini();
+
microcode_ops = NULL;
pr_info("Microcode Update Driver: v" MICROCODE_VERSION " removed.\n");
diff --git a/arch/x86/kernel/mpparse.c b/arch/x86/kernel/mpparse.c
index 5be95ef..35a57c9 100644
--- a/arch/x86/kernel/mpparse.c
+++ b/arch/x86/kernel/mpparse.c
@@ -667,36 +667,18 @@ void __init default_get_smp_config(unsigned int early)
*/
}
-static void __init smp_reserve_bootmem(struct mpf_intel *mpf)
+static void __init smp_reserve_memory(struct mpf_intel *mpf)
{
unsigned long size = get_mpc_size(mpf->physptr);
-#ifdef CONFIG_X86_32
- /*
- * We cannot access to MPC table to compute table size yet,
- * as only few megabytes from the bottom is mapped now.
- * PC-9800's MPC table places on the very last of physical
- * memory; so that simply reserving PAGE_SIZE from mpf->physptr
- * yields BUG() in reserve_bootmem.
- * also need to make sure physptr is below than max_low_pfn
- * we don't need reserve the area above max_low_pfn
- */
- unsigned long end = max_low_pfn * PAGE_SIZE;
- if (mpf->physptr < end) {
- if (mpf->physptr + size > end)
- size = end - mpf->physptr;
- reserve_bootmem_generic(mpf->physptr, size, BOOTMEM_DEFAULT);
- }
-#else
- reserve_bootmem_generic(mpf->physptr, size, BOOTMEM_DEFAULT);
-#endif
+ reserve_early(mpf->physptr, mpf->physptr+size, "MP-table mpc");
}
-static int __init smp_scan_config(unsigned long base, unsigned long length,
- unsigned reserve)
+static int __init smp_scan_config(unsigned long base, unsigned long length)
{
unsigned int *bp = phys_to_virt(base);
struct mpf_intel *mpf;
+ unsigned long mem;
apic_printk(APIC_VERBOSE, "Scan SMP from %p for %ld bytes.\n",
bp, length);
@@ -717,12 +699,10 @@ static int __init smp_scan_config(unsigned long base, unsigned long length,
printk(KERN_INFO "found SMP MP-table at [%p] %llx\n",
mpf, (u64)virt_to_phys(mpf));
- if (!reserve)
- return 1;
- reserve_bootmem_generic(virt_to_phys(mpf), sizeof(*mpf),
- BOOTMEM_DEFAULT);
+ mem = virt_to_phys(mpf);
+ reserve_early(mem, mem + sizeof(*mpf), "MP-table mpf");
if (mpf->physptr)
- smp_reserve_bootmem(mpf);
+ smp_reserve_memory(mpf);
return 1;
}
@@ -732,7 +712,7 @@ static int __init smp_scan_config(unsigned long base, unsigned long length,
return 0;
}
-void __init default_find_smp_config(unsigned int reserve)
+void __init default_find_smp_config(void)
{
unsigned int address;
@@ -744,9 +724,9 @@ void __init default_find_smp_config(unsigned int reserve)
* 2) Scan the top 1K of base RAM
* 3) Scan the 64K of bios
*/
- if (smp_scan_config(0x0, 0x400, reserve) ||
- smp_scan_config(639 * 0x400, 0x400, reserve) ||
- smp_scan_config(0xF0000, 0x10000, reserve))
+ if (smp_scan_config(0x0, 0x400) ||
+ smp_scan_config(639 * 0x400, 0x400) ||
+ smp_scan_config(0xF0000, 0x10000))
return;
/*
* If it is an SMP machine we should know now, unless the
@@ -767,7 +747,7 @@ void __init default_find_smp_config(unsigned int reserve)
address = get_bios_ebda();
if (address)
- smp_scan_config(address, 0x400, reserve);
+ smp_scan_config(address, 0x400);
}
#ifdef CONFIG_X86_IO_APIC
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index a98fe88..c95c8f4 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -349,26 +349,42 @@ out:
return err;
}
-void
-start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp)
+static void
+start_thread_common(struct pt_regs *regs, unsigned long new_ip,
+ unsigned long new_sp,
+ unsigned int _cs, unsigned int _ss, unsigned int _ds)
{
loadsegment(fs, 0);
- loadsegment(es, 0);
- loadsegment(ds, 0);
+ loadsegment(es, _ds);
+ loadsegment(ds, _ds);
load_gs_index(0);
regs->ip = new_ip;
regs->sp = new_sp;
percpu_write(old_rsp, new_sp);
- regs->cs = __USER_CS;
- regs->ss = __USER_DS;
- regs->flags = 0x200;
+ regs->cs = _cs;
+ regs->ss = _ss;
+ regs->flags = X86_EFLAGS_IF;
set_fs(USER_DS);
/*
* Free the old FP and other extended state
*/
free_thread_xstate(current);
}
-EXPORT_SYMBOL_GPL(start_thread);
+
+void
+start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp)
+{
+ start_thread_common(regs, new_ip, new_sp,
+ __USER_CS, __USER_DS, 0);
+}
+
+#ifdef CONFIG_IA32_EMULATION
+void start_thread_ia32(struct pt_regs *regs, u32 new_ip, u32 new_sp)
+{
+ start_thread_common(regs, new_ip, new_sp,
+ __USER32_CS, __USER32_DS, __USER32_DS);
+}
+#endif
/*
* switch_to(x,y) should switch tasks from x to y.
diff --git a/arch/x86/kernel/quirks.c b/arch/x86/kernel/quirks.c
index 6c3b2c6..18093d7 100644
--- a/arch/x86/kernel/quirks.c
+++ b/arch/x86/kernel/quirks.c
@@ -499,6 +499,7 @@ static void __init quirk_amd_nb_node(struct pci_dev *dev)
{
struct pci_dev *nb_ht;
unsigned int devfn;
+ u32 node;
u32 val;
devfn = PCI_DEVFN(PCI_SLOT(dev->devfn), 0);
@@ -507,7 +508,13 @@ static void __init quirk_amd_nb_node(struct pci_dev *dev)
return;
pci_read_config_dword(nb_ht, 0x60, &val);
- set_dev_node(&dev->dev, val & 7);
+ node = val & 7;
+ /*
+ * Some hardware may return an invalid node ID,
+ * so check it first:
+ */
+ if (node_online(node))
+ set_dev_node(&dev->dev, node);
pci_dev_put(nb_ht);
}
diff --git a/arch/x86/kernel/reboot_fixups_32.c b/arch/x86/kernel/reboot_fixups_32.c
index 61a8377..201eab6 100644
--- a/arch/x86/kernel/reboot_fixups_32.c
+++ b/arch/x86/kernel/reboot_fixups_32.c
@@ -80,6 +80,7 @@ void mach_reboot_fixups(void)
continue;
cur->reboot_fixup(dev);
+ pci_dev_put(dev);
}
}
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 82e88cd..946a311 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -106,6 +106,7 @@
#include <asm/percpu.h>
#include <asm/topology.h>
#include <asm/apicdef.h>
+#include <asm/k8.h>
#ifdef CONFIG_X86_64
#include <asm/numa_64.h>
#endif
@@ -487,42 +488,11 @@ static void __init reserve_early_setup_data(void)
#ifdef CONFIG_KEXEC
-/**
- * Reserve @size bytes of crashkernel memory at any suitable offset.
- *
- * @size: Size of the crashkernel memory to reserve.
- * Returns the base address on success, and -1ULL on failure.
- */
-static
-unsigned long long __init find_and_reserve_crashkernel(unsigned long long size)
-{
- const unsigned long long alignment = 16<<20; /* 16M */
- unsigned long long start = 0LL;
-
- while (1) {
- int ret;
-
- start = find_e820_area(start, ULONG_MAX, size, alignment);
- if (start == -1ULL)
- return start;
-
- /* try to reserve it */
- ret = reserve_bootmem_generic(start, size, BOOTMEM_EXCLUSIVE);
- if (ret >= 0)
- return start;
-
- start += alignment;
- }
-}
-
static inline unsigned long long get_total_mem(void)
{
unsigned long long total;
- total = max_low_pfn - min_low_pfn;
-#ifdef CONFIG_HIGHMEM
- total += highend_pfn - highstart_pfn;
-#endif
+ total = max_pfn - min_low_pfn;
return total << PAGE_SHIFT;
}
@@ -542,21 +512,25 @@ static void __init reserve_crashkernel(void)
/* 0 means: find the address automatically */
if (crash_base <= 0) {
- crash_base = find_and_reserve_crashkernel(crash_size);
+ const unsigned long long alignment = 16<<20; /* 16M */
+
+ crash_base = find_e820_area(alignment, ULONG_MAX, crash_size,
+ alignment);
if (crash_base == -1ULL) {
- pr_info("crashkernel reservation failed. "
- "No suitable area found.\n");
+ pr_info("crashkernel reservation failed - No suitable area found.\n");
return;
}
} else {
- ret = reserve_bootmem_generic(crash_base, crash_size,
- BOOTMEM_EXCLUSIVE);
- if (ret < 0) {
- pr_info("crashkernel reservation failed - "
- "memory is in use\n");
+ unsigned long long start;
+
+ start = find_e820_area(crash_base, ULONG_MAX, crash_size,
+ 1<<20);
+ if (start != crash_base) {
+ pr_info("crashkernel reservation failed - memory is in use.\n");
return;
}
}
+ reserve_early(crash_base, crash_base + crash_size, "CRASH KERNEL");
printk(KERN_INFO "Reserving %ldMB of memory at %ldMB "
"for crashkernel (System RAM: %ldMB)\n",
@@ -699,6 +673,9 @@ static struct dmi_system_id __initdata bad_bios_dmi_table[] = {
void __init setup_arch(char **cmdline_p)
{
+ int acpi = 0;
+ int k8 = 0;
+
#ifdef CONFIG_X86_32
memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data));
visws_early_detect();
@@ -791,21 +768,18 @@ void __init setup_arch(char **cmdline_p)
strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
*cmdline_p = command_line;
-#ifdef CONFIG_X86_64
/*
- * Must call this twice: Once just to detect whether hardware doesn't
- * support NX (so that the early EHCI debug console setup can safely
- * call set_fixmap(), and then again after parsing early parameters to
- * honor the respective command line option.
+ * x86_configure_nx() is called before parse_early_param() to detect
+ * whether hardware doesn't support NX (so that the early EHCI debug
+ * console setup can safely call set_fixmap()). It may then be called
+ * again from within noexec_setup() during parsing early parameters
+ * to honor the respective command line option.
*/
- check_efer();
-#endif
+ x86_configure_nx();
parse_early_param();
-#ifdef CONFIG_X86_64
- check_efer();
-#endif
+ x86_report_nx();
/* Must be before kernel pagetables are setup */
vmi_activate();
@@ -901,6 +875,13 @@ void __init setup_arch(char **cmdline_p)
reserve_brk();
+#ifdef CONFIG_ACPI_SLEEP
+ /*
+ * Reserve low memory region for sleep support.
+ * even before init_memory_mapping
+ */
+ acpi_reserve_wakeup_memory();
+#endif
init_gbpages();
/* max_pfn_mapped is updated here */
@@ -927,6 +908,8 @@ void __init setup_arch(char **cmdline_p)
reserve_initrd();
+ reserve_crashkernel();
+
vsmp_init();
io_delay_init();
@@ -938,27 +921,24 @@ void __init setup_arch(char **cmdline_p)
early_acpi_boot_init();
+ /*
+ * Find and reserve possible boot-time SMP configuration:
+ */
+ find_smp_config();
+
#ifdef CONFIG_ACPI_NUMA
/*
* Parse SRAT to discover nodes.
*/
- acpi_numa_init();
+ acpi = acpi_numa_init();
#endif
- initmem_init(0, max_pfn);
-
-#ifdef CONFIG_ACPI_SLEEP
- /*
- * Reserve low memory region for sleep support.
- */
- acpi_reserve_bootmem();
+#ifdef CONFIG_K8_NUMA
+ if (!acpi)
+ k8 = !k8_numa_init(0, max_pfn);
#endif
- /*
- * Find and reserve possible boot-time SMP configuration:
- */
- find_smp_config();
- reserve_crashkernel();
+ initmem_init(0, max_pfn, acpi, k8);
#ifdef CONFIG_X86_64
/*
diff --git a/arch/x86/kernel/tlb_uv.c b/arch/x86/kernel/tlb_uv.c
index 1740c85..364d015ef 100644
--- a/arch/x86/kernel/tlb_uv.c
+++ b/arch/x86/kernel/tlb_uv.c
@@ -817,10 +817,8 @@ static int __init uv_init_blade(int blade)
*/
apicid = blade_to_first_apicid(blade);
pa = uv_read_global_mmr64(pnode, UVH_BAU_DATA_CONFIG);
- if ((pa & 0xff) != UV_BAU_MESSAGE) {
- uv_write_global_mmr64(pnode, UVH_BAU_DATA_CONFIG,
+ uv_write_global_mmr64(pnode, UVH_BAU_DATA_CONFIG,
((apicid << 32) | UV_BAU_MESSAGE));
- }
return 0;
}
diff --git a/arch/x86/kernel/uv_time.c b/arch/x86/kernel/uv_time.c
index 583f11d..3c84aa0 100644
--- a/arch/x86/kernel/uv_time.c
+++ b/arch/x86/kernel/uv_time.c
@@ -74,7 +74,7 @@ struct uv_rtc_timer_head {
*/
static struct uv_rtc_timer_head **blade_info __read_mostly;
-static int uv_rtc_enable;
+static int uv_rtc_evt_enable;
/*
* Hardware interface routines
@@ -90,7 +90,7 @@ static void uv_rtc_send_IPI(int cpu)
pnode = uv_apicid_to_pnode(apicid);
val = (1UL << UVH_IPI_INT_SEND_SHFT) |
(apicid << UVH_IPI_INT_APIC_ID_SHFT) |
- (GENERIC_INTERRUPT_VECTOR << UVH_IPI_INT_VECTOR_SHFT);
+ (X86_PLATFORM_IPI_VECTOR << UVH_IPI_INT_VECTOR_SHFT);
uv_write_global_mmr64(pnode, UVH_IPI_INT, val);
}
@@ -115,7 +115,7 @@ static int uv_setup_intr(int cpu, u64 expires)
uv_write_global_mmr64(pnode, UVH_EVENT_OCCURRED0_ALIAS,
UVH_EVENT_OCCURRED0_RTC1_MASK);
- val = (GENERIC_INTERRUPT_VECTOR << UVH_RTC1_INT_CONFIG_VECTOR_SHFT) |
+ val = (X86_PLATFORM_IPI_VECTOR << UVH_RTC1_INT_CONFIG_VECTOR_SHFT) |
((u64)cpu_physical_id(cpu) << UVH_RTC1_INT_CONFIG_APIC_ID_SHFT);
/* Set configuration */
@@ -123,7 +123,10 @@ static int uv_setup_intr(int cpu, u64 expires)
/* Initialize comparator value */
uv_write_global_mmr64(pnode, UVH_INT_CMPB, expires);
- return (expires < uv_read_rtc(NULL) && !uv_intr_pending(pnode));
+ if (uv_read_rtc(NULL) <= expires)
+ return 0;
+
+ return !uv_intr_pending(pnode);
}
/*
@@ -223,6 +226,7 @@ static int uv_rtc_set_timer(int cpu, u64 expires)
next_cpu = head->next_cpu;
*t = expires;
+
/* Will this one be next to go off? */
if (next_cpu < 0 || bcpu == next_cpu ||
expires < head->cpu[next_cpu].expires) {
@@ -231,7 +235,7 @@ static int uv_rtc_set_timer(int cpu, u64 expires)
*t = ULLONG_MAX;
uv_rtc_find_next_timer(head, pnode);
spin_unlock_irqrestore(&head->lock, flags);
- return 1;
+ return -ETIME;
}
}
@@ -244,7 +248,7 @@ static int uv_rtc_set_timer(int cpu, u64 expires)
*
* Returns 1 if this timer was pending.
*/
-static int uv_rtc_unset_timer(int cpu)
+static int uv_rtc_unset_timer(int cpu, int force)
{
int pnode = uv_cpu_to_pnode(cpu);
int bid = uv_cpu_to_blade_id(cpu);
@@ -256,14 +260,15 @@ static int uv_rtc_unset_timer(int cpu)
spin_lock_irqsave(&head->lock, flags);
- if (head->next_cpu == bcpu && uv_read_rtc(NULL) >= *t)
+ if ((head->next_cpu == bcpu && uv_read_rtc(NULL) >= *t) || force)
rc = 1;
- *t = ULLONG_MAX;
-
- /* Was the hardware setup for this timer? */
- if (head->next_cpu == bcpu)
- uv_rtc_find_next_timer(head, pnode);
+ if (rc) {
+ *t = ULLONG_MAX;
+ /* Was the hardware setup for this timer? */
+ if (head->next_cpu == bcpu)
+ uv_rtc_find_next_timer(head, pnode);
+ }
spin_unlock_irqrestore(&head->lock, flags);
@@ -310,32 +315,32 @@ static void uv_rtc_timer_setup(enum clock_event_mode mode,
break;
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
- uv_rtc_unset_timer(ced_cpu);
+ uv_rtc_unset_timer(ced_cpu, 1);
break;
}
}
static void uv_rtc_interrupt(void)
{
- struct clock_event_device *ced = &__get_cpu_var(cpu_ced);
int cpu = smp_processor_id();
+ struct clock_event_device *ced = &per_cpu(cpu_ced, cpu);
if (!ced || !ced->event_handler)
return;
- if (uv_rtc_unset_timer(cpu) != 1)
+ if (uv_rtc_unset_timer(cpu, 0) != 1)
return;
ced->event_handler(ced);
}
-static int __init uv_enable_rtc(char *str)
+static int __init uv_enable_evt_rtc(char *str)
{
- uv_rtc_enable = 1;
+ uv_rtc_evt_enable = 1;
return 1;
}
-__setup("uvrtc", uv_enable_rtc);
+__setup("uvrtcevt", uv_enable_evt_rtc);
static __init void uv_rtc_register_clockevents(struct work_struct *dummy)
{
@@ -350,27 +355,32 @@ static __init int uv_rtc_setup_clock(void)
{
int rc;
- if (!uv_rtc_enable || !is_uv_system() || generic_interrupt_extension)
+ if (!is_uv_system())
return -ENODEV;
- generic_interrupt_extension = uv_rtc_interrupt;
-
clocksource_uv.mult = clocksource_hz2mult(sn_rtc_cycles_per_second,
clocksource_uv.shift);
+ /* If single blade, prefer tsc */
+ if (uv_num_possible_blades() == 1)
+ clocksource_uv.rating = 250;
+
rc = clocksource_register(&clocksource_uv);
- if (rc) {
- generic_interrupt_extension = NULL;
+ if (rc)
+ printk(KERN_INFO "UV RTC clocksource failed rc %d\n", rc);
+ else
+ printk(KERN_INFO "UV RTC clocksource registered freq %lu MHz\n",
+ sn_rtc_cycles_per_second/(unsigned long)1E6);
+
+ if (rc || !uv_rtc_evt_enable || x86_platform_ipi_callback)
return rc;
- }
/* Setup and register clockevents */
rc = uv_rtc_allocate_timers();
- if (rc) {
- clocksource_unregister(&clocksource_uv);
- generic_interrupt_extension = NULL;
- return rc;
- }
+ if (rc)
+ goto error;
+
+ x86_platform_ipi_callback = uv_rtc_interrupt;
clock_event_device_uv.mult = div_sc(sn_rtc_cycles_per_second,
NSEC_PER_SEC, clock_event_device_uv.shift);
@@ -383,11 +393,19 @@ static __init int uv_rtc_setup_clock(void)
rc = schedule_on_each_cpu(uv_rtc_register_clockevents);
if (rc) {
- clocksource_unregister(&clocksource_uv);
- generic_interrupt_extension = NULL;
+ x86_platform_ipi_callback = NULL;
uv_rtc_deallocate_timers();
+ goto error;
}
+ printk(KERN_INFO "UV RTC clockevents registered\n");
+
+ return 0;
+
+error:
+ clocksource_unregister(&clocksource_uv);
+ printk(KERN_INFO "UV RTC clockevents failed rc %d\n", rc);
+
return rc;
}
arch_initcall(uv_rtc_setup_clock);
diff --git a/arch/x86/kernel/visws_quirks.c b/arch/x86/kernel/visws_quirks.c
index abda6f5..34a279a 100644
--- a/arch/x86/kernel/visws_quirks.c
+++ b/arch/x86/kernel/visws_quirks.c
@@ -197,7 +197,7 @@ static void __init MP_processor_info(struct mpc_cpu *m)
apic_version[m->apicid] = ver;
}
-static void __init visws_find_smp_config(unsigned int reserve)
+static void __init visws_find_smp_config(void)
{
struct mpc_cpu *mp = phys_to_virt(CO_CPU_TAB_PHYS);
unsigned short ncpus = readw(phys_to_virt(CO_CPU_NUM_PHYS));
diff --git a/arch/x86/kernel/vmiclock_32.c b/arch/x86/kernel/vmiclock_32.c
index 611b9e2..74c92bb 100644
--- a/arch/x86/kernel/vmiclock_32.c
+++ b/arch/x86/kernel/vmiclock_32.c
@@ -226,7 +226,7 @@ static void __devinit vmi_time_init_clockevent(void)
evt->min_delta_ns = clockevent_delta2ns(1, evt);
evt->cpumask = cpumask_of(cpu);
- printk(KERN_WARNING "vmi: registering clock event %s. mult=%lu shift=%u\n",
+ printk(KERN_WARNING "vmi: registering clock event %s. mult=%u shift=%u\n",
evt->name, evt->mult, evt->shift);
clockevents_register_device(evt);
}
diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
index 3c68fe2..f3f2104 100644
--- a/arch/x86/kernel/vmlinux.lds.S
+++ b/arch/x86/kernel/vmlinux.lds.S
@@ -41,6 +41,32 @@ ENTRY(phys_startup_64)
jiffies_64 = jiffies;
#endif
+#if defined(CONFIG_X86_64) && defined(CONFIG_DEBUG_RODATA)
+/*
+ * On 64-bit, align RODATA to 2MB so that even with CONFIG_DEBUG_RODATA
+ * we retain large page mappings for boundaries spanning kernel text, rodata
+ * and data sections.
+ *
+ * However, kernel identity mappings will have different RWX permissions
+ * to the pages mapping to text and to the pages padding (which are freed) the
+ * text section. Hence kernel identity mappings will be broken to smaller
+ * pages. For 64-bit, kernel text and kernel identity mappings are different,
+ * so we can enable protection checks that come with CONFIG_DEBUG_RODATA,
+ * as well as retain 2MB large page mappings for kernel text.
+ */
+#define X64_ALIGN_DEBUG_RODATA_BEGIN . = ALIGN(HPAGE_SIZE);
+
+#define X64_ALIGN_DEBUG_RODATA_END \
+ . = ALIGN(HPAGE_SIZE); \
+ __end_rodata_hpage_align = .;
+
+#else
+
+#define X64_ALIGN_DEBUG_RODATA_BEGIN
+#define X64_ALIGN_DEBUG_RODATA_END
+
+#endif
+
PHDRS {
text PT_LOAD FLAGS(5); /* R_E */
data PT_LOAD FLAGS(7); /* RWE */
@@ -90,7 +116,9 @@ SECTIONS
EXCEPTION_TABLE(16) :text = 0x9090
+ X64_ALIGN_DEBUG_RODATA_BEGIN
RO_DATA(PAGE_SIZE)
+ X64_ALIGN_DEBUG_RODATA_END
/* Data */
.data : AT(ADDR(.data) - LOAD_OFFSET) {
@@ -107,13 +135,13 @@ SECTIONS
PAGE_ALIGNED_DATA(PAGE_SIZE)
- CACHELINE_ALIGNED_DATA(CONFIG_X86_L1_CACHE_BYTES)
+ CACHELINE_ALIGNED_DATA(L1_CACHE_BYTES)
DATA_DATA
CONSTRUCTORS
/* rarely changed data like cpu maps */
- READ_MOSTLY_DATA(CONFIG_X86_INTERNODE_CACHE_BYTES)
+ READ_MOSTLY_DATA(INTERNODE_CACHE_BYTES)
/* End of data section */
_edata = .;
@@ -137,12 +165,12 @@ SECTIONS
*(.vsyscall_0)
} :user
- . = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
+ . = ALIGN(L1_CACHE_BYTES);
.vsyscall_fn : AT(VLOAD(.vsyscall_fn)) {
*(.vsyscall_fn)
}
- . = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
+ . = ALIGN(L1_CACHE_BYTES);
.vsyscall_gtod_data : AT(VLOAD(.vsyscall_gtod_data)) {
*(.vsyscall_gtod_data)
}
@@ -166,7 +194,7 @@ SECTIONS
}
vgetcpu_mode = VVIRT(.vgetcpu_mode);
- . = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
+ . = ALIGN(L1_CACHE_BYTES);
.jiffies : AT(VLOAD(.jiffies)) {
*(.jiffies)
}
diff --git a/arch/x86/kernel/vsyscall_64.c b/arch/x86/kernel/vsyscall_64.c
index e02d92d..9055e58 100644
--- a/arch/x86/kernel/vsyscall_64.c
+++ b/arch/x86/kernel/vsyscall_64.c
@@ -73,7 +73,8 @@ void update_vsyscall_tz(void)
write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, flags);
}
-void update_vsyscall(struct timespec *wall_time, struct clocksource *clock)
+void update_vsyscall(struct timespec *wall_time, struct clocksource *clock,
+ u32 mult)
{
unsigned long flags;
@@ -82,7 +83,7 @@ void update_vsyscall(struct timespec *wall_time, struct clocksource *clock)
vsyscall_gtod_data.clock.vread = clock->vread;
vsyscall_gtod_data.clock.cycle_last = clock->cycle_last;
vsyscall_gtod_data.clock.mask = clock->mask;
- vsyscall_gtod_data.clock.mult = clock->mult;
+ vsyscall_gtod_data.clock.mult = mult;
vsyscall_gtod_data.clock.shift = clock->shift;
vsyscall_gtod_data.wall_time_sec = wall_time->tv_sec;
vsyscall_gtod_data.wall_time_nsec = wall_time->tv_nsec;
diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c
index d11c5ff..ccd179d 100644
--- a/arch/x86/kernel/x86_init.c
+++ b/arch/x86/kernel/x86_init.c
@@ -13,6 +13,7 @@
#include <asm/e820.h>
#include <asm/time.h>
#include <asm/irq.h>
+#include <asm/pat.h>
#include <asm/tsc.h>
#include <asm/iommu.h>
@@ -80,4 +81,5 @@ struct x86_platform_ops x86_platform = {
.get_wallclock = mach_get_cmos_time,
.set_wallclock = mach_set_rtc_mmss,
.iommu_shutdown = iommu_shutdown_noop,
+ .is_untracked_pat_range = is_ISA_range,
};
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
index 73ffd55..d406c52 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
@@ -146,10 +146,6 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,
use_gbpages = direct_gbpages;
#endif
- set_nx();
- if (nx_enabled)
- printk(KERN_INFO "NX (Execute Disable) protection: active\n");
-
/* Enable PSE if available */
if (cpu_has_pse)
set_in_cr4(X86_CR4_PSE);
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c
index 30938c1..c973f8e 100644
--- a/arch/x86/mm/init_32.c
+++ b/arch/x86/mm/init_32.c
@@ -412,7 +412,7 @@ static void __init permanent_kmaps_init(pgd_t *pgd_base)
pkmap_page_table = pte;
}
-static void __init add_one_highpage_init(struct page *page, int pfn)
+static void __init add_one_highpage_init(struct page *page)
{
ClearPageReserved(page);
init_page_count(page);
@@ -445,7 +445,7 @@ static int __init add_highpages_work_fn(unsigned long start_pfn,
if (!pfn_valid(node_pfn))
continue;
page = pfn_to_page(node_pfn);
- add_one_highpage_init(page, node_pfn);
+ add_one_highpage_init(page);
}
return 0;
@@ -703,8 +703,8 @@ void __init find_low_pfn_range(void)
}
#ifndef CONFIG_NEED_MULTIPLE_NODES
-void __init initmem_init(unsigned long start_pfn,
- unsigned long end_pfn)
+void __init initmem_init(unsigned long start_pfn, unsigned long end_pfn,
+ int acpi, int k8)
{
#ifdef CONFIG_HIGHMEM
highstart_pfn = highend_pfn = max_pfn;
@@ -997,7 +997,7 @@ static noinline int do_test_wp_bit(void)
const int rodata_test_data = 0xC3;
EXPORT_SYMBOL_GPL(rodata_test_data);
-static int kernel_set_to_readonly;
+int kernel_set_to_readonly __read_mostly;
void set_kernel_text_rw(void)
{
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index 5a4398a..5198b9b 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -568,7 +568,8 @@ kernel_physical_mapping_init(unsigned long start,
}
#ifndef CONFIG_NUMA
-void __init initmem_init(unsigned long start_pfn, unsigned long end_pfn)
+void __init initmem_init(unsigned long start_pfn, unsigned long end_pfn,
+ int acpi, int k8)
{
unsigned long bootmap_size, bootmap;
@@ -694,12 +695,12 @@ void __init mem_init(void)
const int rodata_test_data = 0xC3;
EXPORT_SYMBOL_GPL(rodata_test_data);
-static int kernel_set_to_readonly;
+int kernel_set_to_readonly;
void set_kernel_text_rw(void)
{
- unsigned long start = PFN_ALIGN(_stext);
- unsigned long end = PFN_ALIGN(__start_rodata);
+ unsigned long start = PFN_ALIGN(_text);
+ unsigned long end = PFN_ALIGN(__stop___ex_table);
if (!kernel_set_to_readonly)
return;
@@ -707,13 +708,18 @@ void set_kernel_text_rw(void)
pr_debug("Set kernel text: %lx - %lx for read write\n",
start, end);
+ /*
+ * Make the kernel identity mapping for text RW. Kernel text
+ * mapping will always be RO. Refer to the comment in
+ * static_protections() in pageattr.c
+ */
set_memory_rw(start, (end - start) >> PAGE_SHIFT);
}
void set_kernel_text_ro(void)
{
- unsigned long start = PFN_ALIGN(_stext);
- unsigned long end = PFN_ALIGN(__start_rodata);
+ unsigned long start = PFN_ALIGN(_text);
+ unsigned long end = PFN_ALIGN(__stop___ex_table);
if (!kernel_set_to_readonly)
return;
@@ -721,14 +727,21 @@ void set_kernel_text_ro(void)
pr_debug("Set kernel text: %lx - %lx for read only\n",
start, end);
+ /*
+ * Set the kernel identity mapping for text RO.
+ */
set_memory_ro(start, (end - start) >> PAGE_SHIFT);
}
void mark_rodata_ro(void)
{
- unsigned long start = PFN_ALIGN(_stext), end = PFN_ALIGN(__end_rodata);
+ unsigned long start = PFN_ALIGN(_text);
unsigned long rodata_start =
((unsigned long)__start_rodata + PAGE_SIZE - 1) & PAGE_MASK;
+ unsigned long end = (unsigned long) &__end_rodata_hpage_align;
+ unsigned long text_end = PAGE_ALIGN((unsigned long) &__stop___ex_table);
+ unsigned long rodata_end = PAGE_ALIGN((unsigned long) &__end_rodata);
+ unsigned long data_start = (unsigned long) &_sdata;
printk(KERN_INFO "Write protecting the kernel read-only data: %luk\n",
(end - start) >> 10);
@@ -751,6 +764,14 @@ void mark_rodata_ro(void)
printk(KERN_INFO "Testing CPA: again\n");
set_memory_ro(start, (end-start) >> PAGE_SHIFT);
#endif
+
+ free_init_pages("unused kernel memory",
+ (unsigned long) page_address(virt_to_page(text_end)),
+ (unsigned long)
+ page_address(virt_to_page(rodata_start)));
+ free_init_pages("unused kernel memory",
+ (unsigned long) page_address(virt_to_page(rodata_end)),
+ (unsigned long) page_address(virt_to_page(data_start)));
}
#endif
diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
index 2feb9bd..c246d25 100644
--- a/arch/x86/mm/ioremap.c
+++ b/arch/x86/mm/ioremap.c
@@ -281,30 +281,6 @@ void __iomem *ioremap_cache(resource_size_t phys_addr, unsigned long size)
}
EXPORT_SYMBOL(ioremap_cache);
-static void __iomem *ioremap_default(resource_size_t phys_addr,
- unsigned long size)
-{
- unsigned long flags;
- void __iomem *ret;
- int err;
-
- /*
- * - WB for WB-able memory and no other conflicting mappings
- * - UC_MINUS for non-WB-able memory with no other conflicting mappings
- * - Inherit from confliting mappings otherwise
- */
- err = reserve_memtype(phys_addr, phys_addr + size,
- _PAGE_CACHE_WB, &flags);
- if (err < 0)
- return NULL;
-
- ret = __ioremap_caller(phys_addr, size, flags,
- __builtin_return_address(0));
-
- free_memtype(phys_addr, phys_addr + size);
- return ret;
-}
-
void __iomem *ioremap_prot(resource_size_t phys_addr, unsigned long size,
unsigned long prot_val)
{
@@ -380,7 +356,7 @@ void *xlate_dev_mem_ptr(unsigned long phys)
if (page_is_ram(start >> PAGE_SHIFT))
return __va(phys);
- addr = (void __force *)ioremap_default(start, PAGE_SIZE);
+ addr = (void __force *)ioremap_cache(start, PAGE_SIZE);
if (addr)
addr = (void *)((unsigned long)addr | (phys & ~PAGE_MASK));
diff --git a/arch/x86/mm/k8topology_64.c b/arch/x86/mm/k8topology_64.c
index 268f825..970ed57 100644
--- a/arch/x86/mm/k8topology_64.c
+++ b/arch/x86/mm/k8topology_64.c
@@ -24,6 +24,9 @@
#include <asm/apic.h>
#include <asm/k8.h>
+static struct bootnode __initdata nodes[8];
+static nodemask_t __initdata nodes_parsed = NODE_MASK_NONE;
+
static __init int find_northbridge(void)
{
int num;
@@ -54,18 +57,6 @@ static __init void early_get_boot_cpu_id(void)
* need to get boot_cpu_id so can use that to create apicid_to_node
* in k8_scan_nodes()
*/
- /*
- * Find possible boot-time SMP configuration:
- */
-#ifdef CONFIG_X86_MPPARSE
- early_find_smp_config();
-#endif
-#ifdef CONFIG_ACPI
- /*
- * Read APIC information from ACPI tables.
- */
- early_acpi_boot_init();
-#endif
#ifdef CONFIG_X86_MPPARSE
/*
* get boot-time SMP configuration:
@@ -76,12 +67,26 @@ static __init void early_get_boot_cpu_id(void)
early_init_lapic_mapping();
}
-int __init k8_scan_nodes(unsigned long start, unsigned long end)
+int __init k8_get_nodes(struct bootnode *physnodes)
{
- unsigned numnodes, cores, bits, apicid_base;
+ int i;
+ int ret = 0;
+
+ for_each_node_mask(i, nodes_parsed) {
+ physnodes[ret].start = nodes[i].start;
+ physnodes[ret].end = nodes[i].end;
+ ret++;
+ }
+ return ret;
+}
+
+int __init k8_numa_init(unsigned long start_pfn, unsigned long end_pfn)
+{
+ unsigned long start = PFN_PHYS(start_pfn);
+ unsigned long end = PFN_PHYS(end_pfn);
+ unsigned numnodes;
unsigned long prevbase;
- struct bootnode nodes[8];
- int i, j, nb, found = 0;
+ int i, nb, found = 0;
u32 nodeid, reg;
if (!early_pci_allowed())
@@ -91,16 +96,15 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)
if (nb < 0)
return nb;
- printk(KERN_INFO "Scanning NUMA topology in Northbridge %d\n", nb);
+ pr_info("Scanning NUMA topology in Northbridge %d\n", nb);
reg = read_pci_config(0, nb, 0, 0x60);
numnodes = ((reg >> 4) & 0xF) + 1;
if (numnodes <= 1)
return -1;
- printk(KERN_INFO "Number of nodes %d\n", numnodes);
+ pr_info("Number of physical nodes %d\n", numnodes);
- memset(&nodes, 0, sizeof(nodes));
prevbase = 0;
for (i = 0; i < 8; i++) {
unsigned long base, limit;
@@ -111,28 +115,28 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)
nodeid = limit & 7;
if ((base & 3) == 0) {
if (i < numnodes)
- printk("Skipping disabled node %d\n", i);
+ pr_info("Skipping disabled node %d\n", i);
continue;
}
if (nodeid >= numnodes) {
- printk("Ignoring excess node %d (%lx:%lx)\n", nodeid,
- base, limit);
+ pr_info("Ignoring excess node %d (%lx:%lx)\n", nodeid,
+ base, limit);
continue;
}
if (!limit) {
- printk(KERN_INFO "Skipping node entry %d (base %lx)\n",
- i, base);
+ pr_info("Skipping node entry %d (base %lx)\n",
+ i, base);
continue;
}
if ((base >> 8) & 3 || (limit >> 8) & 3) {
- printk(KERN_ERR "Node %d using interleaving mode %lx/%lx\n",
- nodeid, (base>>8)&3, (limit>>8) & 3);
+ pr_err("Node %d using interleaving mode %lx/%lx\n",
+ nodeid, (base >> 8) & 3, (limit >> 8) & 3);
return -1;
}
- if (node_isset(nodeid, node_possible_map)) {
- printk(KERN_INFO "Node %d already present. Skipping\n",
- nodeid);
+ if (node_isset(nodeid, nodes_parsed)) {
+ pr_info("Node %d already present, skipping\n",
+ nodeid);
continue;
}
@@ -141,8 +145,8 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)
limit |= (1<<24)-1;
limit++;
- if (limit > max_pfn << PAGE_SHIFT)
- limit = max_pfn << PAGE_SHIFT;
+ if (limit > end)
+ limit = end;
if (limit <= base)
continue;
@@ -154,24 +158,24 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)
if (limit > end)
limit = end;
if (limit == base) {
- printk(KERN_ERR "Empty node %d\n", nodeid);
+ pr_err("Empty node %d\n", nodeid);
continue;
}
if (limit < base) {
- printk(KERN_ERR "Node %d bogus settings %lx-%lx.\n",
+ pr_err("Node %d bogus settings %lx-%lx.\n",
nodeid, base, limit);
continue;
}
/* Could sort here, but pun for now. Should not happen anyroads. */
if (prevbase > base) {
- printk(KERN_ERR "Node map not sorted %lx,%lx\n",
+ pr_err("Node map not sorted %lx,%lx\n",
prevbase, base);
return -1;
}
- printk(KERN_INFO "Node %d MemBase %016lx Limit %016lx\n",
- nodeid, base, limit);
+ pr_info("Node %d MemBase %016lx Limit %016lx\n",
+ nodeid, base, limit);
found++;
@@ -180,18 +184,29 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)
prevbase = base;
- node_set(nodeid, node_possible_map);
+ node_set(nodeid, nodes_parsed);
}
if (!found)
return -1;
+ return 0;
+}
+
+int __init k8_scan_nodes(void)
+{
+ unsigned int bits;
+ unsigned int cores;
+ unsigned int apicid_base;
+ int i;
+ BUG_ON(nodes_empty(nodes_parsed));
+ node_possible_map = nodes_parsed;
memnode_shift = compute_hash_shift(nodes, 8, NULL);
if (memnode_shift < 0) {
- printk(KERN_ERR "No NUMA node hash function found. Contact maintainer\n");
+ pr_err("No NUMA node hash function found. Contact maintainer\n");
return -1;
}
- printk(KERN_INFO "Using node hash shift of %d\n", memnode_shift);
+ pr_info("Using node hash shift of %d\n", memnode_shift);
/* use the coreid bits from early_identify_cpu */
bits = boot_cpu_data.x86_coreid_bits;
@@ -200,14 +215,12 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)
/* need to get boot_cpu_id early for system with apicid lifting */
early_get_boot_cpu_id();
if (boot_cpu_physical_apicid > 0) {
- printk(KERN_INFO "BSP APIC ID: %02x\n",
- boot_cpu_physical_apicid);
+ pr_info("BSP APIC ID: %02x\n", boot_cpu_physical_apicid);
apicid_base = boot_cpu_physical_apicid;
}
- for (i = 0; i < 8; i++) {
- if (nodes[i].start == nodes[i].end)
- continue;
+ for_each_node_mask(i, node_possible_map) {
+ int j;
e820_register_active_regions(i,
nodes[i].start >> PAGE_SHIFT,
diff --git a/arch/x86/mm/kmmio.c b/arch/x86/mm/kmmio.c
index 11a4ad4..07bcc30 100644
--- a/arch/x86/mm/kmmio.c
+++ b/arch/x86/mm/kmmio.c
@@ -203,7 +203,7 @@ static void disarm_kmmio_fault_page(struct kmmio_fault_page *f)
*/
/*
* Interrupts are disabled on entry as trap3 is an interrupt gate
- * and they remain disabled thorough out this function.
+ * and they remain disabled throughout this function.
*/
int kmmio_handler(struct pt_regs *regs, unsigned long addr)
{
@@ -302,7 +302,7 @@ no_kmmio:
/*
* Interrupts are disabled on entry as trap1 is an interrupt gate
- * and they remain disabled thorough out this function.
+ * and they remain disabled throughout this function.
* This must always get called as the pair to kmmio_handler().
*/
static int post_kmmio_handler(unsigned long condition, struct pt_regs *regs)
diff --git a/arch/x86/mm/numa_32.c b/arch/x86/mm/numa_32.c
index d253006..b20760c 100644
--- a/arch/x86/mm/numa_32.c
+++ b/arch/x86/mm/numa_32.c
@@ -347,8 +347,8 @@ static void init_remap_allocator(int nid)
(ulong) node_remap_end_vaddr[nid]);
}
-void __init initmem_init(unsigned long start_pfn,
- unsigned long end_pfn)
+void __init initmem_init(unsigned long start_pfn, unsigned long end_pfn,
+ int acpi, int k8)
{
int nid;
long kva_target_pfn;
diff --git a/arch/x86/mm/numa_64.c b/arch/x86/mm/numa_64.c
index 459913b..83bbc70 100644
--- a/arch/x86/mm/numa_64.c
+++ b/arch/x86/mm/numa_64.c
@@ -239,8 +239,14 @@ setup_node_bootmem(int nodeid, unsigned long start, unsigned long end)
bootmap = early_node_mem(nodeid, bootmap_start, end,
bootmap_pages<<PAGE_SHIFT, PAGE_SIZE);
if (bootmap == NULL) {
- if (nodedata_phys < start || nodedata_phys >= end)
- free_bootmem(nodedata_phys, pgdat_size);
+ if (nodedata_phys < start || nodedata_phys >= end) {
+ /*
+ * only need to free it if it is from other node
+ * bootmem
+ */
+ if (nid != nodeid)
+ free_bootmem(nodedata_phys, pgdat_size);
+ }
node_data[nodeid] = NULL;
return;
}
@@ -306,8 +312,71 @@ void __init numa_init_array(void)
#ifdef CONFIG_NUMA_EMU
/* Numa emulation */
+static struct bootnode nodes[MAX_NUMNODES] __initdata;
+static struct bootnode physnodes[MAX_NUMNODES] __initdata;
static char *cmdline __initdata;
+static int __init setup_physnodes(unsigned long start, unsigned long end,
+ int acpi, int k8)
+{
+ int nr_nodes = 0;
+ int ret = 0;
+ int i;
+
+#ifdef CONFIG_ACPI_NUMA
+ if (acpi)
+ nr_nodes = acpi_get_nodes(physnodes);
+#endif
+#ifdef CONFIG_K8_NUMA
+ if (k8)
+ nr_nodes = k8_get_nodes(physnodes);
+#endif
+ /*
+ * Basic sanity checking on the physical node map: there may be errors
+ * if the SRAT or K8 incorrectly reported the topology or the mem=
+ * kernel parameter is used.
+ */
+ for (i = 0; i < nr_nodes; i++) {
+ if (physnodes[i].start == physnodes[i].end)
+ continue;
+ if (physnodes[i].start > end) {
+ physnodes[i].end = physnodes[i].start;
+ continue;
+ }
+ if (physnodes[i].end < start) {
+ physnodes[i].start = physnodes[i].end;
+ continue;
+ }
+ if (physnodes[i].start < start)
+ physnodes[i].start = start;
+ if (physnodes[i].end > end)
+ physnodes[i].end = end;
+ }
+
+ /*
+ * Remove all nodes that have no memory or were truncated because of the
+ * limited address range.
+ */
+ for (i = 0; i < nr_nodes; i++) {
+ if (physnodes[i].start == physnodes[i].end)
+ continue;
+ physnodes[ret].start = physnodes[i].start;
+ physnodes[ret].end = physnodes[i].end;
+ ret++;
+ }
+
+ /*
+ * If no physical topology was detected, a single node is faked to cover
+ * the entire address space.
+ */
+ if (!ret) {
+ physnodes[ret].start = start;
+ physnodes[ret].end = end;
+ ret = 1;
+ }
+ return ret;
+}
+
/*
* Setups up nid to range from addr to addr + size. If the end
* boundary is greater than max_addr, then max_addr is used instead.
@@ -315,11 +384,9 @@ static char *cmdline __initdata;
* allocation past addr and -1 otherwise. addr is adjusted to be at
* the end of the node.
*/
-static int __init setup_node_range(int nid, struct bootnode *nodes, u64 *addr,
- u64 size, u64 max_addr)
+static int __init setup_node_range(int nid, u64 *addr, u64 size, u64 max_addr)
{
int ret = 0;
-
nodes[nid].start = *addr;
*addr += size;
if (*addr >= max_addr) {
@@ -335,12 +402,111 @@ static int __init setup_node_range(int nid, struct bootnode *nodes, u64 *addr,
}
/*
+ * Sets up nr_nodes fake nodes interleaved over physical nodes ranging from addr
+ * to max_addr. The return value is the number of nodes allocated.
+ */
+static int __init split_nodes_interleave(u64 addr, u64 max_addr,
+ int nr_phys_nodes, int nr_nodes)
+{
+ nodemask_t physnode_mask = NODE_MASK_NONE;
+ u64 size;
+ int big;
+ int ret = 0;
+ int i;
+
+ if (nr_nodes <= 0)
+ return -1;
+ if (nr_nodes > MAX_NUMNODES) {
+ pr_info("numa=fake=%d too large, reducing to %d\n",
+ nr_nodes, MAX_NUMNODES);
+ nr_nodes = MAX_NUMNODES;
+ }
+
+ size = (max_addr - addr - e820_hole_size(addr, max_addr)) / nr_nodes;
+ /*
+ * Calculate the number of big nodes that can be allocated as a result
+ * of consolidating the remainder.
+ */
+ big = ((size & ~FAKE_NODE_MIN_HASH_MASK) & nr_nodes) /
+ FAKE_NODE_MIN_SIZE;
+
+ size &= FAKE_NODE_MIN_HASH_MASK;
+ if (!size) {
+ pr_err("Not enough memory for each node. "
+ "NUMA emulation disabled.\n");
+ return -1;
+ }
+
+ for (i = 0; i < nr_phys_nodes; i++)
+ if (physnodes[i].start != physnodes[i].end)
+ node_set(i, physnode_mask);
+
+ /*
+ * Continue to fill physical nodes with fake nodes until there is no
+ * memory left on any of them.
+ */
+ while (nodes_weight(physnode_mask)) {
+ for_each_node_mask(i, physnode_mask) {
+ u64 end = physnodes[i].start + size;
+ u64 dma32_end = PFN_PHYS(MAX_DMA32_PFN);
+
+ if (ret < big)
+ end += FAKE_NODE_MIN_SIZE;
+
+ /*
+ * Continue to add memory to this fake node if its
+ * non-reserved memory is less than the per-node size.
+ */
+ while (end - physnodes[i].start -
+ e820_hole_size(physnodes[i].start, end) < size) {
+ end += FAKE_NODE_MIN_SIZE;
+ if (end > physnodes[i].end) {
+ end = physnodes[i].end;
+ break;
+ }
+ }
+
+ /*
+ * If there won't be at least FAKE_NODE_MIN_SIZE of
+ * non-reserved memory in ZONE_DMA32 for the next node,
+ * this one must extend to the boundary.
+ */
+ if (end < dma32_end && dma32_end - end -
+ e820_hole_size(end, dma32_end) < FAKE_NODE_MIN_SIZE)
+ end = dma32_end;
+
+ /*
+ * If there won't be enough non-reserved memory for the
+ * next node, this one must extend to the end of the
+ * physical node.
+ */
+ if (physnodes[i].end - end -
+ e820_hole_size(end, physnodes[i].end) < size)
+ end = physnodes[i].end;
+
+ /*
+ * Avoid allocating more nodes than requested, which can
+ * happen as a result of rounding down each node's size
+ * to FAKE_NODE_MIN_SIZE.
+ */
+ if (nodes_weight(physnode_mask) + ret >= nr_nodes)
+ end = physnodes[i].end;
+
+ if (setup_node_range(ret++, &physnodes[i].start,
+ end - physnodes[i].start,
+ physnodes[i].end) < 0)
+ node_clear(i, physnode_mask);
+ }
+ }
+ return ret;
+}
+
+/*
* Splits num_nodes nodes up equally starting at node_start. The return value
* is the number of nodes split up and addr is adjusted to be at the end of the
* last node allocated.
*/
-static int __init split_nodes_equally(struct bootnode *nodes, u64 *addr,
- u64 max_addr, int node_start,
+static int __init split_nodes_equally(u64 *addr, u64 max_addr, int node_start,
int num_nodes)
{
unsigned int big;
@@ -388,7 +554,7 @@ static int __init split_nodes_equally(struct bootnode *nodes, u64 *addr,
break;
}
}
- if (setup_node_range(i, nodes, addr, end - *addr, max_addr) < 0)
+ if (setup_node_range(i, addr, end - *addr, max_addr) < 0)
break;
}
return i - node_start + 1;
@@ -399,12 +565,12 @@ static int __init split_nodes_equally(struct bootnode *nodes, u64 *addr,
* always assigned to a final node and can be asymmetric. Returns the number of
* nodes split.
*/
-static int __init split_nodes_by_size(struct bootnode *nodes, u64 *addr,
- u64 max_addr, int node_start, u64 size)
+static int __init split_nodes_by_size(u64 *addr, u64 max_addr, int node_start,
+ u64 size)
{
int i = node_start;
size = (size << 20) & FAKE_NODE_MIN_HASH_MASK;
- while (!setup_node_range(i++, nodes, addr, size, max_addr))
+ while (!setup_node_range(i++, addr, size, max_addr))
;
return i - node_start;
}
@@ -413,15 +579,15 @@ static int __init split_nodes_by_size(struct bootnode *nodes, u64 *addr,
* Sets up the system RAM area from start_pfn to last_pfn according to the
* numa=fake command-line option.
*/
-static struct bootnode nodes[MAX_NUMNODES] __initdata;
-
-static int __init numa_emulation(unsigned long start_pfn, unsigned long last_pfn)
+static int __init numa_emulation(unsigned long start_pfn,
+ unsigned long last_pfn, int acpi, int k8)
{
u64 size, addr = start_pfn << PAGE_SHIFT;
u64 max_addr = last_pfn << PAGE_SHIFT;
int num_nodes = 0, num = 0, coeff_flag, coeff = -1, i;
+ int num_phys_nodes;
- memset(&nodes, 0, sizeof(nodes));
+ num_phys_nodes = setup_physnodes(addr, max_addr, acpi, k8);
/*
* If the numa=fake command-line is just a single number N, split the
* system RAM into N fake nodes.
@@ -429,7 +595,8 @@ static int __init numa_emulation(unsigned long start_pfn, unsigned long last_pfn
if (!strchr(cmdline, '*') && !strchr(cmdline, ',')) {
long n = simple_strtol(cmdline, NULL, 0);
- num_nodes = split_nodes_equally(nodes, &addr, max_addr, 0, n);
+ num_nodes = split_nodes_interleave(addr, max_addr,
+ num_phys_nodes, n);
if (num_nodes < 0)
return num_nodes;
goto out;
@@ -456,8 +623,8 @@ static int __init numa_emulation(unsigned long start_pfn, unsigned long last_pfn
size = ((u64)num << 20) & FAKE_NODE_MIN_HASH_MASK;
if (size)
for (i = 0; i < coeff; i++, num_nodes++)
- if (setup_node_range(num_nodes, nodes,
- &addr, size, max_addr) < 0)
+ if (setup_node_range(num_nodes, &addr,
+ size, max_addr) < 0)
goto done;
if (!*cmdline)
break;
@@ -473,7 +640,7 @@ done:
if (addr < max_addr) {
if (coeff_flag && coeff < 0) {
/* Split remaining nodes into num-sized chunks */
- num_nodes += split_nodes_by_size(nodes, &addr, max_addr,
+ num_nodes += split_nodes_by_size(&addr, max_addr,
num_nodes, num);
goto out;
}
@@ -482,7 +649,7 @@ done:
/* Split remaining nodes into coeff chunks */
if (coeff <= 0)
break;
- num_nodes += split_nodes_equally(nodes, &addr, max_addr,
+ num_nodes += split_nodes_equally(&addr, max_addr,
num_nodes, coeff);
break;
case ',':
@@ -490,8 +657,8 @@ done:
break;
default:
/* Give one final node */
- setup_node_range(num_nodes, nodes, &addr,
- max_addr - addr, max_addr);
+ setup_node_range(num_nodes, &addr, max_addr - addr,
+ max_addr);
num_nodes++;
}
}
@@ -505,14 +672,10 @@ out:
}
/*
- * We need to vacate all active ranges that may have been registered by
- * SRAT and set acpi_numa to -1 so that srat_disabled() always returns
- * true. NUMA emulation has succeeded so we will not scan ACPI nodes.
+ * We need to vacate all active ranges that may have been registered for
+ * the e820 memory map.
*/
remove_all_active_ranges();
-#ifdef CONFIG_ACPI_NUMA
- acpi_numa = -1;
-#endif
for_each_node_mask(i, node_possible_map) {
e820_register_active_regions(i, nodes[i].start >> PAGE_SHIFT,
nodes[i].end >> PAGE_SHIFT);
@@ -524,7 +687,8 @@ out:
}
#endif /* CONFIG_NUMA_EMU */
-void __init initmem_init(unsigned long start_pfn, unsigned long last_pfn)
+void __init initmem_init(unsigned long start_pfn, unsigned long last_pfn,
+ int acpi, int k8)
{
int i;
@@ -532,23 +696,22 @@ void __init initmem_init(unsigned long start_pfn, unsigned long last_pfn)
nodes_clear(node_online_map);
#ifdef CONFIG_NUMA_EMU
- if (cmdline && !numa_emulation(start_pfn, last_pfn))
+ if (cmdline && !numa_emulation(start_pfn, last_pfn, acpi, k8))
return;
nodes_clear(node_possible_map);
nodes_clear(node_online_map);
#endif
#ifdef CONFIG_ACPI_NUMA
- if (!numa_off && !acpi_scan_nodes(start_pfn << PAGE_SHIFT,
- last_pfn << PAGE_SHIFT))
+ if (!numa_off && acpi && !acpi_scan_nodes(start_pfn << PAGE_SHIFT,
+ last_pfn << PAGE_SHIFT))
return;
nodes_clear(node_possible_map);
nodes_clear(node_online_map);
#endif
#ifdef CONFIG_K8_NUMA
- if (!numa_off && !k8_scan_nodes(start_pfn<<PAGE_SHIFT,
- last_pfn<<PAGE_SHIFT))
+ if (!numa_off && k8 && !k8_scan_nodes())
return;
nodes_clear(node_possible_map);
nodes_clear(node_online_map);
@@ -601,6 +764,25 @@ static __init int numa_setup(char *opt)
early_param("numa", numa_setup);
#ifdef CONFIG_NUMA
+
+static __init int find_near_online_node(int node)
+{
+ int n, val;
+ int min_val = INT_MAX;
+ int best_node = -1;
+
+ for_each_online_node(n) {
+ val = node_distance(node, n);
+
+ if (val < min_val) {
+ min_val = val;
+ best_node = n;
+ }
+ }
+
+ return best_node;
+}
+
/*
* Setup early cpu_to_node.
*
@@ -632,7 +814,7 @@ void __init init_cpu_to_node(void)
if (node == NUMA_NO_NODE)
continue;
if (!node_online(node))
- continue;
+ node = find_near_online_node(node);
numa_set_node(cpu, node);
}
}
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index dd38bfb..1d4eb93 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -279,6 +279,22 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address,
__pa((unsigned long)__end_rodata) >> PAGE_SHIFT))
pgprot_val(forbidden) |= _PAGE_RW;
+#if defined(CONFIG_X86_64) && defined(CONFIG_DEBUG_RODATA)
+ /*
+ * Once the kernel maps the text as RO (kernel_set_to_readonly is set),
+ * kernel text mappings for the large page aligned text, rodata sections
+ * will be always read-only. For the kernel identity mappings covering
+ * the holes caused by this alignment can be anything that user asks.
+ *
+ * This will preserve the large page mappings for kernel text/data
+ * at no extra cost.
+ */
+ if (kernel_set_to_readonly &&
+ within(address, (unsigned long)_text,
+ (unsigned long)__end_rodata_hpage_align))
+ pgprot_val(forbidden) |= _PAGE_RW;
+#endif
+
prot = __pgprot(pgprot_val(prot) & ~pgprot_val(forbidden));
return prot;
@@ -1069,12 +1085,18 @@ EXPORT_SYMBOL(set_memory_array_wb);
int set_memory_x(unsigned long addr, int numpages)
{
+ if (!(__supported_pte_mask & _PAGE_NX))
+ return 0;
+
return change_page_attr_clear(&addr, numpages, __pgprot(_PAGE_NX), 0);
}
EXPORT_SYMBOL(set_memory_x);
int set_memory_nx(unsigned long addr, int numpages)
{
+ if (!(__supported_pte_mask & _PAGE_NX))
+ return 0;
+
return change_page_attr_set(&addr, numpages, __pgprot(_PAGE_NX), 0);
}
EXPORT_SYMBOL(set_memory_nx);
diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c
index e78cd0e..66b55d6 100644
--- a/arch/x86/mm/pat.c
+++ b/arch/x86/mm/pat.c
@@ -20,6 +20,7 @@
#include <asm/cacheflush.h>
#include <asm/processor.h>
#include <asm/tlbflush.h>
+#include <asm/x86_init.h>
#include <asm/pgtable.h>
#include <asm/fcntl.h>
#include <asm/e820.h>
@@ -355,9 +356,6 @@ static int free_ram_pages_type(u64 start, u64 end)
* - _PAGE_CACHE_UC_MINUS
* - _PAGE_CACHE_UC
*
- * req_type will have a special case value '-1', when requester want to inherit
- * the memory type from mtrr (if WB), existing PAT, defaulting to UC_MINUS.
- *
* If new_type is NULL, function will return an error if it cannot reserve the
* region with req_type. If new_type is non-NULL, function will return
* available type in new_type in case of no error. In case of any error
@@ -377,9 +375,7 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type,
if (!pat_enabled) {
/* This is identical to page table setting without PAT */
if (new_type) {
- if (req_type == -1)
- *new_type = _PAGE_CACHE_WB;
- else if (req_type == _PAGE_CACHE_WC)
+ if (req_type == _PAGE_CACHE_WC)
*new_type = _PAGE_CACHE_UC_MINUS;
else
*new_type = req_type & _PAGE_CACHE_MASK;
@@ -388,7 +384,7 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type,
}
/* Low ISA region is always mapped WB in page table. No need to track */
- if (is_ISA_range(start, end - 1)) {
+ if (x86_platform.is_untracked_pat_range(start, end)) {
if (new_type)
*new_type = _PAGE_CACHE_WB;
return 0;
@@ -499,7 +495,7 @@ int free_memtype(u64 start, u64 end)
return 0;
/* Low ISA region is always mapped WB. No need to track */
- if (is_ISA_range(start, end - 1))
+ if (x86_platform.is_untracked_pat_range(start, end))
return 0;
is_range_ram = pat_pagerange_is_ram(start, end);
@@ -582,7 +578,7 @@ static unsigned long lookup_memtype(u64 paddr)
int rettype = _PAGE_CACHE_WB;
struct memtype *entry;
- if (is_ISA_range(paddr, paddr + PAGE_SIZE - 1))
+ if (x86_platform.is_untracked_pat_range(paddr, paddr + PAGE_SIZE))
return rettype;
if (pat_pagerange_is_ram(paddr, paddr + PAGE_SIZE)) {
@@ -1018,8 +1014,10 @@ static const struct file_operations memtype_fops = {
static int __init pat_memtype_list_init(void)
{
- debugfs_create_file("pat_memtype_list", S_IRUSR, arch_debugfs_dir,
- NULL, &memtype_fops);
+ if (pat_enabled) {
+ debugfs_create_file("pat_memtype_list", S_IRUSR,
+ arch_debugfs_dir, NULL, &memtype_fops);
+ }
return 0;
}
diff --git a/arch/x86/mm/setup_nx.c b/arch/x86/mm/setup_nx.c
index 513d8ed..a3250aa 100644
--- a/arch/x86/mm/setup_nx.c
+++ b/arch/x86/mm/setup_nx.c
@@ -3,10 +3,8 @@
#include <linux/init.h>
#include <asm/pgtable.h>
+#include <asm/proto.h>
-int nx_enabled;
-
-#if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE)
static int disable_nx __cpuinitdata;
/*
@@ -22,48 +20,41 @@ static int __init noexec_setup(char *str)
if (!str)
return -EINVAL;
if (!strncmp(str, "on", 2)) {
- __supported_pte_mask |= _PAGE_NX;
disable_nx = 0;
} else if (!strncmp(str, "off", 3)) {
disable_nx = 1;
- __supported_pte_mask &= ~_PAGE_NX;
}
+ x86_configure_nx();
return 0;
}
early_param("noexec", noexec_setup);
-#endif
-#ifdef CONFIG_X86_PAE
-void __init set_nx(void)
+void __cpuinit x86_configure_nx(void)
{
- unsigned int v[4], l, h;
-
- if (cpu_has_pae && (cpuid_eax(0x80000000) > 0x80000001)) {
- cpuid(0x80000001, &v[0], &v[1], &v[2], &v[3]);
+ if (cpu_has_nx && !disable_nx)
+ __supported_pte_mask |= _PAGE_NX;
+ else
+ __supported_pte_mask &= ~_PAGE_NX;
+}
- if ((v[3] & (1 << 20)) && !disable_nx) {
- rdmsr(MSR_EFER, l, h);
- l |= EFER_NX;
- wrmsr(MSR_EFER, l, h);
- nx_enabled = 1;
- __supported_pte_mask |= _PAGE_NX;
+void __init x86_report_nx(void)
+{
+ if (!cpu_has_nx) {
+ printk(KERN_NOTICE "Notice: NX (Execute Disable) protection "
+ "missing in CPU or disabled in BIOS!\n");
+ } else {
+#if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE)
+ if (disable_nx) {
+ printk(KERN_INFO "NX (Execute Disable) protection: "
+ "disabled by kernel command line option\n");
+ } else {
+ printk(KERN_INFO "NX (Execute Disable) protection: "
+ "active\n");
}
- }
-}
#else
-void set_nx(void)
-{
-}
+ /* 32bit non-PAE kernel, NX cannot be used */
+ printk(KERN_NOTICE "Notice: NX (Execute Disable) protection "
+ "cannot be enabled: non-PAE kernel!\n");
#endif
-
-#ifdef CONFIG_X86_64
-void __cpuinit check_efer(void)
-{
- unsigned long efer;
-
- rdmsrl(MSR_EFER, efer);
- if (!(efer & EFER_NX) || disable_nx)
- __supported_pte_mask &= ~_PAGE_NX;
+ }
}
-#endif
-
diff --git a/arch/x86/mm/srat_64.c b/arch/x86/mm/srat_64.c
index 9d7ce96..d890754 100644
--- a/arch/x86/mm/srat_64.c
+++ b/arch/x86/mm/srat_64.c
@@ -290,8 +290,6 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
printk(KERN_INFO "SRAT: Node %u PXM %u %lx-%lx\n", node, pxm,
start, end);
- e820_register_active_regions(node, start >> PAGE_SHIFT,
- end >> PAGE_SHIFT);
if (ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) {
update_nodes_add(node, start, end);
@@ -338,6 +336,19 @@ static int __init nodes_cover_memory(const struct bootnode *nodes)
void __init acpi_numa_arch_fixup(void) {}
+int __init acpi_get_nodes(struct bootnode *physnodes)
+{
+ int i;
+ int ret = 0;
+
+ for_each_node_mask(i, nodes_parsed) {
+ physnodes[ret].start = nodes[i].start;
+ physnodes[ret].end = nodes[i].end;
+ ret++;
+ }
+ return ret;
+}
+
/* Use the information discovered above to actually set up the nodes. */
int __init acpi_scan_nodes(unsigned long start, unsigned long end)
{
@@ -350,11 +361,6 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end)
for (i = 0; i < MAX_NUMNODES; i++)
cutoff_node(i, start, end);
- if (!nodes_cover_memory(nodes)) {
- bad_srat();
- return -1;
- }
-
memnode_shift = compute_hash_shift(node_memblk_range, num_node_memblks,
memblk_nodeid);
if (memnode_shift < 0) {
@@ -364,6 +370,14 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end)
return -1;
}
+ for_each_node_mask(i, nodes_parsed)
+ e820_register_active_regions(i, nodes[i].start >> PAGE_SHIFT,
+ nodes[i].end >> PAGE_SHIFT);
+ if (!nodes_cover_memory(nodes)) {
+ bad_srat();
+ return -1;
+ }
+
/* Account for nodes with cpus and no memory */
nodes_or(node_possible_map, nodes_parsed, cpu_nodes_parsed);
@@ -454,7 +468,6 @@ void __init acpi_fake_nodes(const struct bootnode *fake_nodes, int num_nodes)
for (i = 0; i < num_nodes; i++)
if (fake_nodes[i].start != fake_nodes[i].end)
node_set(i, nodes_parsed);
- WARN_ON(!nodes_cover_memory(fake_nodes));
}
static int null_slit_node_compare(int a, int b)
diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c
index 36fe08e..65b58e4 100644
--- a/arch/x86/mm/tlb.c
+++ b/arch/x86/mm/tlb.c
@@ -8,6 +8,7 @@
#include <asm/tlbflush.h>
#include <asm/mmu_context.h>
+#include <asm/cache.h>
#include <asm/apic.h>
#include <asm/uv/uv.h>
@@ -43,7 +44,7 @@ union smp_flush_state {
spinlock_t tlbstate_lock;
DECLARE_BITMAP(flush_cpumask, NR_CPUS);
};
- char pad[CONFIG_X86_INTERNODE_CACHE_BYTES];
+ char pad[INTERNODE_CACHE_BYTES];
} ____cacheline_internodealigned_in_smp;
/* State is put into the per CPU data section, but padded
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index dfbf70e..c462cea 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -1093,10 +1093,8 @@ asmlinkage void __init xen_start_kernel(void)
__supported_pte_mask |= _PAGE_IOMAP;
-#ifdef CONFIG_X86_64
/* Work out if we support NX */
- check_efer();
-#endif
+ x86_configure_nx();
xen_setup_features();
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c
index fe03eee..738da0c 100644
--- a/arch/x86/xen/smp.c
+++ b/arch/x86/xen/smp.c
@@ -73,7 +73,7 @@ static __cpuinit void cpu_bringup(void)
xen_setup_cpu_clockevents();
- cpu_set(cpu, cpu_online_map);
+ set_cpu_online(cpu, true);
percpu_write(cpu_state, CPU_ONLINE);
wmb();
diff --git a/block/blk-iopoll.c b/block/blk-iopoll.c
index ca56420..58916af 100644
--- a/block/blk-iopoll.c
+++ b/block/blk-iopoll.c
@@ -28,7 +28,7 @@ static DEFINE_PER_CPU(struct list_head, blk_cpu_iopoll);
* Description:
* Add this blk_iopoll structure to the pending poll list and trigger the
* raise of the blk iopoll softirq. The driver must already have gotten a
- * succesful return from blk_iopoll_sched_prep() before calling this.
+ * successful return from blk_iopoll_sched_prep() before calling this.
**/
void blk_iopoll_sched(struct blk_iopoll *iop)
{
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 26b5dd0..81c185a 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -440,6 +440,15 @@ config CRYPTO_WP512
See also:
<http://planeta.terra.com.br/informatica/paulobarreto/WhirlpoolPage.html>
+config CRYPTO_GHASH_CLMUL_NI_INTEL
+ tristate "GHASH digest algorithm (CLMUL-NI accelerated)"
+ depends on (X86 || UML_X86) && 64BIT
+ select CRYPTO_SHASH
+ select CRYPTO_CRYPTD
+ help
+ GHASH is message digest algorithm for GCM (Galois/Counter Mode).
+ The implementation is accelerated by CLMUL-NI of Intel.
+
comment "Ciphers"
config CRYPTO_AES
diff --git a/crypto/ansi_cprng.c b/crypto/ansi_cprng.c
index 3aa6e38..2bc3321 100644
--- a/crypto/ansi_cprng.c
+++ b/crypto/ansi_cprng.c
@@ -85,7 +85,7 @@ static void xor_vectors(unsigned char *in1, unsigned char *in2,
* Returns DEFAULT_BLK_SZ bytes of random data per call
* returns 0 if generation succeded, <0 if something went wrong
*/
-static int _get_more_prng_bytes(struct prng_context *ctx)
+static int _get_more_prng_bytes(struct prng_context *ctx, int cont_test)
{
int i;
unsigned char tmp[DEFAULT_BLK_SZ];
@@ -132,7 +132,7 @@ static int _get_more_prng_bytes(struct prng_context *ctx)
*/
if (!memcmp(ctx->rand_data, ctx->last_rand_data,
DEFAULT_BLK_SZ)) {
- if (fips_enabled) {
+ if (cont_test) {
panic("cprng %p Failed repetition check!\n",
ctx);
}
@@ -185,16 +185,14 @@ static int _get_more_prng_bytes(struct prng_context *ctx)
}
/* Our exported functions */
-static int get_prng_bytes(char *buf, size_t nbytes, struct prng_context *ctx)
+static int get_prng_bytes(char *buf, size_t nbytes, struct prng_context *ctx,
+ int do_cont_test)
{
unsigned char *ptr = buf;
unsigned int byte_count = (unsigned int)nbytes;
int err;
- if (nbytes < 0)
- return -EINVAL;
-
spin_lock_bh(&ctx->prng_lock);
err = -EINVAL;
@@ -220,7 +218,7 @@ static int get_prng_bytes(char *buf, size_t nbytes, struct prng_context *ctx)
remainder:
if (ctx->rand_data_valid == DEFAULT_BLK_SZ) {
- if (_get_more_prng_bytes(ctx) < 0) {
+ if (_get_more_prng_bytes(ctx, do_cont_test) < 0) {
memset(buf, 0, nbytes);
err = -EINVAL;
goto done;
@@ -247,7 +245,7 @@ empty_rbuf:
*/
for (; byte_count >= DEFAULT_BLK_SZ; byte_count -= DEFAULT_BLK_SZ) {
if (ctx->rand_data_valid == DEFAULT_BLK_SZ) {
- if (_get_more_prng_bytes(ctx) < 0) {
+ if (_get_more_prng_bytes(ctx, do_cont_test) < 0) {
memset(buf, 0, nbytes);
err = -EINVAL;
goto done;
@@ -356,7 +354,7 @@ static int cprng_get_random(struct crypto_rng *tfm, u8 *rdata,
{
struct prng_context *prng = crypto_rng_ctx(tfm);
- return get_prng_bytes(rdata, dlen, prng);
+ return get_prng_bytes(rdata, dlen, prng, 0);
}
/*
@@ -404,19 +402,79 @@ static struct crypto_alg rng_alg = {
}
};
+#ifdef CONFIG_CRYPTO_FIPS
+static int fips_cprng_get_random(struct crypto_rng *tfm, u8 *rdata,
+ unsigned int dlen)
+{
+ struct prng_context *prng = crypto_rng_ctx(tfm);
+
+ return get_prng_bytes(rdata, dlen, prng, 1);
+}
+
+static int fips_cprng_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen)
+{
+ u8 rdata[DEFAULT_BLK_SZ];
+ int rc;
+
+ struct prng_context *prng = crypto_rng_ctx(tfm);
+
+ rc = cprng_reset(tfm, seed, slen);
+
+ if (!rc)
+ goto out;
+
+ /* this primes our continuity test */
+ rc = get_prng_bytes(rdata, DEFAULT_BLK_SZ, prng, 0);
+ prng->rand_data_valid = DEFAULT_BLK_SZ;
+
+out:
+ return rc;
+}
+
+static struct crypto_alg fips_rng_alg = {
+ .cra_name = "fips(ansi_cprng)",
+ .cra_driver_name = "fips_ansi_cprng",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_RNG,
+ .cra_ctxsize = sizeof(struct prng_context),
+ .cra_type = &crypto_rng_type,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(rng_alg.cra_list),
+ .cra_init = cprng_init,
+ .cra_exit = cprng_exit,
+ .cra_u = {
+ .rng = {
+ .rng_make_random = fips_cprng_get_random,
+ .rng_reset = fips_cprng_reset,
+ .seedsize = DEFAULT_PRNG_KSZ + 2*DEFAULT_BLK_SZ,
+ }
+ }
+};
+#endif
/* Module initalization */
static int __init prng_mod_init(void)
{
- if (fips_enabled)
- rng_alg.cra_priority += 200;
+ int rc = 0;
- return crypto_register_alg(&rng_alg);
+ rc = crypto_register_alg(&rng_alg);
+#ifdef CONFIG_CRYPTO_FIPS
+ if (rc)
+ goto out;
+
+ rc = crypto_register_alg(&fips_rng_alg);
+
+out:
+#endif
+ return rc;
}
static void __exit prng_mod_fini(void)
{
crypto_unregister_alg(&rng_alg);
+#ifdef CONFIG_CRYPTO_FIPS
+ crypto_unregister_alg(&fips_rng_alg);
+#endif
return;
}
diff --git a/crypto/cryptd.c b/crypto/cryptd.c
index 3533582..f8ae0d9 100644
--- a/crypto/cryptd.c
+++ b/crypto/cryptd.c
@@ -711,6 +711,13 @@ struct crypto_shash *cryptd_ahash_child(struct cryptd_ahash *tfm)
}
EXPORT_SYMBOL_GPL(cryptd_ahash_child);
+struct shash_desc *cryptd_shash_desc(struct ahash_request *req)
+{
+ struct cryptd_hash_request_ctx *rctx = ahash_request_ctx(req);
+ return &rctx->desc;
+}
+EXPORT_SYMBOL_GPL(cryptd_shash_desc);
+
void cryptd_free_ahash(struct cryptd_ahash *tfm)
{
crypto_free_ahash(&tfm->base);
diff --git a/crypto/digest.c b/crypto/digest.c
deleted file mode 100644
index 5d3f130..0000000
--- a/crypto/digest.c
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * Cryptographic API.
- *
- * Digest operations.
- *
- * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
- *
- * 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.
- *
- */
-
-#include <crypto/internal/hash.h>
-#include <crypto/scatterwalk.h>
-#include <linux/mm.h>
-#include <linux/errno.h>
-#include <linux/hardirq.h>
-#include <linux/highmem.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/scatterlist.h>
-
-#include "internal.h"
-
-static int init(struct hash_desc *desc)
-{
- struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm);
-
- tfm->__crt_alg->cra_digest.dia_init(tfm);
- return 0;
-}
-
-static int update2(struct hash_desc *desc,
- struct scatterlist *sg, unsigned int nbytes)
-{
- struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm);
- unsigned int alignmask = crypto_tfm_alg_alignmask(tfm);
-
- if (!nbytes)
- return 0;
-
- for (;;) {
- struct page *pg = sg_page(sg);
- unsigned int offset = sg->offset;
- unsigned int l = sg->length;
-
- if (unlikely(l > nbytes))
- l = nbytes;
- nbytes -= l;
-
- do {
- unsigned int bytes_from_page = min(l, ((unsigned int)
- (PAGE_SIZE)) -
- offset);
- char *src = crypto_kmap(pg, 0);
- char *p = src + offset;
-
- if (unlikely(offset & alignmask)) {
- unsigned int bytes =
- alignmask + 1 - (offset & alignmask);
- bytes = min(bytes, bytes_from_page);
- tfm->__crt_alg->cra_digest.dia_update(tfm, p,
- bytes);
- p += bytes;
- bytes_from_page -= bytes;
- l -= bytes;
- }
- tfm->__crt_alg->cra_digest.dia_update(tfm, p,
- bytes_from_page);
- crypto_kunmap(src, 0);
- crypto_yield(desc->flags);
- offset = 0;
- pg++;
- l -= bytes_from_page;
- } while (l > 0);
-
- if (!nbytes)
- break;
- sg = scatterwalk_sg_next(sg);
- }
-
- return 0;
-}
-
-static int update(struct hash_desc *desc,
- struct scatterlist *sg, unsigned int nbytes)
-{
- if (WARN_ON_ONCE(in_irq()))
- return -EDEADLK;
- return update2(desc, sg, nbytes);
-}
-
-static int final(struct hash_desc *desc, u8 *out)
-{
- struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm);
- unsigned long alignmask = crypto_tfm_alg_alignmask(tfm);
- struct digest_alg *digest = &tfm->__crt_alg->cra_digest;
-
- if (unlikely((unsigned long)out & alignmask)) {
- unsigned long align = alignmask + 1;
- unsigned long addr = (unsigned long)crypto_tfm_ctx(tfm);
- u8 *dst = (u8 *)ALIGN(addr, align) +
- ALIGN(tfm->__crt_alg->cra_ctxsize, align);
-
- digest->dia_final(tfm, dst);
- memcpy(out, dst, digest->dia_digestsize);
- } else
- digest->dia_final(tfm, out);
-
- return 0;
-}
-
-static int nosetkey(struct crypto_hash *tfm, const u8 *key, unsigned int keylen)
-{
- crypto_hash_clear_flags(tfm, CRYPTO_TFM_RES_MASK);
- return -ENOSYS;
-}
-
-static int setkey(struct crypto_hash *hash, const u8 *key, unsigned int keylen)
-{
- struct crypto_tfm *tfm = crypto_hash_tfm(hash);
-
- crypto_hash_clear_flags(hash, CRYPTO_TFM_RES_MASK);
- return tfm->__crt_alg->cra_digest.dia_setkey(tfm, key, keylen);
-}
-
-static int digest(struct hash_desc *desc,
- struct scatterlist *sg, unsigned int nbytes, u8 *out)
-{
- if (WARN_ON_ONCE(in_irq()))
- return -EDEADLK;
-
- init(desc);
- update2(desc, sg, nbytes);
- return final(desc, out);
-}
-
-int crypto_init_digest_ops(struct crypto_tfm *tfm)
-{
- struct hash_tfm *ops = &tfm->crt_hash;
- struct digest_alg *dalg = &tfm->__crt_alg->cra_digest;
-
- if (dalg->dia_digestsize > PAGE_SIZE / 8)
- return -EINVAL;
-
- ops->init = init;
- ops->update = update;
- ops->final = final;
- ops->digest = digest;
- ops->setkey = dalg->dia_setkey ? setkey : nosetkey;
- ops->digestsize = dalg->dia_digestsize;
-
- return 0;
-}
-
-void crypto_exit_digest_ops(struct crypto_tfm *tfm)
-{
-}
-
-static int digest_async_nosetkey(struct crypto_ahash *tfm_async, const u8 *key,
- unsigned int keylen)
-{
- crypto_ahash_clear_flags(tfm_async, CRYPTO_TFM_RES_MASK);
- return -ENOSYS;
-}
-
-static int digest_async_setkey(struct crypto_ahash *tfm_async, const u8 *key,
- unsigned int keylen)
-{
- struct crypto_tfm *tfm = crypto_ahash_tfm(tfm_async);
- struct digest_alg *dalg = &tfm->__crt_alg->cra_digest;
-
- crypto_ahash_clear_flags(tfm_async, CRYPTO_TFM_RES_MASK);
- return dalg->dia_setkey(tfm, key, keylen);
-}
-
-static int digest_async_init(struct ahash_request *req)
-{
- struct crypto_tfm *tfm = req->base.tfm;
- struct digest_alg *dalg = &tfm->__crt_alg->cra_digest;
-
- dalg->dia_init(tfm);
- return 0;
-}
-
-static int digest_async_update(struct ahash_request *req)
-{
- struct crypto_tfm *tfm = req->base.tfm;
- struct hash_desc desc = {
- .tfm = __crypto_hash_cast(tfm),
- .flags = req->base.flags,
- };
-
- update(&desc, req->src, req->nbytes);
- return 0;
-}
-
-static int digest_async_final(struct ahash_request *req)
-{
- struct crypto_tfm *tfm = req->base.tfm;
- struct hash_desc desc = {
- .tfm = __crypto_hash_cast(tfm),
- .flags = req->base.flags,
- };
-
- final(&desc, req->result);
- return 0;
-}
-
-static int digest_async_digest(struct ahash_request *req)
-{
- struct crypto_tfm *tfm = req->base.tfm;
- struct hash_desc desc = {
- .tfm = __crypto_hash_cast(tfm),
- .flags = req->base.flags,
- };
-
- return digest(&desc, req->src, req->nbytes, req->result);
-}
-
-int crypto_init_digest_ops_async(struct crypto_tfm *tfm)
-{
- struct ahash_tfm *crt = &tfm->crt_ahash;
- struct digest_alg *dalg = &tfm->__crt_alg->cra_digest;
-
- if (dalg->dia_digestsize > PAGE_SIZE / 8)
- return -EINVAL;
-
- crt->init = digest_async_init;
- crt->update = digest_async_update;
- crt->final = digest_async_final;
- crt->digest = digest_async_digest;
- crt->setkey = dalg->dia_setkey ? digest_async_setkey :
- digest_async_nosetkey;
- crt->digestsize = dalg->dia_digestsize;
-
- return 0;
-}
diff --git a/crypto/hash.c b/crypto/hash.c
deleted file mode 100644
index cb86b19..0000000
--- a/crypto/hash.c
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Cryptographic Hash operations.
- *
- * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
- *
- * 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.
- */
-
-#include <crypto/internal/hash.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/seq_file.h>
-
-#include "internal.h"
-
-static unsigned int crypto_hash_ctxsize(struct crypto_alg *alg, u32 type,
- u32 mask)
-{
- return alg->cra_ctxsize;
-}
-
-static int hash_setkey_unaligned(struct crypto_hash *crt, const u8 *key,
- unsigned int keylen)
-{
- struct crypto_tfm *tfm = crypto_hash_tfm(crt);
- struct hash_alg *alg = &tfm->__crt_alg->cra_hash;
- unsigned long alignmask = crypto_hash_alignmask(crt);
- int ret;
- u8 *buffer, *alignbuffer;
- unsigned long absize;
-
- absize = keylen + alignmask;
- buffer = kmalloc(absize, GFP_ATOMIC);
- if (!buffer)
- return -ENOMEM;
-
- alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
- memcpy(alignbuffer, key, keylen);
- ret = alg->setkey(crt, alignbuffer, keylen);
- memset(alignbuffer, 0, keylen);
- kfree(buffer);
- return ret;
-}
-
-static int hash_setkey(struct crypto_hash *crt, const u8 *key,
- unsigned int keylen)
-{
- struct crypto_tfm *tfm = crypto_hash_tfm(crt);
- struct hash_alg *alg = &tfm->__crt_alg->cra_hash;
- unsigned long alignmask = crypto_hash_alignmask(crt);
-
- if ((unsigned long)key & alignmask)
- return hash_setkey_unaligned(crt, key, keylen);
-
- return alg->setkey(crt, key, keylen);
-}
-
-static int hash_async_setkey(struct crypto_ahash *tfm_async, const u8 *key,
- unsigned int keylen)
-{
- struct crypto_tfm *tfm = crypto_ahash_tfm(tfm_async);
- struct crypto_hash *tfm_hash = __crypto_hash_cast(tfm);
- struct hash_alg *alg = &tfm->__crt_alg->cra_hash;
-
- return alg->setkey(tfm_hash, key, keylen);
-}
-
-static int hash_async_init(struct ahash_request *req)
-{
- struct crypto_tfm *tfm = req->base.tfm;
- struct hash_alg *alg = &tfm->__crt_alg->cra_hash;
- struct hash_desc desc = {
- .tfm = __crypto_hash_cast(tfm),
- .flags = req->base.flags,
- };
-
- return alg->init(&desc);
-}
-
-static int hash_async_update(struct ahash_request *req)
-{
- struct crypto_tfm *tfm = req->base.tfm;
- struct hash_alg *alg = &tfm->__crt_alg->cra_hash;
- struct hash_desc desc = {
- .tfm = __crypto_hash_cast(tfm),
- .flags = req->base.flags,
- };
-
- return alg->update(&desc, req->src, req->nbytes);
-}
-
-static int hash_async_final(struct ahash_request *req)
-{
- struct crypto_tfm *tfm = req->base.tfm;
- struct hash_alg *alg = &tfm->__crt_alg->cra_hash;
- struct hash_desc desc = {
- .tfm = __crypto_hash_cast(tfm),
- .flags = req->base.flags,
- };
-
- return alg->final(&desc, req->result);
-}
-
-static int hash_async_digest(struct ahash_request *req)
-{
- struct crypto_tfm *tfm = req->base.tfm;
- struct hash_alg *alg = &tfm->__crt_alg->cra_hash;
- struct hash_desc desc = {
- .tfm = __crypto_hash_cast(tfm),
- .flags = req->base.flags,
- };
-
- return alg->digest(&desc, req->src, req->nbytes, req->result);
-}
-
-static int crypto_init_hash_ops_async(struct crypto_tfm *tfm)
-{
- struct ahash_tfm *crt = &tfm->crt_ahash;
- struct hash_alg *alg = &tfm->__crt_alg->cra_hash;
-
- crt->init = hash_async_init;
- crt->update = hash_async_update;
- crt->final = hash_async_final;
- crt->digest = hash_async_digest;
- crt->setkey = hash_async_setkey;
- crt->digestsize = alg->digestsize;
-
- return 0;
-}
-
-static int crypto_init_hash_ops_sync(struct crypto_tfm *tfm)
-{
- struct hash_tfm *crt = &tfm->crt_hash;
- struct hash_alg *alg = &tfm->__crt_alg->cra_hash;
-
- crt->init = alg->init;
- crt->update = alg->update;
- crt->final = alg->final;
- crt->digest = alg->digest;
- crt->setkey = hash_setkey;
- crt->digestsize = alg->digestsize;
-
- return 0;
-}
-
-static int crypto_init_hash_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
-{
- struct hash_alg *alg = &tfm->__crt_alg->cra_hash;
-
- if (alg->digestsize > PAGE_SIZE / 8)
- return -EINVAL;
-
- if ((mask & CRYPTO_ALG_TYPE_HASH_MASK) != CRYPTO_ALG_TYPE_HASH_MASK)
- return crypto_init_hash_ops_async(tfm);
- else
- return crypto_init_hash_ops_sync(tfm);
-}
-
-static void crypto_hash_show(struct seq_file *m, struct crypto_alg *alg)
- __attribute__ ((unused));
-static void crypto_hash_show(struct seq_file *m, struct crypto_alg *alg)
-{
- seq_printf(m, "type : hash\n");
- seq_printf(m, "blocksize : %u\n", alg->cra_blocksize);
- seq_printf(m, "digestsize : %u\n", alg->cra_hash.digestsize);
-}
-
-const struct crypto_type crypto_hash_type = {
- .ctxsize = crypto_hash_ctxsize,
- .init = crypto_init_hash_ops,
-#ifdef CONFIG_PROC_FS
- .show = crypto_hash_show,
-#endif
-};
-EXPORT_SYMBOL_GPL(crypto_hash_type);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Generic cryptographic hash type");
diff --git a/crypto/proc.c b/crypto/proc.c
index 1c38733..58fef67 100644
--- a/crypto/proc.c
+++ b/crypto/proc.c
@@ -109,13 +109,6 @@ static int c_show(struct seq_file *m, void *p)
seq_printf(m, "max keysize : %u\n",
alg->cra_cipher.cia_max_keysize);
break;
-
- case CRYPTO_ALG_TYPE_DIGEST:
- seq_printf(m, "type : digest\n");
- seq_printf(m, "blocksize : %u\n", alg->cra_blocksize);
- seq_printf(m, "digestsize : %u\n",
- alg->cra_digest.dia_digestsize);
- break;
case CRYPTO_ALG_TYPE_COMPRESS:
seq_printf(m, "type : compression\n");
break;
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index 6d5b746..7620bfc 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -1201,7 +1201,7 @@ static int test_cprng(struct crypto_rng *tfm, struct cprng_testvec *template,
unsigned int tcount)
{
const char *algo = crypto_tfm_alg_driver_name(crypto_rng_tfm(tfm));
- int err, i, j, seedsize;
+ int err = 0, i, j, seedsize;
u8 *seed;
char result[32];
@@ -1943,6 +1943,15 @@ static const struct alg_test_desc alg_test_descs[] = {
}
}
}, {
+ .alg = "ghash",
+ .test = alg_test_hash,
+ .suite = {
+ .hash = {
+ .vecs = ghash_tv_template,
+ .count = GHASH_TEST_VECTORS
+ }
+ }
+ }, {
.alg = "hmac(md5)",
.test = alg_test_hash,
.suite = {
diff --git a/crypto/testmgr.h b/crypto/testmgr.h
index 9963b18..fb76517 100644
--- a/crypto/testmgr.h
+++ b/crypto/testmgr.h
@@ -1003,6 +1003,21 @@ static struct hash_testvec tgr128_tv_template[] = {
},
};
+#define GHASH_TEST_VECTORS 1
+
+static struct hash_testvec ghash_tv_template[] =
+{
+ {
+
+ .key = "\xdf\xa6\xbf\x4d\xed\x81\xdb\x03\xff\xca\xff\x95\xf8\x30\xf0\x61",
+ .ksize = 16,
+ .plaintext = "\x95\x2b\x2a\x56\xa5\x60\x04a\xc0\xb3\x2b\x66\x56\xa0\x5b\x40\xb6",
+ .psize = 16,
+ .digest = "\xda\x53\xeb\x0a\xd2\xc5\x5b\xb6"
+ "\x4f\xc4\x80\x2c\xc3\xfe\xda\x60",
+ },
+};
+
/*
* HMAC-MD5 test vectors from RFC2202
* (These need to be fixed to not use strlen).
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 48bbdbe..26e434a 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -1,5 +1,3 @@
-# drivers/Kconfig
-
menu "Device Drivers"
source "drivers/base/Kconfig"
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c
index 202dd0c..2be2fb6 100644
--- a/drivers/acpi/numa.c
+++ b/drivers/acpi/numa.c
@@ -283,22 +283,24 @@ acpi_table_parse_srat(enum acpi_srat_type id,
int __init acpi_numa_init(void)
{
+ int ret = 0;
+
/* SRAT: Static Resource Affinity Table */
if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) {
acpi_table_parse_srat(ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY,
acpi_parse_x2apic_affinity, NR_CPUS);
acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY,
acpi_parse_processor_affinity, NR_CPUS);
- acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY,
- acpi_parse_memory_affinity,
- NR_NODE_MEMBLKS);
+ ret = acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY,
+ acpi_parse_memory_affinity,
+ NR_NODE_MEMBLKS);
}
/* SLIT: System Locality Information Table */
acpi_table_parse(ACPI_SIG_SLIT, acpi_parse_slit);
acpi_numa_arch_fixup();
- return 0;
+ return ret;
}
int acpi_get_pxm(acpi_handle h)
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
index 575593a..27c7772 100644
--- a/drivers/acpi/video_detect.c
+++ b/drivers/acpi/video_detect.c
@@ -7,7 +7,7 @@
* video_detect.c:
* Provides acpi_is_video_device() for early scanning of ACPI devices in scan.c
* There a Linux specific (Spec does not provide a HID for video devices) is
- * assinged
+ * assigned
*
* After PCI devices are glued with ACPI devices
* acpi_get_pci_dev() can be called to identify ACPI graphics
@@ -83,16 +83,16 @@ long acpi_is_video_device(struct acpi_device *device)
if (!device)
return 0;
- /* Does this device able to support video switching ? */
+ /* Is this device able to support video switching ? */
if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy)) ||
ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy)))
video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING;
- /* Does this device able to retrieve a video ROM ? */
+ /* Is this device able to retrieve a video ROM ? */
if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy)))
video_caps |= ACPI_VIDEO_ROM_AVAILABLE;
- /* Does this device able to configure which video head to be POSTed ? */
+ /* Is this device able to configure which video head to be POSTed ? */
if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy)) &&
ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy)) &&
ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy)))
@@ -137,7 +137,7 @@ find_video(acpi_handle handle, u32 lvl, void *context, void **rv)
*
* if NULL is passed as argument all ACPI devices are enumerated and
* all graphics capabilities of physically present devices are
- * summerized and returned. This is cached and done only once.
+ * summarized and returned. This is cached and done only once.
*/
long acpi_video_get_capabilities(acpi_handle graphics_handle)
{
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index 0c6155f..19136a7 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -599,7 +599,7 @@ static const struct ich_laptop ich_laptop[] = {
{ 0x27DF, 0x1028, 0x02b0 }, /* ICH7 on unknown Dell */
{ 0x27DF, 0x1043, 0x1267 }, /* ICH7 on Asus W5F */
{ 0x27DF, 0x103C, 0x30A1 }, /* ICH7 on HP Compaq nc2400 */
- { 0x27DF, 0x103C, 0x361a }, /* ICH7 on unkown HP */
+ { 0x27DF, 0x103C, 0x361a }, /* ICH7 on unknown HP */
{ 0x27DF, 0x1071, 0xD221 }, /* ICH7 on Hercules EC-900 */
{ 0x27DF, 0x152D, 0x0778 }, /* ICH7 on unknown Intel */
{ 0x24CA, 0x1025, 0x0061 }, /* ICH4 on ACER Aspire 2023WLMi */
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 62e6b9e..1683ebd 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -1208,6 +1208,7 @@ void ata_scsi_slave_destroy(struct scsi_device *sdev)
* ata_scsi_change_queue_depth - SCSI callback for queue depth config
* @sdev: SCSI device to configure queue depth for
* @queue_depth: new queue depth
+ * @reason: calling context
*
* This is libata standard hostt->change_queue_depth callback.
* SCSI will call into this callback when user tries to set queue
@@ -1219,12 +1220,16 @@ void ata_scsi_slave_destroy(struct scsi_device *sdev)
* RETURNS:
* Newly configured queue depth.
*/
-int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth)
+int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth,
+ int reason)
{
struct ata_port *ap = ata_shost_to_port(sdev->host);
struct ata_device *dev;
unsigned long flags;
+ if (reason != SCSI_QDEPTH_DEFAULT)
+ return -EOPNOTSUPP;
+
if (queue_depth < 1 || queue_depth == sdev->queue_depth)
return sdev->queue_depth;
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index 51eb1e2..efa8773 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -736,7 +736,7 @@ unsigned int ata_sff_data_xfer(struct ata_device *dev, unsigned char *buf,
/*
* Use io*16_rep() accessors here as well to avoid pointlessly
- * swapping bytes to and fro on the big endian machines...
+ * swapping bytes to and from on the big endian machines...
*/
if (rw == READ) {
ioread16_rep(data_addr, pad, 1);
@@ -776,7 +776,7 @@ unsigned int ata_sff_data_xfer32(struct ata_device *dev, unsigned char *buf,
void __iomem *data_addr = ap->ioaddr.data_addr;
unsigned int words = buflen >> 2;
int slop = buflen & 3;
-
+
if (!(ap->pflags & ATA_PFLAG_PIO32))
return ata_sff_data_xfer(dev, buf, buflen, rw);
@@ -795,7 +795,7 @@ unsigned int ata_sff_data_xfer32(struct ata_device *dev, unsigned char *buf,
/*
* Use io*_rep() accessors here as well to avoid pointlessly
- * swapping bytes to and fro on the big endian machines...
+ * swapping bytes to and from on the big endian machines...
*/
if (rw == READ) {
if (slop < 3)
diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c
index 403f561..71cef9a 100644
--- a/drivers/ata/pata_cs5535.c
+++ b/drivers/ata/pata_cs5535.c
@@ -4,7 +4,7 @@
* Alan Cox <alan@lxorguk.ukuu.org.uk>
*
* based upon cs5535.c from AMD <Jens.Altmann@amd.com> as cleaned up and
- * made readable and Linux style by Wolfgang Zuleger <wolfgang.zuleger@gmx.de
+ * made readable and Linux style by Wolfgang Zuleger <wolfgang.zuleger@gmx.de>
* and Alexander Kiausch <alex.kiausch@t-online.de>
*
* This program is free software; you can redistribute it and/or modify
diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c
index 8a5d35b..ce4136e 100644
--- a/drivers/ata/sata_fsl.c
+++ b/drivers/ata/sata_fsl.c
@@ -43,9 +43,9 @@ enum {
/*
* SATA-FSL host controller supports a max. of (15+1) direct PRDEs, and
* chained indirect PRDEs upto a max count of 63.
- * We are allocating an array of 63 PRDEs contigiously, but PRDE#15 will
+ * We are allocating an array of 63 PRDEs contiguously, but PRDE#15 will
* be setup as an indirect descriptor, pointing to it's next
- * (contigious) PRDE. Though chained indirect PRDE arrays are
+ * (contiguous) PRDE. Though chained indirect PRDE arrays are
* supported,it will be more efficient to use a direct PRDT and
* a single chain/link to indirect PRDE array/PRDT.
*/
@@ -314,7 +314,7 @@ static unsigned int sata_fsl_fill_sg(struct ata_queued_cmd *qc, void *cmd_desc,
u32 ttl_dwords = 0;
/*
- * NOTE : direct & indirect prdt's are contigiously allocated
+ * NOTE : direct & indirect prdt's are contiguously allocated
*/
struct prde *prd = (struct prde *)&((struct command_desc *)
cmd_desc)->prdt;
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index 1eb4e02..0c82d33 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -1975,7 +1975,7 @@ static int nv_swncq_slave_config(struct scsi_device *sdev)
ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num));
if (strncmp(model_num, "Maxtor", 6) == 0) {
- ata_scsi_change_queue_depth(sdev, 1);
+ ata_scsi_change_queue_depth(sdev, 1, SCSI_QDEPTH_DEFAULT);
ata_dev_printk(dev, KERN_NOTICE,
"Disabling SWNCQ mode (depth %x)\n", sdev->queue_depth);
}
diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c
index b2c1b37..f734b34 100644
--- a/drivers/atm/iphase.c
+++ b/drivers/atm/iphase.c
@@ -1132,7 +1132,7 @@ static int rx_pkt(struct atm_dev *dev)
IF_ERR(printk(" cause: packet time out\n");)
}
else {
- IF_ERR(printk(" cause: buffer over flow\n");)
+ IF_ERR(printk(" cause: buffer overflow\n");)
}
goto out_free_desc;
}
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 979d159..ee95c76 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -188,7 +188,7 @@ EXPORT_SYMBOL_GPL(wait_for_device_probe);
* @dev: device to try to bind to the driver
*
* This function returns -ENODEV if the device is not registered,
- * 1 if the device is bound sucessfully and 0 otherwise.
+ * 1 if the device is bound successfully and 0 otherwise.
*
* This function must be called with @dev->sem held. When called for a
* USB interface, @dev->parent->sem must be held as well.
diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c
index 847a9e5..a5af1d6 100644
--- a/drivers/block/ataflop.c
+++ b/drivers/block/ataflop.c
@@ -1478,10 +1478,7 @@ void do_fd_request(struct request_queue * q)
stdma_lock(floppy_irq, NULL);
atari_disable_irq( IRQ_MFP_FDC );
- local_save_flags(flags); /* The request function is called with ints
- local_irq_disable(); * disabled... so must save the IPL for later */
redo_fd_request();
- local_irq_restore(flags);
atari_enable_irq( IRQ_MFP_FDC );
}
diff --git a/drivers/block/cciss_cmd.h b/drivers/block/cciss_cmd.h
index b50a9b2..6afa700 100644
--- a/drivers/block/cciss_cmd.h
+++ b/drivers/block/cciss_cmd.h
@@ -5,7 +5,7 @@
//###########################################################################
#define CISS_VERSION "1.00"
-//general boundary defintions
+//general boundary definitions
#define SENSEINFOBYTES 32//note that this value may vary between host implementations
#define MAXSGENTRIES 32
#define CCISS_SG_CHAIN 0x80000000
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c
index 1e6eb1a..f36defa 100644
--- a/drivers/bluetooth/btmrvl_sdio.c
+++ b/drivers/bluetooth/btmrvl_sdio.c
@@ -535,7 +535,7 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv)
break;
default:
- BT_ERR("Unknow packet type:%d", type);
+ BT_ERR("Unknown packet type:%d", type);
print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, payload,
blksz * buf_block_len);
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 4895f0e..aa09193 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -214,7 +214,7 @@ static int hci_uart_send_frame(struct sk_buff *skb)
struct hci_uart *hu;
if (!hdev) {
- BT_ERR("Frame for uknown device (hdev=NULL)");
+ BT_ERR("Frame for unknown device (hdev=NULL)");
return -ENODEV;
}
diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c
index a762283..e789e6c 100644
--- a/drivers/cdrom/gdrom.c
+++ b/drivers/cdrom/gdrom.c
@@ -214,7 +214,7 @@ static void gdrom_spicommand(void *spi_string, int buflen)
gdrom_getsense(NULL);
return;
}
- outsw(PHYSADDR(GDROM_DATA_REG), cmd, 6);
+ outsw(GDROM_DATA_REG, cmd, 6);
}
@@ -298,7 +298,7 @@ static int gdrom_readtoc_cmd(struct gdromtoc *toc, int session)
err = -EINVAL;
goto cleanup_readtoc;
}
- insw(PHYSADDR(GDROM_DATA_REG), toc, tocsize/2);
+ insw(GDROM_DATA_REG, toc, tocsize/2);
if (gd.status & 0x01)
err = -EINVAL;
@@ -449,7 +449,7 @@ static int gdrom_getsense(short *bufstring)
GDROM_DEFAULT_TIMEOUT);
if (gd.pending)
goto cleanup_sense;
- insw(PHYSADDR(GDROM_DATA_REG), &sense, sense_command->buflen/2);
+ insw(GDROM_DATA_REG, &sense, sense_command->buflen/2);
if (sense[1] & 40) {
printk(KERN_INFO "GDROM: Drive not ready - command aborted\n");
goto cleanup_sense;
@@ -586,7 +586,7 @@ static void gdrom_readdisk_dma(struct work_struct *work)
spin_unlock(&gdrom_lock);
block = blk_rq_pos(req)/GD_TO_BLK + GD_SESSION_OFFSET;
block_cnt = blk_rq_sectors(req)/GD_TO_BLK;
- ctrl_outl(PHYSADDR(req->buffer), GDROM_DMA_STARTADDR_REG);
+ ctrl_outl(virt_to_phys(req->buffer), GDROM_DMA_STARTADDR_REG);
ctrl_outl(block_cnt * GDROM_HARD_SECTOR, GDROM_DMA_LENGTH_REG);
ctrl_outl(1, GDROM_DMA_DIRECTION_REG);
ctrl_outl(1, GDROM_DMA_ENABLE_REG);
@@ -615,7 +615,7 @@ static void gdrom_readdisk_dma(struct work_struct *work)
cpu_relax();
gd.pending = 1;
gd.transfer = 1;
- outsw(PHYSADDR(GDROM_DATA_REG), &read_command->cmd, 6);
+ outsw(GDROM_DATA_REG, &read_command->cmd, 6);
timeout = jiffies + HZ / 2;
/* Wait for any pending DMA to finish */
while (ctrl_inb(GDROM_DMA_STATUS_REG) &&
diff --git a/drivers/char/agp/frontend.c b/drivers/char/agp/frontend.c
index a96f319..43412c0 100644
--- a/drivers/char/agp/frontend.c
+++ b/drivers/char/agp/frontend.c
@@ -676,25 +676,25 @@ static int agp_open(struct inode *inode, struct file *file)
int minor = iminor(inode);
struct agp_file_private *priv;
struct agp_client *client;
- int rc = -ENXIO;
-
- lock_kernel();
- mutex_lock(&(agp_fe.agp_mutex));
if (minor != AGPGART_MINOR)
- goto err_out;
+ return -ENXIO;
+
+ mutex_lock(&(agp_fe.agp_mutex));
priv = kzalloc(sizeof(struct agp_file_private), GFP_KERNEL);
- if (priv == NULL)
- goto err_out_nomem;
+ if (priv == NULL) {
+ mutex_unlock(&(agp_fe.agp_mutex));
+ return -ENOMEM;
+ }
set_bit(AGP_FF_ALLOW_CLIENT, &priv->access_flags);
priv->my_pid = current->pid;
- if (capable(CAP_SYS_RAWIO)) {
+ if (capable(CAP_SYS_RAWIO))
/* Root priv, can be controller */
set_bit(AGP_FF_ALLOW_CONTROLLER, &priv->access_flags);
- }
+
client = agp_find_client_by_pid(current->pid);
if (client != NULL) {
@@ -704,16 +704,10 @@ static int agp_open(struct inode *inode, struct file *file)
file->private_data = (void *) priv;
agp_insert_file_private(priv);
DBG("private=%p, client=%p", priv, client);
- mutex_unlock(&(agp_fe.agp_mutex));
- unlock_kernel();
- return 0;
-err_out_nomem:
- rc = -ENOMEM;
-err_out:
mutex_unlock(&(agp_fe.agp_mutex));
- unlock_kernel();
- return rc;
+
+ return 0;
}
diff --git a/drivers/char/cs5535_gpio.c b/drivers/char/cs5535_gpio.c
index 04ba906..4d830dc 100644
--- a/drivers/char/cs5535_gpio.c
+++ b/drivers/char/cs5535_gpio.c
@@ -17,7 +17,7 @@
#include <linux/cdev.h>
#include <linux/ioport.h>
#include <linux/pci.h>
-#include <linux/smp_lock.h>
+
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -158,7 +158,6 @@ static int cs5535_gpio_open(struct inode *inode, struct file *file)
{
u32 m = iminor(inode);
- cycle_kernel_lock();
/* the mask says which pins are usable by this driver */
if ((mask & (1 << m)) == 0)
return -EINVAL;
diff --git a/drivers/char/efirtc.c b/drivers/char/efirtc.c
index 34d15d5..26a47dc 100644
--- a/drivers/char/efirtc.c
+++ b/drivers/char/efirtc.c
@@ -27,8 +27,6 @@
* - Add module support
*/
-
-#include <linux/smp_lock.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
@@ -174,13 +172,12 @@ static long efi_rtc_ioctl(struct file *file, unsigned int cmd,
return -EINVAL;
case RTC_RD_TIME:
- lock_kernel();
spin_lock_irqsave(&efi_rtc_lock, flags);
status = efi.get_time(&eft, &cap);
spin_unlock_irqrestore(&efi_rtc_lock,flags);
- unlock_kernel();
+
if (status != EFI_SUCCESS) {
/* should never happen */
printk(KERN_ERR "efitime: can't read time\n");
@@ -202,13 +199,11 @@ static long efi_rtc_ioctl(struct file *file, unsigned int cmd,
convert_to_efi_time(&wtime, &eft);
- lock_kernel();
spin_lock_irqsave(&efi_rtc_lock, flags);
status = efi.set_time(&eft);
spin_unlock_irqrestore(&efi_rtc_lock,flags);
- unlock_kernel();
return status == EFI_SUCCESS ? 0 : -EINVAL;
@@ -224,7 +219,6 @@ static long efi_rtc_ioctl(struct file *file, unsigned int cmd,
convert_to_efi_time(&wtime, &eft);
- lock_kernel();
spin_lock_irqsave(&efi_rtc_lock, flags);
/*
* XXX Fixme:
@@ -235,19 +229,16 @@ static long efi_rtc_ioctl(struct file *file, unsigned int cmd,
status = efi.set_wakeup_time((efi_bool_t)enabled, &eft);
spin_unlock_irqrestore(&efi_rtc_lock,flags);
- unlock_kernel();
return status == EFI_SUCCESS ? 0 : -EINVAL;
case RTC_WKALM_RD:
- lock_kernel();
spin_lock_irqsave(&efi_rtc_lock, flags);
status = efi.get_wakeup_time((efi_bool_t *)&enabled, (efi_bool_t *)&pending, &eft);
spin_unlock_irqrestore(&efi_rtc_lock,flags);
- unlock_kernel();
if (status != EFI_SUCCESS) return -EINVAL;
@@ -277,7 +268,6 @@ static int efi_rtc_open(struct inode *inode, struct file *file)
* We do accept multiple open files at the same time as we
* synchronize on the per call operation.
*/
- cycle_kernel_lock();
return 0;
}
diff --git a/drivers/char/generic_nvram.c b/drivers/char/generic_nvram.c
index ef31738..fda4181 100644
--- a/drivers/char/generic_nvram.c
+++ b/drivers/char/generic_nvram.c
@@ -19,7 +19,6 @@
#include <linux/miscdevice.h>
#include <linux/fcntl.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <asm/nvram.h>
#ifdef CONFIG_PPC_PMAC
@@ -32,7 +31,6 @@ static ssize_t nvram_len;
static loff_t nvram_llseek(struct file *file, loff_t offset, int origin)
{
- lock_kernel();
switch (origin) {
case 1:
offset += file->f_pos;
@@ -41,12 +39,11 @@ static loff_t nvram_llseek(struct file *file, loff_t offset, int origin)
offset += nvram_len;
break;
}
- if (offset < 0) {
- unlock_kernel();
+ if (offset < 0)
return -EINVAL;
- }
+
file->f_pos = offset;
- unlock_kernel();
+
return file->f_pos;
}
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
index 1573aeb..e989f67 100644
--- a/drivers/char/hw_random/core.c
+++ b/drivers/char/hw_random/core.c
@@ -52,7 +52,9 @@
static struct hwrng *current_rng;
static LIST_HEAD(rng_list);
static DEFINE_MUTEX(rng_mutex);
-
+static int data_avail;
+static u8 rng_buffer[SMP_CACHE_BYTES < 32 ? 32 : SMP_CACHE_BYTES]
+ __cacheline_aligned;
static inline int hwrng_init(struct hwrng *rng)
{
@@ -67,19 +69,6 @@ static inline void hwrng_cleanup(struct hwrng *rng)
rng->cleanup(rng);
}
-static inline int hwrng_data_present(struct hwrng *rng, int wait)
-{
- if (!rng->data_present)
- return 1;
- return rng->data_present(rng, wait);
-}
-
-static inline int hwrng_data_read(struct hwrng *rng, u32 *data)
-{
- return rng->data_read(rng, data);
-}
-
-
static int rng_dev_open(struct inode *inode, struct file *filp)
{
/* enforce read-only access to this chrdev */
@@ -87,58 +76,90 @@ static int rng_dev_open(struct inode *inode, struct file *filp)
return -EINVAL;
if (filp->f_mode & FMODE_WRITE)
return -EINVAL;
- cycle_kernel_lock();
+ return 0;
+}
+
+static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size,
+ int wait) {
+ int present;
+
+ if (rng->read)
+ return rng->read(rng, (void *)buffer, size, wait);
+
+ if (rng->data_present)
+ present = rng->data_present(rng, wait);
+ else
+ present = 1;
+
+ if (present)
+ return rng->data_read(rng, (u32 *)buffer);
+
return 0;
}
static ssize_t rng_dev_read(struct file *filp, char __user *buf,
size_t size, loff_t *offp)
{
- u32 data;
ssize_t ret = 0;
int err = 0;
- int bytes_read;
+ int bytes_read, len;
while (size) {
- err = -ERESTARTSYS;
- if (mutex_lock_interruptible(&rng_mutex))
+ if (mutex_lock_interruptible(&rng_mutex)) {
+ err = -ERESTARTSYS;
goto out;
+ }
+
if (!current_rng) {
- mutex_unlock(&rng_mutex);
err = -ENODEV;
- goto out;
+ goto out_unlock;
}
- bytes_read = 0;
- if (hwrng_data_present(current_rng,
- !(filp->f_flags & O_NONBLOCK)))
- bytes_read = hwrng_data_read(current_rng, &data);
- mutex_unlock(&rng_mutex);
-
- err = -EAGAIN;
- if (!bytes_read && (filp->f_flags & O_NONBLOCK))
- goto out;
- if (bytes_read < 0) {
- err = bytes_read;
- goto out;
+ if (!data_avail) {
+ bytes_read = rng_get_data(current_rng, rng_buffer,
+ sizeof(rng_buffer),
+ !(filp->f_flags & O_NONBLOCK));
+ if (bytes_read < 0) {
+ err = bytes_read;
+ goto out_unlock;
+ }
+ data_avail = bytes_read;
}
- err = -EFAULT;
- while (bytes_read && size) {
- if (put_user((u8)data, buf++))
- goto out;
- size--;
- ret++;
- bytes_read--;
- data >>= 8;
+ if (!data_avail) {
+ if (filp->f_flags & O_NONBLOCK) {
+ err = -EAGAIN;
+ goto out_unlock;
+ }
+ } else {
+ len = data_avail;
+ if (len > size)
+ len = size;
+
+ data_avail -= len;
+
+ if (copy_to_user(buf + ret, rng_buffer + data_avail,
+ len)) {
+ err = -EFAULT;
+ goto out_unlock;
+ }
+
+ size -= len;
+ ret += len;
}
+ mutex_unlock(&rng_mutex);
+
if (need_resched())
schedule_timeout_interruptible(1);
- err = -ERESTARTSYS;
- if (signal_pending(current))
+
+ if (signal_pending(current)) {
+ err = -ERESTARTSYS;
goto out;
+ }
}
+out_unlock:
+ mutex_unlock(&rng_mutex);
out:
return ret ? : err;
}
@@ -280,7 +301,7 @@ int hwrng_register(struct hwrng *rng)
struct hwrng *old_rng, *tmp;
if (rng->name == NULL ||
- rng->data_read == NULL)
+ (rng->data_read == NULL && rng->read == NULL))
goto out;
mutex_lock(&rng_mutex);
diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c
index 915157f..bdaef8e9 100644
--- a/drivers/char/hw_random/virtio-rng.c
+++ b/drivers/char/hw_random/virtio-rng.c
@@ -16,6 +16,7 @@
* 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/err.h>
#include <linux/hw_random.h>
#include <linux/scatterlist.h>
@@ -23,78 +24,64 @@
#include <linux/virtio.h>
#include <linux/virtio_rng.h>
-/* The host will fill any buffer we give it with sweet, sweet randomness. We
- * give it 64 bytes at a time, and the hwrng framework takes it 4 bytes at a
- * time. */
-#define RANDOM_DATA_SIZE 64
-
static struct virtqueue *vq;
-static u32 *random_data;
-static unsigned int data_left;
+static unsigned int data_avail;
static DECLARE_COMPLETION(have_data);
+static bool busy;
static void random_recv_done(struct virtqueue *vq)
{
- unsigned int len;
-
/* We can get spurious callbacks, e.g. shared IRQs + virtio_pci. */
- if (!vq->vq_ops->get_buf(vq, &len))
+ if (!vq->vq_ops->get_buf(vq, &data_avail))
return;
- data_left += len;
complete(&have_data);
}
-static void register_buffer(void)
+/* The host will fill any buffer we give it with sweet, sweet randomness. */
+static void register_buffer(u8 *buf, size_t size)
{
struct scatterlist sg;
- sg_init_one(&sg, random_data+data_left, RANDOM_DATA_SIZE-data_left);
+ sg_init_one(&sg, buf, size);
+
/* There should always be room for one buffer. */
- if (vq->vq_ops->add_buf(vq, &sg, 0, 1, random_data) < 0)
+ if (vq->vq_ops->add_buf(vq, &sg, 0, 1, buf) < 0)
BUG();
+
vq->vq_ops->kick(vq);
}
-/* At least we don't udelay() in a loop like some other drivers. */
-static int virtio_data_present(struct hwrng *rng, int wait)
+static int virtio_read(struct hwrng *rng, void *buf, size_t size, bool wait)
{
- if (data_left >= sizeof(u32))
- return 1;
-again:
+ if (!busy) {
+ busy = true;
+ init_completion(&have_data);
+ register_buffer(buf, size);
+ }
+
if (!wait)
return 0;
wait_for_completion(&have_data);
- /* Not enough? Re-register. */
- if (unlikely(data_left < sizeof(u32))) {
- register_buffer();
- goto again;
- }
+ busy = false;
- return 1;
+ return data_avail;
}
-/* virtio_data_present() must have succeeded before this is called. */
-static int virtio_data_read(struct hwrng *rng, u32 *data)
+static void virtio_cleanup(struct hwrng *rng)
{
- BUG_ON(data_left < sizeof(u32));
- data_left -= sizeof(u32);
- *data = random_data[data_left / 4];
-
- if (data_left < sizeof(u32)) {
- init_completion(&have_data);
- register_buffer();
- }
- return sizeof(*data);
+ if (busy)
+ wait_for_completion(&have_data);
}
+
static struct hwrng virtio_hwrng = {
- .name = "virtio",
- .data_present = virtio_data_present,
- .data_read = virtio_data_read,
+ .name = "virtio",
+ .cleanup = virtio_cleanup,
+ .read = virtio_read,
};
static int virtrng_probe(struct virtio_device *vdev)
@@ -112,7 +99,6 @@ static int virtrng_probe(struct virtio_device *vdev)
return err;
}
- register_buffer();
return 0;
}
@@ -138,21 +124,11 @@ static struct virtio_driver virtio_rng = {
static int __init init(void)
{
- int err;
-
- random_data = kmalloc(RANDOM_DATA_SIZE, GFP_KERNEL);
- if (!random_data)
- return -ENOMEM;
-
- err = register_virtio_driver(&virtio_rng);
- if (err)
- kfree(random_data);
- return err;
+ return register_virtio_driver(&virtio_rng);
}
static void __exit fini(void)
{
- kfree(random_data);
unregister_virtio_driver(&virtio_rng);
}
module_init(init);
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index a074fce..30eff80 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -5,7 +5,7 @@
*
* Added devfs support.
* Jan-11-1998, C. Scott Ananian <cananian@alumni.princeton.edu>
- * Shared /dev/zero mmaping support, Feb 2000, Kanoj Sarcar <kanoj@sgi.com>
+ * Shared /dev/zero mmapping support, Feb 2000, Kanoj Sarcar <kanoj@sgi.com>
*/
#include <linux/mm.h>
@@ -26,7 +26,6 @@
#include <linux/bootmem.h>
#include <linux/splice.h>
#include <linux/pfn.h>
-#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -892,29 +891,23 @@ static int memory_open(struct inode *inode, struct file *filp)
{
int minor;
const struct memdev *dev;
- int ret = -ENXIO;
-
- lock_kernel();
minor = iminor(inode);
if (minor >= ARRAY_SIZE(devlist))
- goto out;
+ return -ENXIO;
dev = &devlist[minor];
if (!dev->fops)
- goto out;
+ return -ENXIO;
filp->f_op = dev->fops;
if (dev->dev_info)
filp->f_mapping->backing_dev_info = dev->dev_info;
if (dev->fops->open)
- ret = dev->fops->open(inode, filp);
- else
- ret = 0;
-out:
- unlock_kernel();
- return ret;
+ return dev->fops->open(inode, filp);
+
+ return 0;
}
static const struct file_operations memory_fops = {
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index 07fa612..96f1cd0 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -49,7 +49,6 @@
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
-#include <linux/smp_lock.h>
/*
* Head entry for the doubly linked miscdevice list
@@ -118,8 +117,7 @@ static int misc_open(struct inode * inode, struct file * file)
struct miscdevice *c;
int err = -ENODEV;
const struct file_operations *old_fops, *new_fops = NULL;
-
- lock_kernel();
+
mutex_lock(&misc_mtx);
list_for_each_entry(c, &misc_list, list) {
@@ -157,7 +155,6 @@ static int misc_open(struct inode * inode, struct file * file)
fops_put(old_fops);
fail:
mutex_unlock(&misc_mtx);
- unlock_kernel();
return err;
}
diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c
index 1997270..ecb89d7 100644
--- a/drivers/char/mspec.c
+++ b/drivers/char/mspec.c
@@ -248,7 +248,7 @@ static const struct vm_operations_struct mspec_vm_ops = {
/*
* mspec_mmap
*
- * Called when mmaping the device. Initializes the vma with a fault handler
+ * Called when mmapping the device. Initializes the vma with a fault handler
* and private data structure necessary to allocate, track, and free the
* underlying pages.
*/
diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c
index 6934025..c1d8b54 100644
--- a/drivers/char/n_r3964.c
+++ b/drivers/char/n_r3964.c
@@ -602,7 +602,7 @@ static void receive_char(struct r3964_info *pInfo, const unsigned char c)
}
break;
case R3964_WAIT_FOR_RX_REPEAT:
- /* FALLTROUGH */
+ /* FALLTHROUGH */
case R3964_IDLE:
if (c == STX) {
/* Prevent rx_queue from overflow: */
diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
index 88cee40..4008e2c 100644
--- a/drivers/char/nvram.c
+++ b/drivers/char/nvram.c
@@ -38,7 +38,6 @@
#define NVRAM_VERSION "1.3"
#include <linux/module.h>
-#include <linux/smp_lock.h>
#include <linux/nvram.h>
#define PC 1
@@ -111,6 +110,7 @@
#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/uaccess.h>
+#include <linux/smp_lock.h>
#include <asm/system.h>
@@ -214,7 +214,6 @@ void nvram_set_checksum(void)
static loff_t nvram_llseek(struct file *file, loff_t offset, int origin)
{
- lock_kernel();
switch (origin) {
case 0:
/* nothing to do */
@@ -226,7 +225,7 @@ static loff_t nvram_llseek(struct file *file, loff_t offset, int origin)
offset += NVRAM_BYTES;
break;
}
- unlock_kernel();
+
return (offset >= 0) ? (file->f_pos = offset) : -EINVAL;
}
diff --git a/drivers/char/pc8736x_gpio.c b/drivers/char/pc8736x_gpio.c
index 3f7da8c..8ecbcc1 100644
--- a/drivers/char/pc8736x_gpio.c
+++ b/drivers/char/pc8736x_gpio.c
@@ -20,7 +20,6 @@
#include <linux/mutex.h>
#include <linux/nsc_gpio.h>
#include <linux/platform_device.h>
-#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#define DEVNAME "pc8736x_gpio"
@@ -223,7 +222,6 @@ static int pc8736x_gpio_open(struct inode *inode, struct file *file)
unsigned m = iminor(inode);
file->private_data = &pc8736x_gpio_ops;
- cycle_kernel_lock();
dev_dbg(&pdev->dev, "open %d\n", m);
if (m >= PC8736X_GPIO_CT)
diff --git a/drivers/char/rio/route.h b/drivers/char/rio/route.h
index 20ed73f..46e9637 100644
--- a/drivers/char/rio/route.h
+++ b/drivers/char/rio/route.h
@@ -67,7 +67,7 @@
typedef struct COST_ROUTE COST_ROUTE;
struct COST_ROUTE {
unsigned char cost; /* Cost down this link */
- unsigned char route[NODE_BYTES]; /* Nodes thorough this route */
+ unsigned char route[NODE_BYTES]; /* Nodes through this route */
};
typedef struct ROUTE_STR ROUTE_STR;
diff --git a/drivers/char/scx200_gpio.c b/drivers/char/scx200_gpio.c
index 1d91005..99e5272 100644
--- a/drivers/char/scx200_gpio.c
+++ b/drivers/char/scx200_gpio.c
@@ -12,7 +12,6 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
-#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -52,7 +51,6 @@ static int scx200_gpio_open(struct inode *inode, struct file *file)
unsigned m = iminor(inode);
file->private_data = &scx200_gpio_ops;
- cycle_kernel_lock();
if (m >= MAX_PINS)
return -EINVAL;
return nonseekable_open(inode, file);
diff --git a/drivers/char/tb0219.c b/drivers/char/tb0219.c
index b3ec9b1..cad4eb6 100644
--- a/drivers/char/tb0219.c
+++ b/drivers/char/tb0219.c
@@ -21,7 +21,6 @@
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/smp_lock.h>
#include <asm/io.h>
#include <asm/reboot.h>
@@ -38,7 +37,7 @@ MODULE_PARM_DESC(major, "Major device number");
static void (*old_machine_restart)(char *command);
static void __iomem *tb0219_base;
-static spinlock_t tb0219_lock;
+static DEFINE_SPINLOCK(tb0219_lock);
#define tb0219_read(offset) readw(tb0219_base + (offset))
#define tb0219_write(offset, value) writew((value), tb0219_base + (offset))
@@ -237,7 +236,6 @@ static int tanbac_tb0219_open(struct inode *inode, struct file *file)
{
unsigned int minor;
- cycle_kernel_lock();
minor = iminor(inode);
switch (minor) {
case 0:
@@ -306,8 +304,6 @@ static int __devinit tb0219_probe(struct platform_device *dev)
return retval;
}
- spin_lock_init(&tb0219_lock);
-
old_machine_restart = _machine_restart;
_machine_restart = tb0219_restart;
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
index 8e67d5c..6bd5f88 100644
--- a/drivers/char/tty_ioctl.c
+++ b/drivers/char/tty_ioctl.c
@@ -315,7 +315,7 @@ EXPORT_SYMBOL(tty_termios_input_baud_rate);
* For maximal back compatibility with legacy SYS5/POSIX *nix behaviour
* we need to carefully set the bits when the user does not get the
* desired speed. We allow small margins and preserve as much of possible
- * of the input intent to keep compatiblity.
+ * of the input intent to keep compatibility.
*
* Locking: Caller should hold termios lock. This is already held
* when calling this function from the driver termios handler.
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index 0c80c68..1e3d728 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -161,6 +161,8 @@ static void set_palette(struct vc_data *vc);
static int printable; /* Is console ready for printing? */
int default_utf8 = true;
module_param(default_utf8, int, S_IRUGO | S_IWUSR);
+int global_cursor_default = -1;
+module_param(global_cursor_default, int, S_IRUGO | S_IWUSR);
/*
* ignore_poke: don't unblank the screen when things are typed. This is
@@ -775,6 +777,12 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */
vc_cons[currcons].d = NULL;
return -ENOMEM;
}
+
+ /* If no drivers have overridden us and the user didn't pass a
+ boot option, default to displaying the cursor */
+ if (global_cursor_default == -1)
+ global_cursor_default = 1;
+
vc_init(vc, vc->vc_rows, vc->vc_cols, 1);
vcs_make_sysfs(currcons);
atomic_notifier_call_chain(&vt_notifier_list, VT_ALLOCATE, &param);
@@ -1616,7 +1624,7 @@ static void reset_terminal(struct vc_data *vc, int do_clear)
vc->vc_decscnm = 0;
vc->vc_decom = 0;
vc->vc_decawm = 1;
- vc->vc_deccm = 1;
+ vc->vc_deccm = global_cursor_default;
vc->vc_decim = 0;
set_kbd(vc, decarm);
@@ -4078,6 +4086,7 @@ EXPORT_SYMBOL(fg_console);
EXPORT_SYMBOL(console_blank_hook);
EXPORT_SYMBOL(console_blanked);
EXPORT_SYMBOL(vc_cons);
+EXPORT_SYMBOL(global_cursor_default);
#ifndef VT_SINGLE_DRIVER
EXPORT_SYMBOL(take_over_console);
EXPORT_SYMBOL(give_up_console);
diff --git a/drivers/cpuidle/governor.c b/drivers/cpuidle/governor.c
index 70b5964..724c164 100644
--- a/drivers/cpuidle/governor.c
+++ b/drivers/cpuidle/governor.c
@@ -21,7 +21,7 @@ struct cpuidle_governor *cpuidle_curr_governor;
* __cpuidle_find_governor - finds a governor of the specified name
* @str: the name
*
- * Must be called with cpuidle_lock aquired.
+ * Must be called with cpuidle_lock acquired.
*/
static struct cpuidle_governor * __cpuidle_find_governor(const char *str)
{
@@ -39,7 +39,7 @@ static struct cpuidle_governor * __cpuidle_find_governor(const char *str)
* @gov: the new target governor
*
* NOTE: "gov" can be NULL to specify disabled
- * Must be called with cpuidle_lock aquired.
+ * Must be called with cpuidle_lock acquired.
*/
int cpuidle_switch_governor(struct cpuidle_governor *gov)
{
diff --git a/drivers/crypto/hifn_795x.c b/drivers/crypto/hifn_795x.c
index 5f753fc..09ad915 100644
--- a/drivers/crypto/hifn_795x.c
+++ b/drivers/crypto/hifn_795x.c
@@ -863,7 +863,7 @@ static int hifn_init_pubrng(struct hifn_device *dev)
dev->dmareg |= HIFN_DMAIER_PUBDONE;
hifn_write_1(dev, HIFN_1_DMA_IER, dev->dmareg);
- dprintk("Chip %s: Public key engine has been sucessfully "
+ dprintk("Chip %s: Public key engine has been successfully "
"initialised.\n", dev->name);
}
diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index 7585c41..c52ac9e 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -99,7 +99,7 @@ static struct at_desc *atc_alloc_descriptor(struct dma_chan *chan,
}
/**
- * atc_desc_get - get a unsused descriptor from free_list
+ * atc_desc_get - get an unused descriptor from free_list
* @atchan: channel we want a new descriptor for
*/
static struct at_desc *atc_desc_get(struct at_dma_chan *atchan)
diff --git a/drivers/firewire/core-topology.c b/drivers/firewire/core-topology.c
index 9a5f38c..93ec64c 100644
--- a/drivers/firewire/core-topology.c
+++ b/drivers/firewire/core-topology.c
@@ -183,7 +183,7 @@ static inline struct fw_node *fw_node(struct list_head *l)
* This function builds the tree representation of the topology given
* by the self IDs from the latest bus reset. During the construction
* of the tree, the function checks that the self IDs are valid and
- * internally consistent. On succcess this function returns the
+ * internally consistent. On success this function returns the
* fw_node corresponding to the local card otherwise NULL.
*/
static struct fw_node *build_tree(struct fw_card *card,
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 5cae0b3..3f7c500 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -272,7 +272,7 @@ EXPORT_SYMBOL(drm_mode_object_find);
* functions & device file and adds it to the master fd list.
*
* RETURNS:
- * Zero on success, error code on falure.
+ * Zero on success, error code on failure.
*/
int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
const struct drm_framebuffer_funcs *funcs)
@@ -2328,7 +2328,7 @@ int drm_mode_connector_property_set_ioctl(struct drm_device *dev,
} else if (connector->funcs->set_property)
ret = connector->funcs->set_property(connector, property, out_resp->value);
- /* store the property value if succesful */
+ /* store the property value if successful */
if (!ret)
drm_connector_property_set_value(connector, property, out_resp->value);
out:
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index abfc27b..a2a3fa5 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1309,7 +1309,7 @@ out_free_list:
* i915_gem_release_mmap - remove physical page mappings
* @obj: obj in question
*
- * Preserve the reservation of the mmaping with the DRM core code, but
+ * Preserve the reservation of the mmapping with the DRM core code, but
* relinquish ownership of the pages back to the system.
*
* It is vital that we remove the page mapping if we have mapped a tiled
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index 2b0fe54..40fcf6f 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -70,7 +70,7 @@ static struct drm_fb_helper_funcs intel_fb_helper_funcs = {
/**
- * Curretly it is assumed that the old framebuffer is reused.
+ * Currently it is assumed that the old framebuffer is reused.
*
* LOCKING
* caller should hold the mode config lock.
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index 083bec2..e7fa327 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -2726,7 +2726,7 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
/* Wrap with our custom algo which switches to DDC mode */
intel_output->ddc_bus->algo = &intel_sdvo_i2c_bit_algo;
- /* In defaut case sdvo lvds is false */
+ /* In default case sdvo lvds is false */
intel_sdvo_get_capabilities(intel_output, &sdvo_priv->caps);
if (intel_sdvo_output_setup(intel_output,
diff --git a/drivers/gpu/drm/radeon/atombios.h b/drivers/gpu/drm/radeon/atombios.h
index c11dddd..6643afc 100644
--- a/drivers/gpu/drm/radeon/atombios.h
+++ b/drivers/gpu/drm/radeon/atombios.h
@@ -1141,7 +1141,7 @@ typedef struct _LVDS_ENCODER_CONTROL_PARAMETERS {
/* ucTableFormatRevision=1,ucTableContentRevision=2 */
typedef struct _LVDS_ENCODER_CONTROL_PARAMETERS_V2 {
USHORT usPixelClock; /* in 10KHz; for bios convenient */
- UCHAR ucMisc; /* see PANEL_ENCODER_MISC_xx defintions below */
+ UCHAR ucMisc; /* see PANEL_ENCODER_MISC_xx definitions below */
UCHAR ucAction; /* 0: turn off encoder */
/* 1: setup and turn on encoder */
UCHAR ucTruncate; /* bit0=0: Disable truncate */
@@ -1424,7 +1424,7 @@ typedef struct _ATOM_MULTIMEDIA_CONFIG_INFO {
/* Structures used in FirmwareInfoTable */
/****************************************************************************/
-/* usBIOSCapability Defintion: */
+/* usBIOSCapability Definition: */
/* Bit 0 = 0: Bios image is not Posted, =1:Bios image is Posted; */
/* Bit 1 = 0: Dual CRTC is not supported, =1: Dual CRTC is supported; */
/* Bit 2 = 0: Extended Desktop is not supported, =1: Extended Desktop is supported; */
@@ -2386,7 +2386,7 @@ typedef struct _ATOM_ANALOG_TV_INFO_V1_2 {
} ATOM_ANALOG_TV_INFO_V1_2;
/**************************************************************************/
-/* VRAM usage and their defintions */
+/* VRAM usage and their definitions */
/* One chunk of VRAM used by Bios are for HWICON surfaces,EDID data. */
/* Current Mode timing and Dail Timing and/or STD timing data EACH device. They can be broken down as below. */
@@ -3046,7 +3046,7 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO {
#define ATOM_S0_SYSTEM_POWER_STATE_VALUE_DC 2
#define ATOM_S0_SYSTEM_POWER_STATE_VALUE_LITEAC 3
-/* Byte aligned defintion for BIOS usage */
+/* Byte aligned definition for BIOS usage */
#define ATOM_S0_CRT1_MONOb0 0x01
#define ATOM_S0_CRT1_COLORb0 0x02
#define ATOM_S0_CRT1_MASKb0 (ATOM_S0_CRT1_MONOb0+ATOM_S0_CRT1_COLORb0)
@@ -3131,7 +3131,7 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO {
#define ATOM_S2_DISPLAY_ROTATION_DEGREE_SHIFT 30
#define ATOM_S2_DISPLAY_ROTATION_ANGLE_MASK 0xC0000000L
-/* Byte aligned defintion for BIOS usage */
+/* Byte aligned definition for BIOS usage */
#define ATOM_S2_TV1_STANDARD_MASKb0 0x0F
#define ATOM_S2_CURRENT_BL_LEVEL_MASKb1 0xFF
#define ATOM_S2_CRT1_DPMS_STATEb2 0x01
@@ -3190,7 +3190,7 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO {
#define ATOM_S3_ALLOW_FAST_PWR_SWITCH 0x40000000L
#define ATOM_S3_RQST_GPU_USE_MIN_PWR 0x80000000L
-/* Byte aligned defintion for BIOS usage */
+/* Byte aligned definition for BIOS usage */
#define ATOM_S3_CRT1_ACTIVEb0 0x01
#define ATOM_S3_LCD1_ACTIVEb0 0x02
#define ATOM_S3_TV1_ACTIVEb0 0x04
@@ -3230,7 +3230,7 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO {
#define ATOM_S4_LCD1_REFRESH_MASK 0x0000FF00L
#define ATOM_S4_LCD1_REFRESH_SHIFT 8
-/* Byte aligned defintion for BIOS usage */
+/* Byte aligned definition for BIOS usage */
#define ATOM_S4_LCD1_PANEL_ID_MASKb0 0x0FF
#define ATOM_S4_LCD1_REFRESH_MASKb1 ATOM_S4_LCD1_PANEL_ID_MASKb0
#define ATOM_S4_VRAM_INFO_MASKb2 ATOM_S4_LCD1_PANEL_ID_MASKb0
@@ -3310,7 +3310,7 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO {
#define ATOM_S6_VRI_BRIGHTNESS_CHANGE 0x40000000L
#define ATOM_S6_CONFIG_DISPLAY_CHANGE_MASK 0x80000000L
-/* Byte aligned defintion for BIOS usage */
+/* Byte aligned definition for BIOS usage */
#define ATOM_S6_DEVICE_CHANGEb0 0x01
#define ATOM_S6_SCALER_CHANGEb0 0x02
#define ATOM_S6_LID_CHANGEb0 0x04
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index 278f646..6740ed2 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -394,11 +394,11 @@ int r600_mc_init(struct radeon_device *rdev)
* AGP so that GPU can catch out of VRAM/AGP access
*/
if (rdev->mc.gtt_location > rdev->mc.mc_vram_size) {
- /* Enought place before */
+ /* Enough place before */
rdev->mc.vram_location = rdev->mc.gtt_location -
rdev->mc.mc_vram_size;
} else if (tmp > rdev->mc.mc_vram_size) {
- /* Enought place after */
+ /* Enough place after */
rdev->mc.vram_location = rdev->mc.gtt_location +
rdev->mc.gtt_size;
} else {
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c
index b38c4c8..d10eb43 100644
--- a/drivers/gpu/drm/radeon/radeon_fb.c
+++ b/drivers/gpu/drm/radeon/radeon_fb.c
@@ -59,7 +59,7 @@ static struct fb_ops radeonfb_ops = {
};
/**
- * Curretly it is assumed that the old framebuffer is reused.
+ * Currently it is assumed that the old framebuffer is reused.
*
* LOCKING
* caller should hold the mode config lock.
diff --git a/drivers/gpu/drm/radeon/radeon_state.c b/drivers/gpu/drm/radeon/radeon_state.c
index 38537d9..067167c 100644
--- a/drivers/gpu/drm/radeon/radeon_state.c
+++ b/drivers/gpu/drm/radeon/radeon_state.c
@@ -1950,7 +1950,7 @@ static void radeon_apply_surface_regs(int surf_index,
* Note that refcount can be at most 2, since during a free refcount=3
* might mean we have to allocate a new surface which might not always
* be available.
- * For example : we allocate three contigous surfaces ABC. If B is
+ * For example : we allocate three contiguous surfaces ABC. If B is
* freed, we suddenly need two surfaces to store A and C, which might
* not always be available.
*/
diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
index 1381e06..eda4ade 100644
--- a/drivers/gpu/drm/radeon/radeon_ttm.c
+++ b/drivers/gpu/drm/radeon/radeon_ttm.c
@@ -378,7 +378,7 @@ static int radeon_bo_move(struct ttm_buffer_object *bo,
new_mem->mem_type == TTM_PL_SYSTEM) ||
(old_mem->mem_type == TTM_PL_SYSTEM &&
new_mem->mem_type == TTM_PL_TT)) {
- /* bind is enought */
+ /* bind is enough */
radeon_move_null(bo, new_mem);
return 0;
}
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
index b0efd0d..5e06ee7 100644
--- a/drivers/gpu/drm/radeon/rv770.c
+++ b/drivers/gpu/drm/radeon/rv770.c
@@ -829,11 +829,11 @@ int rv770_mc_init(struct radeon_device *rdev)
* AGP so that GPU can catch out of VRAM/AGP access
*/
if (rdev->mc.gtt_location > rdev->mc.mc_vram_size) {
- /* Enought place before */
+ /* Enough place before */
rdev->mc.vram_location = rdev->mc.gtt_location -
rdev->mc.mc_vram_size;
} else if (tmp > rdev->mc.mc_vram_size) {
- /* Enought place after */
+ /* Enough place after */
rdev->mc.vram_location = rdev->mc.gtt_location +
rdev->mc.gtt_size;
} else {
diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c
index c70927e..61c5572 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_util.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_util.c
@@ -427,7 +427,7 @@ static int ttm_bo_kmap_ttm(struct ttm_buffer_object *bo,
/*
* We need to use vmap to get the desired page protection
- * or to make the buffer object look contigous.
+ * or to make the buffer object look contiguous.
*/
prot = (mem->placement & TTM_PL_FLAG_CACHED) ?
PAGE_KERNEL :
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 7d05c4b..80792d3 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -39,8 +39,6 @@
* Version Information
*/
-#define DRIVER_VERSION "v2.6"
-#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik, Jiri Kosina"
#define DRIVER_DESC "HID core driver"
#define DRIVER_LICENSE "GPL"
@@ -1294,6 +1292,7 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) },
{ HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) },
@@ -1326,6 +1325,8 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K) },
@@ -1620,6 +1621,7 @@ static const struct hid_device_id hid_ignore_list[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KWORLD, USB_DEVICE_ID_KWORLD_RADIO_FM700) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_GPEN_560) },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_KYE, 0x0058) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOBILECASSY) },
@@ -1918,5 +1920,8 @@ static void __exit hid_exit(void)
module_init(hid_init);
module_exit(hid_exit);
+MODULE_AUTHOR("Andreas Gal");
+MODULE_AUTHOR("Vojtech Pavlik");
+MODULE_AUTHOR("Jiri Kosina");
MODULE_LICENSE(DRIVER_LICENSE);
diff --git a/drivers/hid/hid-cypress.c b/drivers/hid/hid-cypress.c
index 62e9cb1..998b6f4 100644
--- a/drivers/hid/hid-cypress.c
+++ b/drivers/hid/hid-cypress.c
@@ -126,6 +126,8 @@ static const struct hid_device_id cp_devices[] = {
.driver_data = CP_RDESC_SWAPPED_MIN_MAX },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2),
.driver_data = CP_RDESC_SWAPPED_MIN_MAX },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3),
+ .driver_data = CP_RDESC_SWAPPED_MIN_MAX },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE),
.driver_data = CP_2WHEEL_MOUSE_HACK },
{ }
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index adbef5d..3839340 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -117,6 +117,7 @@
#define USB_DEVICE_ID_CH_PRO_PEDALS 0x00f2
#define USB_DEVICE_ID_CH_COMBATSTICK 0x00f4
#define USB_DEVICE_ID_CH_FLIGHT_SIM_YOKE 0x00ff
+#define USB_DEVICE_ID_CH_3AXIS_5BUTTON_STICK 0x00d3
#define USB_VENDOR_ID_CHERRY 0x046a
#define USB_DEVICE_ID_CHERRY_CYMOTION 0x0023
@@ -145,6 +146,7 @@
#define USB_DEVICE_ID_CYPRESS_ULTRAMOUSE 0x7417
#define USB_DEVICE_ID_CYPRESS_BARCODE_1 0xde61
#define USB_DEVICE_ID_CYPRESS_BARCODE_2 0xde64
+#define USB_DEVICE_ID_CYPRESS_BARCODE_3 0xbca1
#define USB_VENDOR_ID_DEALEXTREAME 0x10c5
#define USB_DEVICE_ID_DEALEXTREAME_RADIO_SI4701 0x819a
@@ -304,6 +306,8 @@
#define USB_DEVICE_ID_S510_RECEIVER_2 0xc517
#define USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500 0xc512
#define USB_DEVICE_ID_MX3000_RECEIVER 0xc513
+#define USB_DEVICE_ID_SPACETRAVELLER 0xc623
+#define USB_DEVICE_ID_SPACENAVIGATOR 0xc626
#define USB_DEVICE_ID_DINOVO_DESKTOP 0xc704
#define USB_DEVICE_ID_DINOVO_EDGE 0xc714
#define USB_DEVICE_ID_DINOVO_MINI 0xc71f
@@ -346,6 +350,9 @@
#define USB_VENDOR_ID_NEC 0x073e
#define USB_DEVICE_ID_NEC_USB_GAME_PAD 0x0301
+#define USB_VENDOR_ID_NEXTWINDOW 0x1926
+#define USB_DEVICE_ID_NEXTWINDOW_TOUCHSCREEN 0x0003
+
#define USB_VENDOR_ID_NTRIG 0x1b96
#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN 0x0001
diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
index 0f870a3..9fcd3d0 100644
--- a/drivers/hid/hid-lg.c
+++ b/drivers/hid/hid-lg.c
@@ -33,6 +33,7 @@
#define LG_NOGET 0x100
#define LG_FF 0x200
#define LG_FF2 0x400
+#define LG_RDESC_REL_ABS 0x800
/*
* Certain Logitech keyboards send in report #3 keys which are far
@@ -51,6 +52,13 @@ static void lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
rdesc[84] = rdesc[89] = 0x4d;
rdesc[85] = rdesc[90] = 0x10;
}
+ if ((quirks & LG_RDESC_REL_ABS) && rsize >= 50 &&
+ rdesc[32] == 0x81 && rdesc[33] == 0x06 &&
+ rdesc[49] == 0x81 && rdesc[50] == 0x06) {
+ dev_info(&hdev->dev, "fixing up rel/abs in Logitech "
+ "report descriptor\n");
+ rdesc[33] = rdesc[50] = 0x02;
+ }
}
#define lg_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \
@@ -89,6 +97,22 @@ static int lg_ultrax_remote_mapping(struct hid_input *hi,
return 1;
}
+static int lg_dinovo_mapping(struct hid_input *hi, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
+ return 0;
+
+ switch (usage->hid & HID_USAGE) {
+
+ case 0x00d: lg_map_key_clear(KEY_MEDIA); break;
+ default:
+ return 0;
+
+ }
+ return 1;
+}
+
static int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage,
unsigned long **bit, int *max)
{
@@ -164,6 +188,10 @@ static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
lg_ultrax_remote_mapping(hi, usage, bit, max))
return 1;
+ if (hdev->product == USB_DEVICE_ID_DINOVO_MINI &&
+ lg_dinovo_mapping(hi, usage, bit, max))
+ return 1;
+
if ((quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max))
return 1;
@@ -303,8 +331,13 @@ static const struct hid_device_id lg_devices[] = {
.driver_data = LG_FF },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
.driver_data = LG_FF2 },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR),
+ .driver_data = LG_RDESC_REL_ABS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER),
+ .driver_data = LG_RDESC_REL_ABS },
{ }
};
+
MODULE_DEVICE_TABLE(hid, lg_devices);
static struct hid_driver lg_driver = {
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 03bd703..0258289 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -41,8 +41,6 @@
* Version Information
*/
-#define DRIVER_VERSION "v2.6"
-#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik, Jiri Kosina"
#define DRIVER_DESC "USB HID core driver"
#define DRIVER_LICENSE "GPL"
@@ -998,7 +996,8 @@ static int usbhid_start(struct hid_device *hid)
usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma;
usbhid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
- usbhid_init_reports(hid);
+ if (!(hid->quirks & HID_QUIRK_NO_INIT_REPORTS))
+ usbhid_init_reports(hid);
set_bit(HID_STARTED, &usbhid->iofl);
@@ -1395,8 +1394,7 @@ static int __init hid_init(void)
retval = usb_register(&hid_driver);
if (retval)
goto usb_register_fail;
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
return 0;
usb_register_fail:
@@ -1423,6 +1421,8 @@ static void __exit hid_exit(void)
module_init(hid_init);
module_exit(hid_exit);
-MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_AUTHOR("Andreas Gal");
+MODULE_AUTHOR("Vojtech Pavlik");
+MODULE_AUTHOR("Jiri Kosina");
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE(DRIVER_LICENSE);
diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c
index 484e3ee..e565dbe 100644
--- a/drivers/hid/usbhid/hid-pidff.c
+++ b/drivers/hid/usbhid/hid-pidff.c
@@ -1181,12 +1181,11 @@ static void pidff_reset(struct pidff_device *pidff)
usbhid_wait_io(hid);
if (pidff->pool[PID_SIMULTANEOUS_MAX].value) {
- int sim_effects = pidff->pool[PID_SIMULTANEOUS_MAX].value[0];
- while (sim_effects < 2) {
+ while (pidff->pool[PID_SIMULTANEOUS_MAX].value[0] < 2) {
if (i++ > 20) {
printk(KERN_WARNING "hid-pidff: device reports "
"%d simultaneous effects\n",
- sim_effects);
+ pidff->pool[PID_SIMULTANEOUS_MAX].value[0]);
break;
}
debug("pid_pool requested again");
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index 0d9045a..38773dc 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -37,6 +37,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_NATSU, USB_DEVICE_ID_NATSU_GAMEPAD, HID_QUIRK_BADPAD },
{ USB_VENDOR_ID_NEC, USB_DEVICE_ID_NEC_USB_GAME_PAD, HID_QUIRK_BADPAD },
+ { USB_VENDOR_ID_NEXTWINDOW, USB_DEVICE_ID_NEXTWINDOW_TOUCHSCREEN, HID_QUIRK_MULTI_INPUT},
{ USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD, HID_QUIRK_BADPAD },
{ USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD },
@@ -53,6 +54,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_COMBATSTICK, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_FLIGHT_SIM_YOKE, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_PRO_PEDALS, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_3AXIS_5BUTTON_STICK, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
@@ -280,7 +282,7 @@ u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct)
if (idVendor == USB_VENDOR_ID_NCR &&
idProduct >= USB_DEVICE_ID_NCR_FIRST &&
idProduct <= USB_DEVICE_ID_NCR_LAST)
- return HID_QUIRK_NOGET;
+ return HID_QUIRK_NO_INIT_REPORTS;
down_read(&dquirks_rwsem);
bl_entry = usbhid_exists_dquirk(idVendor, idProduct);
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c
index 8b6ee24..867e084 100644
--- a/drivers/hid/usbhid/hiddev.c
+++ b/drivers/hid/usbhid/hiddev.c
@@ -450,7 +450,6 @@ static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd,
uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL);
if (!uref_multi)
return -ENOMEM;
- lock_kernel();
uref = &uref_multi->uref;
if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
if (copy_from_user(uref_multi, user_arg,
@@ -528,7 +527,6 @@ static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd,
case HIDIOCGCOLLECTIONINDEX:
i = field->usage[uref->usage_index].collection_index;
- unlock_kernel();
kfree(uref_multi);
return i;
case HIDIOCGUSAGES:
@@ -547,15 +545,12 @@ static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd,
}
goodreturn:
- unlock_kernel();
kfree(uref_multi);
return 0;
fault:
- unlock_kernel();
kfree(uref_multi);
return -EFAULT;
inval:
- unlock_kernel();
kfree(uref_multi);
return -EINVAL;
}
diff --git a/drivers/hwmon/adm1029.c b/drivers/hwmon/adm1029.c
index 3671815..e845b75 100644
--- a/drivers/hwmon/adm1029.c
+++ b/drivers/hwmon/adm1029.c
@@ -432,7 +432,7 @@ static int adm1029_remove(struct i2c_client *client)
}
/*
-function that update the status of the chips (temperature for exemple)
+function that update the status of the chips (temperature for example)
*/
static struct adm1029_data *adm1029_update_device(struct device *dev)
{
diff --git a/drivers/hwmon/lm93.c b/drivers/hwmon/lm93.c
index fc36cad..c48a284 100644
--- a/drivers/hwmon/lm93.c
+++ b/drivers/hwmon/lm93.c
@@ -928,7 +928,7 @@ static void lm93_update_client_common(struct lm93_data *data,
data->prochot_interval = lm93_read_byte(client,
LM93_REG_PROCHOT_INTERVAL);
- /* Fan Boost Termperature registers */
+ /* Fan Boost Temperature registers */
for (i = 0; i < 4; i++)
data->boost[i] = lm93_read_byte(client, LM93_REG_BOOST(i));
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index 9a5d0aa..98ccfeb 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -7,50 +7,25 @@ config HAVE_IDE
bool
menuconfig IDE
- tristate "ATA/ATAPI/MFM/RLL support"
+ tristate "ATA/ATAPI/MFM/RLL support (DEPRECATED)"
depends on HAVE_IDE
depends on BLOCK
---help---
- If you say Y here, your kernel will be able to manage low cost mass
- storage units such as ATA/(E)IDE and ATAPI units. The most common
- cases are IDE hard drives and ATAPI CD-ROM drives.
-
- If your system is pure SCSI and doesn't use these interfaces, you
- can say N here.
-
- Integrated Disk Electronics (IDE aka ATA-1) is a connecting standard
- for mass storage units such as hard disks. It was designed by
- Western Digital and Compaq Computer in 1984. It was then named
- ST506. Quite a number of disks use the IDE interface.
-
- AT Attachment (ATA) is the superset of the IDE specifications.
- ST506 was also called ATA-1.
-
- Fast-IDE is ATA-2 (also named Fast ATA), Enhanced IDE (EIDE) is
- ATA-3. It provides support for larger disks (up to 8.4GB by means of
- the LBA standard), more disks (4 instead of 2) and for other mass
- storage units such as tapes and cdrom. UDMA/33 (aka UltraDMA/33) is
- ATA-4 and provides faster (and more CPU friendly) transfer modes
- than previous PIO (Programmed processor Input/Output) from previous
- ATA/IDE standards by means of fast DMA controllers.
-
- ATA Packet Interface (ATAPI) is a protocol used by EIDE tape and
- CD-ROM drives, similar in many respects to the SCSI protocol.
-
- SMART IDE (Self Monitoring, Analysis and Reporting Technology) was
- designed in order to prevent data corruption and disk crash by
- detecting pre hardware failure conditions (heat, access time, and
- the like...). Disks built since June 1995 may follow this standard.
- The kernel itself doesn't manage this; however there are quite a
- number of user programs such as smart that can query the status of
- SMART parameters from disk drives.
+ If you say Y here, your kernel will be able to manage ATA/(E)IDE and
+ ATAPI units. The most common cases are IDE hard drives and ATAPI
+ CD-ROM drives.
+
+ This subsystem is currently in maintenance mode with only bug fix
+ changes applied. Users of ATA hardware are encouraged to migrate to
+ the newer ATA subsystem ("Serial ATA (prod) and Parallel ATA
+ (experimental) drivers") which is more actively maintained.
To compile this driver as a module, choose M here: the
module will be called ide-core.
For further information, please read <file:Documentation/ide/ide.txt>.
- If unsure, say Y.
+ If unsure, say N.
if IDE
diff --git a/drivers/ide/alim15x3.c b/drivers/ide/alim15x3.c
index e59b6de..0abc43f 100644
--- a/drivers/ide/alim15x3.c
+++ b/drivers/ide/alim15x3.c
@@ -40,16 +40,6 @@
#define DRV_NAME "alim15x3"
/*
- * Allow UDMA on M1543C-E chipset for WDC disks that ignore CRC checking
- * (this is DANGEROUS and could result in data corruption).
- */
-static int wdc_udma;
-
-module_param(wdc_udma, bool, 0);
-MODULE_PARM_DESC(wdc_udma,
- "allow UDMA on M1543C-E chipset for WDC disks (DANGEROUS)");
-
-/*
* ALi devices are not plug in. Otherwise these static values would
* need to go. They ought to go away anyway
*/
@@ -132,7 +122,7 @@ static u8 ali_udma_filter(ide_drive_t *drive)
if (m5229_revision > 0x20 && m5229_revision < 0xC2) {
if (drive->media != ide_disk)
return 0;
- if (wdc_udma == 0 && chip_is_1543c_e &&
+ if (chip_is_1543c_e &&
strstr((char *)&drive->id[ATA_ID_PROD], "WDC "))
return 0;
}
diff --git a/drivers/ide/au1xxx-ide.c b/drivers/ide/au1xxx-ide.c
index 58121bd..87cef0c 100644
--- a/drivers/ide/au1xxx-ide.c
+++ b/drivers/ide/au1xxx-ide.c
@@ -532,14 +532,13 @@ static int au_ide_probe(struct platform_device *dev)
goto out;
}
- if (!request_mem_region(res->start, res->end - res->start + 1,
- dev->name)) {
+ if (!request_mem_region(res->start, resource_size(res), dev->name)) {
pr_debug("%s: request_mem_region failed\n", DRV_NAME);
ret = -EBUSY;
goto out;
}
- ahwif->regbase = (u32)ioremap(res->start, res->end - res->start + 1);
+ ahwif->regbase = (u32)ioremap(res->start, resource_size(res));
if (ahwif->regbase == 0) {
ret = -ENOMEM;
goto out;
@@ -575,7 +574,7 @@ static int au_ide_remove(struct platform_device *dev)
iounmap((void *)ahwif->regbase);
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
- release_mem_region(res->start, res->end - res->start + 1);
+ release_mem_region(res->start, resource_size(res));
return 0;
}
diff --git a/drivers/ide/cmd64x.c b/drivers/ide/cmd64x.c
index ca0c46f..f2500c8 100644
--- a/drivers/ide/cmd64x.c
+++ b/drivers/ide/cmd64x.c
@@ -20,14 +20,6 @@
#define DRV_NAME "cmd64x"
-#define CMD_DEBUG 0
-
-#if CMD_DEBUG
-#define cmdprintk(x...) printk(x)
-#else
-#define cmdprintk(x...)
-#endif
-
/*
* CMD64x specific registers definition.
*/
@@ -76,9 +68,6 @@ static void program_cycle_times (ide_drive_t *drive, int cycle_time, int active_
{15, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0};
static const u8 drwtim_regs[4] = {DRWTIM0, DRWTIM1, DRWTIM2, DRWTIM3};
- cmdprintk("program_cycle_times parameters: total=%d, active=%d\n",
- cycle_time, active_time);
-
cycle_count = quantize_timing( cycle_time, clock_time);
active_count = quantize_timing(active_time, clock_time);
recovery_count = cycle_count - active_count;
@@ -94,9 +83,6 @@ static void program_cycle_times (ide_drive_t *drive, int cycle_time, int active_
if (active_count > 16) /* shouldn't actually happen... */
active_count = 16;
- cmdprintk("Final counts: total=%d, active=%d, recovery=%d\n",
- cycle_count, active_count, recovery_count);
-
/*
* Convert values to internal chipset representation
*/
@@ -106,7 +92,6 @@ static void program_cycle_times (ide_drive_t *drive, int cycle_time, int active_
/* Program the active/recovery counts into the DRWTIM register */
drwtim = (active_count << 4) | recovery_count;
(void) pci_write_config_byte(dev, drwtim_regs[drive->dn], drwtim);
- cmdprintk("Write 0x%02x to reg 0x%x\n", drwtim, drwtim_regs[drive->dn]);
}
/*
@@ -150,7 +135,6 @@ static void cmd64x_tune_pio(ide_drive_t *drive, const u8 pio)
if (setup_count > 5) /* shouldn't actually happen... */
setup_count = 5;
- cmdprintk("Final address setup count: %d\n", setup_count);
/*
* Program the address setup clocks into the ARTTIM registers.
@@ -162,7 +146,6 @@ static void cmd64x_tune_pio(ide_drive_t *drive, const u8 pio)
arttim &= ~0xc0;
arttim |= setup_values[setup_count];
(void) pci_write_config_byte(dev, arttim_regs[drive->dn], arttim);
- cmdprintk("Write 0x%02x to reg 0x%x\n", arttim, arttim_regs[drive->dn]);
}
/*
diff --git a/drivers/ide/cs5535.c b/drivers/ide/cs5535.c
index 983d957..b883838 100644
--- a/drivers/ide/cs5535.c
+++ b/drivers/ide/cs5535.c
@@ -187,6 +187,7 @@ static int __devinit cs5535_init_one(struct pci_dev *dev,
static const struct pci_device_id cs5535_pci_tbl[] = {
{ PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_CS5535_IDE), 0 },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5535_IDE), },
{ 0, },
};
diff --git a/drivers/ide/cy82c693.c b/drivers/ide/cy82c693.c
index 74fc540..d6e2cbb 100644
--- a/drivers/ide/cy82c693.c
+++ b/drivers/ide/cy82c693.c
@@ -51,11 +51,6 @@
#define DRV_NAME "cy82c693"
/*
- * The following are used to debug the driver.
- */
-#define CY82C693_DEBUG_INFO 0
-
-/*
* NOTE: the value for busmaster timeout is tricky and I got it by
* trial and error! By using a to low value will cause DMA timeouts
* and drop IDE performance, and by using a to high value will cause
@@ -176,11 +171,6 @@ static void cy82c693_set_dma_mode(ide_drive_t *drive, const u8 mode)
outb(index, CY82_INDEX_PORT);
outb(data, CY82_DATA_PORT);
-#if CY82C693_DEBUG_INFO
- printk(KERN_INFO "%s (ch=%d, dev=%d): set DMA mode to %d (single=%d)\n",
- drive->name, hwif->channel, drive->dn & 1, mode & 3, single);
-#endif /* CY82C693_DEBUG_INFO */
-
/*
* note: below we set the value for Bus Master IDE TimeOut Register
* I'm not absolutly sure what this does, but it solved my problem
@@ -194,11 +184,6 @@ static void cy82c693_set_dma_mode(ide_drive_t *drive, const u8 mode)
data = BUSMASTER_TIMEOUT;
outb(CY82_INDEX_TIMEOUT, CY82_INDEX_PORT);
outb(data, CY82_DATA_PORT);
-
-#if CY82C693_DEBUG_INFO
- printk(KERN_INFO "%s: Set IDE Bus Master TimeOut Register to 0x%X\n",
- drive->name, data);
-#endif /* CY82C693_DEBUG_INFO */
}
static void cy82c693_set_pio_mode(ide_drive_t *drive, const u8 pio)
@@ -239,8 +224,6 @@ static void cy82c693_set_pio_mode(ide_drive_t *drive, const u8 pio)
pci_write_config_byte(dev, CY82_IDE_MASTER_IOR, pclk.time_16r);
pci_write_config_byte(dev, CY82_IDE_MASTER_IOW, pclk.time_16w);
pci_write_config_byte(dev, CY82_IDE_MASTER_8BIT, pclk.time_8);
-
- addrCtrl &= 0xF;
} else {
/*
* set slave drive
@@ -257,17 +240,7 @@ static void cy82c693_set_pio_mode(ide_drive_t *drive, const u8 pio)
pci_write_config_byte(dev, CY82_IDE_SLAVE_IOR, pclk.time_16r);
pci_write_config_byte(dev, CY82_IDE_SLAVE_IOW, pclk.time_16w);
pci_write_config_byte(dev, CY82_IDE_SLAVE_8BIT, pclk.time_8);
-
- addrCtrl >>= 4;
- addrCtrl &= 0xF;
}
-
-#if CY82C693_DEBUG_INFO
- printk(KERN_INFO "%s (ch=%d, dev=%d): set PIO timing to "
- "(addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n",
- drive->name, hwif->channel, drive->dn & 1,
- addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
-#endif /* CY82C693_DEBUG_INFO */
}
static void __devinit init_iops_cy82c693(ide_hwif_t *hwif)
diff --git a/drivers/ide/hpt366.c b/drivers/ide/hpt366.c
index 7ce68ef..4d90ac2 100644
--- a/drivers/ide/hpt366.c
+++ b/drivers/ide/hpt366.c
@@ -297,68 +297,6 @@ static u32 twenty_five_base_hpt36x[] = {
/* XFER_PIO_0 */ 0xc0d08585
};
-#if 0
-/* These are the timing tables from the HighPoint open source drivers... */
-static u32 thirty_three_base_hpt37x[] = {
- /* XFER_UDMA_6 */ 0x12446231, /* 0x12646231 ?? */
- /* XFER_UDMA_5 */ 0x12446231,
- /* XFER_UDMA_4 */ 0x12446231,
- /* XFER_UDMA_3 */ 0x126c6231,
- /* XFER_UDMA_2 */ 0x12486231,
- /* XFER_UDMA_1 */ 0x124c6233,
- /* XFER_UDMA_0 */ 0x12506297,
-
- /* XFER_MW_DMA_2 */ 0x22406c31,
- /* XFER_MW_DMA_1 */ 0x22406c33,
- /* XFER_MW_DMA_0 */ 0x22406c97,
-
- /* XFER_PIO_4 */ 0x06414e31,
- /* XFER_PIO_3 */ 0x06414e42,
- /* XFER_PIO_2 */ 0x06414e53,
- /* XFER_PIO_1 */ 0x06814e93,
- /* XFER_PIO_0 */ 0x06814ea7
-};
-
-static u32 fifty_base_hpt37x[] = {
- /* XFER_UDMA_6 */ 0x12848242,
- /* XFER_UDMA_5 */ 0x12848242,
- /* XFER_UDMA_4 */ 0x12ac8242,
- /* XFER_UDMA_3 */ 0x128c8242,
- /* XFER_UDMA_2 */ 0x120c8242,
- /* XFER_UDMA_1 */ 0x12148254,
- /* XFER_UDMA_0 */ 0x121882ea,
-
- /* XFER_MW_DMA_2 */ 0x22808242,
- /* XFER_MW_DMA_1 */ 0x22808254,
- /* XFER_MW_DMA_0 */ 0x228082ea,
-
- /* XFER_PIO_4 */ 0x0a81f442,
- /* XFER_PIO_3 */ 0x0a81f443,
- /* XFER_PIO_2 */ 0x0a81f454,
- /* XFER_PIO_1 */ 0x0ac1f465,
- /* XFER_PIO_0 */ 0x0ac1f48a
-};
-
-static u32 sixty_six_base_hpt37x[] = {
- /* XFER_UDMA_6 */ 0x1c869c62,
- /* XFER_UDMA_5 */ 0x1cae9c62, /* 0x1c8a9c62 */
- /* XFER_UDMA_4 */ 0x1c8a9c62,
- /* XFER_UDMA_3 */ 0x1c8e9c62,
- /* XFER_UDMA_2 */ 0x1c929c62,
- /* XFER_UDMA_1 */ 0x1c9a9c62,
- /* XFER_UDMA_0 */ 0x1c829c62,
-
- /* XFER_MW_DMA_2 */ 0x2c829c62,
- /* XFER_MW_DMA_1 */ 0x2c829c66,
- /* XFER_MW_DMA_0 */ 0x2c829d2e,
-
- /* XFER_PIO_4 */ 0x0c829c62,
- /* XFER_PIO_3 */ 0x0c829c84,
- /* XFER_PIO_2 */ 0x0c829ca6,
- /* XFER_PIO_1 */ 0x0d029d26,
- /* XFER_PIO_0 */ 0x0d029d5e
-};
-#else
/*
* The following are the new timing tables with PIO mode data/taskfile transfer
* overclocking fixed...
@@ -424,16 +362,13 @@ static u32 sixty_six_base_hpt37x[] = {
/* XFER_PIO_1 */ 0x0d02ff26,
/* XFER_PIO_0 */ 0x0d42ff7f
};
-#endif
-#define HPT366_DEBUG_DRIVE_INFO 0
#define HPT371_ALLOW_ATA133_6 1
#define HPT302_ALLOW_ATA133_6 1
#define HPT372_ALLOW_ATA133_6 1
#define HPT370_ALLOW_ATA100_5 0
#define HPT366_ALLOW_ATA66_4 1
#define HPT366_ALLOW_ATA66_3 1
-#define HPT366_MAX_DEVS 8
/* Supported ATA clock frequencies */
enum ata_clock {
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index 58fc920..6a0e625 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -221,6 +221,8 @@ typedef struct ide_tape_obj {
static DEFINE_MUTEX(idetape_ref_mutex);
+static DEFINE_MUTEX(idetape_chrdev_mutex);
+
static struct class *idetape_sysfs_class;
static void ide_tape_release(struct device *);
@@ -1457,10 +1459,11 @@ static int idetape_chrdev_open(struct inode *inode, struct file *filp)
if (i >= MAX_HWIFS * MAX_DRIVES)
return -ENXIO;
- lock_kernel();
+ mutex_lock(&idetape_chrdev_mutex);
+
tape = ide_tape_get(NULL, true, i);
if (!tape) {
- unlock_kernel();
+ mutex_unlock(&idetape_chrdev_mutex);
return -ENXIO;
}
@@ -1519,12 +1522,15 @@ static int idetape_chrdev_open(struct inode *inode, struct file *filp)
tape->door_locked = DOOR_LOCKED;
}
}
- unlock_kernel();
+ mutex_unlock(&idetape_chrdev_mutex);
+
return 0;
out_put_tape:
ide_tape_put(tape);
- unlock_kernel();
+
+ mutex_unlock(&idetape_chrdev_mutex);
+
return retval;
}
@@ -1551,7 +1557,8 @@ static int idetape_chrdev_release(struct inode *inode, struct file *filp)
ide_drive_t *drive = tape->drive;
unsigned int minor = iminor(inode);
- lock_kernel();
+ mutex_lock(&idetape_chrdev_mutex);
+
tape = drive->driver_data;
ide_debug_log(IDE_DBG_FUNC, "enter");
@@ -1575,7 +1582,9 @@ static int idetape_chrdev_release(struct inode *inode, struct file *filp)
}
clear_bit(ilog2(IDE_AFLAG_BUSY), &drive->atapi_flags);
ide_tape_put(tape);
- unlock_kernel();
+
+ mutex_unlock(&idetape_chrdev_mutex);
+
return 0;
}
diff --git a/drivers/ide/ide_platform.c b/drivers/ide/ide_platform.c
index b579fbe..42965b3 100644
--- a/drivers/ide/ide_platform.c
+++ b/drivers/ide/ide_platform.c
@@ -81,14 +81,14 @@ static int __devinit plat_ide_probe(struct platform_device *pdev)
if (mmio) {
base = devm_ioremap(&pdev->dev,
- res_base->start, res_base->end - res_base->start + 1);
+ res_base->start, resource_size(res_base));
alt_base = devm_ioremap(&pdev->dev,
- res_alt->start, res_alt->end - res_alt->start + 1);
+ res_alt->start, resource_size(res_alt));
} else {
base = devm_ioport_map(&pdev->dev,
- res_base->start, res_base->end - res_base->start + 1);
+ res_base->start, resource_size(res_base));
alt_base = devm_ioport_map(&pdev->dev,
- res_alt->start, res_alt->end - res_alt->start + 1);
+ res_alt->start, resource_size(res_alt));
}
memset(&hw, 0, sizeof(hw));
diff --git a/drivers/ide/pdc202xx_old.c b/drivers/ide/pdc202xx_old.c
index cb812f3..35161dd 100644
--- a/drivers/ide/pdc202xx_old.c
+++ b/drivers/ide/pdc202xx_old.c
@@ -21,8 +21,6 @@
#define DRV_NAME "pdc202xx_old"
-#define PDC202XX_DEBUG_DRIVE_INFO 0
-
static void pdc_old_disable_66MHz_clock(ide_hwif_t *);
static void pdc202xx_set_mode(ide_drive_t *drive, const u8 speed)
@@ -34,11 +32,6 @@ static void pdc202xx_set_mode(ide_drive_t *drive, const u8 speed)
u8 AP = 0, BP = 0, CP = 0;
u8 TA = 0, TB = 0, TC = 0;
-#if PDC202XX_DEBUG_DRIVE_INFO
- u32 drive_conf = 0;
- pci_read_config_dword(dev, drive_pci, &drive_conf);
-#endif
-
/*
* TODO: do this once per channel
*/
@@ -89,14 +82,6 @@ static void pdc202xx_set_mode(ide_drive_t *drive, const u8 speed)
pci_write_config_byte(dev, drive_pci + 1, BP | TB);
pci_write_config_byte(dev, drive_pci + 2, CP | TC);
}
-
-#if PDC202XX_DEBUG_DRIVE_INFO
- printk(KERN_DEBUG "%s: %s drive%d 0x%08x ",
- drive->name, ide_xfer_verbose(speed),
- drive->dn, drive_conf);
- pci_read_config_dword(dev, drive_pci, &drive_conf);
- printk("0x%08x\n", drive_conf);
-#endif
}
static void pdc202xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
diff --git a/drivers/ide/sis5513.c b/drivers/ide/sis5513.c
index 3b88eba..4687060 100644
--- a/drivers/ide/sis5513.c
+++ b/drivers/ide/sis5513.c
@@ -632,12 +632,3 @@ module_exit(sis5513_ide_exit);
MODULE_AUTHOR("Lionel Bouton, L C Chang, Andre Hedrick, Vojtech Pavlik");
MODULE_DESCRIPTION("PCI driver module for SIS IDE");
MODULE_LICENSE("GPL");
-
-/*
- * TODO:
- * - CLEANUP
- * - More checks in the config registers (force values instead of
- * relying on the BIOS setting them correctly).
- * - Further optimisations ?
- * . for example ATA66+ regs 0x48 & 0x4A
- */
diff --git a/drivers/ide/sl82c105.c b/drivers/ide/sl82c105.c
index d698da4..3c2bbf0 100644
--- a/drivers/ide/sl82c105.c
+++ b/drivers/ide/sl82c105.c
@@ -24,13 +24,6 @@
#define DRV_NAME "sl82c105"
-#undef DEBUG
-
-#ifdef DEBUG
-#define DBG(arg) printk arg
-#else
-#define DBG(fmt,...)
-#endif
/*
* SL82C105 PCI config register 0x40 bits.
*/
@@ -104,9 +97,6 @@ static void sl82c105_set_dma_mode(ide_drive_t *drive, const u8 speed)
unsigned long timings = (unsigned long)ide_get_drivedata(drive);
u16 drv_ctrl;
- DBG(("sl82c105_tune_chipset(drive:%s, speed:%s)\n",
- drive->name, ide_xfer_verbose(speed)));
-
drv_ctrl = mwdma_timings[speed - XFER_MW_DMA_0];
/*
@@ -196,8 +186,6 @@ static void sl82c105_dma_start(ide_drive_t *drive)
struct pci_dev *dev = to_pci_dev(hwif->dev);
int reg = 0x44 + drive->dn * 4;
- DBG(("%s(drive:%s)\n", __func__, drive->name));
-
pci_write_config_word(dev, reg,
(unsigned long)ide_get_drivedata(drive) >> 16);
@@ -209,8 +197,6 @@ static void sl82c105_dma_clear(ide_drive_t *drive)
{
struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
- DBG(("sl82c105_dma_clear(drive:%s)\n", drive->name));
-
sl82c105_reset_host(dev);
}
@@ -218,11 +204,7 @@ static int sl82c105_dma_end(ide_drive_t *drive)
{
struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
int reg = 0x44 + drive->dn * 4;
- int ret;
-
- DBG(("%s(drive:%s)\n", __func__, drive->name));
-
- ret = ide_dma_end(drive);
+ int ret = ide_dma_end(drive);
pci_write_config_word(dev, reg,
(unsigned long)ide_get_drivedata(drive));
@@ -239,8 +221,6 @@ static void sl82c105_resetproc(ide_drive_t *drive)
struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
u32 val;
- DBG(("sl82c105_resetproc(drive:%s)\n", drive->name));
-
pci_read_config_dword(dev, 0x40, &val);
val |= (CTRL_P1F16 | CTRL_P0F16);
pci_write_config_dword(dev, 0x40, val);
@@ -291,8 +271,6 @@ static int init_chipset_sl82c105(struct pci_dev *dev)
{
u32 val;
- DBG(("init_chipset_sl82c105()\n"));
-
pci_read_config_dword(dev, 0x40, &val);
val |= CTRL_P0EN | CTRL_P0F16 | CTRL_P1F16;
pci_write_config_dword(dev, 0x40, val);
diff --git a/drivers/ide/slc90e66.c b/drivers/ide/slc90e66.c
index 9aec78d..1ccfb40 100644
--- a/drivers/ide/slc90e66.c
+++ b/drivers/ide/slc90e66.c
@@ -91,8 +91,7 @@ static void slc90e66_set_dma_mode(ide_drive_t *drive, const u8 speed)
if (!(reg48 & u_flag))
pci_write_config_word(dev, 0x48, reg48|u_flag);
- /* FIXME: (reg4a & a_speed) ? */
- if ((reg4a & u_speed) != u_speed) {
+ if ((reg4a & a_speed) != u_speed) {
pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
pci_read_config_word(dev, 0x4a, &reg4a);
pci_write_config_word(dev, 0x4a, reg4a|u_speed);
diff --git a/drivers/ide/tx4938ide.c b/drivers/ide/tx4938ide.c
index ea89fdd..fd59c0d 100644
--- a/drivers/ide/tx4938ide.c
+++ b/drivers/ide/tx4938ide.c
@@ -146,7 +146,7 @@ static int __init tx4938ide_probe(struct platform_device *pdev)
return -ENODEV;
if (!devm_request_mem_region(&pdev->dev, res->start,
- res->end - res->start + 1, "tx4938ide"))
+ resource_size(res), "tx4938ide"))
return -EBUSY;
mapbase = (unsigned long)devm_ioremap(&pdev->dev, res->start,
8 << pdata->ioport_shift);
diff --git a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c
index 2cd00b5..9fd4a0d 100644
--- a/drivers/ieee1394/dv1394.c
+++ b/drivers/ieee1394/dv1394.c
@@ -125,7 +125,7 @@
0 - no debugging messages
1 - some debugging messages, but none during DMA frame transmission
2 - lots of messages, including during DMA frame transmission
- (will cause undeflows if your machine is too slow!)
+ (will cause underflows if your machine is too slow!)
*/
#define DV1394_DEBUG_LEVEL 0
diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c
index 72ed339..0677fc7 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_hal.c
+++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c
@@ -589,7 +589,7 @@ static int cxio_hal_destroy_ctrl_qp(struct cxio_rdev *rdev_p)
/* write len bytes of data into addr (32B aligned address)
* If data is NULL, clear len byte of memory to zero.
- * caller aquires the ctrl_qp lock before the call
+ * caller acquires the ctrl_qp lock before the call
*/
static int cxio_hal_ctrl_qp_write_mem(struct cxio_rdev *rdev_p, u32 addr,
u32 len, void *data)
diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c
index 40dbe54..73933a4 100644
--- a/drivers/infiniband/hw/ipath/ipath_file_ops.c
+++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c
@@ -1821,7 +1821,6 @@ done:
static int ipath_open(struct inode *in, struct file *fp)
{
/* The real work is performed later in ipath_assign_port() */
- cycle_kernel_lock();
fp->private_data = kzalloc(sizeof(struct ipath_filedata), GFP_KERNEL);
return fp->private_data ? 0 : -ENOMEM;
}
diff --git a/drivers/infiniband/hw/ipath/ipath_iba6110.c b/drivers/infiniband/hw/ipath/ipath_iba6110.c
index 4bd39c8..37d12e5 100644
--- a/drivers/infiniband/hw/ipath/ipath_iba6110.c
+++ b/drivers/infiniband/hw/ipath/ipath_iba6110.c
@@ -381,7 +381,7 @@ static const ipath_err_t infinipath_hwe_htclnkbbyte1crcerr =
#define IPATH_GPIO_SCL \
(1ULL << (_IPATH_GPIO_SCL_NUM+INFINIPATH_EXTC_GPIOOE_SHIFT))
-/* keep the code below somewhat more readonable; not used elsewhere */
+/* keep the code below somewhat more readable; not used elsewhere */
#define _IPATH_HTLINK0_CRCBITS (infinipath_hwe_htclnkabyte0crcerr | \
infinipath_hwe_htclnkabyte1crcerr)
#define _IPATH_HTLINK1_CRCBITS (infinipath_hwe_htclnkbbyte0crcerr | \
diff --git a/drivers/infiniband/hw/ipath/ipath_sd7220.c b/drivers/infiniband/hw/ipath/ipath_sd7220.c
index aa47eb5..2a68d9f 100644
--- a/drivers/infiniband/hw/ipath/ipath_sd7220.c
+++ b/drivers/infiniband/hw/ipath/ipath_sd7220.c
@@ -614,7 +614,7 @@ static int epb_trans(struct ipath_devdata *dd, u16 reg, u64 i_val, u64 *o_vp)
* @wd: Write Data - value to set in register
* @mask: ones where data should be spliced into reg.
*
- * Basic register read/modify/write, with un-needed acesses elided. That is,
+ * Basic register read/modify/write, with un-needed accesses elided. That is,
* a mask of zero will prevent write, while a mask of 0xFF will prevent read.
* returns current (presumed, if a write was done) contents of selected
* register, or <0 if errors.
@@ -989,7 +989,7 @@ static struct rxeq_init {
/* Set DFELTHFDR/HDR thresholds */
RXEQ_VAL(7, 8, 0, 0, 0, 0), /* FDR */
RXEQ_VAL(7, 0x21, 0, 0, 0, 0), /* HDR */
- /* Set TLTHFDR/HDR theshold */
+ /* Set TLTHFDR/HDR threshold */
RXEQ_VAL(7, 9, 2, 2, 2, 2), /* FDR */
RXEQ_VAL(7, 0x23, 2, 2, 2, 2), /* HDR */
/* Set Preamp setting 2 (ZFR/ZCNT) */
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c
index 219b103..256a00c 100644
--- a/drivers/infiniband/hw/mlx4/qp.c
+++ b/drivers/infiniband/hw/mlx4/qp.c
@@ -352,7 +352,7 @@ static int set_kernel_sq_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap,
* anymore, so we do this only if selective signaling is off.
*
* Further, on 32-bit platforms, we can't use vmap() to make
- * the QP buffer virtually contigious. Thus we have to use
+ * the QP buffer virtually contiguous. Thus we have to use
* constant-sized WRs to make sure a WR is always fully within
* a single page-sized chunk.
*
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index add9188..5f7a6fc 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -625,6 +625,7 @@ static struct iscsi_transport iscsi_iser_transport = {
ISCSI_USERNAME | ISCSI_PASSWORD |
ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN |
ISCSI_FAST_ABORT | ISCSI_ABORT_TMO |
+ ISCSI_LU_RESET_TMO | ISCSI_TGT_RESET_TMO |
ISCSI_PING_TMO | ISCSI_RECV_TMO |
ISCSI_IFACE_NAME | ISCSI_INITIATOR_NAME,
.host_param_mask = ISCSI_HOST_HWADDRESS |
diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
index ea9e155..8579f32 100644
--- a/drivers/infiniband/ulp/iser/iser_verbs.c
+++ b/drivers/infiniband/ulp/iser/iser_verbs.c
@@ -499,7 +499,7 @@ void iser_conn_init(struct iser_conn *ib_conn)
/**
* starts the process of connecting to the target
- * sleeps untill the connection is established or rejected
+ * sleeps until the connection is established or rejected
*/
int iser_connect(struct iser_conn *ib_conn,
struct sockaddr_in *src_addr,
diff --git a/drivers/input/keyboard/sh_keysc.c b/drivers/input/keyboard/sh_keysc.c
index 887af79..076111f 100644
--- a/drivers/input/keyboard/sh_keysc.c
+++ b/drivers/input/keyboard/sh_keysc.c
@@ -18,9 +18,9 @@
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/input.h>
+#include <linux/input/sh_keysc.h>
#include <linux/clk.h>
#include <linux/io.h>
-#include <asm/sh_keysc.h>
#define KYCR1_OFFS 0x00
#define KYCR2_OFFS 0x04
diff --git a/drivers/input/misc/hp_sdc_rtc.c b/drivers/input/misc/hp_sdc_rtc.c
index ea821b5..ad730e1 100644
--- a/drivers/input/misc/hp_sdc_rtc.c
+++ b/drivers/input/misc/hp_sdc_rtc.c
@@ -35,7 +35,6 @@
#include <linux/hp_sdc.h>
#include <linux/errno.h>
-#include <linux/smp_lock.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/module.h>
@@ -409,7 +408,6 @@ static unsigned int hp_sdc_rtc_poll(struct file *file, poll_table *wait)
static int hp_sdc_rtc_open(struct inode *inode, struct file *file)
{
- cycle_kernel_lock();
return 0;
}
diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c
index 1c9410d..bcc2d30 100644
--- a/drivers/input/serio/hp_sdc.c
+++ b/drivers/input/serio/hp_sdc.c
@@ -955,7 +955,7 @@ static int __init hp_sdc_init_hppa(struct parisc_device *d)
INIT_DELAYED_WORK(&moduleloader_work, request_module_delayed);
ret = hp_sdc_init();
- /* after sucessfull initialization give SDC some time to settle
+ /* after successfull initialization give SDC some time to settle
* and then load the hp_sdc_mlc upper layer driver */
if (!ret)
schedule_delayed_work(&moduleloader_work,
diff --git a/drivers/input/serio/hp_sdc_mlc.c b/drivers/input/serio/hp_sdc_mlc.c
index 820e516..7d2b820 100644
--- a/drivers/input/serio/hp_sdc_mlc.c
+++ b/drivers/input/serio/hp_sdc_mlc.c
@@ -125,7 +125,7 @@ static void hp_sdc_mlc_isr (int irq, void *dev_id,
break;
default:
- printk(KERN_WARNING PREFIX "Unkown HIL Error status (%x)!\n", data);
+ printk(KERN_WARNING PREFIX "Unknown HIL Error status (%x)!\n", data);
break;
}
diff --git a/drivers/input/touchscreen/atmel-wm97xx.c b/drivers/input/touchscreen/atmel-wm97xx.c
index 35377f5..a12242f 100644
--- a/drivers/input/touchscreen/atmel-wm97xx.c
+++ b/drivers/input/touchscreen/atmel-wm97xx.c
@@ -59,7 +59,7 @@
#define ATMEL_WM97XX_AC97C_IRQ (29)
#define ATMEL_WM97XX_GPIO_DEFAULT (32+16) /* Pin 16 on port B. */
#else
-#error Unkown CPU, this driver only supports AT32AP700X CPUs.
+#error Unknown CPU, this driver only supports AT32AP700X CPUs.
#endif
struct continuous {
diff --git a/drivers/input/touchscreen/mainstone-wm97xx.c b/drivers/input/touchscreen/mainstone-wm97xx.c
index 8fc3b08..6cdcf2a 100644
--- a/drivers/input/touchscreen/mainstone-wm97xx.c
+++ b/drivers/input/touchscreen/mainstone-wm97xx.c
@@ -14,7 +14,7 @@
*
* Notes:
* This is a wm97xx extended touch driver to capture touch
- * data in a continuous manner on the Intel XScale archictecture
+ * data in a continuous manner on the Intel XScale architecture
*
* Features:
* - codecs supported:- WM9705, WM9712, WM9713
@@ -131,7 +131,7 @@ static int wm97xx_acc_pen_down(struct wm97xx *wm)
/* When the AC97 queue has been drained we need to allow time
* to buffer up samples otherwise we end up spinning polling
* for samples. The controller can't have a suitably low
- * threashold set to use the notifications it gives.
+ * threshold set to use the notifications it gives.
*/
schedule_timeout_uninterruptible(1);
diff --git a/drivers/input/touchscreen/zylonite-wm97xx.c b/drivers/input/touchscreen/zylonite-wm97xx.c
index 41e4359..eca54db 100644
--- a/drivers/input/touchscreen/zylonite-wm97xx.c
+++ b/drivers/input/touchscreen/zylonite-wm97xx.c
@@ -96,7 +96,7 @@ static int wm97xx_acc_pen_down(struct wm97xx *wm)
/* When the AC97 queue has been drained we need to allow time
* to buffer up samples otherwise we end up spinning polling
* for samples. The controller can't have a suitably low
- * threashold set to use the notifications it gives.
+ * threshold set to use the notifications it gives.
*/
msleep(1);
diff --git a/drivers/isdn/act2000/Kconfig b/drivers/isdn/act2000/Kconfig
index 3fc1a54..fa2673f 100644
--- a/drivers/isdn/act2000/Kconfig
+++ b/drivers/isdn/act2000/Kconfig
@@ -1,6 +1,3 @@
-#
-# Config.in for IBM Active 2000 ISDN driver
-#
config ISDN_DRV_ACT2000
tristate "IBM Active 2000 support"
depends on ISA
@@ -10,4 +7,3 @@ config ISDN_DRV_ACT2000
into the card using a utility which is part of the latest
isdn4k-utils package. Please read the file
<file:Documentation/isdn/README.act2000> for more information.
-
diff --git a/drivers/isdn/capi/Kconfig b/drivers/isdn/capi/Kconfig
index e1afd60..b2a0475 100644
--- a/drivers/isdn/capi/Kconfig
+++ b/drivers/isdn/capi/Kconfig
@@ -1,6 +1,3 @@
-#
-# Config.in for the CAPI subsystem
-#
config ISDN_DRV_AVMB1_VERBOSE_REASON
bool "Verbose reason code reporting"
default y
@@ -59,4 +56,3 @@ config ISDN_CAPI_CAPIDRV
the legacy isdn4linux link layer. If you have a card which is
supported by a CAPI driver, but still want to use old features like
ippp interfaces or ttyI emulation, say Y/M here.
-
diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c
index 3e6d17f..66b7d7a 100644
--- a/drivers/isdn/capi/capidrv.c
+++ b/drivers/isdn/capi/capidrv.c
@@ -830,7 +830,7 @@ static void handle_controller(_cmsg * cmsg)
case 0: break;
case 1: s = "unknown class"; break;
case 2: s = "unknown function"; break;
- default: s = "unkown error"; break;
+ default: s = "unknown error"; break;
}
if (s)
printk(KERN_INFO "capidrv-%d: %s from controller 0x%x function %d: %s\n",
diff --git a/drivers/isdn/hardware/eicon/di.c b/drivers/isdn/hardware/eicon/di.c
index b029d13..cb14ae3 100644
--- a/drivers/isdn/hardware/eicon/di.c
+++ b/drivers/isdn/hardware/eicon/di.c
@@ -806,7 +806,7 @@ static void xdi_xlog_request (byte Adapter, byte Id,
DELIVERY - indication entered isdn_rc function
RNR=... - application had returned RNR=... after the
look ahead callback
- RNum=0 - aplication had not returned any buffer to copy
+ RNum=0 - application had not returned any buffer to copy
this indication and will copy it self
COMPLETE - XDI had copied the data to the buffers provided
bu the application and is about to issue the
diff --git a/drivers/isdn/hardware/eicon/maintidi.c b/drivers/isdn/hardware/eicon/maintidi.c
index 41c26e7..534978b 100644
--- a/drivers/isdn/hardware/eicon/maintidi.c
+++ b/drivers/isdn/hardware/eicon/maintidi.c
@@ -385,7 +385,7 @@ static int SuperTraceMessageInput (void* hLib) {
}
break;
default:
- diva_mnt_internal_dprintf (0, DLI_ERR, "Unknon IDI Ind (DMA mode): %02x", Ind);
+ diva_mnt_internal_dprintf (0, DLI_ERR, "Unknown IDI Ind (DMA mode): %02x", Ind);
}
p += (this_ind_length+1);
total_length -= (4 + this_ind_length);
@@ -420,7 +420,7 @@ static int SuperTraceMessageInput (void* hLib) {
}
break;
default:
- diva_mnt_internal_dprintf (0, DLI_ERR, "Unknon IDI Ind: %02x", Ind);
+ diva_mnt_internal_dprintf (0, DLI_ERR, "Unknown IDI Ind: %02x", Ind);
}
}
}
diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c
index fc46a26..a64bb6c 100644
--- a/drivers/isdn/hardware/mISDN/hfcsusb.c
+++ b/drivers/isdn/hardware/mISDN/hfcsusb.c
@@ -721,7 +721,7 @@ hfcsusb_setup_bch(struct bchannel *bch, int protocol)
switch (protocol) {
case (-1): /* used for init */
bch->state = -1;
- /* fall trough */
+ /* fall through */
case (ISDN_P_NONE):
if (bch->state == ISDN_P_NONE)
return 0; /* already in idle state */
diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.h b/drivers/isdn/hardware/mISDN/hfcsusb.h
index 43efe73..369196a 100644
--- a/drivers/isdn/hardware/mISDN/hfcsusb.h
+++ b/drivers/isdn/hardware/mISDN/hfcsusb.h
@@ -150,7 +150,7 @@ symbolic(struct hfcusb_symbolic_list list[], const int num)
for (i = 0; list[i].name != NULL; i++)
if (list[i].num == num)
return list[i].name;
- return "<unkown USB Error>";
+ return "<unknown USB Error>";
}
/* USB descriptor need to contain one of the following EndPoint combination: */
diff --git a/drivers/isdn/hardware/mISDN/mISDNisar.c b/drivers/isdn/hardware/mISDN/mISDNisar.c
index de352a1..09095c7 100644
--- a/drivers/isdn/hardware/mISDN/mISDNisar.c
+++ b/drivers/isdn/hardware/mISDN/mISDNisar.c
@@ -860,7 +860,7 @@ isar_pump_statev_modem(struct isar_ch *ch, u8 devt) {
pr_debug("%s: pump stev GSTN CLEAR\n", ch->is->name);
break;
default:
- pr_info("u%s: nknown pump stev %x\n", ch->is->name, devt);
+ pr_info("u%s: unknown pump stev %x\n", ch->is->name, devt);
break;
}
}
diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c
index a420b64..aaaeaaf 100644
--- a/drivers/isdn/hisax/hfc_usb.c
+++ b/drivers/isdn/hisax/hfc_usb.c
@@ -1086,7 +1086,7 @@ hfc_usb_l2l1(struct hisax_if *my_hisax_if, int pr, void *arg)
break;
default:
DBG(HFCUSB_DBG_STATES,
- "HFC_USB: hfc_usb_d_l2l1: unkown state : %#x", pr);
+ "HFC_USB: hfc_usb_d_l2l1: unknown state : %#x", pr);
break;
}
}
diff --git a/drivers/isdn/hysdn/Kconfig b/drivers/isdn/hysdn/Kconfig
index c9e4231..e86bc65 100644
--- a/drivers/isdn/hysdn/Kconfig
+++ b/drivers/isdn/hysdn/Kconfig
@@ -1,6 +1,3 @@
-#
-# Config.in for HYSDN ISDN driver
-#
config HYSDN
tristate "Hypercope HYSDN cards (Champ, Ergo, Metro) support (module only)"
depends on m && PROC_FS && PCI
@@ -15,4 +12,3 @@ config HYSDN_CAPI
depends on HYSDN && ISDN_CAPI
help
Say Y here if you like to use Hypercope's CAPI 2.0 interface.
-
diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c
index 90b56ed..507e13d 100644
--- a/drivers/isdn/i4l/isdn_net.c
+++ b/drivers/isdn/i4l/isdn_net.c
@@ -1563,7 +1563,7 @@ isdn_net_ciscohdlck_slarp_send_keepalive(unsigned long data)
*(__be32 *)(p + 4) = cpu_to_be32(CISCO_SLARP_KEEPALIVE);
*(__be32 *)(p + 8) = cpu_to_be32(lp->cisco_myseq);
*(__be32 *)(p + 12) = cpu_to_be32(lp->cisco_yourseq);
- *(__be16 *)(p + 16) = cpu_to_be16(0xffff); // reliablity, always 0xffff
+ *(__be16 *)(p + 16) = cpu_to_be16(0xffff); // reliability, always 0xffff
p += 18;
isdn_net_write_super(lp, skb);
diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c
index 642d5aa..45df667 100644
--- a/drivers/isdn/i4l/isdn_ppp.c
+++ b/drivers/isdn/i4l/isdn_ppp.c
@@ -836,7 +836,7 @@ isdn_ppp_write(int min, struct file *file, const char __user *buf, int count)
unsigned short hl;
struct sk_buff *skb;
/*
- * we need to reserve enought space in front of
+ * we need to reserve enough space in front of
* sk_buff. old call to dev_alloc_skb only reserved
* 16 bytes, now we are looking what the driver want
*/
@@ -1326,7 +1326,7 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
struct sk_buff *new_skb;
unsigned short hl;
/*
- * we need to reserve enought space in front of
+ * we need to reserve enough space in front of
* sk_buff. old call to dev_alloc_skb only reserved
* 16 bytes, now we are looking what the driver want.
*/
@@ -1674,7 +1674,7 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,
* - insert new fragment into the proper sequence slot (once that's done
* newfrag will be set to NULL)
* - reassemble any complete fragment sequence (non-null 'start'
- * indicates there is a continguous sequence present)
+ * indicates there is a contiguous sequence present)
* - discard any incomplete sequences that are below minseq -- due
* to the fact that sender always increment sequence number, if there
* is an incomplete sequence below minseq, no new fragments would
diff --git a/drivers/isdn/i4l/isdn_ttyfax.c b/drivers/isdn/i4l/isdn_ttyfax.c
index 78f7660..4c41f19 100644
--- a/drivers/isdn/i4l/isdn_ttyfax.c
+++ b/drivers/isdn/i4l/isdn_ttyfax.c
@@ -470,7 +470,7 @@ isdn_tty_cmd_FCLASS2(char **p, modem_info * info)
}
return 0;
}
- /* BADMUL=value - dummy 0=disable errorchk disabled (treshold multiplier) */
+ /* BADMUL=value - dummy 0=disable errorchk disabled (threshold multiplier) */
if (!strncmp(p[0], "BADMUL", 6)) {
p[0] += 6;
switch (*p[0]) {
diff --git a/drivers/isdn/icn/Kconfig b/drivers/isdn/icn/Kconfig
index 89d15ee..4534f21 100644
--- a/drivers/isdn/icn/Kconfig
+++ b/drivers/isdn/icn/Kconfig
@@ -1,6 +1,3 @@
-#
-# Config.in for ICN ISDN driver
-#
config ISDN_DRV_ICN
tristate "ICN 2B and 4B support"
depends on ISA
@@ -13,4 +10,3 @@ config ISDN_DRV_ICN
separately. See <file:Documentation/isdn/README> and
<file:Documentation/isdn/README.icn> for more
information.
-
diff --git a/drivers/isdn/mISDN/dsp_core.c b/drivers/isdn/mISDN/dsp_core.c
index 77ee286..43ff4d3 100644
--- a/drivers/isdn/mISDN/dsp_core.c
+++ b/drivers/isdn/mISDN/dsp_core.c
@@ -110,7 +110,7 @@
* crossconnections and conferences via software if not possible through
* hardware. If hardware capability is available, hardware is used.
*
- * Echo: Is generated by CMX and is used to check performane of hard and
+ * Echo: Is generated by CMX and is used to check performance of hard and
* software CMX.
*
* The CMX has special functions for conferences with one, two and more
diff --git a/drivers/isdn/mISDN/tei.c b/drivers/isdn/mISDN/tei.c
index e04bad6..6d4da60 100644
--- a/drivers/isdn/mISDN/tei.c
+++ b/drivers/isdn/mISDN/tei.c
@@ -725,7 +725,7 @@ tei_id_ver_tout_net(struct FsmInst *fi, int event, void *arg)
if (tm->rcnt == 1) {
if (*debug & DEBUG_L2_TEI)
tm->tei_m.printdebug(fi,
- "check req for tei %d sucessful\n", tm->l2->tei);
+ "check req for tei %d successful\n", tm->l2->tei);
mISDN_FsmChangeState(fi, ST_TEI_NOP);
} else if (tm->rcnt > 1) {
/* duplicate assignment; remove */
diff --git a/drivers/isdn/pcbit/Kconfig b/drivers/isdn/pcbit/Kconfig
index ffba6ec..e9b2dd8 100644
--- a/drivers/isdn/pcbit/Kconfig
+++ b/drivers/isdn/pcbit/Kconfig
@@ -1,6 +1,3 @@
-#
-# Config.in for PCBIT ISDN driver
-#
config ISDN_DRV_PCBIT
tristate "PCBIT-D support"
depends on ISA && (BROKEN || X86)
@@ -11,4 +8,3 @@ config ISDN_DRV_PCBIT
the card using a utility which is distributed separately. See
<file:Documentation/isdn/README> and
<file:Documentation/isdn/README.pcbit> for more information.
-
diff --git a/drivers/isdn/sc/Kconfig b/drivers/isdn/sc/Kconfig
index e6510ca..7469863 100644
--- a/drivers/isdn/sc/Kconfig
+++ b/drivers/isdn/sc/Kconfig
@@ -1,6 +1,3 @@
-#
-# Config.in for Spellcaster ISDN driver
-#
config ISDN_DRV_SC
tristate "Spellcaster support"
depends on ISA
@@ -9,4 +6,3 @@ config ISDN_DRV_SC
driver currently builds only in a modularized version.
To build it, choose M here: the module will be called sc.
See <file:Documentation/isdn/README.sc> for more information.
-
diff --git a/drivers/macintosh/ans-lcd.c b/drivers/macintosh/ans-lcd.c
index 6a82218..a3d25da 100644
--- a/drivers/macintosh/ans-lcd.c
+++ b/drivers/macintosh/ans-lcd.c
@@ -3,7 +3,6 @@
*/
#include <linux/types.h>
-#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/miscdevice.h>
@@ -26,6 +25,7 @@
static unsigned long anslcd_short_delay = 80;
static unsigned long anslcd_long_delay = 3280;
static volatile unsigned char __iomem *anslcd_ptr;
+static DEFINE_MUTEX(anslcd_mutex);
#undef DEBUG
@@ -65,26 +65,31 @@ anslcd_write( struct file * file, const char __user * buf,
if (!access_ok(VERIFY_READ, buf, count))
return -EFAULT;
+
+ mutex_lock(&anslcd_mutex);
for ( i = *ppos; count > 0; ++i, ++p, --count )
{
char c;
__get_user(c, p);
anslcd_write_byte_data( c );
}
+ mutex_unlock(&anslcd_mutex);
*ppos = i;
return p - buf;
}
-static int
-anslcd_ioctl( struct inode * inode, struct file * file,
- unsigned int cmd, unsigned long arg )
+static long
+anslcd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
char ch, __user *temp;
+ long ret = 0;
#ifdef DEBUG
printk(KERN_DEBUG "LCD: ioctl(%d,%d)\n",cmd,arg);
#endif
+ mutex_lock(&anslcd_mutex);
+
switch ( cmd )
{
case ANSLCD_CLEAR:
@@ -93,7 +98,7 @@ anslcd_ioctl( struct inode * inode, struct file * file,
anslcd_write_byte_ctrl ( 0x06 );
anslcd_write_byte_ctrl ( 0x01 );
anslcd_write_byte_ctrl ( 0x02 );
- return 0;
+ break;
case ANSLCD_SENDCTRL:
temp = (char __user *) arg;
__get_user(ch, temp);
@@ -101,33 +106,37 @@ anslcd_ioctl( struct inode * inode, struct file * file,
anslcd_write_byte_ctrl ( ch );
__get_user(ch, temp);
}
- return 0;
+ break;
case ANSLCD_SETSHORTDELAY:
if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
- anslcd_short_delay=arg;
- return 0;
+ ret =-EACCES;
+ else
+ anslcd_short_delay=arg;
+ break;
case ANSLCD_SETLONGDELAY:
if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
- anslcd_long_delay=arg;
- return 0;
+ ret = -EACCES;
+ else
+ anslcd_long_delay=arg;
+ break;
default:
- return -EINVAL;
+ ret = -EINVAL;
}
+
+ mutex_unlock(&anslcd_mutex);
+ return ret;
}
static int
anslcd_open( struct inode * inode, struct file * file )
{
- cycle_kernel_lock();
return 0;
}
const struct file_operations anslcd_fops = {
- .write = anslcd_write,
- .ioctl = anslcd_ioctl,
- .open = anslcd_open,
+ .write = anslcd_write,
+ .unlocked_ioctl = anslcd_ioctl,
+ .open = anslcd_open,
};
static struct miscdevice anslcd_dev = {
@@ -168,6 +177,7 @@ anslcd_init(void)
printk(KERN_DEBUG "LCD: init\n");
#endif
+ mutex_lock(&anslcd_mutex);
anslcd_write_byte_ctrl ( 0x38 );
anslcd_write_byte_ctrl ( 0x0c );
anslcd_write_byte_ctrl ( 0x06 );
@@ -176,6 +186,7 @@ anslcd_init(void)
for(a=0;a<80;a++) {
anslcd_write_byte_data(anslcd_logo[a]);
}
+ mutex_unlock(&anslcd_mutex);
return 0;
}
diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c
index 8b93644..3fbe41b 100644
--- a/drivers/macintosh/therm_windtunnel.c
+++ b/drivers/macintosh/therm_windtunnel.c
@@ -15,7 +15,7 @@
*
* WARNING: This driver has only been testen on Apple's
* 1.25 MHz Dual G4 (March 03). It is tuned for a CPU
- * temperatur around 57 C.
+ * temperature around 57 C.
*
* Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se)
*
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index ed10381..e412980 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -988,7 +988,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
goto bad_cipher;
}
- /* Compatiblity mode for old dm-crypt cipher strings */
+ /* Compatibility mode for old dm-crypt cipher strings */
if (!chainmode || (strcmp(chainmode, "plain") == 0 && !ivmode)) {
chainmode = "cbc";
ivmode = "plain";
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index 32d0b87..dce971d 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -1116,8 +1116,9 @@ static int pg_init_limit_reached(struct multipath *m, struct pgpath *pgpath)
return limit_reached;
}
-static void pg_init_done(struct dm_path *path, int errors)
+static void pg_init_done(void *data, int errors)
{
+ struct dm_path *path = data;
struct pgpath *pgpath = path_to_pgpath(path);
struct priority_group *pg = pgpath->pg;
struct multipath *m = pg->m;
@@ -1183,12 +1184,11 @@ static void pg_init_done(struct dm_path *path, int errors)
static void activate_path(struct work_struct *work)
{
- int ret;
struct pgpath *pgpath =
container_of(work, struct pgpath, activate_path);
- ret = scsi_dh_activate(bdev_get_queue(pgpath->path.dev->bdev));
- pg_init_done(&pgpath->path, ret);
+ scsi_dh_activate(bdev_get_queue(pgpath->path.dev->bdev),
+ pg_init_done, &pgpath->path);
}
/*
diff --git a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146_i2c.c
index 7e8f568..48cb154 100644
--- a/drivers/media/common/saa7146_i2c.c
+++ b/drivers/media/common/saa7146_i2c.c
@@ -98,7 +98,7 @@ static int saa7146_i2c_msg_cleanup(const struct i2c_msg *m, int num, __le32 *op)
op_count++;
- /* loop throgh all bytes of message i */
+ /* loop through all bytes of message i */
for(j = 0; j < m[i].len; j++) {
/* write back all bytes that could have been read */
m[i].buf[j] = (le32_to_cpu(op[op_count/3]) >> ((3-(op_count%3))*8));
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
index 810f07d..52e4ce4 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -160,7 +160,7 @@ struct tuner_state {
* search callback possible return status
*
* DVBFE_ALGO_SEARCH_SUCCESS
- * The frontend search algorithm completed and returned succesfully
+ * The frontend search algorithm completed and returned successfully
*
* DVBFE_ALGO_SEARCH_ASLEEP
* The frontend search algorithm is sleeping
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
index 0241a7c..8b8558f 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -1396,7 +1396,7 @@ static int dvb_net_do_ioctl(struct inode *inode, struct file *file,
return ret;
}
- /* binary compatiblity cruft */
+ /* binary compatibility cruft */
case __NET_ADD_IF_OLD:
{
struct __dvb_net_if_old *dvbnetif = parg;
diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c
index 2ae7f64..bb69f37 100644
--- a/drivers/media/dvb/dvb-usb/anysee.c
+++ b/drivers/media/dvb/dvb-usb/anysee.c
@@ -344,7 +344,7 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
if (ret)
return ret;
- err("Unkown Anysee version: %02x %02x %02x. "\
+ err("Unknown Anysee version: %02x %02x %02x. "\
"Please report the <linux-dvb@linuxtv.org>.",
hw_info[0], hw_info[1], hw_info[2]);
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c
index eeef50b..5c0126d 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-mb.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c
@@ -242,7 +242,7 @@ static struct dvb_usb_device_properties dibusb1_1_properties = {
{ &dibusb_dib3000mb_table[9], &dibusb_dib3000mb_table[11], NULL },
{ &dibusb_dib3000mb_table[10], &dibusb_dib3000mb_table[12], NULL },
},
- { "Unkown USB1.1 DVB-T device ???? please report the name to the author",
+ { "Unknown USB1.1 DVB-T device ???? please report the name to the author",
{ &dibusb_dib3000mb_table[13], NULL },
{ &dibusb_dib3000mb_table[14], NULL },
},
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
index edde87c..6b5ded9 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
@@ -259,7 +259,7 @@ int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *d,
*state = REMOTE_KEY_REPEAT;
break;
default:
- deb_err("unkown type of remote status: %d\n",keybuf[0]);
+ deb_err("unknown type of remote status: %d\n",keybuf[0]);
break;
}
return 0;
diff --git a/drivers/media/dvb/dvb-usb/usb-urb.c b/drivers/media/dvb/dvb-usb/usb-urb.c
index 9da2cc9..f9702e3 100644
--- a/drivers/media/dvb/dvb-usb/usb-urb.c
+++ b/drivers/media/dvb/dvb-usb/usb-urb.c
@@ -56,7 +56,7 @@ static void usb_urb_complete(struct urb *urb)
stream->complete(stream, b, urb->actual_length);
break;
default:
- err("unkown endpoint type in completition handler.");
+ err("unknown endpoint type in completition handler.");
return;
}
usb_submit_urb(urb,GFP_ATOMIC);
@@ -228,7 +228,7 @@ int usb_urb_init(struct usb_data_stream *stream, struct usb_data_stream_properti
case USB_ISOC:
return usb_isoc_urb_init(stream);
default:
- err("unkown URB-type for data transfer.");
+ err("unknown URB-type for data transfer.");
return -EINVAL;
}
}
diff --git a/drivers/media/dvb/frontends/au8522_decoder.c b/drivers/media/dvb/frontends/au8522_decoder.c
index 74981ee..7c6431f 100644
--- a/drivers/media/dvb/frontends/au8522_decoder.c
+++ b/drivers/media/dvb/frontends/au8522_decoder.c
@@ -315,7 +315,7 @@ static void setup_decoder_defaults(struct au8522_state *state, u8 input_mode)
if (input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13 ||
input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH24) {
/* Despite what the table says, for the HVR-950q we still need
- to be in CVBS mode for the S-Video input (reason uknown). */
+ to be in CVBS mode for the S-Video input (reason unknown). */
/* filter_coef_type = 3; */
filter_coef_type = 5;
} else {
diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c
index ffbcfab..00a4e8f 100644
--- a/drivers/media/dvb/frontends/cx24110.c
+++ b/drivers/media/dvb/frontends/cx24110.c
@@ -1,4 +1,4 @@
- /*
+/*
cx24110 - Single Chip Satellite Channel Receiver driver module
Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.de> based on
@@ -96,7 +96,7 @@ static struct {u8 reg; u8 data;} cx24110_regdata[]=
{0x42,0x00}, /* @ middle bytes " */
{0x43,0x00}, /* @ LSB " */
/* leave the carrier tracking loop parameters on default */
- /* leave the bit timing loop parameters at gefault */
+ /* leave the bit timing loop parameters at default */
{0x56,0x4d}, /* set the filtune voltage to 2.7V, as recommended by */
/* the cx24108 data sheet for symbol rates above 15MS/s */
{0x57,0x00}, /* @ Filter sigma delta enabled, positive */
diff --git a/drivers/media/dvb/frontends/cx24113.c b/drivers/media/dvb/frontends/cx24113.c
index 075b2b5..e9ee555 100644
--- a/drivers/media/dvb/frontends/cx24113.c
+++ b/drivers/media/dvb/frontends/cx24113.c
@@ -589,7 +589,7 @@ struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe,
info("detected CX24113 variant\n");
break;
case REV_CX24113:
- info("sucessfully detected\n");
+ info("successfully detected\n");
break;
default:
err("unsupported device id: %x\n", state->rev);
diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c
index 136b9d2..ad4c8cf 100644
--- a/drivers/media/dvb/frontends/dib3000mb.c
+++ b/drivers/media/dvb/frontends/dib3000mb.c
@@ -154,7 +154,7 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe,
case BANDWIDTH_AUTO:
return -EOPNOTSUPP;
default:
- err("unkown bandwidth value.");
+ err("unknown bandwidth value.");
return -EINVAL;
}
}
diff --git a/drivers/media/dvb/frontends/drx397xD.c b/drivers/media/dvb/frontends/drx397xD.c
index 0100755..868b78b 100644
--- a/drivers/media/dvb/frontends/drx397xD.c
+++ b/drivers/media/dvb/frontends/drx397xD.c
@@ -81,7 +81,7 @@ static struct {
#include "drx397xD_fw.h"
};
-/* use only with writer lock aquired */
+/* use only with writer lock acquired */
static void _drx_release_fw(struct drx397xD_state *s, enum fw_ix ix)
{
memset(&fw[ix].data[0], 0, sizeof(fw[0].data));
diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c
index 056387b..43971e6 100644
--- a/drivers/media/dvb/frontends/lgdt330x.c
+++ b/drivers/media/dvb/frontends/lgdt330x.c
@@ -479,7 +479,7 @@ static int lgdt3302_read_status(struct dvb_frontend* fe, fe_status_t* status)
switch (state->current_modulation) {
case QAM_256:
case QAM_64:
- /* Need to undestand why there are 3 lock levels here */
+ /* Need to understand why there are 3 lock levels here */
if ((buf[0] & 0x07) == 0x07)
*status |= FE_HAS_CARRIER;
break;
@@ -520,7 +520,7 @@ static int lgdt3303_read_status(struct dvb_frontend* fe, fe_status_t* status)
switch (state->current_modulation) {
case QAM_256:
case QAM_64:
- /* Need to undestand why there are 3 lock levels here */
+ /* Need to understand why there are 3 lock levels here */
if ((buf[0] & 0x07) == 0x07)
*status |= FE_HAS_CARRIER;
else
diff --git a/drivers/media/dvb/frontends/stb0899_drv.c b/drivers/media/dvb/frontends/stb0899_drv.c
index a04c782..1570669 100644
--- a/drivers/media/dvb/frontends/stb0899_drv.c
+++ b/drivers/media/dvb/frontends/stb0899_drv.c
@@ -1571,7 +1571,7 @@ static enum dvbfe_search stb0899_search(struct dvb_frontend *fe, struct dvb_fron
* stb0899_track
* periodically check the signal level against a specified
* threshold level and perform derotator centering.
- * called once we have a lock from a succesful search
+ * called once we have a lock from a successful search
* event.
*
* Will be called periodically called to maintain the
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index 8d65c65..baf3159 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -2425,7 +2425,7 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
* use 0x15 to track VPE interrupts - increase by 1 every vpeirq() is called
*/
saa7146_write(dev, EC1SSR, (0x03<<2) | 3 );
- /* set event counter 1 treshold to maximum allowed value (rEC p55) */
+ /* set event counter 1 threshold to maximum allowed value (rEC p55) */
saa7146_write(dev, ECT1R, 0x3fff );
#endif
/* Set RPS1 Address register to point to RPS code (r108 p42) */
@@ -2559,7 +2559,7 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
* use 0x15 to track VPE interrupts - increase by 1 every vpeirq() is called
*/
saa7146_write(dev, EC1SSR, (0x03<<2) | 3 );
- /* set event counter 1 treshold to maximum allowed value (rEC p55) */
+ /* set event counter 1 threshold to maximum allowed value (rEC p55) */
saa7146_write(dev, ECT1R, 0x3fff );
#endif
/* Setup BUDGETPATCH MAIN RPS1 "program" (p35) */
diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c
index 60136688..9c92f9d 100644
--- a/drivers/media/dvb/ttpci/budget-patch.c
+++ b/drivers/media/dvb/ttpci/budget-patch.c
@@ -456,7 +456,7 @@ static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_exte
// use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled
// use 0x15 to track VPE interrupts - increase by 1 every vpeirq() is called
saa7146_write(dev, EC1SSR, (0x03<<2) | 3 );
- // set event counter 1 treshold to maximum allowed value (rEC p55)
+ // set event counter 1 threshold to maximum allowed value (rEC p55)
saa7146_write(dev, ECT1R, 0x3fff );
#endif
// Fix VSYNC level
diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c
index a123908..5f79acb 100644
--- a/drivers/media/radio/radio-mr800.c
+++ b/drivers/media/radio/radio-mr800.c
@@ -28,7 +28,7 @@
* http://av-usbradio.sourceforge.net/index.php
* http://sourceforge.net/projects/av-usbradio/
* Latest release of theirs project was in 2005.
- * Probably, this driver could be improved trough using their
+ * Probably, this driver could be improved through using their
* achievements (specifications given).
* Also, Faidon Liambotis <paravoid@debian.org> wrote nice driver for this radio
* in 2007. He allowed to use his driver to improve current mr800 radio driver.
diff --git a/drivers/media/video/cx18/cx18-av-core.h b/drivers/media/video/cx18/cx18-av-core.h
index 9b84a0c..cafb7e9 100644
--- a/drivers/media/video/cx18/cx18-av-core.h
+++ b/drivers/media/video/cx18/cx18-av-core.h
@@ -294,7 +294,7 @@ struct cx18_av_state {
#define CXADEC_QAM_CONST_DEC 0x924
#define CXADEC_QAM_ROTATOR_FREQ 0x948
-/* Bit defintions / settings used in Mako Audio */
+/* Bit definitions / settings used in Mako Audio */
#define CXADEC_PREF_MODE_MONO_LANGA 0
#define CXADEC_PREF_MODE_MONO_LANGB 1
#define CXADEC_PREF_MODE_MONO_LANGC 2
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
index 6dd51e2..e12082b 100644
--- a/drivers/media/video/cx18/cx18-driver.c
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -1200,7 +1200,7 @@ static struct pci_driver cx18_pci_driver = {
.remove = cx18_remove,
};
-static int module_start(void)
+static int __init module_start(void)
{
printk(KERN_INFO "cx18: Start initialization, version %s\n", CX18_VERSION);
@@ -1224,7 +1224,7 @@ static int module_start(void)
return 0;
}
-static void module_cleanup(void)
+static void __exit module_cleanup(void)
{
pci_unregister_driver(&cx18_pci_driver);
}
diff --git a/drivers/media/video/cx18/cx18-mailbox.h b/drivers/media/video/cx18/cx18-mailbox.h
index e23aaac..522ad53 100644
--- a/drivers/media/video/cx18/cx18-mailbox.h
+++ b/drivers/media/video/cx18/cx18-mailbox.h
@@ -41,7 +41,7 @@ struct cx18;
/*
* This structure is used by CPU to provide completed buffers information
* Its structure is dictrated by the layout of the SCB, required by the
- * firmware, but its defintion needs to be here, instead of in cx18-scb.h,
+ * firmware, but its definition needs to be here, instead of in cx18-scb.h,
* for mailbox work order scheduling
*/
struct cx18_mdl_ack {
diff --git a/drivers/media/video/cx231xx/cx231xx-avcore.c b/drivers/media/video/cx231xx/cx231xx-avcore.c
index 28f48f4..c217441 100644
--- a/drivers/media/video/cx231xx/cx231xx-avcore.c
+++ b/drivers/media/video/cx231xx/cx231xx-avcore.c
@@ -2414,9 +2414,11 @@ int cx231xx_gpio_i2c_read_ack(struct cx231xx *dev)
cx231xx_info("No ACK after %d msec -GPIO I2C failed!",
nInit * 10);
- /* readAck
- throuth clock stretch ,slave has given a SCL signal,
- so the SDA data can be directly read. */
+ /*
+ * readAck
+ * through clock stretch, slave has given a SCL signal,
+ * so the SDA data can be directly read.
+ */
status = cx231xx_get_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
if ((dev->gpio_val & 1 << dev->board.tuner_sda_gpio) == 0) {
diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c
index c31284b..fa2d350 100644
--- a/drivers/media/video/cx23885/cx23885-core.c
+++ b/drivers/media/video/cx23885/cx23885-core.c
@@ -1957,7 +1957,7 @@ static struct pci_driver cx23885_pci_driver = {
.resume = NULL,
};
-static int cx23885_init(void)
+static int __init cx23885_init(void)
{
printk(KERN_INFO "cx23885 driver version %d.%d.%d loaded\n",
(CX23885_VERSION_CODE >> 16) & 0xff,
@@ -1970,7 +1970,7 @@ static int cx23885_init(void)
return pci_register_driver(&cx23885_pci_driver);
}
-static void cx23885_fini(void)
+static void __exit cx23885_fini(void)
{
pci_unregister_driver(&cx23885_pci_driver);
}
diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c
index 45e13ee..16c6a92 100644
--- a/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/drivers/media/video/cx23885/cx23885-dvb.c
@@ -940,7 +940,7 @@ int cx23885_dvb_register(struct cx23885_tsport *port)
int err, i;
/* Here we need to allocate the correct number of frontends,
- * as reflected in the cards struct. The reality is that currrently
+ * as reflected in the cards struct. The reality is that currently
* no cx23885 boards support this - yet. But, if we don't modify this
* code then the second frontend would never be allocated (later)
* and fail with error before the attach in dvb_register().
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
index cf63460..b354111 100644
--- a/drivers/media/video/cx88/cx88-core.c
+++ b/drivers/media/video/cx88/cx88-core.c
@@ -624,7 +624,7 @@ int cx88_reset(struct cx88_core *core)
/* setup image format */
cx_andor(MO_COLOR_CTRL, 0x4000, 0x4000);
- /* setup FIFO Threshholds */
+ /* setup FIFO Thresholds */
cx_write(MO_PDMA_STHRSH, 0x0807);
cx_write(MO_PDMA_DTHRSH, 0x0807);
diff --git a/drivers/media/video/davinci/dm355_ccdc.c b/drivers/media/video/davinci/dm355_ccdc.c
index 4629cab..3143900 100644
--- a/drivers/media/video/davinci/dm355_ccdc.c
+++ b/drivers/media/video/davinci/dm355_ccdc.c
@@ -285,7 +285,7 @@ static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam)
if ((ccdcparam->med_filt_thres < 0) ||
(ccdcparam->med_filt_thres > CCDC_MED_FILT_THRESH)) {
- dev_dbg(dev, "Invalid value of median filter thresold\n");
+ dev_dbg(dev, "Invalid value of median filter threshold\n");
return -EINVAL;
}
@@ -959,7 +959,7 @@ static struct ccdc_hw_device ccdc_hw_dev = {
},
};
-static int dm355_ccdc_init(void)
+static int __init dm355_ccdc_init(void)
{
printk(KERN_NOTICE "dm355_ccdc_init\n");
if (vpfe_register_ccdc_device(&ccdc_hw_dev) < 0)
@@ -969,7 +969,7 @@ static int dm355_ccdc_init(void)
return 0;
}
-static void dm355_ccdc_exit(void)
+static void __exit dm355_ccdc_exit(void)
{
vpfe_unregister_ccdc_device(&ccdc_hw_dev);
}
diff --git a/drivers/media/video/davinci/dm644x_ccdc.c b/drivers/media/video/davinci/dm644x_ccdc.c
index 2f19a91..d5fa193 100644
--- a/drivers/media/video/davinci/dm644x_ccdc.c
+++ b/drivers/media/video/davinci/dm644x_ccdc.c
@@ -859,7 +859,7 @@ static struct ccdc_hw_device ccdc_hw_dev = {
},
};
-static int dm644x_ccdc_init(void)
+static int __init dm644x_ccdc_init(void)
{
printk(KERN_NOTICE "dm644x_ccdc_init\n");
if (vpfe_register_ccdc_device(&ccdc_hw_dev) < 0)
@@ -869,7 +869,7 @@ static int dm644x_ccdc_init(void)
return 0;
}
-static void dm644x_ccdc_exit(void)
+static void __exit dm644x_ccdc_exit(void)
{
vpfe_unregister_ccdc_device(&ccdc_hw_dev);
}
diff --git a/drivers/media/video/davinci/vpss.c b/drivers/media/video/davinci/vpss.c
index 6d709ca..453236b 100644
--- a/drivers/media/video/davinci/vpss.c
+++ b/drivers/media/video/davinci/vpss.c
@@ -53,7 +53,7 @@ struct vpss_hw_ops {
int (*enable_clock)(enum vpss_clock_sel clock_sel, int en);
/* select input to ccdc */
void (*select_ccdc_source)(enum vpss_ccdc_source_sel src_sel);
- /* clear wbl overlflow bit */
+ /* clear wbl overflow bit */
int (*clear_wbl_overflow)(enum vpss_wbl_sel wbl_sel);
};
diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c
index cf3af8d..e39efb4 100644
--- a/drivers/media/video/gspca/sonixb.c
+++ b/drivers/media/video/gspca/sonixb.c
@@ -304,7 +304,7 @@ static const __u8 initOv6650[] = {
};
static const __u8 ov6650_sensor_init[][8] =
{
- /* Bright, contrast, etc are set througth SCBB interface.
+ /* Bright, contrast, etc are set through SCBB interface.
* AVCAP on win2 do not send any data on this controls. */
/* Anyway, some registers appears to alter bright and constrat */
diff --git a/drivers/media/video/gspca/spca500.c b/drivers/media/video/gspca/spca500.c
index fab7ef8..7dbd5ee 100644
--- a/drivers/media/video/gspca/spca500.c
+++ b/drivers/media/video/gspca/spca500.c
@@ -589,7 +589,7 @@ static void spca500_reinit(struct gspca_dev *gspca_dev)
int err;
__u8 Data;
- /* some unknow command from Aiptek pocket dv and family300 */
+ /* some unknown command from Aiptek pocket dv and family300 */
reg_w(gspca_dev, 0x00, 0x0d01, 0x01);
reg_w(gspca_dev, 0x00, 0x0d03, 0x00);
diff --git a/drivers/media/video/gspca/spca501.c b/drivers/media/video/gspca/spca501.c
index b74a342..66f9f00 100644
--- a/drivers/media/video/gspca/spca501.c
+++ b/drivers/media/video/gspca/spca501.c
@@ -1636,7 +1636,7 @@ static const __u16 spca501c_arowana_init_data[][3] = {
{}
};
-/* Unknow camera from Ori Usbid 0x0000:0x0000 */
+/* Unknown camera from Ori Usbid 0x0000:0x0000 */
/* Based on snoops from Ori Cohen */
static const __u16 spca501c_mysterious_open_data[][3] = {
{0x02, 0x000f, 0x0005},
@@ -1945,7 +1945,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
goto error;
break;
case MystFromOriUnknownCamera:
- /* UnKnow Ori CMOS Camera data */
+ /* Unknown Ori CMOS Camera data */
if (write_vector(gspca_dev, spca501c_mysterious_open_data))
goto error;
break;
@@ -1978,7 +1978,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
write_vector(gspca_dev, spca501c_arowana_open_data);
break;
case MystFromOriUnknownCamera:
- /* UnKnow CMOS Camera data */
+ /* Unknown CMOS Camera data */
write_vector(gspca_dev, spca501c_mysterious_init_data);
break;
default:
diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c
index aa8f995..1a9af2e 100644
--- a/drivers/media/video/gspca/sunplus.c
+++ b/drivers/media/video/gspca/sunplus.c
@@ -631,7 +631,7 @@ static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
count = 200;
while (--count > 0) {
msleep(10);
- /* gsmart mini2 write a each wait setting 1 ms is enought */
+ /* gsmart mini2 write a each wait setting 1 ms is enough */
/* reg_w_riv(dev, req, idx, val); */
status = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
if (status == endcode) {
diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c
index cdf3357..49c3c12 100644
--- a/drivers/media/video/gspca/zc3xx.c
+++ b/drivers/media/video/gspca/zc3xx.c
@@ -7065,7 +7065,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
break;
default:
PDEBUG(D_PROBE,
- "Sensor UNKNOW_0 force Tas5130");
+ "Sensor UNKNOWN_0 force Tas5130");
sd->sensor = SENSOR_TAS5130CXX;
}
break;
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index 463ec34..7cdbc1a 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -1361,7 +1361,7 @@ static struct pci_driver ivtv_pci_driver = {
.remove = ivtv_remove,
};
-static int module_start(void)
+static int __init module_start(void)
{
printk(KERN_INFO "ivtv: Start initialization, version %s\n", IVTV_VERSION);
@@ -1385,7 +1385,7 @@ static int module_start(void)
return 0;
}
-static void module_cleanup(void)
+static void __exit module_cleanup(void)
{
pci_unregister_driver(&ivtv_pci_driver);
}
diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c
index eccb40a..2052293 100644
--- a/drivers/media/video/ov772x.c
+++ b/drivers/media/video/ov772x.c
@@ -247,7 +247,7 @@
/* COM5 */
#define AFR_ON_OFF 0x80 /* Auto frame rate control ON/OFF selection */
-#define AFR_SPPED 0x40 /* Auto frame rate control speed slection */
+#define AFR_SPPED 0x40 /* Auto frame rate control speed selection */
/* Auto frame rate max rate control */
#define AFR_NO_RATE 0x00 /* No reduction of frame rate */
#define AFR_1p2 0x10 /* Max reduction to 1/2 frame rate */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
index 5b152ff..5fcad28 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
@@ -332,7 +332,7 @@ struct pvr2_hdw {
/* Bit mask of PVR2_CVAL_INPUT choices which are valid for the hardware */
unsigned int input_avail_mask;
- /* Bit mask of PVR2_CVAL_INPUT choices which are currenly allowed */
+ /* Bit mask of PVR2_CVAL_INPUT choices which are currently allowed */
unsigned int input_allowed_mask;
/* Location of eeprom or a negative number if none */
diff --git a/drivers/media/video/s2255drv.c b/drivers/media/video/s2255drv.c
index 2c0bb06..03d3926 100644
--- a/drivers/media/video/s2255drv.c
+++ b/drivers/media/video/s2255drv.c
@@ -1980,7 +1980,7 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
wake_up(&dev->fw_data->wait_fw);
break;
default:
- printk(KERN_INFO "s2255 unknwn resp\n");
+ printk(KERN_INFO "s2255 unknown resp\n");
}
default:
pdata++;
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index f87757f..c673901 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -1319,7 +1319,7 @@ static struct pci_driver saa7134_pci_driver = {
#endif
};
-static int saa7134_init(void)
+static int __init saa7134_init(void)
{
INIT_LIST_HEAD(&saa7134_devlist);
printk(KERN_INFO "saa7130/34: v4l2 driver version %d.%d.%d loaded\n",
@@ -1333,7 +1333,7 @@ static int saa7134_init(void)
return pci_register_driver(&saa7134_pci_driver);
}
-static void saa7134_fini(void)
+static void __exit saa7134_fini(void)
{
pci_unregister_driver(&saa7134_pci_driver);
}
diff --git a/drivers/media/video/saa7164/saa7164-core.c b/drivers/media/video/saa7164/saa7164-core.c
index 709affc..e6aa0fb 100644
--- a/drivers/media/video/saa7164/saa7164-core.c
+++ b/drivers/media/video/saa7164/saa7164-core.c
@@ -724,13 +724,13 @@ static struct pci_driver saa7164_pci_driver = {
.resume = NULL,
};
-static int saa7164_init(void)
+static int __init saa7164_init(void)
{
printk(KERN_INFO "saa7164 driver loaded\n");
return pci_register_driver(&saa7164_pci_driver);
}
-static void saa7164_fini(void)
+static void __exit saa7164_fini(void)
{
pci_unregister_driver(&saa7164_pci_driver);
}
diff --git a/drivers/media/video/zoran/zoran.h b/drivers/media/video/zoran/zoran.h
index d439c76..cb1de7e 100644
--- a/drivers/media/video/zoran/zoran.h
+++ b/drivers/media/video/zoran/zoran.h
@@ -106,7 +106,7 @@ struct zoran_params {
unsigned long jpeg_markers; /* Which markers should go into the JPEG output.
* Unless you exactly know what you do, leave them untouched.
* Inluding less markers will make the resulting code
- * smaller, but there will be fewer aplications
+ * smaller, but there will be fewer applications
* which can read it.
* The presence of the APP and COM marker is
* influenced by APP0_len and COM_len ONLY! */
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
index 8dd4d21..b494867 100644
--- a/drivers/message/fusion/mptbase.h
+++ b/drivers/message/fusion/mptbase.h
@@ -76,8 +76,8 @@
#define COPYRIGHT "Copyright (c) 1999-2008 " MODULEAUTHOR
#endif
-#define MPT_LINUX_VERSION_COMMON "3.04.12"
-#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.12"
+#define MPT_LINUX_VERSION_COMMON "3.04.13"
+#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.13"
#define WHAT_MAGIC_STRING "@" "(" "#" ")"
#define show_mptmod_ver(s,ver) \
diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c
index 9b2e219..352acd0 100644
--- a/drivers/message/fusion/mptctl.c
+++ b/drivers/message/fusion/mptctl.c
@@ -621,11 +621,8 @@ __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 MYNAM "%s::mptctl_ioctl() @%d - ioc%d not found!\n",
- __FILE__, __LINE__, iocnumX);
+ (iocp == NULL))
return -ENODEV;
- }
if (!iocp->active) {
printk(KERN_DEBUG MYNAM "%s::mptctl_ioctl() @%d - Controller disabled.\n",
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
index c295786..5775275 100644
--- a/drivers/message/fusion/mptscsih.c
+++ b/drivers/message/fusion/mptscsih.c
@@ -792,11 +792,36 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
* precedence!
*/
sc->result = (DID_OK << 16) | scsi_status;
- if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
- /* Have already saved the status and sense data
+ if (!(scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)) {
+
+ /*
+ * For an Errata on LSI53C1030
+ * When the length of request data
+ * and transfer data are different
+ * with result of command (READ or VERIFY),
+ * DID_SOFT_ERROR is set.
*/
- ;
- } else {
+ if (ioc->bus_type == SPI) {
+ if (pScsiReq->CDB[0] == READ_6 ||
+ pScsiReq->CDB[0] == READ_10 ||
+ pScsiReq->CDB[0] == READ_12 ||
+ pScsiReq->CDB[0] == READ_16 ||
+ pScsiReq->CDB[0] == VERIFY ||
+ pScsiReq->CDB[0] == VERIFY_16) {
+ if (scsi_bufflen(sc) !=
+ xfer_cnt) {
+ sc->result =
+ DID_SOFT_ERROR << 16;
+ printk(KERN_WARNING "Errata"
+ "on LSI53C1030 occurred."
+ "sc->req_bufflen=0x%02x,"
+ "xfer_cnt=0x%02x\n",
+ scsi_bufflen(sc),
+ xfer_cnt);
+ }
+ }
+ }
+
if (xfer_cnt < sc->underflow) {
if (scsi_status == SAM_STAT_BUSY)
sc->result = SAM_STAT_BUSY;
@@ -835,7 +860,58 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
sc->result = (DID_OK << 16) | scsi_status;
if (scsi_state == 0) {
;
- } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
+ } else if (scsi_state &
+ MPI_SCSI_STATE_AUTOSENSE_VALID) {
+
+ /*
+ * For potential trouble on LSI53C1030.
+ * (date:2007.xx.)
+ * It is checked whether the length of
+ * request data is equal to
+ * the length of transfer and residual.
+ * MEDIUM_ERROR is set by incorrect data.
+ */
+ if ((ioc->bus_type == SPI) &&
+ (sc->sense_buffer[2] & 0x20)) {
+ u32 difftransfer;
+ difftransfer =
+ sc->sense_buffer[3] << 24 |
+ sc->sense_buffer[4] << 16 |
+ sc->sense_buffer[5] << 8 |
+ sc->sense_buffer[6];
+ if (((sc->sense_buffer[3] & 0x80) ==
+ 0x80) && (scsi_bufflen(sc)
+ != xfer_cnt)) {
+ sc->sense_buffer[2] =
+ MEDIUM_ERROR;
+ sc->sense_buffer[12] = 0xff;
+ sc->sense_buffer[13] = 0xff;
+ printk(KERN_WARNING"Errata"
+ "on LSI53C1030 occurred."
+ "sc->req_bufflen=0x%02x,"
+ "xfer_cnt=0x%02x\n" ,
+ scsi_bufflen(sc),
+ xfer_cnt);
+ }
+ if (((sc->sense_buffer[3] & 0x80)
+ != 0x80) &&
+ (scsi_bufflen(sc) !=
+ xfer_cnt + difftransfer)) {
+ sc->sense_buffer[2] =
+ MEDIUM_ERROR;
+ sc->sense_buffer[12] = 0xff;
+ sc->sense_buffer[13] = 0xff;
+ printk(KERN_WARNING
+ "Errata on LSI53C1030 occurred"
+ "sc->req_bufflen=0x%02x,"
+ " xfer_cnt=0x%02x,"
+ "difftransfer=0x%02x\n",
+ scsi_bufflen(sc),
+ xfer_cnt,
+ difftransfer);
+ }
+ }
+
/*
* If running against circa 200003dd 909 MPT f/w,
* may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
@@ -2275,11 +2351,12 @@ mptscsih_slave_destroy(struct scsi_device *sdev)
* mptscsih_change_queue_depth - This function will set a devices queue depth
* @sdev: per scsi_device pointer
* @qdepth: requested queue depth
+ * @reason: calling context
*
* Adding support for new 'change_queue_depth' api.
*/
int
-mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
+mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
{
MPT_SCSI_HOST *hd = shost_priv(sdev->host);
VirtTarget *vtarget;
@@ -2291,6 +2368,9 @@ mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
starget = scsi_target(sdev);
vtarget = starget->hostdata;
+ if (reason != SCSI_QDEPTH_DEFAULT)
+ return -EOPNOTSUPP;
+
if (ioc->bus_type == SPI) {
if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
max_depth = 1;
@@ -2357,7 +2437,8 @@ mptscsih_slave_configure(struct scsi_device *sdev)
ioc->name, vtarget->negoFlags, vtarget->maxOffset,
vtarget->minSyncFactor));
- mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
+ mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH,
+ SCSI_QDEPTH_DEFAULT);
dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"tagged %d, simple %d, ordered %d\n",
ioc->name,sdev->tagged_supported, sdev->simple_tags,
diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h
index e0b33e0..45a5ff3 100644
--- a/drivers/message/fusion/mptscsih.h
+++ b/drivers/message/fusion/mptscsih.h
@@ -128,7 +128,8 @@ extern int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_F
extern int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
extern int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
extern int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
-extern int mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth);
+extern int mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth,
+ int reason);
extern u8 mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id);
extern int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id);
extern struct device_attribute *mptscsih_host_attrs[];
diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c
index d505b68..e39986a 100644
--- a/drivers/message/i2o/i2o_block.c
+++ b/drivers/message/i2o/i2o_block.c
@@ -940,7 +940,7 @@ static const struct block_device_operations i2o_block_fops = {
* Allocate memory for the i2o_block_device struct, gendisk and request
* queue and initialize them as far as no additional information is needed.
*
- * Returns a pointer to the allocated I2O Block device on succes or a
+ * Returns a pointer to the allocated I2O Block device on success or a
* negative error code on failure.
*/
static struct i2o_block_device *i2o_block_device_alloc(void)
diff --git a/drivers/message/i2o/iop.c b/drivers/message/i2o/iop.c
index 27cf4af..e5ab621 100644
--- a/drivers/message/i2o/iop.c
+++ b/drivers/message/i2o/iop.c
@@ -132,7 +132,7 @@ u32 i2o_cntxt_list_add(struct i2o_controller * c, void *ptr)
* Removes a previously added pointer from the context list and returns
* the matching context id.
*
- * Returns context id on succes or 0 on failure.
+ * Returns context id on success or 0 on failure.
*/
u32 i2o_cntxt_list_remove(struct i2o_controller * c, void *ptr)
{
@@ -198,7 +198,7 @@ void *i2o_cntxt_list_get(struct i2o_controller *c, u32 context)
* @c: controller to which the context list belong
* @ptr: pointer to which the context id should be fetched
*
- * Returns context id which matches to the pointer on succes or 0 on
+ * Returns context id which matches to the pointer on success or 0 on
* failure.
*/
u32 i2o_cntxt_list_get_ptr(struct i2o_controller * c, void *ptr)
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 08f2d07..a296e71 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -35,6 +35,14 @@ config MFD_ASIC3
This driver supports the ASIC3 multifunction chip found on many
PDAs (mainly iPAQ and HTC based ones)
+config MFD_SH_MOBILE_SDHI
+ bool "Support for SuperH Mobile SDHI"
+ depends on SUPERH
+ select MFD_CORE
+ ---help---
+ This driver supports the SDHI hardware block found in many
+ SuperH Mobile SoCs.
+
config MFD_DM355EVM_MSP
bool "DaVinci DM355 EVM microcontroller"
depends on I2C && MACH_DAVINCI_DM355_EVM
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index af0fc90..11350c1 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -4,6 +4,7 @@
obj-$(CONFIG_MFD_SM501) += sm501.o
obj-$(CONFIG_MFD_ASIC3) += asic3.o
+obj-$(CONFIG_MFD_SH_MOBILE_SDHI) += sh_mobile_sdhi.o
obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o
obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o
diff --git a/drivers/mfd/sh_mobile_sdhi.c b/drivers/mfd/sh_mobile_sdhi.c
new file mode 100644
index 0000000..03efae8
--- /dev/null
+++ b/drivers/mfd/sh_mobile_sdhi.c
@@ -0,0 +1,156 @@
+/*
+ * SuperH Mobile SDHI
+ *
+ * Copyright (C) 2009 Magnus Damm
+ *
+ * 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.
+ *
+ * Based on "Compaq ASIC3 support":
+ *
+ * Copyright 2001 Compaq Computer Corporation.
+ * Copyright 2004-2005 Phil Blundell
+ * Copyright 2007-2008 OpenedHand Ltd.
+ *
+ * Authors: Phil Blundell <pb@handhelds.org>,
+ * Samuel Ortiz <sameo@openedhand.com>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+#include <linux/mfd/core.h>
+#include <linux/mfd/tmio.h>
+#include <linux/mfd/sh_mobile_sdhi.h>
+
+struct sh_mobile_sdhi {
+ struct clk *clk;
+ struct tmio_mmc_data mmc_data;
+ struct mfd_cell cell_mmc;
+};
+
+static struct resource sh_mobile_sdhi_resources[] = {
+ {
+ .start = 0x000,
+ .end = 0x1ff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = 0,
+ .end = 0,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct mfd_cell sh_mobile_sdhi_cell = {
+ .name = "tmio-mmc",
+ .num_resources = ARRAY_SIZE(sh_mobile_sdhi_resources),
+ .resources = sh_mobile_sdhi_resources,
+};
+
+static void sh_mobile_sdhi_set_pwr(struct platform_device *tmio, int state)
+{
+ struct platform_device *pdev = to_platform_device(tmio->dev.parent);
+ struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
+
+ if (p && p->set_pwr)
+ p->set_pwr(pdev, state);
+}
+
+static int __init sh_mobile_sdhi_probe(struct platform_device *pdev)
+{
+ struct sh_mobile_sdhi *priv;
+ struct resource *mem;
+ char clk_name[8];
+ int ret, irq;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem)
+ dev_err(&pdev->dev, "missing MEM resource\n");
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ dev_err(&pdev->dev, "missing IRQ resource\n");
+
+ if (!mem || (irq < 0))
+ return -EINVAL;
+
+ priv = kzalloc(sizeof(struct sh_mobile_sdhi), GFP_KERNEL);
+ if (priv == NULL) {
+ dev_err(&pdev->dev, "kzalloc failed\n");
+ return -ENOMEM;
+ }
+
+ snprintf(clk_name, sizeof(clk_name), "sdhi%d", pdev->id);
+ priv->clk = clk_get(&pdev->dev, clk_name);
+ if (IS_ERR(priv->clk)) {
+ dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
+ ret = PTR_ERR(priv->clk);
+ kfree(priv);
+ return ret;
+ }
+
+ clk_enable(priv->clk);
+
+ /* FIXME: silly const unsigned int hclk */
+ *(unsigned int *)&priv->mmc_data.hclk = clk_get_rate(priv->clk);
+ priv->mmc_data.set_pwr = sh_mobile_sdhi_set_pwr;
+
+ memcpy(&priv->cell_mmc, &sh_mobile_sdhi_cell, sizeof(priv->cell_mmc));
+ priv->cell_mmc.driver_data = &priv->mmc_data;
+ priv->cell_mmc.platform_data = &priv->cell_mmc;
+ priv->cell_mmc.data_size = sizeof(priv->cell_mmc);
+
+ platform_set_drvdata(pdev, priv);
+
+ ret = mfd_add_devices(&pdev->dev, pdev->id,
+ &priv->cell_mmc, 1, mem, irq);
+ if (ret) {
+ clk_disable(priv->clk);
+ clk_put(priv->clk);
+ kfree(priv);
+ }
+
+ return ret;
+}
+
+static int sh_mobile_sdhi_remove(struct platform_device *pdev)
+{
+ struct sh_mobile_sdhi *priv = platform_get_drvdata(pdev);
+
+ mfd_remove_devices(&pdev->dev);
+ clk_disable(priv->clk);
+ clk_put(priv->clk);
+ kfree(priv);
+
+ return 0;
+}
+
+static struct platform_driver sh_mobile_sdhi_driver = {
+ .driver = {
+ .name = "sh_mobile_sdhi",
+ .owner = THIS_MODULE,
+ },
+ .probe = sh_mobile_sdhi_probe,
+ .remove = __devexit_p(sh_mobile_sdhi_remove),
+};
+
+static int __init sh_mobile_sdhi_init(void)
+{
+ return platform_driver_register(&sh_mobile_sdhi_driver);
+}
+
+static void __exit sh_mobile_sdhi_exit(void)
+{
+ platform_driver_unregister(&sh_mobile_sdhi_driver);
+}
+
+module_init(sh_mobile_sdhi_init);
+module_exit(sh_mobile_sdhi_exit);
+
+MODULE_DESCRIPTION("SuperH Mobile SDHI driver");
+MODULE_AUTHOR("Magnus Damm");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/sgi-gru/grufile.c b/drivers/misc/sgi-gru/grufile.c
index 41c8fe2..ce5eda9 100644
--- a/drivers/misc/sgi-gru/grufile.c
+++ b/drivers/misc/sgi-gru/grufile.c
@@ -92,7 +92,7 @@ static void gru_vma_close(struct vm_area_struct *vma)
/*
* gru_file_mmap
*
- * Called when mmaping the device. Initializes the vma with a fault handler
+ * Called when mmapping the device. Initializes the vma with a fault handler
* and private data structure necessary to allocate, track, and free the
* underlying pages.
*/
diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c
index 36a8d53..b8e7c5a 100644
--- a/drivers/mmc/card/sdio_uart.c
+++ b/drivers/mmc/card/sdio_uart.c
@@ -231,7 +231,8 @@ static unsigned int sdio_uart_get_mctrl(struct sdio_uart_port *port)
return ret;
}
-static void sdio_uart_write_mctrl(struct sdio_uart_port *port, unsigned int mctrl)
+static void sdio_uart_write_mctrl(struct sdio_uart_port *port,
+ unsigned int mctrl)
{
unsigned char mcr = 0;
@@ -387,7 +388,8 @@ static void sdio_uart_stop_rx(struct sdio_uart_port *port)
sdio_out(port, UART_IER, port->ier);
}
-static void sdio_uart_receive_chars(struct sdio_uart_port *port, unsigned int *status)
+static void sdio_uart_receive_chars(struct sdio_uart_port *port,
+ unsigned int *status)
{
struct tty_struct *tty = port->tty;
unsigned int ch, flag;
@@ -399,7 +401,7 @@ static void sdio_uart_receive_chars(struct sdio_uart_port *port, unsigned int *s
port->icount.rx++;
if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
- UART_LSR_FE | UART_LSR_OE))) {
+ UART_LSR_FE | UART_LSR_OE))) {
/*
* For statistics only
*/
@@ -417,9 +419,9 @@ static void sdio_uart_receive_chars(struct sdio_uart_port *port, unsigned int *s
* Mask off conditions which should be ignored.
*/
*status &= port->read_status_mask;
- if (*status & UART_LSR_BI) {
+ if (*status & UART_LSR_BI)
flag = TTY_BREAK;
- } else if (*status & UART_LSR_PE)
+ else if (*status & UART_LSR_PE)
flag = TTY_PARITY;
else if (*status & UART_LSR_FE)
flag = TTY_FRAME;
@@ -574,7 +576,7 @@ static int sdio_uart_startup(struct sdio_uart_port *port)
*/
sdio_out(port, UART_FCR, UART_FCR_ENABLE_FIFO);
sdio_out(port, UART_FCR, UART_FCR_ENABLE_FIFO |
- UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+ UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
sdio_out(port, UART_FCR, 0);
/*
@@ -635,7 +637,7 @@ static void sdio_uart_shutdown(struct sdio_uart_port *port)
if (port->tty->termios->c_cflag & HUPCL)
sdio_uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
- /* Disable interrupts from this port */
+ /* Disable interrupts from this port */
sdio_release_irq(port->func);
port->ier = 0;
sdio_out(port, UART_IER, 0);
@@ -659,7 +661,7 @@ skip:
free_page((unsigned long)port->xmit.buf);
}
-static int sdio_uart_open (struct tty_struct *tty, struct file * filp)
+static int sdio_uart_open(struct tty_struct *tty, struct file *filp)
{
struct sdio_uart_port *port;
int ret;
@@ -846,7 +848,7 @@ static void sdio_uart_set_termios(struct tty_struct *tty, struct ktermios *old_t
struct sdio_uart_port *port = tty->driver_data;
unsigned int cflag = tty->termios->c_cflag;
-#define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+#define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
if ((cflag ^ old_termios->c_cflag) == 0 &&
RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0)
@@ -925,7 +927,7 @@ static int sdio_uart_tiocmset(struct tty_struct *tty, struct file *file,
struct sdio_uart_port *port = tty->driver_data;
int result;
- result =sdio_uart_claim_func(port);
+ result = sdio_uart_claim_func(port);
if(!result) {
sdio_uart_update_mctrl(port, set, clear);
sdio_uart_release_func(port);
@@ -946,31 +948,31 @@ static int sdio_uart_proc_show(struct seq_file *m, void *v)
seq_printf(m, "%d: uart:SDIO", i);
if(capable(CAP_SYS_ADMIN)) {
seq_printf(m, " tx:%d rx:%d",
- port->icount.tx, port->icount.rx);
+ port->icount.tx, port->icount.rx);
if (port->icount.frame)
seq_printf(m, " fe:%d",
- port->icount.frame);
+ port->icount.frame);
if (port->icount.parity)
seq_printf(m, " pe:%d",
- port->icount.parity);
+ port->icount.parity);
if (port->icount.brk)
seq_printf(m, " brk:%d",
- port->icount.brk);
+ port->icount.brk);
if (port->icount.overrun)
seq_printf(m, " oe:%d",
- port->icount.overrun);
+ port->icount.overrun);
if (port->icount.cts)
seq_printf(m, " cts:%d",
- port->icount.cts);
+ port->icount.cts);
if (port->icount.dsr)
seq_printf(m, " dsr:%d",
- port->icount.dsr);
+ port->icount.dsr);
if (port->icount.rng)
seq_printf(m, " rng:%d",
- port->icount.rng);
+ port->icount.rng);
if (port->icount.dcd)
seq_printf(m, " dcd:%d",
- port->icount.dcd);
+ port->icount.dcd);
}
sdio_uart_port_put(port);
seq_putc(m, '\n');
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 432ae83..e04b751 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -329,7 +329,7 @@ config MMC_SDRICOH_CS
config MMC_TMIO
tristate "Toshiba Mobile IO Controller (TMIO) MMC/SD function support"
- depends on MFD_TMIO || MFD_ASIC3
+ depends on MFD_TMIO || MFD_ASIC3 || SUPERH
help
This provides support for the SD/MMC cell found in TC6393XB,
T7L66XB and also HTC ASIC3
diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c
index 99b74a3..941a4d3 100644
--- a/drivers/mmc/host/s3cmci.c
+++ b/drivers/mmc/host/s3cmci.c
@@ -1360,7 +1360,7 @@ static struct mmc_host_ops s3cmci_ops = {
static struct s3c24xx_mci_pdata s3cmci_def_pdata = {
/* This is currently here to avoid a number of if (host->pdata)
- * checks. Any zero fields to ensure reaonable defaults are picked. */
+ * checks. Any zero fields to ensure reasonable defaults are picked. */
};
#ifdef CONFIG_CPU_FREQ
diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig
index 9408099..35c6a23 100644
--- a/drivers/mtd/chips/Kconfig
+++ b/drivers/mtd/chips/Kconfig
@@ -1,5 +1,3 @@
-# drivers/mtd/chips/Kconfig
-
menu "RAM/ROM/Flash chip drivers"
depends on MTD!=n
@@ -242,4 +240,3 @@ config MTD_XIP
then say N.
endmenu
-
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index c222514..35081ce 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -1,5 +1,3 @@
-# drivers/mtd/maps/Kconfig
-
menu "Self-contained MTD device drivers"
depends on MTD!=n
@@ -308,4 +306,3 @@ config MTD_DOCPROBE_55AA
you have managed to wipe the first block.
endmenu
-
diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c
index 3aa05cd..592016a 100644
--- a/drivers/mtd/devices/slram.c
+++ b/drivers/mtd/devices/slram.c
@@ -18,7 +18,7 @@
to specify the offset instead of the absolute address
NOTE:
- With slram it's only possible to map a contigous memory region. Therfore
+ With slram it's only possible to map a contiguous memory region. Therefore
if there's a device mapped somewhere in the region specified slram will
fail to load (see kernel log if modprobe fails).
diff --git a/drivers/mtd/lpddr/Kconfig b/drivers/mtd/lpddr/Kconfig
index 5a401d8..265f969 100644
--- a/drivers/mtd/lpddr/Kconfig
+++ b/drivers/mtd/lpddr/Kconfig
@@ -1,5 +1,3 @@
-# drivers/mtd/chips/Kconfig
-
menu "LPDDR flash memory drivers"
depends on MTD!=n
@@ -20,4 +18,3 @@ config MTD_QINFO_PROBE
families of devices. This serves similar purpose of CFI on legacy
Flash products
endmenu
-
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index 14be075..847e214 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -1,5 +1,3 @@
-# drivers/mtd/maps/Kconfig
-
menu "Mapping drivers for chip access"
depends on MTD!=n
@@ -389,9 +387,9 @@ config MTD_IXP2000
depends on MTD_CFI && MTD_COMPLEX_MAPPINGS && ARCH_IXP2000
help
This enables MTD access to flash devices on platforms based
- on Intel's IXP2000 family of network processors such as the
- IXDP425 and Coyote. If you have an IXP2000 based board and
- would like to use the flash chips on it, say 'Y'.
+ on Intel's IXP2000 family of network processors. If you have an
+ IXP2000 based board and would like to use the flash chips on it,
+ say 'Y'.
config MTD_FORTUNET
tristate "CFI Flash device mapped on the FortuNet board"
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 8f8e87b..0e35e1a 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -1,5 +1,3 @@
-# drivers/mtd/nand/Kconfig
-
menuconfig MTD_NAND
tristate "NAND Device Support"
depends on MTD
diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c
index e51c1ed7..b126cf8 100644
--- a/drivers/mtd/nand/diskonchip.c
+++ b/drivers/mtd/nand/diskonchip.c
@@ -1056,7 +1056,7 @@ static struct nand_ecclayout doc200x_oobinfo = {
};
/* Find the (I)NFTL Media Header, and optionally also the mirror media header.
- On sucessful return, buf will contain a copy of the media header for
+ On successful return, buf will contain a copy of the media header for
further processing. id is the string to scan for, and will presumably be
either "ANAND" or "BNAND". If findmirror=1, also look for the mirror media
header. The page #s of the found media headers are placed in mh0_page and
diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c
index db7ae9d..92320a6 100644
--- a/drivers/mtd/nand/nand_ecc.c
+++ b/drivers/mtd/nand/nand_ecc.c
@@ -475,7 +475,7 @@ int __nand_correct_data(unsigned char *buf,
*
* The b2 shift is there to get rid of the lowest two bits.
* We could also do addressbits[b2] >> 1 but for the
- * performace it does not make any difference
+ * performance it does not make any difference
*/
if (eccsize_mult == 1)
byte_addr = (addressbits[b1] << 4) + addressbits[b0];
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index 11dc7e6..68b5b3a 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -875,7 +875,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
* @info: The controller instance.
* @nmtd: The driver version of the MTD instance.
*
- * This routine is called after the chip probe has succesfully completed
+ * This routine is called after the chip probe has successfully completed
* and the relevant per-chip information updated. This call ensure that
* we update the internal state accordingly.
*
diff --git a/drivers/mtd/onenand/Kconfig b/drivers/mtd/onenand/Kconfig
index a38f580..3a9f157 100644
--- a/drivers/mtd/onenand/Kconfig
+++ b/drivers/mtd/onenand/Kconfig
@@ -1,7 +1,3 @@
-#
-# linux/drivers/mtd/onenand/Kconfig
-#
-
menuconfig MTD_ONENAND
tristate "OneNAND Device Support"
depends on MTD
diff --git a/drivers/mtd/ubi/Kconfig b/drivers/mtd/ubi/Kconfig
index b1cd7a1..0a8c7ea 100644
--- a/drivers/mtd/ubi/Kconfig
+++ b/drivers/mtd/ubi/Kconfig
@@ -1,5 +1,3 @@
-# drivers/mtd/ubi/Kconfig
-
menu "UBI - Unsorted block images"
depends on MTD
diff --git a/drivers/net/82596.c b/drivers/net/82596.c
index ea6b139..1663bc9 100644
--- a/drivers/net/82596.c
+++ b/drivers/net/82596.c
@@ -19,7 +19,7 @@
TBD:
* look at deferring rx frames rather than discarding (as per tulip)
* handle tx ring full as per tulip
- * performace test to tune rx_copybreak
+ * performance test to tune rx_copybreak
Most of my modifications relate to the braindead big-endian
implementation by Intel. When the i596 is operating in
diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c
index 4e6359f..766aabf 100644
--- a/drivers/net/amd8111e.c
+++ b/drivers/net/amd8111e.c
@@ -1633,8 +1633,13 @@ static int amd8111e_enable_link_change(struct amd8111e_priv* lp)
readl(lp->mmio + CMD7);
return 0;
}
-/* This function is called when a packet transmission fails to complete within a resonable period, on the assumption that an interrupts have been failed or the interface is locked up. This function will reinitialize the hardware */
+/*
+ * This function is called when a packet transmission fails to complete
+ * within a reasonable period, on the assumption that an interrupt have
+ * failed or the interface is locked up. This function will reinitialize
+ * the hardware.
+ */
static void amd8111e_tx_timeout(struct net_device *dev)
{
struct amd8111e_priv* lp = netdev_priv(dev);
diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c
index 50cecf4..73b38c2 100644
--- a/drivers/net/appletalk/cops.c
+++ b/drivers/net/appletalk/cops.c
@@ -120,7 +120,7 @@ static int irq = 5; /* Default IRQ */
* DAYNA driver mode:
* Dayna DL2000/DaynaTalk PC (Half Length), COPS LT-95,
* Farallon PhoneNET PC III, Farallon PhoneNET PC II
- * Other cards possibly supported mode unkown though:
+ * Other cards possibly supported mode unknown though:
* Dayna DL2000 (Full length), COPS LT/M (Micro-Channel)
*
* Cards NOT supported by this driver but supported by the ltpc.c
diff --git a/drivers/net/ariadne.h b/drivers/net/ariadne.h
index bb613f2..727be5c 100644
--- a/drivers/net/ariadne.h
+++ b/drivers/net/ariadne.h
@@ -244,7 +244,7 @@ struct Am79C960 {
#define DLNKTST 0x0010 /* Disable Link Status */
#define DAPC 0x0008 /* Disable Automatic Polarity Correction */
#define MENDECL 0x0004 /* MENDEC Loopback Mode */
-#define LRTTSEL 0x0002 /* Low Receive Treshold/Transmit Mode Select */
+#define LRTTSEL 0x0002 /* Low Receive Threshold/Transmit Mode Select */
#define PORTSEL1 0x0001 /* Port Select Bits */
#define PORTSEL2 0x8000 /* Port Select Bits */
#define INTL 0x4000 /* Internal Loopback */
diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c
index 1e2f57d..6eb9241 100644
--- a/drivers/net/atl1c/atl1c_main.c
+++ b/drivers/net/atl1c/atl1c_main.c
@@ -1540,7 +1540,7 @@ static irqreturn_t atl1c_intr(int irq, void *data)
if (status & ISR_OVER)
if (netif_msg_intr(adapter))
dev_warn(&pdev->dev,
- "TX/RX over flow (status = 0x%x)\n",
+ "TX/RX overflow (status = 0x%x)\n",
status & ISR_OVER);
/* link event */
diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h
index e7323be..92b87ef 100644
--- a/drivers/net/benet/be_cmds.h
+++ b/drivers/net/benet/be_cmds.h
@@ -444,7 +444,7 @@ enum be_if_flags {
* filtering capabilities. */
struct be_cmd_req_if_create {
struct be_cmd_req_hdr hdr;
- u32 version; /* ignore currntly */
+ u32 version; /* ignore currently */
u32 capability_flags;
u32 enable_flags;
u8 mac_addr[ETH_ALEN];
diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c
index 957a0f7..24c7d99 100644
--- a/drivers/net/benet/be_main.c
+++ b/drivers/net/benet/be_main.c
@@ -1982,7 +1982,7 @@ int be_load_fw(struct be_adapter *adapter, u8 *func)
goto fw_exit;
}
- dev_info(&adapter->pdev->dev, "Firmware flashed succesfully\n");
+ dev_info(&adapter->pdev->dev, "Firmware flashed successfully\n");
fw_exit:
release_firmware(fw);
diff --git a/drivers/net/bnx2x_reg.h b/drivers/net/bnx2x_reg.h
index b668173..944964e 100644
--- a/drivers/net/bnx2x_reg.h
+++ b/drivers/net/bnx2x_reg.h
@@ -2536,7 +2536,7 @@
/* [RC 1] A flag to indicate that overflow error occurred in one of the
queues. */
#define QM_REG_OVFERROR 0x16805c
-/* [RC 7] the Q were the qverflow occurs */
+/* [RC 7] the Q where the overflow occurs */
#define QM_REG_OVFQNUM 0x168058
/* [R 16] Pause state for physical queues 15-0 */
#define QM_REG_PAUSESTATE0 0x168410
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 0d30d1e..00ab51e 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -556,7 +556,7 @@ static void rlb_update_rx_clients(struct bonding *bond)
}
}
- /* do not update the entries again untill this counter is zero so that
+ /* do not update the entries again until this counter is zero so that
* not to confuse the clients.
*/
bond_info->rlb_update_delay_counter = RLB_UPDATE_DELAY;
diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c
index 49f3de7..bdbd147 100644
--- a/drivers/net/cxgb3/sge.c
+++ b/drivers/net/cxgb3/sge.c
@@ -1285,7 +1285,7 @@ netdev_tx_t t3_eth_xmit(struct sk_buff *skb, struct net_device *dev)
/*
* We do not use Tx completion interrupts to free DMAd Tx packets.
- * This is good for performamce but means that we rely on new Tx
+ * This is good for performance but means that we rely on new Tx
* packets arriving to run the destructors of completed packets,
* which open up space in their sockets' send queues. Sometimes
* we do not get such new packets causing Tx to stall. A single
diff --git a/drivers/net/ehea/ehea_ethtool.c b/drivers/net/ehea/ehea_ethtool.c
index d768852..75b099c 100644
--- a/drivers/net/ehea/ehea_ethtool.c
+++ b/drivers/net/ehea/ehea_ethtool.c
@@ -118,7 +118,7 @@ doit:
ret = ehea_set_portspeed(port, sp);
if (!ret)
- ehea_info("%s: Port speed succesfully set: %dMbps "
+ ehea_info("%s: Port speed successfully set: %dMbps "
"%s Duplex",
port->netdev->name, port->port_speed,
port->full_duplex == 1 ? "Full" : "Half");
@@ -134,7 +134,7 @@ static int ehea_nway_reset(struct net_device *dev)
ret = ehea_set_portspeed(port, EHEA_SPEED_AUTONEG);
if (!ret)
- ehea_info("%s: Port speed succesfully set: %dMbps "
+ ehea_info("%s: Port speed successfully set: %dMbps "
"%s Duplex",
port->netdev->name, port->port_speed,
port->full_duplex == 1 ? "Full" : "Half");
diff --git a/drivers/net/hamradio/baycom_ser_fdx.c b/drivers/net/hamradio/baycom_ser_fdx.c
index ed60fd6..0cab992 100644
--- a/drivers/net/hamradio/baycom_ser_fdx.c
+++ b/drivers/net/hamradio/baycom_ser_fdx.c
@@ -35,7 +35,7 @@
* driver only supports standard serial hardware (8250, 16450, 16550A)
*
* This modem usually draws its supply current out of the otherwise unused
- * TXD pin of the serial port. Thus a contignuous stream of 0x00-bytes
+ * TXD pin of the serial port. Thus a contiguous stream of 0x00-bytes
* is transmitted to achieve a positive supply voltage.
*
* hsk: This is a 4800 baud FSK modem, designed for TNC use. It works fine
diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c
index 1e8dd8c..8f7d0d1 100644
--- a/drivers/net/irda/smsc-ircc2.c
+++ b/drivers/net/irda/smsc-ircc2.c
@@ -115,7 +115,7 @@ struct smsc_ircc_subsystem_configuration {
unsigned short vendor; /* PCI vendor ID */
unsigned short device; /* PCI vendor ID */
unsigned short subvendor; /* PCI subsystem vendor ID */
- unsigned short subdevice; /* PCI sybsystem device ID */
+ unsigned short subdevice; /* PCI subsystem device ID */
unsigned short sir_io; /* I/O port for SIR */
unsigned short fir_io; /* I/O port for FIR */
unsigned char fir_irq; /* FIR IRQ */
diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c
index 4999719..16c9191 100644
--- a/drivers/net/iseries_veth.c
+++ b/drivers/net/iseries_veth.c
@@ -1384,7 +1384,7 @@ static inline void veth_build_dma_list(struct dma_chunk *list,
unsigned long done;
int i = 1;
- /* FIXME: skbs are continguous in real addresses. Do we
+ /* FIXME: skbs are contiguous in real addresses. Do we
* really need to break it into PAGE_SIZE chunks, or can we do
* it just at the granularity of iSeries real->absolute
* mapping? Indeed, given the way the allocator works, can we
diff --git a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c
index a0c5785..b77238d 100644
--- a/drivers/net/lasi_82596.c
+++ b/drivers/net/lasi_82596.c
@@ -47,7 +47,7 @@
TBD:
* look at deferring rx frames rather than discarding (as per tulip)
* handle tx ring full as per tulip
- * performace test to tune rx_copybreak
+ * performance test to tune rx_copybreak
Most of my modifications relate to the braindead big-endian
implementation by Intel. When the i596 is operating in
diff --git a/drivers/net/lib82596.c b/drivers/net/lib82596.c
index 7a07430..b117f7f 100644
--- a/drivers/net/lib82596.c
+++ b/drivers/net/lib82596.c
@@ -47,7 +47,7 @@
TBD:
* look at deferring rx frames rather than discarding (as per tulip)
* handle tx ring full as per tulip
- * performace test to tune rx_copybreak
+ * performance test to tune rx_copybreak
Most of my modifications relate to the braindead big-endian
implementation by Intel. When the i596 is operating in
diff --git a/drivers/net/mlx4/en_rx.c b/drivers/net/mlx4/en_rx.c
index 03b781a..829b9ec 100644
--- a/drivers/net/mlx4/en_rx.c
+++ b/drivers/net/mlx4/en_rx.c
@@ -204,7 +204,7 @@ static void mlx4_en_free_rx_desc(struct mlx4_en_priv *priv,
en_dbg(DRV, priv, "Freeing fragment:%d\n", nr);
dma = be64_to_cpu(rx_desc->data[nr].addr);
- en_dbg(DRV, priv, "Unmaping buffer at dma:0x%llx\n", (u64) dma);
+ en_dbg(DRV, priv, "Unmapping buffer at dma:0x%llx\n", (u64) dma);
pci_unmap_single(mdev->pdev, dma, skb_frags[nr].size,
PCI_DMA_FROMDEVICE);
put_page(skb_frags[nr].page);
diff --git a/drivers/net/mlx4/en_tx.c b/drivers/net/mlx4/en_tx.c
index 8c72799..3d1396a 100644
--- a/drivers/net/mlx4/en_tx.c
+++ b/drivers/net/mlx4/en_tx.c
@@ -47,7 +47,7 @@ enum {
static int inline_thold __read_mostly = MAX_INLINE;
module_param_named(inline_thold, inline_thold, int, 0444);
-MODULE_PARM_DESC(inline_thold, "treshold for using inline data");
+MODULE_PARM_DESC(inline_thold, "threshold for using inline data");
int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
struct mlx4_en_tx_ring *ring, u32 size,
diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h
index 4376147..82c3ebc 100644
--- a/drivers/net/mlx4/mlx4_en.h
+++ b/drivers/net/mlx4/mlx4_en.h
@@ -162,7 +162,7 @@ enum {
#define MLX4_EN_DEF_RX_PAUSE 1
#define MLX4_EN_DEF_TX_PAUSE 1
-/* Interval between sucessive polls in the Tx routine when polling is used
+/* Interval between successive polls in the Tx routine when polling is used
instead of interrupts (in per-core Tx rings) - should be power of 2 */
#define MLX4_EN_TX_POLL_MODER 16
#define MLX4_EN_TX_POLL_TIMEOUT (HZ / 4)
diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c
index 89c4948..0c76859 100644
--- a/drivers/net/ps3_gelic_net.c
+++ b/drivers/net/ps3_gelic_net.c
@@ -314,7 +314,7 @@ static void gelic_card_reset_chain(struct gelic_card *card,
* @card: card structure
* @descr: descriptor to re-init
*
- * return 0 on succes, <0 on failure
+ * return 0 on success, <0 on failure
*
* allocates a new rx skb, iommu-maps it and attaches it to the descriptor.
* Activate the descriptor state-wise
diff --git a/drivers/net/ps3_gelic_wireless.h b/drivers/net/ps3_gelic_wireless.h
index 5b631c6..0a88b53 100644
--- a/drivers/net/ps3_gelic_wireless.h
+++ b/drivers/net/ps3_gelic_wireless.h
@@ -199,7 +199,7 @@ struct gelic_eurus_rssi_info {
/* for 'stat' member of gelic_wl_info */
enum gelic_wl_info_status_bit {
GELIC_WL_STAT_CONFIGURED,
- GELIC_WL_STAT_CH_INFO, /* ch info aquired */
+ GELIC_WL_STAT_CH_INFO, /* ch info acquired */
GELIC_WL_STAT_ESSID_SET, /* ESSID specified by userspace */
GELIC_WL_STAT_BSSID_SET, /* BSSID specified by userspace */
GELIC_WL_STAT_WPA_PSK_SET, /* PMK specified by userspace */
diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c
index e3e6bc9..dd35066 100644
--- a/drivers/net/qla3xxx.c
+++ b/drivers/net/qla3xxx.c
@@ -3651,7 +3651,7 @@ static int ql_adapter_up(struct ql3_adapter *qdev)
ql_sem_unlock(qdev, QL_DRVR_SEM_MASK);
} else {
printk(KERN_ERR PFX
- "%s: Could not aquire driver lock.\n",
+ "%s: Could not acquire driver lock.\n",
ndev->name);
goto err_lock;
}
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index 0dd7839..cc42186 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -3238,7 +3238,7 @@ static u64 s2io_mdio_read(u32 mmd_type, u64 addr, struct net_device *dev)
/**
* s2io_chk_xpak_counter - Function to check the status of the xpak counters
- * @counter : couter value to be updated
+ * @counter : counter value to be updated
* @flag : flag to indicate the status
* @type : counter type
* Description:
diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c
index 9a12d88..7360d4b 100644
--- a/drivers/net/sis900.c
+++ b/drivers/net/sis900.c
@@ -1760,7 +1760,7 @@ static int sis900_rx(struct net_device *net_dev)
sis_priv->rx_ring[entry].bufptr, RX_BUF_SIZE,
PCI_DMA_FROMDEVICE);
- /* refill the Rx buffer, what if there is not enought
+ /* refill the Rx buffer, what if there is not enough
* memory for new socket buffer ?? */
if ((skb = dev_alloc_skb(RX_BUF_SIZE)) == NULL) {
/*
@@ -1775,7 +1775,7 @@ static int sis900_rx(struct net_device *net_dev)
}
/* This situation should never happen, but due to
- some unknow bugs, it is possible that
+ some unknown bugs, it is possible that
we are working on NULL sk_buff :-( */
if (sis_priv->rx_skbuff[entry] == NULL) {
if (netif_msg_rx_err(sis_priv))
diff --git a/drivers/net/skfp/h/smc.h b/drivers/net/skfp/h/smc.h
index 1758d95..026a83b 100644
--- a/drivers/net/skfp/h/smc.h
+++ b/drivers/net/skfp/h/smc.h
@@ -393,10 +393,10 @@ struct smt_config {
*/
u_long mac_d_max ; /* MAC : D_Max timer value */
- u_long lct_short ; /* LCT : error threshhold */
- u_long lct_medium ; /* LCT : error threshhold */
- u_long lct_long ; /* LCT : error threshhold */
- u_long lct_extended ; /* LCT : error threshhold */
+ u_long lct_short ; /* LCT : error threshold */
+ u_long lct_medium ; /* LCT : error threshold */
+ u_long lct_long ; /* LCT : error threshold */
+ u_long lct_extended ; /* LCT : error threshold */
} ;
#ifdef DEBUG
diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c
index b27156eaf..db216a7 100644
--- a/drivers/net/skfp/skfddi.c
+++ b/drivers/net/skfp/skfddi.c
@@ -1002,7 +1002,7 @@ static int skfp_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
}
break;
default:
- printk("ioctl for %s: unknow cmd: %04x\n", dev->name, ioc.cmd);
+ printk("ioctl for %s: unknown cmd: %04x\n", dev->name, ioc.cmd);
status = -EOPNOTSUPP;
} // switch
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 3943d89..044e681 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -2017,7 +2017,7 @@ static void sky2_link_down(struct sky2_port *sky2)
netif_carrier_off(sky2->netdev);
- /* Turn on link LED */
+ /* Turn off link LED */
sky2_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_OFF);
if (netif_msg_link(sky2))
diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c
index 4d0d5c5..20d6095 100644
--- a/drivers/net/smsc911x.c
+++ b/drivers/net/smsc911x.c
@@ -816,7 +816,7 @@ static int smsc911x_mii_probe(struct net_device *dev)
SMSC_TRACE(HW, "Passed Loop Back Test");
#endif /* USE_PHY_WORK_AROUND */
- SMSC_TRACE(HW, "phy initialised succesfully");
+ SMSC_TRACE(HW, "phy initialised successfully");
return 0;
}
diff --git a/drivers/net/smsc911x.h b/drivers/net/smsc911x.h
index b5716bd..016360c 100644
--- a/drivers/net/smsc911x.h
+++ b/drivers/net/smsc911x.h
@@ -30,7 +30,7 @@
#define SMSC_NAPI_WEIGHT 16
/* implements a PHY loopback test at initialisation time, to ensure a packet
- * can be succesfully looped back */
+ * can be successfully looped back */
#define USE_PHY_WORK_AROUND
#define DPRINTK(nlevel, klevel, fmt, args...) \
diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c
index 782910c..2185248 100644
--- a/drivers/net/spider_net.c
+++ b/drivers/net/spider_net.c
@@ -410,7 +410,7 @@ spider_net_free_rx_chain_contents(struct spider_net_card *card)
* @card: card structure
* @descr: descriptor to re-init
*
- * Return 0 on succes, <0 on failure.
+ * Return 0 on success, <0 on failure.
*
* Allocates a new rx skb, iommu-maps it and attaches it to the
* descriptor. Mark the descriptor as activated, ready-to-use.
diff --git a/drivers/net/stmmac/gmac.c b/drivers/net/stmmac/gmac.c
index b624bb5..52586ee 100644
--- a/drivers/net/stmmac/gmac.c
+++ b/drivers/net/stmmac/gmac.c
@@ -112,7 +112,7 @@ static void gmac_dma_operation_mode(unsigned long ioaddr, int txmode,
" (threshold = %d)\n", txmode);
csr6 &= ~DMA_CONTROL_TSF;
csr6 &= DMA_CONTROL_TC_TX_MASK;
- /* Set the transmit threashold */
+ /* Set the transmit threshold */
if (txmode <= 32)
csr6 |= DMA_CONTROL_TTC_32;
else if (txmode <= 64)
diff --git a/drivers/net/stmmac/gmac.h b/drivers/net/stmmac/gmac.h
index 684a363..2e82d6c 100644
--- a/drivers/net/stmmac/gmac.h
+++ b/drivers/net/stmmac/gmac.h
@@ -154,14 +154,14 @@ enum rx_tx_priority_ratio {
#define DMA_CONTROL_DT 0x04000000 /* Disable Drop TCP/IP csum error */
#define DMA_CONTROL_RSF 0x02000000 /* Receive Store and Forward */
#define DMA_CONTROL_DFF 0x01000000 /* Disaable flushing */
-/* Theshold for Activating the FC */
+/* Threshold for Activating the FC */
enum rfa {
act_full_minus_1 = 0x00800000,
act_full_minus_2 = 0x00800200,
act_full_minus_3 = 0x00800400,
act_full_minus_4 = 0x00800600,
};
-/* Theshold for Deactivating the FC */
+/* Threshold for Deactivating the FC */
enum rfd {
deac_full_minus_1 = 0x00400000,
deac_full_minus_2 = 0x00400800,
diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c
index 5db0270..66272f2 100644
--- a/drivers/net/tokenring/ibmtr.c
+++ b/drivers/net/tokenring/ibmtr.c
@@ -96,7 +96,7 @@
*
* Change by Mike Sullivan et al.:
* + added turbo card support. No need to use lanaid to configure
- * the adapter into isa compatiblity mode.
+ * the adapter into isa compatibility mode.
*
* Changes by Burt Silverman to allow the computer to behave nicely when
* a cable is pulled or not in place, or a PCMCIA card is removed hot.
diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c
index 427a8970..5401d86 100644
--- a/drivers/net/tokenring/smctr.c
+++ b/drivers/net/tokenring/smctr.c
@@ -426,7 +426,7 @@ static int smctr_alloc_shared_memory(struct net_device *dev)
smctr_malloc(dev, 1L);
/* Allocate Non-MAC receive data buffers.
- * To guarantee a minimum of 256 contigous memory to
+ * To guarantee a minimum of 256 contiguous memory to
* UM_Receive_Packet's lookahead pointer, before a page
* change or ring end is encountered, place each rx buffer on
* a 256 byte boundary.
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index 9f44c99..afaf088 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -3798,7 +3798,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
prop = of_get_property(np, "tx-clock", NULL);
if (!prop) {
printk(KERN_ERR
- "ucc_geth: mising tx-clock-name property\n");
+ "ucc_geth: missing tx-clock-name property\n");
return -EINVAL;
}
if ((*prop < QE_CLK_NONE) || (*prop > QE_CLK24)) {
diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h
index 03a6ca0..a007e2a 100644
--- a/drivers/net/ucc_geth.h
+++ b/drivers/net/ucc_geth.h
@@ -80,16 +80,16 @@ struct ucc_geth {
frames) received that were between 128
(Including FCS length==4) and 255 octets */
u32 txok; /* Total number of octets residing in frames
- that where involved in succesfull
+ that where involved in successfull
transmission */
u16 txcf; /* Total number of PAUSE control frames
transmitted by this MAC */
u8 res4[0x2];
u32 tmca; /* Total number of frames that were transmitted
- succesfully with the group address bit set
+ successfully with the group address bit set
that are not broadcast frames */
u32 tbca; /* Total number of frames transmitted
- succesfully that had destination address
+ successfully that had destination address
field equal to the broadcast address */
u32 rxfok; /* Total number of frames received OK */
u32 rxbok; /* Total number of octets received OK */
@@ -98,9 +98,9 @@ struct ucc_geth {
HW because it includes octets in frames that
never even reach the UCC */
u32 rmca; /* Total number of frames that were received
- succesfully with the group address bit set
+ successfully with the group address bit set
that are not broadcast frames */
- u32 rbca; /* Total number of frames received succesfully
+ u32 rbca; /* Total number of frames received successfully
that had destination address equal to the
broadcast address */
u32 scar; /* Statistics carry register */
@@ -759,15 +759,15 @@ struct ucc_geth_hardware_statistics {
frames) received that were between 128
(Including FCS length==4) and 255 octets */
u32 txok; /* Total number of octets residing in frames
- that where involved in succesfull
+ that where involved in successfull
transmission */
u16 txcf; /* Total number of PAUSE control frames
transmitted by this MAC */
u32 tmca; /* Total number of frames that were transmitted
- succesfully with the group address bit set
+ successfully with the group address bit set
that are not broadcast frames */
u32 tbca; /* Total number of frames transmitted
- succesfully that had destination address
+ successfully that had destination address
field equal to the broadcast address */
u32 rxfok; /* Total number of frames received OK */
u32 rxbok; /* Total number of octets received OK */
@@ -776,9 +776,9 @@ struct ucc_geth_hardware_statistics {
HW because it includes octets in frames that
never even reach the UCC */
u32 rmca; /* Total number of frames that were received
- succesfully with the group address bit set
+ successfully with the group address bit set
that are not broadcast frames */
- u32 rbca; /* Total number of frames received succesfully
+ u32 rbca; /* Total number of frames received successfully
that had destination address equal to the
broadcast address */
} __attribute__ ((packed));
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index c6c9222..0c3c738 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -748,7 +748,7 @@ static int smsc95xx_phy_initialize(struct usbnet *dev)
mii_nway_restart(&dev->mii);
if (netif_msg_ifup(dev))
- devdbg(dev, "phy initialised succesfully");
+ devdbg(dev, "phy initialised successfully");
return 0;
}
diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c
index a7d4fc1..0e52993 100644
--- a/drivers/net/wan/hdlc_fr.c
+++ b/drivers/net/wan/hdlc_fr.c
@@ -182,7 +182,7 @@ static inline pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci)
if (pvc->dlci == dlci)
return pvc;
if (pvc->dlci > dlci)
- return NULL; /* the listed is sorted */
+ return NULL; /* the list is sorted */
pvc = pvc->next;
}
diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c
index 2ebe935..4b6f27e 100644
--- a/drivers/net/wan/lmc/lmc_main.c
+++ b/drivers/net/wan/lmc/lmc_main.c
@@ -927,7 +927,7 @@ static int __devinit lmc_init_one(struct pci_dev *pdev,
sc->lmc_media = &lmc_t1_media;
break;
default:
- printk(KERN_WARNING "%s: LMC UNKOWN CARD!\n", dev->name);
+ printk(KERN_WARNING "%s: LMC UNKNOWN CARD!\n", dev->name);
break;
}
diff --git a/drivers/net/wimax/i2400m/rx.c b/drivers/net/wimax/i2400m/rx.c
index e3d2a9d..7ddb173 100644
--- a/drivers/net/wimax/i2400m/rx.c
+++ b/drivers/net/wimax/i2400m/rx.c
@@ -1194,7 +1194,7 @@ error:
* device. See the file header for the format. Run all checks on the
* buffer header, then run over each payload's descriptors, verify
* their consistency and act on each payload's contents. If
- * everything is succesful, update the device's statistics.
+ * everything is successful, update the device's statistics.
*
* Note: You need to set the skb to contain only the length of the
* received buffer; for that, use skb_trim(skb, RECEIVED_SIZE).
diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h
index b72338c..952b3a2 100644
--- a/drivers/net/wireless/ath/ath5k/base.h
+++ b/drivers/net/wireless/ath/ath5k/base.h
@@ -36,7 +36,7 @@
*/
/*
- * Defintions for the Atheros Wireless LAN controller driver.
+ * Definitions for the Atheros Wireless LAN controller driver.
*/
#ifndef _DEV_ATH_ATHVAR_H
#define _DEV_ATH_ATHVAR_H
@@ -190,7 +190,7 @@ struct ath5k_softc {
struct ath5k_txq *cabq; /* content after beacon */
int power_level; /* Requested tx power in dbm */
- bool assoc; /* assocate state */
+ bool assoc; /* associate state */
bool enable_beacon; /* true if beacons are on */
};
diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c
index 644962a..81ea52c 100644
--- a/drivers/net/wireless/ath/ath5k/eeprom.c
+++ b/drivers/net/wireless/ath/ath5k/eeprom.c
@@ -1492,7 +1492,7 @@ ath5k_eeprom_read_target_rate_pwr_info(struct ath5k_hw *ah, unsigned int mode)
* This info is used to calibrate the baseband power table. Imagine
* that for each channel there is a power curve that's hw specific
* (depends on amplifier etc) and we try to "correct" this curve using
- * offests we pass on to phy chip (baseband -> before amplifier) so that
+ * offsets we pass on to phy chip (baseband -> before amplifier) so that
* it can use accurate power values when setting tx power (takes amplifier's
* performance on each channel into account).
*
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c
index bbfdcd5..72474c0 100644
--- a/drivers/net/wireless/ath/ath5k/phy.c
+++ b/drivers/net/wireless/ath/ath5k/phy.c
@@ -117,7 +117,7 @@ static unsigned int ath5k_hw_rfb_op(struct ath5k_hw *ah,
/*
* This code is used to optimize rf gain on different environments
- * (temprature mostly) based on feedback from a power detector.
+ * (temperature mostly) based on feedback from a power detector.
*
* It's only used on RF5111 and RF5112, later RF chips seem to have
* auto adjustment on hw -notice they have a much smaller BANK 7 and
@@ -2746,7 +2746,7 @@ ath5k_setup_channel_powertable(struct ath5k_hw *ah,
/* Fill curves in reverse order
* from lower power (max gain)
* to higher power. Use curve -> idx
- * backmaping we did on eeprom init */
+ * backmapping we did on eeprom init */
u8 idx = pdg_curve_to_idx[pdg];
/* Grab the needed curves by index */
@@ -2848,7 +2848,7 @@ ath5k_setup_channel_powertable(struct ath5k_hw *ah,
/* Now we have a set of curves for this
* channel on tmpL (x range is table_max - table_min
* and y values are tmpL[pdg][]) sorted in the same
- * order as EEPROM (because we've used the backmaping).
+ * order as EEPROM (because we've used the backmapping).
* So for RF5112 it's from higher power to lower power
* and for RF2413 it's from lower power to higher power.
* For RF5111 we only have one curve. */
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c
index c915954..70fdb9d 100644
--- a/drivers/net/wireless/ath/ath9k/rc.c
+++ b/drivers/net/wireless/ath/ath9k/rc.c
@@ -880,7 +880,7 @@ static bool ath_rc_update_per(struct ath_softc *sc,
* Since this probe succeeded, we allow the next
* probe twice as soon. This allows the maxRate
* to move up faster if the probes are
- * succesful.
+ * successful.
*/
ath_rc_priv->probe_time =
now_msec - rate_table->probe_interval / 2;
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 077480c..71e5c99 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -2955,7 +2955,7 @@ static void do_periodic_work(struct b43_wldev *dev)
/* Periodic work locking policy:
* The whole periodic work handler is protected by
* wl->mutex. If another lock is needed somewhere in the
- * pwork callchain, it's aquired in-place, where it's needed.
+ * pwork callchain, it's acquired in-place, where it's needed.
*/
static void b43_periodic_work_handler(struct work_struct *work)
{
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index ab6a18c..4a905b6 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -2277,7 +2277,7 @@ static void do_periodic_work(struct b43legacy_wldev *dev)
/* Periodic work locking policy:
* The whole periodic work handler is protected by
* wl->mutex. If another lock is needed somewhere in the
- * pwork callchain, it's aquired in-place, where it's needed.
+ * pwork callchain, it's acquired in-place, where it's needed.
*/
static void b43legacy_periodic_work_handler(struct work_struct *work)
{
diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c
index 17a9cb3..56afcf0 100644
--- a/drivers/net/wireless/ipw2x00/ipw2100.c
+++ b/drivers/net/wireless/ipw2x00/ipw2100.c
@@ -578,7 +578,7 @@ static int ipw2100_get_ordinal(struct ipw2100_priv *priv, u32 ord,
/* get number of entries */
field_count = *(((u16 *) & field_info) + 1);
- /* abort if no enought memory */
+ /* abort if no enough memory */
total_length = field_len * field_count;
if (total_length > *len) {
*len = total_length;
@@ -3127,7 +3127,7 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv)
IPW_MAX_BDS)) {
/* TODO: Support merging buffers if more than
* IPW_MAX_BDS are used */
- IPW_DEBUG_INFO("%s: Maximum BD theshold exceeded. "
+ IPW_DEBUG_INFO("%s: Maximum BD threshold exceeded. "
"Increase fragmentation level.\n",
priv->net_dev->name);
}
@@ -6897,7 +6897,7 @@ static int ipw2100_wx_get_range(struct net_device *dev,
range->max_qual.updated = 7; /* Updated all three */
range->avg_qual.qual = 70; /* > 8% missed beacons is 'bad' */
- /* TODO: Find real 'good' to 'bad' threshol value for RSSI */
+ /* TODO: Find real 'good' to 'bad' threshold value for RSSI */
range->avg_qual.level = 20 + IPW2100_RSSI_TO_DBM;
range->avg_qual.noise = 0;
range->avg_qual.updated = 7; /* Updated all three */
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c
index c28984a..09ddd3e 100644
--- a/drivers/net/wireless/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/ipw2x00/ipw2200.c
@@ -792,7 +792,7 @@ static int ipw_get_ordinal(struct ipw_priv *priv, u32 ord, void *val, u32 * len)
/* get number of entries */
field_count = *(((u16 *) & field_info) + 1);
- /* abort if not enought memory */
+ /* abort if not enough memory */
total_len = field_len * field_count;
if (total_len > *len) {
*len = total_len;
@@ -7760,7 +7760,7 @@ static void ipw_rebuild_decrypted_skb(struct ipw_priv *priv,
case SEC_LEVEL_0:
break;
default:
- printk(KERN_ERR "Unknow security level %d\n",
+ printk(KERN_ERR "Unknown security level %d\n",
priv->ieee->sec.level);
break;
}
@@ -8926,7 +8926,7 @@ static int ipw_wx_get_range(struct net_device *dev,
range->max_qual.updated = 7; /* Updated all three */
range->avg_qual.qual = 70;
- /* TODO: Find real 'good' to 'bad' threshol value for RSSI */
+ /* TODO: Find real 'good' to 'bad' threshold value for RSSI */
range->avg_qual.level = 0; /* FIXME to real average level */
range->avg_qual.noise = 0;
range->avg_qual.updated = 7; /* Updated all three */
@@ -10299,7 +10299,7 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct libipw_txb *txb,
case SEC_LEVEL_0:
break;
default:
- printk(KERN_ERR "Unknow security level %d\n",
+ printk(KERN_ERR "Unknown security level %d\n",
priv->ieee->sec.level);
break;
}
diff --git a/drivers/net/wireless/ipw2x00/libipw_module.c b/drivers/net/wireless/ipw2x00/libipw_module.c
index bf21eb3..1ae0b2b 100644
--- a/drivers/net/wireless/ipw2x00/libipw_module.c
+++ b/drivers/net/wireless/ipw2x00/libipw_module.c
@@ -199,7 +199,7 @@ struct net_device *alloc_ieee80211(int sizeof_priv, int monitor)
ieee->host_decrypt = 1;
ieee->host_mc_decrypt = 1;
- /* Host fragementation in Open mode. Default is enabled.
+ /* Host fragmentation in Open mode. Default is enabled.
* Note: host fragmentation is always enabled if host encryption
* is enabled. For cards can do hardware encryption, they must do
* hardware fragmentation as well. So we don't need a variable
diff --git a/drivers/net/wireless/iwmc3200wifi/hal.c b/drivers/net/wireless/iwmc3200wifi/hal.c
index c430418..d13c885 100644
--- a/drivers/net/wireless/iwmc3200wifi/hal.c
+++ b/drivers/net/wireless/iwmc3200wifi/hal.c
@@ -411,7 +411,7 @@ static void iwm_build_lmac_hdr(struct iwm_priv *iwm, struct iwm_lmac_hdr *hdr,
/*
* iwm_hal_send_host_cmd(): sends commands to the UMAC or the LMAC.
* Sending command to the LMAC is equivalent to sending a
- * regular UMAC command with the LMAC passtrough or the LMAC
+ * regular UMAC command with the LMAC passthrough or the LMAC
* wrapper UMAC command IDs.
*/
int iwm_hal_send_host_cmd(struct iwm_priv *iwm,
diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c
index 72c27a3e..1c57c1f 100644
--- a/drivers/net/wireless/iwmc3200wifi/rx.c
+++ b/drivers/net/wireless/iwmc3200wifi/rx.c
@@ -1578,7 +1578,7 @@ static void iwm_rx_process_packet(struct iwm_priv *iwm,
kfree_skb(packet->skb);
break;
default:
- IWM_ERR(iwm, "Unknow ticket action: %d\n",
+ IWM_ERR(iwm, "Unknown ticket action: %d\n",
le16_to_cpu(ticket_node->ticket->action));
kfree_skb(packet->skb);
}
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index 09fcfad..7a73f62 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -993,7 +993,7 @@ static int if_sdio_probe(struct sdio_func *func,
}
if (i == ARRAY_SIZE(if_sdio_models)) {
- lbs_pr_err("unkown card model 0x%x\n", card->model);
+ lbs_pr_err("unknown card model 0x%x\n", card->model);
ret = -ENODEV;
goto free;
}
diff --git a/drivers/net/wireless/orinoco/hermes_dld.c b/drivers/net/wireless/orinoco/hermes_dld.c
index a3eefe1..84200da 100644
--- a/drivers/net/wireless/orinoco/hermes_dld.c
+++ b/drivers/net/wireless/orinoco/hermes_dld.c
@@ -550,7 +550,7 @@ static const struct { \
#define DEFAULT_PDR(pid) default_pdr_data_##pid
-/* HWIF Compatiblity */
+/* HWIF Compatibility */
DEFINE_DEFAULT_PDR(0x0005, 10, "\x00\x00\x06\x00\x01\x00\x01\x00\x01\x00");
/* PPPPSign */
@@ -656,7 +656,7 @@ int hermes_apply_pda_with_defaults(hermes_t *hw,
record_id + 1, pdi);
}
break;
- case 0x5: /* HWIF Compatiblity */
+ case 0x5: /* HWIF Compatibility */
default_pdi = (struct pdi *) &DEFAULT_PDR(0x0005);
break;
case 0x108: /* PPPPSign */
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index bc08464..f7f5c79 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -1897,7 +1897,7 @@ prism54_get_mac(struct net_device *ndev, struct iw_request_info *info,
return 0;
}
-/* Setting policy also clears the MAC acl, even if we don't change the defaut
+/* Setting policy also clears the MAC acl, even if we don't change the default
* policy
*/
@@ -2323,7 +2323,7 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
case DOT11_OID_BEACON:
send_formatted_event(priv,
- "Received a beacon from an unkown AP",
+ "Received a beacon from an unknown AP",
mlme, 0);
break;
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h
index 6c21ef6..c3dea69 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.h
+++ b/drivers/net/wireless/rt2x00/rt2400pci.h
@@ -35,7 +35,7 @@
/*
* Signal information.
- * Defaul offset is required for RSSI <-> dBm conversion.
+ * Default offset is required for RSSI <-> dBm conversion.
*/
#define DEFAULT_RSSI_OFFSET 100
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.h b/drivers/net/wireless/rt2x00/rt2500pci.h
index b007567..c6bd1fc 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.h
+++ b/drivers/net/wireless/rt2x00/rt2500pci.h
@@ -46,7 +46,7 @@
/*
* Signal information.
- * Defaul offset is required for RSSI <-> dBm conversion.
+ * Default offset is required for RSSI <-> dBm conversion.
*/
#define DEFAULT_RSSI_OFFSET 121
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h
index 341a704..b493306 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.h
+++ b/drivers/net/wireless/rt2x00/rt2500usb.h
@@ -46,7 +46,7 @@
/*
* Signal information.
- * Defaul offset is required for RSSI <-> dBm conversion.
+ * Default offset is required for RSSI <-> dBm conversion.
*/
#define DEFAULT_RSSI_OFFSET 120
diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h
index 6f33f7f..8f13810 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.h
+++ b/drivers/net/wireless/rt2x00/rt61pci.h
@@ -37,7 +37,7 @@
/*
* Signal information.
- * Defaul offset is required for RSSI <-> dBm conversion.
+ * Default offset is required for RSSI <-> dBm conversion.
*/
#define DEFAULT_RSSI_OFFSET 120
diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h
index e783a09..7942f81 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.h
+++ b/drivers/net/wireless/rt2x00/rt73usb.h
@@ -37,7 +37,7 @@
/*
* Signal information.
- * Defaul offset is required for RSSI <-> dBm conversion.
+ * Default offset is required for RSSI <-> dBm conversion.
*/
#define DEFAULT_RSSI_OFFSET 120
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 8a24373..cf51e8f 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -374,7 +374,7 @@ static void zd_mac_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
* zd_mac_tx_failed - callback for failed frames
* @dev: the mac80211 wireless device
*
- * This function is called if a frame couldn't be succesfully be
+ * This function is called if a frame couldn't be successfully be
* transferred. The first frame from the tx queue, will be selected and
* reported as error to the upper layers.
*/
diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c
index a6b4a5a..f511e70 100644
--- a/drivers/parisc/ccio-dma.c
+++ b/drivers/parisc/ccio-dma.c
@@ -650,7 +650,7 @@ ccio_clear_io_tlb(struct ioc *ioc, dma_addr_t iovp, size_t byte_cnt)
* Mark the I/O Pdir entries invalid and blow away the corresponding I/O
* TLB entries.
*
- * FIXME: at some threshhold it might be "cheaper" to just blow
+ * FIXME: at some threshold it might be "cheaper" to just blow
* away the entire I/O TLB instead of individual entries.
*
* FIXME: Uturn has 256 TLB entries. We don't need to purge every
diff --git a/drivers/parisc/eisa_eeprom.c b/drivers/parisc/eisa_eeprom.c
index 8c0b26e9..cce00ed 100644
--- a/drivers/parisc/eisa_eeprom.c
+++ b/drivers/parisc/eisa_eeprom.c
@@ -75,17 +75,8 @@ static ssize_t eisa_eeprom_read(struct file * file,
return ret;
}
-static int eisa_eeprom_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd,
- unsigned long arg)
-{
- return -ENOTTY;
-}
-
static int eisa_eeprom_open(struct inode *inode, struct file *file)
{
- cycle_kernel_lock();
-
if (file->f_mode & FMODE_WRITE)
return -EINVAL;
@@ -104,7 +95,6 @@ static const struct file_operations eisa_eeprom_fops = {
.owner = THIS_MODULE,
.llseek = eisa_eeprom_llseek,
.read = eisa_eeprom_read,
- .ioctl = eisa_eeprom_ioctl,
.open = eisa_eeprom_open,
.release = eisa_eeprom_release,
};
diff --git a/drivers/pci/intr_remapping.c b/drivers/pci/intr_remapping.c
index 0ed78a7..3b36586 100644
--- a/drivers/pci/intr_remapping.c
+++ b/drivers/pci/intr_remapping.c
@@ -2,6 +2,7 @@
#include <linux/dmar.h>
#include <linux/spinlock.h>
#include <linux/jiffies.h>
+#include <linux/hpet.h>
#include <linux/pci.h>
#include <linux/irq.h>
#include <asm/io_apic.h>
@@ -14,7 +15,8 @@
#include "pci.h"
static struct ioapic_scope ir_ioapic[MAX_IO_APICS];
-static int ir_ioapic_num;
+static struct hpet_scope ir_hpet[MAX_HPET_TBS];
+static int ir_ioapic_num, ir_hpet_num;
int intr_remapping_enabled;
static int disable_intremap;
@@ -343,6 +345,16 @@ int flush_irte(int irq)
return rc;
}
+struct intel_iommu *map_hpet_to_ir(u8 hpet_id)
+{
+ int i;
+
+ for (i = 0; i < MAX_HPET_TBS; i++)
+ if (ir_hpet[i].id == hpet_id)
+ return ir_hpet[i].iommu;
+ return NULL;
+}
+
struct intel_iommu *map_ioapic_to_ir(int apic)
{
int i;
@@ -470,6 +482,36 @@ int set_ioapic_sid(struct irte *irte, int apic)
return 0;
}
+int set_hpet_sid(struct irte *irte, u8 id)
+{
+ int i;
+ u16 sid = 0;
+
+ if (!irte)
+ return -1;
+
+ for (i = 0; i < MAX_HPET_TBS; i++) {
+ if (ir_hpet[i].id == id) {
+ sid = (ir_hpet[i].bus << 8) | ir_hpet[i].devfn;
+ break;
+ }
+ }
+
+ if (sid == 0) {
+ pr_warning("Failed to set source-id of HPET block (%d)\n", id);
+ return -1;
+ }
+
+ /*
+ * Should really use SQ_ALL_16. Some platforms are broken.
+ * While we figure out the right quirks for these broken platforms, use
+ * SQ_13_IGNORE_3 for now.
+ */
+ set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_13_IGNORE_3, sid);
+
+ return 0;
+}
+
int set_msi_sid(struct irte *irte, struct pci_dev *dev)
{
struct pci_dev *bridge;
@@ -711,6 +753,34 @@ error:
return -1;
}
+static void ir_parse_one_hpet_scope(struct acpi_dmar_device_scope *scope,
+ struct intel_iommu *iommu)
+{
+ struct acpi_dmar_pci_path *path;
+ u8 bus;
+ int count;
+
+ bus = scope->bus;
+ path = (struct acpi_dmar_pci_path *)(scope + 1);
+ count = (scope->length - sizeof(struct acpi_dmar_device_scope))
+ / sizeof(struct acpi_dmar_pci_path);
+
+ while (--count > 0) {
+ /*
+ * Access PCI directly due to the PCI
+ * subsystem isn't initialized yet.
+ */
+ bus = read_pci_config_byte(bus, path->dev, path->fn,
+ PCI_SECONDARY_BUS);
+ path++;
+ }
+ ir_hpet[ir_hpet_num].bus = bus;
+ ir_hpet[ir_hpet_num].devfn = PCI_DEVFN(path->dev, path->fn);
+ ir_hpet[ir_hpet_num].iommu = iommu;
+ ir_hpet[ir_hpet_num].id = scope->enumeration_id;
+ ir_hpet_num++;
+}
+
static void ir_parse_one_ioapic_scope(struct acpi_dmar_device_scope *scope,
struct intel_iommu *iommu)
{
@@ -740,8 +810,8 @@ static void ir_parse_one_ioapic_scope(struct acpi_dmar_device_scope *scope,
ir_ioapic_num++;
}
-static int ir_parse_ioapic_scope(struct acpi_dmar_header *header,
- struct intel_iommu *iommu)
+static int ir_parse_ioapic_hpet_scope(struct acpi_dmar_header *header,
+ struct intel_iommu *iommu)
{
struct acpi_dmar_hardware_unit *drhd;
struct acpi_dmar_device_scope *scope;
@@ -765,6 +835,17 @@ static int ir_parse_ioapic_scope(struct acpi_dmar_header *header,
drhd->address);
ir_parse_one_ioapic_scope(scope, iommu);
+ } else if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_HPET) {
+ if (ir_hpet_num == MAX_HPET_TBS) {
+ printk(KERN_WARNING "Exceeded Max HPET blocks\n");
+ return -1;
+ }
+
+ printk(KERN_INFO "HPET id %d under DRHD base"
+ " 0x%Lx\n", scope->enumeration_id,
+ drhd->address);
+
+ ir_parse_one_hpet_scope(scope, iommu);
}
start += scope->length;
}
@@ -785,7 +866,7 @@ int __init parse_ioapics_under_ir(void)
struct intel_iommu *iommu = drhd->iommu;
if (ecap_ir_support(iommu->ecap)) {
- if (ir_parse_ioapic_scope(drhd->hdr, iommu))
+ if (ir_parse_ioapic_hpet_scope(drhd->hdr, iommu))
return -1;
ir_supported = 1;
diff --git a/drivers/pci/intr_remapping.h b/drivers/pci/intr_remapping.h
index 63a263c..5662fec 100644
--- a/drivers/pci/intr_remapping.h
+++ b/drivers/pci/intr_remapping.h
@@ -7,4 +7,11 @@ struct ioapic_scope {
unsigned int devfn; /* PCI devfn number */
};
+struct hpet_scope {
+ struct intel_iommu *iommu;
+ u8 id;
+ unsigned int bus;
+ unsigned int devfn;
+};
+
#define IR_X2APIC_MODE(mode) (mode ? (1 << 11) : 0)
diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig
index 9652c3f..8390dca 100644
--- a/drivers/platform/Kconfig
+++ b/drivers/platform/Kconfig
@@ -1,5 +1,3 @@
-# drivers/platform/Kconfig
-
if X86
source "drivers/platform/x86/Kconfig"
endif
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index a848c7e..edb1690 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -6545,7 +6545,7 @@ static struct ibm_struct volume_driver_data = {
* The speeds are stored on handles
* (FANA:FAN9), (FANC:FANB), (FANE:FAND).
*
- * There are three default speed sets, acessible as handles:
+ * There are three default speed sets, accessible as handles:
* FS1L,FS1M,FS1H; FS2L,FS2M,FS2H; FS3L,FS3M,FS3H
*
* ACPI DSDT switches which set is in use depending on various
diff --git a/drivers/pnp/pnpbios/rsparser.c b/drivers/pnp/pnpbios/rsparser.c
index 87b4f49..a5135eb 100644
--- a/drivers/pnp/pnpbios/rsparser.c
+++ b/drivers/pnp/pnpbios/rsparser.c
@@ -191,7 +191,7 @@ static unsigned char *pnpbios_parse_allocated_resource_data(struct pnp_dev *dev,
return (unsigned char *)p;
break;
- default: /* an unkown tag */
+ default: /* an unknown tag */
len_err:
dev_err(&dev->dev, "unknown tag %#x length %d\n",
tag, len);
@@ -405,7 +405,7 @@ pnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end,
case SMALL_TAG_END:
return p + 2;
- default: /* an unkown tag */
+ default: /* an unknown tag */
len_err:
dev_err(&dev->dev, "unknown tag %#x length %d\n",
tag, len);
@@ -475,7 +475,7 @@ static unsigned char *pnpbios_parse_compatible_ids(unsigned char *p,
return (unsigned char *)p;
break;
- default: /* an unkown tag */
+ default: /* an unknown tag */
len_err:
dev_err(&dev->dev, "unknown tag %#x length %d\n",
tag, len);
@@ -744,7 +744,7 @@ static unsigned char *pnpbios_encode_allocated_resource_data(struct pnp_dev
return (unsigned char *)p;
break;
- default: /* an unkown tag */
+ default: /* an unknown tag */
len_err:
dev_err(&dev->dev, "unknown tag %#x length %d\n",
tag, len);
diff --git a/drivers/ps3/ps3-sys-manager.c b/drivers/ps3/ps3-sys-manager.c
index 88cb740..3cbaf18 100644
--- a/drivers/ps3/ps3-sys-manager.c
+++ b/drivers/ps3/ps3-sys-manager.c
@@ -46,7 +46,7 @@
/**
* struct ps3_sys_manager_header - System manager message header.
* @version: Header version, currently 1.
- * @size: Header size in bytes, curently 16.
+ * @size: Header size in bytes, currently 16.
* @payload_size: Message payload size in bytes.
* @service_id: Message type, one of enum ps3_sys_manager_service_id.
* @request_tag: Unique number to identify reply.
diff --git a/drivers/rtc/rtc-ds1302.c b/drivers/rtc/rtc-ds1302.c
index d490628..1e73c8f 100644
--- a/drivers/rtc/rtc-ds1302.c
+++ b/drivers/rtc/rtc-ds1302.c
@@ -201,7 +201,7 @@ static struct platform_driver ds1302_platform_driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
},
- .remove = __exit_p(ds1302_rtc_remove),
+ .remove = __devexit_p(ds1302_rtc_remove),
};
static int __init ds1302_rtc_init(void)
diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c
index 0b6b773..539676e 100644
--- a/drivers/rtc/rtc-ds1511.c
+++ b/drivers/rtc/rtc-ds1511.c
@@ -2,7 +2,7 @@
* An rtc driver for the Dallas DS1511
*
* Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
- * Copyright (C) 2007 Andrew Sharp <andy.sharp@onstor.com>
+ * Copyright (C) 2007 Andrew Sharp <andy.sharp@lsi.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
@@ -636,7 +636,7 @@ ds1511_rtc_exit(void)
module_init(ds1511_rtc_init);
module_exit(ds1511_rtc_exit);
-MODULE_AUTHOR("Andrew Sharp <andy.sharp@onstor.com>");
+MODULE_AUTHOR("Andrew Sharp <andy.sharp@lsi.com>");
MODULE_DESCRIPTION("Dallas DS1511 RTC driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/rtc/rtc-stk17ta8.c b/drivers/rtc/rtc-stk17ta8.c
index 7d1547b..d491eb2 100644
--- a/drivers/rtc/rtc-stk17ta8.c
+++ b/drivers/rtc/rtc-stk17ta8.c
@@ -286,7 +286,7 @@ static struct bin_attribute stk17ta8_nvram_attr = {
.write = stk17ta8_nvram_write,
};
-static int __init stk17ta8_rtc_probe(struct platform_device *pdev)
+static int __devinit stk17ta8_rtc_probe(struct platform_device *pdev)
{
struct rtc_device *rtc;
struct resource *res;
diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c
index 423cd5a..ad741af 100644
--- a/drivers/rtc/rtc-v3020.c
+++ b/drivers/rtc/rtc-v3020.c
@@ -335,7 +335,7 @@ static int rtc_probe(struct platform_device *pdev)
goto err_io;
}
- /* Make sure frequency measurment mode, test modes, and lock
+ /* Make sure frequency measurement mode, test modes, and lock
* are all disabled */
v3020_set_reg(chip, V3020_STATUS_0, 0x0);
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index aaccc8e..fdb2e7c 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -24,7 +24,6 @@
#include <asm/ccwdev.h>
#include <asm/ebcdic.h>
#include <asm/idals.h>
-#include <asm/todclk.h>
#include <asm/itcw.h>
/* This is ugly... */
@@ -64,6 +63,7 @@ static void do_restore_device(struct work_struct *);
static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *);
static void dasd_device_timeout(unsigned long);
static void dasd_block_timeout(unsigned long);
+static void __dasd_process_erp(struct dasd_device *, struct dasd_ccw_req *);
/*
* SECTION: Operations on the device structure.
@@ -960,7 +960,7 @@ static void dasd_device_timeout(unsigned long ptr)
device = (struct dasd_device *) ptr;
spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
/* re-activate request queue */
- device->stopped &= ~DASD_STOPPED_PENDING;
+ dasd_device_remove_stop_bits(device, DASD_STOPPED_PENDING);
spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
dasd_schedule_device_bh(device);
}
@@ -994,10 +994,9 @@ static void dasd_handle_killed_request(struct ccw_device *cdev,
return;
cqr = (struct dasd_ccw_req *) intparm;
if (cqr->status != DASD_CQR_IN_IO) {
- DBF_EVENT(DBF_DEBUG,
- "invalid status in handle_killed_request: "
- "bus_id %s, status %02x",
- dev_name(&cdev->dev), cqr->status);
+ DBF_EVENT_DEVID(DBF_DEBUG, cdev,
+ "invalid status in handle_killed_request: "
+ "%02x", cqr->status);
return;
}
@@ -1023,7 +1022,7 @@ void dasd_generic_handle_state_change(struct dasd_device *device)
/* First of all start sense subsystem status request. */
dasd_eer_snss(device);
- device->stopped &= ~DASD_STOPPED_PENDING;
+ dasd_device_remove_stop_bits(device, DASD_STOPPED_PENDING);
dasd_schedule_device_bh(device);
if (device->block)
dasd_schedule_block_bh(device->block);
@@ -1045,12 +1044,13 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
case -EIO:
break;
case -ETIMEDOUT:
- DBF_EVENT(DBF_WARNING, "%s(%s): request timed out\n",
- __func__, dev_name(&cdev->dev));
+ DBF_EVENT_DEVID(DBF_WARNING, cdev, "%s: "
+ "request timed out\n", __func__);
break;
default:
- DBF_EVENT(DBF_WARNING, "%s(%s): unknown error %ld\n",
- __func__, dev_name(&cdev->dev), PTR_ERR(irb));
+ DBF_EVENT_DEVID(DBF_WARNING, cdev, "%s: "
+ "unknown error %ld\n", __func__,
+ PTR_ERR(irb));
}
dasd_handle_killed_request(cdev, intparm);
return;
@@ -1405,6 +1405,20 @@ void dasd_schedule_device_bh(struct dasd_device *device)
tasklet_hi_schedule(&device->tasklet);
}
+void dasd_device_set_stop_bits(struct dasd_device *device, int bits)
+{
+ device->stopped |= bits;
+}
+EXPORT_SYMBOL_GPL(dasd_device_set_stop_bits);
+
+void dasd_device_remove_stop_bits(struct dasd_device *device, int bits)
+{
+ device->stopped &= ~bits;
+ if (!device->stopped)
+ wake_up(&generic_waitq);
+}
+EXPORT_SYMBOL_GPL(dasd_device_remove_stop_bits);
+
/*
* Queue a request to the head of the device ccw_queue.
* Start the I/O if possible.
@@ -1465,58 +1479,135 @@ static inline int _wait_for_wakeup(struct dasd_ccw_req *cqr)
}
/*
- * Queue a request to the tail of the device ccw_queue and wait for
- * it's completion.
+ * checks if error recovery is necessary, returns 1 if yes, 0 otherwise.
*/
-int dasd_sleep_on(struct dasd_ccw_req *cqr)
+static int __dasd_sleep_on_erp(struct dasd_ccw_req *cqr)
{
struct dasd_device *device;
- int rc;
+ dasd_erp_fn_t erp_fn;
+ if (cqr->status == DASD_CQR_FILLED)
+ return 0;
device = cqr->startdev;
+ if (test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags)) {
+ if (cqr->status == DASD_CQR_TERMINATED) {
+ device->discipline->handle_terminated_request(cqr);
+ return 1;
+ }
+ if (cqr->status == DASD_CQR_NEED_ERP) {
+ erp_fn = device->discipline->erp_action(cqr);
+ erp_fn(cqr);
+ return 1;
+ }
+ if (cqr->status == DASD_CQR_FAILED)
+ dasd_log_sense(cqr, &cqr->irb);
+ if (cqr->refers) {
+ __dasd_process_erp(device, cqr);
+ return 1;
+ }
+ }
+ return 0;
+}
- cqr->callback = dasd_wakeup_cb;
- cqr->callback_data = (void *) &generic_waitq;
- dasd_add_request_tail(cqr);
- wait_event(generic_waitq, _wait_for_wakeup(cqr));
+static int __dasd_sleep_on_loop_condition(struct dasd_ccw_req *cqr)
+{
+ if (test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags)) {
+ if (cqr->refers) /* erp is not done yet */
+ return 1;
+ return ((cqr->status != DASD_CQR_DONE) &&
+ (cqr->status != DASD_CQR_FAILED));
+ } else
+ return (cqr->status == DASD_CQR_FILLED);
+}
- if (cqr->status == DASD_CQR_DONE)
+static int _dasd_sleep_on(struct dasd_ccw_req *maincqr, int interruptible)
+{
+ struct dasd_device *device;
+ int rc;
+ struct list_head ccw_queue;
+ struct dasd_ccw_req *cqr;
+
+ INIT_LIST_HEAD(&ccw_queue);
+ maincqr->status = DASD_CQR_FILLED;
+ device = maincqr->startdev;
+ list_add(&maincqr->blocklist, &ccw_queue);
+ for (cqr = maincqr; __dasd_sleep_on_loop_condition(cqr);
+ cqr = list_first_entry(&ccw_queue,
+ struct dasd_ccw_req, blocklist)) {
+
+ if (__dasd_sleep_on_erp(cqr))
+ continue;
+ if (cqr->status != DASD_CQR_FILLED) /* could be failed */
+ continue;
+
+ /* Non-temporary stop condition will trigger fail fast */
+ if (device->stopped & ~DASD_STOPPED_PENDING &&
+ test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&
+ (!dasd_eer_enabled(device))) {
+ cqr->status = DASD_CQR_FAILED;
+ continue;
+ }
+
+ /* Don't try to start requests if device is stopped */
+ if (interruptible) {
+ rc = wait_event_interruptible(
+ generic_waitq, !(device->stopped));
+ if (rc == -ERESTARTSYS) {
+ cqr->status = DASD_CQR_FAILED;
+ maincqr->intrc = rc;
+ continue;
+ }
+ } else
+ wait_event(generic_waitq, !(device->stopped));
+
+ cqr->callback = dasd_wakeup_cb;
+ cqr->callback_data = (void *) &generic_waitq;
+ dasd_add_request_tail(cqr);
+ if (interruptible) {
+ rc = wait_event_interruptible(
+ generic_waitq, _wait_for_wakeup(cqr));
+ if (rc == -ERESTARTSYS) {
+ dasd_cancel_req(cqr);
+ /* wait (non-interruptible) for final status */
+ wait_event(generic_waitq,
+ _wait_for_wakeup(cqr));
+ cqr->status = DASD_CQR_FAILED;
+ maincqr->intrc = rc;
+ continue;
+ }
+ } else
+ wait_event(generic_waitq, _wait_for_wakeup(cqr));
+ }
+
+ maincqr->endclk = get_clock();
+ if ((maincqr->status != DASD_CQR_DONE) &&
+ (maincqr->intrc != -ERESTARTSYS))
+ dasd_log_sense(maincqr, &maincqr->irb);
+ if (maincqr->status == DASD_CQR_DONE)
rc = 0;
- else if (cqr->intrc)
- rc = cqr->intrc;
+ else if (maincqr->intrc)
+ rc = maincqr->intrc;
else
rc = -EIO;
return rc;
}
/*
+ * Queue a request to the tail of the device ccw_queue and wait for
+ * it's completion.
+ */
+int dasd_sleep_on(struct dasd_ccw_req *cqr)
+{
+ return _dasd_sleep_on(cqr, 0);
+}
+
+/*
* Queue a request to the tail of the device ccw_queue and wait
* interruptible for it's completion.
*/
int dasd_sleep_on_interruptible(struct dasd_ccw_req *cqr)
{
- struct dasd_device *device;
- int rc;
-
- device = cqr->startdev;
- cqr->callback = dasd_wakeup_cb;
- cqr->callback_data = (void *) &generic_waitq;
- dasd_add_request_tail(cqr);
- rc = wait_event_interruptible(generic_waitq, _wait_for_wakeup(cqr));
- if (rc == -ERESTARTSYS) {
- dasd_cancel_req(cqr);
- /* wait (non-interruptible) for final status */
- wait_event(generic_waitq, _wait_for_wakeup(cqr));
- cqr->intrc = rc;
- }
-
- if (cqr->status == DASD_CQR_DONE)
- rc = 0;
- else if (cqr->intrc)
- rc = cqr->intrc;
- else
- rc = -EIO;
- return rc;
+ return _dasd_sleep_on(cqr, 1);
}
/*
@@ -1630,7 +1721,7 @@ static void dasd_block_timeout(unsigned long ptr)
block = (struct dasd_block *) ptr;
spin_lock_irqsave(get_ccwdev_lock(block->base->cdev), flags);
/* re-activate request queue */
- block->base->stopped &= ~DASD_STOPPED_PENDING;
+ dasd_device_remove_stop_bits(block->base, DASD_STOPPED_PENDING);
spin_unlock_irqrestore(get_ccwdev_lock(block->base->cdev), flags);
dasd_schedule_block_bh(block);
}
@@ -1657,11 +1748,10 @@ void dasd_block_clear_timer(struct dasd_block *block)
/*
* Process finished error recovery ccw.
*/
-static inline void __dasd_block_process_erp(struct dasd_block *block,
- struct dasd_ccw_req *cqr)
+static void __dasd_process_erp(struct dasd_device *device,
+ struct dasd_ccw_req *cqr)
{
dasd_erp_fn_t erp_fn;
- struct dasd_device *device = block->base;
if (cqr->status == DASD_CQR_DONE)
DBF_DEV_EVENT(DBF_NOTICE, device, "%s", "ERP successful");
@@ -1725,9 +1815,12 @@ static void __dasd_process_request_queue(struct dasd_block *block)
*/
if (!list_empty(&block->ccw_queue))
break;
- spin_lock_irqsave(get_ccwdev_lock(basedev->cdev), flags);
- basedev->stopped |= DASD_STOPPED_PENDING;
- spin_unlock_irqrestore(get_ccwdev_lock(basedev->cdev), flags);
+ spin_lock_irqsave(
+ get_ccwdev_lock(basedev->cdev), flags);
+ dasd_device_set_stop_bits(basedev,
+ DASD_STOPPED_PENDING);
+ spin_unlock_irqrestore(
+ get_ccwdev_lock(basedev->cdev), flags);
dasd_block_set_timer(block, HZ/2);
break;
}
@@ -1813,7 +1906,7 @@ restart:
cqr->status = DASD_CQR_FILLED;
cqr->retries = 255;
spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
- base->stopped |= DASD_STOPPED_QUIESCE;
+ dasd_device_set_stop_bits(base, DASD_STOPPED_QUIESCE);
spin_unlock_irqrestore(get_ccwdev_lock(base->cdev),
flags);
goto restart;
@@ -1821,7 +1914,7 @@ restart:
/* Process finished ERP request. */
if (cqr->refers) {
- __dasd_block_process_erp(block, cqr);
+ __dasd_process_erp(base, cqr);
goto restart;
}
@@ -1952,7 +2045,7 @@ restart_cb:
/* Process finished ERP request. */
if (cqr->refers) {
spin_lock_bh(&block->queue_lock);
- __dasd_block_process_erp(block, cqr);
+ __dasd_process_erp(block->base, cqr);
spin_unlock_bh(&block->queue_lock);
/* restart list_for_xx loop since dasd_process_erp
* might remove multiple elements */
@@ -2208,18 +2301,11 @@ int dasd_generic_probe(struct ccw_device *cdev,
{
int ret;
- ret = ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP);
- if (ret) {
- DBF_EVENT(DBF_WARNING,
- "dasd_generic_probe: could not set ccw-device options "
- "for %s\n", dev_name(&cdev->dev));
- return ret;
- }
ret = dasd_add_sysfs_files(cdev);
if (ret) {
- DBF_EVENT(DBF_WARNING,
- "dasd_generic_probe: could not add sysfs entries "
- "for %s\n", dev_name(&cdev->dev));
+ DBF_EVENT_DEVID(DBF_WARNING, cdev, "%s",
+ "dasd_generic_probe: could not add "
+ "sysfs entries");
return ret;
}
cdev->handler = &dasd_int_handler;
@@ -2418,16 +2504,16 @@ int dasd_generic_notify(struct ccw_device *cdev, int event)
cqr->status = DASD_CQR_QUEUED;
cqr->retries++;
}
- device->stopped |= DASD_STOPPED_DC_WAIT;
+ dasd_device_set_stop_bits(device, DASD_STOPPED_DC_WAIT);
dasd_device_clear_timer(device);
dasd_schedule_device_bh(device);
ret = 1;
break;
case CIO_OPER:
/* FIXME: add a sanity check. */
- device->stopped &= ~DASD_STOPPED_DC_WAIT;
+ dasd_device_remove_stop_bits(device, DASD_STOPPED_DC_WAIT);
if (device->stopped & DASD_UNRESUMED_PM) {
- device->stopped &= ~DASD_UNRESUMED_PM;
+ dasd_device_remove_stop_bits(device, DASD_UNRESUMED_PM);
dasd_restore_device(device);
ret = 1;
break;
@@ -2452,7 +2538,7 @@ int dasd_generic_pm_freeze(struct ccw_device *cdev)
if (IS_ERR(device))
return PTR_ERR(device);
/* disallow new I/O */
- device->stopped |= DASD_STOPPED_PM;
+ dasd_device_set_stop_bits(device, DASD_STOPPED_PM);
/* clear active requests */
INIT_LIST_HEAD(&freeze_queue);
spin_lock_irq(get_ccwdev_lock(cdev));
@@ -2504,14 +2590,18 @@ int dasd_generic_restore_device(struct ccw_device *cdev)
return PTR_ERR(device);
/* allow new IO again */
- device->stopped &= ~DASD_STOPPED_PM;
- device->stopped &= ~DASD_UNRESUMED_PM;
+ dasd_device_remove_stop_bits(device,
+ (DASD_STOPPED_PM | DASD_UNRESUMED_PM));
dasd_schedule_device_bh(device);
- if (device->discipline->restore)
+ /*
+ * call discipline restore function
+ * if device is stopped do nothing e.g. for disconnected devices
+ */
+ if (device->discipline->restore && !(device->stopped))
rc = device->discipline->restore(device);
- if (rc)
+ if (rc || device->stopped)
/*
* if the resume failed for the DASD we put it in
* an UNRESUMED stop state
@@ -2561,8 +2651,7 @@ static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device,
cqr->startdev = device;
cqr->memdev = device;
cqr->expires = 10*HZ;
- clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
- cqr->retries = 2;
+ cqr->retries = 256;
cqr->buildclk = get_clock();
cqr->status = DASD_CQR_FILLED;
return cqr;
diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c
index e8ff7b0..44796ba 100644
--- a/drivers/s390/block/dasd_3990_erp.c
+++ b/drivers/s390/block/dasd_3990_erp.c
@@ -12,7 +12,6 @@
#include <linux/timer.h>
#include <linux/slab.h>
#include <asm/idals.h>
-#include <asm/todclk.h>
#define PRINTK_HEADER "dasd_erp(3990): "
@@ -70,8 +69,7 @@ dasd_3990_erp_cleanup(struct dasd_ccw_req * erp, char final_status)
* processing until the started timer has expired or an related
* interrupt was received.
*/
-static void
-dasd_3990_erp_block_queue(struct dasd_ccw_req * erp, int expires)
+static void dasd_3990_erp_block_queue(struct dasd_ccw_req *erp, int expires)
{
struct dasd_device *device = erp->startdev;
@@ -81,10 +79,13 @@ dasd_3990_erp_block_queue(struct dasd_ccw_req * erp, int expires)
"blocking request queue for %is", expires/HZ);
spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
- device->stopped |= DASD_STOPPED_PENDING;
+ dasd_device_set_stop_bits(device, DASD_STOPPED_PENDING);
spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
erp->status = DASD_CQR_FILLED;
- dasd_block_set_timer(device->block, expires);
+ if (erp->block)
+ dasd_block_set_timer(erp->block, expires);
+ else
+ dasd_device_set_timer(device, expires);
}
/*
@@ -243,9 +244,13 @@ dasd_3990_erp_DCTL(struct dasd_ccw_req * erp, char modifier)
* DESCRIPTION
* Setup ERP to do the ERP action 1 (see Reference manual).
* Repeat the operation on a different channel path.
- * If all alternate paths have been tried, the request is posted with a
- * permanent error.
- * Note: duplex handling is not implemented (yet).
+ * As deviation from the recommended recovery action, we reset the path mask
+ * after we have tried each path and go through all paths a second time.
+ * This will cover situations where only one path at a time is actually down,
+ * but all paths fail and recover just with the same sequence and timing as
+ * we try to use them (flapping links).
+ * If all alternate paths have been tried twice, the request is posted with
+ * a permanent error.
*
* PARAMETER
* erp pointer to the current ERP
@@ -254,17 +259,25 @@ dasd_3990_erp_DCTL(struct dasd_ccw_req * erp, char modifier)
* erp pointer to the ERP
*
*/
-static struct dasd_ccw_req *
-dasd_3990_erp_action_1(struct dasd_ccw_req * erp)
+static struct dasd_ccw_req *dasd_3990_erp_action_1_sec(struct dasd_ccw_req *erp)
{
+ erp->function = dasd_3990_erp_action_1_sec;
+ dasd_3990_erp_alternate_path(erp);
+ return erp;
+}
+static struct dasd_ccw_req *dasd_3990_erp_action_1(struct dasd_ccw_req *erp)
+{
erp->function = dasd_3990_erp_action_1;
-
dasd_3990_erp_alternate_path(erp);
-
+ if (erp->status == DASD_CQR_FAILED) {
+ erp->status = DASD_CQR_FILLED;
+ erp->retries = 10;
+ erp->lpm = LPM_ANYPATH;
+ erp->function = dasd_3990_erp_action_1_sec;
+ }
return erp;
-
-} /* end dasd_3990_erp_action_1 */
+} /* end dasd_3990_erp_action_1(b) */
/*
* DASD_3990_ERP_ACTION_4
@@ -2295,6 +2308,7 @@ static struct dasd_ccw_req *dasd_3990_erp_add_erp(struct dasd_ccw_req *cqr)
return cqr;
}
+ ccw = cqr->cpaddr;
if (cqr->cpmode == 1) {
/* make a shallow copy of the original tcw but set new tsb */
erp->cpmode = 1;
@@ -2303,6 +2317,9 @@ static struct dasd_ccw_req *dasd_3990_erp_add_erp(struct dasd_ccw_req *cqr)
tsb = (struct tsb *) &tcw[1];
*tcw = *((struct tcw *)cqr->cpaddr);
tcw->tsb = (long)tsb;
+ } else if (ccw->cmd_code == DASD_ECKD_CCW_PSF) {
+ /* PSF cannot be chained from NOOP/TIC */
+ erp->cpaddr = cqr->cpaddr;
} else {
/* initialize request with default TIC to current ERP/CQR */
ccw = erp->cpaddr;
@@ -2487,6 +2504,8 @@ dasd_3990_erp_further_erp(struct dasd_ccw_req *erp)
erp = dasd_3990_erp_action_1(erp);
+ } else if (erp->function == dasd_3990_erp_action_1_sec) {
+ erp = dasd_3990_erp_action_1_sec(erp);
} else if (erp->function == dasd_3990_erp_action_5) {
/* retries have not been successful */
diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c
index 70a008c..fd12317 100644
--- a/drivers/s390/block/dasd_alias.c
+++ b/drivers/s390/block/dasd_alias.c
@@ -152,6 +152,7 @@ static struct alias_lcu *_allocate_lcu(struct dasd_uid *uid)
INIT_WORK(&lcu->suc_data.worker, summary_unit_check_handling_work);
INIT_DELAYED_WORK(&lcu->ruac_data.dwork, lcu_update_work);
spin_lock_init(&lcu->lock);
+ init_completion(&lcu->lcu_setup);
return lcu;
out_err4:
@@ -240,6 +241,67 @@ int dasd_alias_make_device_known_to_lcu(struct dasd_device *device)
}
/*
+ * The first device to be registered on an LCU will have to do
+ * some additional setup steps to configure that LCU on the
+ * storage server. All further devices should wait with their
+ * initialization until the first device is done.
+ * To synchronize this work, the first device will call
+ * dasd_alias_lcu_setup_complete when it is done, and all
+ * other devices will wait for it with dasd_alias_wait_for_lcu_setup.
+ */
+void dasd_alias_lcu_setup_complete(struct dasd_device *device)
+{
+ struct dasd_eckd_private *private;
+ unsigned long flags;
+ struct alias_server *server;
+ struct alias_lcu *lcu;
+ struct dasd_uid *uid;
+
+ private = (struct dasd_eckd_private *) device->private;
+ uid = &private->uid;
+ lcu = NULL;
+ spin_lock_irqsave(&aliastree.lock, flags);
+ server = _find_server(uid);
+ if (server)
+ lcu = _find_lcu(server, uid);
+ spin_unlock_irqrestore(&aliastree.lock, flags);
+ if (!lcu) {
+ DBF_EVENT_DEVID(DBF_ERR, device->cdev,
+ "could not find lcu for %04x %02x",
+ uid->ssid, uid->real_unit_addr);
+ WARN_ON(1);
+ return;
+ }
+ complete_all(&lcu->lcu_setup);
+}
+
+void dasd_alias_wait_for_lcu_setup(struct dasd_device *device)
+{
+ struct dasd_eckd_private *private;
+ unsigned long flags;
+ struct alias_server *server;
+ struct alias_lcu *lcu;
+ struct dasd_uid *uid;
+
+ private = (struct dasd_eckd_private *) device->private;
+ uid = &private->uid;
+ lcu = NULL;
+ spin_lock_irqsave(&aliastree.lock, flags);
+ server = _find_server(uid);
+ if (server)
+ lcu = _find_lcu(server, uid);
+ spin_unlock_irqrestore(&aliastree.lock, flags);
+ if (!lcu) {
+ DBF_EVENT_DEVID(DBF_ERR, device->cdev,
+ "could not find lcu for %04x %02x",
+ uid->ssid, uid->real_unit_addr);
+ WARN_ON(1);
+ return;
+ }
+ wait_for_completion(&lcu->lcu_setup);
+}
+
+/*
* This function removes a device from the scope of alias management.
* The complicated part is to make sure that it is not in use by
* any of the workers. If necessary cancel the work.
@@ -755,11 +817,11 @@ static void __stop_device_on_lcu(struct dasd_device *device,
{
/* If pos == device then device is already locked! */
if (pos == device) {
- pos->stopped |= DASD_STOPPED_SU;
+ dasd_device_set_stop_bits(pos, DASD_STOPPED_SU);
return;
}
spin_lock(get_ccwdev_lock(pos->cdev));
- pos->stopped |= DASD_STOPPED_SU;
+ dasd_device_set_stop_bits(pos, DASD_STOPPED_SU);
spin_unlock(get_ccwdev_lock(pos->cdev));
}
@@ -793,26 +855,26 @@ static void _unstop_all_devices_on_lcu(struct alias_lcu *lcu)
list_for_each_entry(device, &lcu->active_devices, alias_list) {
spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
- device->stopped &= ~DASD_STOPPED_SU;
+ dasd_device_remove_stop_bits(device, DASD_STOPPED_SU);
spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
}
list_for_each_entry(device, &lcu->inactive_devices, alias_list) {
spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
- device->stopped &= ~DASD_STOPPED_SU;
+ dasd_device_remove_stop_bits(device, DASD_STOPPED_SU);
spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
}
list_for_each_entry(pavgroup, &lcu->grouplist, group) {
list_for_each_entry(device, &pavgroup->baselist, alias_list) {
spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
- device->stopped &= ~DASD_STOPPED_SU;
+ dasd_device_remove_stop_bits(device, DASD_STOPPED_SU);
spin_unlock_irqrestore(get_ccwdev_lock(device->cdev),
flags);
}
list_for_each_entry(device, &pavgroup->aliaslist, alias_list) {
spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
- device->stopped &= ~DASD_STOPPED_SU;
+ dasd_device_remove_stop_bits(device, DASD_STOPPED_SU);
spin_unlock_irqrestore(get_ccwdev_lock(device->cdev),
flags);
}
@@ -836,7 +898,8 @@ static void summary_unit_check_handling_work(struct work_struct *work)
/* 2. reset summary unit check */
spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
- device->stopped &= ~(DASD_STOPPED_SU | DASD_STOPPED_PENDING);
+ dasd_device_remove_stop_bits(device,
+ (DASD_STOPPED_SU | DASD_STOPPED_PENDING));
spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
reset_summary_unit_check(lcu, device, suc_data->reason);
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
index 4e49b4a..f64d0db 100644
--- a/drivers/s390/block/dasd_diag.c
+++ b/drivers/s390/block/dasd_diag.c
@@ -24,7 +24,6 @@
#include <asm/ebcdic.h>
#include <asm/io.h>
#include <asm/s390_ext.h>
-#include <asm/todclk.h>
#include <asm/vtoc.h>
#include <asm/diag.h>
@@ -145,6 +144,15 @@ dasd_diag_erp(struct dasd_device *device)
mdsk_term_io(device);
rc = mdsk_init_io(device, device->block->bp_block, 0, NULL);
+ if (rc == 4) {
+ if (!(device->features & DASD_FEATURE_READONLY)) {
+ dev_warn(&device->cdev->dev,
+ "The access mode of a DIAG device changed"
+ " to read-only");
+ device->features |= DASD_FEATURE_READONLY;
+ }
+ rc = 0;
+ }
if (rc)
dev_warn(&device->cdev->dev, "DIAG ERP failed with "
"rc=%d\n", rc);
@@ -433,16 +441,20 @@ dasd_diag_check_device(struct dasd_device *device)
for (sb = 512; sb < bsize; sb = sb << 1)
block->s2b_shift++;
rc = mdsk_init_io(device, block->bp_block, 0, NULL);
- if (rc) {
+ if (rc && (rc != 4)) {
dev_warn(&device->cdev->dev, "DIAG initialization "
"failed with rc=%d\n", rc);
rc = -EIO;
} else {
+ if (rc == 4)
+ device->features |= DASD_FEATURE_READONLY;
dev_info(&device->cdev->dev,
- "New DASD with %ld byte/block, total size %ld KB\n",
+ "New DASD with %ld byte/block, total size %ld KB%s\n",
(unsigned long) block->bp_block,
(unsigned long) (block->blocks <<
- block->s2b_shift) >> 1);
+ block->s2b_shift) >> 1,
+ (rc == 4) ? ", read-only device" : "");
+ rc = 0;
}
out_label:
free_page((long) label);
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 417b97c..5819dc0 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -24,7 +24,6 @@
#include <asm/idals.h>
#include <asm/ebcdic.h>
#include <asm/io.h>
-#include <asm/todclk.h>
#include <asm/uaccess.h>
#include <asm/cio.h>
#include <asm/ccwdev.h>
@@ -78,6 +77,11 @@ MODULE_DEVICE_TABLE(ccw, dasd_eckd_ids);
static struct ccw_driver dasd_eckd_driver; /* see below */
+#define INIT_CQR_OK 0
+#define INIT_CQR_UNFORMATTED 1
+#define INIT_CQR_ERROR 2
+
+
/* initial attempt at a probe function. this can be simplified once
* the other detection code is gone */
static int
@@ -86,11 +90,12 @@ dasd_eckd_probe (struct ccw_device *cdev)
int ret;
/* set ECKD specific ccw-device options */
- ret = ccw_device_set_options(cdev, CCWDEV_ALLOW_FORCE);
+ ret = ccw_device_set_options(cdev, CCWDEV_ALLOW_FORCE |
+ CCWDEV_DO_PATHGROUP | CCWDEV_DO_MULTIPATH);
if (ret) {
- DBF_EVENT(DBF_WARNING,
- "dasd_eckd_probe: could not set ccw-device options "
- "for %s\n", dev_name(&cdev->dev));
+ DBF_EVENT_DEVID(DBF_WARNING, cdev, "%s",
+ "dasd_eckd_probe: could not set "
+ "ccw-device options");
return ret;
}
ret = dasd_generic_probe(cdev, &dasd_eckd_discipline);
@@ -749,8 +754,7 @@ static struct dasd_ccw_req *dasd_eckd_build_rcd_lpm(struct dasd_device *device,
cqr->block = NULL;
cqr->expires = 10*HZ;
cqr->lpm = lpm;
- clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
- cqr->retries = 2;
+ cqr->retries = 256;
cqr->buildclk = get_clock();
cqr->status = DASD_CQR_FILLED;
return cqr;
@@ -885,16 +889,15 @@ static int dasd_eckd_read_conf(struct dasd_device *device)
rc = dasd_eckd_read_conf_lpm(device, &conf_data,
&conf_len, lpm);
if (rc && rc != -EOPNOTSUPP) { /* -EOPNOTSUPP is ok */
- DBF_EVENT(DBF_WARNING,
+ DBF_EVENT_DEVID(DBF_WARNING, device->cdev,
"Read configuration data returned "
- "error %d for device: %s", rc,
- dev_name(&device->cdev->dev));
+ "error %d", rc);
return rc;
}
if (conf_data == NULL) {
- DBF_EVENT(DBF_WARNING, "No configuration "
- "data retrieved for device: %s",
- dev_name(&device->cdev->dev));
+ DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s",
+ "No configuration data "
+ "retrieved");
continue; /* no error */
}
/* save first valid configuration data */
@@ -941,16 +944,14 @@ static int dasd_eckd_read_features(struct dasd_device *device)
sizeof(struct dasd_rssd_features)),
device);
if (IS_ERR(cqr)) {
- DBF_EVENT(DBF_WARNING, "Could not allocate initialization "
- "request for device: %s",
- dev_name(&device->cdev->dev));
+ DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s", "Could not "
+ "allocate initialization request");
return PTR_ERR(cqr);
}
cqr->startdev = device;
cqr->memdev = device;
cqr->block = NULL;
- clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
- cqr->retries = 5;
+ cqr->retries = 256;
cqr->expires = 10 * HZ;
/* Prepare for Read Subsystem Data */
@@ -1012,9 +1013,9 @@ static struct dasd_ccw_req *dasd_eckd_build_psf_ssc(struct dasd_device *device,
}
psf_ssc_data = (struct dasd_psf_ssc_data *)cqr->data;
psf_ssc_data->order = PSF_ORDER_SSC;
- psf_ssc_data->suborder = 0x40;
+ psf_ssc_data->suborder = 0xc0;
if (enable_pav) {
- psf_ssc_data->suborder |= 0x88;
+ psf_ssc_data->suborder |= 0x08;
psf_ssc_data->reserved[0] = 0x88;
}
ccw = cqr->cpaddr;
@@ -1025,6 +1026,7 @@ static struct dasd_ccw_req *dasd_eckd_build_psf_ssc(struct dasd_device *device,
cqr->startdev = device;
cqr->memdev = device;
cqr->block = NULL;
+ cqr->retries = 256;
cqr->expires = 10*HZ;
cqr->buildclk = get_clock();
cqr->status = DASD_CQR_FILLED;
@@ -1057,7 +1059,7 @@ dasd_eckd_psf_ssc(struct dasd_device *device, int enable_pav)
/*
* Valide storage server of current device.
*/
-static int dasd_eckd_validate_server(struct dasd_device *device)
+static void dasd_eckd_validate_server(struct dasd_device *device)
{
int rc;
struct dasd_eckd_private *private;
@@ -1068,15 +1070,12 @@ static int dasd_eckd_validate_server(struct dasd_device *device)
else
enable_pav = 1;
rc = dasd_eckd_psf_ssc(device, enable_pav);
+
/* may be requested feature is not available on server,
* therefore just report error and go ahead */
private = (struct dasd_eckd_private *) device->private;
- DBF_EVENT(DBF_WARNING, "PSF-SSC on storage subsystem %s.%s.%04x "
- "returned rc=%d for device: %s",
- private->uid.vendor, private->uid.serial,
- private->uid.ssid, rc, dev_name(&device->cdev->dev));
- /* RE-Read Configuration Data */
- return dasd_eckd_read_conf(device);
+ DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "PSF-SSC for SSID %04x "
+ "returned rc=%d", private->uid.ssid, rc);
}
/*
@@ -1090,6 +1089,15 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
struct dasd_block *block;
int is_known, rc;
+ if (!ccw_device_is_pathgroup(device->cdev)) {
+ dev_warn(&device->cdev->dev,
+ "A channel path group could not be established\n");
+ return -EIO;
+ }
+ if (!ccw_device_is_multipath(device->cdev)) {
+ dev_info(&device->cdev->dev,
+ "The DASD is not operating in multipath mode\n");
+ }
private = (struct dasd_eckd_private *) device->private;
if (!private) {
private = kzalloc(sizeof(*private), GFP_KERNEL | GFP_DMA);
@@ -1123,9 +1131,9 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
if (private->uid.type == UA_BASE_DEVICE) {
block = dasd_alloc_block();
if (IS_ERR(block)) {
- DBF_EVENT(DBF_WARNING, "could not allocate dasd "
- "block structure for device: %s",
- dev_name(&device->cdev->dev));
+ DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s",
+ "could not allocate dasd "
+ "block structure");
rc = PTR_ERR(block);
goto out_err1;
}
@@ -1139,12 +1147,21 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
rc = is_known;
goto out_err2;
}
+ /*
+ * dasd_eckd_vaildate_server is done on the first device that
+ * is found for an LCU. All later other devices have to wait
+ * for it, so they will read the correct feature codes.
+ */
if (!is_known) {
- /* new lcu found */
- rc = dasd_eckd_validate_server(device); /* will switch pav on */
- if (rc)
- goto out_err3;
- }
+ dasd_eckd_validate_server(device);
+ dasd_alias_lcu_setup_complete(device);
+ } else
+ dasd_alias_wait_for_lcu_setup(device);
+
+ /* device may report different configuration data after LCU setup */
+ rc = dasd_eckd_read_conf(device);
+ if (rc)
+ goto out_err3;
/* Read Feature Codes */
dasd_eckd_read_features(device);
@@ -1153,9 +1170,8 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
rc = dasd_generic_read_dev_chars(device, DASD_ECKD_MAGIC,
&private->rdc_data, 64);
if (rc) {
- DBF_EVENT(DBF_WARNING,
- "Read device characteristics failed, rc=%d for "
- "device: %s", rc, dev_name(&device->cdev->dev));
+ DBF_EVENT_DEVID(DBF_WARNING, device->cdev,
+ "Read device characteristic failed, rc=%d", rc);
goto out_err3;
}
/* find the vaild cylinder size */
@@ -1256,12 +1272,29 @@ dasd_eckd_analysis_ccw(struct dasd_device *device)
cqr->block = NULL;
cqr->startdev = device;
cqr->memdev = device;
- cqr->retries = 0;
+ cqr->retries = 255;
cqr->buildclk = get_clock();
cqr->status = DASD_CQR_FILLED;
return cqr;
}
+/* differentiate between 'no record found' and any other error */
+static int dasd_eckd_analysis_evaluation(struct dasd_ccw_req *init_cqr)
+{
+ char *sense;
+ if (init_cqr->status == DASD_CQR_DONE)
+ return INIT_CQR_OK;
+ else if (init_cqr->status == DASD_CQR_NEED_ERP ||
+ init_cqr->status == DASD_CQR_FAILED) {
+ sense = dasd_get_sense(&init_cqr->irb);
+ if (sense && (sense[1] & SNS1_NO_REC_FOUND))
+ return INIT_CQR_UNFORMATTED;
+ else
+ return INIT_CQR_ERROR;
+ } else
+ return INIT_CQR_ERROR;
+}
+
/*
* This is the callback function for the init_analysis cqr. It saves
* the status of the initial analysis ccw before it frees it and kicks
@@ -1269,21 +1302,20 @@ dasd_eckd_analysis_ccw(struct dasd_device *device)
* dasd_eckd_do_analysis again (if the devices has not been marked
* for deletion in the meantime).
*/
-static void
-dasd_eckd_analysis_callback(struct dasd_ccw_req *init_cqr, void *data)
+static void dasd_eckd_analysis_callback(struct dasd_ccw_req *init_cqr,
+ void *data)
{
struct dasd_eckd_private *private;
struct dasd_device *device;
device = init_cqr->startdev;
private = (struct dasd_eckd_private *) device->private;
- private->init_cqr_status = init_cqr->status;
+ private->init_cqr_status = dasd_eckd_analysis_evaluation(init_cqr);
dasd_sfree_request(init_cqr, device);
dasd_kick_device(device);
}
-static int
-dasd_eckd_start_analysis(struct dasd_block *block)
+static int dasd_eckd_start_analysis(struct dasd_block *block)
{
struct dasd_eckd_private *private;
struct dasd_ccw_req *init_cqr;
@@ -1295,27 +1327,44 @@ dasd_eckd_start_analysis(struct dasd_block *block)
init_cqr->callback = dasd_eckd_analysis_callback;
init_cqr->callback_data = NULL;
init_cqr->expires = 5*HZ;
+ /* first try without ERP, so we can later handle unformatted
+ * devices as special case
+ */
+ clear_bit(DASD_CQR_FLAGS_USE_ERP, &init_cqr->flags);
+ init_cqr->retries = 0;
dasd_add_request_head(init_cqr);
return -EAGAIN;
}
-static int
-dasd_eckd_end_analysis(struct dasd_block *block)
+static int dasd_eckd_end_analysis(struct dasd_block *block)
{
struct dasd_device *device;
struct dasd_eckd_private *private;
struct eckd_count *count_area;
unsigned int sb, blk_per_trk;
int status, i;
+ struct dasd_ccw_req *init_cqr;
device = block->base;
private = (struct dasd_eckd_private *) device->private;
status = private->init_cqr_status;
private->init_cqr_status = -1;
- if (status != DASD_CQR_DONE) {
- dev_warn(&device->cdev->dev,
- "The DASD is not formatted\n");
+ if (status == INIT_CQR_ERROR) {
+ /* try again, this time with full ERP */
+ init_cqr = dasd_eckd_analysis_ccw(device);
+ dasd_sleep_on(init_cqr);
+ status = dasd_eckd_analysis_evaluation(init_cqr);
+ dasd_sfree_request(init_cqr, device);
+ }
+
+ if (status == INIT_CQR_UNFORMATTED) {
+ dev_warn(&device->cdev->dev, "The DASD is not formatted\n");
return -EMEDIUMTYPE;
+ } else if (status == INIT_CQR_ERROR) {
+ dev_err(&device->cdev->dev,
+ "Detecting the DASD disk layout failed because "
+ "of an I/O error\n");
+ return -EIO;
}
private->uses_cdl = 1;
@@ -1607,8 +1656,7 @@ dasd_eckd_format_device(struct dasd_device * device,
}
fcp->startdev = device;
fcp->memdev = device;
- clear_bit(DASD_CQR_FLAGS_USE_ERP, &fcp->flags);
- fcp->retries = 5; /* set retry counter to enable default ERP */
+ fcp->retries = 256;
fcp->buildclk = get_clock();
fcp->status = DASD_CQR_FILLED;
return fcp;
@@ -2690,6 +2738,7 @@ dasd_eckd_performance(struct dasd_device *device, void __user *argp)
cqr->startdev = device;
cqr->memdev = device;
cqr->retries = 0;
+ clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
cqr->expires = 10 * HZ;
/* Prepare for Read Subsystem Data */
@@ -3240,11 +3289,15 @@ int dasd_eckd_restore_device(struct dasd_device *device)
if (is_known < 0)
return is_known;
if (!is_known) {
- /* new lcu found */
- rc = dasd_eckd_validate_server(device); /* will switch pav on */
- if (rc)
- goto out_err;
- }
+ dasd_eckd_validate_server(device);
+ dasd_alias_lcu_setup_complete(device);
+ } else
+ dasd_alias_wait_for_lcu_setup(device);
+
+ /* RE-Read Configuration Data */
+ rc = dasd_eckd_read_conf(device);
+ if (rc)
+ goto out_err;
/* Read Feature Codes */
dasd_eckd_read_features(device);
@@ -3253,9 +3306,8 @@ int dasd_eckd_restore_device(struct dasd_device *device)
rc = dasd_generic_read_dev_chars(device, DASD_ECKD_MAGIC,
&temp_rdc_data, 64);
if (rc) {
- DBF_EVENT(DBF_WARNING,
- "Read device characteristics failed, rc=%d for "
- "device: %s", rc, dev_name(&device->cdev->dev));
+ DBF_EVENT_DEVID(DBF_WARNING, device->cdev,
+ "Read device characteristic failed, rc=%d", rc);
goto out_err;
}
spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h
index ad45bca..864d53c 100644
--- a/drivers/s390/block/dasd_eckd.h
+++ b/drivers/s390/block/dasd_eckd.h
@@ -414,6 +414,7 @@ struct alias_lcu {
struct summary_unit_check_work_data suc_data;
struct read_uac_work_data ruac_data;
struct dasd_ccw_req *rsu_cqr;
+ struct completion lcu_setup;
};
struct alias_pav_group {
@@ -460,5 +461,6 @@ int dasd_alias_remove_device(struct dasd_device *);
struct dasd_device *dasd_alias_get_start_dev(struct dasd_device *);
void dasd_alias_handle_summary_unit_check(struct dasd_device *, struct irb *);
void dasd_eckd_reset_ccw_to_base_io(struct dasd_ccw_req *);
-
+void dasd_alias_lcu_setup_complete(struct dasd_device *);
+void dasd_alias_wait_for_lcu_setup(struct dasd_device *);
#endif /* DASD_ECKD_H */
diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c
index d96039e..1f3e967 100644
--- a/drivers/s390/block/dasd_eer.c
+++ b/drivers/s390/block/dasd_eer.c
@@ -536,7 +536,6 @@ static int dasd_eer_open(struct inode *inp, struct file *filp)
eerb = kzalloc(sizeof(struct eerbuffer), GFP_KERNEL);
if (!eerb)
return -ENOMEM;
- lock_kernel();
eerb->buffer_page_count = eer_pages;
if (eerb->buffer_page_count < 1 ||
eerb->buffer_page_count > INT_MAX / PAGE_SIZE) {
@@ -544,7 +543,6 @@ static int dasd_eer_open(struct inode *inp, struct file *filp)
DBF_EVENT(DBF_WARNING, "can't open device since module "
"parameter eer_pages is smaller than 1 or"
" bigger than %d", (int)(INT_MAX / PAGE_SIZE));
- unlock_kernel();
return -EINVAL;
}
eerb->buffersize = eerb->buffer_page_count * PAGE_SIZE;
@@ -552,14 +550,12 @@ static int dasd_eer_open(struct inode *inp, struct file *filp)
GFP_KERNEL);
if (!eerb->buffer) {
kfree(eerb);
- unlock_kernel();
return -ENOMEM;
}
if (dasd_eer_allocate_buffer_pages(eerb->buffer,
eerb->buffer_page_count)) {
kfree(eerb->buffer);
kfree(eerb);
- unlock_kernel();
return -ENOMEM;
}
filp->private_data = eerb;
@@ -567,7 +563,6 @@ static int dasd_eer_open(struct inode *inp, struct file *filp)
list_add(&eerb->list, &bufferlist);
spin_unlock_irqrestore(&bufferlock, flags);
- unlock_kernel();
return nonseekable_open(inp,filp);
}
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c
index f245377..0f15244 100644
--- a/drivers/s390/block/dasd_fba.c
+++ b/drivers/s390/block/dasd_fba.c
@@ -20,7 +20,6 @@
#include <asm/idals.h>
#include <asm/ebcdic.h>
#include <asm/io.h>
-#include <asm/todclk.h>
#include <asm/ccwdev.h>
#include "dasd_int.h"
@@ -141,9 +140,8 @@ dasd_fba_check_characteristics(struct dasd_device *device)
}
block = dasd_alloc_block();
if (IS_ERR(block)) {
- DBF_EVENT(DBF_WARNING, "could not allocate dasd block "
- "structure for device: %s",
- dev_name(&device->cdev->dev));
+ DBF_EVENT_DEVID(DBF_WARNING, cdev, "%s", "could not allocate "
+ "dasd block structure");
device->private = NULL;
kfree(private);
return PTR_ERR(block);
@@ -155,9 +153,8 @@ dasd_fba_check_characteristics(struct dasd_device *device)
rc = dasd_generic_read_dev_chars(device, DASD_FBA_MAGIC,
&private->rdc_data, 32);
if (rc) {
- DBF_EVENT(DBF_WARNING, "Read device characteristics returned "
- "error %d for device: %s",
- rc, dev_name(&device->cdev->dev));
+ DBF_EVENT_DEVID(DBF_WARNING, cdev, "Read device "
+ "characteristics returned error %d", rc);
device->block = NULL;
dasd_free_block(block);
device->private = NULL;
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index 8afd9fa..e4c2143 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -108,6 +108,16 @@ do { \
d_data); \
} while(0)
+#define DBF_EVENT_DEVID(d_level, d_cdev, d_str, d_data...) \
+do { \
+ struct ccw_dev_id __dev_id; \
+ ccw_device_get_id(d_cdev, &__dev_id); \
+ debug_sprintf_event(dasd_debug_area, \
+ d_level, \
+ "0.%x.%04x " d_str "\n", \
+ __dev_id.ssid, __dev_id.devno, d_data); \
+} while (0)
+
#define DBF_EXC(d_level, d_str, d_data...)\
do { \
debug_sprintf_exception(dasd_debug_area, \
@@ -595,6 +605,9 @@ int dasd_generic_restore_device(struct ccw_device *);
int dasd_generic_read_dev_chars(struct dasd_device *, int, void *, int);
char *dasd_get_sense(struct irb *);
+void dasd_device_set_stop_bits(struct dasd_device *, int);
+void dasd_device_remove_stop_bits(struct dasd_device *, int);
+
/* externals in dasd_devmap.c */
extern int dasd_max_devindex;
extern int dasd_probeonly;
diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c
index f756a1b..478bcdb 100644
--- a/drivers/s390/block/dasd_ioctl.c
+++ b/drivers/s390/block/dasd_ioctl.c
@@ -101,7 +101,7 @@ static int dasd_ioctl_quiesce(struct dasd_block *block)
pr_info("%s: The DASD has been put in the quiesce "
"state\n", dev_name(&base->cdev->dev));
spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
- base->stopped |= DASD_STOPPED_QUIESCE;
+ dasd_device_set_stop_bits(base, DASD_STOPPED_QUIESCE);
spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags);
return 0;
}
@@ -122,7 +122,7 @@ static int dasd_ioctl_resume(struct dasd_block *block)
pr_info("%s: I/O operations have been resumed "
"on the DASD\n", dev_name(&base->cdev->dev));
spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
- base->stopped &= ~DASD_STOPPED_QUIESCE;
+ dasd_device_remove_stop_bits(base, DASD_STOPPED_QUIESCE);
spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags);
dasd_schedule_block_bh(block);
diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c
index 654daa3..5f23eca 100644
--- a/drivers/s390/block/dasd_proc.c
+++ b/drivers/s390/block/dasd_proc.c
@@ -215,7 +215,7 @@ dasd_statistics_read(char *page, char **start, off_t off,
}
prof = &dasd_global_profile;
- /* prevent couter 'overflow' on output */
+ /* prevent counter 'overflow' on output */
for (factor = 1; (prof->dasd_io_reqs / factor) > 9999999;
factor *= 10);
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index 21639d6..9d61683 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -857,7 +857,6 @@ static struct console con3215 = {
/*
* 3215 console initialization code called from console_init().
- * NOTE: This is called before kmalloc is available.
*/
static int __init con3215_init(void)
{
diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c
index bb838bd..6bca81a 100644
--- a/drivers/s390/char/con3270.c
+++ b/drivers/s390/char/con3270.c
@@ -572,7 +572,6 @@ static struct console con3270 = {
/*
* 3270 console initialization code called from console_init().
- * NOTE: This is called before kmalloc is available.
*/
static int __init
con3270_init(void)
diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c
index 097d384..28e4649 100644
--- a/drivers/s390/char/fs3270.c
+++ b/drivers/s390/char/fs3270.c
@@ -38,6 +38,8 @@ struct fs3270 {
size_t rdbuf_size; /* size of data returned by RDBUF */
};
+static DEFINE_MUTEX(fs3270_mutex);
+
static void
fs3270_wake_up(struct raw3270_request *rq, void *data)
{
@@ -74,7 +76,7 @@ fs3270_do_io(struct raw3270_view *view, struct raw3270_request *rq)
}
rc = raw3270_start(view, rq);
if (rc == 0) {
- /* Started sucessfully. Now wait for completion. */
+ /* Started successfully. Now wait for completion. */
wait_event(fp->wait, raw3270_request_final(rq));
}
} while (rc == -EACCES);
@@ -328,7 +330,7 @@ fs3270_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (!fp)
return -ENODEV;
rc = 0;
- lock_kernel();
+ mutex_lock(&fs3270_mutex);
switch (cmd) {
case TUBICMD:
fp->read_command = arg;
@@ -354,7 +356,7 @@ fs3270_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
rc = -EFAULT;
break;
}
- unlock_kernel();
+ mutex_unlock(&fs3270_mutex);
return rc;
}
@@ -437,7 +439,7 @@ fs3270_open(struct inode *inode, struct file *filp)
minor = tty->index + RAW3270_FIRSTMINOR;
tty_kref_put(tty);
}
- lock_kernel();
+ mutex_lock(&fs3270_mutex);
/* Check if some other program is already using fullscreen mode. */
fp = (struct fs3270 *) raw3270_find_view(&fs3270_fn, minor);
if (!IS_ERR(fp)) {
@@ -478,7 +480,7 @@ fs3270_open(struct inode *inode, struct file *filp)
}
filp->private_data = fp;
out:
- unlock_kernel();
+ mutex_unlock(&fs3270_mutex);
return rc;
}
diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c
index 66e21dd..60473f8 100644
--- a/drivers/s390/char/monreader.c
+++ b/drivers/s390/char/monreader.c
@@ -12,7 +12,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -283,7 +282,6 @@ static int mon_open(struct inode *inode, struct file *filp)
/*
* only one user allowed
*/
- lock_kernel();
rc = -EBUSY;
if (test_and_set_bit(MON_IN_USE, &mon_in_use))
goto out;
@@ -321,7 +319,6 @@ static int mon_open(struct inode *inode, struct file *filp)
}
filp->private_data = monpriv;
dev_set_drvdata(monreader_device, monpriv);
- unlock_kernel();
return nonseekable_open(inode, filp);
out_path:
@@ -331,7 +328,6 @@ out_priv:
out_use:
clear_bit(MON_IN_USE, &mon_in_use);
out:
- unlock_kernel();
return rc;
}
@@ -607,6 +603,10 @@ static int __init mon_init(void)
}
dcss_mkname(mon_dcss_name, &user_data_connect[8]);
+ /*
+ * misc_register() has to be the last action in module_init(), because
+ * file operations will be available right after this.
+ */
rc = misc_register(&mon_dev);
if (rc < 0 )
goto out;
diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c
index 66fb8eb..6532ed8 100644
--- a/drivers/s390/char/monwriter.c
+++ b/drivers/s390/char/monwriter.c
@@ -13,7 +13,6 @@
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/errno.h>
-#include <linux/smp_lock.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/miscdevice.h>
@@ -185,13 +184,11 @@ static int monwrite_open(struct inode *inode, struct file *filp)
monpriv = kzalloc(sizeof(struct mon_private), GFP_KERNEL);
if (!monpriv)
return -ENOMEM;
- lock_kernel();
INIT_LIST_HEAD(&monpriv->list);
monpriv->hdr_to_read = sizeof(monpriv->hdr);
mutex_init(&monpriv->thread_mutex);
filp->private_data = monpriv;
list_add_tail(&monpriv->priv_list, &mon_priv_list);
- unlock_kernel();
return nonseekable_open(inode, filp);
}
@@ -364,6 +361,10 @@ static int __init mon_init(void)
goto out_driver;
}
+ /*
+ * misc_register() has to be the last action in module_init(), because
+ * file operations will be available right after this.
+ */
rc = misc_register(&mon_dev);
if (rc)
goto out_device;
diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c
index 5cc11c6..28b5afc 100644
--- a/drivers/s390/char/sclp_cmd.c
+++ b/drivers/s390/char/sclp_cmd.c
@@ -84,6 +84,7 @@ static void __init sclp_read_info_early(void)
do {
memset(sccb, 0, sizeof(*sccb));
sccb->header.length = sizeof(*sccb);
+ sccb->header.function_code = 0x80;
sccb->header.control_mask[2] = 0x80;
rc = sclp_cmd_sync_early(commands[i], sccb);
} while (rc == -EBUSY);
diff --git a/drivers/s390/char/tape.h b/drivers/s390/char/tape.h
index a263337..7a242f0 100644
--- a/drivers/s390/char/tape.h
+++ b/drivers/s390/char/tape.h
@@ -212,6 +212,9 @@ struct tape_device {
struct tape_class_device * nt;
struct tape_class_device * rt;
+ /* Device mutex to serialize tape commands. */
+ struct mutex mutex;
+
/* Device discipline information. */
struct tape_discipline * discipline;
void * discdata;
@@ -292,9 +295,9 @@ extern int tape_generic_pm_suspend(struct ccw_device *);
extern int tape_generic_probe(struct ccw_device *);
extern void tape_generic_remove(struct ccw_device *);
-extern struct tape_device *tape_get_device(int devindex);
-extern struct tape_device *tape_get_device_reference(struct tape_device *);
-extern struct tape_device *tape_put_device(struct tape_device *);
+extern struct tape_device *tape_find_device(int devindex);
+extern struct tape_device *tape_get_device(struct tape_device *);
+extern void tape_put_device(struct tape_device *);
/* Externals from tape_char.c */
extern int tapechar_init(void);
diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c
index 2fe45ff..3657fe1 100644
--- a/drivers/s390/char/tape_34xx.c
+++ b/drivers/s390/char/tape_34xx.c
@@ -113,16 +113,16 @@ tape_34xx_work_handler(struct work_struct *work)
{
struct tape_34xx_work *p =
container_of(work, struct tape_34xx_work, work);
+ struct tape_device *device = p->device;
switch(p->op) {
case TO_MSEN:
- tape_34xx_medium_sense(p->device);
+ tape_34xx_medium_sense(device);
break;
default:
DBF_EVENT(3, "T34XX: internal error: unknown work\n");
}
-
- p->device = tape_put_device(p->device);
+ tape_put_device(device);
kfree(p);
}
@@ -136,7 +136,7 @@ tape_34xx_schedule_work(struct tape_device *device, enum tape_op op)
INIT_WORK(&p->work, tape_34xx_work_handler);
- p->device = tape_get_device_reference(device);
+ p->device = tape_get_device(device);
p->op = op;
schedule_work(&p->work);
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c
index e4cc3aa..0c72aad 100644
--- a/drivers/s390/char/tape_3590.c
+++ b/drivers/s390/char/tape_3590.c
@@ -608,7 +608,7 @@ tape_3590_schedule_work(struct tape_device *device, enum tape_op op)
INIT_WORK(&p->work, tape_3590_work_handler);
- p->device = tape_get_device_reference(device);
+ p->device = tape_get_device(device);
p->op = op;
schedule_work(&p->work);
diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c
index 0c0705b..4799cc2 100644
--- a/drivers/s390/char/tape_block.c
+++ b/drivers/s390/char/tape_block.c
@@ -54,7 +54,7 @@ static const struct block_device_operations tapeblock_fops = {
.owner = THIS_MODULE,
.open = tapeblock_open,
.release = tapeblock_release,
- .locked_ioctl = tapeblock_ioctl,
+ .ioctl = tapeblock_ioctl,
.media_changed = tapeblock_medium_changed,
.revalidate_disk = tapeblock_revalidate_disk,
};
@@ -239,7 +239,7 @@ tapeblock_setup_device(struct tape_device * device)
disk->major = tapeblock_major;
disk->first_minor = device->first_minor;
disk->fops = &tapeblock_fops;
- disk->private_data = tape_get_device_reference(device);
+ disk->private_data = tape_get_device(device);
disk->queue = blkdat->request_queue;
set_capacity(disk, 0);
sprintf(disk->disk_name, "btibm%d",
@@ -247,11 +247,11 @@ tapeblock_setup_device(struct tape_device * device)
blkdat->disk = disk;
blkdat->medium_changed = 1;
- blkdat->request_queue->queuedata = tape_get_device_reference(device);
+ blkdat->request_queue->queuedata = tape_get_device(device);
add_disk(disk);
- tape_get_device_reference(device);
+ tape_get_device(device);
INIT_WORK(&blkdat->requeue_task, tapeblock_requeue);
return 0;
@@ -274,13 +274,14 @@ tapeblock_cleanup_device(struct tape_device *device)
}
del_gendisk(device->blk_data.disk);
- device->blk_data.disk->private_data =
- tape_put_device(device->blk_data.disk->private_data);
+ device->blk_data.disk->private_data = NULL;
+ tape_put_device(device);
put_disk(device->blk_data.disk);
device->blk_data.disk = NULL;
cleanup_queue:
- device->blk_data.request_queue->queuedata = tape_put_device(device);
+ device->blk_data.request_queue->queuedata = NULL;
+ tape_put_device(device);
blk_cleanup_queue(device->blk_data.request_queue);
device->blk_data.request_queue = NULL;
@@ -363,7 +364,7 @@ tapeblock_open(struct block_device *bdev, fmode_t mode)
struct tape_device * device;
int rc;
- device = tape_get_device_reference(disk->private_data);
+ device = tape_get_device(disk->private_data);
if (device->required_tapemarks) {
DBF_EVENT(2, "TBLOCK: missing tapemarks\n");
diff --git a/drivers/s390/char/tape_char.c b/drivers/s390/char/tape_char.c
index 31566c5..23d773a 100644
--- a/drivers/s390/char/tape_char.c
+++ b/drivers/s390/char/tape_char.c
@@ -33,8 +33,7 @@ static ssize_t tapechar_read(struct file *, char __user *, size_t, loff_t *);
static ssize_t tapechar_write(struct file *, const char __user *, size_t, loff_t *);
static int tapechar_open(struct inode *,struct file *);
static int tapechar_release(struct inode *,struct file *);
-static int tapechar_ioctl(struct inode *, struct file *, unsigned int,
- unsigned long);
+static long tapechar_ioctl(struct file *, unsigned int, unsigned long);
static long tapechar_compat_ioctl(struct file *, unsigned int,
unsigned long);
@@ -43,7 +42,7 @@ static const struct file_operations tape_fops =
.owner = THIS_MODULE,
.read = tapechar_read,
.write = tapechar_write,
- .ioctl = tapechar_ioctl,
+ .unlocked_ioctl = tapechar_ioctl,
.compat_ioctl = tapechar_compat_ioctl,
.open = tapechar_open,
.release = tapechar_release,
@@ -170,7 +169,6 @@ tapechar_read(struct file *filp, char __user *data, size_t count, loff_t *ppos)
if (rc == 0) {
rc = block_size - request->rescnt;
DBF_EVENT(6, "TCHAR:rbytes: %x\n", rc);
- filp->f_pos += rc;
/* Copy data from idal buffer to user space. */
if (idal_buffer_to_user(device->char_data.idal_buf,
data, rc) != 0)
@@ -238,7 +236,6 @@ tapechar_write(struct file *filp, const char __user *data, size_t count, loff_t
break;
DBF_EVENT(6, "TCHAR:wbytes: %lx\n",
block_size - request->rescnt);
- filp->f_pos += block_size - request->rescnt;
written += block_size - request->rescnt;
if (request->rescnt != 0)
break;
@@ -286,26 +283,20 @@ tapechar_open (struct inode *inode, struct file *filp)
if (imajor(filp->f_path.dentry->d_inode) != tapechar_major)
return -ENODEV;
- lock_kernel();
minor = iminor(filp->f_path.dentry->d_inode);
- device = tape_get_device(minor / TAPE_MINORS_PER_DEV);
+ device = tape_find_device(minor / TAPE_MINORS_PER_DEV);
if (IS_ERR(device)) {
- DBF_EVENT(3, "TCHAR:open: tape_get_device() failed\n");
- rc = PTR_ERR(device);
- goto out;
+ DBF_EVENT(3, "TCHAR:open: tape_find_device() failed\n");
+ return PTR_ERR(device);
}
-
rc = tape_open(device);
if (rc == 0) {
filp->private_data = device;
- rc = nonseekable_open(inode, filp);
- }
- else
+ nonseekable_open(inode, filp);
+ } else
tape_put_device(device);
-out:
- unlock_kernel();
return rc;
}
@@ -342,7 +333,8 @@ tapechar_release(struct inode *inode, struct file *filp)
device->char_data.idal_buf = NULL;
}
tape_release(device);
- filp->private_data = tape_put_device(device);
+ filp->private_data = NULL;
+ tape_put_device(device);
return 0;
}
@@ -351,16 +343,11 @@ tapechar_release(struct inode *inode, struct file *filp)
* Tape device io controls.
*/
static int
-tapechar_ioctl(struct inode *inp, struct file *filp,
- unsigned int no, unsigned long data)
+__tapechar_ioctl(struct tape_device *device,
+ unsigned int no, unsigned long data)
{
- struct tape_device *device;
int rc;
- DBF_EVENT(6, "TCHAR:ioct\n");
-
- device = (struct tape_device *) filp->private_data;
-
if (no == MTIOCTOP) {
struct mtop op;
@@ -453,15 +440,30 @@ tapechar_ioctl(struct inode *inp, struct file *filp,
}
static long
+tapechar_ioctl(struct file *filp, unsigned int no, unsigned long data)
+{
+ struct tape_device *device;
+ long rc;
+
+ DBF_EVENT(6, "TCHAR:ioct\n");
+
+ device = (struct tape_device *) filp->private_data;
+ mutex_lock(&device->mutex);
+ rc = __tapechar_ioctl(device, no, data);
+ mutex_unlock(&device->mutex);
+ return rc;
+}
+
+static long
tapechar_compat_ioctl(struct file *filp, unsigned int no, unsigned long data)
{
struct tape_device *device = filp->private_data;
int rval = -ENOIOCTLCMD;
if (device->discipline->ioctl_fn) {
- lock_kernel();
+ mutex_lock(&device->mutex);
rval = device->discipline->ioctl_fn(device, no, data);
- unlock_kernel();
+ mutex_unlock(&device->mutex);
if (rval == -EINVAL)
rval = -ENOIOCTLCMD;
}
diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c
index 5cd31e0..f5d6802 100644
--- a/drivers/s390/char/tape_core.c
+++ b/drivers/s390/char/tape_core.c
@@ -492,6 +492,7 @@ tape_alloc_device(void)
kfree(device);
return ERR_PTR(-ENOMEM);
}
+ mutex_init(&device->mutex);
INIT_LIST_HEAD(&device->req_queue);
INIT_LIST_HEAD(&device->node);
init_waitqueue_head(&device->state_change_wq);
@@ -511,11 +512,12 @@ tape_alloc_device(void)
* increment the reference count.
*/
struct tape_device *
-tape_get_device_reference(struct tape_device *device)
+tape_get_device(struct tape_device *device)
{
- DBF_EVENT(4, "tape_get_device_reference(%p) = %i\n", device,
- atomic_inc_return(&device->ref_count));
+ int count;
+ count = atomic_inc_return(&device->ref_count);
+ DBF_EVENT(4, "tape_get_device(%p) = %i\n", device, count);
return device;
}
@@ -525,32 +527,25 @@ tape_get_device_reference(struct tape_device *device)
* The function returns a NULL pointer to be used by the caller
* for clearing reference pointers.
*/
-struct tape_device *
+void
tape_put_device(struct tape_device *device)
{
- int remain;
+ int count;
- remain = atomic_dec_return(&device->ref_count);
- if (remain > 0) {
- DBF_EVENT(4, "tape_put_device(%p) -> %i\n", device, remain);
- } else {
- if (remain < 0) {
- DBF_EVENT(4, "put device without reference\n");
- } else {
- DBF_EVENT(4, "tape_free_device(%p)\n", device);
- kfree(device->modeset_byte);
- kfree(device);
- }
+ count = atomic_dec_return(&device->ref_count);
+ DBF_EVENT(4, "tape_put_device(%p) -> %i\n", device, count);
+ BUG_ON(count < 0);
+ if (count == 0) {
+ kfree(device->modeset_byte);
+ kfree(device);
}
-
- return NULL;
}
/*
* Find tape device by a device index.
*/
struct tape_device *
-tape_get_device(int devindex)
+tape_find_device(int devindex)
{
struct tape_device *device, *tmp;
@@ -558,7 +553,7 @@ tape_get_device(int devindex)
read_lock(&tape_device_lock);
list_for_each_entry(tmp, &tape_device_list, node) {
if (tmp->first_minor / TAPE_MINORS_PER_DEV == devindex) {
- device = tape_get_device_reference(tmp);
+ device = tape_get_device(tmp);
break;
}
}
@@ -579,7 +574,8 @@ tape_generic_probe(struct ccw_device *cdev)
device = tape_alloc_device();
if (IS_ERR(device))
return -ENODEV;
- ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP);
+ ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP |
+ CCWDEV_DO_MULTIPATH);
ret = sysfs_create_group(&cdev->dev.kobj, &tape_attr_group);
if (ret) {
tape_put_device(device);
@@ -606,7 +602,8 @@ __tape_discard_requests(struct tape_device *device)
list_del(&request->list);
/* Decrease ref_count for removed request. */
- request->device = tape_put_device(device);
+ request->device = NULL;
+ tape_put_device(device);
request->rc = -EIO;
if (request->callback != NULL)
request->callback(request, request->callback_data);
@@ -664,9 +661,11 @@ tape_generic_remove(struct ccw_device *cdev)
tape_cleanup_device(device);
}
- if (!dev_get_drvdata(&cdev->dev)) {
+ device = dev_get_drvdata(&cdev->dev);
+ if (device) {
sysfs_remove_group(&cdev->dev.kobj, &tape_attr_group);
- dev_set_drvdata(&cdev->dev, tape_put_device(dev_get_drvdata(&cdev->dev)));
+ dev_set_drvdata(&cdev->dev, NULL);
+ tape_put_device(device);
}
}
@@ -721,9 +720,8 @@ tape_free_request (struct tape_request * request)
{
DBF_LH(6, "Free request %p\n", request);
- if (request->device != NULL) {
- request->device = tape_put_device(request->device);
- }
+ if (request->device)
+ tape_put_device(request->device);
kfree(request->cpdata);
kfree(request->cpaddr);
kfree(request);
@@ -838,7 +836,8 @@ static void tape_long_busy_timeout(unsigned long data)
BUG_ON(request->status != TAPE_REQUEST_LONG_BUSY);
DBF_LH(6, "%08x: Long busy timeout.\n", device->cdev_id);
__tape_start_next_request(device);
- device->lb_timeout.data = (unsigned long) tape_put_device(device);
+ device->lb_timeout.data = 0UL;
+ tape_put_device(device);
spin_unlock_irq(get_ccwdev_lock(device->cdev));
}
@@ -918,7 +917,7 @@ __tape_start_request(struct tape_device *device, struct tape_request *request)
}
/* Increase use count of device for the added request. */
- request->device = tape_get_device_reference(device);
+ request->device = tape_get_device(device);
if (list_empty(&device->req_queue)) {
/* No other requests are on the queue. Start this one. */
@@ -1117,8 +1116,8 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
if (req->status == TAPE_REQUEST_LONG_BUSY) {
DBF_EVENT(3, "(%08x): del timer\n", device->cdev_id);
if (del_timer(&device->lb_timeout)) {
- device->lb_timeout.data = (unsigned long)
- tape_put_device(device);
+ device->lb_timeout.data = 0UL;
+ tape_put_device(device);
__tape_start_next_request(device);
}
return;
@@ -1173,7 +1172,7 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
break;
case TAPE_IO_LONG_BUSY:
device->lb_timeout.data =
- (unsigned long)tape_get_device_reference(device);
+ (unsigned long) tape_get_device(device);
device->lb_timeout.expires = jiffies +
LONG_BUSY_TIMEOUT * HZ;
DBF_EVENT(3, "(%08x): add timer\n", device->cdev_id);
@@ -1326,7 +1325,7 @@ EXPORT_SYMBOL(tape_generic_online);
EXPORT_SYMBOL(tape_generic_offline);
EXPORT_SYMBOL(tape_generic_pm_suspend);
EXPORT_SYMBOL(tape_put_device);
-EXPORT_SYMBOL(tape_get_device_reference);
+EXPORT_SYMBOL(tape_get_device);
EXPORT_SYMBOL(tape_state_verbose);
EXPORT_SYMBOL(tape_op_verbose);
EXPORT_SYMBOL(tape_state_set);
diff --git a/drivers/s390/char/tape_proc.c b/drivers/s390/char/tape_proc.c
index 202f421..ebd820c 100644
--- a/drivers/s390/char/tape_proc.c
+++ b/drivers/s390/char/tape_proc.c
@@ -45,7 +45,7 @@ static int tape_proc_show(struct seq_file *m, void *v)
seq_printf(m, "TapeNo\tBusID CuType/Model\t"
"DevType/Model\tBlkSize\tState\tOp\tMedState\n");
}
- device = tape_get_device(n);
+ device = tape_find_device(n);
if (IS_ERR(device))
return 0;
spin_lock_irq(get_ccwdev_lock(device->cdev));
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
index 3838567..911822db 100644
--- a/drivers/s390/char/tty3270.c
+++ b/drivers/s390/char/tty3270.c
@@ -19,6 +19,7 @@
#include <linux/slab.h>
#include <linux/bootmem.h>
+#include <linux/compat.h>
#include <asm/ccwdev.h>
#include <asm/cio.h>
@@ -1731,6 +1732,22 @@ tty3270_ioctl(struct tty_struct *tty, struct file *file,
return kbd_ioctl(tp->kbd, file, cmd, arg);
}
+#ifdef CONFIG_COMPAT
+static long
+tty3270_compat_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct tty3270 *tp;
+
+ tp = tty->driver_data;
+ if (!tp)
+ return -ENODEV;
+ if (tty->flags & (1 << TTY_IO_ERROR))
+ return -EIO;
+ return kbd_ioctl(tp->kbd, file, cmd, (unsigned long)compat_ptr(arg));
+}
+#endif
+
static const struct tty_operations tty3270_ops = {
.open = tty3270_open,
.close = tty3270_close,
@@ -1745,6 +1762,9 @@ static const struct tty_operations tty3270_ops = {
.hangup = tty3270_hangup,
.wait_until_sent = tty3270_wait_until_sent,
.ioctl = tty3270_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = tty3270_compat_ioctl,
+#endif
.set_termios = tty3270_set_termios
};
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c
index d1a142fa..899aa79 100644
--- a/drivers/s390/char/vmlogrdr.c
+++ b/drivers/s390/char/vmlogrdr.c
@@ -312,11 +312,9 @@ static int vmlogrdr_open (struct inode *inode, struct file *filp)
return -ENOSYS;
/* Besure this device hasn't already been opened */
- lock_kernel();
spin_lock_bh(&logptr->priv_lock);
if (logptr->dev_in_use) {
spin_unlock_bh(&logptr->priv_lock);
- unlock_kernel();
return -EBUSY;
}
logptr->dev_in_use = 1;
@@ -360,9 +358,8 @@ static int vmlogrdr_open (struct inode *inode, struct file *filp)
|| (logptr->iucv_path_severed));
if (logptr->iucv_path_severed)
goto out_record;
- ret = nonseekable_open(inode, filp);
- unlock_kernel();
- return ret;
+ nonseekable_open(inode, filp);
+ return 0;
out_record:
if (logptr->autorecording)
@@ -372,7 +369,6 @@ out_path:
logptr->path = NULL;
out_dev:
logptr->dev_in_use = 0;
- unlock_kernel();
return -EIO;
}
diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c
index 77571b6..cc56fc7 100644
--- a/drivers/s390/char/vmur.c
+++ b/drivers/s390/char/vmur.c
@@ -695,7 +695,6 @@ static int ur_open(struct inode *inode, struct file *file)
if (accmode == O_RDWR)
return -EACCES;
- lock_kernel();
/*
* We treat the minor number as the devno of the ur device
* to find in the driver tree.
@@ -749,7 +748,6 @@ static int ur_open(struct inode *inode, struct file *file)
goto fail_urfile_free;
urf->file_reclen = rc;
file->private_data = urf;
- unlock_kernel();
return 0;
fail_urfile_free:
@@ -761,7 +759,6 @@ fail_unlock:
fail_put:
urdev_put(urd);
out:
- unlock_kernel();
return rc;
}
diff --git a/drivers/s390/char/vmwatchdog.c b/drivers/s390/char/vmwatchdog.c
index f2bc287..c974058 100644
--- a/drivers/s390/char/vmwatchdog.c
+++ b/drivers/s390/char/vmwatchdog.c
@@ -19,7 +19,6 @@
#include <linux/moduleparam.h>
#include <linux/suspend.h>
#include <linux/watchdog.h>
-#include <linux/smp_lock.h>
#include <asm/ebcdic.h>
#include <asm/io.h>
@@ -49,6 +48,8 @@ static unsigned int vmwdt_interval = 60;
static unsigned long vmwdt_is_open;
static int vmwdt_expect_close;
+static DEFINE_MUTEX(vmwdt_mutex);
+
#define VMWDT_OPEN 0 /* devnode is open or suspend in progress */
#define VMWDT_RUNNING 1 /* The watchdog is armed */
@@ -133,15 +134,11 @@ static int __init vmwdt_probe(void)
static int vmwdt_open(struct inode *i, struct file *f)
{
int ret;
- lock_kernel();
- if (test_and_set_bit(VMWDT_OPEN, &vmwdt_is_open)) {
- unlock_kernel();
+ if (test_and_set_bit(VMWDT_OPEN, &vmwdt_is_open))
return -EBUSY;
- }
ret = vmwdt_keepalive();
if (ret)
clear_bit(VMWDT_OPEN, &vmwdt_is_open);
- unlock_kernel();
return ret ? ret : nonseekable_open(i, f);
}
@@ -160,8 +157,7 @@ static struct watchdog_info vmwdt_info = {
.identity = "z/VM Watchdog Timer",
};
-static int vmwdt_ioctl(struct inode *i, struct file *f,
- unsigned int cmd, unsigned long arg)
+static int __vmwdt_ioctl(unsigned int cmd, unsigned long arg)
{
switch (cmd) {
case WDIOC_GETSUPPORT:
@@ -205,10 +201,19 @@ static int vmwdt_ioctl(struct inode *i, struct file *f,
case WDIOC_KEEPALIVE:
return vmwdt_keepalive();
}
-
return -EINVAL;
}
+static long vmwdt_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
+{
+ int rc;
+
+ mutex_lock(&vmwdt_mutex);
+ rc = __vmwdt_ioctl(cmd, arg);
+ mutex_unlock(&vmwdt_mutex);
+ return (long) rc;
+}
+
static ssize_t vmwdt_write(struct file *f, const char __user *buf,
size_t count, loff_t *ppos)
{
@@ -288,7 +293,7 @@ static struct notifier_block vmwdt_power_notifier = {
static const struct file_operations vmwdt_fops = {
.open = &vmwdt_open,
.release = &vmwdt_close,
- .ioctl = &vmwdt_ioctl,
+ .unlocked_ioctl = &vmwdt_ioctl,
.write = &vmwdt_write,
.owner = THIS_MODULE,
};
@@ -309,6 +314,10 @@ static int __init vmwdt_init(void)
ret = register_pm_notifier(&vmwdt_power_notifier);
if (ret)
return ret;
+ /*
+ * misc_register() has to be the last action in module_init(), because
+ * file operations will be available right after this.
+ */
ret = misc_register(&vmwdt_dev);
if (ret) {
unregister_pm_notifier(&vmwdt_power_notifier);
diff --git a/drivers/s390/cio/Makefile b/drivers/s390/cio/Makefile
index fa4c966..d033414 100644
--- a/drivers/s390/cio/Makefile
+++ b/drivers/s390/cio/Makefile
@@ -3,7 +3,7 @@
#
obj-y += airq.o blacklist.o chsc.o cio.o css.o chp.o idset.o isc.o \
- fcx.o itcw.o crw.o
+ fcx.o itcw.o crw.o ccwreq.o
ccw_device-objs += device.o device_fsm.o device_ops.o
ccw_device-objs += device_id.o device_pgid.o device_status.o
obj-y += ccw_device.o cmf.o
diff --git a/drivers/s390/cio/ccwreq.c b/drivers/s390/cio/ccwreq.c
new file mode 100644
index 0000000..9509e38
--- /dev/null
+++ b/drivers/s390/cio/ccwreq.c
@@ -0,0 +1,328 @@
+/*
+ * Handling of internal CCW device requests.
+ *
+ * Copyright IBM Corp. 2009
+ * Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
+ */
+
+#include <linux/types.h>
+#include <linux/err.h>
+#include <asm/ccwdev.h>
+#include <asm/cio.h>
+
+#include "io_sch.h"
+#include "cio.h"
+#include "device.h"
+#include "cio_debug.h"
+
+/**
+ * lpm_adjust - adjust path mask
+ * @lpm: path mask to adjust
+ * @mask: mask of available paths
+ *
+ * Shift @lpm right until @lpm and @mask have at least one bit in common or
+ * until @lpm is zero. Return the resulting lpm.
+ */
+int lpm_adjust(int lpm, int mask)
+{
+ while (lpm && ((lpm & mask) == 0))
+ lpm >>= 1;
+ return lpm;
+}
+
+/*
+ * Adjust path mask to use next path and reset retry count. Return resulting
+ * path mask.
+ */
+static u16 ccwreq_next_path(struct ccw_device *cdev)
+{
+ struct ccw_request *req = &cdev->private->req;
+
+ req->retries = req->maxretries;
+ req->mask = lpm_adjust(req->mask >>= 1, req->lpm);
+
+ return req->mask;
+}
+
+/*
+ * Clean up device state and report to callback.
+ */
+static void ccwreq_stop(struct ccw_device *cdev, int rc)
+{
+ struct subchannel *sch = to_subchannel(cdev->dev.parent);
+ struct ccw_request *req = &cdev->private->req;
+
+ if (req->done)
+ return;
+ req->done = 1;
+ ccw_device_set_timeout(cdev, 0);
+ memset(&cdev->private->irb, 0, sizeof(struct irb));
+ sch->lpm = sch->schib.pmcw.pam;
+ if (rc && rc != -ENODEV && req->drc)
+ rc = req->drc;
+ req->callback(cdev, req->data, rc);
+}
+
+/*
+ * (Re-)Start the operation until retries and paths are exhausted.
+ */
+static void ccwreq_do(struct ccw_device *cdev)
+{
+ struct ccw_request *req = &cdev->private->req;
+ struct subchannel *sch = to_subchannel(cdev->dev.parent);
+ struct ccw1 *cp = req->cp;
+ int rc = -EACCES;
+
+ while (req->mask) {
+ if (req->retries-- == 0) {
+ /* Retries exhausted, try next path. */
+ ccwreq_next_path(cdev);
+ continue;
+ }
+ /* Perform start function. */
+ sch->lpm = 0xff;
+ memset(&cdev->private->irb, 0, sizeof(struct irb));
+ rc = cio_start(sch, cp, (u8) req->mask);
+ if (rc == 0) {
+ /* I/O started successfully. */
+ ccw_device_set_timeout(cdev, req->timeout);
+ return;
+ }
+ if (rc == -ENODEV) {
+ /* Permanent device error. */
+ break;
+ }
+ if (rc == -EACCES) {
+ /* Permant path error. */
+ ccwreq_next_path(cdev);
+ continue;
+ }
+ /* Temporary improper status. */
+ rc = cio_clear(sch);
+ if (rc)
+ break;
+ return;
+ }
+ ccwreq_stop(cdev, rc);
+}
+
+/**
+ * ccw_request_start - perform I/O request
+ * @cdev: ccw device
+ *
+ * Perform the I/O request specified by cdev->req.
+ */
+void ccw_request_start(struct ccw_device *cdev)
+{
+ struct ccw_request *req = &cdev->private->req;
+
+ /* Try all paths twice to counter link flapping. */
+ req->mask = 0x8080;
+ req->retries = req->maxretries;
+ req->mask = lpm_adjust(req->mask, req->lpm);
+ req->drc = 0;
+ req->done = 0;
+ req->cancel = 0;
+ if (!req->mask)
+ goto out_nopath;
+ ccwreq_do(cdev);
+ return;
+
+out_nopath:
+ ccwreq_stop(cdev, -EACCES);
+}
+
+/**
+ * ccw_request_cancel - cancel running I/O request
+ * @cdev: ccw device
+ *
+ * Cancel the I/O request specified by cdev->req. Return non-zero if request
+ * has already finished, zero otherwise.
+ */
+int ccw_request_cancel(struct ccw_device *cdev)
+{
+ struct subchannel *sch = to_subchannel(cdev->dev.parent);
+ struct ccw_request *req = &cdev->private->req;
+ int rc;
+
+ if (req->done)
+ return 1;
+ req->cancel = 1;
+ rc = cio_clear(sch);
+ if (rc)
+ ccwreq_stop(cdev, rc);
+ return 0;
+}
+
+/*
+ * Return the status of the internal I/O started on the specified ccw device.
+ * Perform BASIC SENSE if required.
+ */
+static enum io_status ccwreq_status(struct ccw_device *cdev, struct irb *lcirb)
+{
+ struct irb *irb = &cdev->private->irb;
+ struct cmd_scsw *scsw = &irb->scsw.cmd;
+
+ /* Perform BASIC SENSE if needed. */
+ if (ccw_device_accumulate_and_sense(cdev, lcirb))
+ return IO_RUNNING;
+ /* Check for halt/clear interrupt. */
+ if (scsw->fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC))
+ return IO_KILLED;
+ /* Check for path error. */
+ if (scsw->cc == 3 || scsw->pno)
+ return IO_PATH_ERROR;
+ /* Handle BASIC SENSE data. */
+ if (irb->esw.esw0.erw.cons) {
+ CIO_TRACE_EVENT(2, "sensedata");
+ CIO_HEX_EVENT(2, &cdev->private->dev_id,
+ sizeof(struct ccw_dev_id));
+ CIO_HEX_EVENT(2, &cdev->private->irb.ecw, SENSE_MAX_COUNT);
+ /* Check for command reject. */
+ if (irb->ecw[0] & SNS0_CMD_REJECT)
+ return IO_REJECTED;
+ /* Assume that unexpected SENSE data implies an error. */
+ return IO_STATUS_ERROR;
+ }
+ /* Check for channel errors. */
+ if (scsw->cstat != 0)
+ return IO_STATUS_ERROR;
+ /* Check for device errors. */
+ if (scsw->dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END))
+ return IO_STATUS_ERROR;
+ /* Check for final state. */
+ if (!(scsw->dstat & DEV_STAT_DEV_END))
+ return IO_RUNNING;
+ /* Check for other improper status. */
+ if (scsw->cc == 1 && (scsw->stctl & SCSW_STCTL_ALERT_STATUS))
+ return IO_STATUS_ERROR;
+ return IO_DONE;
+}
+
+/*
+ * Log ccw request status.
+ */
+static void ccwreq_log_status(struct ccw_device *cdev, enum io_status status)
+{
+ struct ccw_request *req = &cdev->private->req;
+ struct {
+ struct ccw_dev_id dev_id;
+ u16 retries;
+ u8 lpm;
+ u8 status;
+ } __attribute__ ((packed)) data;
+ data.dev_id = cdev->private->dev_id;
+ data.retries = req->retries;
+ data.lpm = (u8) req->mask;
+ data.status = (u8) status;
+ CIO_TRACE_EVENT(2, "reqstat");
+ CIO_HEX_EVENT(2, &data, sizeof(data));
+}
+
+/**
+ * ccw_request_handler - interrupt handler for I/O request procedure.
+ * @cdev: ccw device
+ *
+ * Handle interrupt during I/O request procedure.
+ */
+void ccw_request_handler(struct ccw_device *cdev)
+{
+ struct ccw_request *req = &cdev->private->req;
+ struct irb *irb = (struct irb *) __LC_IRB;
+ enum io_status status;
+ int rc = -EOPNOTSUPP;
+
+ /* Check status of I/O request. */
+ status = ccwreq_status(cdev, irb);
+ if (req->filter)
+ status = req->filter(cdev, req->data, irb, status);
+ if (status != IO_RUNNING)
+ ccw_device_set_timeout(cdev, 0);
+ if (status != IO_DONE && status != IO_RUNNING)
+ ccwreq_log_status(cdev, status);
+ switch (status) {
+ case IO_DONE:
+ break;
+ case IO_RUNNING:
+ return;
+ case IO_REJECTED:
+ goto err;
+ case IO_PATH_ERROR:
+ goto out_next_path;
+ case IO_STATUS_ERROR:
+ goto out_restart;
+ case IO_KILLED:
+ /* Check if request was cancelled on purpose. */
+ if (req->cancel) {
+ rc = -EIO;
+ goto err;
+ }
+ goto out_restart;
+ }
+ /* Check back with request initiator. */
+ if (!req->check)
+ goto out;
+ switch (req->check(cdev, req->data)) {
+ case 0:
+ break;
+ case -EAGAIN:
+ goto out_restart;
+ case -EACCES:
+ goto out_next_path;
+ default:
+ goto err;
+ }
+out:
+ ccwreq_stop(cdev, 0);
+ return;
+
+out_next_path:
+ /* Try next path and restart I/O. */
+ if (!ccwreq_next_path(cdev)) {
+ rc = -EACCES;
+ goto err;
+ }
+out_restart:
+ /* Restart. */
+ ccwreq_do(cdev);
+ return;
+err:
+ ccwreq_stop(cdev, rc);
+}
+
+
+/**
+ * ccw_request_timeout - timeout handler for I/O request procedure
+ * @cdev: ccw device
+ *
+ * Handle timeout during I/O request procedure.
+ */
+void ccw_request_timeout(struct ccw_device *cdev)
+{
+ struct subchannel *sch = to_subchannel(cdev->dev.parent);
+ struct ccw_request *req = &cdev->private->req;
+ int rc;
+
+ if (!ccwreq_next_path(cdev)) {
+ /* set the final return code for this request */
+ req->drc = -ETIME;
+ }
+ rc = cio_clear(sch);
+ if (rc)
+ goto err;
+ return;
+
+err:
+ ccwreq_stop(cdev, rc);
+}
+
+/**
+ * ccw_request_notoper - notoper handler for I/O request procedure
+ * @cdev: ccw device
+ *
+ * Handle timeout during I/O request procedure.
+ */
+void ccw_request_notoper(struct ccw_device *cdev)
+{
+ ccwreq_stop(cdev, -ENODEV);
+}
diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c
index 8ab5160..c268a2e 100644
--- a/drivers/s390/cio/chp.c
+++ b/drivers/s390/cio/chp.c
@@ -65,7 +65,7 @@ static void set_chp_logically_online(struct chp_id chpid, int onoff)
chpid_to_chp(chpid)->state = onoff;
}
-/* On succes return 0 if channel-path is varied offline, 1 if it is varied
+/* On success return 0 if channel-path is varied offline, 1 if it is varied
* online. Return -ENODEV if channel-path is not registered. */
int chp_get_status(struct chp_id chpid)
{
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 138124f..126f240 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -618,6 +618,7 @@ void __irq_entry do_IRQ(struct pt_regs *regs)
old_regs = set_irq_regs(regs);
s390_idle_check();
irq_enter();
+ __get_cpu_var(s390_idle).nohz_delay = 1;
if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator)
/* Serve timer interrupts first. */
clock_comparator_work();
diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h
index 2e43558..bf7f80f 100644
--- a/drivers/s390/cio/cio.h
+++ b/drivers/s390/cio/cio.h
@@ -68,6 +68,11 @@ struct schib {
__u8 mda[4]; /* model dependent area */
} __attribute__ ((packed,aligned(4)));
+enum sch_todo {
+ SCH_TODO_NOTHING,
+ SCH_TODO_UNREG,
+};
+
/* subchannel data structure used by I/O subroutines */
struct subchannel {
struct subchannel_id schid;
@@ -95,7 +100,8 @@ struct subchannel {
struct device dev; /* entry in device tree */
struct css_driver *driver;
void *private; /* private per subchannel type data */
- struct work_struct work;
+ enum sch_todo todo;
+ struct work_struct todo_work;
struct schib_config config;
} __attribute__ ((aligned(8)));
diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c
index 30f5161..2985eb4 100644
--- a/drivers/s390/cio/cmf.c
+++ b/drivers/s390/cio/cmf.c
@@ -462,7 +462,7 @@ static struct cmb_area cmb_area = {
* 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.
+ * a reasonable value of 1024, or 32 kb of memory.
* Current kernels don't allow kmalloc with more than 128kb, so the
* maximum is 4096.
*/
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 91c2570..92ff88a 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -133,6 +133,8 @@ out:
return rc;
}
+static void css_sch_todo(struct work_struct *work);
+
static struct subchannel *
css_alloc_subchannel(struct subchannel_id schid)
{
@@ -147,6 +149,7 @@ css_alloc_subchannel(struct subchannel_id schid)
kfree(sch);
return ERR_PTR(ret);
}
+ INIT_WORK(&sch->todo_work, css_sch_todo);
return sch;
}
@@ -190,6 +193,51 @@ void css_sch_device_unregister(struct subchannel *sch)
}
EXPORT_SYMBOL_GPL(css_sch_device_unregister);
+static void css_sch_todo(struct work_struct *work)
+{
+ struct subchannel *sch;
+ enum sch_todo todo;
+
+ sch = container_of(work, struct subchannel, todo_work);
+ /* Find out todo. */
+ spin_lock_irq(sch->lock);
+ todo = sch->todo;
+ CIO_MSG_EVENT(4, "sch_todo: sch=0.%x.%04x, todo=%d\n", sch->schid.ssid,
+ sch->schid.sch_no, todo);
+ sch->todo = SCH_TODO_NOTHING;
+ spin_unlock_irq(sch->lock);
+ /* Perform todo. */
+ if (todo == SCH_TODO_UNREG)
+ css_sch_device_unregister(sch);
+ /* Release workqueue ref. */
+ put_device(&sch->dev);
+}
+
+/**
+ * css_sched_sch_todo - schedule a subchannel operation
+ * @sch: subchannel
+ * @todo: todo
+ *
+ * Schedule the operation identified by @todo to be performed on the slow path
+ * workqueue. Do nothing if another operation with higher priority is already
+ * scheduled. Needs to be called with subchannel lock held.
+ */
+void css_sched_sch_todo(struct subchannel *sch, enum sch_todo todo)
+{
+ CIO_MSG_EVENT(4, "sch_todo: sched sch=0.%x.%04x todo=%d\n",
+ sch->schid.ssid, sch->schid.sch_no, todo);
+ if (sch->todo >= todo)
+ return;
+ /* Get workqueue ref. */
+ if (!get_device(&sch->dev))
+ return;
+ sch->todo = todo;
+ if (!queue_work(slow_path_wq, &sch->todo_work)) {
+ /* Already queued, release workqueue ref. */
+ put_device(&sch->dev);
+ }
+}
+
static void ssd_from_pmcw(struct chsc_ssd_info *ssd, struct pmcw *pmcw)
{
int i;
@@ -376,8 +424,8 @@ static int css_evaluate_new_subchannel(struct subchannel_id schid, int slow)
/* Unusable - ignore. */
return 0;
}
- CIO_MSG_EVENT(4, "Evaluating schid 0.%x.%04x, event %d, unknown, "
- "slow path.\n", schid.ssid, schid.sch_no, CIO_OPER);
+ CIO_MSG_EVENT(4, "event: sch 0.%x.%04x, new\n", schid.ssid,
+ schid.sch_no);
return css_probe_device(schid);
}
@@ -394,6 +442,10 @@ static int css_evaluate_known_subchannel(struct subchannel *sch, int slow)
"Got subchannel machine check but "
"no sch_event handler provided.\n");
}
+ if (ret != 0 && ret != -EAGAIN) {
+ CIO_MSG_EVENT(2, "eval: sch 0.%x.%04x, rc=%d\n",
+ sch->schid.ssid, sch->schid.sch_no, ret);
+ }
return ret;
}
@@ -684,6 +736,7 @@ static int __init setup_css(int nr)
css->pseudo_subchannel->dev.parent = &css->device;
css->pseudo_subchannel->dev.release = css_subchannel_release;
dev_set_name(&css->pseudo_subchannel->dev, "defunct");
+ mutex_init(&css->pseudo_subchannel->reg_mutex);
ret = cio_create_sch_lock(css->pseudo_subchannel);
if (ret) {
kfree(css->pseudo_subchannel);
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h
index 68d6b0b..fe84b92 100644
--- a/drivers/s390/cio/css.h
+++ b/drivers/s390/cio/css.h
@@ -11,6 +11,8 @@
#include <asm/chpid.h>
#include <asm/schid.h>
+#include "cio.h"
+
/*
* path grouping stuff
*/
@@ -151,4 +153,5 @@ int css_sch_is_valid(struct schib *);
extern struct workqueue_struct *slow_path_wq;
void css_wait_for_slow_path(void);
+void css_sched_sch_todo(struct subchannel *sch, enum sch_todo todo);
#endif
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 2490b74..9fecfb4 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -7,6 +7,10 @@
* Cornelia Huck (cornelia.huck@de.ibm.com)
* Martin Schwidefsky (schwidefsky@de.ibm.com)
*/
+
+#define KMSG_COMPONENT "cio"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/spinlock.h>
@@ -299,53 +303,18 @@ int ccw_device_is_orphan(struct ccw_device *cdev)
static void ccw_device_unregister(struct ccw_device *cdev)
{
- if (test_and_clear_bit(1, &cdev->private->registered)) {
+ if (device_is_registered(&cdev->dev)) {
+ /* Undo device_add(). */
device_del(&cdev->dev);
+ }
+ if (cdev->private->flags.initialized) {
+ cdev->private->flags.initialized = 0;
/* Release reference from device_initialize(). */
put_device(&cdev->dev);
}
}
-static void ccw_device_remove_orphan_cb(struct work_struct *work)
-{
- struct ccw_device_private *priv;
- struct ccw_device *cdev;
-
- priv = container_of(work, struct ccw_device_private, kick_work);
- cdev = priv->cdev;
- ccw_device_unregister(cdev);
- /* Release cdev reference for workqueue processing. */
- put_device(&cdev->dev);
-}
-
-static void
-ccw_device_remove_disconnected(struct ccw_device *cdev)
-{
- unsigned long flags;
-
- /*
- * Forced offline in disconnected state means
- * 'throw away device'.
- */
- if (ccw_device_is_orphan(cdev)) {
- /*
- * Deregister ccw device.
- * Unfortunately, we cannot do this directly from the
- * attribute method.
- */
- /* Get cdev reference for workqueue processing. */
- if (!get_device(&cdev->dev))
- return;
- spin_lock_irqsave(cdev->ccwlock, flags);
- cdev->private->state = DEV_STATE_NOT_OPER;
- spin_unlock_irqrestore(cdev->ccwlock, flags);
- PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_remove_orphan_cb);
- queue_work(slow_path_wq, &cdev->private->kick_work);
- } else
- /* Deregister subchannel, which will kill the ccw device. */
- ccw_device_schedule_sch_unregister(cdev);
-}
+static void io_subchannel_quiesce(struct subchannel *);
/**
* ccw_device_set_offline() - disable a ccw device for I/O
@@ -360,7 +329,8 @@ ccw_device_remove_disconnected(struct ccw_device *cdev)
*/
int ccw_device_set_offline(struct ccw_device *cdev)
{
- int ret;
+ struct subchannel *sch;
+ int ret, state;
if (!cdev)
return -ENODEV;
@@ -374,6 +344,7 @@ int ccw_device_set_offline(struct ccw_device *cdev)
}
cdev->online = 0;
spin_lock_irq(cdev->ccwlock);
+ sch = to_subchannel(cdev->dev.parent);
/* Wait until a final state or DISCONNECTED is reached */
while (!dev_fsm_final_state(cdev) &&
cdev->private->state != DEV_STATE_DISCONNECTED) {
@@ -382,20 +353,37 @@ int ccw_device_set_offline(struct ccw_device *cdev)
cdev->private->state == DEV_STATE_DISCONNECTED));
spin_lock_irq(cdev->ccwlock);
}
- ret = ccw_device_offline(cdev);
- if (ret)
- goto error;
+ do {
+ ret = ccw_device_offline(cdev);
+ if (!ret)
+ break;
+ CIO_MSG_EVENT(0, "ccw_device_offline returned %d, device "
+ "0.%x.%04x\n", ret, cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno);
+ if (ret != -EBUSY)
+ goto error;
+ state = cdev->private->state;
+ spin_unlock_irq(cdev->ccwlock);
+ io_subchannel_quiesce(sch);
+ spin_lock_irq(cdev->ccwlock);
+ cdev->private->state = state;
+ } while (ret == -EBUSY);
spin_unlock_irq(cdev->ccwlock);
wait_event(cdev->private->wait_q, (dev_fsm_final_state(cdev) ||
cdev->private->state == DEV_STATE_DISCONNECTED));
+ /* Inform the user if set offline failed. */
+ if (cdev->private->state == DEV_STATE_BOXED) {
+ pr_warning("%s: The device entered boxed state while "
+ "being set offline\n", dev_name(&cdev->dev));
+ } else if (cdev->private->state == DEV_STATE_NOT_OPER) {
+ pr_warning("%s: The device stopped operating while "
+ "being set offline\n", dev_name(&cdev->dev));
+ }
/* Give up reference from ccw_device_set_online(). */
put_device(&cdev->dev);
return 0;
error:
- CIO_MSG_EVENT(0, "ccw_device_offline returned %d, device 0.%x.%04x\n",
- ret, cdev->private->dev_id.ssid,
- cdev->private->dev_id.devno);
cdev->private->state = DEV_STATE_OFFLINE;
dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
spin_unlock_irq(cdev->ccwlock);
@@ -448,6 +436,16 @@ int ccw_device_set_online(struct ccw_device *cdev)
if ((cdev->private->state != DEV_STATE_ONLINE) &&
(cdev->private->state != DEV_STATE_W4SENSE)) {
spin_unlock_irq(cdev->ccwlock);
+ /* Inform the user that set online failed. */
+ if (cdev->private->state == DEV_STATE_BOXED) {
+ pr_warning("%s: Setting the device online failed "
+ "because it is boxed\n",
+ dev_name(&cdev->dev));
+ } else if (cdev->private->state == DEV_STATE_NOT_OPER) {
+ pr_warning("%s: Setting the device online failed "
+ "because it is not operational\n",
+ dev_name(&cdev->dev));
+ }
/* Give up online reference since onlining failed. */
put_device(&cdev->dev);
return -ENODEV;
@@ -494,27 +492,22 @@ error:
static int online_store_handle_offline(struct ccw_device *cdev)
{
- if (cdev->private->state == DEV_STATE_DISCONNECTED)
- ccw_device_remove_disconnected(cdev);
- else if (cdev->online && cdev->drv && cdev->drv->set_offline)
+ if (cdev->private->state == DEV_STATE_DISCONNECTED) {
+ spin_lock_irq(cdev->ccwlock);
+ ccw_device_sched_todo(cdev, CDEV_TODO_UNREG_EVAL);
+ spin_unlock_irq(cdev->ccwlock);
+ } else if (cdev->online && cdev->drv && cdev->drv->set_offline)
return ccw_device_set_offline(cdev);
return 0;
}
static int online_store_recog_and_online(struct ccw_device *cdev)
{
- int ret;
-
/* Do device recognition, if needed. */
if (cdev->private->state == DEV_STATE_BOXED) {
- ret = ccw_device_recognition(cdev);
- if (ret) {
- CIO_MSG_EVENT(0, "Couldn't start recognition "
- "for device 0.%x.%04x (ret=%d)\n",
- cdev->private->dev_id.ssid,
- cdev->private->dev_id.devno, ret);
- return ret;
- }
+ spin_lock_irq(cdev->ccwlock);
+ ccw_device_recognition(cdev);
+ spin_unlock_irq(cdev->ccwlock);
wait_event(cdev->private->wait_q,
cdev->private->flags.recog_done);
if (cdev->private->state != DEV_STATE_OFFLINE)
@@ -553,11 +546,10 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr,
int force, ret;
unsigned long i;
- if ((cdev->private->state != DEV_STATE_OFFLINE &&
- cdev->private->state != DEV_STATE_ONLINE &&
- cdev->private->state != DEV_STATE_BOXED &&
- cdev->private->state != DEV_STATE_DISCONNECTED) ||
- atomic_cmpxchg(&cdev->private->onoff, 0, 1) != 0)
+ if (!dev_fsm_final_state(cdev) &&
+ cdev->private->state != DEV_STATE_DISCONNECTED)
+ return -EAGAIN;
+ if (atomic_cmpxchg(&cdev->private->onoff, 0, 1) != 0)
return -EAGAIN;
if (cdev->drv && !try_module_get(cdev->drv->owner)) {
@@ -665,81 +657,31 @@ static int ccw_device_register(struct ccw_device *cdev)
cdev->private->dev_id.devno);
if (ret)
return ret;
- ret = device_add(dev);
- if (ret)
- return ret;
-
- set_bit(1, &cdev->private->registered);
- return ret;
+ return device_add(dev);
}
-struct match_data {
- struct ccw_dev_id dev_id;
- struct ccw_device * sibling;
-};
-
-static int
-match_devno(struct device * dev, void * data)
-{
- struct match_data * d = data;
- struct ccw_device * cdev;
-
- cdev = to_ccwdev(dev);
- if ((cdev->private->state == DEV_STATE_DISCONNECTED) &&
- !ccw_device_is_orphan(cdev) &&
- ccw_dev_id_is_equal(&cdev->private->dev_id, &d->dev_id) &&
- (cdev != d->sibling))
- return 1;
- return 0;
-}
-
-static struct ccw_device * get_disc_ccwdev_by_dev_id(struct ccw_dev_id *dev_id,
- struct ccw_device *sibling)
-{
- struct device *dev;
- struct match_data data;
-
- data.dev_id = *dev_id;
- data.sibling = sibling;
- dev = bus_find_device(&ccw_bus_type, NULL, &data, match_devno);
-
- return dev ? to_ccwdev(dev) : NULL;
-}
-
-static int match_orphan(struct device *dev, void *data)
+static int match_dev_id(struct device *dev, void *data)
{
- struct ccw_dev_id *dev_id;
- struct ccw_device *cdev;
+ struct ccw_device *cdev = to_ccwdev(dev);
+ struct ccw_dev_id *dev_id = data;
- dev_id = data;
- cdev = to_ccwdev(dev);
return ccw_dev_id_is_equal(&cdev->private->dev_id, dev_id);
}
-static struct ccw_device *
-get_orphaned_ccwdev_by_dev_id(struct channel_subsystem *css,
- struct ccw_dev_id *dev_id)
+static struct ccw_device *get_ccwdev_by_dev_id(struct ccw_dev_id *dev_id)
{
struct device *dev;
- dev = device_find_child(&css->pseudo_subchannel->dev, dev_id,
- match_orphan);
+ dev = bus_find_device(&ccw_bus_type, NULL, dev_id, match_dev_id);
return dev ? to_ccwdev(dev) : NULL;
}
-void ccw_device_do_unbind_bind(struct work_struct *work)
+static void ccw_device_do_unbind_bind(struct ccw_device *cdev)
{
- struct ccw_device_private *priv;
- struct ccw_device *cdev;
- struct subchannel *sch;
int ret;
- priv = container_of(work, struct ccw_device_private, kick_work);
- cdev = priv->cdev;
- sch = to_subchannel(cdev->dev.parent);
-
- if (test_bit(1, &cdev->private->registered)) {
+ if (device_is_registered(&cdev->dev)) {
device_release_driver(&cdev->dev);
ret = device_attach(&cdev->dev);
WARN_ON(ret == -ENODEV);
@@ -773,6 +715,8 @@ static struct ccw_device * io_subchannel_allocate_dev(struct subchannel *sch)
return ERR_PTR(-ENOMEM);
}
+static void ccw_device_todo(struct work_struct *work);
+
static int io_subchannel_initialize_dev(struct subchannel *sch,
struct ccw_device *cdev)
{
@@ -780,7 +724,7 @@ static int io_subchannel_initialize_dev(struct subchannel *sch,
atomic_set(&cdev->private->onoff, 0);
cdev->dev.parent = &sch->dev;
cdev->dev.release = ccw_device_release;
- INIT_WORK(&cdev->private->kick_work, NULL);
+ INIT_WORK(&cdev->private->todo_work, ccw_device_todo);
cdev->dev.groups = ccwdev_attr_groups;
/* Do first half of device_register. */
device_initialize(&cdev->dev);
@@ -789,6 +733,7 @@ static int io_subchannel_initialize_dev(struct subchannel *sch,
put_device(&cdev->dev);
return -ENODEV;
}
+ cdev->private->flags.initialized = 1;
return 0;
}
@@ -806,76 +751,7 @@ static struct ccw_device * io_subchannel_create_ccwdev(struct subchannel *sch)
return cdev;
}
-static int io_subchannel_recog(struct ccw_device *, struct subchannel *);
-
-static void sch_attach_device(struct subchannel *sch,
- struct ccw_device *cdev)
-{
- css_update_ssd_info(sch);
- spin_lock_irq(sch->lock);
- sch_set_cdev(sch, cdev);
- cdev->private->schid = sch->schid;
- cdev->ccwlock = sch->lock;
- ccw_device_trigger_reprobe(cdev);
- spin_unlock_irq(sch->lock);
-}
-
-static void sch_attach_disconnected_device(struct subchannel *sch,
- struct ccw_device *cdev)
-{
- struct subchannel *other_sch;
- int ret;
-
- /* Get reference for new parent. */
- if (!get_device(&sch->dev))
- return;
- other_sch = to_subchannel(cdev->dev.parent);
- /* Note: device_move() changes cdev->dev.parent */
- ret = device_move(&cdev->dev, &sch->dev, DPM_ORDER_PARENT_BEFORE_DEV);
- if (ret) {
- CIO_MSG_EVENT(0, "Moving disconnected device 0.%x.%04x failed "
- "(ret=%d)!\n", cdev->private->dev_id.ssid,
- cdev->private->dev_id.devno, ret);
- /* Put reference for new parent. */
- put_device(&sch->dev);
- return;
- }
- sch_set_cdev(other_sch, NULL);
- /* No need to keep a subchannel without ccw device around. */
- css_sch_device_unregister(other_sch);
- sch_attach_device(sch, cdev);
- /* Put reference for old parent. */
- put_device(&other_sch->dev);
-}
-
-static void sch_attach_orphaned_device(struct subchannel *sch,
- struct ccw_device *cdev)
-{
- int ret;
- struct subchannel *pseudo_sch;
-
- /* Get reference for new parent. */
- if (!get_device(&sch->dev))
- return;
- pseudo_sch = to_subchannel(cdev->dev.parent);
- /*
- * Try to move the ccw device to its new subchannel.
- * Note: device_move() changes cdev->dev.parent
- */
- ret = device_move(&cdev->dev, &sch->dev, DPM_ORDER_PARENT_BEFORE_DEV);
- if (ret) {
- CIO_MSG_EVENT(0, "Moving device 0.%x.%04x from orphanage "
- "failed (ret=%d)!\n",
- cdev->private->dev_id.ssid,
- cdev->private->dev_id.devno, ret);
- /* Put reference for new parent. */
- put_device(&sch->dev);
- return;
- }
- sch_attach_device(sch, cdev);
- /* Put reference on pseudo subchannel. */
- put_device(&pseudo_sch->dev);
-}
+static void io_subchannel_recog(struct ccw_device *, struct subchannel *);
static void sch_create_and_recog_new_device(struct subchannel *sch)
{
@@ -888,100 +764,19 @@ static void sch_create_and_recog_new_device(struct subchannel *sch)
css_sch_device_unregister(sch);
return;
}
- spin_lock_irq(sch->lock);
- sch_set_cdev(sch, cdev);
- spin_unlock_irq(sch->lock);
/* Start recognition for the new ccw device. */
- if (io_subchannel_recog(cdev, sch)) {
- spin_lock_irq(sch->lock);
- sch_set_cdev(sch, NULL);
- spin_unlock_irq(sch->lock);
- css_sch_device_unregister(sch);
- /* Put reference from io_subchannel_create_ccwdev(). */
- put_device(&sch->dev);
- /* Give up initial reference. */
- put_device(&cdev->dev);
- }
-}
-
-
-void ccw_device_move_to_orphanage(struct work_struct *work)
-{
- struct ccw_device_private *priv;
- struct ccw_device *cdev;
- struct ccw_device *replacing_cdev;
- struct subchannel *sch;
- int ret;
- struct channel_subsystem *css;
- struct ccw_dev_id dev_id;
-
- priv = container_of(work, struct ccw_device_private, kick_work);
- cdev = priv->cdev;
- sch = to_subchannel(cdev->dev.parent);
- css = to_css(sch->dev.parent);
- dev_id.devno = sch->schib.pmcw.dev;
- dev_id.ssid = sch->schid.ssid;
-
- /* Increase refcount for pseudo subchannel. */
- get_device(&css->pseudo_subchannel->dev);
- /*
- * Move the orphaned ccw device to the orphanage so the replacing
- * ccw device can take its place on the subchannel.
- * Note: device_move() changes cdev->dev.parent
- */
- ret = device_move(&cdev->dev, &css->pseudo_subchannel->dev,
- DPM_ORDER_NONE);
- if (ret) {
- CIO_MSG_EVENT(0, "Moving device 0.%x.%04x to orphanage failed "
- "(ret=%d)!\n", cdev->private->dev_id.ssid,
- cdev->private->dev_id.devno, ret);
- /* Decrease refcount for pseudo subchannel again. */
- put_device(&css->pseudo_subchannel->dev);
- return;
- }
- cdev->ccwlock = css->pseudo_subchannel->lock;
- /*
- * Search for the replacing ccw device
- * - among the disconnected devices
- * - in the orphanage
- */
- replacing_cdev = get_disc_ccwdev_by_dev_id(&dev_id, cdev);
- if (replacing_cdev) {
- sch_attach_disconnected_device(sch, replacing_cdev);
- /* Release reference from get_disc_ccwdev_by_dev_id() */
- put_device(&replacing_cdev->dev);
- /* Release reference of subchannel from old cdev. */
- put_device(&sch->dev);
- return;
- }
- replacing_cdev = get_orphaned_ccwdev_by_dev_id(css, &dev_id);
- if (replacing_cdev) {
- sch_attach_orphaned_device(sch, replacing_cdev);
- /* Release reference from get_orphaned_ccwdev_by_dev_id() */
- put_device(&replacing_cdev->dev);
- /* Release reference of subchannel from old cdev. */
- put_device(&sch->dev);
- return;
- }
- sch_create_and_recog_new_device(sch);
- /* Release reference of subchannel from old cdev. */
- put_device(&sch->dev);
+ io_subchannel_recog(cdev, sch);
}
/*
* Register recognized device.
*/
-static void
-io_subchannel_register(struct work_struct *work)
+static void io_subchannel_register(struct ccw_device *cdev)
{
- 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;
sch = to_subchannel(cdev->dev.parent);
/*
* Check if subchannel is still registered. It may have become
@@ -1033,41 +828,23 @@ out:
cdev->private->flags.recog_done = 1;
wake_up(&cdev->private->wait_q);
out_err:
- /* Release reference for workqueue processing. */
- put_device(&cdev->dev);
if (atomic_dec_and_test(&ccw_device_init_count))
wake_up(&ccw_device_init_wq);
}
-static void ccw_device_call_sch_unregister(struct work_struct *work)
+static void ccw_device_call_sch_unregister(struct ccw_device *cdev)
{
- struct ccw_device_private *priv;
- struct ccw_device *cdev;
struct subchannel *sch;
- priv = container_of(work, struct ccw_device_private, kick_work);
- cdev = priv->cdev;
/* Get subchannel reference for local processing. */
if (!get_device(cdev->dev.parent))
return;
sch = to_subchannel(cdev->dev.parent);
css_sch_device_unregister(sch);
- /* Release cdev reference for workqueue processing.*/
- put_device(&cdev->dev);
/* Release subchannel reference for local processing. */
put_device(&sch->dev);
}
-void ccw_device_schedule_sch_unregister(struct ccw_device *cdev)
-{
- /* Get cdev reference for workqueue processing. */
- if (!get_device(&cdev->dev))
- return;
- PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_call_sch_unregister);
- queue_work(slow_path_wq, &cdev->private->kick_work);
-}
-
/*
* subchannel recognition done. Called from the state machine.
*/
@@ -1083,7 +860,8 @@ io_subchannel_recog_done(struct ccw_device *cdev)
/* Device did not respond in time. */
case DEV_STATE_NOT_OPER:
cdev->private->flags.recog_done = 1;
- ccw_device_schedule_sch_unregister(cdev);
+ /* Remove device found not operational. */
+ ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
if (atomic_dec_and_test(&ccw_device_init_count))
wake_up(&ccw_device_init_wq);
break;
@@ -1092,22 +870,15 @@ io_subchannel_recog_done(struct ccw_device *cdev)
* We can't register the device in interrupt context so
* we schedule a work item.
*/
- if (!get_device(&cdev->dev))
- break;
- PREPARE_WORK(&cdev->private->kick_work,
- io_subchannel_register);
- queue_work(slow_path_wq, &cdev->private->kick_work);
+ ccw_device_sched_todo(cdev, CDEV_TODO_REGISTER);
break;
}
}
-static int
-io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch)
+static void io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch)
{
- int rc;
struct ccw_device_private *priv;
- sch_set_cdev(sch, cdev);
cdev->ccwlock = sch->lock;
/* Init private data. */
@@ -1125,62 +896,81 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch)
/* Start async. device sensing. */
spin_lock_irq(sch->lock);
- rc = ccw_device_recognition(cdev);
+ sch_set_cdev(sch, cdev);
+ ccw_device_recognition(cdev);
spin_unlock_irq(sch->lock);
- if (rc) {
- if (atomic_dec_and_test(&ccw_device_init_count))
- wake_up(&ccw_device_init_wq);
- }
- return rc;
}
-static void ccw_device_move_to_sch(struct work_struct *work)
+static int ccw_device_move_to_sch(struct ccw_device *cdev,
+ struct subchannel *sch)
{
- struct ccw_device_private *priv;
- int rc;
- struct subchannel *sch;
- struct ccw_device *cdev;
- struct subchannel *former_parent;
+ struct subchannel *old_sch;
+ int rc, old_enabled = 0;
- priv = container_of(work, struct ccw_device_private, kick_work);
- sch = priv->sch;
- cdev = priv->cdev;
- former_parent = to_subchannel(cdev->dev.parent);
- /* Get reference for new parent. */
+ old_sch = to_subchannel(cdev->dev.parent);
+ /* Obtain child reference for new parent. */
if (!get_device(&sch->dev))
- return;
+ return -ENODEV;
+
+ if (!sch_is_pseudo_sch(old_sch)) {
+ spin_lock_irq(old_sch->lock);
+ old_enabled = old_sch->schib.pmcw.ena;
+ rc = 0;
+ if (old_enabled)
+ rc = cio_disable_subchannel(old_sch);
+ spin_unlock_irq(old_sch->lock);
+ if (rc == -EBUSY) {
+ /* Release child reference for new parent. */
+ put_device(&sch->dev);
+ return rc;
+ }
+ }
+
mutex_lock(&sch->reg_mutex);
- /*
- * Try to move the ccw device to its new subchannel.
- * Note: device_move() changes cdev->dev.parent
- */
rc = device_move(&cdev->dev, &sch->dev, DPM_ORDER_PARENT_BEFORE_DEV);
mutex_unlock(&sch->reg_mutex);
if (rc) {
- CIO_MSG_EVENT(0, "Moving device 0.%x.%04x to subchannel "
- "0.%x.%04x failed (ret=%d)!\n",
+ CIO_MSG_EVENT(0, "device_move(0.%x.%04x,0.%x.%04x)=%d\n",
cdev->private->dev_id.ssid,
cdev->private->dev_id.devno, sch->schid.ssid,
- sch->schid.sch_no, rc);
- css_sch_device_unregister(sch);
- /* Put reference for new parent again. */
+ sch->schib.pmcw.dev, rc);
+ if (old_enabled) {
+ /* Try to reenable the old subchannel. */
+ spin_lock_irq(old_sch->lock);
+ cio_enable_subchannel(old_sch, (u32)(addr_t)old_sch);
+ spin_unlock_irq(old_sch->lock);
+ }
+ /* Release child reference for new parent. */
put_device(&sch->dev);
- goto out;
+ return rc;
}
- if (!sch_is_pseudo_sch(former_parent)) {
- spin_lock_irq(former_parent->lock);
- sch_set_cdev(former_parent, NULL);
- spin_unlock_irq(former_parent->lock);
- css_sch_device_unregister(former_parent);
- /* Reset intparm to zeroes. */
- former_parent->config.intparm = 0;
- cio_commit_config(former_parent);
+ /* Clean up old subchannel. */
+ if (!sch_is_pseudo_sch(old_sch)) {
+ spin_lock_irq(old_sch->lock);
+ sch_set_cdev(old_sch, NULL);
+ spin_unlock_irq(old_sch->lock);
+ css_schedule_eval(old_sch->schid);
}
- sch_attach_device(sch, cdev);
-out:
- /* Put reference for old parent. */
- put_device(&former_parent->dev);
- put_device(&cdev->dev);
+ /* Release child reference for old parent. */
+ put_device(&old_sch->dev);
+ /* Initialize new subchannel. */
+ spin_lock_irq(sch->lock);
+ cdev->private->schid = sch->schid;
+ cdev->ccwlock = sch->lock;
+ if (!sch_is_pseudo_sch(sch))
+ sch_set_cdev(sch, cdev);
+ spin_unlock_irq(sch->lock);
+ if (!sch_is_pseudo_sch(sch))
+ css_update_ssd_info(sch);
+ return 0;
+}
+
+static int ccw_device_move_to_orph(struct ccw_device *cdev)
+{
+ struct subchannel *sch = to_subchannel(cdev->dev.parent);
+ struct channel_subsystem *css = to_css(sch->dev.parent);
+
+ return ccw_device_move_to_sch(cdev, css->pseudo_subchannel);
}
static void io_subchannel_irq(struct subchannel *sch)
@@ -1199,9 +989,6 @@ void io_subchannel_init_config(struct subchannel *sch)
{
memset(&sch->config, 0, sizeof(sch->config));
sch->config.csense = 1;
- /* Use subchannel mp mode when there is more than 1 installed CHPID. */
- if ((sch->schib.pmcw.pim & (sch->schib.pmcw.pim - 1)) != 0)
- sch->config.mp = 1;
}
static void io_subchannel_init_fields(struct subchannel *sch)
@@ -1222,23 +1009,6 @@ static void io_subchannel_init_fields(struct subchannel *sch)
io_subchannel_init_config(sch);
}
-static void io_subchannel_do_unreg(struct work_struct *work)
-{
- struct subchannel *sch;
-
- sch = container_of(work, struct subchannel, work);
- css_sch_device_unregister(sch);
- put_device(&sch->dev);
-}
-
-/* Schedule unregister if we have no cdev. */
-static void io_subchannel_schedule_removal(struct subchannel *sch)
-{
- get_device(&sch->dev);
- INIT_WORK(&sch->work, io_subchannel_do_unreg);
- queue_work(slow_path_wq, &sch->work);
-}
-
/*
* Note: We always return 0 so that we bind to the device even on error.
* This is needed so that our remove function is called on unregister.
@@ -1247,8 +1017,6 @@ static int io_subchannel_probe(struct subchannel *sch)
{
struct ccw_device *cdev;
int rc;
- unsigned long flags;
- struct ccw_dev_id dev_id;
if (cio_is_console(sch->schid)) {
rc = sysfs_create_group(&sch->dev.kobj,
@@ -1268,6 +1036,7 @@ static int io_subchannel_probe(struct subchannel *sch)
cdev = sch_get_cdev(sch);
cdev->dev.groups = ccwdev_attr_groups;
device_initialize(&cdev->dev);
+ cdev->private->flags.initialized = 1;
ccw_device_register(cdev);
/*
* Check if the device is already online. If it is
@@ -1292,44 +1061,14 @@ static int io_subchannel_probe(struct subchannel *sch)
sch->private = kzalloc(sizeof(struct io_subchannel_private),
GFP_KERNEL | GFP_DMA);
if (!sch->private)
- goto out_err;
- /*
- * First check if a fitting device may be found amongst the
- * disconnected devices or in the orphanage.
- */
- dev_id.devno = sch->schib.pmcw.dev;
- dev_id.ssid = sch->schid.ssid;
- cdev = get_disc_ccwdev_by_dev_id(&dev_id, NULL);
- if (!cdev)
- cdev = get_orphaned_ccwdev_by_dev_id(to_css(sch->dev.parent),
- &dev_id);
- if (cdev) {
- /*
- * Schedule moving the device until when we have a registered
- * subchannel to move to and succeed the probe. We can
- * unregister later again, when the probe is through.
- */
- cdev->private->sch = sch;
- PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_move_to_sch);
- queue_work(slow_path_wq, &cdev->private->kick_work);
- return 0;
- }
- cdev = io_subchannel_create_ccwdev(sch);
- if (IS_ERR(cdev))
- goto out_err;
- rc = io_subchannel_recog(cdev, sch);
- if (rc) {
- spin_lock_irqsave(sch->lock, flags);
- io_subchannel_recog_done(cdev);
- spin_unlock_irqrestore(sch->lock, flags);
- }
+ goto out_schedule;
+ css_schedule_eval(sch->schid);
return 0;
-out_err:
- kfree(sch->private);
- sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group);
+
out_schedule:
- io_subchannel_schedule_removal(sch);
+ spin_lock_irq(sch->lock);
+ css_sched_sch_todo(sch, SCH_TODO_UNREG);
+ spin_unlock_irq(sch->lock);
return 0;
}
@@ -1337,32 +1076,23 @@ static int
io_subchannel_remove (struct subchannel *sch)
{
struct ccw_device *cdev;
- unsigned long flags;
cdev = sch_get_cdev(sch);
if (!cdev)
- return 0;
+ goto out_free;
+ io_subchannel_quiesce(sch);
/* Set ccw device to not operational and drop reference. */
- spin_lock_irqsave(cdev->ccwlock, flags);
+ spin_lock_irq(cdev->ccwlock);
sch_set_cdev(sch, NULL);
cdev->private->state = DEV_STATE_NOT_OPER;
- spin_unlock_irqrestore(cdev->ccwlock, flags);
+ spin_unlock_irq(cdev->ccwlock);
ccw_device_unregister(cdev);
+out_free:
kfree(sch->private);
sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group);
return 0;
}
-static int io_subchannel_notify(struct subchannel *sch, int event)
-{
- struct ccw_device *cdev;
-
- cdev = sch_get_cdev(sch);
- if (!cdev)
- return 0;
- return ccw_device_notify(cdev, event);
-}
-
static void io_subchannel_verify(struct subchannel *sch)
{
struct ccw_device *cdev;
@@ -1372,36 +1102,6 @@ static void io_subchannel_verify(struct subchannel *sch)
dev_fsm_event(cdev, DEV_EVENT_VERIFY);
}
-static int check_for_io_on_path(struct subchannel *sch, int mask)
-{
- if (cio_update_schib(sch))
- return 0;
- if (scsw_actl(&sch->schib.scsw) && sch->schib.pmcw.lpum == mask)
- return 1;
- return 0;
-}
-
-static void terminate_internal_io(struct subchannel *sch,
- struct ccw_device *cdev)
-{
- if (cio_clear(sch)) {
- /* Recheck device in case clear failed. */
- sch->lpm = 0;
- if (cdev->online)
- dev_fsm_event(cdev, DEV_EVENT_VERIFY);
- else
- css_schedule_eval(sch->schid);
- return;
- }
- cdev->private->state = DEV_STATE_CLEAR_VERIFY;
- /* Request retry of internal operation. */
- cdev->private->flags.intretry = 1;
- /* Call handler. */
- if (cdev->handler)
- cdev->handler(cdev, cdev->private->intparm,
- ERR_PTR(-EIO));
-}
-
static void io_subchannel_terminate_path(struct subchannel *sch, u8 mask)
{
struct ccw_device *cdev;
@@ -1409,18 +1109,24 @@ static void io_subchannel_terminate_path(struct subchannel *sch, u8 mask)
cdev = sch_get_cdev(sch);
if (!cdev)
return;
- if (check_for_io_on_path(sch, mask)) {
- if (cdev->private->state == DEV_STATE_ONLINE)
- ccw_device_kill_io(cdev);
- else {
- terminate_internal_io(sch, cdev);
- /* Re-start path verification. */
- dev_fsm_event(cdev, DEV_EVENT_VERIFY);
- }
- } else
- /* trigger path verification. */
- dev_fsm_event(cdev, DEV_EVENT_VERIFY);
+ if (cio_update_schib(sch))
+ goto err;
+ /* Check for I/O on path. */
+ if (scsw_actl(&sch->schib.scsw) == 0 || sch->schib.pmcw.lpum != mask)
+ goto out;
+ if (cdev->private->state == DEV_STATE_ONLINE) {
+ ccw_device_kill_io(cdev);
+ goto out;
+ }
+ if (cio_clear(sch))
+ goto err;
+out:
+ /* Trigger path verification. */
+ dev_fsm_event(cdev, DEV_EVENT_VERIFY);
+ return;
+err:
+ dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
}
static int io_subchannel_chp_event(struct subchannel *sch,
@@ -1457,46 +1163,41 @@ static int io_subchannel_chp_event(struct subchannel *sch,
return 0;
}
-static void
-io_subchannel_shutdown(struct subchannel *sch)
+static void io_subchannel_quiesce(struct subchannel *sch)
{
struct ccw_device *cdev;
int ret;
+ spin_lock_irq(sch->lock);
cdev = sch_get_cdev(sch);
-
if (cio_is_console(sch->schid))
- return;
+ goto out_unlock;
if (!sch->schib.pmcw.ena)
- /* Nothing to do. */
- return;
+ goto out_unlock;
ret = cio_disable_subchannel(sch);
if (ret != -EBUSY)
- /* Subchannel is disabled, we're done. */
- return;
- cdev->private->state = DEV_STATE_QUIESCE;
+ goto out_unlock;
if (cdev->handler)
- cdev->handler(cdev, cdev->private->intparm,
- ERR_PTR(-EIO));
- ret = ccw_device_cancel_halt_clear(cdev);
- if (ret == -EBUSY) {
- ccw_device_set_timeout(cdev, HZ/10);
- wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
+ cdev->handler(cdev, cdev->private->intparm, ERR_PTR(-EIO));
+ while (ret == -EBUSY) {
+ cdev->private->state = DEV_STATE_QUIESCE;
+ ret = ccw_device_cancel_halt_clear(cdev);
+ if (ret == -EBUSY) {
+ ccw_device_set_timeout(cdev, HZ/10);
+ spin_unlock_irq(sch->lock);
+ wait_event(cdev->private->wait_q,
+ cdev->private->state != DEV_STATE_QUIESCE);
+ spin_lock_irq(sch->lock);
+ }
+ ret = cio_disable_subchannel(sch);
}
- cio_disable_subchannel(sch);
+out_unlock:
+ spin_unlock_irq(sch->lock);
}
-static int io_subchannel_get_status(struct subchannel *sch)
+static void io_subchannel_shutdown(struct subchannel *sch)
{
- struct schib schib;
-
- if (stsch(sch->schid, &schib) || !schib.pmcw.dnv)
- return CIO_GONE;
- if (sch->schib.pmcw.dnv && (schib.pmcw.dev != sch->schib.pmcw.dev))
- return CIO_REVALIDATE;
- if (!sch->lpm)
- return CIO_NO_PATH;
- return CIO_OPER;
+ io_subchannel_quiesce(sch);
}
static int device_is_disconnected(struct ccw_device *cdev)
@@ -1575,20 +1276,16 @@ static void ccw_device_schedule_recovery(void)
static int purge_fn(struct device *dev, void *data)
{
struct ccw_device *cdev = to_ccwdev(dev);
- struct ccw_device_private *priv = cdev->private;
- int unreg;
+ struct ccw_dev_id *id = &cdev->private->dev_id;
spin_lock_irq(cdev->ccwlock);
- unreg = is_blacklisted(priv->dev_id.ssid, priv->dev_id.devno) &&
- (priv->state == DEV_STATE_OFFLINE);
+ if (is_blacklisted(id->ssid, id->devno) &&
+ (cdev->private->state == DEV_STATE_OFFLINE)) {
+ CIO_MSG_EVENT(3, "ccw: purging 0.%x.%04x\n", id->ssid,
+ id->devno);
+ ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
+ }
spin_unlock_irq(cdev->ccwlock);
- if (!unreg)
- goto out;
- CIO_MSG_EVENT(3, "ccw: purging 0.%x.%04x\n", priv->dev_id.ssid,
- priv->dev_id.devno);
- ccw_device_schedule_sch_unregister(cdev);
-
-out:
/* Abort loop in case of pending signal. */
if (signal_pending(current))
return -EINTR;
@@ -1630,91 +1327,169 @@ void ccw_device_set_notoper(struct ccw_device *cdev)
cdev->private->state = DEV_STATE_NOT_OPER;
}
-static int io_subchannel_sch_event(struct subchannel *sch, int slow)
+enum io_sch_action {
+ IO_SCH_UNREG,
+ IO_SCH_ORPH_UNREG,
+ IO_SCH_ATTACH,
+ IO_SCH_UNREG_ATTACH,
+ IO_SCH_ORPH_ATTACH,
+ IO_SCH_REPROBE,
+ IO_SCH_VERIFY,
+ IO_SCH_DISC,
+ IO_SCH_NOP,
+};
+
+static enum io_sch_action sch_get_action(struct subchannel *sch)
+{
+ struct ccw_device *cdev;
+
+ cdev = sch_get_cdev(sch);
+ if (cio_update_schib(sch)) {
+ /* Not operational. */
+ if (!cdev)
+ return IO_SCH_UNREG;
+ if (!ccw_device_notify(cdev, CIO_GONE))
+ return IO_SCH_UNREG;
+ return IO_SCH_ORPH_UNREG;
+ }
+ /* Operational. */
+ if (!cdev)
+ return IO_SCH_ATTACH;
+ if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) {
+ if (!ccw_device_notify(cdev, CIO_GONE))
+ return IO_SCH_UNREG_ATTACH;
+ return IO_SCH_ORPH_ATTACH;
+ }
+ if ((sch->schib.pmcw.pam & sch->opm) == 0) {
+ if (!ccw_device_notify(cdev, CIO_NO_PATH))
+ return IO_SCH_UNREG;
+ return IO_SCH_DISC;
+ }
+ if (device_is_disconnected(cdev))
+ return IO_SCH_REPROBE;
+ if (cdev->online)
+ return IO_SCH_VERIFY;
+ return IO_SCH_NOP;
+}
+
+/**
+ * io_subchannel_sch_event - process subchannel event
+ * @sch: subchannel
+ * @process: non-zero if function is called in process context
+ *
+ * An unspecified event occurred for this subchannel. Adjust data according
+ * to the current operational state of the subchannel and device. Return
+ * zero when the event has been handled sufficiently or -EAGAIN when this
+ * function should be called again in process context.
+ */
+static int io_subchannel_sch_event(struct subchannel *sch, int process)
{
- int event, ret, disc;
unsigned long flags;
- enum { NONE, UNREGISTER, UNREGISTER_PROBE, REPROBE, DISC } action;
struct ccw_device *cdev;
+ struct ccw_dev_id dev_id;
+ enum io_sch_action action;
+ int rc = -EAGAIN;
spin_lock_irqsave(sch->lock, flags);
+ if (!device_is_registered(&sch->dev))
+ goto out_unlock;
+ if (work_pending(&sch->todo_work))
+ goto out_unlock;
cdev = sch_get_cdev(sch);
- disc = device_is_disconnected(cdev);
- if (disc && slow) {
- /* Disconnected devices are evaluated directly only.*/
- spin_unlock_irqrestore(sch->lock, flags);
- return 0;
- }
- /* No interrupt after machine check - kill pending timers. */
- if (cdev)
- ccw_device_set_timeout(cdev, 0);
- if (!disc && !slow) {
- /* Non-disconnected devices are evaluated on the slow path. */
- spin_unlock_irqrestore(sch->lock, flags);
- return -EAGAIN;
+ if (cdev && work_pending(&cdev->private->todo_work))
+ goto out_unlock;
+ action = sch_get_action(sch);
+ CIO_MSG_EVENT(2, "event: sch 0.%x.%04x, process=%d, action=%d\n",
+ sch->schid.ssid, sch->schid.sch_no, process,
+ action);
+ /* Perform immediate actions while holding the lock. */
+ switch (action) {
+ case IO_SCH_REPROBE:
+ /* Trigger device recognition. */
+ ccw_device_trigger_reprobe(cdev);
+ rc = 0;
+ goto out_unlock;
+ case IO_SCH_VERIFY:
+ /* Trigger path verification. */
+ io_subchannel_verify(sch);
+ rc = 0;
+ goto out_unlock;
+ case IO_SCH_DISC:
+ ccw_device_set_disconnected(cdev);
+ rc = 0;
+ goto out_unlock;
+ case IO_SCH_ORPH_UNREG:
+ case IO_SCH_ORPH_ATTACH:
+ ccw_device_set_disconnected(cdev);
+ break;
+ case IO_SCH_UNREG_ATTACH:
+ case IO_SCH_UNREG:
+ if (cdev)
+ ccw_device_set_notoper(cdev);
+ break;
+ case IO_SCH_NOP:
+ rc = 0;
+ goto out_unlock;
+ default:
+ break;
}
- event = io_subchannel_get_status(sch);
- CIO_MSG_EVENT(4, "Evaluating schid 0.%x.%04x, event %d, %s, %s path.\n",
- sch->schid.ssid, sch->schid.sch_no, event,
- disc ? "disconnected" : "normal",
- slow ? "slow" : "fast");
- /* Analyze subchannel status. */
- action = NONE;
- switch (event) {
- case CIO_NO_PATH:
- if (disc) {
- /* Check if paths have become available. */
- action = REPROBE;
- break;
- }
- /* fall through */
- case CIO_GONE:
- /* Ask driver what to do with device. */
- if (io_subchannel_notify(sch, event))
- action = DISC;
- else
- action = UNREGISTER;
+ spin_unlock_irqrestore(sch->lock, flags);
+ /* All other actions require process context. */
+ if (!process)
+ goto out;
+ /* Handle attached ccw device. */
+ switch (action) {
+ case IO_SCH_ORPH_UNREG:
+ case IO_SCH_ORPH_ATTACH:
+ /* Move ccw device to orphanage. */
+ rc = ccw_device_move_to_orph(cdev);
+ if (rc)
+ goto out;
break;
- case CIO_REVALIDATE:
- /* Device will be removed, so no notify necessary. */
- if (disc)
- /* Reprobe because immediate unregister might block. */
- action = REPROBE;
- else
- action = UNREGISTER_PROBE;
+ case IO_SCH_UNREG_ATTACH:
+ /* Unregister ccw device. */
+ ccw_device_unregister(cdev);
break;
- case CIO_OPER:
- if (disc)
- /* Get device operational again. */
- action = REPROBE;
+ default:
break;
}
- /* Perform action. */
- ret = 0;
+ /* Handle subchannel. */
switch (action) {
- case UNREGISTER:
- case UNREGISTER_PROBE:
- ccw_device_set_notoper(cdev);
- /* Unregister device (will use subchannel lock). */
- spin_unlock_irqrestore(sch->lock, flags);
+ case IO_SCH_ORPH_UNREG:
+ case IO_SCH_UNREG:
css_sch_device_unregister(sch);
- spin_lock_irqsave(sch->lock, flags);
break;
- case REPROBE:
+ case IO_SCH_ORPH_ATTACH:
+ case IO_SCH_UNREG_ATTACH:
+ case IO_SCH_ATTACH:
+ dev_id.ssid = sch->schid.ssid;
+ dev_id.devno = sch->schib.pmcw.dev;
+ cdev = get_ccwdev_by_dev_id(&dev_id);
+ if (!cdev) {
+ sch_create_and_recog_new_device(sch);
+ break;
+ }
+ rc = ccw_device_move_to_sch(cdev, sch);
+ if (rc) {
+ /* Release reference from get_ccwdev_by_dev_id() */
+ put_device(&cdev->dev);
+ goto out;
+ }
+ spin_lock_irqsave(sch->lock, flags);
ccw_device_trigger_reprobe(cdev);
- break;
- case DISC:
- ccw_device_set_disconnected(cdev);
+ spin_unlock_irqrestore(sch->lock, flags);
+ /* Release reference from get_ccwdev_by_dev_id() */
+ put_device(&cdev->dev);
break;
default:
break;
}
- spin_unlock_irqrestore(sch->lock, flags);
- /* Probe if necessary. */
- if (action == UNREGISTER_PROBE)
- ret = css_probe_device(sch->schid);
+ return 0;
- return ret;
+out_unlock:
+ spin_unlock_irqrestore(sch->lock, flags);
+out:
+ return rc;
}
#ifdef CONFIG_CCW_CONSOLE
@@ -1744,10 +1519,7 @@ static int ccw_device_console_enable(struct ccw_device *cdev,
sch->driver = &io_subchannel_driver;
/* Initialize the ccw_device structure. */
cdev->dev.parent= &sch->dev;
- rc = io_subchannel_recog(cdev, sch);
- if (rc)
- return rc;
-
+ io_subchannel_recog(cdev, sch);
/* Now wait for the async. recognition to come to an end. */
spin_lock_irq(cdev->ccwlock);
while (!dev_fsm_final_state(cdev))
@@ -1763,7 +1535,7 @@ static int ccw_device_console_enable(struct ccw_device *cdev,
rc = 0;
out_unlock:
spin_unlock_irq(cdev->ccwlock);
- return 0;
+ return rc;
}
struct ccw_device *
@@ -1919,7 +1691,7 @@ static int ccw_device_pm_prepare(struct device *dev)
{
struct ccw_device *cdev = to_ccwdev(dev);
- if (work_pending(&cdev->private->kick_work))
+ if (work_pending(&cdev->private->todo_work))
return -EAGAIN;
/* Fail while device is being set online/offline. */
if (atomic_read(&cdev->private->onoff))
@@ -2005,7 +1777,6 @@ static int ccw_device_pm_thaw(struct device *dev)
static void __ccw_device_pm_restore(struct ccw_device *cdev)
{
struct subchannel *sch = to_subchannel(cdev->dev.parent);
- int ret;
if (cio_is_console(sch->schid))
goto out;
@@ -2015,22 +1786,10 @@ static void __ccw_device_pm_restore(struct ccw_device *cdev)
*/
spin_lock_irq(sch->lock);
cdev->private->flags.resuming = 1;
- ret = ccw_device_recognition(cdev);
+ ccw_device_recognition(cdev);
spin_unlock_irq(sch->lock);
- if (ret) {
- CIO_MSG_EVENT(0, "Couldn't start recognition for device "
- "0.%x.%04x (ret=%d)\n",
- cdev->private->dev_id.ssid,
- cdev->private->dev_id.devno, ret);
- spin_lock_irq(sch->lock);
- cdev->private->state = DEV_STATE_DISCONNECTED;
- spin_unlock_irq(sch->lock);
- /* notify driver after the resume cb */
- goto out;
- }
wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev) ||
cdev->private->state == DEV_STATE_DISCONNECTED);
-
out:
cdev->private->flags.resuming = 0;
}
@@ -2040,7 +1799,7 @@ static int resume_handle_boxed(struct ccw_device *cdev)
cdev->private->state = DEV_STATE_BOXED;
if (ccw_device_notify(cdev, CIO_BOXED))
return 0;
- ccw_device_schedule_sch_unregister(cdev);
+ ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
return -ENODEV;
}
@@ -2049,7 +1808,7 @@ static int resume_handle_disc(struct ccw_device *cdev)
cdev->private->state = DEV_STATE_DISCONNECTED;
if (ccw_device_notify(cdev, CIO_GONE))
return 0;
- ccw_device_schedule_sch_unregister(cdev);
+ ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
return -ENODEV;
}
@@ -2094,9 +1853,7 @@ static int ccw_device_pm_restore(struct device *dev)
/* check if the device type has changed */
if (!ccw_device_test_sense_data(cdev)) {
ccw_device_update_sense_data(cdev);
- PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_do_unbind_bind);
- queue_work(ccw_device_work, &cdev->private->kick_work);
+ ccw_device_sched_todo(cdev, CDEV_TODO_REBIND);
ret = -ENODEV;
goto out_unlock;
}
@@ -2140,7 +1897,7 @@ out_disc_unlock:
goto out_restore;
out_unreg_unlock:
- ccw_device_schedule_sch_unregister(cdev);
+ ccw_device_sched_todo(cdev, CDEV_TODO_UNREG_EVAL);
ret = -ENODEV;
out_unlock:
spin_unlock_irq(sch->lock);
@@ -2205,6 +1962,77 @@ ccw_device_get_subchannel_id(struct ccw_device *cdev)
return sch->schid;
}
+static void ccw_device_todo(struct work_struct *work)
+{
+ struct ccw_device_private *priv;
+ struct ccw_device *cdev;
+ struct subchannel *sch;
+ enum cdev_todo todo;
+
+ priv = container_of(work, struct ccw_device_private, todo_work);
+ cdev = priv->cdev;
+ sch = to_subchannel(cdev->dev.parent);
+ /* Find out todo. */
+ spin_lock_irq(cdev->ccwlock);
+ todo = priv->todo;
+ priv->todo = CDEV_TODO_NOTHING;
+ CIO_MSG_EVENT(4, "cdev_todo: cdev=0.%x.%04x todo=%d\n",
+ priv->dev_id.ssid, priv->dev_id.devno, todo);
+ spin_unlock_irq(cdev->ccwlock);
+ /* Perform todo. */
+ switch (todo) {
+ case CDEV_TODO_ENABLE_CMF:
+ cmf_reenable(cdev);
+ break;
+ case CDEV_TODO_REBIND:
+ ccw_device_do_unbind_bind(cdev);
+ break;
+ case CDEV_TODO_REGISTER:
+ io_subchannel_register(cdev);
+ break;
+ case CDEV_TODO_UNREG_EVAL:
+ if (!sch_is_pseudo_sch(sch))
+ css_schedule_eval(sch->schid);
+ /* fall-through */
+ case CDEV_TODO_UNREG:
+ if (sch_is_pseudo_sch(sch))
+ ccw_device_unregister(cdev);
+ else
+ ccw_device_call_sch_unregister(cdev);
+ break;
+ default:
+ break;
+ }
+ /* Release workqueue ref. */
+ put_device(&cdev->dev);
+}
+
+/**
+ * ccw_device_sched_todo - schedule ccw device operation
+ * @cdev: ccw device
+ * @todo: todo
+ *
+ * Schedule the operation identified by @todo to be performed on the slow path
+ * workqueue. Do nothing if another operation with higher priority is already
+ * scheduled. Needs to be called with ccwdev lock held.
+ */
+void ccw_device_sched_todo(struct ccw_device *cdev, enum cdev_todo todo)
+{
+ CIO_MSG_EVENT(4, "cdev_todo: sched cdev=0.%x.%04x todo=%d\n",
+ cdev->private->dev_id.ssid, cdev->private->dev_id.devno,
+ todo);
+ if (cdev->private->todo >= todo)
+ return;
+ cdev->private->todo = todo;
+ /* Get workqueue ref. */
+ if (!get_device(&cdev->dev))
+ return;
+ if (!queue_work(slow_path_wq, &cdev->private->todo_work)) {
+ /* Already queued, release workqueue ref. */
+ put_device(&cdev->dev);
+ }
+}
+
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(ccw_device_set_online);
EXPORT_SYMBOL(ccw_device_set_offline);
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h
index 246c648..bcfe13e 100644
--- a/drivers/s390/cio/device.h
+++ b/drivers/s390/cio/device.h
@@ -21,7 +21,6 @@ enum dev_state {
DEV_STATE_DISBAND_PGID,
DEV_STATE_BOXED,
/* states to wait for i/o completion before doing something */
- DEV_STATE_CLEAR_VERIFY,
DEV_STATE_TIMEOUT_KILL,
DEV_STATE_QUIESCE,
/* special states for devices gone not operational */
@@ -29,6 +28,7 @@ enum dev_state {
DEV_STATE_DISCONNECTED_SENSE_ID,
DEV_STATE_CMFCHANGE,
DEV_STATE_CMFUPDATE,
+ DEV_STATE_STEAL_LOCK,
/* last element! */
NR_DEV_STATES
};
@@ -81,17 +81,16 @@ void io_subchannel_init_config(struct subchannel *sch);
int ccw_device_cancel_halt_clear(struct ccw_device *);
-void ccw_device_do_unbind_bind(struct work_struct *);
-void ccw_device_move_to_orphanage(struct work_struct *);
int ccw_device_is_orphan(struct ccw_device *);
-int ccw_device_recognition(struct ccw_device *);
+void ccw_device_recognition(struct ccw_device *);
int ccw_device_online(struct ccw_device *);
int ccw_device_offline(struct ccw_device *);
void ccw_device_update_sense_data(struct ccw_device *);
int ccw_device_test_sense_data(struct ccw_device *);
void ccw_device_schedule_sch_unregister(struct ccw_device *);
int ccw_purge_blacklisted(void);
+void ccw_device_sched_todo(struct ccw_device *cdev, enum cdev_todo todo);
/* Function prototypes for device status and basic sense stuff. */
void ccw_device_accumulate_irb(struct ccw_device *, struct irb *);
@@ -99,24 +98,28 @@ void ccw_device_accumulate_basic_sense(struct ccw_device *, struct irb *);
int ccw_device_accumulate_and_sense(struct ccw_device *, struct irb *);
int ccw_device_do_sense(struct ccw_device *, struct irb *);
+/* Function prototype for internal request handling. */
+int lpm_adjust(int lpm, int mask);
+void ccw_request_start(struct ccw_device *);
+int ccw_request_cancel(struct ccw_device *cdev);
+void ccw_request_handler(struct ccw_device *cdev);
+void ccw_request_timeout(struct ccw_device *cdev);
+void ccw_request_notoper(struct ccw_device *cdev);
+
/* Function prototypes for sense id stuff. */
void ccw_device_sense_id_start(struct ccw_device *);
-void ccw_device_sense_id_irq(struct ccw_device *, enum dev_event);
void ccw_device_sense_id_done(struct ccw_device *, int);
/* Function prototypes for path grouping stuff. */
-void ccw_device_sense_pgid_start(struct ccw_device *);
-void ccw_device_sense_pgid_irq(struct ccw_device *, enum dev_event);
-void ccw_device_sense_pgid_done(struct ccw_device *, int);
-
void ccw_device_verify_start(struct ccw_device *);
-void ccw_device_verify_irq(struct ccw_device *, enum dev_event);
void ccw_device_verify_done(struct ccw_device *, int);
void ccw_device_disband_start(struct ccw_device *);
-void ccw_device_disband_irq(struct ccw_device *, enum dev_event);
void ccw_device_disband_done(struct ccw_device *, int);
+void ccw_device_stlck_start(struct ccw_device *, void *, void *, void *);
+void ccw_device_stlck_done(struct ccw_device *, void *, int);
+
int ccw_device_call_handler(struct ccw_device *);
int ccw_device_stlck(struct ccw_device *);
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index b9613d7..ae76065 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -229,8 +229,8 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
sch = to_subchannel(cdev->dev.parent);
- ccw_device_set_timeout(cdev, 0);
- cio_disable_subchannel(sch);
+ if (cio_disable_subchannel(sch))
+ state = DEV_STATE_NOT_OPER;
/*
* Now that we tried recognition, we have performed device selection
* through ssch() and the path information is up to date.
@@ -263,22 +263,10 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
}
switch (state) {
case DEV_STATE_NOT_OPER:
- CIO_MSG_EVENT(2, "SenseID : unknown device %04x on "
- "subchannel 0.%x.%04x\n",
- cdev->private->dev_id.devno,
- sch->schid.ssid, sch->schid.sch_no);
break;
case DEV_STATE_OFFLINE:
if (!cdev->online) {
ccw_device_update_sense_data(cdev);
- /* Issue device info message. */
- CIO_MSG_EVENT(4, "SenseID : device 0.%x.%04x reports: "
- "CU Type/Mod = %04X/%02X, Dev Type/Mod "
- "= %04X/%02X\n",
- cdev->private->dev_id.ssid,
- cdev->private->dev_id.devno,
- cdev->id.cu_type, cdev->id.cu_model,
- cdev->id.dev_type, cdev->id.dev_model);
break;
}
cdev->private->state = DEV_STATE_OFFLINE;
@@ -289,16 +277,10 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
wake_up(&cdev->private->wait_q);
} else {
ccw_device_update_sense_data(cdev);
- PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_do_unbind_bind);
- queue_work(ccw_device_work, &cdev->private->kick_work);
+ ccw_device_sched_todo(cdev, CDEV_TODO_REBIND);
}
return;
case DEV_STATE_BOXED:
- CIO_MSG_EVENT(0, "SenseID : boxed device %04x on "
- " subchannel 0.%x.%04x\n",
- cdev->private->dev_id.devno,
- sch->schid.ssid, sch->schid.sch_no);
if (cdev->id.cu_type != 0) { /* device was recognized before */
cdev->private->flags.recog_done = 1;
cdev->private->state = DEV_STATE_BOXED;
@@ -343,28 +325,16 @@ int ccw_device_notify(struct ccw_device *cdev, int event)
return cdev->drv->notify ? cdev->drv->notify(cdev, event) : 0;
}
-static void cmf_reenable_delayed(struct work_struct *work)
-{
- struct ccw_device_private *priv;
- struct ccw_device *cdev;
-
- priv = container_of(work, struct ccw_device_private, kick_work);
- cdev = priv->cdev;
- cmf_reenable(cdev);
-}
-
static void ccw_device_oper_notify(struct ccw_device *cdev)
{
if (ccw_device_notify(cdev, CIO_OPER)) {
/* Reenable channel measurements, if needed. */
- PREPARE_WORK(&cdev->private->kick_work, cmf_reenable_delayed);
- queue_work(ccw_device_work, &cdev->private->kick_work);
+ ccw_device_sched_todo(cdev, CDEV_TODO_ENABLE_CMF);
return;
}
/* Driver doesn't want device back. */
ccw_device_set_notoper(cdev);
- PREPARE_WORK(&cdev->private->kick_work, ccw_device_do_unbind_bind);
- queue_work(ccw_device_work, &cdev->private->kick_work);
+ ccw_device_sched_todo(cdev, CDEV_TODO_REBIND);
}
/*
@@ -392,14 +362,14 @@ ccw_device_done(struct ccw_device *cdev, int state)
CIO_MSG_EVENT(0, "Boxed device %04x on subchannel %04x\n",
cdev->private->dev_id.devno, sch->schid.sch_no);
if (cdev->online && !ccw_device_notify(cdev, CIO_BOXED))
- ccw_device_schedule_sch_unregister(cdev);
+ ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
cdev->private->flags.donotify = 0;
break;
case DEV_STATE_NOT_OPER:
CIO_MSG_EVENT(0, "Device %04x gone on subchannel %04x\n",
cdev->private->dev_id.devno, sch->schid.sch_no);
if (!ccw_device_notify(cdev, CIO_GONE))
- ccw_device_schedule_sch_unregister(cdev);
+ ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
else
ccw_device_set_disconnected(cdev);
cdev->private->flags.donotify = 0;
@@ -409,7 +379,7 @@ ccw_device_done(struct ccw_device *cdev, int state)
"%04x\n", cdev->private->dev_id.devno,
sch->schid.sch_no);
if (!ccw_device_notify(cdev, CIO_NO_PATH))
- ccw_device_schedule_sch_unregister(cdev);
+ ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
else
ccw_device_set_disconnected(cdev);
cdev->private->flags.donotify = 0;
@@ -425,107 +395,12 @@ ccw_device_done(struct ccw_device *cdev, int state)
wake_up(&cdev->private->wait_q);
}
-static int cmp_pgid(struct pgid *p1, struct pgid *p2)
-{
- char *c1;
- char *c2;
-
- c1 = (char *)p1;
- c2 = (char *)p2;
-
- return memcmp(c1 + 1, c2 + 1, sizeof(struct pgid) - 1);
-}
-
-static void __ccw_device_get_common_pgid(struct ccw_device *cdev)
-{
- int i;
- int last;
-
- last = 0;
- for (i = 0; i < 8; i++) {
- if (cdev->private->pgid[i].inf.ps.state1 == SNID_STATE1_RESET)
- /* No PGID yet */
- continue;
- if (cdev->private->pgid[last].inf.ps.state1 ==
- SNID_STATE1_RESET) {
- /* First non-zero PGID */
- last = i;
- continue;
- }
- if (cmp_pgid(&cdev->private->pgid[i],
- &cdev->private->pgid[last]) == 0)
- /* Non-conflicting PGIDs */
- continue;
-
- /* PGID mismatch, can't pathgroup. */
- CIO_MSG_EVENT(0, "SNID - pgid mismatch for device "
- "0.%x.%04x, can't pathgroup\n",
- cdev->private->dev_id.ssid,
- cdev->private->dev_id.devno);
- cdev->private->options.pgroup = 0;
- return;
- }
- if (cdev->private->pgid[last].inf.ps.state1 ==
- SNID_STATE1_RESET)
- /* No previous pgid found */
- memcpy(&cdev->private->pgid[0],
- &channel_subsystems[0]->global_pgid,
- sizeof(struct pgid));
- else
- /* Use existing pgid */
- memcpy(&cdev->private->pgid[0], &cdev->private->pgid[last],
- sizeof(struct pgid));
-}
-
-/*
- * Function called from device_pgid.c after sense path ground has completed.
- */
-void
-ccw_device_sense_pgid_done(struct ccw_device *cdev, int err)
-{
- struct subchannel *sch;
-
- sch = to_subchannel(cdev->dev.parent);
- switch (err) {
- case -EOPNOTSUPP: /* path grouping not supported, use nop instead. */
- cdev->private->options.pgroup = 0;
- break;
- case 0: /* success */
- case -EACCES: /* partial success, some paths not operational */
- /* Check if all pgids are equal or 0. */
- __ccw_device_get_common_pgid(cdev);
- break;
- case -ETIME: /* Sense path group id stopped by timeout. */
- case -EUSERS: /* device is reserved for someone else. */
- ccw_device_done(cdev, DEV_STATE_BOXED);
- return;
- default:
- ccw_device_done(cdev, DEV_STATE_NOT_OPER);
- return;
- }
- /* Start Path Group verification. */
- cdev->private->state = DEV_STATE_VERIFY;
- cdev->private->flags.doverify = 0;
- ccw_device_verify_start(cdev);
-}
-
/*
* Start device recognition.
*/
-int
-ccw_device_recognition(struct ccw_device *cdev)
+void ccw_device_recognition(struct ccw_device *cdev)
{
- struct subchannel *sch;
- int ret;
-
- sch = to_subchannel(cdev->dev.parent);
- ret = cio_enable_subchannel(sch, (u32)(addr_t)sch);
- if (ret != 0)
- /* Couldn't enable the subchannel for i/o. Sick device. */
- return ret;
-
- /* After 60s the device recognition is considered to have failed. */
- ccw_device_set_timeout(cdev, 60*HZ);
+ struct subchannel *sch = to_subchannel(cdev->dev.parent);
/*
* We used to start here with a sense pgid to find out whether a device
@@ -537,32 +412,33 @@ ccw_device_recognition(struct ccw_device *cdev)
*/
cdev->private->flags.recog_done = 0;
cdev->private->state = DEV_STATE_SENSE_ID;
+ if (cio_enable_subchannel(sch, (u32) (addr_t) sch)) {
+ ccw_device_recog_done(cdev, DEV_STATE_NOT_OPER);
+ return;
+ }
ccw_device_sense_id_start(cdev);
- return 0;
}
/*
- * Handle timeout in device recognition.
+ * Handle events for states that use the ccw request infrastructure.
*/
-static void
-ccw_device_recog_timeout(struct ccw_device *cdev, enum dev_event dev_event)
+static void ccw_device_request_event(struct ccw_device *cdev, enum dev_event e)
{
- int ret;
-
- ret = ccw_device_cancel_halt_clear(cdev);
- switch (ret) {
- case 0:
- ccw_device_recog_done(cdev, DEV_STATE_BOXED);
+ switch (e) {
+ case DEV_EVENT_NOTOPER:
+ ccw_request_notoper(cdev);
break;
- case -ENODEV:
- ccw_device_recog_done(cdev, DEV_STATE_NOT_OPER);
+ case DEV_EVENT_INTERRUPT:
+ ccw_request_handler(cdev);
+ break;
+ case DEV_EVENT_TIMEOUT:
+ ccw_request_timeout(cdev);
break;
default:
- ccw_device_set_timeout(cdev, 3*HZ);
+ break;
}
}
-
void
ccw_device_verify_done(struct ccw_device *cdev, int err)
{
@@ -571,21 +447,18 @@ ccw_device_verify_done(struct ccw_device *cdev, int err)
sch = to_subchannel(cdev->dev.parent);
/* Update schib - pom may have changed. */
if (cio_update_schib(sch)) {
- cdev->private->flags.donotify = 0;
- ccw_device_done(cdev, DEV_STATE_NOT_OPER);
- return;
+ err = -ENODEV;
+ goto callback;
}
/* Update lpm with verified path mask. */
sch->lpm = sch->vpm;
/* Repeat path verification? */
if (cdev->private->flags.doverify) {
- cdev->private->flags.doverify = 0;
ccw_device_verify_start(cdev);
return;
}
+callback:
switch (err) {
- case -EOPNOTSUPP: /* path grouping not supported, just set online. */
- cdev->private->options.pgroup = 0;
case 0:
ccw_device_done(cdev, DEV_STATE_ONLINE);
/* Deliver fake irb to device driver, if needed. */
@@ -604,18 +477,20 @@ ccw_device_verify_done(struct ccw_device *cdev, int err)
}
break;
case -ETIME:
+ case -EUSERS:
/* Reset oper notify indication after verify error. */
cdev->private->flags.donotify = 0;
ccw_device_done(cdev, DEV_STATE_BOXED);
break;
+ case -EACCES:
+ /* Reset oper notify indication after verify error. */
+ cdev->private->flags.donotify = 0;
+ ccw_device_done(cdev, DEV_STATE_DISCONNECTED);
+ break;
default:
/* Reset oper notify indication after verify error. */
cdev->private->flags.donotify = 0;
- if (cdev->online) {
- ccw_device_set_timeout(cdev, 0);
- dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
- } else
- ccw_device_done(cdev, DEV_STATE_NOT_OPER);
+ ccw_device_done(cdev, DEV_STATE_NOT_OPER);
break;
}
}
@@ -640,17 +515,9 @@ ccw_device_online(struct ccw_device *cdev)
dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
return ret;
}
- /* Do we want to do path grouping? */
- if (!cdev->private->options.pgroup) {
- /* Start initial path verification. */
- cdev->private->state = DEV_STATE_VERIFY;
- cdev->private->flags.doverify = 0;
- ccw_device_verify_start(cdev);
- return 0;
- }
- /* Do a SensePGID first. */
- cdev->private->state = DEV_STATE_SENSE_PGID;
- ccw_device_sense_pgid_start(cdev);
+ /* Start initial path verification. */
+ cdev->private->state = DEV_STATE_VERIFY;
+ ccw_device_verify_start(cdev);
return 0;
}
@@ -666,7 +533,6 @@ ccw_device_disband_done(struct ccw_device *cdev, int err)
break;
default:
cdev->private->flags.donotify = 0;
- dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
ccw_device_done(cdev, DEV_STATE_NOT_OPER);
break;
}
@@ -703,7 +569,7 @@ ccw_device_offline(struct ccw_device *cdev)
if (cdev->private->state != DEV_STATE_ONLINE)
return -EINVAL;
/* Are we doing path grouping? */
- if (!cdev->private->options.pgroup) {
+ if (!cdev->private->flags.pgroup) {
/* No, set state offline immediately. */
ccw_device_done(cdev, DEV_STATE_OFFLINE);
return 0;
@@ -715,43 +581,13 @@ ccw_device_offline(struct ccw_device *cdev)
}
/*
- * Handle timeout in device online/offline process.
- */
-static void
-ccw_device_onoff_timeout(struct ccw_device *cdev, enum dev_event dev_event)
-{
- int ret;
-
- ret = ccw_device_cancel_halt_clear(cdev);
- switch (ret) {
- case 0:
- ccw_device_done(cdev, DEV_STATE_BOXED);
- break;
- case -ENODEV:
- ccw_device_done(cdev, DEV_STATE_NOT_OPER);
- break;
- default:
- ccw_device_set_timeout(cdev, 3*HZ);
- }
-}
-
-/*
- * Handle not oper event in device recognition.
- */
-static void
-ccw_device_recog_notoper(struct ccw_device *cdev, enum dev_event dev_event)
-{
- ccw_device_recog_done(cdev, DEV_STATE_NOT_OPER);
-}
-
-/*
* Handle not operational event in non-special state.
*/
static void ccw_device_generic_notoper(struct ccw_device *cdev,
enum dev_event dev_event)
{
if (!ccw_device_notify(cdev, CIO_GONE))
- ccw_device_schedule_sch_unregister(cdev);
+ ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
else
ccw_device_set_disconnected(cdev);
}
@@ -802,11 +638,27 @@ ccw_device_online_verify(struct ccw_device *cdev, enum dev_event dev_event)
}
/* Device is idle, we can do the path verification. */
cdev->private->state = DEV_STATE_VERIFY;
- cdev->private->flags.doverify = 0;
ccw_device_verify_start(cdev);
}
/*
+ * Handle path verification event in boxed state.
+ */
+static void ccw_device_boxed_verify(struct ccw_device *cdev,
+ enum dev_event dev_event)
+{
+ struct subchannel *sch = to_subchannel(cdev->dev.parent);
+
+ if (cdev->online) {
+ if (cio_enable_subchannel(sch, (u32) (addr_t) sch))
+ ccw_device_done(cdev, DEV_STATE_NOT_OPER);
+ else
+ ccw_device_online_verify(cdev, dev_event);
+ } else
+ css_schedule_eval(sch->schid);
+}
+
+/*
* Got an interrupt for a normal io (state online).
*/
static void
@@ -904,12 +756,6 @@ ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event)
*/
if (scsw_fctl(&irb->scsw) &
(SCSW_FCTL_CLEAR_FUNC | SCSW_FCTL_HALT_FUNC)) {
- /* Retry Basic Sense if requested. */
- if (cdev->private->flags.intretry) {
- cdev->private->flags.intretry = 0;
- ccw_device_do_sense(cdev, irb);
- return;
- }
cdev->private->flags.dosense = 0;
memset(&cdev->private->irb, 0, sizeof(struct irb));
ccw_device_accumulate_irb(cdev, irb);
@@ -933,21 +779,6 @@ call_handler:
}
static void
-ccw_device_clear_verify(struct ccw_device *cdev, enum dev_event dev_event)
-{
- struct irb *irb;
-
- irb = (struct irb *) __LC_IRB;
- /* Accumulate status. We don't do basic sense. */
- ccw_device_accumulate_irb(cdev, irb);
- /* Remember to clear irb to avoid residuals. */
- memset(&cdev->private->irb, 0, sizeof(struct irb));
- /* Try to start delayed device verification. */
- ccw_device_online_verify(cdev, 0);
- /* Note: Don't call handler for cio initiated clear! */
-}
-
-static void
ccw_device_killing_irq(struct ccw_device *cdev, enum dev_event dev_event)
{
struct subchannel *sch;
@@ -1004,32 +835,6 @@ ccw_device_delay_verify(struct ccw_device *cdev, enum dev_event dev_event)
}
static void
-ccw_device_stlck_done(struct ccw_device *cdev, enum dev_event dev_event)
-{
- struct irb *irb;
-
- switch (dev_event) {
- case DEV_EVENT_INTERRUPT:
- irb = (struct irb *) __LC_IRB;
- /* Check for unsolicited interrupt. */
- if ((scsw_stctl(&irb->scsw) ==
- (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) &&
- (!scsw_cc(&irb->scsw)))
- /* FIXME: we should restart stlck here, but this
- * is extremely unlikely ... */
- goto out_wakeup;
-
- ccw_device_accumulate_irb(cdev, irb);
- /* We don't care about basic sense etc. */
- break;
- default: /* timeout */
- break;
- }
-out_wakeup:
- wake_up(&cdev->private->wait_q);
-}
-
-static void
ccw_device_start_id(struct ccw_device *cdev, enum dev_event dev_event)
{
struct subchannel *sch;
@@ -1038,10 +843,6 @@ ccw_device_start_id(struct ccw_device *cdev, enum dev_event dev_event)
if (cio_enable_subchannel(sch, (u32)(addr_t)sch) != 0)
/* Couldn't enable the subchannel for i/o. Sick device. */
return;
-
- /* After 60s the device recognition is considered to have failed. */
- ccw_device_set_timeout(cdev, 60*HZ);
-
cdev->private->state = DEV_STATE_DISCONNECTED_SENSE_ID;
ccw_device_sense_id_start(cdev);
}
@@ -1072,22 +873,20 @@ void ccw_device_trigger_reprobe(struct ccw_device *cdev)
/* We should also udate ssd info, but this has to wait. */
/* Check if this is another device which appeared on the same sch. */
- if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) {
- PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_move_to_orphanage);
- queue_work(slow_path_wq, &cdev->private->kick_work);
- } else
+ if (sch->schib.pmcw.dev != cdev->private->dev_id.devno)
+ css_schedule_eval(sch->schid);
+ else
ccw_device_start_id(cdev, 0);
}
-static void
-ccw_device_offline_irq(struct ccw_device *cdev, enum dev_event dev_event)
+static void ccw_device_disabled_irq(struct ccw_device *cdev,
+ enum dev_event dev_event)
{
struct subchannel *sch;
sch = to_subchannel(cdev->dev.parent);
/*
- * An interrupt in state offline means a previous disable was not
+ * An interrupt in a disabled state means a previous disable was not
* successful - should not happen, but we try to disable again.
*/
cio_disable_subchannel(sch);
@@ -1113,10 +912,7 @@ static void
ccw_device_quiesce_done(struct ccw_device *cdev, enum dev_event dev_event)
{
ccw_device_set_timeout(cdev, 0);
- if (dev_event == DEV_EVENT_NOTOPER)
- cdev->private->state = DEV_STATE_NOT_OPER;
- else
- cdev->private->state = DEV_STATE_OFFLINE;
+ cdev->private->state = DEV_STATE_NOT_OPER;
wake_up(&cdev->private->wait_q);
}
@@ -1126,17 +922,11 @@ ccw_device_quiesce_timeout(struct ccw_device *cdev, enum dev_event dev_event)
int ret;
ret = ccw_device_cancel_halt_clear(cdev);
- switch (ret) {
- case 0:
- cdev->private->state = DEV_STATE_OFFLINE;
- wake_up(&cdev->private->wait_q);
- break;
- case -ENODEV:
+ if (ret == -EBUSY) {
+ ccw_device_set_timeout(cdev, HZ/10);
+ } else {
cdev->private->state = DEV_STATE_NOT_OPER;
wake_up(&cdev->private->wait_q);
- break;
- default:
- ccw_device_set_timeout(cdev, HZ/10);
}
}
@@ -1150,50 +940,37 @@ ccw_device_nop(struct ccw_device *cdev, enum dev_event dev_event)
}
/*
- * Bug operation action.
- */
-static void
-ccw_device_bug(struct ccw_device *cdev, enum dev_event dev_event)
-{
- CIO_MSG_EVENT(0, "Internal state [%i][%i] not handled for device "
- "0.%x.%04x\n", cdev->private->state, dev_event,
- cdev->private->dev_id.ssid,
- cdev->private->dev_id.devno);
- BUG();
-}
-
-/*
* device statemachine
*/
fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
[DEV_STATE_NOT_OPER] = {
[DEV_EVENT_NOTOPER] = ccw_device_nop,
- [DEV_EVENT_INTERRUPT] = ccw_device_bug,
+ [DEV_EVENT_INTERRUPT] = ccw_device_disabled_irq,
[DEV_EVENT_TIMEOUT] = ccw_device_nop,
[DEV_EVENT_VERIFY] = ccw_device_nop,
},
[DEV_STATE_SENSE_PGID] = {
- [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
- [DEV_EVENT_INTERRUPT] = ccw_device_sense_pgid_irq,
- [DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout,
+ [DEV_EVENT_NOTOPER] = ccw_device_request_event,
+ [DEV_EVENT_INTERRUPT] = ccw_device_request_event,
+ [DEV_EVENT_TIMEOUT] = ccw_device_request_event,
[DEV_EVENT_VERIFY] = ccw_device_nop,
},
[DEV_STATE_SENSE_ID] = {
- [DEV_EVENT_NOTOPER] = ccw_device_recog_notoper,
- [DEV_EVENT_INTERRUPT] = ccw_device_sense_id_irq,
- [DEV_EVENT_TIMEOUT] = ccw_device_recog_timeout,
+ [DEV_EVENT_NOTOPER] = ccw_device_request_event,
+ [DEV_EVENT_INTERRUPT] = ccw_device_request_event,
+ [DEV_EVENT_TIMEOUT] = ccw_device_request_event,
[DEV_EVENT_VERIFY] = ccw_device_nop,
},
[DEV_STATE_OFFLINE] = {
[DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
- [DEV_EVENT_INTERRUPT] = ccw_device_offline_irq,
+ [DEV_EVENT_INTERRUPT] = ccw_device_disabled_irq,
[DEV_EVENT_TIMEOUT] = ccw_device_nop,
[DEV_EVENT_VERIFY] = ccw_device_offline_verify,
},
[DEV_STATE_VERIFY] = {
- [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
- [DEV_EVENT_INTERRUPT] = ccw_device_verify_irq,
- [DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout,
+ [DEV_EVENT_NOTOPER] = ccw_device_request_event,
+ [DEV_EVENT_INTERRUPT] = ccw_device_request_event,
+ [DEV_EVENT_TIMEOUT] = ccw_device_request_event,
[DEV_EVENT_VERIFY] = ccw_device_delay_verify,
},
[DEV_STATE_ONLINE] = {
@@ -1209,24 +986,18 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
[DEV_EVENT_VERIFY] = ccw_device_online_verify,
},
[DEV_STATE_DISBAND_PGID] = {
- [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
- [DEV_EVENT_INTERRUPT] = ccw_device_disband_irq,
- [DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout,
+ [DEV_EVENT_NOTOPER] = ccw_device_request_event,
+ [DEV_EVENT_INTERRUPT] = ccw_device_request_event,
+ [DEV_EVENT_TIMEOUT] = ccw_device_request_event,
[DEV_EVENT_VERIFY] = ccw_device_nop,
},
[DEV_STATE_BOXED] = {
[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_generic_notoper,
- [DEV_EVENT_INTERRUPT] = ccw_device_clear_verify,
+ [DEV_EVENT_INTERRUPT] = ccw_device_nop,
[DEV_EVENT_TIMEOUT] = ccw_device_nop,
- [DEV_EVENT_VERIFY] = ccw_device_nop,
+ [DEV_EVENT_VERIFY] = ccw_device_boxed_verify,
},
+ /* states to wait for i/o completion before doing something */
[DEV_STATE_TIMEOUT_KILL] = {
[DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_killing_irq,
@@ -1243,13 +1014,13 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
[DEV_STATE_DISCONNECTED] = {
[DEV_EVENT_NOTOPER] = ccw_device_nop,
[DEV_EVENT_INTERRUPT] = ccw_device_start_id,
- [DEV_EVENT_TIMEOUT] = ccw_device_bug,
+ [DEV_EVENT_TIMEOUT] = ccw_device_nop,
[DEV_EVENT_VERIFY] = ccw_device_start_id,
},
[DEV_STATE_DISCONNECTED_SENSE_ID] = {
- [DEV_EVENT_NOTOPER] = ccw_device_recog_notoper,
- [DEV_EVENT_INTERRUPT] = ccw_device_sense_id_irq,
- [DEV_EVENT_TIMEOUT] = ccw_device_recog_timeout,
+ [DEV_EVENT_NOTOPER] = ccw_device_request_event,
+ [DEV_EVENT_INTERRUPT] = ccw_device_request_event,
+ [DEV_EVENT_TIMEOUT] = ccw_device_request_event,
[DEV_EVENT_VERIFY] = ccw_device_nop,
},
[DEV_STATE_CMFCHANGE] = {
@@ -1264,6 +1035,12 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
[DEV_EVENT_TIMEOUT] = ccw_device_update_cmfblock,
[DEV_EVENT_VERIFY] = ccw_device_update_cmfblock,
},
+ [DEV_STATE_STEAL_LOCK] = {
+ [DEV_EVENT_NOTOPER] = ccw_device_request_event,
+ [DEV_EVENT_INTERRUPT] = ccw_device_request_event,
+ [DEV_EVENT_TIMEOUT] = ccw_device_request_event,
+ [DEV_EVENT_VERIFY] = ccw_device_nop,
+ },
};
EXPORT_SYMBOL_GPL(ccw_device_set_timeout);
diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c
index 1bdaa61..78a0b43 100644
--- a/drivers/s390/cio/device_id.c
+++ b/drivers/s390/cio/device_id.c
@@ -1,40 +1,39 @@
/*
- * drivers/s390/cio/device_id.c
+ * CCW device SENSE ID I/O handling.
*
- * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
- * IBM Corporation
- * Author(s): Cornelia Huck (cornelia.huck@de.ibm.com)
- * Martin Schwidefsky (schwidefsky@de.ibm.com)
- *
- * Sense ID functions.
+ * Copyright IBM Corp. 2002,2009
+ * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
+ * Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
*/
-#include <linux/module.h>
-#include <linux/init.h>
#include <linux/kernel.h>
-
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/errno.h>
#include <asm/ccwdev.h>
-#include <asm/delay.h>
+#include <asm/setup.h>
#include <asm/cio.h>
-#include <asm/lowcore.h>
#include <asm/diag.h>
#include "cio.h"
#include "cio_debug.h"
-#include "css.h"
#include "device.h"
-#include "ioasm.h"
#include "io_sch.h"
+#define SENSE_ID_RETRIES 256
+#define SENSE_ID_TIMEOUT (10 * HZ)
+#define SENSE_ID_MIN_LEN 4
+#define SENSE_ID_BASIC_LEN 7
+
/**
- * vm_vdev_to_cu_type - Convert vm virtual device into control unit type
- * for certain devices.
- * @class: virtual device class
- * @type: virtual device type
+ * diag210_to_senseid - convert diag 0x210 data to sense id information
+ * @senseid: sense id
+ * @diag: diag 0x210 data
*
- * Returns control unit type if a match was made or %0xffff otherwise.
+ * Return 0 on success, non-zero otherwise.
*/
-static int vm_vdev_to_cu_type(int class, int type)
+static int diag210_to_senseid(struct senseid *senseid, struct diag210 *diag)
{
static struct {
int class, type, cu_type;
@@ -71,253 +70,153 @@ static int vm_vdev_to_cu_type(int class, int type)
};
int i;
- for (i = 0; i < ARRAY_SIZE(vm_devices); i++)
- if (class == vm_devices[i].class && type == vm_devices[i].type)
- return vm_devices[i].cu_type;
+ /* Special case for osa devices. */
+ if (diag->vrdcvcla == 0x02 && diag->vrdcvtyp == 0x20) {
+ senseid->cu_type = 0x3088;
+ senseid->cu_model = 0x60;
+ senseid->reserved = 0xff;
+ return 0;
+ }
+ for (i = 0; i < ARRAY_SIZE(vm_devices); i++) {
+ if (diag->vrdcvcla == vm_devices[i].class &&
+ diag->vrdcvtyp == vm_devices[i].type) {
+ senseid->cu_type = vm_devices[i].cu_type;
+ senseid->reserved = 0xff;
+ return 0;
+ }
+ }
- return 0xffff;
+ return -ENODEV;
}
/**
- * diag_get_dev_info - retrieve device information via DIAG X'210'
- * @devno: device number
- * @ps: pointer to sense ID data area
+ * diag_get_dev_info - retrieve device information via diag 0x210
+ * @cdev: ccw device
*
* Returns zero on success, non-zero otherwise.
*/
-static int diag_get_dev_info(u16 devno, struct senseid *ps)
+static int diag210_get_dev_info(struct ccw_device *cdev)
{
+ struct ccw_dev_id *dev_id = &cdev->private->dev_id;
+ struct senseid *senseid = &cdev->private->senseid;
struct diag210 diag_data;
- int ccode;
-
- CIO_TRACE_EVENT (4, "VMvdinf");
-
- diag_data = (struct diag210) {
- .vrdcdvno = devno,
- .vrdclen = sizeof (diag_data),
- };
-
- ccode = diag210 (&diag_data);
- if ((ccode == 0) || (ccode == 2)) {
- ps->reserved = 0xff;
-
- /* Special case for osa devices. */
- if (diag_data.vrdcvcla == 0x02 && diag_data.vrdcvtyp == 0x20) {
- ps->cu_type = 0x3088;
- ps->cu_model = 0x60;
- return 0;
- }
- ps->cu_type = vm_vdev_to_cu_type(diag_data.vrdcvcla,
- diag_data.vrdcvtyp);
- if (ps->cu_type != 0xffff)
- return 0;
- }
-
- CIO_MSG_EVENT(0, "DIAG X'210' for device %04X returned (cc = %d):"
- "vdev class : %02X, vdev type : %04X \n ... "
- "rdev class : %02X, rdev type : %04X, "
- "rdev model: %02X\n",
- devno, ccode,
- diag_data.vrdcvcla, diag_data.vrdcvtyp,
- diag_data.vrdcrccl, diag_data.vrdccrty,
- diag_data.vrdccrmd);
-
+ int rc;
+
+ if (dev_id->ssid != 0)
+ return -ENODEV;
+ memset(&diag_data, 0, sizeof(diag_data));
+ diag_data.vrdcdvno = dev_id->devno;
+ diag_data.vrdclen = sizeof(diag_data);
+ rc = diag210(&diag_data);
+ CIO_TRACE_EVENT(4, "diag210");
+ CIO_HEX_EVENT(4, &rc, sizeof(rc));
+ CIO_HEX_EVENT(4, &diag_data, sizeof(diag_data));
+ if (rc != 0 && rc != 2)
+ goto err_failed;
+ if (diag210_to_senseid(senseid, &diag_data))
+ goto err_unknown;
+ return 0;
+
+err_unknown:
+ CIO_MSG_EVENT(0, "snsid: device 0.%x.%04x: unknown diag210 data\n",
+ dev_id->ssid, dev_id->devno);
+ return -ENODEV;
+err_failed:
+ CIO_MSG_EVENT(0, "snsid: device 0.%x.%04x: diag210 failed (rc=%d)\n",
+ dev_id->ssid, dev_id->devno, rc);
return -ENODEV;
}
/*
- * Start Sense ID helper function.
- * Try to obtain the 'control unit'/'device type' information
- * associated with the subchannel.
+ * Initialize SENSE ID data.
*/
-static int
-__ccw_device_sense_id_start(struct ccw_device *cdev)
-{
- struct subchannel *sch;
- struct ccw1 *ccw;
- int ret;
-
- sch = to_subchannel(cdev->dev.parent);
- /* Setup sense channel program. */
- ccw = cdev->private->iccws;
- ccw->cmd_code = CCW_CMD_SENSE_ID;
- ccw->cda = (__u32) __pa (&cdev->private->senseid);
- ccw->count = sizeof (struct senseid);
- ccw->flags = CCW_FLAG_SLI;
-
- /* Reset device status. */
- memset(&cdev->private->irb, 0, sizeof(struct irb));
-
- /* Try on every path. */
- ret = -ENODEV;
- while (cdev->private->imask != 0) {
- cdev->private->senseid.cu_type = 0xFFFF;
- if ((sch->opm & cdev->private->imask) != 0 &&
- cdev->private->iretry > 0) {
- cdev->private->iretry--;
- /* Reset internal retry indication. */
- cdev->private->flags.intretry = 0;
- ret = cio_start (sch, cdev->private->iccws,
- cdev->private->imask);
- /* ret is 0, -EBUSY, -EACCES or -ENODEV */
- if (ret != -EACCES)
- return ret;
- }
- cdev->private->imask >>= 1;
- cdev->private->iretry = 5;
- }
- return ret;
-}
-
-void
-ccw_device_sense_id_start(struct ccw_device *cdev)
+static void snsid_init(struct ccw_device *cdev)
{
- int ret;
-
- memset (&cdev->private->senseid, 0, sizeof (struct senseid));
- cdev->private->imask = 0x80;
- cdev->private->iretry = 5;
- ret = __ccw_device_sense_id_start(cdev);
- if (ret && ret != -EBUSY)
- ccw_device_sense_id_done(cdev, ret);
+ cdev->private->flags.esid = 0;
+ memset(&cdev->private->senseid, 0, sizeof(cdev->private->senseid));
+ cdev->private->senseid.cu_type = 0xffff;
}
/*
- * Called from interrupt context to check if a valid answer
- * to Sense ID was received.
+ * Check for complete SENSE ID data.
*/
-static int
-ccw_device_check_sense_id(struct ccw_device *cdev)
+static int snsid_check(struct ccw_device *cdev, void *data)
{
- struct subchannel *sch;
- struct irb *irb;
-
- sch = to_subchannel(cdev->dev.parent);
- irb = &cdev->private->irb;
-
- /* Check the error cases. */
- if (irb->scsw.cmd.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) {
- /* Retry Sense ID if requested. */
- if (cdev->private->flags.intretry) {
- cdev->private->flags.intretry = 0;
- return -EAGAIN;
- }
- return -ETIME;
- }
- if (irb->esw.esw0.erw.cons && (irb->ecw[0] & SNS0_CMD_REJECT)) {
- /*
- * if the device doesn't support the SenseID
- * command further retries wouldn't help ...
- * NB: We don't check here for intervention required like we
- * did before, because tape devices with no tape inserted
- * may present this status *in conjunction with* the
- * sense id information. So, for intervention required,
- * we use the "whack it until it talks" strategy...
- */
- CIO_MSG_EVENT(0, "SenseID : device %04x on Subchannel "
- "0.%x.%04x reports cmd reject\n",
- cdev->private->dev_id.devno, sch->schid.ssid,
- sch->schid.sch_no);
+ struct cmd_scsw *scsw = &cdev->private->irb.scsw.cmd;
+ int len = sizeof(struct senseid) - scsw->count;
+
+ /* Check for incomplete SENSE ID data. */
+ if (len < SENSE_ID_MIN_LEN)
+ goto out_restart;
+ if (cdev->private->senseid.cu_type == 0xffff)
+ goto out_restart;
+ /* Check for incompatible SENSE ID data. */
+ if (cdev->private->senseid.reserved != 0xff)
return -EOPNOTSUPP;
- }
- if (irb->esw.esw0.erw.cons) {
- CIO_MSG_EVENT(2, "SenseID : UC on dev 0.%x.%04x, "
- "lpum %02X, cnt %02d, sns :"
- " %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
- cdev->private->dev_id.ssid,
- cdev->private->dev_id.devno,
- irb->esw.esw0.sublog.lpum,
- irb->esw.esw0.erw.scnt,
- irb->ecw[0], irb->ecw[1],
- irb->ecw[2], irb->ecw[3],
- irb->ecw[4], irb->ecw[5],
- irb->ecw[6], irb->ecw[7]);
- return -EAGAIN;
- }
- if (irb->scsw.cmd.cc == 3) {
- u8 lpm;
+ /* Check for extended-identification information. */
+ if (len > SENSE_ID_BASIC_LEN)
+ cdev->private->flags.esid = 1;
+ return 0;
- lpm = to_io_private(sch)->orb.cmd.lpm;
- if ((lpm & sch->schib.pmcw.pim & sch->schib.pmcw.pam) != 0)
- CIO_MSG_EVENT(4, "SenseID : path %02X for device %04x "
- "on subchannel 0.%x.%04x is "
- "'not operational'\n", lpm,
- cdev->private->dev_id.devno,
- sch->schid.ssid, sch->schid.sch_no);
- return -EACCES;
- }
-
- /* Did we get a proper answer ? */
- if (irb->scsw.cmd.cc == 0 && cdev->private->senseid.cu_type != 0xFFFF &&
- cdev->private->senseid.reserved == 0xFF) {
- if (irb->scsw.cmd.count < sizeof(struct senseid) - 8)
- cdev->private->flags.esid = 1;
- return 0; /* Success */
- }
-
- /* Hmm, whatever happened, try again. */
- CIO_MSG_EVENT(2, "SenseID : start_IO() for device %04x on "
- "subchannel 0.%x.%04x returns status %02X%02X\n",
- cdev->private->dev_id.devno, sch->schid.ssid,
- sch->schid.sch_no,
- irb->scsw.cmd.dstat, irb->scsw.cmd.cstat);
+out_restart:
+ snsid_init(cdev);
return -EAGAIN;
}
/*
- * Got interrupt for Sense ID.
+ * Process SENSE ID request result.
*/
-void
-ccw_device_sense_id_irq(struct ccw_device *cdev, enum dev_event dev_event)
+static void snsid_callback(struct ccw_device *cdev, void *data, int rc)
{
- struct subchannel *sch;
- struct irb *irb;
- int ret;
-
- sch = to_subchannel(cdev->dev.parent);
- irb = (struct irb *) __LC_IRB;
- /* Retry sense id, if needed. */
- if (irb->scsw.cmd.stctl ==
- (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
- if ((irb->scsw.cmd.cc == 1) || !irb->scsw.cmd.actl) {
- ret = __ccw_device_sense_id_start(cdev);
- if (ret && ret != -EBUSY)
- ccw_device_sense_id_done(cdev, ret);
+ struct ccw_dev_id *id = &cdev->private->dev_id;
+ struct senseid *senseid = &cdev->private->senseid;
+ int vm = 0;
+
+ if (rc && MACHINE_IS_VM) {
+ /* Try diag 0x210 fallback on z/VM. */
+ snsid_init(cdev);
+ if (diag210_get_dev_info(cdev) == 0) {
+ rc = 0;
+ vm = 1;
}
- return;
}
- if (ccw_device_accumulate_and_sense(cdev, irb) != 0)
- return;
- ret = ccw_device_check_sense_id(cdev);
- memset(&cdev->private->irb, 0, sizeof(struct irb));
- switch (ret) {
- /* 0, -ETIME, -EOPNOTSUPP, -EAGAIN or -EACCES */
- case 0: /* Sense id succeeded. */
- case -ETIME: /* Sense id stopped by timeout. */
- ccw_device_sense_id_done(cdev, ret);
- break;
- case -EACCES: /* channel is not operational. */
- sch->lpm &= ~cdev->private->imask;
- cdev->private->imask >>= 1;
- cdev->private->iretry = 5;
- /* fall through. */
- case -EAGAIN: /* try again. */
- ret = __ccw_device_sense_id_start(cdev);
- if (ret == 0 || ret == -EBUSY)
- break;
- /* fall through. */
- default: /* Sense ID failed. Try asking VM. */
- if (MACHINE_IS_VM)
- ret = diag_get_dev_info(cdev->private->dev_id.devno,
- &cdev->private->senseid);
- else
- /*
- * If we can't couldn't identify the device type we
- * consider the device "not operational".
- */
- ret = -ENODEV;
+ CIO_MSG_EVENT(2, "snsid: device 0.%x.%04x: rc=%d %04x/%02x "
+ "%04x/%02x%s\n", id->ssid, id->devno, rc,
+ senseid->cu_type, senseid->cu_model, senseid->dev_type,
+ senseid->dev_model, vm ? " (diag210)" : "");
+ ccw_device_sense_id_done(cdev, rc);
+}
- ccw_device_sense_id_done(cdev, ret);
- break;
- }
+/**
+ * ccw_device_sense_id_start - perform SENSE ID
+ * @cdev: ccw device
+ *
+ * Execute a SENSE ID channel program on @cdev to update its sense id
+ * information. When finished, call ccw_device_sense_id_done with a
+ * return code specifying the result.
+ */
+void ccw_device_sense_id_start(struct ccw_device *cdev)
+{
+ struct subchannel *sch = to_subchannel(cdev->dev.parent);
+ struct ccw_request *req = &cdev->private->req;
+ struct ccw1 *cp = cdev->private->iccws;
+
+ CIO_TRACE_EVENT(4, "snsid");
+ CIO_HEX_EVENT(4, &cdev->private->dev_id, sizeof(cdev->private->dev_id));
+ /* Data setup. */
+ snsid_init(cdev);
+ /* Channel program setup. */
+ cp->cmd_code = CCW_CMD_SENSE_ID;
+ cp->cda = (u32) (addr_t) &cdev->private->senseid;
+ cp->count = sizeof(struct senseid);
+ cp->flags = CCW_FLAG_SLI;
+ /* Request setup. */
+ memset(req, 0, sizeof(*req));
+ req->cp = cp;
+ req->timeout = SENSE_ID_TIMEOUT;
+ req->maxretries = SENSE_ID_RETRIES;
+ req->lpm = sch->schib.pmcw.pam & sch->opm;
+ req->check = snsid_check;
+ req->callback = snsid_callback;
+ ccw_request_start(cdev);
}
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
index 2d0efee..6da8454 100644
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -11,6 +11,7 @@
#include <linux/list.h>
#include <linux/device.h>
#include <linux/delay.h>
+#include <linux/completion.h>
#include <asm/ccwdev.h>
#include <asm/idals.h>
@@ -46,6 +47,7 @@ int ccw_device_set_options_mask(struct ccw_device *cdev, unsigned long flags)
cdev->private->options.repall = (flags & CCWDEV_REPORT_ALL) != 0;
cdev->private->options.pgroup = (flags & CCWDEV_DO_PATHGROUP) != 0;
cdev->private->options.force = (flags & CCWDEV_ALLOW_FORCE) != 0;
+ cdev->private->options.mpath = (flags & CCWDEV_DO_MULTIPATH) != 0;
return 0;
}
@@ -74,6 +76,7 @@ int ccw_device_set_options(struct ccw_device *cdev, unsigned long flags)
cdev->private->options.repall |= (flags & CCWDEV_REPORT_ALL) != 0;
cdev->private->options.pgroup |= (flags & CCWDEV_DO_PATHGROUP) != 0;
cdev->private->options.force |= (flags & CCWDEV_ALLOW_FORCE) != 0;
+ cdev->private->options.mpath |= (flags & CCWDEV_DO_MULTIPATH) != 0;
return 0;
}
@@ -90,9 +93,34 @@ void ccw_device_clear_options(struct ccw_device *cdev, unsigned long flags)
cdev->private->options.repall &= (flags & CCWDEV_REPORT_ALL) == 0;
cdev->private->options.pgroup &= (flags & CCWDEV_DO_PATHGROUP) == 0;
cdev->private->options.force &= (flags & CCWDEV_ALLOW_FORCE) == 0;
+ cdev->private->options.mpath &= (flags & CCWDEV_DO_MULTIPATH) == 0;
}
/**
+ * ccw_device_is_pathgroup - determine if paths to this device are grouped
+ * @cdev: ccw device
+ *
+ * Return non-zero if there is a path group, zero otherwise.
+ */
+int ccw_device_is_pathgroup(struct ccw_device *cdev)
+{
+ return cdev->private->flags.pgroup;
+}
+EXPORT_SYMBOL(ccw_device_is_pathgroup);
+
+/**
+ * ccw_device_is_multipath - determine if device is operating in multipath mode
+ * @cdev: ccw device
+ *
+ * Return non-zero if device is operating in multipath mode, zero otherwise.
+ */
+int ccw_device_is_multipath(struct ccw_device *cdev)
+{
+ return cdev->private->flags.mpath;
+}
+EXPORT_SYMBOL(ccw_device_is_multipath);
+
+/**
* ccw_device_clear() - terminate I/O request processing
* @cdev: target ccw device
* @intparm: interruption parameter; value is only used if no I/O is
@@ -167,8 +195,7 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
return -EINVAL;
if (cdev->private->state == DEV_STATE_NOT_OPER)
return -ENODEV;
- if (cdev->private->state == DEV_STATE_VERIFY ||
- cdev->private->state == DEV_STATE_CLEAR_VERIFY) {
+ if (cdev->private->state == DEV_STATE_VERIFY) {
/* Remember to fake irb when finished. */
if (!cdev->private->flags.fake_irb) {
cdev->private->flags.fake_irb = 1;
@@ -478,74 +505,65 @@ __u8 ccw_device_get_path_mask(struct ccw_device *cdev)
return sch->lpm;
}
-/*
- * Try to break the lock on a boxed device.
- */
-int
-ccw_device_stlck(struct ccw_device *cdev)
-{
- void *buf, *buf2;
- unsigned long flags;
- struct subchannel *sch;
- int ret;
+struct stlck_data {
+ struct completion done;
+ int rc;
+};
- if (!cdev)
- return -ENODEV;
+void ccw_device_stlck_done(struct ccw_device *cdev, void *data, int rc)
+{
+ struct stlck_data *sdata = data;
- if (cdev->drv && !cdev->private->options.force)
- return -EINVAL;
+ sdata->rc = rc;
+ complete(&sdata->done);
+}
- sch = to_subchannel(cdev->dev.parent);
-
- CIO_TRACE_EVENT(2, "stl lock");
- CIO_TRACE_EVENT(2, dev_name(&cdev->dev));
+/*
+ * Perform unconditional reserve + release.
+ */
+int ccw_device_stlck(struct ccw_device *cdev)
+{
+ struct subchannel *sch = to_subchannel(cdev->dev.parent);
+ struct stlck_data data;
+ u8 *buffer;
+ int rc;
- buf = kmalloc(32*sizeof(char), GFP_DMA|GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
- buf2 = kmalloc(32*sizeof(char), GFP_DMA|GFP_KERNEL);
- if (!buf2) {
- kfree(buf);
- return -ENOMEM;
+ /* Check if steal lock operation is valid for this device. */
+ if (cdev->drv) {
+ if (!cdev->private->options.force)
+ return -EINVAL;
}
- spin_lock_irqsave(sch->lock, flags);
- ret = cio_enable_subchannel(sch, (u32)(addr_t)sch);
- if (ret)
- goto out_unlock;
- /*
- * Setup ccw. We chain an unconditional reserve and a release so we
- * only break the lock.
- */
- cdev->private->iccws[0].cmd_code = CCW_CMD_STLCK;
- cdev->private->iccws[0].cda = (__u32) __pa(buf);
- cdev->private->iccws[0].count = 32;
- cdev->private->iccws[0].flags = CCW_FLAG_CC;
- cdev->private->iccws[1].cmd_code = CCW_CMD_RELEASE;
- cdev->private->iccws[1].cda = (__u32) __pa(buf2);
- cdev->private->iccws[1].count = 32;
- cdev->private->iccws[1].flags = 0;
- ret = cio_start(sch, cdev->private->iccws, 0);
- if (ret) {
- cio_disable_subchannel(sch); //FIXME: return code?
+ buffer = kzalloc(64, GFP_DMA | GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+ init_completion(&data.done);
+ data.rc = -EIO;
+ spin_lock_irq(sch->lock);
+ rc = cio_enable_subchannel(sch, (u32) (addr_t) sch);
+ if (rc)
goto out_unlock;
+ /* Perform operation. */
+ cdev->private->state = DEV_STATE_STEAL_LOCK,
+ ccw_device_stlck_start(cdev, &data, &buffer[0], &buffer[32]);
+ spin_unlock_irq(sch->lock);
+ /* Wait for operation to finish. */
+ if (wait_for_completion_interruptible(&data.done)) {
+ /* Got a signal. */
+ spin_lock_irq(sch->lock);
+ ccw_request_cancel(cdev);
+ spin_unlock_irq(sch->lock);
+ wait_for_completion(&data.done);
}
- cdev->private->irb.scsw.cmd.actl |= SCSW_ACTL_START_PEND;
- spin_unlock_irqrestore(sch->lock, flags);
- wait_event(cdev->private->wait_q,
- cdev->private->irb.scsw.cmd.actl == 0);
- spin_lock_irqsave(sch->lock, flags);
- cio_disable_subchannel(sch); //FIXME: return code?
- if ((cdev->private->irb.scsw.cmd.dstat !=
- (DEV_STAT_CHN_END|DEV_STAT_DEV_END)) ||
- (cdev->private->irb.scsw.cmd.cstat != 0))
- ret = -EIO;
- /* Clear irb. */
- memset(&cdev->private->irb, 0, sizeof(struct irb));
+ rc = data.rc;
+ /* Check results. */
+ spin_lock_irq(sch->lock);
+ cio_disable_subchannel(sch);
+ cdev->private->state = DEV_STATE_BOXED;
out_unlock:
- kfree(buf);
- kfree(buf2);
- spin_unlock_irqrestore(sch->lock, flags);
- return ret;
+ spin_unlock_irq(sch->lock);
+ kfree(buffer);
+
+ return rc;
}
void *ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no)
diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c
index fc5ca1d..aad188e 100644
--- a/drivers/s390/cio/device_pgid.c
+++ b/drivers/s390/cio/device_pgid.c
@@ -1,594 +1,561 @@
/*
- * drivers/s390/cio/device_pgid.c
+ * CCW device PGID and path verification I/O handling.
*
- * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
- * IBM Corporation
- * Author(s): Cornelia Huck (cornelia.huck@de.ibm.com)
- * Martin Schwidefsky (schwidefsky@de.ibm.com)
- *
- * Path Group ID functions.
+ * Copyright IBM Corp. 2002,2009
+ * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
+ * Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
*/
-#include <linux/module.h>
-#include <linux/init.h>
-
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/bitops.h>
#include <asm/ccwdev.h>
#include <asm/cio.h>
-#include <asm/delay.h>
-#include <asm/lowcore.h>
#include "cio.h"
#include "cio_debug.h"
-#include "css.h"
#include "device.h"
-#include "ioasm.h"
#include "io_sch.h"
+#define PGID_RETRIES 256
+#define PGID_TIMEOUT (10 * HZ)
+
/*
- * Helper function called from interrupt context to decide whether an
- * operation should be tried again.
+ * Process path verification data and report result.
*/
-static int __ccw_device_should_retry(union scsw *scsw)
+static void verify_done(struct ccw_device *cdev, int rc)
{
- /* CC is only valid if start function bit is set. */
- if ((scsw->cmd.fctl & SCSW_FCTL_START_FUNC) && scsw->cmd.cc == 1)
- return 1;
- /* No more activity. For sense and set PGID we stubbornly try again. */
- if (!scsw->cmd.actl)
- return 1;
- return 0;
+ struct subchannel *sch = to_subchannel(cdev->dev.parent);
+ struct ccw_dev_id *id = &cdev->private->dev_id;
+ int mpath = cdev->private->flags.mpath;
+ int pgroup = cdev->private->flags.pgroup;
+
+ if (rc)
+ goto out;
+ /* Ensure consistent multipathing state at device and channel. */
+ if (sch->config.mp != mpath) {
+ sch->config.mp = mpath;
+ rc = cio_commit_config(sch);
+ }
+out:
+ CIO_MSG_EVENT(2, "vrfy: device 0.%x.%04x: rc=%d pgroup=%d mpath=%d "
+ "vpm=%02x\n", id->ssid, id->devno, rc, pgroup, mpath,
+ sch->vpm);
+ ccw_device_verify_done(cdev, rc);
}
/*
- * Start Sense Path Group ID helper function. Used in ccw_device_recog
- * and ccw_device_sense_pgid.
+ * Create channel program to perform a NOOP.
*/
-static int
-__ccw_device_sense_pgid_start(struct ccw_device *cdev)
+static void nop_build_cp(struct ccw_device *cdev)
{
- struct subchannel *sch;
- struct ccw1 *ccw;
- int ret;
- int i;
-
- sch = to_subchannel(cdev->dev.parent);
- /* Return if we already checked on all paths. */
- if (cdev->private->imask == 0)
- return (sch->lpm == 0) ? -ENODEV : -EACCES;
- i = 8 - ffs(cdev->private->imask);
-
- /* Setup sense path group id channel program. */
- ccw = cdev->private->iccws;
- ccw->cmd_code = CCW_CMD_SENSE_PGID;
- ccw->count = sizeof (struct pgid);
- ccw->flags = CCW_FLAG_SLI;
-
- /* Reset device status. */
- memset(&cdev->private->irb, 0, sizeof(struct irb));
- /* Try on every path. */
- ret = -ENODEV;
- while (cdev->private->imask != 0) {
- /* Try every path multiple times. */
- ccw->cda = (__u32) __pa (&cdev->private->pgid[i]);
- if (cdev->private->iretry > 0) {
- cdev->private->iretry--;
- /* Reset internal retry indication. */
- cdev->private->flags.intretry = 0;
- ret = cio_start (sch, cdev->private->iccws,
- cdev->private->imask);
- /* ret is 0, -EBUSY, -EACCES or -ENODEV */
- if (ret != -EACCES)
- return ret;
- CIO_MSG_EVENT(3, "SNID - Device %04x on Subchannel "
- "0.%x.%04x, lpm %02X, became 'not "
- "operational'\n",
- cdev->private->dev_id.devno,
- sch->schid.ssid,
- sch->schid.sch_no, cdev->private->imask);
-
- }
- cdev->private->imask >>= 1;
- cdev->private->iretry = 5;
- i++;
- }
-
- return ret;
+ struct ccw_request *req = &cdev->private->req;
+ struct ccw1 *cp = cdev->private->iccws;
+
+ cp->cmd_code = CCW_CMD_NOOP;
+ cp->cda = 0;
+ cp->count = 0;
+ cp->flags = CCW_FLAG_SLI;
+ req->cp = cp;
}
-void
-ccw_device_sense_pgid_start(struct ccw_device *cdev)
+/*
+ * Perform NOOP on a single path.
+ */
+static void nop_do(struct ccw_device *cdev)
{
- int ret;
-
- /* Set a timeout of 60s */
- ccw_device_set_timeout(cdev, 60*HZ);
-
- cdev->private->state = DEV_STATE_SENSE_PGID;
- cdev->private->imask = 0x80;
- cdev->private->iretry = 5;
- memset (&cdev->private->pgid, 0, sizeof (cdev->private->pgid));
- ret = __ccw_device_sense_pgid_start(cdev);
- if (ret && ret != -EBUSY)
- ccw_device_sense_pgid_done(cdev, ret);
+ struct subchannel *sch = to_subchannel(cdev->dev.parent);
+ struct ccw_request *req = &cdev->private->req;
+
+ /* Adjust lpm. */
+ req->lpm = lpm_adjust(req->lpm, sch->schib.pmcw.pam & sch->opm);
+ if (!req->lpm)
+ goto out_nopath;
+ nop_build_cp(cdev);
+ ccw_request_start(cdev);
+ return;
+
+out_nopath:
+ verify_done(cdev, sch->vpm ? 0 : -EACCES);
}
/*
- * Called from interrupt context to check if a valid answer
- * to Sense Path Group ID was received.
+ * Adjust NOOP I/O status.
*/
-static int
-__ccw_device_check_sense_pgid(struct ccw_device *cdev)
+static enum io_status nop_filter(struct ccw_device *cdev, void *data,
+ struct irb *irb, enum io_status status)
{
- struct subchannel *sch;
- struct irb *irb;
- int i;
-
- sch = to_subchannel(cdev->dev.parent);
- irb = &cdev->private->irb;
- if (irb->scsw.cmd.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) {
- /* Retry Sense PGID if requested. */
- if (cdev->private->flags.intretry) {
- cdev->private->flags.intretry = 0;
- return -EAGAIN;
- }
- return -ETIME;
- }
- if (irb->esw.esw0.erw.cons &&
- (irb->ecw[0]&(SNS0_CMD_REJECT|SNS0_INTERVENTION_REQ))) {
- /*
- * If the device doesn't support the Sense Path Group ID
- * command further retries wouldn't help ...
- */
- return -EOPNOTSUPP;
- }
- if (irb->esw.esw0.erw.cons) {
- CIO_MSG_EVENT(2, "SNID - device 0.%x.%04x, unit check, "
- "lpum %02X, cnt %02d, sns : "
- "%02X%02X%02X%02X %02X%02X%02X%02X ...\n",
- cdev->private->dev_id.ssid,
- cdev->private->dev_id.devno,
- irb->esw.esw0.sublog.lpum,
- irb->esw.esw0.erw.scnt,
- irb->ecw[0], irb->ecw[1],
- irb->ecw[2], irb->ecw[3],
- irb->ecw[4], irb->ecw[5],
- irb->ecw[6], irb->ecw[7]);
- return -EAGAIN;
- }
- if (irb->scsw.cmd.cc == 3) {
- u8 lpm;
-
- lpm = to_io_private(sch)->orb.cmd.lpm;
- CIO_MSG_EVENT(3, "SNID - Device %04x on Subchannel 0.%x.%04x,"
- " lpm %02X, became 'not operational'\n",
- cdev->private->dev_id.devno, sch->schid.ssid,
- sch->schid.sch_no, lpm);
- return -EACCES;
- }
- i = 8 - ffs(cdev->private->imask);
- if (cdev->private->pgid[i].inf.ps.state2 == SNID_STATE2_RESVD_ELSE) {
- CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel 0.%x.%04x "
- "is reserved by someone else\n",
- cdev->private->dev_id.devno, sch->schid.ssid,
- sch->schid.sch_no);
- return -EUSERS;
- }
- return 0;
+ /* Only subchannel status might indicate a path error. */
+ if (status == IO_STATUS_ERROR && irb->scsw.cmd.cstat == 0)
+ return IO_DONE;
+ return status;
}
/*
- * Got interrupt for Sense Path Group ID.
+ * Process NOOP request result for a single path.
*/
-void
-ccw_device_sense_pgid_irq(struct ccw_device *cdev, enum dev_event dev_event)
+static void nop_callback(struct ccw_device *cdev, void *data, int rc)
{
- struct subchannel *sch;
- struct irb *irb;
- int ret;
-
- irb = (struct irb *) __LC_IRB;
-
- if (irb->scsw.cmd.stctl ==
- (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
- if (__ccw_device_should_retry(&irb->scsw)) {
- ret = __ccw_device_sense_pgid_start(cdev);
- if (ret && ret != -EBUSY)
- ccw_device_sense_pgid_done(cdev, ret);
- }
- return;
- }
- if (ccw_device_accumulate_and_sense(cdev, irb) != 0)
- return;
- sch = to_subchannel(cdev->dev.parent);
- ret = __ccw_device_check_sense_pgid(cdev);
- memset(&cdev->private->irb, 0, sizeof(struct irb));
- switch (ret) {
- /* 0, -ETIME, -EOPNOTSUPP, -EAGAIN, -EACCES or -EUSERS */
- case -EOPNOTSUPP: /* Sense Path Group ID not supported */
- ccw_device_sense_pgid_done(cdev, -EOPNOTSUPP);
- break;
- case -ETIME: /* Sense path group id stopped by timeout. */
- ccw_device_sense_pgid_done(cdev, -ETIME);
- break;
- case -EACCES: /* channel is not operational. */
- sch->lpm &= ~cdev->private->imask;
- /* Fall through. */
- case 0: /* Sense Path Group ID successful. */
- cdev->private->imask >>= 1;
- cdev->private->iretry = 5;
- /* Fall through. */
- case -EAGAIN: /* Try again. */
- ret = __ccw_device_sense_pgid_start(cdev);
- if (ret != 0 && ret != -EBUSY)
- ccw_device_sense_pgid_done(cdev, ret);
- break;
- case -EUSERS: /* device is reserved for someone else. */
- ccw_device_sense_pgid_done(cdev, -EUSERS);
- break;
- }
+ struct subchannel *sch = to_subchannel(cdev->dev.parent);
+ struct ccw_request *req = &cdev->private->req;
+
+ if (rc == 0)
+ sch->vpm |= req->lpm;
+ else if (rc != -EACCES)
+ goto err;
+ req->lpm >>= 1;
+ nop_do(cdev);
+ return;
+
+err:
+ verify_done(cdev, rc);
}
/*
- * Path Group ID helper function.
+ * Create channel program to perform SET PGID on a single path.
*/
-static int
-__ccw_device_do_pgid(struct ccw_device *cdev, __u8 func)
+static void spid_build_cp(struct ccw_device *cdev, u8 fn)
{
- struct subchannel *sch;
- struct ccw1 *ccw;
- int ret;
-
- sch = to_subchannel(cdev->dev.parent);
-
- /* Setup sense path group id channel program. */
- cdev->private->pgid[0].inf.fc = func;
- ccw = cdev->private->iccws;
- if (cdev->private->flags.pgid_single)
- cdev->private->pgid[0].inf.fc |= SPID_FUNC_SINGLE_PATH;
- else
- cdev->private->pgid[0].inf.fc |= SPID_FUNC_MULTI_PATH;
- ccw->cmd_code = CCW_CMD_SET_PGID;
- ccw->cda = (__u32) __pa (&cdev->private->pgid[0]);
- ccw->count = sizeof (struct pgid);
- ccw->flags = CCW_FLAG_SLI;
-
- /* Reset device status. */
- memset(&cdev->private->irb, 0, sizeof(struct irb));
-
- /* Try multiple times. */
- ret = -EACCES;
- if (cdev->private->iretry > 0) {
- cdev->private->iretry--;
- /* Reset internal retry indication. */
- cdev->private->flags.intretry = 0;
- ret = cio_start (sch, cdev->private->iccws,
- cdev->private->imask);
- /* We expect an interrupt in case of success or busy
- * indication. */
- if ((ret == 0) || (ret == -EBUSY))
- return ret;
- }
- /* PGID command failed on this path. */
- CIO_MSG_EVENT(3, "SPID - Device %04x on Subchannel "
- "0.%x.%04x, lpm %02X, became 'not operational'\n",
- cdev->private->dev_id.devno, sch->schid.ssid,
- sch->schid.sch_no, cdev->private->imask);
- return ret;
+ struct ccw_request *req = &cdev->private->req;
+ struct ccw1 *cp = cdev->private->iccws;
+ int i = 8 - ffs(req->lpm);
+ struct pgid *pgid = &cdev->private->pgid[i];
+
+ pgid->inf.fc = fn;
+ cp->cmd_code = CCW_CMD_SET_PGID;
+ cp->cda = (u32) (addr_t) pgid;
+ cp->count = sizeof(*pgid);
+ cp->flags = CCW_FLAG_SLI;
+ req->cp = cp;
}
/*
- * Helper function to send a nop ccw down a path.
+ * Perform establish/resign SET PGID on a single path.
*/
-static int __ccw_device_do_nop(struct ccw_device *cdev)
+static void spid_do(struct ccw_device *cdev)
{
- struct subchannel *sch;
- struct ccw1 *ccw;
- int ret;
-
- sch = to_subchannel(cdev->dev.parent);
-
- /* Setup nop channel program. */
- ccw = cdev->private->iccws;
- ccw->cmd_code = CCW_CMD_NOOP;
- ccw->cda = 0;
- ccw->count = 0;
- ccw->flags = CCW_FLAG_SLI;
-
- /* Reset device status. */
- memset(&cdev->private->irb, 0, sizeof(struct irb));
-
- /* Try multiple times. */
- ret = -EACCES;
- if (cdev->private->iretry > 0) {
- cdev->private->iretry--;
- /* Reset internal retry indication. */
- cdev->private->flags.intretry = 0;
- ret = cio_start (sch, cdev->private->iccws,
- cdev->private->imask);
- /* We expect an interrupt in case of success or busy
- * indication. */
- if ((ret == 0) || (ret == -EBUSY))
- return ret;
- }
- /* nop command failed on this path. */
- CIO_MSG_EVENT(3, "NOP - Device %04x on Subchannel "
- "0.%x.%04x, lpm %02X, became 'not operational'\n",
- cdev->private->dev_id.devno, sch->schid.ssid,
- sch->schid.sch_no, cdev->private->imask);
- return ret;
+ struct subchannel *sch = to_subchannel(cdev->dev.parent);
+ struct ccw_request *req = &cdev->private->req;
+ u8 fn;
+
+ /* Use next available path that is not already in correct state. */
+ req->lpm = lpm_adjust(req->lpm, sch->schib.pmcw.pam & ~sch->vpm);
+ if (!req->lpm)
+ goto out_nopath;
+ /* Channel program setup. */
+ if (req->lpm & sch->opm)
+ fn = SPID_FUNC_ESTABLISH;
+ else
+ fn = SPID_FUNC_RESIGN;
+ if (cdev->private->flags.mpath)
+ fn |= SPID_FUNC_MULTI_PATH;
+ spid_build_cp(cdev, fn);
+ ccw_request_start(cdev);
+ return;
+
+out_nopath:
+ verify_done(cdev, sch->vpm ? 0 : -EACCES);
}
+static void verify_start(struct ccw_device *cdev);
/*
- * Called from interrupt context to check if a valid answer
- * to Set Path Group ID was received.
+ * Process SET PGID request result for a single path.
*/
-static int
-__ccw_device_check_pgid(struct ccw_device *cdev)
+static void spid_callback(struct ccw_device *cdev, void *data, int rc)
{
- struct subchannel *sch;
- struct irb *irb;
-
- sch = to_subchannel(cdev->dev.parent);
- irb = &cdev->private->irb;
- if (irb->scsw.cmd.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) {
- /* Retry Set PGID if requested. */
- if (cdev->private->flags.intretry) {
- cdev->private->flags.intretry = 0;
- return -EAGAIN;
+ struct subchannel *sch = to_subchannel(cdev->dev.parent);
+ struct ccw_request *req = &cdev->private->req;
+
+ switch (rc) {
+ case 0:
+ sch->vpm |= req->lpm & sch->opm;
+ break;
+ case -EACCES:
+ break;
+ case -EOPNOTSUPP:
+ if (cdev->private->flags.mpath) {
+ /* Try without multipathing. */
+ cdev->private->flags.mpath = 0;
+ goto out_restart;
}
- return -ETIME;
+ /* Try without pathgrouping. */
+ cdev->private->flags.pgroup = 0;
+ goto out_restart;
+ default:
+ goto err;
}
- if (irb->esw.esw0.erw.cons) {
- if (irb->ecw[0] & SNS0_CMD_REJECT)
- return -EOPNOTSUPP;
- /* Hmm, whatever happened, try again. */
- CIO_MSG_EVENT(2, "SPID - device 0.%x.%04x, unit check, "
- "cnt %02d, "
- "sns : %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
- cdev->private->dev_id.ssid,
- cdev->private->dev_id.devno,
- irb->esw.esw0.erw.scnt,
- irb->ecw[0], irb->ecw[1],
- irb->ecw[2], irb->ecw[3],
- irb->ecw[4], irb->ecw[5],
- irb->ecw[6], irb->ecw[7]);
- return -EAGAIN;
- }
- if (irb->scsw.cmd.cc == 3) {
- CIO_MSG_EVENT(3, "SPID - Device %04x on Subchannel 0.%x.%04x,"
- " lpm %02X, became 'not operational'\n",
- cdev->private->dev_id.devno, sch->schid.ssid,
- sch->schid.sch_no, cdev->private->imask);
- return -EACCES;
- }
- return 0;
+ req->lpm >>= 1;
+ spid_do(cdev);
+ return;
+
+out_restart:
+ verify_start(cdev);
+ return;
+err:
+ verify_done(cdev, rc);
+}
+
+static void spid_start(struct ccw_device *cdev)
+{
+ struct ccw_request *req = &cdev->private->req;
+
+ /* Initialize request data. */
+ memset(req, 0, sizeof(*req));
+ req->timeout = PGID_TIMEOUT;
+ req->maxretries = PGID_RETRIES;
+ req->lpm = 0x80;
+ req->callback = spid_callback;
+ spid_do(cdev);
+}
+
+static int pgid_cmp(struct pgid *p1, struct pgid *p2)
+{
+ return memcmp((char *) p1 + 1, (char *) p2 + 1,
+ sizeof(struct pgid) - 1);
}
/*
- * Called from interrupt context to check the path status after a nop has
- * been send.
+ * Determine pathgroup state from PGID data.
*/
-static int __ccw_device_check_nop(struct ccw_device *cdev)
+static void pgid_analyze(struct ccw_device *cdev, struct pgid **p,
+ int *mismatch, int *reserved, int *reset)
{
- struct subchannel *sch;
- struct irb *irb;
-
- sch = to_subchannel(cdev->dev.parent);
- irb = &cdev->private->irb;
- if (irb->scsw.cmd.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) {
- /* Retry NOP if requested. */
- if (cdev->private->flags.intretry) {
- cdev->private->flags.intretry = 0;
- return -EAGAIN;
+ struct pgid *pgid = &cdev->private->pgid[0];
+ struct pgid *first = NULL;
+ int lpm;
+ int i;
+
+ *mismatch = 0;
+ *reserved = 0;
+ *reset = 0;
+ for (i = 0, lpm = 0x80; i < 8; i++, pgid++, lpm >>= 1) {
+ if ((cdev->private->pgid_valid_mask & lpm) == 0)
+ continue;
+ if (pgid->inf.ps.state2 == SNID_STATE2_RESVD_ELSE)
+ *reserved = 1;
+ if (pgid->inf.ps.state1 == SNID_STATE1_RESET) {
+ /* A PGID was reset. */
+ *reset = 1;
+ continue;
}
- return -ETIME;
- }
- if (irb->scsw.cmd.cc == 3) {
- CIO_MSG_EVENT(3, "NOP - Device %04x on Subchannel 0.%x.%04x,"
- " lpm %02X, became 'not operational'\n",
- cdev->private->dev_id.devno, sch->schid.ssid,
- sch->schid.sch_no, cdev->private->imask);
- return -EACCES;
+ if (!first) {
+ first = pgid;
+ continue;
+ }
+ if (pgid_cmp(pgid, first) != 0)
+ *mismatch = 1;
}
- return 0;
+ if (!first)
+ first = &channel_subsystems[0]->global_pgid;
+ *p = first;
}
-static void
-__ccw_device_verify_start(struct ccw_device *cdev)
+static u8 pgid_to_vpm(struct ccw_device *cdev)
{
- struct subchannel *sch;
- __u8 func;
- int ret;
-
- sch = to_subchannel(cdev->dev.parent);
- /* Repeat for all paths. */
- for (; cdev->private->imask; cdev->private->imask >>= 1,
- cdev->private->iretry = 5) {
- if ((cdev->private->imask & sch->schib.pmcw.pam) == 0)
- /* Path not available, try next. */
+ struct subchannel *sch = to_subchannel(cdev->dev.parent);
+ struct pgid *pgid;
+ int i;
+ int lpm;
+ u8 vpm = 0;
+
+ /* Set VPM bits for paths which are already in the target state. */
+ for (i = 0; i < 8; i++) {
+ lpm = 0x80 >> i;
+ if ((cdev->private->pgid_valid_mask & lpm) == 0)
continue;
- if (cdev->private->options.pgroup) {
- if (sch->opm & cdev->private->imask)
- func = SPID_FUNC_ESTABLISH;
- else
- func = SPID_FUNC_RESIGN;
- ret = __ccw_device_do_pgid(cdev, func);
- } else
- ret = __ccw_device_do_nop(cdev);
- /* We expect an interrupt in case of success or busy
- * indication. */
- if (ret == 0 || ret == -EBUSY)
- return;
- /* Permanent path failure, try next. */
+ pgid = &cdev->private->pgid[i];
+ if (sch->opm & lpm) {
+ if (pgid->inf.ps.state1 != SNID_STATE1_GROUPED)
+ continue;
+ } else {
+ if (pgid->inf.ps.state1 != SNID_STATE1_UNGROUPED)
+ continue;
+ }
+ if (cdev->private->flags.mpath) {
+ if (pgid->inf.ps.state3 != SNID_STATE3_MULTI_PATH)
+ continue;
+ } else {
+ if (pgid->inf.ps.state3 != SNID_STATE3_SINGLE_PATH)
+ continue;
+ }
+ vpm |= lpm;
}
- /* Done with all paths. */
- ccw_device_verify_done(cdev, (sch->vpm != 0) ? 0 : -ENODEV);
+
+ return vpm;
}
-
-/*
- * Got interrupt for Set Path Group ID.
- */
-void
-ccw_device_verify_irq(struct ccw_device *cdev, enum dev_event dev_event)
+
+static void pgid_fill(struct ccw_device *cdev, struct pgid *pgid)
{
- struct subchannel *sch;
- struct irb *irb;
- int ret;
+ int i;
- irb = (struct irb *) __LC_IRB;
+ for (i = 0; i < 8; i++)
+ memcpy(&cdev->private->pgid[i], pgid, sizeof(struct pgid));
+}
- if (irb->scsw.cmd.stctl ==
- (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
- if (__ccw_device_should_retry(&irb->scsw))
- __ccw_device_verify_start(cdev);
- return;
+/*
+ * Process SENSE PGID data and report result.
+ */
+static void snid_done(struct ccw_device *cdev, int rc)
+{
+ struct ccw_dev_id *id = &cdev->private->dev_id;
+ struct subchannel *sch = to_subchannel(cdev->dev.parent);
+ struct pgid *pgid;
+ int mismatch = 0;
+ int reserved = 0;
+ int reset = 0;
+
+ if (rc)
+ goto out;
+ pgid_analyze(cdev, &pgid, &mismatch, &reserved, &reset);
+ if (reserved)
+ rc = -EUSERS;
+ else if (mismatch)
+ rc = -EOPNOTSUPP;
+ else {
+ sch->vpm = pgid_to_vpm(cdev);
+ pgid_fill(cdev, pgid);
}
- if (ccw_device_accumulate_and_sense(cdev, irb) != 0)
- return;
- sch = to_subchannel(cdev->dev.parent);
- if (cdev->private->options.pgroup)
- ret = __ccw_device_check_pgid(cdev);
- else
- ret = __ccw_device_check_nop(cdev);
- memset(&cdev->private->irb, 0, sizeof(struct irb));
-
- switch (ret) {
- /* 0, -ETIME, -EAGAIN, -EOPNOTSUPP or -EACCES */
+out:
+ CIO_MSG_EVENT(2, "snid: device 0.%x.%04x: rc=%d pvm=%02x vpm=%02x "
+ "mism=%d rsvd=%d reset=%d\n", id->ssid, id->devno, rc,
+ cdev->private->pgid_valid_mask, sch->vpm, mismatch,
+ reserved, reset);
+ switch (rc) {
case 0:
- /* Path verification ccw finished successfully, update lpm. */
- sch->vpm |= sch->opm & cdev->private->imask;
- /* Go on with next path. */
- cdev->private->imask >>= 1;
- cdev->private->iretry = 5;
- __ccw_device_verify_start(cdev);
+ /* Anything left to do? */
+ if (sch->vpm == sch->schib.pmcw.pam) {
+ verify_done(cdev, sch->vpm == 0 ? -EACCES : 0);
+ return;
+ }
+ /* Perform path-grouping. */
+ spid_start(cdev);
break;
case -EOPNOTSUPP:
- /*
- * One of those strange devices which claim to be able
- * to do multipathing but not for Set Path Group ID.
- */
- if (cdev->private->flags.pgid_single)
- cdev->private->options.pgroup = 0;
- else
- cdev->private->flags.pgid_single = 1;
- /* Retry */
- sch->vpm = 0;
- cdev->private->imask = 0x80;
- cdev->private->iretry = 5;
- /* fall through. */
- case -EAGAIN: /* Try again. */
- __ccw_device_verify_start(cdev);
- break;
- case -ETIME: /* Set path group id stopped by timeout. */
- ccw_device_verify_done(cdev, -ETIME);
- break;
- case -EACCES: /* channel is not operational. */
- cdev->private->imask >>= 1;
- cdev->private->iretry = 5;
- __ccw_device_verify_start(cdev);
+ /* Path-grouping not supported. */
+ cdev->private->flags.pgroup = 0;
+ cdev->private->flags.mpath = 0;
+ verify_start(cdev);
break;
+ default:
+ verify_done(cdev, rc);
}
}
-void
-ccw_device_verify_start(struct ccw_device *cdev)
+/*
+ * Create channel program to perform a SENSE PGID on a single path.
+ */
+static void snid_build_cp(struct ccw_device *cdev)
+{
+ struct ccw_request *req = &cdev->private->req;
+ struct ccw1 *cp = cdev->private->iccws;
+ int i = 8 - ffs(req->lpm);
+
+ /* Channel program setup. */
+ cp->cmd_code = CCW_CMD_SENSE_PGID;
+ cp->cda = (u32) (addr_t) &cdev->private->pgid[i];
+ cp->count = sizeof(struct pgid);
+ cp->flags = CCW_FLAG_SLI;
+ req->cp = cp;
+}
+
+/*
+ * Perform SENSE PGID on a single path.
+ */
+static void snid_do(struct ccw_device *cdev)
{
struct subchannel *sch = to_subchannel(cdev->dev.parent);
+ struct ccw_request *req = &cdev->private->req;
+
+ /* Adjust lpm if paths are not set in pam. */
+ req->lpm = lpm_adjust(req->lpm, sch->schib.pmcw.pam);
+ if (!req->lpm)
+ goto out_nopath;
+ snid_build_cp(cdev);
+ ccw_request_start(cdev);
+ return;
+
+out_nopath:
+ snid_done(cdev, cdev->private->pgid_valid_mask ? 0 : -EACCES);
+}
- cdev->private->flags.pgid_single = 0;
- cdev->private->imask = 0x80;
- cdev->private->iretry = 5;
+/*
+ * Process SENSE PGID request result for single path.
+ */
+static void snid_callback(struct ccw_device *cdev, void *data, int rc)
+{
+ struct ccw_request *req = &cdev->private->req;
+
+ if (rc == 0)
+ cdev->private->pgid_valid_mask |= req->lpm;
+ else if (rc != -EACCES)
+ goto err;
+ req->lpm >>= 1;
+ snid_do(cdev);
+ return;
+
+err:
+ snid_done(cdev, rc);
+}
- /* Start with empty vpm. */
- sch->vpm = 0;
+/*
+ * Perform path verification.
+ */
+static void verify_start(struct ccw_device *cdev)
+{
+ struct subchannel *sch = to_subchannel(cdev->dev.parent);
+ struct ccw_request *req = &cdev->private->req;
+ struct ccw_dev_id *devid = &cdev->private->dev_id;
- /* Get current pam. */
- if (cio_update_schib(sch)) {
- ccw_device_verify_done(cdev, -ENODEV);
- return;
+ sch->vpm = 0;
+ /* Initialize request data. */
+ memset(req, 0, sizeof(*req));
+ req->timeout = PGID_TIMEOUT;
+ req->maxretries = PGID_RETRIES;
+ req->lpm = 0x80;
+ if (cdev->private->flags.pgroup) {
+ CIO_TRACE_EVENT(4, "snid");
+ CIO_HEX_EVENT(4, devid, sizeof(*devid));
+ req->callback = snid_callback;
+ snid_do(cdev);
+ } else {
+ CIO_TRACE_EVENT(4, "nop");
+ CIO_HEX_EVENT(4, devid, sizeof(*devid));
+ req->filter = nop_filter;
+ req->callback = nop_callback;
+ nop_do(cdev);
}
- /* After 60s path verification is considered to have failed. */
- ccw_device_set_timeout(cdev, 60*HZ);
- __ccw_device_verify_start(cdev);
}
-static void
-__ccw_device_disband_start(struct ccw_device *cdev)
+/**
+ * ccw_device_verify_start - perform path verification
+ * @cdev: ccw device
+ *
+ * Perform an I/O on each available channel path to @cdev to determine which
+ * paths are operational. The resulting path mask is stored in sch->vpm.
+ * If device options specify pathgrouping, establish a pathgroup for the
+ * operational paths. When finished, call ccw_device_verify_done with a
+ * return code specifying the result.
+ */
+void ccw_device_verify_start(struct ccw_device *cdev)
{
- struct subchannel *sch;
- int ret;
-
- sch = to_subchannel(cdev->dev.parent);
- while (cdev->private->imask != 0) {
- if (sch->lpm & cdev->private->imask) {
- ret = __ccw_device_do_pgid(cdev, SPID_FUNC_DISBAND);
- if (ret == 0)
- return;
- }
- cdev->private->iretry = 5;
- cdev->private->imask >>= 1;
- }
- ccw_device_disband_done(cdev, (sch->lpm != 0) ? 0 : -ENODEV);
+ CIO_TRACE_EVENT(4, "vrfy");
+ CIO_HEX_EVENT(4, &cdev->private->dev_id, sizeof(cdev->private->dev_id));
+ /* Initialize PGID data. */
+ memset(cdev->private->pgid, 0, sizeof(cdev->private->pgid));
+ cdev->private->pgid_valid_mask = 0;
+ /*
+ * Initialize pathgroup and multipath state with target values.
+ * They may change in the course of path verification.
+ */
+ cdev->private->flags.pgroup = cdev->private->options.pgroup;
+ cdev->private->flags.mpath = cdev->private->options.mpath;
+ cdev->private->flags.doverify = 0;
+ verify_start(cdev);
}
/*
- * Got interrupt for Unset Path Group ID.
+ * Process disband SET PGID request result.
*/
-void
-ccw_device_disband_irq(struct ccw_device *cdev, enum dev_event dev_event)
+static void disband_callback(struct ccw_device *cdev, void *data, int rc)
{
- struct subchannel *sch;
- struct irb *irb;
- int ret;
+ struct subchannel *sch = to_subchannel(cdev->dev.parent);
+ struct ccw_dev_id *id = &cdev->private->dev_id;
+
+ if (rc)
+ goto out;
+ /* Ensure consistent multipathing state at device and channel. */
+ cdev->private->flags.mpath = 0;
+ if (sch->config.mp) {
+ sch->config.mp = 0;
+ rc = cio_commit_config(sch);
+ }
+out:
+ CIO_MSG_EVENT(0, "disb: device 0.%x.%04x: rc=%d\n", id->ssid, id->devno,
+ rc);
+ ccw_device_disband_done(cdev, rc);
+}
- irb = (struct irb *) __LC_IRB;
+/**
+ * ccw_device_disband_start - disband pathgroup
+ * @cdev: ccw device
+ *
+ * Execute a SET PGID channel program on @cdev to disband a previously
+ * established pathgroup. When finished, call ccw_device_disband_done with
+ * a return code specifying the result.
+ */
+void ccw_device_disband_start(struct ccw_device *cdev)
+{
+ struct subchannel *sch = to_subchannel(cdev->dev.parent);
+ struct ccw_request *req = &cdev->private->req;
+ u8 fn;
+
+ CIO_TRACE_EVENT(4, "disb");
+ CIO_HEX_EVENT(4, &cdev->private->dev_id, sizeof(cdev->private->dev_id));
+ /* Request setup. */
+ memset(req, 0, sizeof(*req));
+ req->timeout = PGID_TIMEOUT;
+ req->maxretries = PGID_RETRIES;
+ req->lpm = sch->schib.pmcw.pam & sch->opm;
+ req->callback = disband_callback;
+ fn = SPID_FUNC_DISBAND;
+ if (cdev->private->flags.mpath)
+ fn |= SPID_FUNC_MULTI_PATH;
+ spid_build_cp(cdev, fn);
+ ccw_request_start(cdev);
+}
- if (irb->scsw.cmd.stctl ==
- (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
- if (__ccw_device_should_retry(&irb->scsw))
- __ccw_device_disband_start(cdev);
- return;
- }
- if (ccw_device_accumulate_and_sense(cdev, irb) != 0)
- return;
- sch = to_subchannel(cdev->dev.parent);
- ret = __ccw_device_check_pgid(cdev);
- memset(&cdev->private->irb, 0, sizeof(struct irb));
- switch (ret) {
- /* 0, -ETIME, -EAGAIN, -EOPNOTSUPP or -EACCES */
- case 0: /* disband successful. */
- ccw_device_disband_done(cdev, ret);
- break;
- case -EOPNOTSUPP:
- /*
- * One of those strange devices which claim to be able
- * to do multipathing but not for Unset Path Group ID.
- */
- cdev->private->flags.pgid_single = 1;
- /* fall through. */
- case -EAGAIN: /* Try again. */
- __ccw_device_disband_start(cdev);
- break;
- case -ETIME: /* Set path group id stopped by timeout. */
- ccw_device_disband_done(cdev, -ETIME);
- break;
- case -EACCES: /* channel is not operational. */
- cdev->private->imask >>= 1;
- cdev->private->iretry = 5;
- __ccw_device_disband_start(cdev);
- break;
- }
+static void stlck_build_cp(struct ccw_device *cdev, void *buf1, void *buf2)
+{
+ struct ccw_request *req = &cdev->private->req;
+ struct ccw1 *cp = cdev->private->iccws;
+
+ cp[0].cmd_code = CCW_CMD_STLCK;
+ cp[0].cda = (u32) (addr_t) buf1;
+ cp[0].count = 32;
+ cp[0].flags = CCW_FLAG_CC;
+ cp[1].cmd_code = CCW_CMD_RELEASE;
+ cp[1].cda = (u32) (addr_t) buf2;
+ cp[1].count = 32;
+ cp[1].flags = 0;
+ req->cp = cp;
}
-void
-ccw_device_disband_start(struct ccw_device *cdev)
+static void stlck_callback(struct ccw_device *cdev, void *data, int rc)
{
- /* After 60s disbanding is considered to have failed. */
- ccw_device_set_timeout(cdev, 60*HZ);
+ ccw_device_stlck_done(cdev, data, rc);
+}
- cdev->private->flags.pgid_single = 0;
- cdev->private->iretry = 5;
- cdev->private->imask = 0x80;
- __ccw_device_disband_start(cdev);
+/**
+ * ccw_device_stlck_start - perform unconditional release
+ * @cdev: ccw device
+ * @data: data pointer to be passed to ccw_device_stlck_done
+ * @buf1: data pointer used in channel program
+ * @buf2: data pointer used in channel program
+ *
+ * Execute a channel program on @cdev to release an existing PGID reservation.
+ * When finished, call ccw_device_stlck_done with a return code specifying the
+ * result.
+ */
+void ccw_device_stlck_start(struct ccw_device *cdev, void *data, void *buf1,
+ void *buf2)
+{
+ struct subchannel *sch = to_subchannel(cdev->dev.parent);
+ struct ccw_request *req = &cdev->private->req;
+
+ CIO_TRACE_EVENT(4, "stlck");
+ CIO_HEX_EVENT(4, &cdev->private->dev_id, sizeof(cdev->private->dev_id));
+ /* Request setup. */
+ memset(req, 0, sizeof(*req));
+ req->timeout = PGID_TIMEOUT;
+ req->maxretries = PGID_RETRIES;
+ req->lpm = sch->schib.pmcw.pam & sch->opm;
+ req->data = data;
+ req->callback = stlck_callback;
+ stlck_build_cp(cdev, buf1, buf2);
+ ccw_request_start(cdev);
}
+
diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c
index 5814dbe..66d8066 100644
--- a/drivers/s390/cio/device_status.c
+++ b/drivers/s390/cio/device_status.c
@@ -336,9 +336,6 @@ ccw_device_do_sense(struct ccw_device *cdev, struct irb *irb)
sense_ccw->count = SENSE_MAX_COUNT;
sense_ccw->flags = CCW_FLAG_SLI;
- /* Reset internal retry indication. */
- cdev->private->flags.intretry = 0;
-
rc = cio_start(sch, sense_ccw, 0xff);
if (rc == -ENODEV || rc == -EACCES)
dev_fsm_event(cdev, DEV_EVENT_VERIFY);
diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h
index 0b8f381..d72ae4c 100644
--- a/drivers/s390/cio/io_sch.h
+++ b/drivers/s390/cio/io_sch.h
@@ -1,7 +1,10 @@
#ifndef S390_IO_SCH_H
#define S390_IO_SCH_H
+#include <linux/types.h>
#include <asm/schid.h>
+#include <asm/ccwdev.h>
+#include "css.h"
/*
* command-mode operation request block
@@ -68,6 +71,52 @@ struct io_subchannel_private {
#define MAX_CIWS 8
/*
+ * Possible status values for a CCW request's I/O.
+ */
+enum io_status {
+ IO_DONE,
+ IO_RUNNING,
+ IO_STATUS_ERROR,
+ IO_PATH_ERROR,
+ IO_REJECTED,
+ IO_KILLED
+};
+
+/**
+ * ccw_request - Internal CCW request.
+ * @cp: channel program to start
+ * @timeout: maximum allowable time in jiffies between start I/O and interrupt
+ * @maxretries: number of retries per I/O operation and path
+ * @lpm: mask of paths to use
+ * @check: optional callback that determines if results are final
+ * @filter: optional callback to adjust request status based on IRB data
+ * @callback: final callback
+ * @data: user-defined pointer passed to all callbacks
+ * @mask: current path mask
+ * @retries: current number of retries
+ * @drc: delayed return code
+ * @cancel: non-zero if request was cancelled
+ * @done: non-zero if request was finished
+ */
+struct ccw_request {
+ struct ccw1 *cp;
+ unsigned long timeout;
+ u16 maxretries;
+ u8 lpm;
+ int (*check)(struct ccw_device *, void *);
+ enum io_status (*filter)(struct ccw_device *, void *, struct irb *,
+ enum io_status);
+ void (*callback)(struct ccw_device *, void *, int);
+ void *data;
+ /* These fields are used internally. */
+ u16 mask;
+ u16 retries;
+ int drc;
+ int cancel:1;
+ int done:1;
+} __attribute__((packed));
+
+/*
* sense-id response buffer layout
*/
struct senseid {
@@ -82,32 +131,43 @@ struct senseid {
struct ciw ciw[MAX_CIWS]; /* variable # of CIWs */
} __attribute__ ((packed, aligned(4)));
+enum cdev_todo {
+ CDEV_TODO_NOTHING,
+ CDEV_TODO_ENABLE_CMF,
+ CDEV_TODO_REBIND,
+ CDEV_TODO_REGISTER,
+ CDEV_TODO_UNREG,
+ CDEV_TODO_UNREG_EVAL,
+};
+
struct ccw_device_private {
struct ccw_device *cdev;
struct subchannel *sch;
int state; /* device state */
atomic_t onoff;
- unsigned long registered;
struct ccw_dev_id dev_id; /* device id */
struct subchannel_id schid; /* subchannel number */
- u8 imask; /* lpm mask for SNID/SID/SPGID */
- int iretry; /* retry counter SNID/SID/SPGID */
+ struct ccw_request req; /* internal I/O request */
+ int iretry;
+ u8 pgid_valid_mask; /* mask of valid PGIDs */
struct {
unsigned int fast:1; /* post with "channel end" */
unsigned int repall:1; /* report every interrupt status */
unsigned int pgroup:1; /* do path grouping */
unsigned int force:1; /* allow forced online */
+ unsigned int mpath:1; /* do multipathing */
} __attribute__ ((packed)) options;
struct {
- unsigned int pgid_single:1; /* use single path for Set PGID */
unsigned int esid:1; /* Ext. SenseID supported by HW */
unsigned int dosense:1; /* delayed SENSE required */
unsigned int doverify:1; /* delayed path verification */
unsigned int donotify:1; /* call notify function */
unsigned int recog_done:1; /* dev. recog. complete */
unsigned int fake_irb:1; /* deliver faked irb */
- unsigned int intretry:1; /* retry internal operation */
unsigned int resuming:1; /* recognition while resume */
+ unsigned int pgroup:1; /* pathgroup is set up */
+ unsigned int mpath:1; /* multipathing is set up */
+ unsigned int initialized:1; /* set if initial reference held */
} __attribute__((packed)) flags;
unsigned long intparm; /* user interruption parameter */
struct qdio_irq *qdio_data;
@@ -115,7 +175,8 @@ struct ccw_device_private {
struct senseid senseid; /* SenseID info */
struct pgid pgid[8]; /* path group IDs per chpid*/
struct ccw1 iccws[2]; /* ccws for SNID/SID/SPGID commands */
- struct work_struct kick_work;
+ struct work_struct todo_work;
+ enum cdev_todo todo;
wait_queue_head_t wait_q;
struct timer_list timer;
void *cmb; /* measurement information */
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index 1294876..20836ef 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -102,6 +102,7 @@ static atomic_t ap_poll_requests = ATOMIC_INIT(0);
static DECLARE_WAIT_QUEUE_HEAD(ap_poll_wait);
static struct task_struct *ap_poll_kthread = NULL;
static DEFINE_MUTEX(ap_poll_thread_mutex);
+static DEFINE_SPINLOCK(ap_poll_timer_lock);
static void *ap_interrupt_indicator;
static struct hrtimer ap_poll_timer;
/* In LPAR poll with 4kHz frequency. Poll every 250000 nanoseconds.
@@ -282,6 +283,7 @@ static int ap_queue_enable_interruption(ap_qid_t qid, void *ind)
* @psmid: The program supplied message identifier
* @msg: The message text
* @length: The message length
+ * @special: Special Bit
*
* Returns AP queue status structure.
* Condition code 1 on NQAP can't happen because the L bit is 1.
@@ -289,7 +291,8 @@ static int ap_queue_enable_interruption(ap_qid_t qid, void *ind)
* because a segment boundary was reached. The NQAP is repeated.
*/
static inline struct ap_queue_status
-__ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length)
+__ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length,
+ unsigned int special)
{
typedef struct { char _[length]; } msgblock;
register unsigned long reg0 asm ("0") = qid | 0x40000000UL;
@@ -299,6 +302,9 @@ __ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length)
register unsigned long reg4 asm ("4") = (unsigned int) (psmid >> 32);
register unsigned long reg5 asm ("5") = (unsigned int) psmid;
+ if (special == 1)
+ reg0 |= 0x400000UL;
+
asm volatile (
"0: .long 0xb2ad0042\n" /* DQAP */
" brc 2,0b"
@@ -312,13 +318,15 @@ int ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length)
{
struct ap_queue_status status;
- status = __ap_send(qid, psmid, msg, length);
+ status = __ap_send(qid, psmid, msg, length, 0);
switch (status.response_code) {
case AP_RESPONSE_NORMAL:
return 0;
case AP_RESPONSE_Q_FULL:
case AP_RESPONSE_RESET_IN_PROGRESS:
return -EBUSY;
+ case AP_RESPONSE_REQ_FAC_NOT_INST:
+ return -EINVAL;
default: /* Device is gone. */
return -ENODEV;
}
@@ -1008,7 +1016,7 @@ static int ap_probe_device_type(struct ap_device *ap_dev)
}
status = __ap_send(ap_dev->qid, 0x0102030405060708ULL,
- msg, sizeof(msg));
+ msg, sizeof(msg), 0);
if (status.response_code != AP_RESPONSE_NORMAL) {
rc = -ENODEV;
goto out_free;
@@ -1163,16 +1171,19 @@ ap_config_timeout(unsigned long ptr)
static inline void ap_schedule_poll_timer(void)
{
ktime_t hr_time;
+
+ spin_lock_bh(&ap_poll_timer_lock);
if (ap_using_interrupts() || ap_suspend_flag)
- return;
+ goto out;
if (hrtimer_is_queued(&ap_poll_timer))
- return;
+ goto out;
if (ktime_to_ns(hrtimer_expires_remaining(&ap_poll_timer)) <= 0) {
hr_time = ktime_set(0, poll_timeout);
hrtimer_forward_now(&ap_poll_timer, hr_time);
hrtimer_restart(&ap_poll_timer);
}
- return;
+out:
+ spin_unlock_bh(&ap_poll_timer_lock);
}
/**
@@ -1243,7 +1254,7 @@ static int ap_poll_write(struct ap_device *ap_dev, unsigned long *flags)
/* Start the next request on the queue. */
ap_msg = list_entry(ap_dev->requestq.next, struct ap_message, list);
status = __ap_send(ap_dev->qid, ap_msg->psmid,
- ap_msg->message, ap_msg->length);
+ ap_msg->message, ap_msg->length, ap_msg->special);
switch (status.response_code) {
case AP_RESPONSE_NORMAL:
atomic_inc(&ap_poll_requests);
@@ -1261,6 +1272,7 @@ static int ap_poll_write(struct ap_device *ap_dev, unsigned long *flags)
*flags |= 2;
break;
case AP_RESPONSE_MESSAGE_TOO_BIG:
+ case AP_RESPONSE_REQ_FAC_NOT_INST:
return -EINVAL;
default:
return -ENODEV;
@@ -1302,7 +1314,8 @@ static int __ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_ms
if (list_empty(&ap_dev->requestq) &&
ap_dev->queue_count < ap_dev->queue_depth) {
status = __ap_send(ap_dev->qid, ap_msg->psmid,
- ap_msg->message, ap_msg->length);
+ ap_msg->message, ap_msg->length,
+ ap_msg->special);
switch (status.response_code) {
case AP_RESPONSE_NORMAL:
list_add_tail(&ap_msg->list, &ap_dev->pendingq);
@@ -1317,6 +1330,7 @@ static int __ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_ms
ap_dev->requestq_count++;
ap_dev->total_request_count++;
return -EBUSY;
+ case AP_RESPONSE_REQ_FAC_NOT_INST:
case AP_RESPONSE_MESSAGE_TOO_BIG:
ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-EINVAL));
return -EINVAL;
@@ -1658,6 +1672,7 @@ int __init ap_module_init(void)
*/
if (MACHINE_IS_VM)
poll_timeout = 1500000;
+ spin_lock_init(&ap_poll_timer_lock);
hrtimer_init(&ap_poll_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
ap_poll_timer.function = ap_poll_timeout;
diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h
index a353622..4785d07 100644
--- a/drivers/s390/crypto/ap_bus.h
+++ b/drivers/s390/crypto/ap_bus.h
@@ -87,6 +87,7 @@ struct ap_queue_status {
#define AP_RESPONSE_INDEX_TOO_BIG 0x11
#define AP_RESPONSE_NO_FIRST_PART 0x13
#define AP_RESPONSE_MESSAGE_TOO_BIG 0x15
+#define AP_RESPONSE_REQ_FAC_NOT_INST 0x16
/*
* Known device types
@@ -96,8 +97,8 @@ struct ap_queue_status {
#define AP_DEVICE_TYPE_PCIXCC 5
#define AP_DEVICE_TYPE_CEX2A 6
#define AP_DEVICE_TYPE_CEX2C 7
-#define AP_DEVICE_TYPE_CEX2A2 8
-#define AP_DEVICE_TYPE_CEX2C2 9
+#define AP_DEVICE_TYPE_CEX3A 8
+#define AP_DEVICE_TYPE_CEX3C 9
/*
* AP reset flag states
@@ -161,12 +162,25 @@ struct ap_message {
size_t length; /* Message length. */
void *private; /* ap driver private pointer. */
+ unsigned int special:1; /* Used for special commands. */
};
#define AP_DEVICE(dt) \
.dev_type=(dt), \
.match_flags=AP_DEVICE_ID_MATCH_DEVICE_TYPE,
+/**
+ * ap_init_message() - Initialize ap_message.
+ * Initialize a message before using. Otherwise this might result in
+ * unexpected behaviour.
+ */
+static inline void ap_init_message(struct ap_message *ap_msg)
+{
+ ap_msg->psmid = 0;
+ ap_msg->length = 0;
+ ap_msg->special = 0;
+}
+
/*
* Note: don't use ap_send/ap_recv after using ap_queue_message
* for the first time. Otherwise the ap message queue will get
diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c
index 65b6a96..0d4d18b 100644
--- a/drivers/s390/crypto/zcrypt_api.c
+++ b/drivers/s390/crypto/zcrypt_api.c
@@ -299,9 +299,7 @@ static ssize_t zcrypt_write(struct file *filp, const char __user *buf,
*/
static int zcrypt_open(struct inode *inode, struct file *filp)
{
- lock_kernel();
atomic_inc(&zcrypt_open_count);
- unlock_kernel();
return 0;
}
@@ -1009,6 +1007,10 @@ static int zcrypt_status_read(char *resp_buff, char **start, off_t offset,
zcrypt_count_type(ZCRYPT_CEX2C));
len += sprintf(resp_buff + len, "CEX2A count: %d\n",
zcrypt_count_type(ZCRYPT_CEX2A));
+ len += sprintf(resp_buff + len, "CEX3C count: %d\n",
+ zcrypt_count_type(ZCRYPT_CEX3C));
+ len += sprintf(resp_buff + len, "CEX3A count: %d\n",
+ zcrypt_count_type(ZCRYPT_CEX3A));
len += sprintf(resp_buff + len, "requestq count: %d\n",
zcrypt_requestq_count());
len += sprintf(resp_buff + len, "pendingq count: %d\n",
@@ -1017,7 +1019,7 @@ static int zcrypt_status_read(char *resp_buff, char **start, off_t offset,
atomic_read(&zcrypt_open_count));
zcrypt_status_mask(workarea);
len += sprinthx("Online devices: 1=PCICA 2=PCICC 3=PCIXCC(MCL2) "
- "4=PCIXCC(MCL3) 5=CEX2C 6=CEX2A",
+ "4=PCIXCC(MCL3) 5=CEX2C 6=CEX2A 7=CEX3C 8=CEX3A",
resp_buff+len, workarea, AP_DEVICES);
zcrypt_qdepth_mask(workarea);
len += sprinthx("Waiting work element counts",
@@ -1095,8 +1097,9 @@ static int zcrypt_status_write(struct file *file, const char __user *buffer,
* '0' for no device, '1' for PCICA, '2' for PCICC,
* '3' for PCIXCC_MCL2, '4' for PCIXCC_MCL3,
* '5' for CEX2C and '6' for CEX2A'
+ * '7' for CEX3C and '8' for CEX3A
*/
- if (*ptr >= '0' && *ptr <= '6')
+ if (*ptr >= '0' && *ptr <= '8')
j++;
else if (*ptr == 'd' || *ptr == 'D')
zcrypt_disable_card(j++);
diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h
index 1d1ec74..8e7ffbf 100644
--- a/drivers/s390/crypto/zcrypt_api.h
+++ b/drivers/s390/crypto/zcrypt_api.h
@@ -71,6 +71,8 @@ struct ica_z90_status {
#define ZCRYPT_PCIXCC_MCL3 4
#define ZCRYPT_CEX2C 5
#define ZCRYPT_CEX2A 6
+#define ZCRYPT_CEX3C 7
+#define ZCRYPT_CEX3A 8
/**
* Large random numbers are pulled in 4096 byte chunks from the crypto cards
diff --git a/drivers/s390/crypto/zcrypt_cex2a.c b/drivers/s390/crypto/zcrypt_cex2a.c
index 326ea08..c6fb0aa 100644
--- a/drivers/s390/crypto/zcrypt_cex2a.c
+++ b/drivers/s390/crypto/zcrypt_cex2a.c
@@ -39,17 +39,24 @@
#define CEX2A_MIN_MOD_SIZE 1 /* 8 bits */
#define CEX2A_MAX_MOD_SIZE 256 /* 2048 bits */
+#define CEX3A_MIN_MOD_SIZE CEX2A_MIN_MOD_SIZE
+#define CEX3A_MAX_MOD_SIZE CEX2A_MAX_MOD_SIZE
#define CEX2A_SPEED_RATING 970
+#define CEX3A_SPEED_RATING 900 /* Fixme: Needs finetuning */
#define CEX2A_MAX_MESSAGE_SIZE 0x390 /* sizeof(struct type50_crb2_msg) */
#define CEX2A_MAX_RESPONSE_SIZE 0x110 /* max outputdatalength + type80_hdr */
+#define CEX3A_MAX_MESSAGE_SIZE CEX2A_MAX_MESSAGE_SIZE
+#define CEX3A_MAX_RESPONSE_SIZE CEX2A_MAX_RESPONSE_SIZE
+
#define CEX2A_CLEANUP_TIME (15*HZ)
+#define CEX3A_CLEANUP_TIME CEX2A_CLEANUP_TIME
static struct ap_device_id zcrypt_cex2a_ids[] = {
{ AP_DEVICE(AP_DEVICE_TYPE_CEX2A) },
- { AP_DEVICE(AP_DEVICE_TYPE_CEX2A2) },
+ { AP_DEVICE(AP_DEVICE_TYPE_CEX3A) },
{ /* end of list */ },
};
@@ -298,6 +305,7 @@ static long zcrypt_cex2a_modexpo(struct zcrypt_device *zdev,
struct completion work;
int rc;
+ ap_init_message(&ap_msg);
ap_msg.message = kmalloc(CEX2A_MAX_MESSAGE_SIZE, GFP_KERNEL);
if (!ap_msg.message)
return -ENOMEM;
@@ -335,6 +343,7 @@ static long zcrypt_cex2a_modexpo_crt(struct zcrypt_device *zdev,
struct completion work;
int rc;
+ ap_init_message(&ap_msg);
ap_msg.message = kmalloc(CEX2A_MAX_MESSAGE_SIZE, GFP_KERNEL);
if (!ap_msg.message)
return -ENOMEM;
@@ -373,31 +382,45 @@ static struct zcrypt_ops zcrypt_cex2a_ops = {
*/
static int zcrypt_cex2a_probe(struct ap_device *ap_dev)
{
- struct zcrypt_device *zdev;
- int rc;
-
- zdev = zcrypt_device_alloc(CEX2A_MAX_RESPONSE_SIZE);
- if (!zdev)
- return -ENOMEM;
- zdev->ap_dev = ap_dev;
- zdev->ops = &zcrypt_cex2a_ops;
- zdev->online = 1;
- zdev->user_space_type = ZCRYPT_CEX2A;
- zdev->type_string = "CEX2A";
- zdev->min_mod_size = CEX2A_MIN_MOD_SIZE;
- zdev->max_mod_size = CEX2A_MAX_MOD_SIZE;
- zdev->short_crt = 1;
- zdev->speed_rating = CEX2A_SPEED_RATING;
- ap_dev->reply = &zdev->reply;
- ap_dev->private = zdev;
- rc = zcrypt_device_register(zdev);
- if (rc)
- goto out_free;
- return 0;
-
-out_free:
- ap_dev->private = NULL;
- zcrypt_device_free(zdev);
+ struct zcrypt_device *zdev = NULL;
+ int rc = 0;
+
+ switch (ap_dev->device_type) {
+ case AP_DEVICE_TYPE_CEX2A:
+ zdev = zcrypt_device_alloc(CEX2A_MAX_RESPONSE_SIZE);
+ if (!zdev)
+ return -ENOMEM;
+ zdev->user_space_type = ZCRYPT_CEX2A;
+ zdev->type_string = "CEX2A";
+ zdev->min_mod_size = CEX2A_MIN_MOD_SIZE;
+ zdev->max_mod_size = CEX2A_MAX_MOD_SIZE;
+ zdev->short_crt = 1;
+ zdev->speed_rating = CEX2A_SPEED_RATING;
+ break;
+ case AP_DEVICE_TYPE_CEX3A:
+ zdev = zcrypt_device_alloc(CEX3A_MAX_RESPONSE_SIZE);
+ if (!zdev)
+ return -ENOMEM;
+ zdev->user_space_type = ZCRYPT_CEX3A;
+ zdev->type_string = "CEX3A";
+ zdev->min_mod_size = CEX3A_MIN_MOD_SIZE;
+ zdev->max_mod_size = CEX3A_MAX_MOD_SIZE;
+ zdev->short_crt = 1;
+ zdev->speed_rating = CEX3A_SPEED_RATING;
+ break;
+ }
+ if (zdev != NULL) {
+ zdev->ap_dev = ap_dev;
+ zdev->ops = &zcrypt_cex2a_ops;
+ zdev->online = 1;
+ ap_dev->reply = &zdev->reply;
+ ap_dev->private = zdev;
+ rc = zcrypt_device_register(zdev);
+ }
+ if (rc) {
+ ap_dev->private = NULL;
+ zcrypt_device_free(zdev);
+ }
return rc;
}
diff --git a/drivers/s390/crypto/zcrypt_pcica.c b/drivers/s390/crypto/zcrypt_pcica.c
index 17ba81b..e78df36 100644
--- a/drivers/s390/crypto/zcrypt_pcica.c
+++ b/drivers/s390/crypto/zcrypt_pcica.c
@@ -281,6 +281,7 @@ static long zcrypt_pcica_modexpo(struct zcrypt_device *zdev,
struct completion work;
int rc;
+ ap_init_message(&ap_msg);
ap_msg.message = kmalloc(PCICA_MAX_MESSAGE_SIZE, GFP_KERNEL);
if (!ap_msg.message)
return -ENOMEM;
@@ -318,6 +319,7 @@ static long zcrypt_pcica_modexpo_crt(struct zcrypt_device *zdev,
struct completion work;
int rc;
+ ap_init_message(&ap_msg);
ap_msg.message = kmalloc(PCICA_MAX_MESSAGE_SIZE, GFP_KERNEL);
if (!ap_msg.message)
return -ENOMEM;
diff --git a/drivers/s390/crypto/zcrypt_pcicc.c b/drivers/s390/crypto/zcrypt_pcicc.c
index f4b0c47..a23726a 100644
--- a/drivers/s390/crypto/zcrypt_pcicc.c
+++ b/drivers/s390/crypto/zcrypt_pcicc.c
@@ -483,6 +483,7 @@ static long zcrypt_pcicc_modexpo(struct zcrypt_device *zdev,
struct completion work;
int rc;
+ ap_init_message(&ap_msg);
ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
if (!ap_msg.message)
return -ENOMEM;
@@ -521,6 +522,7 @@ static long zcrypt_pcicc_modexpo_crt(struct zcrypt_device *zdev,
struct completion work;
int rc;
+ ap_init_message(&ap_msg);
ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
if (!ap_msg.message)
return -ENOMEM;
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c
index 5677b40..79c1205 100644
--- a/drivers/s390/crypto/zcrypt_pcixcc.c
+++ b/drivers/s390/crypto/zcrypt_pcixcc.c
@@ -43,10 +43,13 @@
#define PCIXCC_MIN_MOD_SIZE 16 /* 128 bits */
#define PCIXCC_MIN_MOD_SIZE_OLD 64 /* 512 bits */
#define PCIXCC_MAX_MOD_SIZE 256 /* 2048 bits */
+#define CEX3C_MIN_MOD_SIZE PCIXCC_MIN_MOD_SIZE
+#define CEX3C_MAX_MOD_SIZE PCIXCC_MAX_MOD_SIZE
-#define PCIXCC_MCL2_SPEED_RATING 7870 /* FIXME: needs finetuning */
+#define PCIXCC_MCL2_SPEED_RATING 7870
#define PCIXCC_MCL3_SPEED_RATING 7870
-#define CEX2C_SPEED_RATING 8540
+#define CEX2C_SPEED_RATING 7000
+#define CEX3C_SPEED_RATING 6500 /* FIXME: needs finetuning */
#define PCIXCC_MAX_ICA_MESSAGE_SIZE 0x77c /* max size type6 v2 crt message */
#define PCIXCC_MAX_ICA_RESPONSE_SIZE 0x77c /* max size type86 v2 reply */
@@ -72,7 +75,7 @@ struct response_type {
static struct ap_device_id zcrypt_pcixcc_ids[] = {
{ AP_DEVICE(AP_DEVICE_TYPE_PCIXCC) },
{ AP_DEVICE(AP_DEVICE_TYPE_CEX2C) },
- { AP_DEVICE(AP_DEVICE_TYPE_CEX2C2) },
+ { AP_DEVICE(AP_DEVICE_TYPE_CEX3C) },
{ /* end of list */ },
};
@@ -326,6 +329,11 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev,
function_code = ((unsigned char *)&msg->cprbx) + msg->cprbx.cprb_len;
memcpy(msg->hdr.function_code, function_code, sizeof(msg->hdr.function_code));
+ if (memcmp(function_code, "US", 2) == 0)
+ ap_msg->special = 1;
+ else
+ ap_msg->special = 0;
+
/* copy data block */
if (xcRB->request_data_length &&
copy_from_user(req_data, xcRB->request_data_address,
@@ -688,6 +696,7 @@ static long zcrypt_pcixcc_modexpo(struct zcrypt_device *zdev,
};
int rc;
+ ap_init_message(&ap_msg);
ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
if (!ap_msg.message)
return -ENOMEM;
@@ -727,6 +736,7 @@ static long zcrypt_pcixcc_modexpo_crt(struct zcrypt_device *zdev,
};
int rc;
+ ap_init_message(&ap_msg);
ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
if (!ap_msg.message)
return -ENOMEM;
@@ -766,6 +776,7 @@ static long zcrypt_pcixcc_send_cprb(struct zcrypt_device *zdev,
};
int rc;
+ ap_init_message(&ap_msg);
ap_msg.message = kmalloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE, GFP_KERNEL);
if (!ap_msg.message)
return -ENOMEM;
@@ -805,6 +816,7 @@ static long zcrypt_pcixcc_rng(struct zcrypt_device *zdev,
};
int rc;
+ ap_init_message(&ap_msg);
ap_msg.message = kmalloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE, GFP_KERNEL);
if (!ap_msg.message)
return -ENOMEM;
@@ -972,6 +984,7 @@ static int zcrypt_pcixcc_rng_supported(struct ap_device *ap_dev)
} __attribute__((packed)) *reply;
int rc, i;
+ ap_init_message(&ap_msg);
ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
if (!ap_msg.message)
return -ENOMEM;
@@ -1016,14 +1029,15 @@ out_free:
static int zcrypt_pcixcc_probe(struct ap_device *ap_dev)
{
struct zcrypt_device *zdev;
- int rc;
+ int rc = 0;
zdev = zcrypt_device_alloc(PCIXCC_MAX_RESPONSE_SIZE);
if (!zdev)
return -ENOMEM;
zdev->ap_dev = ap_dev;
zdev->online = 1;
- if (ap_dev->device_type == AP_DEVICE_TYPE_PCIXCC) {
+ switch (ap_dev->device_type) {
+ case AP_DEVICE_TYPE_PCIXCC:
rc = zcrypt_pcixcc_mcl(ap_dev);
if (rc < 0) {
zcrypt_device_free(zdev);
@@ -1041,13 +1055,25 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev)
zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE;
zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;
}
- } else {
+ break;
+ case AP_DEVICE_TYPE_CEX2C:
zdev->user_space_type = ZCRYPT_CEX2C;
zdev->type_string = "CEX2C";
zdev->speed_rating = CEX2C_SPEED_RATING;
zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE;
zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;
+ break;
+ case AP_DEVICE_TYPE_CEX3C:
+ zdev->user_space_type = ZCRYPT_CEX3C;
+ zdev->type_string = "CEX3C";
+ zdev->speed_rating = CEX3C_SPEED_RATING;
+ zdev->min_mod_size = CEX3C_MIN_MOD_SIZE;
+ zdev->max_mod_size = CEX3C_MAX_MOD_SIZE;
+ break;
+ default:
+ goto out_free;
}
+
rc = zcrypt_pcixcc_rng_supported(ap_dev);
if (rc < 0) {
zcrypt_device_free(zdev);
diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h
index 52c0343..1ba5115 100644
--- a/drivers/s390/net/qeth_core_mpc.h
+++ b/drivers/s390/net/qeth_core_mpc.h
@@ -528,7 +528,7 @@ extern unsigned char ULP_ENABLE[];
(PDU_ENCAPSULATION(buffer) + 0x17)
#define QETH_ULP_ENABLE_RESP_LINK_TYPE(buffer) \
(PDU_ENCAPSULATION(buffer) + 0x2b)
-/* Layer 2 defintions */
+/* Layer 2 definitions */
#define QETH_PROT_LAYER2 0x08
#define QETH_PROT_TCPIP 0x03
#define QETH_PROT_OSN2 0x0a
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index 2889e5f..9d0c941 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -31,6 +31,7 @@
#include <linux/miscdevice.h>
#include <linux/seq_file.h>
#include "zfcp_ext.h"
+#include "zfcp_fc.h"
#define ZFCP_BUS_ID_SIZE 20
@@ -80,48 +81,40 @@ int zfcp_reqlist_isempty(struct zfcp_adapter *adapter)
static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun)
{
- struct ccw_device *ccwdev;
+ struct ccw_device *cdev;
struct zfcp_adapter *adapter;
struct zfcp_port *port;
struct zfcp_unit *unit;
- ccwdev = get_ccwdev_by_busid(&zfcp_ccw_driver, busid);
- if (!ccwdev)
+ cdev = get_ccwdev_by_busid(&zfcp_ccw_driver, busid);
+ if (!cdev)
return;
- if (ccw_device_set_online(ccwdev))
- goto out_ccwdev;
+ if (ccw_device_set_online(cdev))
+ goto out_ccw_device;
- mutex_lock(&zfcp_data.config_mutex);
- adapter = dev_get_drvdata(&ccwdev->dev);
+ adapter = zfcp_ccw_adapter_by_cdev(cdev);
if (!adapter)
- goto out_unlock;
- zfcp_adapter_get(adapter);
+ goto out_ccw_device;
port = zfcp_get_port_by_wwpn(adapter, wwpn);
if (!port)
goto out_port;
- zfcp_port_get(port);
unit = zfcp_unit_enqueue(port, lun);
if (IS_ERR(unit))
goto out_unit;
- mutex_unlock(&zfcp_data.config_mutex);
zfcp_erp_unit_reopen(unit, 0, "auidc_1", NULL);
zfcp_erp_wait(adapter);
flush_work(&unit->scsi_work);
- mutex_lock(&zfcp_data.config_mutex);
- zfcp_unit_put(unit);
out_unit:
- zfcp_port_put(port);
+ put_device(&port->sysfs_device);
out_port:
- zfcp_adapter_put(adapter);
-out_unlock:
- mutex_unlock(&zfcp_data.config_mutex);
-out_ccwdev:
- put_device(&ccwdev->dev);
+ zfcp_ccw_adapter_put(adapter);
+out_ccw_device:
+ put_device(&cdev->dev);
return;
}
@@ -167,7 +160,7 @@ static int __init zfcp_module_init(void)
int retval = -ENOMEM;
zfcp_data.gpn_ft_cache = zfcp_cache_hw_align("zfcp_gpn",
- sizeof(struct ct_iu_gpn_ft_req));
+ sizeof(struct zfcp_fc_gpn_ft_req));
if (!zfcp_data.gpn_ft_cache)
goto out;
@@ -182,12 +175,14 @@ static int __init zfcp_module_init(void)
goto out_sr_cache;
zfcp_data.gid_pn_cache = zfcp_cache_hw_align("zfcp_gid",
- sizeof(struct zfcp_gid_pn_data));
+ sizeof(struct zfcp_fc_gid_pn));
if (!zfcp_data.gid_pn_cache)
goto out_gid_cache;
- mutex_init(&zfcp_data.config_mutex);
- rwlock_init(&zfcp_data.config_lock);
+ zfcp_data.adisc_cache = zfcp_cache_hw_align("zfcp_adisc",
+ sizeof(struct zfcp_fc_els_adisc));
+ if (!zfcp_data.adisc_cache)
+ goto out_adisc_cache;
zfcp_data.scsi_transport_template =
fc_attach_transport(&zfcp_transport_functions);
@@ -200,7 +195,7 @@ static int __init zfcp_module_init(void)
goto out_misc;
}
- retval = zfcp_ccw_register();
+ retval = ccw_driver_register(&zfcp_ccw_driver);
if (retval) {
pr_err("The zfcp device driver could not register with "
"the common I/O layer\n");
@@ -216,6 +211,8 @@ out_ccw_register:
out_misc:
fc_release_transport(zfcp_data.scsi_transport_template);
out_transport:
+ kmem_cache_destroy(zfcp_data.adisc_cache);
+out_adisc_cache:
kmem_cache_destroy(zfcp_data.gid_pn_cache);
out_gid_cache:
kmem_cache_destroy(zfcp_data.sr_buffer_cache);
@@ -229,6 +226,20 @@ out:
module_init(zfcp_module_init);
+static void __exit zfcp_module_exit(void)
+{
+ ccw_driver_unregister(&zfcp_ccw_driver);
+ misc_deregister(&zfcp_cfdc_misc);
+ fc_release_transport(zfcp_data.scsi_transport_template);
+ kmem_cache_destroy(zfcp_data.adisc_cache);
+ kmem_cache_destroy(zfcp_data.gid_pn_cache);
+ kmem_cache_destroy(zfcp_data.sr_buffer_cache);
+ kmem_cache_destroy(zfcp_data.qtcb_cache);
+ kmem_cache_destroy(zfcp_data.gpn_ft_cache);
+}
+
+module_exit(zfcp_module_exit);
+
/**
* zfcp_get_unit_by_lun - find unit in unit list of port by FCP LUN
* @port: pointer to port to search for unit
@@ -238,12 +249,18 @@ module_init(zfcp_module_init);
*/
struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *port, u64 fcp_lun)
{
+ unsigned long flags;
struct zfcp_unit *unit;
- list_for_each_entry(unit, &port->unit_list_head, list)
- if ((unit->fcp_lun == fcp_lun) &&
- !(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_REMOVE))
- return unit;
+ read_lock_irqsave(&port->unit_list_lock, flags);
+ list_for_each_entry(unit, &port->unit_list, list)
+ if (unit->fcp_lun == fcp_lun) {
+ if (!get_device(&unit->sysfs_device))
+ unit = NULL;
+ read_unlock_irqrestore(&port->unit_list_lock, flags);
+ return unit;
+ }
+ read_unlock_irqrestore(&port->unit_list_lock, flags);
return NULL;
}
@@ -257,18 +274,35 @@ struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *port, u64 fcp_lun)
struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *adapter,
u64 wwpn)
{
+ unsigned long flags;
struct zfcp_port *port;
- list_for_each_entry(port, &adapter->port_list_head, list)
- if ((port->wwpn == wwpn) &&
- !(atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE))
+ read_lock_irqsave(&adapter->port_list_lock, flags);
+ list_for_each_entry(port, &adapter->port_list, list)
+ if (port->wwpn == wwpn) {
+ if (!get_device(&port->sysfs_device))
+ port = NULL;
+ read_unlock_irqrestore(&adapter->port_list_lock, flags);
return port;
+ }
+ read_unlock_irqrestore(&adapter->port_list_lock, flags);
return NULL;
}
-static void zfcp_sysfs_unit_release(struct device *dev)
+/**
+ * zfcp_unit_release - dequeue unit
+ * @dev: pointer to device
+ *
+ * waits until all work is done on unit and removes it then from the unit->list
+ * of the associated port.
+ */
+static void zfcp_unit_release(struct device *dev)
{
- kfree(container_of(dev, struct zfcp_unit, sysfs_device));
+ struct zfcp_unit *unit = container_of(dev, struct zfcp_unit,
+ sysfs_device);
+
+ put_device(&unit->port->sysfs_device);
+ kfree(unit);
}
/**
@@ -276,43 +310,40 @@ static void zfcp_sysfs_unit_release(struct device *dev)
* @port: pointer to port where unit is added
* @fcp_lun: FCP LUN of unit to be enqueued
* Returns: pointer to enqueued unit on success, ERR_PTR on error
- * Locks: config_mutex must be held to serialize changes to the unit list
*
* Sets up some unit internal structures and creates sysfs entry.
*/
struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun)
{
struct zfcp_unit *unit;
+ int retval = -ENOMEM;
- read_lock_irq(&zfcp_data.config_lock);
- if (zfcp_get_unit_by_lun(port, fcp_lun)) {
- read_unlock_irq(&zfcp_data.config_lock);
- return ERR_PTR(-EINVAL);
+ get_device(&port->sysfs_device);
+
+ unit = zfcp_get_unit_by_lun(port, fcp_lun);
+ if (unit) {
+ put_device(&unit->sysfs_device);
+ retval = -EEXIST;
+ goto err_out;
}
- read_unlock_irq(&zfcp_data.config_lock);
unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL);
if (!unit)
- return ERR_PTR(-ENOMEM);
-
- atomic_set(&unit->refcount, 0);
- init_waitqueue_head(&unit->remove_wq);
- INIT_WORK(&unit->scsi_work, zfcp_scsi_scan);
+ goto err_out;
unit->port = port;
unit->fcp_lun = fcp_lun;
+ unit->sysfs_device.parent = &port->sysfs_device;
+ unit->sysfs_device.release = zfcp_unit_release;
if (dev_set_name(&unit->sysfs_device, "0x%016llx",
(unsigned long long) fcp_lun)) {
kfree(unit);
- return ERR_PTR(-ENOMEM);
+ goto err_out;
}
- unit->sysfs_device.parent = &port->sysfs_device;
- unit->sysfs_device.release = zfcp_sysfs_unit_release;
- dev_set_drvdata(&unit->sysfs_device, unit);
+ retval = -EINVAL;
- /* mark unit unusable as long as sysfs registration is not complete */
- atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status);
+ INIT_WORK(&unit->scsi_work, zfcp_scsi_scan);
spin_lock_init(&unit->latencies.lock);
unit->latencies.write.channel.min = 0xFFFFFFFF;
@@ -324,50 +355,30 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun)
if (device_register(&unit->sysfs_device)) {
put_device(&unit->sysfs_device);
- return ERR_PTR(-EINVAL);
+ goto err_out;
}
if (sysfs_create_group(&unit->sysfs_device.kobj,
- &zfcp_sysfs_unit_attrs)) {
- device_unregister(&unit->sysfs_device);
- return ERR_PTR(-EINVAL);
- }
+ &zfcp_sysfs_unit_attrs))
+ goto err_out_put;
- zfcp_unit_get(unit);
+ write_lock_irq(&port->unit_list_lock);
+ list_add_tail(&unit->list, &port->unit_list);
+ write_unlock_irq(&port->unit_list_lock);
- write_lock_irq(&zfcp_data.config_lock);
- list_add_tail(&unit->list, &port->unit_list_head);
- atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status);
atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status);
- write_unlock_irq(&zfcp_data.config_lock);
-
- zfcp_port_get(port);
-
return unit;
-}
-/**
- * zfcp_unit_dequeue - dequeue unit
- * @unit: pointer to zfcp_unit
- *
- * waits until all work is done on unit and removes it then from the unit->list
- * of the associated port.
- */
-void zfcp_unit_dequeue(struct zfcp_unit *unit)
-{
- wait_event(unit->remove_wq, atomic_read(&unit->refcount) == 0);
- write_lock_irq(&zfcp_data.config_lock);
- list_del(&unit->list);
- write_unlock_irq(&zfcp_data.config_lock);
- zfcp_port_put(unit->port);
- sysfs_remove_group(&unit->sysfs_device.kobj, &zfcp_sysfs_unit_attrs);
+err_out_put:
device_unregister(&unit->sysfs_device);
+err_out:
+ put_device(&port->sysfs_device);
+ return ERR_PTR(retval);
}
static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter)
{
- /* must only be called with zfcp_data.config_mutex taken */
adapter->pool.erp_req =
mempool_create_kmalloc_pool(1, sizeof(struct zfcp_fsf_req));
if (!adapter->pool.erp_req)
@@ -405,9 +416,9 @@ static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter)
if (!adapter->pool.status_read_data)
return -ENOMEM;
- adapter->pool.gid_pn_data =
+ adapter->pool.gid_pn =
mempool_create_slab_pool(1, zfcp_data.gid_pn_cache);
- if (!adapter->pool.gid_pn_data)
+ if (!adapter->pool.gid_pn)
return -ENOMEM;
return 0;
@@ -415,7 +426,6 @@ static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter)
static void zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter)
{
- /* zfcp_data.config_mutex must be held */
if (adapter->pool.erp_req)
mempool_destroy(adapter->pool.erp_req);
if (adapter->pool.scsi_req)
@@ -428,8 +438,8 @@ static void zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter)
mempool_destroy(adapter->pool.status_read_req);
if (adapter->pool.status_read_data)
mempool_destroy(adapter->pool.status_read_data);
- if (adapter->pool.gid_pn_data)
- mempool_destroy(adapter->pool.gid_pn_data);
+ if (adapter->pool.gid_pn)
+ mempool_destroy(adapter->pool.gid_pn);
}
/**
@@ -497,53 +507,56 @@ static void zfcp_destroy_adapter_work_queue(struct zfcp_adapter *adapter)
* zfcp_adapter_enqueue - enqueue a new adapter to the list
* @ccw_device: pointer to the struct cc_device
*
- * Returns: 0 if a new adapter was successfully enqueued
- * -ENOMEM if alloc failed
+ * Returns: struct zfcp_adapter*
* Enqueues an adapter at the end of the adapter list in the driver data.
* All adapter internal structures are set up.
* Proc-fs entries are also created.
- * locks: config_mutex must be held to serialize changes to the adapter list
*/
-int zfcp_adapter_enqueue(struct ccw_device *ccw_device)
+struct zfcp_adapter *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
- * are protected by the config_mutex, which must be held to get here
- */
+ if (!get_device(&ccw_device->dev))
+ return ERR_PTR(-ENODEV);
adapter = kzalloc(sizeof(struct zfcp_adapter), GFP_KERNEL);
- if (!adapter)
- return -ENOMEM;
+ if (!adapter) {
+ put_device(&ccw_device->dev);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ kref_init(&adapter->ref);
ccw_device->handler = NULL;
adapter->ccw_device = ccw_device;
- atomic_set(&adapter->refcount, 0);
+
+ INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler);
+ INIT_WORK(&adapter->scan_work, zfcp_fc_scan_ports);
if (zfcp_qdio_setup(adapter))
- goto qdio_failed;
+ goto failed;
if (zfcp_allocate_low_mem_buffers(adapter))
- goto low_mem_buffers_failed;
+ goto failed;
if (zfcp_reqlist_alloc(adapter))
- goto low_mem_buffers_failed;
+ goto failed;
if (zfcp_dbf_adapter_register(adapter))
- goto debug_register_failed;
+ goto failed;
if (zfcp_setup_adapter_work_queue(adapter))
- goto work_queue_failed;
+ goto failed;
if (zfcp_fc_gs_setup(adapter))
- goto generic_services_failed;
+ goto failed;
+
+ rwlock_init(&adapter->port_list_lock);
+ INIT_LIST_HEAD(&adapter->port_list);
- init_waitqueue_head(&adapter->remove_wq);
init_waitqueue_head(&adapter->erp_ready_wq);
init_waitqueue_head(&adapter->erp_done_wqh);
- INIT_LIST_HEAD(&adapter->port_list_head);
INIT_LIST_HEAD(&adapter->erp_ready_head);
INIT_LIST_HEAD(&adapter->erp_running_head);
@@ -553,83 +566,85 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device)
rwlock_init(&adapter->abort_lock);
if (zfcp_erp_thread_setup(adapter))
- goto erp_thread_failed;
-
- INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler);
- INIT_WORK(&adapter->scan_work, _zfcp_fc_scan_ports_later);
+ goto failed;
adapter->service_level.seq_print = zfcp_print_sl;
- /* mark adapter unusable as long as sysfs registration is not complete */
- atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status);
-
dev_set_drvdata(&ccw_device->dev, adapter);
if (sysfs_create_group(&ccw_device->dev.kobj,
&zfcp_sysfs_adapter_attrs))
- goto sysfs_failed;
-
- atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status);
+ goto failed;
if (!zfcp_adapter_scsi_register(adapter))
- return 0;
+ return adapter;
-sysfs_failed:
- zfcp_erp_thread_kill(adapter);
-erp_thread_failed:
- zfcp_fc_gs_destroy(adapter);
-generic_services_failed:
+failed:
+ zfcp_adapter_unregister(adapter);
+ return ERR_PTR(-ENOMEM);
+}
+
+void zfcp_adapter_unregister(struct zfcp_adapter *adapter)
+{
+ struct ccw_device *cdev = adapter->ccw_device;
+
+ cancel_work_sync(&adapter->scan_work);
+ cancel_work_sync(&adapter->stat_work);
zfcp_destroy_adapter_work_queue(adapter);
-work_queue_failed:
+
+ zfcp_fc_wka_ports_force_offline(adapter->gs);
+ zfcp_adapter_scsi_unregister(adapter);
+ sysfs_remove_group(&cdev->dev.kobj, &zfcp_sysfs_adapter_attrs);
+
+ zfcp_erp_thread_kill(adapter);
zfcp_dbf_adapter_unregister(adapter->dbf);
-debug_register_failed:
- dev_set_drvdata(&ccw_device->dev, NULL);
- kfree(adapter->req_list);
-low_mem_buffers_failed:
- zfcp_free_low_mem_buffers(adapter);
-qdio_failed:
zfcp_qdio_destroy(adapter->qdio);
- kfree(adapter);
- return -ENOMEM;
+
+ zfcp_ccw_adapter_put(adapter); /* final put to release */
}
/**
- * zfcp_adapter_dequeue - remove the adapter from the resource list
- * @adapter: pointer to struct zfcp_adapter which should be removed
+ * zfcp_adapter_release - remove the adapter from the resource list
+ * @ref: pointer to struct kref
* locks: adapter list write lock is assumed to be held by caller
*/
-void zfcp_adapter_dequeue(struct zfcp_adapter *adapter)
+void zfcp_adapter_release(struct kref *ref)
{
- int retval = 0;
- unsigned long flags;
+ struct zfcp_adapter *adapter = container_of(ref, struct zfcp_adapter,
+ ref);
+ struct ccw_device *cdev = adapter->ccw_device;
- cancel_work_sync(&adapter->stat_work);
- zfcp_fc_wka_ports_force_offline(adapter->gs);
- sysfs_remove_group(&adapter->ccw_device->dev.kobj,
- &zfcp_sysfs_adapter_attrs);
dev_set_drvdata(&adapter->ccw_device->dev, NULL);
- /* sanity check: no pending FSF requests */
- spin_lock_irqsave(&adapter->req_list_lock, flags);
- retval = zfcp_reqlist_isempty(adapter);
- spin_unlock_irqrestore(&adapter->req_list_lock, flags);
- if (!retval)
- return;
-
zfcp_fc_gs_destroy(adapter);
- zfcp_erp_thread_kill(adapter);
- zfcp_destroy_adapter_work_queue(adapter);
- zfcp_dbf_adapter_unregister(adapter->dbf);
zfcp_free_low_mem_buffers(adapter);
- zfcp_qdio_destroy(adapter->qdio);
kfree(adapter->req_list);
kfree(adapter->fc_stats);
kfree(adapter->stats_reset_data);
kfree(adapter);
+ put_device(&cdev->dev);
}
-static void zfcp_sysfs_port_release(struct device *dev)
+/**
+ * zfcp_device_unregister - remove port, unit from system
+ * @dev: reference to device which is to be removed
+ * @grp: related reference to attribute group
+ *
+ * Helper function to unregister port, unit from system
+ */
+void zfcp_device_unregister(struct device *dev,
+ const struct attribute_group *grp)
{
- kfree(container_of(dev, struct zfcp_port, sysfs_device));
+ sysfs_remove_group(&dev->kobj, grp);
+ device_unregister(dev);
+}
+
+static void zfcp_port_release(struct device *dev)
+{
+ struct zfcp_port *port = container_of(dev, struct zfcp_port,
+ sysfs_device);
+
+ zfcp_ccw_adapter_put(port->adapter);
+ kfree(port);
}
/**
@@ -639,7 +654,6 @@ static void zfcp_sysfs_port_release(struct device *dev)
* @status: initial status for the port
* @d_id: destination id of the remote port to be enqueued
* Returns: pointer to enqueued port on success, ERR_PTR on error
- * Locks: config_mutex must be held to serialize changes to the port list
*
* All port internal structures are set up and the sysfs entry is generated.
* d_id is used to enqueue ports with a well known address like the Directory
@@ -649,20 +663,24 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,
u32 status, u32 d_id)
{
struct zfcp_port *port;
+ int retval = -ENOMEM;
- read_lock_irq(&zfcp_data.config_lock);
- if (zfcp_get_port_by_wwpn(adapter, wwpn)) {
- read_unlock_irq(&zfcp_data.config_lock);
- return ERR_PTR(-EINVAL);
+ kref_get(&adapter->ref);
+
+ port = zfcp_get_port_by_wwpn(adapter, wwpn);
+ if (port) {
+ put_device(&port->sysfs_device);
+ retval = -EEXIST;
+ goto err_out;
}
- read_unlock_irq(&zfcp_data.config_lock);
port = kzalloc(sizeof(struct zfcp_port), GFP_KERNEL);
if (!port)
- return ERR_PTR(-ENOMEM);
+ goto err_out;
+
+ rwlock_init(&port->unit_list_lock);
+ INIT_LIST_HEAD(&port->unit_list);
- init_waitqueue_head(&port->remove_wq);
- INIT_LIST_HEAD(&port->unit_list_head);
INIT_WORK(&port->gid_pn_work, zfcp_fc_port_did_lookup);
INIT_WORK(&port->test_link_work, zfcp_fc_link_test_work);
INIT_WORK(&port->rport_work, zfcp_scsi_rport_work);
@@ -671,58 +689,38 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,
port->d_id = d_id;
port->wwpn = wwpn;
port->rport_task = RPORT_NONE;
-
- /* mark port unusable as long as sysfs registration is not complete */
- atomic_set_mask(status | ZFCP_STATUS_COMMON_REMOVE, &port->status);
- atomic_set(&port->refcount, 0);
+ port->sysfs_device.parent = &adapter->ccw_device->dev;
+ port->sysfs_device.release = zfcp_port_release;
if (dev_set_name(&port->sysfs_device, "0x%016llx",
(unsigned long long)wwpn)) {
kfree(port);
- return ERR_PTR(-ENOMEM);
+ goto err_out;
}
- port->sysfs_device.parent = &adapter->ccw_device->dev;
- port->sysfs_device.release = zfcp_sysfs_port_release;
- dev_set_drvdata(&port->sysfs_device, port);
+ retval = -EINVAL;
if (device_register(&port->sysfs_device)) {
put_device(&port->sysfs_device);
- return ERR_PTR(-EINVAL);
+ goto err_out;
}
if (sysfs_create_group(&port->sysfs_device.kobj,
- &zfcp_sysfs_port_attrs)) {
- device_unregister(&port->sysfs_device);
- return ERR_PTR(-EINVAL);
- }
+ &zfcp_sysfs_port_attrs))
+ goto err_out_put;
- zfcp_port_get(port);
+ write_lock_irq(&adapter->port_list_lock);
+ list_add_tail(&port->list, &adapter->port_list);
+ write_unlock_irq(&adapter->port_list_lock);
- write_lock_irq(&zfcp_data.config_lock);
- list_add_tail(&port->list, &adapter->port_list_head);
- atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status);
- atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &port->status);
+ atomic_set_mask(status | ZFCP_STATUS_COMMON_RUNNING, &port->status);
- write_unlock_irq(&zfcp_data.config_lock);
-
- zfcp_adapter_get(adapter);
return port;
-}
-/**
- * zfcp_port_dequeue - dequeues a port from the port list of the adapter
- * @port: pointer to struct zfcp_port which should be removed
- */
-void zfcp_port_dequeue(struct zfcp_port *port)
-{
- write_lock_irq(&zfcp_data.config_lock);
- list_del(&port->list);
- write_unlock_irq(&zfcp_data.config_lock);
- wait_event(port->remove_wq, atomic_read(&port->refcount) == 0);
- cancel_work_sync(&port->rport_work); /* usually not necessary */
- zfcp_adapter_put(port->adapter);
- sysfs_remove_group(&port->sysfs_device.kobj, &zfcp_sysfs_port_attrs);
+err_out_put:
device_unregister(&port->sysfs_device);
+err_out:
+ zfcp_ccw_adapter_put(adapter);
+ return ERR_PTR(retval);
}
/**
diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c
index e083394..c22cb72 100644
--- a/drivers/s390/scsi/zfcp_ccw.c
+++ b/drivers/s390/scsi/zfcp_ccw.c
@@ -13,28 +13,34 @@
#define ZFCP_MODEL_PRIV 0x4
-static int zfcp_ccw_suspend(struct ccw_device *cdev)
+static DEFINE_SPINLOCK(zfcp_ccw_adapter_ref_lock);
+struct zfcp_adapter *zfcp_ccw_adapter_by_cdev(struct ccw_device *cdev)
{
- struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev);
-
- if (!adapter)
- return 0;
-
- mutex_lock(&zfcp_data.config_mutex);
+ struct zfcp_adapter *adapter;
+ unsigned long flags;
- zfcp_erp_adapter_shutdown(adapter, 0, "ccsusp1", NULL);
- zfcp_erp_wait(adapter);
+ spin_lock_irqsave(&zfcp_ccw_adapter_ref_lock, flags);
+ adapter = dev_get_drvdata(&cdev->dev);
+ if (adapter)
+ kref_get(&adapter->ref);
+ spin_unlock_irqrestore(&zfcp_ccw_adapter_ref_lock, flags);
+ return adapter;
+}
- mutex_unlock(&zfcp_data.config_mutex);
+void zfcp_ccw_adapter_put(struct zfcp_adapter *adapter)
+{
+ unsigned long flags;
- return 0;
+ spin_lock_irqsave(&zfcp_ccw_adapter_ref_lock, flags);
+ kref_put(&adapter->ref, zfcp_adapter_release);
+ spin_unlock_irqrestore(&zfcp_ccw_adapter_ref_lock, flags);
}
static int zfcp_ccw_activate(struct ccw_device *cdev)
{
- struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev);
+ struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);
if (!adapter)
return 0;
@@ -46,6 +52,8 @@ static int zfcp_ccw_activate(struct ccw_device *cdev)
zfcp_erp_wait(adapter);
flush_work(&adapter->scan_work);
+ zfcp_ccw_adapter_put(adapter);
+
return 0;
}
@@ -67,28 +75,28 @@ int zfcp_ccw_priv_sch(struct zfcp_adapter *adapter)
/**
* zfcp_ccw_probe - probe function of zfcp driver
- * @ccw_device: pointer to belonging ccw device
+ * @cdev: pointer to belonging ccw device
*
* This function gets called by the common i/o layer for each FCP
* device found on the current system. This is only a stub to make cio
* work: To only allocate adapter resources for devices actually used,
* the allocation is deferred to the first call to ccw_set_online.
*/
-static int zfcp_ccw_probe(struct ccw_device *ccw_device)
+static int zfcp_ccw_probe(struct ccw_device *cdev)
{
return 0;
}
/**
* zfcp_ccw_remove - remove function of zfcp driver
- * @ccw_device: pointer to belonging ccw device
+ * @cdev: pointer to belonging ccw device
*
* This function gets called by the common i/o layer and removes an adapter
* from the system. Task of this function is to get rid of all units and
* ports that belong to this adapter. And in addition all resources of this
* adapter will be freed too.
*/
-static void zfcp_ccw_remove(struct ccw_device *ccw_device)
+static void zfcp_ccw_remove(struct ccw_device *cdev)
{
struct zfcp_adapter *adapter;
struct zfcp_port *port, *p;
@@ -96,49 +104,37 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device)
LIST_HEAD(unit_remove_lh);
LIST_HEAD(port_remove_lh);
- ccw_device_set_offline(ccw_device);
+ ccw_device_set_offline(cdev);
- mutex_lock(&zfcp_data.config_mutex);
- adapter = dev_get_drvdata(&ccw_device->dev);
+ adapter = zfcp_ccw_adapter_by_cdev(cdev);
if (!adapter)
- goto out;
- mutex_unlock(&zfcp_data.config_mutex);
+ return;
- cancel_work_sync(&adapter->scan_work);
-
- mutex_lock(&zfcp_data.config_mutex);
-
- /* this also removes the scsi devices, so call it first */
- zfcp_adapter_scsi_unregister(adapter);
-
- write_lock_irq(&zfcp_data.config_lock);
- list_for_each_entry_safe(port, p, &adapter->port_list_head, list) {
- list_for_each_entry_safe(unit, u, &port->unit_list_head, list) {
+ write_lock_irq(&adapter->port_list_lock);
+ list_for_each_entry_safe(port, p, &adapter->port_list, list) {
+ write_lock(&port->unit_list_lock);
+ list_for_each_entry_safe(unit, u, &port->unit_list, list)
list_move(&unit->list, &unit_remove_lh);
- atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE,
- &unit->status);
- }
+ write_unlock(&port->unit_list_lock);
list_move(&port->list, &port_remove_lh);
- atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status);
}
- atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status);
- write_unlock_irq(&zfcp_data.config_lock);
+ write_unlock_irq(&adapter->port_list_lock);
+ zfcp_ccw_adapter_put(adapter); /* put from zfcp_ccw_adapter_by_cdev */
- list_for_each_entry_safe(port, p, &port_remove_lh, list) {
- list_for_each_entry_safe(unit, u, &unit_remove_lh, list)
- zfcp_unit_dequeue(unit);
- zfcp_port_dequeue(port);
- }
- wait_event(adapter->remove_wq, atomic_read(&adapter->refcount) == 0);
- zfcp_adapter_dequeue(adapter);
+ list_for_each_entry_safe(unit, u, &unit_remove_lh, list)
+ zfcp_device_unregister(&unit->sysfs_device,
+ &zfcp_sysfs_unit_attrs);
-out:
- mutex_unlock(&zfcp_data.config_mutex);
+ list_for_each_entry_safe(port, p, &port_remove_lh, list)
+ zfcp_device_unregister(&port->sysfs_device,
+ &zfcp_sysfs_port_attrs);
+
+ zfcp_adapter_unregister(adapter);
}
/**
* zfcp_ccw_set_online - set_online function of zfcp driver
- * @ccw_device: pointer to belonging ccw device
+ * @cdev: pointer to belonging ccw device
*
* This function gets called by the common i/o layer and sets an
* adapter into state online. The first call will allocate all
@@ -149,23 +145,20 @@ out:
* the SCSI stack, that the QDIO queues will be set up and that the
* adapter will be opened.
*/
-static int zfcp_ccw_set_online(struct ccw_device *ccw_device)
+static int zfcp_ccw_set_online(struct ccw_device *cdev)
{
- struct zfcp_adapter *adapter;
- int ret = 0;
-
- mutex_lock(&zfcp_data.config_mutex);
- adapter = dev_get_drvdata(&ccw_device->dev);
+ struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);
if (!adapter) {
- ret = zfcp_adapter_enqueue(ccw_device);
- if (ret) {
- dev_err(&ccw_device->dev,
+ adapter = zfcp_adapter_enqueue(cdev);
+
+ if (IS_ERR(adapter)) {
+ dev_err(&cdev->dev,
"Setting up data structures for the "
"FCP adapter failed\n");
- goto out;
+ return PTR_ERR(adapter);
}
- adapter = dev_get_drvdata(&ccw_device->dev);
+ kref_get(&adapter->ref);
}
/* initialize request counter */
@@ -177,58 +170,61 @@ static int zfcp_ccw_set_online(struct ccw_device *ccw_device)
zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
"ccsonl2", NULL);
zfcp_erp_wait(adapter);
-out:
- mutex_unlock(&zfcp_data.config_mutex);
- if (!ret)
- flush_work(&adapter->scan_work);
- return ret;
+
+ flush_work(&adapter->scan_work);
+
+ zfcp_ccw_adapter_put(adapter);
+ return 0;
}
/**
* zfcp_ccw_set_offline - set_offline function of zfcp driver
- * @ccw_device: pointer to belonging ccw device
+ * @cdev: pointer to belonging ccw device
*
* This function gets called by the common i/o layer and sets an adapter
* into state offline.
*/
-static int zfcp_ccw_set_offline(struct ccw_device *ccw_device)
+static int zfcp_ccw_set_offline(struct ccw_device *cdev)
{
- struct zfcp_adapter *adapter;
+ struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);
+
+ if (!adapter)
+ return 0;
- mutex_lock(&zfcp_data.config_mutex);
- adapter = dev_get_drvdata(&ccw_device->dev);
zfcp_erp_adapter_shutdown(adapter, 0, "ccsoff1", NULL);
zfcp_erp_wait(adapter);
- mutex_unlock(&zfcp_data.config_mutex);
+
+ zfcp_ccw_adapter_put(adapter);
return 0;
}
/**
* zfcp_ccw_notify - ccw notify function
- * @ccw_device: pointer to belonging ccw device
+ * @cdev: pointer to belonging ccw device
* @event: indicates if adapter was detached or attached
*
* This function gets called by the common i/o layer if an adapter has gone
* or reappeared.
*/
-static int zfcp_ccw_notify(struct ccw_device *ccw_device, int event)
+static int zfcp_ccw_notify(struct ccw_device *cdev, int event)
{
- struct zfcp_adapter *adapter = dev_get_drvdata(&ccw_device->dev);
+ struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);
+
+ if (!adapter)
+ return 1;
switch (event) {
case CIO_GONE:
- dev_warn(&adapter->ccw_device->dev,
- "The FCP device has been detached\n");
+ dev_warn(&cdev->dev, "The FCP device has been detached\n");
zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti1", NULL);
break;
case CIO_NO_PATH:
- dev_warn(&adapter->ccw_device->dev,
+ dev_warn(&cdev->dev,
"The CHPID for the FCP device is offline\n");
zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti2", NULL);
break;
case CIO_OPER:
- dev_info(&adapter->ccw_device->dev,
- "The FCP device is operational again\n");
+ dev_info(&cdev->dev, "The FCP device is operational again\n");
zfcp_erp_modify_adapter_status(adapter, "ccnoti3", NULL,
ZFCP_STATUS_COMMON_RUNNING,
ZFCP_SET);
@@ -236,11 +232,13 @@ static int zfcp_ccw_notify(struct ccw_device *ccw_device, int event)
"ccnoti4", NULL);
break;
case CIO_BOXED:
- dev_warn(&adapter->ccw_device->dev, "The FCP device "
- "did not respond within the specified time\n");
+ dev_warn(&cdev->dev, "The FCP device did not respond within "
+ "the specified time\n");
zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti5", NULL);
break;
}
+
+ zfcp_ccw_adapter_put(adapter);
return 1;
}
@@ -250,18 +248,16 @@ static int zfcp_ccw_notify(struct ccw_device *ccw_device, int event)
*/
static void zfcp_ccw_shutdown(struct ccw_device *cdev)
{
- struct zfcp_adapter *adapter;
+ struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);
- mutex_lock(&zfcp_data.config_mutex);
- adapter = dev_get_drvdata(&cdev->dev);
if (!adapter)
- goto out;
+ return;
zfcp_erp_adapter_shutdown(adapter, 0, "ccshut1", NULL);
zfcp_erp_wait(adapter);
zfcp_erp_thread_kill(adapter);
-out:
- mutex_unlock(&zfcp_data.config_mutex);
+
+ zfcp_ccw_adapter_put(adapter);
}
struct ccw_driver zfcp_ccw_driver = {
@@ -274,18 +270,7 @@ struct ccw_driver zfcp_ccw_driver = {
.set_offline = zfcp_ccw_set_offline,
.notify = zfcp_ccw_notify,
.shutdown = zfcp_ccw_shutdown,
- .freeze = zfcp_ccw_suspend,
+ .freeze = zfcp_ccw_set_offline,
.thaw = zfcp_ccw_activate,
.restore = zfcp_ccw_activate,
};
-
-/**
- * zfcp_ccw_register - ccw register function
- *
- * Registers the driver at the common i/o layer. This function will be called
- * at module load time/system start.
- */
-int __init zfcp_ccw_register(void)
-{
- return ccw_driver_register(&zfcp_ccw_driver);
-}
diff --git a/drivers/s390/scsi/zfcp_cfdc.c b/drivers/s390/scsi/zfcp_cfdc.c
index ef681df..f932400 100644
--- a/drivers/s390/scsi/zfcp_cfdc.c
+++ b/drivers/s390/scsi/zfcp_cfdc.c
@@ -86,22 +86,17 @@ static int zfcp_cfdc_copy_to_user(void __user *user_buffer,
static struct zfcp_adapter *zfcp_cfdc_get_adapter(u32 devno)
{
char busid[9];
- struct ccw_device *ccwdev;
- struct zfcp_adapter *adapter = NULL;
+ struct ccw_device *cdev;
+ struct zfcp_adapter *adapter;
snprintf(busid, sizeof(busid), "0.0.%04x", devno);
- ccwdev = get_ccwdev_by_busid(&zfcp_ccw_driver, busid);
- if (!ccwdev)
- goto out;
-
- adapter = dev_get_drvdata(&ccwdev->dev);
- if (!adapter)
- goto out_put;
-
- zfcp_adapter_get(adapter);
-out_put:
- put_device(&ccwdev->dev);
-out:
+ cdev = get_ccwdev_by_busid(&zfcp_ccw_driver, busid);
+ if (!cdev)
+ return NULL;
+
+ adapter = zfcp_ccw_adapter_by_cdev(cdev);
+
+ put_device(&cdev->dev);
return adapter;
}
@@ -212,7 +207,6 @@ static long zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command,
retval = -ENXIO;
goto free_buffer;
}
- zfcp_adapter_get(adapter);
retval = zfcp_cfdc_sg_setup(data->command, fsf_cfdc->sg,
data_user->control_file);
@@ -245,7 +239,7 @@ static long zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command,
free_sg:
zfcp_sg_free_table(fsf_cfdc->sg, ZFCP_CFDC_PAGES);
adapter_put:
- zfcp_adapter_put(adapter);
+ zfcp_ccw_adapter_put(adapter);
free_buffer:
kfree(data);
no_mem_sense:
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c
index 215b707..8445095 100644
--- a/drivers/s390/scsi/zfcp_dbf.c
+++ b/drivers/s390/scsi/zfcp_dbf.c
@@ -13,6 +13,7 @@
#include <asm/debug.h>
#include "zfcp_dbf.h"
#include "zfcp_ext.h"
+#include "zfcp_fc.h"
static u32 dbfsize = 4;
@@ -177,8 +178,7 @@ void _zfcp_dbf_hba_fsf_response(const char *tag2, int level,
case FSF_QTCB_SEND_ELS:
send_els = (struct zfcp_send_els *)fsf_req->data;
- response->u.els.d_id = qtcb->bottom.support.d_id;
- response->u.els.ls_code = send_els->ls_code >> 24;
+ response->u.els.d_id = ntoh24(qtcb->bottom.support.d_id);
break;
case FSF_QTCB_ABORT_FCP_CMND:
@@ -348,7 +348,6 @@ static void zfcp_dbf_hba_view_response(char **p,
case FSF_QTCB_SEND_ELS:
zfcp_dbf_out(p, "d_id", "0x%06x", r->u.els.d_id);
- zfcp_dbf_out(p, "ls_code", "0x%02x", r->u.els.ls_code);
break;
case FSF_QTCB_ABORT_FCP_CMND:
@@ -677,14 +676,14 @@ void zfcp_dbf_rec_action(char *id2, struct zfcp_erp_action *erp_action)
/**
* zfcp_dbf_san_ct_request - trace event for issued CT request
* @fsf_req: request containing issued CT data
+ * @d_id: destination id where ct request is sent to
*/
-void zfcp_dbf_san_ct_request(struct zfcp_fsf_req *fsf_req)
+void zfcp_dbf_san_ct_request(struct zfcp_fsf_req *fsf_req, u32 d_id)
{
- struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data;
- struct zfcp_wka_port *wka_port = ct->wka_port;
- struct zfcp_adapter *adapter = wka_port->adapter;
+ struct zfcp_fsf_ct_els *ct = (struct zfcp_fsf_ct_els *)fsf_req->data;
+ struct zfcp_adapter *adapter = fsf_req->adapter;
struct zfcp_dbf *dbf = adapter->dbf;
- struct ct_hdr *hdr = sg_virt(ct->req);
+ struct fc_ct_hdr *hdr = sg_virt(ct->req);
struct zfcp_dbf_san_record *r = &dbf->san_buf;
struct zfcp_dbf_san_record_ct_request *oct = &r->u.ct_req;
int level = 3;
@@ -695,19 +694,18 @@ void zfcp_dbf_san_ct_request(struct zfcp_fsf_req *fsf_req)
strncpy(r->tag, "octc", ZFCP_DBF_TAG_SIZE);
r->fsf_reqid = fsf_req->req_id;
r->fsf_seqno = fsf_req->seq_no;
- r->s_id = fc_host_port_id(adapter->scsi_host);
- r->d_id = wka_port->d_id;
- oct->cmd_req_code = hdr->cmd_rsp_code;
- oct->revision = hdr->revision;
- oct->gs_type = hdr->gs_type;
- oct->gs_subtype = hdr->gs_subtype;
- oct->options = hdr->options;
- oct->max_res_size = hdr->max_res_size;
- oct->len = min((int)ct->req->length - (int)sizeof(struct ct_hdr),
+ oct->d_id = d_id;
+ oct->cmd_req_code = hdr->ct_cmd;
+ oct->revision = hdr->ct_rev;
+ oct->gs_type = hdr->ct_fs_type;
+ oct->gs_subtype = hdr->ct_fs_subtype;
+ oct->options = hdr->ct_options;
+ oct->max_res_size = hdr->ct_mr_size;
+ oct->len = min((int)ct->req->length - (int)sizeof(struct fc_ct_hdr),
ZFCP_DBF_SAN_MAX_PAYLOAD);
debug_event(dbf->san, level, r, sizeof(*r));
zfcp_dbf_hexdump(dbf->san, r, sizeof(*r), level,
- (void *)hdr + sizeof(struct ct_hdr), oct->len);
+ (void *)hdr + sizeof(struct fc_ct_hdr), oct->len);
spin_unlock_irqrestore(&dbf->san_lock, flags);
}
@@ -717,10 +715,9 @@ void zfcp_dbf_san_ct_request(struct zfcp_fsf_req *fsf_req)
*/
void zfcp_dbf_san_ct_response(struct zfcp_fsf_req *fsf_req)
{
- struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data;
- struct zfcp_wka_port *wka_port = ct->wka_port;
- struct zfcp_adapter *adapter = wka_port->adapter;
- struct ct_hdr *hdr = sg_virt(ct->resp);
+ struct zfcp_fsf_ct_els *ct = (struct zfcp_fsf_ct_els *)fsf_req->data;
+ struct zfcp_adapter *adapter = fsf_req->adapter;
+ struct fc_ct_hdr *hdr = sg_virt(ct->resp);
struct zfcp_dbf *dbf = adapter->dbf;
struct zfcp_dbf_san_record *r = &dbf->san_buf;
struct zfcp_dbf_san_record_ct_response *rct = &r->u.ct_resp;
@@ -732,25 +729,23 @@ void zfcp_dbf_san_ct_response(struct zfcp_fsf_req *fsf_req)
strncpy(r->tag, "rctc", ZFCP_DBF_TAG_SIZE);
r->fsf_reqid = fsf_req->req_id;
r->fsf_seqno = fsf_req->seq_no;
- r->s_id = wka_port->d_id;
- r->d_id = fc_host_port_id(adapter->scsi_host);
- rct->cmd_rsp_code = hdr->cmd_rsp_code;
- rct->revision = hdr->revision;
- rct->reason_code = hdr->reason_code;
- rct->expl = hdr->reason_code_expl;
- rct->vendor_unique = hdr->vendor_unique;
- rct->max_res_size = hdr->max_res_size;
- rct->len = min((int)ct->resp->length - (int)sizeof(struct ct_hdr),
+ rct->cmd_rsp_code = hdr->ct_cmd;
+ rct->revision = hdr->ct_rev;
+ rct->reason_code = hdr->ct_reason;
+ rct->expl = hdr->ct_explan;
+ rct->vendor_unique = hdr->ct_vendor;
+ rct->max_res_size = hdr->ct_mr_size;
+ rct->len = min((int)ct->resp->length - (int)sizeof(struct fc_ct_hdr),
ZFCP_DBF_SAN_MAX_PAYLOAD);
debug_event(dbf->san, level, r, sizeof(*r));
zfcp_dbf_hexdump(dbf->san, r, sizeof(*r), level,
- (void *)hdr + sizeof(struct ct_hdr), rct->len);
+ (void *)hdr + sizeof(struct fc_ct_hdr), rct->len);
spin_unlock_irqrestore(&dbf->san_lock, flags);
}
static void zfcp_dbf_san_els(const char *tag, int level,
- struct zfcp_fsf_req *fsf_req, u32 s_id, u32 d_id,
- u8 ls_code, void *buffer, int buflen)
+ struct zfcp_fsf_req *fsf_req, u32 d_id,
+ void *buffer, int buflen)
{
struct zfcp_adapter *adapter = fsf_req->adapter;
struct zfcp_dbf *dbf = adapter->dbf;
@@ -762,9 +757,7 @@ static void zfcp_dbf_san_els(const char *tag, int level,
strncpy(rec->tag, tag, ZFCP_DBF_TAG_SIZE);
rec->fsf_reqid = fsf_req->req_id;
rec->fsf_seqno = fsf_req->seq_no;
- rec->s_id = s_id;
- rec->d_id = d_id;
- rec->u.els.ls_code = ls_code;
+ rec->u.els.d_id = d_id;
debug_event(dbf->san, level, rec, sizeof(*rec));
zfcp_dbf_hexdump(dbf->san, rec, sizeof(*rec), level,
buffer, min(buflen, ZFCP_DBF_SAN_MAX_PAYLOAD));
@@ -777,12 +770,11 @@ static void zfcp_dbf_san_els(const char *tag, int level,
*/
void zfcp_dbf_san_els_request(struct zfcp_fsf_req *fsf_req)
{
- struct zfcp_send_els *els = (struct zfcp_send_els *)fsf_req->data;
+ struct zfcp_fsf_ct_els *els = (struct zfcp_fsf_ct_els *)fsf_req->data;
+ u32 d_id = ntoh24(fsf_req->qtcb->bottom.support.d_id);
- zfcp_dbf_san_els("oels", 2, fsf_req,
- fc_host_port_id(els->adapter->scsi_host),
- els->d_id, *(u8 *) sg_virt(els->req),
- sg_virt(els->req), els->req->length);
+ zfcp_dbf_san_els("oels", 2, fsf_req, d_id,
+ sg_virt(els->req), els->req->length);
}
/**
@@ -791,12 +783,11 @@ void zfcp_dbf_san_els_request(struct zfcp_fsf_req *fsf_req)
*/
void zfcp_dbf_san_els_response(struct zfcp_fsf_req *fsf_req)
{
- struct zfcp_send_els *els = (struct zfcp_send_els *)fsf_req->data;
+ struct zfcp_fsf_ct_els *els = (struct zfcp_fsf_ct_els *)fsf_req->data;
+ u32 d_id = ntoh24(fsf_req->qtcb->bottom.support.d_id);
- zfcp_dbf_san_els("rels", 2, fsf_req, els->d_id,
- fc_host_port_id(els->adapter->scsi_host),
- *(u8 *)sg_virt(els->req), sg_virt(els->resp),
- els->resp->length);
+ zfcp_dbf_san_els("rels", 2, fsf_req, d_id,
+ sg_virt(els->resp), els->resp->length);
}
/**
@@ -805,16 +796,13 @@ void zfcp_dbf_san_els_response(struct zfcp_fsf_req *fsf_req)
*/
void zfcp_dbf_san_incoming_els(struct zfcp_fsf_req *fsf_req)
{
- struct zfcp_adapter *adapter = fsf_req->adapter;
struct fsf_status_read_buffer *buf =
(struct fsf_status_read_buffer *)fsf_req->data;
int length = (int)buf->length -
(int)((void *)&buf->payload - (void *)buf);
- zfcp_dbf_san_els("iels", 1, fsf_req, buf->d_id,
- fc_host_port_id(adapter->scsi_host),
- buf->payload.data[0], (void *)buf->payload.data,
- length);
+ zfcp_dbf_san_els("iels", 1, fsf_req, ntoh24(buf->d_id),
+ (void *)buf->payload.data, length);
}
static int zfcp_dbf_san_view_format(debug_info_t *id, struct debug_view *view,
@@ -829,11 +817,10 @@ static int zfcp_dbf_san_view_format(debug_info_t *id, struct debug_view *view,
zfcp_dbf_tag(&p, "tag", r->tag);
zfcp_dbf_out(&p, "fsf_reqid", "0x%0Lx", r->fsf_reqid);
zfcp_dbf_out(&p, "fsf_seqno", "0x%08x", r->fsf_seqno);
- zfcp_dbf_out(&p, "s_id", "0x%06x", r->s_id);
- zfcp_dbf_out(&p, "d_id", "0x%06x", r->d_id);
if (strncmp(r->tag, "octc", ZFCP_DBF_TAG_SIZE) == 0) {
struct zfcp_dbf_san_record_ct_request *ct = &r->u.ct_req;
+ zfcp_dbf_out(&p, "d_id", "0x%06x", ct->d_id);
zfcp_dbf_out(&p, "cmd_req_code", "0x%04x", ct->cmd_req_code);
zfcp_dbf_out(&p, "revision", "0x%02x", ct->revision);
zfcp_dbf_out(&p, "gs_type", "0x%02x", ct->gs_type);
@@ -852,7 +839,7 @@ static int zfcp_dbf_san_view_format(debug_info_t *id, struct debug_view *view,
strncmp(r->tag, "rels", ZFCP_DBF_TAG_SIZE) == 0 ||
strncmp(r->tag, "iels", ZFCP_DBF_TAG_SIZE) == 0) {
struct zfcp_dbf_san_record_els *els = &r->u.els;
- zfcp_dbf_out(&p, "ls_code", "0x%02x", els->ls_code);
+ zfcp_dbf_out(&p, "d_id", "0x%06x", els->d_id);
}
return p - out_buf;
}
@@ -870,8 +857,9 @@ void _zfcp_dbf_scsi(const char *tag, const char *tag2, int level,
struct zfcp_dbf_scsi_record *rec = &dbf->scsi_buf;
struct zfcp_dbf_dump *dump = (struct zfcp_dbf_dump *)rec;
unsigned long flags;
- struct fcp_rsp_iu *fcp_rsp;
- char *fcp_rsp_info = NULL, *fcp_sns_info = NULL;
+ struct fcp_resp_with_ext *fcp_rsp;
+ struct fcp_resp_rsp_info *fcp_rsp_info = NULL;
+ char *fcp_sns_info = NULL;
int offset = 0, buflen = 0;
spin_lock_irqsave(&dbf->scsi_lock, flags);
@@ -895,20 +883,22 @@ void _zfcp_dbf_scsi(const char *tag, const char *tag2, int level,
rec->scsi_allowed = scsi_cmnd->allowed;
}
if (fsf_req != NULL) {
- fcp_rsp = (struct fcp_rsp_iu *)
- &(fsf_req->qtcb->bottom.io.fcp_rsp);
- fcp_rsp_info = (unsigned char *) &fcp_rsp[1];
- fcp_sns_info =
- zfcp_get_fcp_sns_info_ptr(fcp_rsp);
-
- rec->rsp_validity = fcp_rsp->validity.value;
- rec->rsp_scsi_status = fcp_rsp->scsi_status;
- rec->rsp_resid = fcp_rsp->fcp_resid;
- if (fcp_rsp->validity.bits.fcp_rsp_len_valid)
- rec->rsp_code = *(fcp_rsp_info + 3);
- if (fcp_rsp->validity.bits.fcp_sns_len_valid) {
- buflen = min((int)fcp_rsp->fcp_sns_len,
- ZFCP_DBF_SCSI_MAX_FCP_SNS_INFO);
+ fcp_rsp = (struct fcp_resp_with_ext *)
+ &(fsf_req->qtcb->bottom.io.fcp_rsp);
+ fcp_rsp_info = (struct fcp_resp_rsp_info *)
+ &fcp_rsp[1];
+ fcp_sns_info = (char *) &fcp_rsp[1];
+ if (fcp_rsp->resp.fr_flags & FCP_RSP_LEN_VAL)
+ fcp_sns_info += fcp_rsp->ext.fr_sns_len;
+
+ rec->rsp_validity = fcp_rsp->resp.fr_flags;
+ rec->rsp_scsi_status = fcp_rsp->resp.fr_status;
+ rec->rsp_resid = fcp_rsp->ext.fr_resid;
+ if (fcp_rsp->resp.fr_flags & FCP_RSP_LEN_VAL)
+ rec->rsp_code = fcp_rsp_info->rsp_code;
+ if (fcp_rsp->resp.fr_flags & FCP_SNS_LEN_VAL) {
+ buflen = min(fcp_rsp->ext.fr_sns_len,
+ (u32)ZFCP_DBF_SCSI_MAX_FCP_SNS_INFO);
rec->sns_info_len = buflen;
memcpy(rec->sns_info, fcp_sns_info,
min(buflen,
@@ -1067,6 +1057,8 @@ err_out:
*/
void zfcp_dbf_adapter_unregister(struct zfcp_dbf *dbf)
{
+ if (!dbf)
+ return;
debug_unregister(dbf->scsi);
debug_unregister(dbf->san);
debug_unregister(dbf->hba);
diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h
index 6b1461e..8b7fd9a 100644
--- a/drivers/s390/scsi/zfcp_dbf.h
+++ b/drivers/s390/scsi/zfcp_dbf.h
@@ -22,6 +22,7 @@
#ifndef ZFCP_DBF_H
#define ZFCP_DBF_H
+#include <scsi/fc/fc_fcp.h>
#include "zfcp_ext.h"
#include "zfcp_fsf.h"
#include "zfcp_def.h"
@@ -122,7 +123,6 @@ struct zfcp_dbf_hba_record_response {
} unit;
struct {
u32 d_id;
- u8 ls_code;
} els;
} u;
} __attribute__ ((packed));
@@ -166,6 +166,7 @@ struct zfcp_dbf_san_record_ct_request {
u8 options;
u16 max_res_size;
u32 len;
+ u32 d_id;
} __attribute__ ((packed));
struct zfcp_dbf_san_record_ct_response {
@@ -179,16 +180,13 @@ struct zfcp_dbf_san_record_ct_response {
} __attribute__ ((packed));
struct zfcp_dbf_san_record_els {
- u8 ls_code;
- u32 len;
+ u32 d_id;
} __attribute__ ((packed));
struct zfcp_dbf_san_record {
u8 tag[ZFCP_DBF_TAG_SIZE];
u64 fsf_reqid;
u32 fsf_seqno;
- u32 s_id;
- u32 d_id;
union {
struct zfcp_dbf_san_record_ct_request ct_req;
struct zfcp_dbf_san_record_ct_response ct_resp;
@@ -343,7 +341,7 @@ static inline
void zfcp_dbf_scsi_devreset(const char *tag, u8 flag, struct zfcp_unit *unit,
struct scsi_cmnd *scsi_cmnd)
{
- zfcp_dbf_scsi(flag == FCP_TARGET_RESET ? "trst" : "lrst", tag, 1,
+ zfcp_dbf_scsi(flag == FCP_TMF_TGT_RESET ? "trst" : "lrst", tag, 1,
unit->port->adapter->dbf, scsi_cmnd, NULL, 0);
}
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h
index 7da2fad..e1b5b88 100644
--- a/drivers/s390/scsi/zfcp_def.h
+++ b/drivers/s390/scsi/zfcp_def.h
@@ -71,131 +71,6 @@
/* timeout value for "default timer" for fsf requests */
#define ZFCP_FSF_REQUEST_TIMEOUT (60*HZ)
-/*************** FIBRE CHANNEL PROTOCOL SPECIFIC DEFINES ********************/
-
-/* task attribute values in FCP-2 FCP_CMND IU */
-#define SIMPLE_Q 0
-#define HEAD_OF_Q 1
-#define ORDERED_Q 2
-#define ACA_Q 4
-#define UNTAGGED 5
-
-/* task management flags in FCP-2 FCP_CMND IU */
-#define FCP_CLEAR_ACA 0x40
-#define FCP_TARGET_RESET 0x20
-#define FCP_LOGICAL_UNIT_RESET 0x10
-#define FCP_CLEAR_TASK_SET 0x04
-#define FCP_ABORT_TASK_SET 0x02
-
-#define FCP_CDB_LENGTH 16
-
-#define ZFCP_DID_MASK 0x00FFFFFF
-
-/* FCP(-2) FCP_CMND IU */
-struct fcp_cmnd_iu {
- u64 fcp_lun; /* FCP logical unit number */
- u8 crn; /* command reference number */
- u8 reserved0:5; /* reserved */
- u8 task_attribute:3; /* task attribute */
- u8 task_management_flags; /* task management flags */
- u8 add_fcp_cdb_length:6; /* additional FCP_CDB length */
- u8 rddata:1; /* read data */
- u8 wddata:1; /* write data */
- u8 fcp_cdb[FCP_CDB_LENGTH];
-} __attribute__((packed));
-
-/* FCP(-2) FCP_RSP IU */
-struct fcp_rsp_iu {
- u8 reserved0[10];
- union {
- struct {
- u8 reserved1:3;
- u8 fcp_conf_req:1;
- u8 fcp_resid_under:1;
- u8 fcp_resid_over:1;
- u8 fcp_sns_len_valid:1;
- u8 fcp_rsp_len_valid:1;
- } bits;
- u8 value;
- } validity;
- u8 scsi_status;
- u32 fcp_resid;
- u32 fcp_sns_len;
- u32 fcp_rsp_len;
-} __attribute__((packed));
-
-
-#define RSP_CODE_GOOD 0
-#define RSP_CODE_LENGTH_MISMATCH 1
-#define RSP_CODE_FIELD_INVALID 2
-#define RSP_CODE_RO_MISMATCH 3
-#define RSP_CODE_TASKMAN_UNSUPP 4
-#define RSP_CODE_TASKMAN_FAILED 5
-
-/* see fc-fs */
-#define LS_RSCN 0x61
-#define LS_LOGO 0x05
-#define LS_PLOGI 0x03
-
-struct fcp_rscn_head {
- u8 command;
- u8 page_length; /* always 0x04 */
- u16 payload_len;
-} __attribute__((packed));
-
-struct fcp_rscn_element {
- u8 reserved:2;
- u8 event_qual:4;
- u8 addr_format:2;
- u32 nport_did:24;
-} __attribute__((packed));
-
-/* see fc-ph */
-struct fcp_logo {
- u32 command;
- u32 nport_did;
- u64 nport_wwpn;
-} __attribute__((packed));
-
-/*
- * FC-FS stuff
- */
-#define R_A_TOV 10 /* seconds */
-
-#define ZFCP_LS_RLS 0x0f
-#define ZFCP_LS_ADISC 0x52
-#define ZFCP_LS_RPS 0x56
-#define ZFCP_LS_RSCN 0x61
-#define ZFCP_LS_RNID 0x78
-
-struct zfcp_ls_adisc {
- u8 code;
- u8 field[3];
- u32 hard_nport_id;
- u64 wwpn;
- u64 wwnn;
- u32 nport_id;
-} __attribute__ ((packed));
-
-/*
- * FC-GS-2 stuff
- */
-#define ZFCP_CT_REVISION 0x01
-#define ZFCP_CT_DIRECTORY_SERVICE 0xFC
-#define ZFCP_CT_NAME_SERVER 0x02
-#define ZFCP_CT_SYNCHRONOUS 0x00
-#define ZFCP_CT_SCSI_FCP 0x08
-#define ZFCP_CT_UNABLE_TO_PERFORM_CMD 0x09
-#define ZFCP_CT_GID_PN 0x0121
-#define ZFCP_CT_GPN_FT 0x0172
-#define ZFCP_CT_ACCEPT 0x8002
-#define ZFCP_CT_REJECT 0x8001
-
-/*
- * FC-GS-4 stuff
- */
-#define ZFCP_CT_TIMEOUT (3 * R_A_TOV)
-
/*************** ADAPTER/PORT/UNIT AND FSF_REQ STATUS FLAGS ******************/
/*
@@ -205,7 +80,6 @@ struct zfcp_ls_adisc {
#define ZFCP_COMMON_FLAGS 0xfff00000
/* common status bits */
-#define ZFCP_STATUS_COMMON_REMOVE 0x80000000
#define ZFCP_STATUS_COMMON_RUNNING 0x40000000
#define ZFCP_STATUS_COMMON_ERP_FAILED 0x20000000
#define ZFCP_STATUS_COMMON_UNBLOCKED 0x10000000
@@ -222,21 +96,10 @@ struct zfcp_ls_adisc {
#define ZFCP_STATUS_ADAPTER_ERP_PENDING 0x00000100
#define ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED 0x00000200
-/* FC-PH/FC-GS well-known address identifiers for generic services */
-#define ZFCP_DID_WKA 0xFFFFF0
-
/* remote port status */
#define ZFCP_STATUS_PORT_PHYS_OPEN 0x00000001
#define ZFCP_STATUS_PORT_LINK_TEST 0x00000002
-/* well known address (WKA) port status*/
-enum zfcp_wka_status {
- ZFCP_WKA_PORT_OFFLINE,
- ZFCP_WKA_PORT_CLOSING,
- ZFCP_WKA_PORT_OPENING,
- ZFCP_WKA_PORT_ONLINE,
-};
-
/* logical unit status */
#define ZFCP_STATUS_UNIT_SHARED 0x00000004
#define ZFCP_STATUS_UNIT_READONLY 0x00000008
@@ -247,10 +110,7 @@ enum zfcp_wka_status {
#define ZFCP_STATUS_FSFREQ_CLEANUP 0x00000010
#define ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED 0x00000040
#define ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED 0x00000080
-#define ZFCP_STATUS_FSFREQ_ABORTED 0x00000100
#define ZFCP_STATUS_FSFREQ_TMFUNCFAILED 0x00000200
-#define ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP 0x00000400
-#define ZFCP_STATUS_FSFREQ_RETRY 0x00000800
#define ZFCP_STATUS_FSFREQ_DISMISSED 0x00001000
/************************* STRUCTURE DEFINITIONS *****************************/
@@ -265,125 +125,10 @@ struct zfcp_adapter_mempool {
mempool_t *scsi_abort;
mempool_t *status_read_req;
mempool_t *status_read_data;
- mempool_t *gid_pn_data;
+ mempool_t *gid_pn;
mempool_t *qtcb_pool;
};
-/*
- * header for CT_IU
- */
-struct ct_hdr {
- u8 revision; // 0x01
- u8 in_id[3]; // 0x00
- u8 gs_type; // 0xFC Directory Service
- u8 gs_subtype; // 0x02 Name Server
- u8 options; // 0x00 single bidirectional exchange
- u8 reserved0;
- u16 cmd_rsp_code; // 0x0121 GID_PN, or 0x0100 GA_NXT
- u16 max_res_size; // <= (4096 - 16) / 4
- u8 reserved1;
- u8 reason_code;
- u8 reason_code_expl;
- u8 vendor_unique;
-} __attribute__ ((packed));
-
-/* nameserver request CT_IU -- for requests where
- * a port name is required */
-struct ct_iu_gid_pn_req {
- struct ct_hdr header;
- u64 wwpn;
-} __attribute__ ((packed));
-
-/* FS_ACC IU and data unit for GID_PN nameserver request */
-struct ct_iu_gid_pn_resp {
- struct ct_hdr header;
- u32 d_id;
-} __attribute__ ((packed));
-
-struct ct_iu_gpn_ft_req {
- struct ct_hdr header;
- u8 flags;
- u8 domain_id_scope;
- u8 area_id_scope;
- u8 fc4_type;
-} __attribute__ ((packed));
-
-
-/**
- * struct zfcp_send_ct - used to pass parameters to function zfcp_fsf_send_ct
- * @wka_port: port where the request is sent to
- * @req: scatter-gather list for request
- * @resp: scatter-gather list for response
- * @handler: handler function (called for response to the request)
- * @handler_data: data passed to handler function
- * @completion: completion for synchronization purposes
- * @status: used to pass error status to calling function
- */
-struct zfcp_send_ct {
- struct zfcp_wka_port *wka_port;
- struct scatterlist *req;
- struct scatterlist *resp;
- void (*handler)(unsigned long);
- unsigned long handler_data;
- struct completion *completion;
- int status;
-};
-
-/* used for name server requests in error recovery */
-struct zfcp_gid_pn_data {
- struct zfcp_send_ct ct;
- struct scatterlist req;
- struct scatterlist resp;
- struct ct_iu_gid_pn_req ct_iu_req;
- struct ct_iu_gid_pn_resp ct_iu_resp;
- struct zfcp_port *port;
-};
-
-/**
- * struct zfcp_send_els - used to pass parameters to function zfcp_fsf_send_els
- * @adapter: adapter where request is sent from
- * @port: port where ELS is destinated (port reference count has to be increased)
- * @d_id: destiniation id of port where request is sent to
- * @req: scatter-gather list for request
- * @resp: scatter-gather list for response
- * @handler: handler function (called for response to the request)
- * @handler_data: data passed to handler function
- * @completion: completion for synchronization purposes
- * @ls_code: hex code of ELS command
- * @status: used to pass error status to calling function
- */
-struct zfcp_send_els {
- struct zfcp_adapter *adapter;
- struct zfcp_port *port;
- u32 d_id;
- struct scatterlist *req;
- struct scatterlist *resp;
- void (*handler)(unsigned long);
- unsigned long handler_data;
- struct completion *completion;
- int ls_code;
- int status;
-};
-
-struct zfcp_wka_port {
- struct zfcp_adapter *adapter;
- wait_queue_head_t completion_wq;
- enum zfcp_wka_status status;
- atomic_t refcount;
- u32 d_id;
- u32 handle;
- struct mutex mutex;
- struct delayed_work work;
-};
-
-struct zfcp_wka_ports {
- struct zfcp_wka_port ms; /* management service */
- struct zfcp_wka_port ts; /* time service */
- struct zfcp_wka_port ds; /* directory service */
- struct zfcp_wka_port as; /* alias service */
- struct zfcp_wka_port ks; /* key distribution service */
-};
-
struct zfcp_qdio_queue {
struct qdio_buffer *sbal[QDIO_MAX_BUFFERS_PER_Q];
u8 first; /* index of next free bfr in queue */
@@ -446,9 +191,7 @@ struct zfcp_qdio {
};
struct zfcp_adapter {
- atomic_t refcount; /* reference count */
- wait_queue_head_t remove_wq; /* can be used to wait for
- refcount drop to zero */
+ struct kref ref;
u64 peer_wwnn; /* P2P peer WWNN */
u64 peer_wwpn; /* P2P peer WWPN */
u32 peer_d_id; /* P2P peer D_ID */
@@ -461,7 +204,8 @@ struct zfcp_adapter {
u32 hardware_version; /* of FCP channel */
u16 timer_ticks; /* time int for a tick */
struct Scsi_Host *scsi_host; /* Pointer to mid-layer */
- struct list_head port_list_head; /* remote port list */
+ struct list_head port_list; /* remote port list */
+ rwlock_t port_list_lock; /* port list lock */
unsigned long req_no; /* unique FSF req number */
struct list_head *req_list; /* list of pending reqs */
spinlock_t req_list_lock; /* request list lock */
@@ -485,7 +229,7 @@ struct zfcp_adapter {
u32 erp_low_mem_count; /* nr of erp actions waiting
for memory */
struct task_struct *erp_thread;
- struct zfcp_wka_ports *gs; /* generic services */
+ struct zfcp_fc_wka_ports *gs; /* generic services */
struct zfcp_dbf *dbf; /* debug traces */
struct zfcp_adapter_mempool pool; /* Adapter memory pools */
struct fc_host_statistics *fc_stats;
@@ -500,11 +244,9 @@ struct zfcp_port {
struct device sysfs_device; /* sysfs device */
struct fc_rport *rport; /* rport of fc transport class */
struct list_head list; /* list of remote ports */
- atomic_t refcount; /* reference count */
- wait_queue_head_t remove_wq; /* can be used to wait for
- refcount drop to zero */
struct zfcp_adapter *adapter; /* adapter used to access port */
- struct list_head unit_list_head; /* head of logical unit list */
+ struct list_head unit_list; /* head of logical unit list */
+ rwlock_t unit_list_lock; /* unit list lock */
atomic_t status; /* status of this remote port */
u64 wwnn; /* WWNN if known */
u64 wwpn; /* WWPN */
@@ -523,9 +265,6 @@ struct zfcp_port {
struct zfcp_unit {
struct device sysfs_device; /* sysfs device */
struct list_head list; /* list of logical units */
- atomic_t refcount; /* reference count */
- wait_queue_head_t remove_wq; /* can be used to wait for
- refcount drop to zero */
struct zfcp_port *port; /* remote port of unit */
atomic_t status; /* status of this logical unit */
u64 fcp_lun; /* own FCP_LUN */
@@ -601,14 +340,11 @@ struct zfcp_fsf_req {
struct zfcp_data {
struct scsi_host_template scsi_host_template;
struct scsi_transport_template *scsi_transport_template;
- rwlock_t config_lock; /* serialises changes
- to adapter/port/unit
- lists */
- struct mutex config_mutex;
struct kmem_cache *gpn_ft_cache;
struct kmem_cache *qtcb_cache;
struct kmem_cache *sr_buffer_cache;
struct kmem_cache *gid_pn_cache;
+ struct kmem_cache *adisc_cache;
};
/********************** ZFCP SPECIFIC DEFINES ********************************/
@@ -657,47 +393,4 @@ zfcp_reqlist_find_safe(struct zfcp_adapter *adapter, struct zfcp_fsf_req *req)
return NULL;
}
-/*
- * functions needed for reference/usage counting
- */
-
-static inline void
-zfcp_unit_get(struct zfcp_unit *unit)
-{
- atomic_inc(&unit->refcount);
-}
-
-static inline void
-zfcp_unit_put(struct zfcp_unit *unit)
-{
- if (atomic_dec_return(&unit->refcount) == 0)
- wake_up(&unit->remove_wq);
-}
-
-static inline void
-zfcp_port_get(struct zfcp_port *port)
-{
- atomic_inc(&port->refcount);
-}
-
-static inline void
-zfcp_port_put(struct zfcp_port *port)
-{
- if (atomic_dec_return(&port->refcount) == 0)
- wake_up(&port->remove_wq);
-}
-
-static inline void
-zfcp_adapter_get(struct zfcp_adapter *adapter)
-{
- atomic_inc(&adapter->refcount);
-}
-
-static inline void
-zfcp_adapter_put(struct zfcp_adapter *adapter)
-{
- if (atomic_dec_return(&adapter->refcount) == 0)
- wake_up(&adapter->remove_wq);
-}
-
#endif /* ZFCP_DEF_H */
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index f73e218..b51a11a 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -99,9 +99,12 @@ static void zfcp_erp_action_dismiss_port(struct zfcp_port *port)
if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
zfcp_erp_action_dismiss(&port->erp_action);
- else
- list_for_each_entry(unit, &port->unit_list_head, list)
- zfcp_erp_action_dismiss_unit(unit);
+ else {
+ read_lock(&port->unit_list_lock);
+ list_for_each_entry(unit, &port->unit_list, list)
+ zfcp_erp_action_dismiss_unit(unit);
+ read_unlock(&port->unit_list_lock);
+ }
}
static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter)
@@ -110,9 +113,12 @@ static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter)
if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
zfcp_erp_action_dismiss(&adapter->erp_action);
- else
- list_for_each_entry(port, &adapter->port_list_head, list)
+ else {
+ read_lock(&adapter->port_list_lock);
+ list_for_each_entry(port, &adapter->port_list, list)
zfcp_erp_action_dismiss_port(port);
+ read_unlock(&adapter->port_list_lock);
+ }
}
static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter,
@@ -168,7 +174,8 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need,
switch (need) {
case ZFCP_ERP_ACTION_REOPEN_UNIT:
- zfcp_unit_get(unit);
+ if (!get_device(&unit->sysfs_device))
+ return NULL;
atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status);
erp_action = &unit->erp_action;
if (!(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_RUNNING))
@@ -177,7 +184,8 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need,
case ZFCP_ERP_ACTION_REOPEN_PORT:
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
- zfcp_port_get(port);
+ if (!get_device(&port->sysfs_device))
+ return NULL;
zfcp_erp_action_dismiss_port(port);
atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status);
erp_action = &port->erp_action;
@@ -186,7 +194,7 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need,
break;
case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
- zfcp_adapter_get(adapter);
+ kref_get(&adapter->ref);
zfcp_erp_action_dismiss_adapter(adapter);
atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status);
erp_action = &adapter->erp_action;
@@ -264,11 +272,16 @@ void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear,
{
unsigned long flags;
- read_lock_irqsave(&zfcp_data.config_lock, flags);
- write_lock(&adapter->erp_lock);
- _zfcp_erp_adapter_reopen(adapter, clear, id, ref);
- write_unlock(&adapter->erp_lock);
- read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+ zfcp_erp_adapter_block(adapter, clear);
+ zfcp_scsi_schedule_rports_block(adapter);
+
+ write_lock_irqsave(&adapter->erp_lock, flags);
+ if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
+ zfcp_erp_adapter_failed(adapter, "erareo1", NULL);
+ else
+ zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, adapter,
+ NULL, NULL, id, ref);
+ write_unlock_irqrestore(&adapter->erp_lock, flags);
}
/**
@@ -345,11 +358,9 @@ void zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, char *id,
unsigned long flags;
struct zfcp_adapter *adapter = port->adapter;
- read_lock_irqsave(&zfcp_data.config_lock, flags);
- write_lock(&adapter->erp_lock);
+ write_lock_irqsave(&adapter->erp_lock, flags);
_zfcp_erp_port_forced_reopen(port, clear, id, ref);
- write_unlock(&adapter->erp_lock);
- read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+ write_unlock_irqrestore(&adapter->erp_lock, flags);
}
static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id,
@@ -377,15 +388,13 @@ static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id,
*/
int zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id, void *ref)
{
- unsigned long flags;
int retval;
+ unsigned long flags;
struct zfcp_adapter *adapter = port->adapter;
- read_lock_irqsave(&zfcp_data.config_lock, flags);
- write_lock(&adapter->erp_lock);
+ write_lock_irqsave(&adapter->erp_lock, flags);
retval = _zfcp_erp_port_reopen(port, clear, id, ref);
- write_unlock(&adapter->erp_lock);
- read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+ write_unlock_irqrestore(&adapter->erp_lock, flags);
return retval;
}
@@ -424,11 +433,9 @@ void zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, char *id,
struct zfcp_port *port = unit->port;
struct zfcp_adapter *adapter = port->adapter;
- read_lock_irqsave(&zfcp_data.config_lock, flags);
- write_lock(&adapter->erp_lock);
+ write_lock_irqsave(&adapter->erp_lock, flags);
_zfcp_erp_unit_reopen(unit, clear, id, ref);
- write_unlock(&adapter->erp_lock);
- read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+ write_unlock_irqrestore(&adapter->erp_lock, flags);
}
static int status_change_set(unsigned long mask, atomic_t *status)
@@ -540,8 +547,10 @@ static void _zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter,
{
struct zfcp_port *port;
- list_for_each_entry(port, &adapter->port_list_head, list)
+ read_lock(&adapter->port_list_lock);
+ list_for_each_entry(port, &adapter->port_list, list)
_zfcp_erp_port_reopen(port, clear, id, ref);
+ read_unlock(&adapter->port_list_lock);
}
static void _zfcp_erp_unit_reopen_all(struct zfcp_port *port, int clear,
@@ -549,8 +558,10 @@ static void _zfcp_erp_unit_reopen_all(struct zfcp_port *port, int clear,
{
struct zfcp_unit *unit;
- list_for_each_entry(unit, &port->unit_list_head, list)
+ read_lock(&port->unit_list_lock);
+ list_for_each_entry(unit, &port->unit_list, list)
_zfcp_erp_unit_reopen(unit, clear, id, ref);
+ read_unlock(&port->unit_list_lock);
}
static void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act)
@@ -590,16 +601,14 @@ static void zfcp_erp_wakeup(struct zfcp_adapter *adapter)
{
unsigned long flags;
- read_lock_irqsave(&zfcp_data.config_lock, flags);
- read_lock(&adapter->erp_lock);
+ read_lock_irqsave(&adapter->erp_lock, flags);
if (list_empty(&adapter->erp_ready_head) &&
list_empty(&adapter->erp_running_head)) {
atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING,
&adapter->status);
wake_up(&adapter->erp_done_wqh);
}
- read_unlock(&adapter->erp_lock);
- read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+ read_unlock_irqrestore(&adapter->erp_lock, flags);
}
static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *act)
@@ -1170,28 +1179,28 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
switch (act->action) {
case ZFCP_ERP_ACTION_REOPEN_UNIT:
if ((result == ZFCP_ERP_SUCCEEDED) && !unit->device) {
- zfcp_unit_get(unit);
+ get_device(&unit->sysfs_device);
if (scsi_queue_work(unit->port->adapter->scsi_host,
&unit->scsi_work) <= 0)
- zfcp_unit_put(unit);
+ put_device(&unit->sysfs_device);
}
- zfcp_unit_put(unit);
+ put_device(&unit->sysfs_device);
break;
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
case ZFCP_ERP_ACTION_REOPEN_PORT:
if (result == ZFCP_ERP_SUCCEEDED)
zfcp_scsi_schedule_rport_register(port);
- zfcp_port_put(port);
+ put_device(&port->sysfs_device);
break;
case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
if (result == ZFCP_ERP_SUCCEEDED) {
register_service_level(&adapter->service_level);
- schedule_work(&adapter->scan_work);
+ queue_work(adapter->work_queue, &adapter->scan_work);
} else
unregister_service_level(&adapter->service_level);
- zfcp_adapter_put(adapter);
+ kref_put(&adapter->ref, zfcp_adapter_release);
break;
}
}
@@ -1214,12 +1223,12 @@ static int zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action)
static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
{
int retval;
- struct zfcp_adapter *adapter = erp_action->adapter;
unsigned long flags;
+ struct zfcp_adapter *adapter = erp_action->adapter;
- read_lock_irqsave(&zfcp_data.config_lock, flags);
- write_lock(&adapter->erp_lock);
+ kref_get(&adapter->ref);
+ write_lock_irqsave(&adapter->erp_lock, flags);
zfcp_erp_strategy_check_fsfreq(erp_action);
if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) {
@@ -1231,11 +1240,9 @@ static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
zfcp_erp_action_to_running(erp_action);
/* no lock to allow for blocking operations */
- write_unlock(&adapter->erp_lock);
- read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+ write_unlock_irqrestore(&adapter->erp_lock, flags);
retval = zfcp_erp_strategy_do_action(erp_action);
- read_lock_irqsave(&zfcp_data.config_lock, flags);
- write_lock(&adapter->erp_lock);
+ write_lock_irqsave(&adapter->erp_lock, flags);
if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED)
retval = ZFCP_ERP_CONTINUES;
@@ -1273,12 +1280,12 @@ static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
zfcp_erp_strategy_followup_failed(erp_action);
unlock:
- write_unlock(&adapter->erp_lock);
- read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+ write_unlock_irqrestore(&adapter->erp_lock, flags);
if (retval != ZFCP_ERP_CONTINUES)
zfcp_erp_action_cleanup(erp_action, retval);
+ kref_put(&adapter->ref, zfcp_adapter_release);
return retval;
}
@@ -1415,6 +1422,7 @@ void zfcp_erp_modify_adapter_status(struct zfcp_adapter *adapter, char *id,
void *ref, u32 mask, int set_or_clear)
{
struct zfcp_port *port;
+ unsigned long flags;
u32 common_mask = mask & ZFCP_COMMON_FLAGS;
if (set_or_clear == ZFCP_SET) {
@@ -1429,10 +1437,13 @@ void zfcp_erp_modify_adapter_status(struct zfcp_adapter *adapter, char *id,
atomic_set(&adapter->erp_counter, 0);
}
- if (common_mask)
- list_for_each_entry(port, &adapter->port_list_head, list)
+ if (common_mask) {
+ read_lock_irqsave(&adapter->port_list_lock, flags);
+ list_for_each_entry(port, &adapter->port_list, list)
zfcp_erp_modify_port_status(port, id, ref, common_mask,
set_or_clear);
+ read_unlock_irqrestore(&adapter->port_list_lock, flags);
+ }
}
/**
@@ -1449,6 +1460,7 @@ void zfcp_erp_modify_port_status(struct zfcp_port *port, char *id, void *ref,
u32 mask, int set_or_clear)
{
struct zfcp_unit *unit;
+ unsigned long flags;
u32 common_mask = mask & ZFCP_COMMON_FLAGS;
if (set_or_clear == ZFCP_SET) {
@@ -1463,10 +1475,13 @@ void zfcp_erp_modify_port_status(struct zfcp_port *port, char *id, void *ref,
atomic_set(&port->erp_counter, 0);
}
- if (common_mask)
- list_for_each_entry(unit, &port->unit_list_head, list)
+ if (common_mask) {
+ read_lock_irqsave(&port->unit_list_lock, flags);
+ list_for_each_entry(unit, &port->unit_list, list)
zfcp_erp_modify_unit_status(unit, id, ref, common_mask,
set_or_clear);
+ read_unlock_irqrestore(&port->unit_list_lock, flags);
+ }
}
/**
@@ -1502,12 +1517,8 @@ void zfcp_erp_modify_unit_status(struct zfcp_unit *unit, char *id, void *ref,
*/
void zfcp_erp_port_boxed(struct zfcp_port *port, char *id, void *ref)
{
- unsigned long flags;
-
- read_lock_irqsave(&zfcp_data.config_lock, flags);
zfcp_erp_modify_port_status(port, id, ref,
ZFCP_STATUS_COMMON_ACCESS_BOXED, ZFCP_SET);
- read_unlock_irqrestore(&zfcp_data.config_lock, flags);
zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref);
}
@@ -1535,13 +1546,9 @@ void zfcp_erp_unit_boxed(struct zfcp_unit *unit, char *id, void *ref)
*/
void zfcp_erp_port_access_denied(struct zfcp_port *port, char *id, void *ref)
{
- unsigned long flags;
-
- read_lock_irqsave(&zfcp_data.config_lock, flags);
zfcp_erp_modify_port_status(port, id, ref,
ZFCP_STATUS_COMMON_ERP_FAILED |
ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET);
- read_unlock_irqrestore(&zfcp_data.config_lock, flags);
}
/**
@@ -1574,12 +1581,15 @@ static void zfcp_erp_port_access_changed(struct zfcp_port *port, char *id,
void *ref)
{
struct zfcp_unit *unit;
+ unsigned long flags;
int status = atomic_read(&port->status);
if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED |
ZFCP_STATUS_COMMON_ACCESS_BOXED))) {
- list_for_each_entry(unit, &port->unit_list_head, list)
+ read_lock_irqsave(&port->unit_list_lock, flags);
+ list_for_each_entry(unit, &port->unit_list, list)
zfcp_erp_unit_access_changed(unit, id, ref);
+ read_unlock_irqrestore(&port->unit_list_lock, flags);
return;
}
@@ -1595,14 +1605,14 @@ static void zfcp_erp_port_access_changed(struct zfcp_port *port, char *id,
void zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter, char *id,
void *ref)
{
- struct zfcp_port *port;
unsigned long flags;
+ struct zfcp_port *port;
if (adapter->connection_features & FSF_FEATURE_NPIV_MODE)
return;
- read_lock_irqsave(&zfcp_data.config_lock, flags);
- list_for_each_entry(port, &adapter->port_list_head, list)
+ read_lock_irqsave(&adapter->port_list_lock, flags);
+ list_for_each_entry(port, &adapter->port_list, list)
zfcp_erp_port_access_changed(port, id, ref);
- read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+ read_unlock_irqrestore(&adapter->port_list_lock, flags);
}
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
index b3f28de..03dec83 100644
--- a/drivers/s390/scsi/zfcp_ext.h
+++ b/drivers/s390/scsi/zfcp_ext.h
@@ -9,26 +9,31 @@
#ifndef ZFCP_EXT_H
#define ZFCP_EXT_H
+#include <linux/types.h>
+#include <scsi/fc/fc_els.h>
#include "zfcp_def.h"
+#include "zfcp_fc.h"
/* zfcp_aux.c */
extern struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *, u64);
extern struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *, u64);
-extern int zfcp_adapter_enqueue(struct ccw_device *);
-extern void zfcp_adapter_dequeue(struct zfcp_adapter *);
+extern struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *);
extern struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *, u64, u32,
u32);
-extern void zfcp_port_dequeue(struct zfcp_port *);
extern struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *, u64);
-extern void zfcp_unit_dequeue(struct zfcp_unit *);
extern int zfcp_reqlist_isempty(struct zfcp_adapter *);
extern void zfcp_sg_free_table(struct scatterlist *, int);
extern int zfcp_sg_setup_table(struct scatterlist *, int);
+extern void zfcp_device_unregister(struct device *,
+ const struct attribute_group *);
+extern void zfcp_adapter_release(struct kref *);
+extern void zfcp_adapter_unregister(struct zfcp_adapter *);
/* zfcp_ccw.c */
-extern int zfcp_ccw_register(void);
extern int zfcp_ccw_priv_sch(struct zfcp_adapter *);
extern struct ccw_driver zfcp_ccw_driver;
+extern struct zfcp_adapter *zfcp_ccw_adapter_by_cdev(struct ccw_device *);
+extern void zfcp_ccw_adapter_put(struct zfcp_adapter *);
/* zfcp_cfdc.c */
extern struct miscdevice zfcp_cfdc_misc;
@@ -51,7 +56,7 @@ extern void _zfcp_dbf_hba_fsf_unsol(const char *, int level, struct zfcp_dbf *,
struct fsf_status_read_buffer *);
extern void zfcp_dbf_hba_qdio(struct zfcp_dbf *, unsigned int, int, int);
extern void zfcp_dbf_hba_berr(struct zfcp_dbf *, struct zfcp_fsf_req *);
-extern void zfcp_dbf_san_ct_request(struct zfcp_fsf_req *);
+extern void zfcp_dbf_san_ct_request(struct zfcp_fsf_req *, u32);
extern void zfcp_dbf_san_ct_response(struct zfcp_fsf_req *);
extern void zfcp_dbf_san_els_request(struct zfcp_fsf_req *);
extern void zfcp_dbf_san_els_response(struct zfcp_fsf_req *);
@@ -92,24 +97,22 @@ extern void zfcp_erp_adapter_access_changed(struct zfcp_adapter *, char *,
extern void zfcp_erp_timeout_handler(unsigned long);
/* zfcp_fc.c */
-extern int zfcp_fc_scan_ports(struct zfcp_adapter *);
-extern void _zfcp_fc_scan_ports_later(struct work_struct *);
+extern void zfcp_fc_scan_ports(struct work_struct *);
extern void zfcp_fc_incoming_els(struct zfcp_fsf_req *);
extern void zfcp_fc_port_did_lookup(struct work_struct *);
extern void zfcp_fc_trigger_did_lookup(struct zfcp_port *);
-extern void zfcp_fc_plogi_evaluate(struct zfcp_port *, struct fsf_plogi *);
+extern void zfcp_fc_plogi_evaluate(struct zfcp_port *, struct fc_els_flogi *);
extern void zfcp_fc_test_link(struct zfcp_port *);
extern void zfcp_fc_link_test_work(struct work_struct *);
-extern void zfcp_fc_wka_ports_force_offline(struct zfcp_wka_ports *);
+extern void zfcp_fc_wka_ports_force_offline(struct zfcp_fc_wka_ports *);
extern int zfcp_fc_gs_setup(struct zfcp_adapter *);
extern void zfcp_fc_gs_destroy(struct zfcp_adapter *);
-extern int zfcp_fc_execute_els_fc_job(struct fc_bsg_job *);
-extern int zfcp_fc_execute_ct_fc_job(struct fc_bsg_job *);
+extern int zfcp_fc_exec_bsg_job(struct fc_bsg_job *);
/* zfcp_fsf.c */
extern int zfcp_fsf_open_port(struct zfcp_erp_action *);
-extern int zfcp_fsf_open_wka_port(struct zfcp_wka_port *);
-extern int zfcp_fsf_close_wka_port(struct zfcp_wka_port *);
+extern int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *);
+extern int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *);
extern int zfcp_fsf_close_port(struct zfcp_erp_action *);
extern int zfcp_fsf_close_physical_port(struct zfcp_erp_action *);
extern int zfcp_fsf_open_unit(struct zfcp_erp_action *);
@@ -125,8 +128,10 @@ extern struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *,
extern void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *);
extern int zfcp_fsf_status_read(struct zfcp_qdio *);
extern int zfcp_status_read_refill(struct zfcp_adapter *adapter);
-extern int zfcp_fsf_send_ct(struct zfcp_send_ct *, mempool_t *);
-extern int zfcp_fsf_send_els(struct zfcp_send_els *);
+extern int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *, struct zfcp_fsf_ct_els *,
+ mempool_t *);
+extern int zfcp_fsf_send_els(struct zfcp_adapter *, u32,
+ struct zfcp_fsf_ct_els *);
extern int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *,
struct scsi_cmnd *);
extern void zfcp_fsf_req_free(struct zfcp_fsf_req *);
@@ -153,7 +158,6 @@ extern void zfcp_qdio_close(struct zfcp_qdio *);
extern struct zfcp_data zfcp_data;
extern int zfcp_adapter_scsi_register(struct zfcp_adapter *);
extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *);
-extern char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *);
extern struct fc_function_template zfcp_transport_functions;
extern void zfcp_scsi_rport_work(struct work_struct *);
extern void zfcp_scsi_schedule_rport_register(struct zfcp_port *);
diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c
index df23bce..ac5e3b7 100644
--- a/drivers/s390/scsi/zfcp_fc.c
+++ b/drivers/s390/scsi/zfcp_fc.c
@@ -9,73 +9,38 @@
#define KMSG_COMPONENT "zfcp"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+#include <linux/types.h>
+#include <scsi/fc/fc_els.h>
+#include <scsi/libfc.h>
#include "zfcp_ext.h"
+#include "zfcp_fc.h"
-enum rscn_address_format {
- RSCN_PORT_ADDRESS = 0x0,
- RSCN_AREA_ADDRESS = 0x1,
- RSCN_DOMAIN_ADDRESS = 0x2,
- RSCN_FABRIC_ADDRESS = 0x3,
+static u32 zfcp_fc_rscn_range_mask[] = {
+ [ELS_ADDR_FMT_PORT] = 0xFFFFFF,
+ [ELS_ADDR_FMT_AREA] = 0xFFFF00,
+ [ELS_ADDR_FMT_DOM] = 0xFF0000,
+ [ELS_ADDR_FMT_FAB] = 0x000000,
};
-static u32 rscn_range_mask[] = {
- [RSCN_PORT_ADDRESS] = 0xFFFFFF,
- [RSCN_AREA_ADDRESS] = 0xFFFF00,
- [RSCN_DOMAIN_ADDRESS] = 0xFF0000,
- [RSCN_FABRIC_ADDRESS] = 0x000000,
-};
-
-struct gpn_ft_resp_acc {
- u8 control;
- u8 port_id[3];
- u8 reserved[4];
- u64 wwpn;
-} __attribute__ ((packed));
-
-#define ZFCP_CT_SIZE_ONE_PAGE (PAGE_SIZE - sizeof(struct ct_hdr))
-#define ZFCP_GPN_FT_ENTRIES (ZFCP_CT_SIZE_ONE_PAGE \
- / sizeof(struct gpn_ft_resp_acc))
-#define ZFCP_GPN_FT_BUFFERS 4
-#define ZFCP_GPN_FT_MAX_SIZE (ZFCP_GPN_FT_BUFFERS * PAGE_SIZE \
- - sizeof(struct ct_hdr))
-#define ZFCP_GPN_FT_MAX_ENTRIES ZFCP_GPN_FT_BUFFERS * (ZFCP_GPN_FT_ENTRIES + 1)
-
-struct ct_iu_gpn_ft_resp {
- struct ct_hdr header;
- struct gpn_ft_resp_acc accept[ZFCP_GPN_FT_ENTRIES];
-} __attribute__ ((packed));
-
-struct zfcp_gpn_ft {
- struct zfcp_send_ct ct;
- struct scatterlist sg_req;
- struct scatterlist sg_resp[ZFCP_GPN_FT_BUFFERS];
-};
-
-struct zfcp_fc_ns_handler_data {
- struct completion done;
- void (*handler)(unsigned long);
- unsigned long handler_data;
-};
-
-static int zfcp_fc_wka_port_get(struct zfcp_wka_port *wka_port)
+static int zfcp_fc_wka_port_get(struct zfcp_fc_wka_port *wka_port)
{
if (mutex_lock_interruptible(&wka_port->mutex))
return -ERESTARTSYS;
- if (wka_port->status == ZFCP_WKA_PORT_OFFLINE ||
- wka_port->status == ZFCP_WKA_PORT_CLOSING) {
- wka_port->status = ZFCP_WKA_PORT_OPENING;
+ if (wka_port->status == ZFCP_FC_WKA_PORT_OFFLINE ||
+ wka_port->status == ZFCP_FC_WKA_PORT_CLOSING) {
+ wka_port->status = ZFCP_FC_WKA_PORT_OPENING;
if (zfcp_fsf_open_wka_port(wka_port))
- wka_port->status = ZFCP_WKA_PORT_OFFLINE;
+ wka_port->status = ZFCP_FC_WKA_PORT_OFFLINE;
}
mutex_unlock(&wka_port->mutex);
wait_event(wka_port->completion_wq,
- wka_port->status == ZFCP_WKA_PORT_ONLINE ||
- wka_port->status == ZFCP_WKA_PORT_OFFLINE);
+ wka_port->status == ZFCP_FC_WKA_PORT_ONLINE ||
+ wka_port->status == ZFCP_FC_WKA_PORT_OFFLINE);
- if (wka_port->status == ZFCP_WKA_PORT_ONLINE) {
+ if (wka_port->status == ZFCP_FC_WKA_PORT_ONLINE) {
atomic_inc(&wka_port->refcount);
return 0;
}
@@ -85,24 +50,24 @@ static int zfcp_fc_wka_port_get(struct zfcp_wka_port *wka_port)
static void zfcp_fc_wka_port_offline(struct work_struct *work)
{
struct delayed_work *dw = to_delayed_work(work);
- struct zfcp_wka_port *wka_port =
- container_of(dw, struct zfcp_wka_port, work);
+ struct zfcp_fc_wka_port *wka_port =
+ container_of(dw, struct zfcp_fc_wka_port, work);
mutex_lock(&wka_port->mutex);
if ((atomic_read(&wka_port->refcount) != 0) ||
- (wka_port->status != ZFCP_WKA_PORT_ONLINE))
+ (wka_port->status != ZFCP_FC_WKA_PORT_ONLINE))
goto out;
- wka_port->status = ZFCP_WKA_PORT_CLOSING;
+ wka_port->status = ZFCP_FC_WKA_PORT_CLOSING;
if (zfcp_fsf_close_wka_port(wka_port)) {
- wka_port->status = ZFCP_WKA_PORT_OFFLINE;
+ wka_port->status = ZFCP_FC_WKA_PORT_OFFLINE;
wake_up(&wka_port->completion_wq);
}
out:
mutex_unlock(&wka_port->mutex);
}
-static void zfcp_fc_wka_port_put(struct zfcp_wka_port *wka_port)
+static void zfcp_fc_wka_port_put(struct zfcp_fc_wka_port *wka_port)
{
if (atomic_dec_return(&wka_port->refcount) != 0)
return;
@@ -110,7 +75,7 @@ static void zfcp_fc_wka_port_put(struct zfcp_wka_port *wka_port)
schedule_delayed_work(&wka_port->work, HZ / 100);
}
-static void zfcp_fc_wka_port_init(struct zfcp_wka_port *wka_port, u32 d_id,
+static void zfcp_fc_wka_port_init(struct zfcp_fc_wka_port *wka_port, u32 d_id,
struct zfcp_adapter *adapter)
{
init_waitqueue_head(&wka_port->completion_wq);
@@ -118,107 +83,107 @@ static void zfcp_fc_wka_port_init(struct zfcp_wka_port *wka_port, u32 d_id,
wka_port->adapter = adapter;
wka_port->d_id = d_id;
- wka_port->status = ZFCP_WKA_PORT_OFFLINE;
+ wka_port->status = ZFCP_FC_WKA_PORT_OFFLINE;
atomic_set(&wka_port->refcount, 0);
mutex_init(&wka_port->mutex);
INIT_DELAYED_WORK(&wka_port->work, zfcp_fc_wka_port_offline);
}
-static void zfcp_fc_wka_port_force_offline(struct zfcp_wka_port *wka)
+static void zfcp_fc_wka_port_force_offline(struct zfcp_fc_wka_port *wka)
{
cancel_delayed_work_sync(&wka->work);
mutex_lock(&wka->mutex);
- wka->status = ZFCP_WKA_PORT_OFFLINE;
+ wka->status = ZFCP_FC_WKA_PORT_OFFLINE;
mutex_unlock(&wka->mutex);
}
-void zfcp_fc_wka_ports_force_offline(struct zfcp_wka_ports *gs)
+void zfcp_fc_wka_ports_force_offline(struct zfcp_fc_wka_ports *gs)
{
+ if (!gs)
+ return;
zfcp_fc_wka_port_force_offline(&gs->ms);
zfcp_fc_wka_port_force_offline(&gs->ts);
zfcp_fc_wka_port_force_offline(&gs->ds);
zfcp_fc_wka_port_force_offline(&gs->as);
- zfcp_fc_wka_port_force_offline(&gs->ks);
}
static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range,
- struct fcp_rscn_element *elem)
+ struct fc_els_rscn_page *page)
{
unsigned long flags;
+ struct zfcp_adapter *adapter = fsf_req->adapter;
struct zfcp_port *port;
- read_lock_irqsave(&zfcp_data.config_lock, flags);
- list_for_each_entry(port, &fsf_req->adapter->port_list_head, list) {
- if ((port->d_id & range) == (elem->nport_did & range))
+ read_lock_irqsave(&adapter->port_list_lock, flags);
+ list_for_each_entry(port, &adapter->port_list, list) {
+ if ((port->d_id & range) == (ntoh24(page->rscn_fid) & range))
zfcp_fc_test_link(port);
if (!port->d_id)
zfcp_erp_port_reopen(port,
ZFCP_STATUS_COMMON_ERP_FAILED,
"fcrscn1", NULL);
}
-
- read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+ read_unlock_irqrestore(&adapter->port_list_lock, flags);
}
static void zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req)
{
struct fsf_status_read_buffer *status_buffer = (void *)fsf_req->data;
- struct fcp_rscn_head *fcp_rscn_head;
- struct fcp_rscn_element *fcp_rscn_element;
+ struct fc_els_rscn *head;
+ struct fc_els_rscn_page *page;
u16 i;
u16 no_entries;
- u32 range_mask;
+ unsigned int afmt;
- fcp_rscn_head = (struct fcp_rscn_head *) status_buffer->payload.data;
- fcp_rscn_element = (struct fcp_rscn_element *) fcp_rscn_head;
+ head = (struct fc_els_rscn *) status_buffer->payload.data;
+ page = (struct fc_els_rscn_page *) head;
/* see FC-FS */
- no_entries = fcp_rscn_head->payload_len /
- sizeof(struct fcp_rscn_element);
+ no_entries = head->rscn_plen / sizeof(struct fc_els_rscn_page);
for (i = 1; i < no_entries; i++) {
/* skip head and start with 1st element */
- fcp_rscn_element++;
- range_mask = rscn_range_mask[fcp_rscn_element->addr_format];
- _zfcp_fc_incoming_rscn(fsf_req, range_mask, fcp_rscn_element);
+ page++;
+ afmt = page->rscn_page_flags & ELS_RSCN_ADDR_FMT_MASK;
+ _zfcp_fc_incoming_rscn(fsf_req, zfcp_fc_rscn_range_mask[afmt],
+ page);
}
- schedule_work(&fsf_req->adapter->scan_work);
+ queue_work(fsf_req->adapter->work_queue, &fsf_req->adapter->scan_work);
}
static void zfcp_fc_incoming_wwpn(struct zfcp_fsf_req *req, u64 wwpn)
{
+ unsigned long flags;
struct zfcp_adapter *adapter = req->adapter;
struct zfcp_port *port;
- unsigned long flags;
- read_lock_irqsave(&zfcp_data.config_lock, flags);
- list_for_each_entry(port, &adapter->port_list_head, list)
- if (port->wwpn == wwpn)
+ read_lock_irqsave(&adapter->port_list_lock, flags);
+ list_for_each_entry(port, &adapter->port_list, list)
+ if (port->wwpn == wwpn) {
+ zfcp_erp_port_forced_reopen(port, 0, "fciwwp1", req);
break;
- read_unlock_irqrestore(&zfcp_data.config_lock, flags);
-
- if (port && (port->wwpn == wwpn))
- zfcp_erp_port_forced_reopen(port, 0, "fciwwp1", req);
+ }
+ read_unlock_irqrestore(&adapter->port_list_lock, flags);
}
static void zfcp_fc_incoming_plogi(struct zfcp_fsf_req *req)
{
- struct fsf_status_read_buffer *status_buffer =
- (struct fsf_status_read_buffer *)req->data;
- struct fsf_plogi *els_plogi =
- (struct fsf_plogi *) status_buffer->payload.data;
+ struct fsf_status_read_buffer *status_buffer;
+ struct fc_els_flogi *plogi;
- zfcp_fc_incoming_wwpn(req, els_plogi->serv_param.wwpn);
+ status_buffer = (struct fsf_status_read_buffer *) req->data;
+ plogi = (struct fc_els_flogi *) status_buffer->payload.data;
+ zfcp_fc_incoming_wwpn(req, plogi->fl_wwpn);
}
static void zfcp_fc_incoming_logo(struct zfcp_fsf_req *req)
{
struct fsf_status_read_buffer *status_buffer =
(struct fsf_status_read_buffer *)req->data;
- struct fcp_logo *els_logo =
- (struct fcp_logo *) status_buffer->payload.data;
+ struct fc_els_logo *logo =
+ (struct fc_els_logo *) status_buffer->payload.data;
- zfcp_fc_incoming_wwpn(req, els_logo->nport_wwpn);
+ zfcp_fc_incoming_wwpn(req, logo->fl_n_port_wwn);
}
/**
@@ -232,79 +197,72 @@ void zfcp_fc_incoming_els(struct zfcp_fsf_req *fsf_req)
unsigned int els_type = status_buffer->payload.data[0];
zfcp_dbf_san_incoming_els(fsf_req);
- if (els_type == LS_PLOGI)
+ if (els_type == ELS_PLOGI)
zfcp_fc_incoming_plogi(fsf_req);
- else if (els_type == LS_LOGO)
+ else if (els_type == ELS_LOGO)
zfcp_fc_incoming_logo(fsf_req);
- else if (els_type == LS_RSCN)
+ else if (els_type == ELS_RSCN)
zfcp_fc_incoming_rscn(fsf_req);
}
-static void zfcp_fc_ns_handler(unsigned long data)
+static void zfcp_fc_ns_gid_pn_eval(void *data)
{
- struct zfcp_fc_ns_handler_data *compl_rec =
- (struct zfcp_fc_ns_handler_data *) data;
-
- if (compl_rec->handler)
- compl_rec->handler(compl_rec->handler_data);
-
- complete(&compl_rec->done);
-}
-
-static void zfcp_fc_ns_gid_pn_eval(unsigned long data)
-{
- struct zfcp_gid_pn_data *gid_pn = (struct zfcp_gid_pn_data *) data;
- struct zfcp_send_ct *ct = &gid_pn->ct;
- struct ct_iu_gid_pn_req *ct_iu_req = sg_virt(ct->req);
- struct ct_iu_gid_pn_resp *ct_iu_resp = sg_virt(ct->resp);
+ struct zfcp_fc_gid_pn *gid_pn = data;
+ struct zfcp_fsf_ct_els *ct = &gid_pn->ct;
+ struct zfcp_fc_gid_pn_req *gid_pn_req = sg_virt(ct->req);
+ struct zfcp_fc_gid_pn_resp *gid_pn_resp = sg_virt(ct->resp);
struct zfcp_port *port = gid_pn->port;
if (ct->status)
return;
- if (ct_iu_resp->header.cmd_rsp_code != ZFCP_CT_ACCEPT)
+ if (gid_pn_resp->ct_hdr.ct_cmd != FC_FS_ACC)
return;
/* paranoia */
- if (ct_iu_req->wwpn != port->wwpn)
+ if (gid_pn_req->gid_pn.fn_wwpn != port->wwpn)
return;
/* looks like a valid d_id */
- port->d_id = ct_iu_resp->d_id & ZFCP_DID_MASK;
+ port->d_id = ntoh24(gid_pn_resp->gid_pn.fp_fid);
+}
+
+static void zfcp_fc_complete(void *data)
+{
+ complete(data);
}
static int zfcp_fc_ns_gid_pn_request(struct zfcp_port *port,
- struct zfcp_gid_pn_data *gid_pn)
+ struct zfcp_fc_gid_pn *gid_pn)
{
struct zfcp_adapter *adapter = port->adapter;
- struct zfcp_fc_ns_handler_data compl_rec;
+ DECLARE_COMPLETION_ONSTACK(completion);
int ret;
/* setup parameters for send generic command */
gid_pn->port = port;
- gid_pn->ct.wka_port = &adapter->gs->ds;
- gid_pn->ct.handler = zfcp_fc_ns_handler;
- gid_pn->ct.handler_data = (unsigned long) &compl_rec;
- gid_pn->ct.req = &gid_pn->req;
- gid_pn->ct.resp = &gid_pn->resp;
- sg_init_one(&gid_pn->req, &gid_pn->ct_iu_req,
- sizeof(struct ct_iu_gid_pn_req));
- sg_init_one(&gid_pn->resp, &gid_pn->ct_iu_resp,
- sizeof(struct ct_iu_gid_pn_resp));
+ gid_pn->ct.handler = zfcp_fc_complete;
+ gid_pn->ct.handler_data = &completion;
+ gid_pn->ct.req = &gid_pn->sg_req;
+ gid_pn->ct.resp = &gid_pn->sg_resp;
+ sg_init_one(&gid_pn->sg_req, &gid_pn->gid_pn_req,
+ sizeof(struct zfcp_fc_gid_pn_req));
+ sg_init_one(&gid_pn->sg_resp, &gid_pn->gid_pn_resp,
+ sizeof(struct zfcp_fc_gid_pn_resp));
/* setup nameserver request */
- gid_pn->ct_iu_req.header.revision = ZFCP_CT_REVISION;
- gid_pn->ct_iu_req.header.gs_type = ZFCP_CT_DIRECTORY_SERVICE;
- gid_pn->ct_iu_req.header.gs_subtype = ZFCP_CT_NAME_SERVER;
- gid_pn->ct_iu_req.header.options = ZFCP_CT_SYNCHRONOUS;
- gid_pn->ct_iu_req.header.cmd_rsp_code = ZFCP_CT_GID_PN;
- gid_pn->ct_iu_req.header.max_res_size = ZFCP_CT_SIZE_ONE_PAGE / 4;
- gid_pn->ct_iu_req.wwpn = port->wwpn;
-
- init_completion(&compl_rec.done);
- compl_rec.handler = zfcp_fc_ns_gid_pn_eval;
- compl_rec.handler_data = (unsigned long) gid_pn;
- ret = zfcp_fsf_send_ct(&gid_pn->ct, adapter->pool.gid_pn_req);
- if (!ret)
- wait_for_completion(&compl_rec.done);
+ gid_pn->gid_pn_req.ct_hdr.ct_rev = FC_CT_REV;
+ gid_pn->gid_pn_req.ct_hdr.ct_fs_type = FC_FST_DIR;
+ gid_pn->gid_pn_req.ct_hdr.ct_fs_subtype = FC_NS_SUBTYPE;
+ gid_pn->gid_pn_req.ct_hdr.ct_options = 0;
+ gid_pn->gid_pn_req.ct_hdr.ct_cmd = FC_NS_GID_PN;
+ gid_pn->gid_pn_req.ct_hdr.ct_mr_size = ZFCP_FC_CT_SIZE_PAGE / 4;
+ gid_pn->gid_pn_req.gid_pn.fn_wwpn = port->wwpn;
+
+ ret = zfcp_fsf_send_ct(&adapter->gs->ds, &gid_pn->ct,
+ adapter->pool.gid_pn_req);
+ if (!ret) {
+ wait_for_completion(&completion);
+ zfcp_fc_ns_gid_pn_eval(gid_pn);
+ }
return ret;
}
@@ -316,10 +274,10 @@ static int zfcp_fc_ns_gid_pn_request(struct zfcp_port *port,
static int zfcp_fc_ns_gid_pn(struct zfcp_port *port)
{
int ret;
- struct zfcp_gid_pn_data *gid_pn;
+ struct zfcp_fc_gid_pn *gid_pn;
struct zfcp_adapter *adapter = port->adapter;
- gid_pn = mempool_alloc(adapter->pool.gid_pn_data, GFP_ATOMIC);
+ gid_pn = mempool_alloc(adapter->pool.gid_pn, GFP_ATOMIC);
if (!gid_pn)
return -ENOMEM;
@@ -333,7 +291,7 @@ static int zfcp_fc_ns_gid_pn(struct zfcp_port *port)
zfcp_fc_wka_port_put(&adapter->gs->ds);
out:
- mempool_free(gid_pn, adapter->pool.gid_pn_data);
+ mempool_free(gid_pn, adapter->pool.gid_pn);
return ret;
}
@@ -357,7 +315,7 @@ void zfcp_fc_port_did_lookup(struct work_struct *work)
zfcp_erp_port_reopen(port, 0, "fcgpn_3", NULL);
out:
- zfcp_port_put(port);
+ put_device(&port->sysfs_device);
}
/**
@@ -366,9 +324,9 @@ out:
*/
void zfcp_fc_trigger_did_lookup(struct zfcp_port *port)
{
- zfcp_port_get(port);
+ get_device(&port->sysfs_device);
if (!queue_work(port->adapter->work_queue, &port->gid_pn_work))
- zfcp_port_put(port);
+ put_device(&port->sysfs_device);
}
/**
@@ -378,33 +336,36 @@ void zfcp_fc_trigger_did_lookup(struct zfcp_port *port)
*
* Evaluate PLOGI playload and copy important fields into zfcp_port structure
*/
-void zfcp_fc_plogi_evaluate(struct zfcp_port *port, struct fsf_plogi *plogi)
-{
- port->maxframe_size = plogi->serv_param.common_serv_param[7] |
- ((plogi->serv_param.common_serv_param[6] & 0x0F) << 8);
- if (plogi->serv_param.class1_serv_param[0] & 0x80)
+void zfcp_fc_plogi_evaluate(struct zfcp_port *port, struct fc_els_flogi *plogi)
+{
+ if (plogi->fl_wwpn != port->wwpn) {
+ port->d_id = 0;
+ dev_warn(&port->adapter->ccw_device->dev,
+ "A port opened with WWPN 0x%016Lx returned data that "
+ "identifies it as WWPN 0x%016Lx\n",
+ (unsigned long long) port->wwpn,
+ (unsigned long long) plogi->fl_wwpn);
+ return;
+ }
+
+ port->wwnn = plogi->fl_wwnn;
+ port->maxframe_size = plogi->fl_csp.sp_bb_data;
+
+ if (plogi->fl_cssp[0].cp_class & FC_CPC_VALID)
port->supported_classes |= FC_COS_CLASS1;
- if (plogi->serv_param.class2_serv_param[0] & 0x80)
+ if (plogi->fl_cssp[1].cp_class & FC_CPC_VALID)
port->supported_classes |= FC_COS_CLASS2;
- if (plogi->serv_param.class3_serv_param[0] & 0x80)
+ if (plogi->fl_cssp[2].cp_class & FC_CPC_VALID)
port->supported_classes |= FC_COS_CLASS3;
- if (plogi->serv_param.class4_serv_param[0] & 0x80)
+ if (plogi->fl_cssp[3].cp_class & FC_CPC_VALID)
port->supported_classes |= FC_COS_CLASS4;
}
-struct zfcp_els_adisc {
- struct zfcp_send_els els;
- struct scatterlist req;
- struct scatterlist resp;
- struct zfcp_ls_adisc ls_adisc;
- struct zfcp_ls_adisc ls_adisc_acc;
-};
-
-static void zfcp_fc_adisc_handler(unsigned long data)
+static void zfcp_fc_adisc_handler(void *data)
{
- struct zfcp_els_adisc *adisc = (struct zfcp_els_adisc *) data;
+ struct zfcp_fc_els_adisc *adisc = data;
struct zfcp_port *port = adisc->els.port;
- struct zfcp_ls_adisc *ls_adisc = &adisc->ls_adisc_acc;
+ struct fc_els_adisc *adisc_resp = &adisc->adisc_resp;
if (adisc->els.status) {
/* request rejected or timed out */
@@ -414,9 +375,9 @@ static void zfcp_fc_adisc_handler(unsigned long data)
}
if (!port->wwnn)
- port->wwnn = ls_adisc->wwnn;
+ port->wwnn = adisc_resp->adisc_wwnn;
- if ((port->wwpn != ls_adisc->wwpn) ||
+ if ((port->wwpn != adisc_resp->adisc_wwpn) ||
!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN)) {
zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED,
"fcadh_2", NULL);
@@ -427,40 +388,44 @@ static void zfcp_fc_adisc_handler(unsigned long data)
zfcp_scsi_schedule_rport_register(port);
out:
atomic_clear_mask(ZFCP_STATUS_PORT_LINK_TEST, &port->status);
- zfcp_port_put(port);
- kfree(adisc);
+ put_device(&port->sysfs_device);
+ kmem_cache_free(zfcp_data.adisc_cache, adisc);
}
static int zfcp_fc_adisc(struct zfcp_port *port)
{
- struct zfcp_els_adisc *adisc;
+ struct zfcp_fc_els_adisc *adisc;
struct zfcp_adapter *adapter = port->adapter;
+ int ret;
- adisc = kzalloc(sizeof(struct zfcp_els_adisc), GFP_ATOMIC);
+ adisc = kmem_cache_alloc(zfcp_data.adisc_cache, GFP_ATOMIC);
if (!adisc)
return -ENOMEM;
+ adisc->els.port = port;
adisc->els.req = &adisc->req;
adisc->els.resp = &adisc->resp;
- sg_init_one(adisc->els.req, &adisc->ls_adisc,
- sizeof(struct zfcp_ls_adisc));
- sg_init_one(adisc->els.resp, &adisc->ls_adisc_acc,
- sizeof(struct zfcp_ls_adisc));
+ sg_init_one(adisc->els.req, &adisc->adisc_req,
+ sizeof(struct fc_els_adisc));
+ sg_init_one(adisc->els.resp, &adisc->adisc_resp,
+ sizeof(struct fc_els_adisc));
- adisc->els.adapter = adapter;
- adisc->els.port = port;
- adisc->els.d_id = port->d_id;
adisc->els.handler = zfcp_fc_adisc_handler;
- adisc->els.handler_data = (unsigned long) adisc;
- adisc->els.ls_code = adisc->ls_adisc.code = ZFCP_LS_ADISC;
+ adisc->els.handler_data = adisc;
/* acc. to FC-FS, hard_nport_id in ADISC should not be set for ports
without FC-AL-2 capability, so we don't set it */
- adisc->ls_adisc.wwpn = fc_host_port_name(adapter->scsi_host);
- adisc->ls_adisc.wwnn = fc_host_node_name(adapter->scsi_host);
- adisc->ls_adisc.nport_id = fc_host_port_id(adapter->scsi_host);
+ adisc->adisc_req.adisc_wwpn = fc_host_port_name(adapter->scsi_host);
+ adisc->adisc_req.adisc_wwnn = fc_host_node_name(adapter->scsi_host);
+ adisc->adisc_req.adisc_cmd = ELS_ADISC;
+ hton24(adisc->adisc_req.adisc_port_id,
+ fc_host_port_id(adapter->scsi_host));
+
+ ret = zfcp_fsf_send_els(adapter, port->d_id, &adisc->els);
+ if (ret)
+ kmem_cache_free(zfcp_data.adisc_cache, adisc);
- return zfcp_fsf_send_els(&adisc->els);
+ return ret;
}
void zfcp_fc_link_test_work(struct work_struct *work)
@@ -469,7 +434,7 @@ void zfcp_fc_link_test_work(struct work_struct *work)
container_of(work, struct zfcp_port, test_link_work);
int retval;
- zfcp_port_get(port);
+ get_device(&port->sysfs_device);
port->rport_task = RPORT_DEL;
zfcp_scsi_rport_work(&port->rport_work);
@@ -488,7 +453,7 @@ void zfcp_fc_link_test_work(struct work_struct *work)
zfcp_erp_port_forced_reopen(port, 0, "fcltwk1", NULL);
out:
- zfcp_port_put(port);
+ put_device(&port->sysfs_device);
}
/**
@@ -501,12 +466,12 @@ out:
*/
void zfcp_fc_test_link(struct zfcp_port *port)
{
- zfcp_port_get(port);
+ get_device(&port->sysfs_device);
if (!queue_work(port->adapter->work_queue, &port->test_link_work))
- zfcp_port_put(port);
+ put_device(&port->sysfs_device);
}
-static void zfcp_free_sg_env(struct zfcp_gpn_ft *gpn_ft, int buf_num)
+static void zfcp_free_sg_env(struct zfcp_fc_gpn_ft *gpn_ft, int buf_num)
{
struct scatterlist *sg = &gpn_ft->sg_req;
@@ -516,10 +481,10 @@ static void zfcp_free_sg_env(struct zfcp_gpn_ft *gpn_ft, int buf_num)
kfree(gpn_ft);
}
-static struct zfcp_gpn_ft *zfcp_alloc_sg_env(int buf_num)
+static struct zfcp_fc_gpn_ft *zfcp_alloc_sg_env(int buf_num)
{
- struct zfcp_gpn_ft *gpn_ft;
- struct ct_iu_gpn_ft_req *req;
+ struct zfcp_fc_gpn_ft *gpn_ft;
+ struct zfcp_fc_gpn_ft_req *req;
gpn_ft = kzalloc(sizeof(*gpn_ft), GFP_KERNEL);
if (!gpn_ft)
@@ -542,159 +507,152 @@ out:
}
-static int zfcp_fc_send_gpn_ft(struct zfcp_gpn_ft *gpn_ft,
+static int zfcp_fc_send_gpn_ft(struct zfcp_fc_gpn_ft *gpn_ft,
struct zfcp_adapter *adapter, int max_bytes)
{
- struct zfcp_send_ct *ct = &gpn_ft->ct;
- struct ct_iu_gpn_ft_req *req = sg_virt(&gpn_ft->sg_req);
- struct zfcp_fc_ns_handler_data compl_rec;
+ struct zfcp_fsf_ct_els *ct = &gpn_ft->ct;
+ struct zfcp_fc_gpn_ft_req *req = sg_virt(&gpn_ft->sg_req);
+ DECLARE_COMPLETION_ONSTACK(completion);
int ret;
/* prepare CT IU for GPN_FT */
- req->header.revision = ZFCP_CT_REVISION;
- req->header.gs_type = ZFCP_CT_DIRECTORY_SERVICE;
- req->header.gs_subtype = ZFCP_CT_NAME_SERVER;
- req->header.options = ZFCP_CT_SYNCHRONOUS;
- req->header.cmd_rsp_code = ZFCP_CT_GPN_FT;
- req->header.max_res_size = max_bytes / 4;
- req->flags = 0;
- req->domain_id_scope = 0;
- req->area_id_scope = 0;
- req->fc4_type = ZFCP_CT_SCSI_FCP;
+ req->ct_hdr.ct_rev = FC_CT_REV;
+ req->ct_hdr.ct_fs_type = FC_FST_DIR;
+ req->ct_hdr.ct_fs_subtype = FC_NS_SUBTYPE;
+ req->ct_hdr.ct_options = 0;
+ req->ct_hdr.ct_cmd = FC_NS_GPN_FT;
+ req->ct_hdr.ct_mr_size = max_bytes / 4;
+ req->gpn_ft.fn_domain_id_scope = 0;
+ req->gpn_ft.fn_area_id_scope = 0;
+ req->gpn_ft.fn_fc4_type = FC_TYPE_FCP;
/* prepare zfcp_send_ct */
- ct->wka_port = &adapter->gs->ds;
- ct->handler = zfcp_fc_ns_handler;
- ct->handler_data = (unsigned long)&compl_rec;
+ ct->handler = zfcp_fc_complete;
+ ct->handler_data = &completion;
ct->req = &gpn_ft->sg_req;
ct->resp = gpn_ft->sg_resp;
- init_completion(&compl_rec.done);
- compl_rec.handler = NULL;
- ret = zfcp_fsf_send_ct(ct, NULL);
+ ret = zfcp_fsf_send_ct(&adapter->gs->ds, ct, NULL);
if (!ret)
- wait_for_completion(&compl_rec.done);
+ wait_for_completion(&completion);
return ret;
}
-static void zfcp_fc_validate_port(struct zfcp_port *port)
+static void zfcp_fc_validate_port(struct zfcp_port *port, struct list_head *lh)
{
- struct zfcp_adapter *adapter = port->adapter;
-
if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC))
return;
atomic_clear_mask(ZFCP_STATUS_COMMON_NOESC, &port->status);
if ((port->supported_classes != 0) ||
- !list_empty(&port->unit_list_head)) {
- zfcp_port_put(port);
+ !list_empty(&port->unit_list))
return;
- }
- zfcp_erp_port_shutdown(port, 0, "fcpval1", NULL);
- zfcp_erp_wait(adapter);
- zfcp_port_put(port);
- zfcp_port_dequeue(port);
+
+ list_move_tail(&port->list, lh);
}
-static int zfcp_fc_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries)
+static int zfcp_fc_eval_gpn_ft(struct zfcp_fc_gpn_ft *gpn_ft,
+ struct zfcp_adapter *adapter, int max_entries)
{
- struct zfcp_send_ct *ct = &gpn_ft->ct;
+ struct zfcp_fsf_ct_els *ct = &gpn_ft->ct;
struct scatterlist *sg = gpn_ft->sg_resp;
- struct ct_hdr *hdr = sg_virt(sg);
- struct gpn_ft_resp_acc *acc = sg_virt(sg);
- struct zfcp_adapter *adapter = ct->wka_port->adapter;
+ struct fc_ct_hdr *hdr = sg_virt(sg);
+ struct fc_gpn_ft_resp *acc = sg_virt(sg);
struct zfcp_port *port, *tmp;
+ unsigned long flags;
+ LIST_HEAD(remove_lh);
u32 d_id;
int ret = 0, x, last = 0;
if (ct->status)
return -EIO;
- if (hdr->cmd_rsp_code != ZFCP_CT_ACCEPT) {
- if (hdr->reason_code == ZFCP_CT_UNABLE_TO_PERFORM_CMD)
+ if (hdr->ct_cmd != FC_FS_ACC) {
+ if (hdr->ct_reason == FC_BA_RJT_UNABLE)
return -EAGAIN; /* might be a temporary condition */
return -EIO;
}
- if (hdr->max_res_size) {
+ if (hdr->ct_mr_size) {
dev_warn(&adapter->ccw_device->dev,
"The name server reported %d words residual data\n",
- hdr->max_res_size);
+ hdr->ct_mr_size);
return -E2BIG;
}
- mutex_lock(&zfcp_data.config_mutex);
-
/* first entry is the header */
for (x = 1; x < max_entries && !last; x++) {
- if (x % (ZFCP_GPN_FT_ENTRIES + 1))
+ if (x % (ZFCP_FC_GPN_FT_ENT_PAGE + 1))
acc++;
else
acc = sg_virt(++sg);
- last = acc->control & 0x80;
- d_id = acc->port_id[0] << 16 | acc->port_id[1] << 8 |
- acc->port_id[2];
+ last = acc->fp_flags & FC_NS_FID_LAST;
+ d_id = ntoh24(acc->fp_fid);
/* don't attach ports with a well known address */
- if ((d_id & ZFCP_DID_WKA) == ZFCP_DID_WKA)
+ if (d_id >= FC_FID_WELL_KNOWN_BASE)
continue;
/* skip the adapter's port and known remote ports */
- if (acc->wwpn == fc_host_port_name(adapter->scsi_host))
- continue;
- port = zfcp_get_port_by_wwpn(adapter, acc->wwpn);
- if (port)
+ if (acc->fp_wwpn == fc_host_port_name(adapter->scsi_host))
continue;
- port = zfcp_port_enqueue(adapter, acc->wwpn,
+ port = zfcp_port_enqueue(adapter, acc->fp_wwpn,
ZFCP_STATUS_COMMON_NOESC, d_id);
- if (IS_ERR(port))
- ret = PTR_ERR(port);
- else
+ if (!IS_ERR(port))
zfcp_erp_port_reopen(port, 0, "fcegpf1", NULL);
+ else if (PTR_ERR(port) != -EEXIST)
+ ret = PTR_ERR(port);
}
zfcp_erp_wait(adapter);
- list_for_each_entry_safe(port, tmp, &adapter->port_list_head, list)
- zfcp_fc_validate_port(port);
- mutex_unlock(&zfcp_data.config_mutex);
+ write_lock_irqsave(&adapter->port_list_lock, flags);
+ list_for_each_entry_safe(port, tmp, &adapter->port_list, list)
+ zfcp_fc_validate_port(port, &remove_lh);
+ write_unlock_irqrestore(&adapter->port_list_lock, flags);
+
+ list_for_each_entry_safe(port, tmp, &remove_lh, list) {
+ zfcp_erp_port_shutdown(port, 0, "fcegpf2", NULL);
+ zfcp_device_unregister(&port->sysfs_device,
+ &zfcp_sysfs_port_attrs);
+ }
+
return ret;
}
/**
* zfcp_fc_scan_ports - scan remote ports and attach new ports
- * @adapter: pointer to struct zfcp_adapter
+ * @work: reference to scheduled work
*/
-int zfcp_fc_scan_ports(struct zfcp_adapter *adapter)
+void zfcp_fc_scan_ports(struct work_struct *work)
{
+ struct zfcp_adapter *adapter = container_of(work, struct zfcp_adapter,
+ scan_work);
int ret, i;
- struct zfcp_gpn_ft *gpn_ft;
+ struct zfcp_fc_gpn_ft *gpn_ft;
int chain, max_entries, buf_num, max_bytes;
chain = adapter->adapter_features & FSF_FEATURE_ELS_CT_CHAINED_SBALS;
- buf_num = chain ? ZFCP_GPN_FT_BUFFERS : 1;
- max_entries = chain ? ZFCP_GPN_FT_MAX_ENTRIES : ZFCP_GPN_FT_ENTRIES;
- max_bytes = chain ? ZFCP_GPN_FT_MAX_SIZE : ZFCP_CT_SIZE_ONE_PAGE;
+ buf_num = chain ? ZFCP_FC_GPN_FT_NUM_BUFS : 1;
+ max_entries = chain ? ZFCP_FC_GPN_FT_MAX_ENT : ZFCP_FC_GPN_FT_ENT_PAGE;
+ max_bytes = chain ? ZFCP_FC_GPN_FT_MAX_SIZE : ZFCP_FC_CT_SIZE_PAGE;
if (fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPORT &&
fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPIV)
- return 0;
+ return;
- ret = zfcp_fc_wka_port_get(&adapter->gs->ds);
- if (ret)
- return ret;
+ if (zfcp_fc_wka_port_get(&adapter->gs->ds))
+ return;
gpn_ft = zfcp_alloc_sg_env(buf_num);
- if (!gpn_ft) {
- ret = -ENOMEM;
+ if (!gpn_ft)
goto out;
- }
for (i = 0; i < 3; i++) {
ret = zfcp_fc_send_gpn_ft(gpn_ft, adapter, max_bytes);
if (!ret) {
- ret = zfcp_fc_eval_gpn_ft(gpn_ft, max_entries);
+ ret = zfcp_fc_eval_gpn_ft(gpn_ft, adapter, max_entries);
if (ret == -EAGAIN)
ssleep(1);
else
@@ -704,174 +662,116 @@ int zfcp_fc_scan_ports(struct zfcp_adapter *adapter)
zfcp_free_sg_env(gpn_ft, buf_num);
out:
zfcp_fc_wka_port_put(&adapter->gs->ds);
- return ret;
-}
-
-
-void _zfcp_fc_scan_ports_later(struct work_struct *work)
-{
- zfcp_fc_scan_ports(container_of(work, struct zfcp_adapter, scan_work));
}
-struct zfcp_els_fc_job {
- struct zfcp_send_els els;
- struct fc_bsg_job *job;
-};
-
-static void zfcp_fc_generic_els_handler(unsigned long data)
+static void zfcp_fc_ct_els_job_handler(void *data)
{
- struct zfcp_els_fc_job *els_fc_job = (struct zfcp_els_fc_job *) data;
- struct fc_bsg_job *job = els_fc_job->job;
- struct fc_bsg_reply *reply = job->reply;
-
- if (els_fc_job->els.status) {
- /* request rejected or timed out */
- reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_REJECT;
- goto out;
- }
-
- reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_OK;
- reply->reply_payload_rcv_len = job->reply_payload.payload_len;
+ struct fc_bsg_job *job = data;
+ struct zfcp_fsf_ct_els *zfcp_ct_els = job->dd_data;
+ int status = zfcp_ct_els->status;
+ int reply_status;
-out:
- job->state_flags = FC_RQST_STATE_DONE;
+ reply_status = status ? FC_CTELS_STATUS_REJECT : FC_CTELS_STATUS_OK;
+ job->reply->reply_data.ctels_reply.status = reply_status;
+ job->reply->reply_payload_rcv_len = job->reply_payload.payload_len;
job->job_done(job);
- kfree(els_fc_job);
}
-int zfcp_fc_execute_els_fc_job(struct fc_bsg_job *job)
+static int zfcp_fc_exec_els_job(struct fc_bsg_job *job,
+ struct zfcp_adapter *adapter)
{
- struct zfcp_els_fc_job *els_fc_job;
+ struct zfcp_fsf_ct_els *els = job->dd_data;
struct fc_rport *rport = job->rport;
- struct Scsi_Host *shost;
- struct zfcp_adapter *adapter;
struct zfcp_port *port;
- u8 *port_did;
-
- shost = rport ? rport_to_shost(rport) : job->shost;
- adapter = (struct zfcp_adapter *)shost->hostdata[0];
-
- if (!(atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_OPEN))
- return -EINVAL;
-
- els_fc_job = kzalloc(sizeof(struct zfcp_els_fc_job), GFP_KERNEL);
- if (!els_fc_job)
- return -ENOMEM;
+ u32 d_id;
- els_fc_job->els.adapter = adapter;
if (rport) {
- read_lock_irq(&zfcp_data.config_lock);
port = zfcp_get_port_by_wwpn(adapter, rport->port_name);
- if (port)
- els_fc_job->els.d_id = port->d_id;
- read_unlock_irq(&zfcp_data.config_lock);
- if (!port) {
- kfree(els_fc_job);
+ if (!port)
return -EINVAL;
- }
- } else {
- port_did = job->request->rqst_data.h_els.port_id;
- els_fc_job->els.d_id = (port_did[0] << 16) +
- (port_did[1] << 8) + port_did[2];
- }
-
- els_fc_job->els.req = job->request_payload.sg_list;
- els_fc_job->els.resp = job->reply_payload.sg_list;
- els_fc_job->els.handler = zfcp_fc_generic_els_handler;
- els_fc_job->els.handler_data = (unsigned long) els_fc_job;
- els_fc_job->job = job;
-
- return zfcp_fsf_send_els(&els_fc_job->els);
-}
-
-struct zfcp_ct_fc_job {
- struct zfcp_send_ct ct;
- struct fc_bsg_job *job;
-};
-
-static void zfcp_fc_generic_ct_handler(unsigned long data)
-{
- struct zfcp_ct_fc_job *ct_fc_job = (struct zfcp_ct_fc_job *) data;
- struct fc_bsg_job *job = ct_fc_job->job;
-
- job->reply->reply_data.ctels_reply.status = ct_fc_job->ct.status ?
- FC_CTELS_STATUS_REJECT : FC_CTELS_STATUS_OK;
- job->reply->reply_payload_rcv_len = job->reply_payload.payload_len;
- job->state_flags = FC_RQST_STATE_DONE;
- job->job_done(job);
- zfcp_fc_wka_port_put(ct_fc_job->ct.wka_port);
+ d_id = port->d_id;
+ put_device(&port->sysfs_device);
+ } else
+ d_id = ntoh24(job->request->rqst_data.h_els.port_id);
- kfree(ct_fc_job);
+ return zfcp_fsf_send_els(adapter, d_id, els);
}
-int zfcp_fc_execute_ct_fc_job(struct fc_bsg_job *job)
+static int zfcp_fc_exec_ct_job(struct fc_bsg_job *job,
+ struct zfcp_adapter *adapter)
{
int ret;
u8 gs_type;
- struct fc_rport *rport = job->rport;
- struct Scsi_Host *shost;
- struct zfcp_adapter *adapter;
- struct zfcp_ct_fc_job *ct_fc_job;
+ struct zfcp_fsf_ct_els *ct = job->dd_data;
+ struct zfcp_fc_wka_port *wka_port;
u32 preamble_word1;
- shost = rport ? rport_to_shost(rport) : job->shost;
-
- adapter = (struct zfcp_adapter *)shost->hostdata[0];
- if (!(atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_OPEN))
- return -EINVAL;
-
- ct_fc_job = kzalloc(sizeof(struct zfcp_ct_fc_job), GFP_KERNEL);
- if (!ct_fc_job)
- return -ENOMEM;
-
preamble_word1 = job->request->rqst_data.r_ct.preamble_word1;
gs_type = (preamble_word1 & 0xff000000) >> 24;
switch (gs_type) {
case FC_FST_ALIAS:
- ct_fc_job->ct.wka_port = &adapter->gs->as;
+ wka_port = &adapter->gs->as;
break;
case FC_FST_MGMT:
- ct_fc_job->ct.wka_port = &adapter->gs->ms;
+ wka_port = &adapter->gs->ms;
break;
case FC_FST_TIME:
- ct_fc_job->ct.wka_port = &adapter->gs->ts;
+ wka_port = &adapter->gs->ts;
break;
case FC_FST_DIR:
- ct_fc_job->ct.wka_port = &adapter->gs->ds;
+ wka_port = &adapter->gs->ds;
break;
default:
- kfree(ct_fc_job);
return -EINVAL; /* no such service */
}
- ret = zfcp_fc_wka_port_get(ct_fc_job->ct.wka_port);
- if (ret) {
- kfree(ct_fc_job);
+ ret = zfcp_fc_wka_port_get(wka_port);
+ if (ret)
return ret;
- }
- ct_fc_job->ct.req = job->request_payload.sg_list;
- ct_fc_job->ct.resp = job->reply_payload.sg_list;
- ct_fc_job->ct.handler = zfcp_fc_generic_ct_handler;
- ct_fc_job->ct.handler_data = (unsigned long) ct_fc_job;
- ct_fc_job->ct.completion = NULL;
- ct_fc_job->job = job;
+ ret = zfcp_fsf_send_ct(wka_port, ct, NULL);
+ if (ret)
+ zfcp_fc_wka_port_put(wka_port);
- ret = zfcp_fsf_send_ct(&ct_fc_job->ct, NULL);
- if (ret) {
- kfree(ct_fc_job);
- zfcp_fc_wka_port_put(ct_fc_job->ct.wka_port);
- }
return ret;
}
+int zfcp_fc_exec_bsg_job(struct fc_bsg_job *job)
+{
+ struct Scsi_Host *shost;
+ struct zfcp_adapter *adapter;
+ struct zfcp_fsf_ct_els *ct_els = job->dd_data;
+
+ shost = job->rport ? rport_to_shost(job->rport) : job->shost;
+ adapter = (struct zfcp_adapter *)shost->hostdata[0];
+
+ if (!(atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_OPEN))
+ return -EINVAL;
+
+ ct_els->req = job->request_payload.sg_list;
+ ct_els->resp = job->reply_payload.sg_list;
+ ct_els->handler = zfcp_fc_ct_els_job_handler;
+ ct_els->handler_data = job;
+
+ switch (job->request->msgcode) {
+ case FC_BSG_RPT_ELS:
+ case FC_BSG_HST_ELS_NOLOGIN:
+ return zfcp_fc_exec_els_job(job, adapter);
+ case FC_BSG_RPT_CT:
+ case FC_BSG_HST_CT:
+ return zfcp_fc_exec_ct_job(job, adapter);
+ default:
+ return -EINVAL;
+ }
+}
+
int zfcp_fc_gs_setup(struct zfcp_adapter *adapter)
{
- struct zfcp_wka_ports *wka_ports;
+ struct zfcp_fc_wka_ports *wka_ports;
- wka_ports = kzalloc(sizeof(struct zfcp_wka_ports), GFP_KERNEL);
+ wka_ports = kzalloc(sizeof(struct zfcp_fc_wka_ports), GFP_KERNEL);
if (!wka_ports)
return -ENOMEM;
@@ -880,7 +780,6 @@ int zfcp_fc_gs_setup(struct zfcp_adapter *adapter)
zfcp_fc_wka_port_init(&wka_ports->ts, FC_FID_TIME_SERV, adapter);
zfcp_fc_wka_port_init(&wka_ports->ds, FC_FID_DIR_SERV, adapter);
zfcp_fc_wka_port_init(&wka_ports->as, FC_FID_ALIASES, adapter);
- zfcp_fc_wka_port_init(&wka_ports->ks, FC_FID_SEC_KEY, adapter);
return 0;
}
diff --git a/drivers/s390/scsi/zfcp_fc.h b/drivers/s390/scsi/zfcp_fc.h
new file mode 100644
index 0000000..cb2a366
--- /dev/null
+++ b/drivers/s390/scsi/zfcp_fc.h
@@ -0,0 +1,260 @@
+/*
+ * zfcp device driver
+ *
+ * Fibre Channel related definitions and inline functions for the zfcp
+ * device driver
+ *
+ * Copyright IBM Corporation 2009
+ */
+
+#ifndef ZFCP_FC_H
+#define ZFCP_FC_H
+
+#include <scsi/fc/fc_els.h>
+#include <scsi/fc/fc_fcp.h>
+#include <scsi/fc/fc_ns.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_tcq.h>
+#include "zfcp_fsf.h"
+
+#define ZFCP_FC_CT_SIZE_PAGE (PAGE_SIZE - sizeof(struct fc_ct_hdr))
+#define ZFCP_FC_GPN_FT_ENT_PAGE (ZFCP_FC_CT_SIZE_PAGE \
+ / sizeof(struct fc_gpn_ft_resp))
+#define ZFCP_FC_GPN_FT_NUM_BUFS 4 /* memory pages */
+
+#define ZFCP_FC_GPN_FT_MAX_SIZE (ZFCP_FC_GPN_FT_NUM_BUFS * PAGE_SIZE \
+ - sizeof(struct fc_ct_hdr))
+#define ZFCP_FC_GPN_FT_MAX_ENT (ZFCP_FC_GPN_FT_NUM_BUFS * \
+ (ZFCP_FC_GPN_FT_ENT_PAGE + 1))
+
+/**
+ * struct zfcp_fc_gid_pn_req - container for ct header plus gid_pn request
+ * @ct_hdr: FC GS common transport header
+ * @gid_pn: GID_PN request
+ */
+struct zfcp_fc_gid_pn_req {
+ struct fc_ct_hdr ct_hdr;
+ struct fc_ns_gid_pn gid_pn;
+} __packed;
+
+/**
+ * struct zfcp_fc_gid_pn_resp - container for ct header plus gid_pn response
+ * @ct_hdr: FC GS common transport header
+ * @gid_pn: GID_PN response
+ */
+struct zfcp_fc_gid_pn_resp {
+ struct fc_ct_hdr ct_hdr;
+ struct fc_gid_pn_resp gid_pn;
+} __packed;
+
+/**
+ * struct zfcp_fc_gid_pn - everything required in zfcp for gid_pn request
+ * @ct: data passed to zfcp_fsf for issuing fsf request
+ * @sg_req: scatterlist entry for request data
+ * @sg_resp: scatterlist entry for response data
+ * @gid_pn_req: GID_PN request data
+ * @gid_pn_resp: GID_PN response data
+ */
+struct zfcp_fc_gid_pn {
+ struct zfcp_fsf_ct_els ct;
+ struct scatterlist sg_req;
+ struct scatterlist sg_resp;
+ struct zfcp_fc_gid_pn_req gid_pn_req;
+ struct zfcp_fc_gid_pn_resp gid_pn_resp;
+ struct zfcp_port *port;
+};
+
+/**
+ * struct zfcp_fc_gpn_ft - container for ct header plus gpn_ft request
+ * @ct_hdr: FC GS common transport header
+ * @gpn_ft: GPN_FT request
+ */
+struct zfcp_fc_gpn_ft_req {
+ struct fc_ct_hdr ct_hdr;
+ struct fc_ns_gid_ft gpn_ft;
+} __packed;
+
+/**
+ * struct zfcp_fc_gpn_ft_resp - container for ct header plus gpn_ft response
+ * @ct_hdr: FC GS common transport header
+ * @gpn_ft: Array of gpn_ft response data to fill one memory page
+ */
+struct zfcp_fc_gpn_ft_resp {
+ struct fc_ct_hdr ct_hdr;
+ struct fc_gpn_ft_resp gpn_ft[ZFCP_FC_GPN_FT_ENT_PAGE];
+} __packed;
+
+/**
+ * struct zfcp_fc_gpn_ft - zfcp data for gpn_ft request
+ * @ct: data passed to zfcp_fsf for issuing fsf request
+ * @sg_req: scatter list entry for gpn_ft request
+ * @sg_resp: scatter list entries for gpn_ft responses (per memory page)
+ */
+struct zfcp_fc_gpn_ft {
+ struct zfcp_fsf_ct_els ct;
+ struct scatterlist sg_req;
+ struct scatterlist sg_resp[ZFCP_FC_GPN_FT_NUM_BUFS];
+};
+
+/**
+ * struct zfcp_fc_els_adisc - everything required in zfcp for issuing ELS ADISC
+ * @els: data required for issuing els fsf command
+ * @req: scatterlist entry for ELS ADISC request
+ * @resp: scatterlist entry for ELS ADISC response
+ * @adisc_req: ELS ADISC request data
+ * @adisc_resp: ELS ADISC response data
+ */
+struct zfcp_fc_els_adisc {
+ struct zfcp_fsf_ct_els els;
+ struct scatterlist req;
+ struct scatterlist resp;
+ struct fc_els_adisc adisc_req;
+ struct fc_els_adisc adisc_resp;
+};
+
+/**
+ * enum zfcp_fc_wka_status - FC WKA port status in zfcp
+ * @ZFCP_FC_WKA_PORT_OFFLINE: Port is closed and not in use
+ * @ZFCP_FC_WKA_PORT_CLOSING: The FSF "close port" request is pending
+ * @ZFCP_FC_WKA_PORT_OPENING: The FSF "open port" request is pending
+ * @ZFCP_FC_WKA_PORT_ONLINE: The port is open and the port handle is valid
+ */
+enum zfcp_fc_wka_status {
+ ZFCP_FC_WKA_PORT_OFFLINE,
+ ZFCP_FC_WKA_PORT_CLOSING,
+ ZFCP_FC_WKA_PORT_OPENING,
+ ZFCP_FC_WKA_PORT_ONLINE,
+};
+
+/**
+ * struct zfcp_fc_wka_port - representation of well-known-address (WKA) FC port
+ * @adapter: Pointer to adapter structure this WKA port belongs to
+ * @completion_wq: Wait for completion of open/close command
+ * @status: Current status of WKA port
+ * @refcount: Reference count to keep port open as long as it is in use
+ * @d_id: FC destination id or well-known-address
+ * @handle: FSF handle for the open WKA port
+ * @mutex: Mutex used during opening/closing state changes
+ * @work: For delaying the closing of the WKA port
+ */
+struct zfcp_fc_wka_port {
+ struct zfcp_adapter *adapter;
+ wait_queue_head_t completion_wq;
+ enum zfcp_fc_wka_status status;
+ atomic_t refcount;
+ u32 d_id;
+ u32 handle;
+ struct mutex mutex;
+ struct delayed_work work;
+};
+
+/**
+ * struct zfcp_fc_wka_ports - Data structures for FC generic services
+ * @ms: FC Management service
+ * @ts: FC time service
+ * @ds: FC directory service
+ * @as: FC alias service
+ */
+struct zfcp_fc_wka_ports {
+ struct zfcp_fc_wka_port ms;
+ struct zfcp_fc_wka_port ts;
+ struct zfcp_fc_wka_port ds;
+ struct zfcp_fc_wka_port as;
+};
+
+/**
+ * zfcp_fc_scsi_to_fcp - setup FCP command with data from scsi_cmnd
+ * @fcp: fcp_cmnd to setup
+ * @scsi: scsi_cmnd where to get LUN, task attributes/flags and CDB
+ */
+static inline
+void zfcp_fc_scsi_to_fcp(struct fcp_cmnd *fcp, struct scsi_cmnd *scsi)
+{
+ char tag[2];
+
+ int_to_scsilun(scsi->device->lun, (struct scsi_lun *) &fcp->fc_lun);
+
+ if (scsi_populate_tag_msg(scsi, tag)) {
+ switch (tag[0]) {
+ case MSG_ORDERED_TAG:
+ fcp->fc_pri_ta |= FCP_PTA_ORDERED;
+ break;
+ case MSG_SIMPLE_TAG:
+ fcp->fc_pri_ta |= FCP_PTA_SIMPLE;
+ break;
+ };
+ } else
+ fcp->fc_pri_ta = FCP_PTA_SIMPLE;
+
+ if (scsi->sc_data_direction == DMA_FROM_DEVICE)
+ fcp->fc_flags |= FCP_CFL_RDDATA;
+ if (scsi->sc_data_direction == DMA_TO_DEVICE)
+ fcp->fc_flags |= FCP_CFL_WRDATA;
+
+ memcpy(fcp->fc_cdb, scsi->cmnd, scsi->cmd_len);
+
+ fcp->fc_dl = scsi_bufflen(scsi);
+}
+
+/**
+ * zfcp_fc_fcp_tm - setup FCP command as task management command
+ * @fcp: fcp_cmnd to setup
+ * @dev: scsi_device where to send the task management command
+ * @tm: task management flags to setup tm command
+ */
+static inline
+void zfcp_fc_fcp_tm(struct fcp_cmnd *fcp, struct scsi_device *dev, u8 tm_flags)
+{
+ int_to_scsilun(dev->lun, (struct scsi_lun *) &fcp->fc_lun);
+ fcp->fc_tm_flags |= tm_flags;
+}
+
+/**
+ * zfcp_fc_evap_fcp_rsp - evaluate FCP RSP IU and update scsi_cmnd accordingly
+ * @fcp_rsp: FCP RSP IU to evaluate
+ * @scsi: SCSI command where to update status and sense buffer
+ */
+static inline
+void zfcp_fc_eval_fcp_rsp(struct fcp_resp_with_ext *fcp_rsp,
+ struct scsi_cmnd *scsi)
+{
+ struct fcp_resp_rsp_info *rsp_info;
+ char *sense;
+ u32 sense_len, resid;
+ u8 rsp_flags;
+
+ set_msg_byte(scsi, COMMAND_COMPLETE);
+ scsi->result |= fcp_rsp->resp.fr_status;
+
+ rsp_flags = fcp_rsp->resp.fr_flags;
+
+ if (unlikely(rsp_flags & FCP_RSP_LEN_VAL)) {
+ rsp_info = (struct fcp_resp_rsp_info *) &fcp_rsp[1];
+ if (rsp_info->rsp_code == FCP_TMF_CMPL)
+ set_host_byte(scsi, DID_OK);
+ else {
+ set_host_byte(scsi, DID_ERROR);
+ return;
+ }
+ }
+
+ if (unlikely(rsp_flags & FCP_SNS_LEN_VAL)) {
+ sense = (char *) &fcp_rsp[1];
+ if (rsp_flags & FCP_RSP_LEN_VAL)
+ sense += fcp_rsp->ext.fr_sns_len;
+ sense_len = min(fcp_rsp->ext.fr_sns_len,
+ (u32) SCSI_SENSE_BUFFERSIZE);
+ memcpy(scsi->sense_buffer, sense, sense_len);
+ }
+
+ if (unlikely(rsp_flags & FCP_RESID_UNDER)) {
+ resid = fcp_rsp->ext.fr_resid;
+ scsi_set_resid(scsi, resid);
+ if (scsi_bufflen(scsi) - resid < scsi->underflow &&
+ !(rsp_flags & FCP_SNS_LEN_VAL) &&
+ fcp_rsp->resp.fr_status == SAM_STAT_GOOD)
+ set_host_byte(scsi, DID_ERROR);
+ }
+}
+
+#endif
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 4e41baa..482dcd9 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -10,7 +10,9 @@
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
#include <linux/blktrace_api.h>
+#include <scsi/fc/fc_els.h>
#include "zfcp_ext.h"
+#include "zfcp_fc.h"
#include "zfcp_dbf.h"
static void zfcp_fsf_request_timeout_handler(unsigned long data)
@@ -122,36 +124,32 @@ void zfcp_fsf_req_free(struct zfcp_fsf_req *req)
static void zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *req)
{
+ unsigned long flags;
struct fsf_status_read_buffer *sr_buf = req->data;
struct zfcp_adapter *adapter = req->adapter;
struct zfcp_port *port;
- int d_id = sr_buf->d_id & ZFCP_DID_MASK;
- unsigned long flags;
+ int d_id = ntoh24(sr_buf->d_id);
- read_lock_irqsave(&zfcp_data.config_lock, flags);
- list_for_each_entry(port, &adapter->port_list_head, list)
+ read_lock_irqsave(&adapter->port_list_lock, flags);
+ list_for_each_entry(port, &adapter->port_list, list)
if (port->d_id == d_id) {
- read_unlock_irqrestore(&zfcp_data.config_lock, flags);
zfcp_erp_port_reopen(port, 0, "fssrpc1", req);
- return;
+ break;
}
- read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+ read_unlock_irqrestore(&adapter->port_list_lock, flags);
}
static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req, char *id,
struct fsf_link_down_info *link_down)
{
struct zfcp_adapter *adapter = req->adapter;
- unsigned long flags;
if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED)
return;
atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status);
- read_lock_irqsave(&zfcp_data.config_lock, flags);
zfcp_scsi_schedule_rports_block(adapter);
- read_unlock_irqrestore(&zfcp_data.config_lock, flags);
if (!link_down)
goto out;
@@ -291,7 +289,7 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req)
zfcp_erp_adapter_access_changed(adapter, "fssrh_3",
req);
if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_INCOMING_ELS)
- schedule_work(&adapter->scan_work);
+ queue_work(adapter->work_queue, &adapter->scan_work);
break;
case FSF_STATUS_READ_CFDC_UPDATED:
zfcp_erp_adapter_access_changed(adapter, "fssrh_4", req);
@@ -317,7 +315,6 @@ static void zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *req)
case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
return;
case FSF_SQ_COMMAND_ABORTED:
- req->status |= ZFCP_STATUS_FSFREQ_ABORTED;
break;
case FSF_SQ_NO_RECOM:
dev_err(&req->adapter->ccw_device->dev,
@@ -358,8 +355,7 @@ static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req)
zfcp_dbf_hba_fsf_response(req);
if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED) {
- req->status |= ZFCP_STATUS_FSFREQ_ERROR |
- ZFCP_STATUS_FSFREQ_RETRY; /* only for SCSI cmnds. */
+ req->status |= ZFCP_STATUS_FSFREQ_ERROR;
return;
}
@@ -377,7 +373,7 @@ static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req)
case FSF_PROT_ERROR_STATE:
case FSF_PROT_SEQ_NUMB_ERROR:
zfcp_erp_adapter_reopen(adapter, 0, "fspse_2", req);
- req->status |= ZFCP_STATUS_FSFREQ_RETRY;
+ req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_PROT_UNSUPP_QTCB_TYPE:
dev_err(&adapter->ccw_device->dev,
@@ -480,20 +476,27 @@ void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter)
static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req)
{
- struct fsf_qtcb_bottom_config *bottom;
+ struct fsf_qtcb_bottom_config *bottom = &req->qtcb->bottom.config;
struct zfcp_adapter *adapter = req->adapter;
struct Scsi_Host *shost = adapter->scsi_host;
+ struct fc_els_flogi *nsp, *plogi;
- bottom = &req->qtcb->bottom.config;
+ /* adjust pointers for missing command code */
+ nsp = (struct fc_els_flogi *) ((u8 *)&bottom->nport_serv_param
+ - sizeof(u32));
+ plogi = (struct fc_els_flogi *) ((u8 *)&bottom->plogi_payload
+ - sizeof(u32));
if (req->data)
memcpy(req->data, bottom, sizeof(*bottom));
- 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_port_name(shost) = nsp->fl_wwpn;
+ fc_host_node_name(shost) = nsp->fl_wwnn;
+ fc_host_port_id(shost) = ntoh24(bottom->s_id);
fc_host_speed(shost) = bottom->fc_link_speed;
fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3;
+ fc_host_supported_fc4s(shost)[2] = 1; /* FCP */
+ fc_host_active_fc4s(shost)[2] = 1; /* FCP */
adapter->hydra_version = bottom->adapter_type;
adapter->timer_ticks = bottom->timer_interval;
@@ -503,9 +506,9 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req)
switch (bottom->fc_topology) {
case FSF_TOPO_P2P:
- adapter->peer_d_id = bottom->peer_d_id & ZFCP_DID_MASK;
- adapter->peer_wwpn = bottom->plogi_payload.wwpn;
- adapter->peer_wwnn = bottom->plogi_payload.wwnn;
+ adapter->peer_d_id = ntoh24(bottom->peer_d_id);
+ adapter->peer_wwpn = plogi->fl_wwpn;
+ adapter->peer_wwnn = plogi->fl_wwnn;
fc_host_port_type(shost) = FC_PORTTYPE_PTP;
break;
case FSF_TOPO_FABRIC:
@@ -881,13 +884,11 @@ static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req)
break;
case FSF_PORT_BOXED:
zfcp_erp_port_boxed(unit->port, "fsafch3", req);
- req->status |= ZFCP_STATUS_FSFREQ_ERROR |
- ZFCP_STATUS_FSFREQ_RETRY;
+ req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_LUN_BOXED:
zfcp_erp_unit_boxed(unit, "fsafch4", req);
- req->status |= ZFCP_STATUS_FSFREQ_ERROR |
- ZFCP_STATUS_FSFREQ_RETRY;
+ req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_ADAPTER_STATUS_AVAILABLE:
switch (fsq->word[0]) {
@@ -958,10 +959,10 @@ out:
static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req)
{
struct zfcp_adapter *adapter = req->adapter;
- struct zfcp_send_ct *send_ct = req->data;
+ struct zfcp_fsf_ct_els *ct = req->data;
struct fsf_qtcb_header *header = &req->qtcb->header;
- send_ct->status = -EINVAL;
+ ct->status = -EINVAL;
if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
goto skip_fsfstatus;
@@ -969,7 +970,7 @@ static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req)
switch (header->fsf_status) {
case FSF_GOOD:
zfcp_dbf_san_ct_response(req);
- send_ct->status = 0;
+ ct->status = 0;
break;
case FSF_SERVICE_CLASS_NOT_SUPPORTED:
zfcp_fsf_class_not_supp(req);
@@ -985,8 +986,7 @@ static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req)
case FSF_ACCESS_DENIED:
break;
case FSF_PORT_BOXED:
- req->status |= ZFCP_STATUS_FSFREQ_ERROR |
- ZFCP_STATUS_FSFREQ_RETRY;
+ req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_PORT_HANDLE_NOT_VALID:
zfcp_erp_adapter_reopen(adapter, 0, "fsscth1", req);
@@ -1001,8 +1001,8 @@ static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req)
}
skip_fsfstatus:
- if (send_ct->handler)
- send_ct->handler(send_ct->handler_data);
+ if (ct->handler)
+ ct->handler(ct->handler_data);
}
static void zfcp_fsf_setup_ct_els_unchained(struct qdio_buffer_element *sbale,
@@ -1071,15 +1071,17 @@ static int zfcp_fsf_setup_ct_els(struct zfcp_fsf_req *req,
int max_sbals)
{
int ret;
+ unsigned int fcp_chan_timeout;
ret = zfcp_fsf_setup_ct_els_sbals(req, sg_req, sg_resp, max_sbals);
if (ret)
return ret;
/* common settings for ct/gs and els requests */
+ fcp_chan_timeout = 2 * FC_DEF_R_A_TOV / 1000;
req->qtcb->bottom.support.service_class = FSF_CLASS_3;
- req->qtcb->bottom.support.timeout = 2 * R_A_TOV;
- zfcp_fsf_start_timer(req, (2 * R_A_TOV + 10) * HZ);
+ req->qtcb->bottom.support.timeout = fcp_chan_timeout;
+ zfcp_fsf_start_timer(req, (fcp_chan_timeout + 10) * HZ);
return 0;
}
@@ -1089,9 +1091,9 @@ static int zfcp_fsf_setup_ct_els(struct zfcp_fsf_req *req,
* @ct: pointer to struct zfcp_send_ct with data for request
* @pool: if non-null this mempool is used to allocate struct zfcp_fsf_req
*/
-int zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool)
+int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *wka_port,
+ struct zfcp_fsf_ct_els *ct, mempool_t *pool)
{
- struct zfcp_wka_port *wka_port = ct->wka_port;
struct zfcp_qdio *qdio = wka_port->adapter->qdio;
struct zfcp_fsf_req *req;
int ret = -EIO;
@@ -1117,7 +1119,7 @@ int zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool)
req->qtcb->header.port_handle = wka_port->handle;
req->data = ct;
- zfcp_dbf_san_ct_request(req);
+ zfcp_dbf_san_ct_request(req, wka_port->d_id);
ret = zfcp_fsf_req_send(req);
if (ret)
@@ -1134,7 +1136,7 @@ out:
static void zfcp_fsf_send_els_handler(struct zfcp_fsf_req *req)
{
- struct zfcp_send_els *send_els = req->data;
+ struct zfcp_fsf_ct_els *send_els = req->data;
struct zfcp_port *port = send_els->port;
struct fsf_qtcb_header *header = &req->qtcb->header;
@@ -1154,9 +1156,6 @@ static void zfcp_fsf_send_els_handler(struct zfcp_fsf_req *req)
case FSF_ADAPTER_STATUS_AVAILABLE:
switch (header->fsf_status_qual.word[0]){
case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
- if (port && (send_els->ls_code != ZFCP_LS_ADISC))
- zfcp_fc_test_link(port);
- /*fall through */
case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
case FSF_SQ_RETRY_IF_POSSIBLE:
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
@@ -1188,10 +1187,11 @@ skip_fsfstatus:
* zfcp_fsf_send_els - initiate an ELS command (FC-FS)
* @els: pointer to struct zfcp_send_els with data for the command
*/
-int zfcp_fsf_send_els(struct zfcp_send_els *els)
+int zfcp_fsf_send_els(struct zfcp_adapter *adapter, u32 d_id,
+ struct zfcp_fsf_ct_els *els)
{
struct zfcp_fsf_req *req;
- struct zfcp_qdio *qdio = els->adapter->qdio;
+ struct zfcp_qdio *qdio = adapter->qdio;
int ret = -EIO;
spin_lock_bh(&qdio->req_q_lock);
@@ -1211,7 +1211,7 @@ int zfcp_fsf_send_els(struct zfcp_send_els *els)
if (ret)
goto failed_send;
- req->qtcb->bottom.support.d_id = els->d_id;
+ hton24(req->qtcb->bottom.support.d_id, d_id);
req->handler = zfcp_fsf_send_els_handler;
req->data = els;
@@ -1422,7 +1422,7 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req)
{
struct zfcp_port *port = req->data;
struct fsf_qtcb_header *header = &req->qtcb->header;
- struct fsf_plogi *plogi;
+ struct fc_els_flogi *plogi;
if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
goto out;
@@ -1472,23 +1472,10 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req)
* another GID_PN straight after a port has been opened.
* Alternately, an ADISC/PDISC ELS should suffice, as well.
*/
- plogi = (struct fsf_plogi *) req->qtcb->bottom.support.els;
+ plogi = (struct fc_els_flogi *) req->qtcb->bottom.support.els;
if (req->qtcb->bottom.support.els1_length >=
- FSF_PLOGI_MIN_LEN) {
- if (plogi->serv_param.wwpn != port->wwpn) {
- port->d_id = 0;
- dev_warn(&port->adapter->ccw_device->dev,
- "A port opened with WWPN 0x%016Lx "
- "returned data that identifies it as "
- "WWPN 0x%016Lx\n",
- (unsigned long long) port->wwpn,
- (unsigned long long)
- plogi->serv_param.wwpn);
- } else {
- port->wwnn = plogi->serv_param.wwnn;
+ FSF_PLOGI_MIN_LEN)
zfcp_fc_plogi_evaluate(port, plogi);
- }
- }
break;
case FSF_UNKNOWN_OP_SUBTYPE:
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
@@ -1496,7 +1483,7 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req)
}
out:
- zfcp_port_put(port);
+ put_device(&port->sysfs_device);
}
/**
@@ -1530,18 +1517,18 @@ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
req->handler = zfcp_fsf_open_port_handler;
- req->qtcb->bottom.support.d_id = port->d_id;
+ hton24(req->qtcb->bottom.support.d_id, port->d_id);
req->data = port;
req->erp_action = erp_action;
erp_action->fsf_req = req;
- zfcp_port_get(port);
+ get_device(&port->sysfs_device);
zfcp_fsf_start_erp_timer(req);
retval = zfcp_fsf_req_send(req);
if (retval) {
zfcp_fsf_req_free(req);
erp_action->fsf_req = NULL;
- zfcp_port_put(port);
+ put_device(&port->sysfs_device);
}
out:
spin_unlock_bh(&qdio->req_q_lock);
@@ -1618,11 +1605,11 @@ out:
static void zfcp_fsf_open_wka_port_handler(struct zfcp_fsf_req *req)
{
- struct zfcp_wka_port *wka_port = req->data;
+ struct zfcp_fc_wka_port *wka_port = req->data;
struct fsf_qtcb_header *header = &req->qtcb->header;
if (req->status & ZFCP_STATUS_FSFREQ_ERROR) {
- wka_port->status = ZFCP_WKA_PORT_OFFLINE;
+ wka_port->status = ZFCP_FC_WKA_PORT_OFFLINE;
goto out;
}
@@ -1635,13 +1622,13 @@ static void zfcp_fsf_open_wka_port_handler(struct zfcp_fsf_req *req)
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
/* fall through */
case FSF_ACCESS_DENIED:
- wka_port->status = ZFCP_WKA_PORT_OFFLINE;
+ wka_port->status = ZFCP_FC_WKA_PORT_OFFLINE;
break;
case FSF_GOOD:
wka_port->handle = header->port_handle;
/* fall through */
case FSF_PORT_ALREADY_OPEN:
- wka_port->status = ZFCP_WKA_PORT_ONLINE;
+ wka_port->status = ZFCP_FC_WKA_PORT_ONLINE;
}
out:
wake_up(&wka_port->completion_wq);
@@ -1649,10 +1636,10 @@ out:
/**
* zfcp_fsf_open_wka_port - create and send open wka-port request
- * @wka_port: pointer to struct zfcp_wka_port
+ * @wka_port: pointer to struct zfcp_fc_wka_port
* Returns: 0 on success, error otherwise
*/
-int zfcp_fsf_open_wka_port(struct zfcp_wka_port *wka_port)
+int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *wka_port)
{
struct qdio_buffer_element *sbale;
struct zfcp_qdio *qdio = wka_port->adapter->qdio;
@@ -1677,7 +1664,7 @@ int zfcp_fsf_open_wka_port(struct zfcp_wka_port *wka_port)
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
req->handler = zfcp_fsf_open_wka_port_handler;
- req->qtcb->bottom.support.d_id = wka_port->d_id;
+ hton24(req->qtcb->bottom.support.d_id, wka_port->d_id);
req->data = wka_port;
zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
@@ -1691,23 +1678,23 @@ out:
static void zfcp_fsf_close_wka_port_handler(struct zfcp_fsf_req *req)
{
- struct zfcp_wka_port *wka_port = req->data;
+ struct zfcp_fc_wka_port *wka_port = req->data;
if (req->qtcb->header.fsf_status == FSF_PORT_HANDLE_NOT_VALID) {
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
zfcp_erp_adapter_reopen(wka_port->adapter, 0, "fscwph1", req);
}
- wka_port->status = ZFCP_WKA_PORT_OFFLINE;
+ wka_port->status = ZFCP_FC_WKA_PORT_OFFLINE;
wake_up(&wka_port->completion_wq);
}
/**
* zfcp_fsf_close_wka_port - create and send close wka port request
- * @erp_action: pointer to struct zfcp_erp_action
+ * @wka_port: WKA port to open
* Returns: 0 on success, error otherwise
*/
-int zfcp_fsf_close_wka_port(struct zfcp_wka_port *wka_port)
+int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *wka_port)
{
struct qdio_buffer_element *sbale;
struct zfcp_qdio *qdio = wka_port->adapter->qdio;
@@ -1765,13 +1752,13 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req)
/* can't use generic zfcp_erp_modify_port_status because
* ZFCP_STATUS_COMMON_OPEN must not be reset for the port */
atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
- list_for_each_entry(unit, &port->unit_list_head, list)
+ read_lock(&port->unit_list_lock);
+ list_for_each_entry(unit, &port->unit_list, list)
atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN,
&unit->status);
+ read_unlock(&port->unit_list_lock);
zfcp_erp_port_boxed(port, "fscpph2", req);
- req->status |= ZFCP_STATUS_FSFREQ_ERROR |
- ZFCP_STATUS_FSFREQ_RETRY;
-
+ req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_ADAPTER_STATUS_AVAILABLE:
switch (header->fsf_status_qual.word[0]) {
@@ -1787,9 +1774,11 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req)
* ZFCP_STATUS_COMMON_OPEN must not be reset for the port
*/
atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
- list_for_each_entry(unit, &port->unit_list_head, list)
+ read_lock(&port->unit_list_lock);
+ list_for_each_entry(unit, &port->unit_list, list)
atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN,
&unit->status);
+ read_unlock(&port->unit_list_lock);
break;
}
}
@@ -1873,8 +1862,7 @@ static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req)
break;
case FSF_PORT_BOXED:
zfcp_erp_port_boxed(unit->port, "fsouh_2", req);
- req->status |= ZFCP_STATUS_FSFREQ_ERROR |
- ZFCP_STATUS_FSFREQ_RETRY;
+ req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_LUN_SHARING_VIOLATION:
if (header->fsf_status_qual.word[0])
@@ -2036,8 +2024,7 @@ static void zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *req)
break;
case FSF_PORT_BOXED:
zfcp_erp_port_boxed(unit->port, "fscuh_3", req);
- req->status |= ZFCP_STATUS_FSFREQ_ERROR |
- ZFCP_STATUS_FSFREQ_RETRY;
+ req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_ADAPTER_STATUS_AVAILABLE:
switch (req->qtcb->header.fsf_status_qual.word[0]) {
@@ -2109,72 +2096,57 @@ static void zfcp_fsf_update_lat(struct fsf_latency_record *lat_rec, u32 lat)
lat_rec->max = max(lat_rec->max, lat);
}
-static void zfcp_fsf_req_latency(struct zfcp_fsf_req *req)
+static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi)
{
- struct fsf_qual_latency_info *lat_inf;
- struct latency_cont *lat;
+ struct fsf_qual_latency_info *lat_in;
+ struct latency_cont *lat = NULL;
struct zfcp_unit *unit = req->unit;
+ struct zfcp_blk_drv_data blktrc;
+ int ticks = req->adapter->timer_ticks;
- lat_inf = &req->qtcb->prefix.prot_status_qual.latency_info;
-
- switch (req->qtcb->bottom.io.data_direction) {
- case FSF_DATADIR_READ:
- lat = &unit->latencies.read;
- break;
- case FSF_DATADIR_WRITE:
- lat = &unit->latencies.write;
- break;
- case FSF_DATADIR_CMND:
- lat = &unit->latencies.cmd;
- break;
- default:
- return;
- }
+ lat_in = &req->qtcb->prefix.prot_status_qual.latency_info;
- spin_lock(&unit->latencies.lock);
- zfcp_fsf_update_lat(&lat->channel, lat_inf->channel_lat);
- zfcp_fsf_update_lat(&lat->fabric, lat_inf->fabric_lat);
- lat->counter++;
- spin_unlock(&unit->latencies.lock);
-}
-
-#ifdef CONFIG_BLK_DEV_IO_TRACE
-static void zfcp_fsf_trace_latency(struct zfcp_fsf_req *fsf_req)
-{
- struct fsf_qual_latency_info *lat_inf;
- struct scsi_cmnd *scsi_cmnd = (struct scsi_cmnd *)fsf_req->data;
- struct request *req = scsi_cmnd->request;
- struct zfcp_blk_drv_data trace;
- int ticks = fsf_req->adapter->timer_ticks;
+ blktrc.flags = 0;
+ blktrc.magic = ZFCP_BLK_DRV_DATA_MAGIC;
+ if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
+ blktrc.flags |= ZFCP_BLK_REQ_ERROR;
+ blktrc.inb_usage = req->queue_req.qdio_inb_usage;
+ blktrc.outb_usage = req->queue_req.qdio_outb_usage;
+
+ if (req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA) {
+ blktrc.flags |= ZFCP_BLK_LAT_VALID;
+ blktrc.channel_lat = lat_in->channel_lat * ticks;
+ blktrc.fabric_lat = lat_in->fabric_lat * ticks;
+
+ switch (req->qtcb->bottom.io.data_direction) {
+ case FSF_DATADIR_READ:
+ lat = &unit->latencies.read;
+ break;
+ case FSF_DATADIR_WRITE:
+ lat = &unit->latencies.write;
+ break;
+ case FSF_DATADIR_CMND:
+ lat = &unit->latencies.cmd;
+ break;
+ }
- trace.flags = 0;
- trace.magic = ZFCP_BLK_DRV_DATA_MAGIC;
- if (fsf_req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA) {
- trace.flags |= ZFCP_BLK_LAT_VALID;
- lat_inf = &fsf_req->qtcb->prefix.prot_status_qual.latency_info;
- trace.channel_lat = lat_inf->channel_lat * ticks;
- trace.fabric_lat = lat_inf->fabric_lat * ticks;
+ if (lat) {
+ spin_lock(&unit->latencies.lock);
+ zfcp_fsf_update_lat(&lat->channel, lat_in->channel_lat);
+ zfcp_fsf_update_lat(&lat->fabric, lat_in->fabric_lat);
+ lat->counter++;
+ spin_unlock(&unit->latencies.lock);
+ }
}
- if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)
- trace.flags |= ZFCP_BLK_REQ_ERROR;
- trace.inb_usage = fsf_req->queue_req.qdio_inb_usage;
- trace.outb_usage = fsf_req->queue_req.qdio_outb_usage;
- blk_add_driver_data(req->q, req, &trace, sizeof(trace));
-}
-#else
-static inline void zfcp_fsf_trace_latency(struct zfcp_fsf_req *fsf_req)
-{
+ blk_add_driver_data(scsi->request->q, scsi->request, &blktrc,
+ sizeof(blktrc));
}
-#endif
static void zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *req)
{
struct scsi_cmnd *scpnt;
- struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *)
- &(req->qtcb->bottom.io.fcp_rsp);
- u32 sns_len;
- char *fcp_rsp_info = (unsigned char *) &fcp_rsp_iu[1];
+ struct fcp_resp_with_ext *fcp_rsp;
unsigned long flags;
read_lock_irqsave(&req->adapter->abort_lock, flags);
@@ -2185,50 +2157,16 @@ static void zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *req)
return;
}
- if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ABORTED)) {
- set_host_byte(scpnt, DID_SOFT_ERROR);
- goto skip_fsfstatus;
- }
-
if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
- set_host_byte(scpnt, DID_ERROR);
+ set_host_byte(scpnt, DID_TRANSPORT_DISRUPTED);
goto skip_fsfstatus;
}
- set_msg_byte(scpnt, COMMAND_COMPLETE);
-
- scpnt->result |= fcp_rsp_iu->scsi_status;
+ fcp_rsp = (struct fcp_resp_with_ext *) &req->qtcb->bottom.io.fcp_rsp;
+ zfcp_fc_eval_fcp_rsp(fcp_rsp, scpnt);
- if (req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA)
- zfcp_fsf_req_latency(req);
-
- zfcp_fsf_trace_latency(req);
-
- if (unlikely(fcp_rsp_iu->validity.bits.fcp_rsp_len_valid)) {
- if (fcp_rsp_info[3] == RSP_CODE_GOOD)
- set_host_byte(scpnt, DID_OK);
- else {
- set_host_byte(scpnt, DID_ERROR);
- goto skip_fsfstatus;
- }
- }
-
- if (unlikely(fcp_rsp_iu->validity.bits.fcp_sns_len_valid)) {
- sns_len = FSF_FCP_RSP_SIZE - sizeof(struct fcp_rsp_iu) +
- fcp_rsp_iu->fcp_rsp_len;
- sns_len = min(sns_len, (u32) SCSI_SENSE_BUFFERSIZE);
- sns_len = min(sns_len, fcp_rsp_iu->fcp_sns_len);
-
- memcpy(scpnt->sense_buffer,
- zfcp_get_fcp_sns_info_ptr(fcp_rsp_iu), sns_len);
- }
+ zfcp_fsf_req_trace(req, scpnt);
- if (unlikely(fcp_rsp_iu->validity.bits.fcp_resid_under)) {
- scsi_set_resid(scpnt, fcp_rsp_iu->fcp_resid);
- if (scsi_bufflen(scpnt) - scsi_get_resid(scpnt) <
- scpnt->underflow)
- set_host_byte(scpnt, DID_ERROR);
- }
skip_fsfstatus:
if (scpnt->result != 0)
zfcp_dbf_scsi_result("erro", 3, req->adapter->dbf, scpnt, req);
@@ -2250,11 +2188,13 @@ skip_fsfstatus:
static void zfcp_fsf_send_fcp_ctm_handler(struct zfcp_fsf_req *req)
{
- struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *)
- &(req->qtcb->bottom.io.fcp_rsp);
- char *fcp_rsp_info = (unsigned char *) &fcp_rsp_iu[1];
+ struct fcp_resp_with_ext *fcp_rsp;
+ struct fcp_resp_rsp_info *rsp_info;
+
+ fcp_rsp = (struct fcp_resp_with_ext *) &req->qtcb->bottom.io.fcp_rsp;
+ rsp_info = (struct fcp_resp_rsp_info *) &fcp_rsp[1];
- if ((fcp_rsp_info[3] != RSP_CODE_GOOD) ||
+ if ((rsp_info->rsp_code != FCP_TMF_CMPL) ||
(req->status & ZFCP_STATUS_FSFREQ_ERROR))
req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED;
}
@@ -2314,13 +2254,11 @@ static void zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *req)
break;
case FSF_PORT_BOXED:
zfcp_erp_port_boxed(unit->port, "fssfch5", req);
- req->status |= ZFCP_STATUS_FSFREQ_ERROR |
- ZFCP_STATUS_FSFREQ_RETRY;
+ req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_LUN_BOXED:
zfcp_erp_unit_boxed(unit, "fssfch6", req);
- req->status |= ZFCP_STATUS_FSFREQ_ERROR |
- ZFCP_STATUS_FSFREQ_RETRY;
+ req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_ADAPTER_STATUS_AVAILABLE:
if (header->fsf_status_qual.word[0] ==
@@ -2335,24 +2273,10 @@ skip_fsfstatus:
else {
zfcp_fsf_send_fcp_command_task_handler(req);
req->unit = NULL;
- zfcp_unit_put(unit);
+ put_device(&unit->sysfs_device);
}
}
-static void zfcp_set_fcp_dl(struct fcp_cmnd_iu *fcp_cmd, u32 fcp_dl)
-{
- u32 *fcp_dl_ptr;
-
- /*
- * 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
- */
- fcp_dl_ptr = (u32 *) ((unsigned char *) &fcp_cmd[1] +
- (fcp_cmd->add_fcp_cdb_length << 2));
- *fcp_dl_ptr = fcp_dl;
-}
-
/**
* zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command)
* @unit: unit where command is sent to
@@ -2362,7 +2286,7 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
struct scsi_cmnd *scsi_cmnd)
{
struct zfcp_fsf_req *req;
- struct fcp_cmnd_iu *fcp_cmnd_iu;
+ struct fcp_cmnd *fcp_cmnd;
unsigned int sbtype = SBAL_FLAGS0_TYPE_READ;
int real_bytes, retval = -EIO;
struct zfcp_adapter *adapter = unit->port->adapter;
@@ -2387,23 +2311,21 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
}
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
- zfcp_unit_get(unit);
+ get_device(&unit->sysfs_device);
req->unit = unit;
req->data = scsi_cmnd;
req->handler = zfcp_fsf_send_fcp_command_handler;
req->qtcb->header.lun_handle = unit->handle;
req->qtcb->header.port_handle = unit->port->handle;
req->qtcb->bottom.io.service_class = FSF_CLASS_3;
+ req->qtcb->bottom.io.fcp_cmnd_length = FCP_CMND_LEN;
scsi_cmnd->host_scribble = (unsigned char *) req->req_id;
- fcp_cmnd_iu = (struct fcp_cmnd_iu *) &(req->qtcb->bottom.io.fcp_cmnd);
- fcp_cmnd_iu->fcp_lun = unit->fcp_lun;
/*
* set depending on data direction:
* data direction bits in SBALE (SB Type)
* data direction bits in QTCB
- * data direction bits in FCP_CMND IU
*/
switch (scsi_cmnd->sc_data_direction) {
case DMA_NONE:
@@ -2411,32 +2333,17 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
break;
case DMA_FROM_DEVICE:
req->qtcb->bottom.io.data_direction = FSF_DATADIR_READ;
- fcp_cmnd_iu->rddata = 1;
break;
case DMA_TO_DEVICE:
req->qtcb->bottom.io.data_direction = FSF_DATADIR_WRITE;
sbtype = SBAL_FLAGS0_TYPE_WRITE;
- fcp_cmnd_iu->wddata = 1;
break;
case DMA_BIDIRECTIONAL:
goto failed_scsi_cmnd;
}
- if (likely((scsi_cmnd->device->simple_tags) ||
- ((atomic_read(&unit->status) & ZFCP_STATUS_UNIT_READONLY) &&
- (atomic_read(&unit->status) & ZFCP_STATUS_UNIT_SHARED))))
- fcp_cmnd_iu->task_attribute = SIMPLE_Q;
- else
- fcp_cmnd_iu->task_attribute = UNTAGGED;
-
- if (unlikely(scsi_cmnd->cmd_len > FCP_CDB_LENGTH))
- fcp_cmnd_iu->add_fcp_cdb_length =
- (scsi_cmnd->cmd_len - FCP_CDB_LENGTH) >> 2;
-
- memcpy(fcp_cmnd_iu->fcp_cdb, scsi_cmnd->cmnd, scsi_cmnd->cmd_len);
-
- req->qtcb->bottom.io.fcp_cmnd_length = sizeof(struct fcp_cmnd_iu) +
- fcp_cmnd_iu->add_fcp_cdb_length + sizeof(u32);
+ fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd;
+ zfcp_fc_scsi_to_fcp(fcp_cmnd, scsi_cmnd);
real_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->queue_req, sbtype,
scsi_sglist(scsi_cmnd),
@@ -2454,8 +2361,6 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
goto failed_scsi_cmnd;
}
- zfcp_set_fcp_dl(fcp_cmnd_iu, real_bytes);
-
retval = zfcp_fsf_req_send(req);
if (unlikely(retval))
goto failed_scsi_cmnd;
@@ -2463,7 +2368,7 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
goto out;
failed_scsi_cmnd:
- zfcp_unit_put(unit);
+ put_device(&unit->sysfs_device);
zfcp_fsf_req_free(req);
scsi_cmnd->host_scribble = NULL;
out:
@@ -2481,7 +2386,7 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags)
{
struct qdio_buffer_element *sbale;
struct zfcp_fsf_req *req = NULL;
- struct fcp_cmnd_iu *fcp_cmnd_iu;
+ struct fcp_cmnd *fcp_cmnd;
struct zfcp_qdio *qdio = unit->port->adapter->qdio;
if (unlikely(!(atomic_read(&unit->status) &
@@ -2507,16 +2412,14 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags)
req->qtcb->header.port_handle = unit->port->handle;
req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND;
req->qtcb->bottom.io.service_class = FSF_CLASS_3;
- req->qtcb->bottom.io.fcp_cmnd_length = sizeof(struct fcp_cmnd_iu) +
- sizeof(u32);
+ req->qtcb->bottom.io.fcp_cmnd_length = FCP_CMND_LEN;
sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req);
sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE;
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
- fcp_cmnd_iu = (struct fcp_cmnd_iu *) &req->qtcb->bottom.io.fcp_cmnd;
- fcp_cmnd_iu->fcp_lun = unit->fcp_lun;
- fcp_cmnd_iu->task_management_flags = tm_flags;
+ fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd;
+ zfcp_fc_fcp_tm(fcp_cmnd, unit->device, tm_flags);
zfcp_fsf_start_timer(req, ZFCP_SCSI_ER_TIMEOUT);
if (!zfcp_fsf_req_send(req))
diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h
index dcc7c1d..b3de682 100644
--- a/drivers/s390/scsi/zfcp_fsf.h
+++ b/drivers/s390/scsi/zfcp_fsf.h
@@ -11,6 +11,7 @@
#include <linux/pfn.h>
#include <linux/scatterlist.h>
+#include <scsi/libfc.h>
#define FSF_QTCB_CURRENT_VERSION 0x00000001
@@ -228,7 +229,8 @@ struct fsf_status_read_buffer {
u32 length;
u32 res1;
struct fsf_queue_designator queue_designator;
- u32 d_id;
+ u8 res2;
+ u8 d_id[3];
u32 class;
u64 fcp_lun;
u8 res3[24];
@@ -309,22 +311,7 @@ struct fsf_qtcb_header {
u8 res4[16];
} __attribute__ ((packed));
-struct fsf_nport_serv_param {
- u8 common_serv_param[16];
- u64 wwpn;
- u64 wwnn;
- u8 class1_serv_param[16];
- u8 class2_serv_param[16];
- u8 class3_serv_param[16];
- u8 class4_serv_param[16];
- u8 vendor_version_level[16];
-} __attribute__ ((packed));
-
#define FSF_PLOGI_MIN_LEN 112
-struct fsf_plogi {
- u32 code;
- struct fsf_nport_serv_param serv_param;
-} __attribute__ ((packed));
#define FSF_FCP_CMND_SIZE 288
#define FSF_FCP_RSP_SIZE 128
@@ -342,8 +329,8 @@ struct fsf_qtcb_bottom_io {
struct fsf_qtcb_bottom_support {
u32 operation_subtype;
- u8 res1[12];
- u32 d_id;
+ u8 res1[13];
+ u8 d_id[3];
u32 option;
u64 fcp_lun;
u64 res2;
@@ -372,18 +359,18 @@ struct fsf_qtcb_bottom_config {
u32 fc_topology;
u32 fc_link_speed;
u32 adapter_type;
- u32 peer_d_id;
+ u8 res0;
+ u8 peer_d_id[3];
u8 res1[2];
u16 timer_interval;
- u8 res2[8];
- u32 s_id;
- struct fsf_nport_serv_param nport_serv_param;
- u8 reserved_nport_serv_param[16];
+ u8 res2[9];
+ u8 s_id[3];
+ u8 nport_serv_param[128];
u8 res3[8];
u32 adapter_ports;
u32 hardware_version;
u8 serial_number[32];
- struct fsf_nport_serv_param plogi_payload;
+ u8 plogi_payload[112];
struct fsf_statistics_info stat_info;
u8 res4[112];
} __attribute__ ((packed));
@@ -450,4 +437,22 @@ struct zfcp_blk_drv_data {
u64 fabric_lat;
} __attribute__ ((packed));
+/**
+ * struct zfcp_fsf_ct_els - zfcp data for ct or els request
+ * @req: scatter-gather list for request
+ * @resp: scatter-gather list for response
+ * @handler: handler function (called for response to the request)
+ * @handler_data: data passed to handler function
+ * @port: Optional pointer to port for zfcp internal ELS (only test link ADISC)
+ * @status: used to pass error status to calling function
+ */
+struct zfcp_fsf_ct_els {
+ struct scatterlist *req;
+ struct scatterlist *resp;
+ void (*handler)(void *);
+ void *handler_data;
+ struct zfcp_port *port;
+ int status;
+};
+
#endif /* FSF_H */
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index 0e1a346..771cc53 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -9,29 +9,33 @@
#define KMSG_COMPONENT "zfcp"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+#include <linux/types.h>
+#include <scsi/fc/fc_fcp.h>
#include <asm/atomic.h>
#include "zfcp_ext.h"
#include "zfcp_dbf.h"
+#include "zfcp_fc.h"
static unsigned int default_depth = 32;
module_param_named(queue_depth, default_depth, uint, 0600);
MODULE_PARM_DESC(queue_depth, "Default queue depth for new SCSI devices");
-/* Find start of Sense Information in FCP response unit*/
-char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *fcp_rsp_iu)
+static int zfcp_scsi_change_queue_depth(struct scsi_device *sdev, int depth,
+ int reason)
{
- char *fcp_sns_info_ptr;
-
- fcp_sns_info_ptr = (unsigned char *) &fcp_rsp_iu[1];
- if (fcp_rsp_iu->validity.bits.fcp_rsp_len_valid)
- fcp_sns_info_ptr += fcp_rsp_iu->fcp_rsp_len;
-
- return fcp_sns_info_ptr;
-}
-
-static int zfcp_scsi_change_queue_depth(struct scsi_device *sdev, int depth)
-{
- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
+ switch (reason) {
+ case SCSI_QDEPTH_DEFAULT:
+ scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
+ break;
+ case SCSI_QDEPTH_QFULL:
+ scsi_track_queue_full(sdev, depth);
+ break;
+ case SCSI_QDEPTH_RAMP_UP:
+ scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
return sdev->queue_depth;
}
@@ -39,7 +43,7 @@ static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt)
{
struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata;
unit->device = NULL;
- zfcp_unit_put(unit);
+ put_device(&unit->sysfs_device);
}
static int zfcp_scsi_slave_configure(struct scsi_device *sdp)
@@ -99,12 +103,26 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
}
status = atomic_read(&unit->status);
- if (unlikely((status & ZFCP_STATUS_COMMON_ERP_FAILED) ||
- !(status & ZFCP_STATUS_COMMON_RUNNING))) {
+ if (unlikely(status & ZFCP_STATUS_COMMON_ERP_FAILED) &&
+ !(atomic_read(&unit->port->status) &
+ ZFCP_STATUS_COMMON_ERP_FAILED)) {
+ /* only unit access denied, but port is good
+ * not covered by FC transport, have to fail here */
zfcp_scsi_command_fail(scpnt, DID_ERROR);
return 0;
}
+ if (unlikely(!(status & ZFCP_STATUS_COMMON_UNBLOCKED))) {
+ /* This could be either
+ * open unit pending: this is temporary, will result in
+ * open unit or ERP_FAILED, so retry command
+ * call to rport_delete pending: mimic retry from
+ * fc_remote_port_chkready until rport is BLOCKED
+ */
+ zfcp_scsi_command_fail(scpnt, DID_IMM_RETRY);
+ return 0;
+ }
+
ret = zfcp_fsf_send_fcp_command_task(unit, scpnt);
if (unlikely(ret == -EBUSY))
return SCSI_MLQUEUE_DEVICE_BUSY;
@@ -115,49 +133,44 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
}
static struct zfcp_unit *zfcp_unit_lookup(struct zfcp_adapter *adapter,
- int channel, unsigned int id,
- unsigned int lun)
+ unsigned int id, u64 lun)
{
+ unsigned long flags;
struct zfcp_port *port;
- struct zfcp_unit *unit;
- int scsi_lun;
+ struct zfcp_unit *unit = NULL;
- list_for_each_entry(port, &adapter->port_list_head, list) {
+ read_lock_irqsave(&adapter->port_list_lock, flags);
+ list_for_each_entry(port, &adapter->port_list, list) {
if (!port->rport || (id != port->rport->scsi_target_id))
continue;
- list_for_each_entry(unit, &port->unit_list_head, list) {
- scsi_lun = scsilun_to_int(
- (struct scsi_lun *)&unit->fcp_lun);
- if (lun == scsi_lun)
- return unit;
- }
+ unit = zfcp_get_unit_by_lun(port, lun);
+ if (unit)
+ break;
}
+ read_unlock_irqrestore(&adapter->port_list_lock, flags);
- return NULL;
+ return unit;
}
static int zfcp_scsi_slave_alloc(struct scsi_device *sdp)
{
struct zfcp_adapter *adapter;
struct zfcp_unit *unit;
- unsigned long flags;
- int retval = -ENXIO;
+ u64 lun;
adapter = (struct zfcp_adapter *) sdp->host->hostdata[0];
if (!adapter)
goto out;
- read_lock_irqsave(&zfcp_data.config_lock, flags);
- unit = zfcp_unit_lookup(adapter, sdp->channel, sdp->id, sdp->lun);
+ int_to_scsilun(sdp->lun, (struct scsi_lun *)&lun);
+ unit = zfcp_unit_lookup(adapter, sdp->id, lun);
if (unit) {
sdp->hostdata = unit;
unit->device = sdp;
- zfcp_unit_get(unit);
- retval = 0;
+ return 0;
}
- read_unlock_irqrestore(&zfcp_data.config_lock, flags);
out:
- return retval;
+ return -ENXIO;
}
static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
@@ -196,6 +209,7 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
break;
zfcp_erp_wait(adapter);
+ fc_block_scsi_eh(scpnt);
if (!(atomic_read(&adapter->status) &
ZFCP_STATUS_COMMON_RUNNING)) {
zfcp_dbf_scsi_abort("nres", adapter->dbf, scpnt, NULL,
@@ -235,6 +249,7 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags)
break;
zfcp_erp_wait(adapter);
+ fc_block_scsi_eh(scpnt);
if (!(atomic_read(&adapter->status) &
ZFCP_STATUS_COMMON_RUNNING)) {
zfcp_dbf_scsi_devreset("nres", tm_flags, unit, scpnt);
@@ -249,9 +264,6 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags)
if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) {
zfcp_dbf_scsi_devreset("fail", tm_flags, unit, scpnt);
retval = FAILED;
- } else if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP) {
- zfcp_dbf_scsi_devreset("nsup", tm_flags, unit, scpnt);
- retval = FAILED;
} else
zfcp_dbf_scsi_devreset("okay", tm_flags, unit, scpnt);
@@ -261,12 +273,12 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags)
static int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt)
{
- return zfcp_task_mgmt_function(scpnt, FCP_LOGICAL_UNIT_RESET);
+ return zfcp_task_mgmt_function(scpnt, FCP_TMF_LUN_RESET);
}
static int zfcp_scsi_eh_target_reset_handler(struct scsi_cmnd *scpnt)
{
- return zfcp_task_mgmt_function(scpnt, FCP_TARGET_RESET);
+ return zfcp_task_mgmt_function(scpnt, FCP_TMF_TGT_RESET);
}
static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
@@ -276,6 +288,7 @@ static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
zfcp_erp_adapter_reopen(adapter, 0, "schrh_1", scpnt);
zfcp_erp_wait(adapter);
+ fc_block_scsi_eh(scpnt);
return SUCCESS;
}
@@ -303,7 +316,7 @@ int zfcp_adapter_scsi_register(struct zfcp_adapter *adapter)
adapter->scsi_host->max_lun = 1;
adapter->scsi_host->max_channel = 0;
adapter->scsi_host->unique_id = dev_id.devno;
- adapter->scsi_host->max_cmd_len = 255;
+ adapter->scsi_host->max_cmd_len = 16; /* in struct fcp_cmnd */
adapter->scsi_host->transportt = zfcp_data.scsi_transport_template;
adapter->scsi_host->hostdata[0] = (unsigned long) adapter;
@@ -325,12 +338,11 @@ void zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter)
if (!shost)
return;
- read_lock_irq(&zfcp_data.config_lock);
- list_for_each_entry(port, &adapter->port_list_head, list)
- if (port->rport)
- port->rport = NULL;
+ read_lock_irq(&adapter->port_list_lock);
+ list_for_each_entry(port, &adapter->port_list, list)
+ port->rport = NULL;
+ read_unlock_irq(&adapter->port_list_lock);
- read_unlock_irq(&zfcp_data.config_lock);
fc_remove_host(shost);
scsi_remove_host(shost);
scsi_host_put(shost);
@@ -348,7 +360,7 @@ zfcp_init_fc_host_stats(struct zfcp_adapter *adapter)
fc_stats = kmalloc(sizeof(*fc_stats), GFP_KERNEL);
if (!fc_stats)
return NULL;
- adapter->fc_stats = fc_stats; /* freed in adater_dequeue */
+ adapter->fc_stats = fc_stats; /* freed in adapter_release */
}
memset(adapter->fc_stats, 0, sizeof(*adapter->fc_stats));
return adapter->fc_stats;
@@ -464,7 +476,7 @@ static void zfcp_reset_fc_host_stats(struct Scsi_Host *shost)
adapter->stats_reset = jiffies/HZ;
kfree(adapter->stats_reset_data);
adapter->stats_reset_data = data; /* finally freed in
- adapter_dequeue */
+ adapter_release */
}
}
@@ -495,7 +507,7 @@ static void zfcp_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout)
* @rport: The FC rport where to teminate I/O
*
* Abort all pending SCSI commands for a port by closing the
- * port. Using a reopen for avoids a conflict with a shutdown
+ * port. Using a reopen avoiding a conflict with a shutdown
* overwriting a reopen.
*/
static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport)
@@ -505,15 +517,11 @@ static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport)
struct zfcp_adapter *adapter =
(struct zfcp_adapter *)shost->hostdata[0];
- write_lock_irq(&zfcp_data.config_lock);
port = zfcp_get_port_by_wwpn(adapter, rport->port_name);
- if (port)
- zfcp_port_get(port);
- write_unlock_irq(&zfcp_data.config_lock);
if (port) {
zfcp_erp_port_reopen(port, 0, "sctrpi1", NULL);
- zfcp_port_put(port);
+ put_device(&port->sysfs_device);
}
}
@@ -555,31 +563,34 @@ static void zfcp_scsi_rport_block(struct zfcp_port *port)
void zfcp_scsi_schedule_rport_register(struct zfcp_port *port)
{
- zfcp_port_get(port);
+ get_device(&port->sysfs_device);
port->rport_task = RPORT_ADD;
if (!queue_work(port->adapter->work_queue, &port->rport_work))
- zfcp_port_put(port);
+ put_device(&port->sysfs_device);
}
void zfcp_scsi_schedule_rport_block(struct zfcp_port *port)
{
- zfcp_port_get(port);
+ get_device(&port->sysfs_device);
port->rport_task = RPORT_DEL;
if (port->rport && queue_work(port->adapter->work_queue,
&port->rport_work))
return;
- zfcp_port_put(port);
+ put_device(&port->sysfs_device);
}
void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *adapter)
{
+ unsigned long flags;
struct zfcp_port *port;
- list_for_each_entry(port, &adapter->port_list_head, list)
+ read_lock_irqsave(&adapter->port_list_lock, flags);
+ list_for_each_entry(port, &adapter->port_list, list)
zfcp_scsi_schedule_rport_block(port);
+ read_unlock_irqrestore(&adapter->port_list_lock, flags);
}
void zfcp_scsi_rport_work(struct work_struct *work)
@@ -597,7 +608,7 @@ void zfcp_scsi_rport_work(struct work_struct *work)
}
}
- zfcp_port_put(port);
+ put_device(&port->sysfs_device);
}
@@ -615,21 +626,7 @@ void zfcp_scsi_scan(struct work_struct *work)
scsilun_to_int((struct scsi_lun *)
&unit->fcp_lun), 0);
- zfcp_unit_put(unit);
-}
-
-static int zfcp_execute_fc_job(struct fc_bsg_job *job)
-{
- switch (job->request->msgcode) {
- case FC_BSG_RPT_ELS:
- case FC_BSG_HST_ELS_NOLOGIN:
- return zfcp_fc_execute_els_fc_job(job);
- case FC_BSG_RPT_CT:
- case FC_BSG_HST_CT:
- return zfcp_fc_execute_ct_fc_job(job);
- default:
- return -EINVAL;
- }
+ put_device(&unit->sysfs_device);
}
struct fc_function_template zfcp_transport_functions = {
@@ -643,6 +640,7 @@ struct fc_function_template zfcp_transport_functions = {
.show_host_port_name = 1,
.show_host_permanent_port_name = 1,
.show_host_supported_classes = 1,
+ .show_host_supported_fc4s = 1,
.show_host_supported_speeds = 1,
.show_host_maxframe_size = 1,
.show_host_serial_number = 1,
@@ -652,13 +650,15 @@ struct fc_function_template zfcp_transport_functions = {
.get_host_port_state = zfcp_get_host_port_state,
.terminate_rport_io = zfcp_scsi_terminate_rport_io,
.show_host_port_state = 1,
- .bsg_request = zfcp_execute_fc_job,
+ .show_host_active_fc4s = 1,
+ .bsg_request = zfcp_fc_exec_bsg_job,
/* no functions registered for following dynamic attributes but
directly set by LLDD */
.show_host_port_type = 1,
.show_host_speed = 1,
.show_host_port_id = 1,
.disable_target_scan = 1,
+ .dd_bsg_size = sizeof(struct zfcp_fsf_ct_els),
};
struct zfcp_data zfcp_data = {
diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c
index d310008..f539e00 100644
--- a/drivers/s390/scsi/zfcp_sysfs.c
+++ b/drivers/s390/scsi/zfcp_sysfs.c
@@ -3,7 +3,7 @@
*
* sysfs attributes.
*
- * Copyright IBM Corporation 2008
+ * Copyright IBM Corporation 2008, 2009
*/
#define KMSG_COMPONENT "zfcp"
@@ -19,30 +19,44 @@ static ssize_t zfcp_sysfs_##_feat##_##_name##_show(struct device *dev, \
struct device_attribute *at,\
char *buf) \
{ \
- struct _feat_def *_feat = dev_get_drvdata(dev); \
+ struct _feat_def *_feat = container_of(dev, struct _feat_def, \
+ sysfs_device); \
\
return sprintf(buf, _format, _value); \
} \
static ZFCP_DEV_ATTR(_feat, _name, S_IRUGO, \
zfcp_sysfs_##_feat##_##_name##_show, NULL);
-ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, status, "0x%08x\n",
- atomic_read(&adapter->status));
-ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, peer_wwnn, "0x%016llx\n",
- (unsigned long long) adapter->peer_wwnn);
-ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, peer_wwpn, "0x%016llx\n",
- (unsigned long long) adapter->peer_wwpn);
-ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, peer_d_id, "0x%06x\n",
- adapter->peer_d_id);
-ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, card_version, "0x%04x\n",
- adapter->hydra_version);
-ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, lic_version, "0x%08x\n",
- adapter->fsf_lic_version);
-ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, hardware_version, "0x%08x\n",
- adapter->hardware_version);
-ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, in_recovery, "%d\n",
- (atomic_read(&adapter->status) &
- ZFCP_STATUS_COMMON_ERP_INUSE) != 0);
+#define ZFCP_DEFINE_A_ATTR(_name, _format, _value) \
+static ssize_t zfcp_sysfs_adapter_##_name##_show(struct device *dev, \
+ struct device_attribute *at,\
+ char *buf) \
+{ \
+ struct ccw_device *cdev = to_ccwdev(dev); \
+ struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); \
+ int i; \
+ \
+ if (!adapter) \
+ return -ENODEV; \
+ \
+ i = sprintf(buf, _format, _value); \
+ zfcp_ccw_adapter_put(adapter); \
+ return i; \
+} \
+static ZFCP_DEV_ATTR(adapter, _name, S_IRUGO, \
+ zfcp_sysfs_adapter_##_name##_show, NULL);
+
+ZFCP_DEFINE_A_ATTR(status, "0x%08x\n", atomic_read(&adapter->status));
+ZFCP_DEFINE_A_ATTR(peer_wwnn, "0x%016llx\n",
+ (unsigned long long) adapter->peer_wwnn);
+ZFCP_DEFINE_A_ATTR(peer_wwpn, "0x%016llx\n",
+ (unsigned long long) adapter->peer_wwpn);
+ZFCP_DEFINE_A_ATTR(peer_d_id, "0x%06x\n", adapter->peer_d_id);
+ZFCP_DEFINE_A_ATTR(card_version, "0x%04x\n", adapter->hydra_version);
+ZFCP_DEFINE_A_ATTR(lic_version, "0x%08x\n", adapter->fsf_lic_version);
+ZFCP_DEFINE_A_ATTR(hardware_version, "0x%08x\n", adapter->hardware_version);
+ZFCP_DEFINE_A_ATTR(in_recovery, "%d\n", (atomic_read(&adapter->status) &
+ ZFCP_STATUS_COMMON_ERP_INUSE) != 0);
ZFCP_DEFINE_ATTR(zfcp_port, port, status, "0x%08x\n",
atomic_read(&port->status));
@@ -73,7 +87,8 @@ static ssize_t zfcp_sysfs_##_feat##_failed_show(struct device *dev, \
struct device_attribute *attr, \
char *buf) \
{ \
- struct _feat_def *_feat = dev_get_drvdata(dev); \
+ struct _feat_def *_feat = container_of(dev, struct _feat_def, \
+ sysfs_device); \
\
if (atomic_read(&_feat->status) & ZFCP_STATUS_COMMON_ERP_FAILED) \
return sprintf(buf, "1\n"); \
@@ -84,15 +99,13 @@ static ssize_t zfcp_sysfs_##_feat##_failed_store(struct device *dev, \
struct device_attribute *attr,\
const char *buf, size_t count)\
{ \
- struct _feat_def *_feat = dev_get_drvdata(dev); \
+ struct _feat_def *_feat = container_of(dev, struct _feat_def, \
+ sysfs_device); \
unsigned long val; \
int retval = 0; \
\
- mutex_lock(&zfcp_data.config_mutex); \
- if (atomic_read(&_feat->status) & ZFCP_STATUS_COMMON_REMOVE) { \
- retval = -EBUSY; \
- goto out; \
- } \
+ if (!(_feat && get_device(&_feat->sysfs_device))) \
+ return -EBUSY; \
\
if (strict_strtoul(buf, 0, &val) || val != 0) { \
retval = -EINVAL; \
@@ -105,29 +118,82 @@ static ssize_t zfcp_sysfs_##_feat##_failed_store(struct device *dev, \
_reopen_id, NULL); \
zfcp_erp_wait(_adapter); \
out: \
- mutex_unlock(&zfcp_data.config_mutex); \
+ put_device(&_feat->sysfs_device); \
return retval ? retval : (ssize_t) count; \
} \
static ZFCP_DEV_ATTR(_feat, failed, S_IWUSR | S_IRUGO, \
zfcp_sysfs_##_feat##_failed_show, \
zfcp_sysfs_##_feat##_failed_store);
-ZFCP_SYSFS_FAILED(zfcp_adapter, adapter, adapter, "syafai1", "syafai2");
ZFCP_SYSFS_FAILED(zfcp_port, port, port->adapter, "sypfai1", "sypfai2");
ZFCP_SYSFS_FAILED(zfcp_unit, unit, unit->port->adapter, "syufai1", "syufai2");
+static ssize_t zfcp_sysfs_adapter_failed_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ccw_device *cdev = to_ccwdev(dev);
+ struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);
+ int i;
+
+ if (!adapter)
+ return -ENODEV;
+
+ if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
+ i = sprintf(buf, "1\n");
+ else
+ i = sprintf(buf, "0\n");
+
+ zfcp_ccw_adapter_put(adapter);
+ return i;
+}
+
+static ssize_t zfcp_sysfs_adapter_failed_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ccw_device *cdev = to_ccwdev(dev);
+ struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);
+ unsigned long val;
+ int retval = 0;
+
+ if (!adapter)
+ return -ENODEV;
+
+ if (strict_strtoul(buf, 0, &val) || val != 0) {
+ retval = -EINVAL;
+ goto out;
+ }
+
+ zfcp_erp_modify_adapter_status(adapter, "syafai1", NULL,
+ ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET);
+ zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
+ "syafai2", NULL);
+ zfcp_erp_wait(adapter);
+out:
+ zfcp_ccw_adapter_put(adapter);
+ return retval ? retval : (ssize_t) count;
+}
+static ZFCP_DEV_ATTR(adapter, failed, S_IWUSR | S_IRUGO,
+ zfcp_sysfs_adapter_failed_show,
+ zfcp_sysfs_adapter_failed_store);
+
static ssize_t zfcp_sysfs_port_rescan_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct zfcp_adapter *adapter = dev_get_drvdata(dev);
- int ret;
+ struct ccw_device *cdev = to_ccwdev(dev);
+ struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);
- if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_REMOVE)
- return -EBUSY;
+ if (!adapter)
+ return -ENODEV;
- ret = zfcp_fc_scan_ports(adapter);
- return ret ? ret : (ssize_t) count;
+ /* sync the user-space- with the kernel-invocation of scan_work */
+ queue_work(adapter->work_queue, &adapter->scan_work);
+ flush_work(&adapter->scan_work);
+ zfcp_ccw_adapter_put(adapter);
+
+ return (ssize_t) count;
}
static ZFCP_DEV_ATTR(adapter, port_rescan, S_IWUSR, NULL,
zfcp_sysfs_port_rescan_store);
@@ -136,44 +202,34 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct zfcp_adapter *adapter = dev_get_drvdata(dev);
+ struct ccw_device *cdev = to_ccwdev(dev);
+ struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);
struct zfcp_port *port;
u64 wwpn;
- int retval = 0;
- LIST_HEAD(port_remove_lh);
+ int retval = -EINVAL;
- mutex_lock(&zfcp_data.config_mutex);
- if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_REMOVE) {
- retval = -EBUSY;
- goto out;
- }
+ if (!adapter)
+ return -ENODEV;
- if (strict_strtoull(buf, 0, (unsigned long long *) &wwpn)) {
- retval = -EINVAL;
+ if (strict_strtoull(buf, 0, (unsigned long long *) &wwpn))
goto out;
- }
- write_lock_irq(&zfcp_data.config_lock);
port = zfcp_get_port_by_wwpn(adapter, wwpn);
- if (port && (atomic_read(&port->refcount) == 0)) {
- zfcp_port_get(port);
- atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status);
- list_move(&port->list, &port_remove_lh);
- } else
- port = NULL;
- write_unlock_irq(&zfcp_data.config_lock);
-
- if (!port) {
- retval = -ENXIO;
+ if (!port)
goto out;
- }
+ else
+ retval = 0;
+
+ write_lock_irq(&adapter->port_list_lock);
+ list_del(&port->list);
+ write_unlock_irq(&adapter->port_list_lock);
+
+ put_device(&port->sysfs_device);
zfcp_erp_port_shutdown(port, 0, "syprs_1", NULL);
- zfcp_erp_wait(adapter);
- zfcp_port_put(port);
- zfcp_port_dequeue(port);
+ zfcp_device_unregister(&port->sysfs_device, &zfcp_sysfs_port_attrs);
out:
- mutex_unlock(&zfcp_data.config_mutex);
+ zfcp_ccw_adapter_put(adapter);
return retval ? retval : (ssize_t) count;
}
static ZFCP_DEV_ATTR(adapter, port_remove, S_IWUSR, NULL,
@@ -202,16 +258,14 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct zfcp_port *port = dev_get_drvdata(dev);
+ struct zfcp_port *port = container_of(dev, struct zfcp_port,
+ sysfs_device);
struct zfcp_unit *unit;
u64 fcp_lun;
int retval = -EINVAL;
- mutex_lock(&zfcp_data.config_mutex);
- if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE) {
- retval = -EBUSY;
- goto out;
- }
+ if (!(port && get_device(&port->sysfs_device)))
+ return -EBUSY;
if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun))
goto out;
@@ -219,15 +273,14 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev,
unit = zfcp_unit_enqueue(port, fcp_lun);
if (IS_ERR(unit))
goto out;
-
- retval = 0;
+ else
+ retval = 0;
zfcp_erp_unit_reopen(unit, 0, "syuas_1", NULL);
zfcp_erp_wait(unit->port->adapter);
flush_work(&unit->scsi_work);
- zfcp_unit_put(unit);
out:
- mutex_unlock(&zfcp_data.config_mutex);
+ put_device(&port->sysfs_device);
return retval ? retval : (ssize_t) count;
}
static DEVICE_ATTR(unit_add, S_IWUSR, NULL, zfcp_sysfs_unit_add_store);
@@ -236,54 +289,37 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct zfcp_port *port = dev_get_drvdata(dev);
+ struct zfcp_port *port = container_of(dev, struct zfcp_port,
+ sysfs_device);
struct zfcp_unit *unit;
u64 fcp_lun;
- int retval = 0;
- LIST_HEAD(unit_remove_lh);
+ int retval = -EINVAL;
- mutex_lock(&zfcp_data.config_mutex);
- if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE) {
- retval = -EBUSY;
- goto out;
- }
+ if (!(port && get_device(&port->sysfs_device)))
+ return -EBUSY;
- if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun)) {
- retval = -EINVAL;
+ if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun))
goto out;
- }
- write_lock_irq(&zfcp_data.config_lock);
unit = zfcp_get_unit_by_lun(port, fcp_lun);
- if (unit) {
- write_unlock_irq(&zfcp_data.config_lock);
- /* wait for possible timeout during SCSI probe */
- flush_work(&unit->scsi_work);
- write_lock_irq(&zfcp_data.config_lock);
-
- if (atomic_read(&unit->refcount) == 0) {
- zfcp_unit_get(unit);
- atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE,
- &unit->status);
- list_move(&unit->list, &unit_remove_lh);
- } else {
- unit = NULL;
- }
- }
+ if (!unit)
+ goto out;
+ else
+ retval = 0;
- write_unlock_irq(&zfcp_data.config_lock);
+ /* wait for possible timeout during SCSI probe */
+ flush_work(&unit->scsi_work);
- if (!unit) {
- retval = -ENXIO;
- goto out;
- }
+ write_lock_irq(&port->unit_list_lock);
+ list_del(&unit->list);
+ write_unlock_irq(&port->unit_list_lock);
+
+ put_device(&unit->sysfs_device);
zfcp_erp_unit_shutdown(unit, 0, "syurs_1", NULL);
- zfcp_erp_wait(unit->port->adapter);
- zfcp_unit_put(unit);
- zfcp_unit_dequeue(unit);
+ zfcp_device_unregister(&unit->sysfs_device, &zfcp_sysfs_unit_attrs);
out:
- mutex_unlock(&zfcp_data.config_mutex);
+ put_device(&port->sysfs_device);
return retval ? retval : (ssize_t) count;
}
static DEVICE_ATTR(unit_remove, S_IWUSR, NULL, zfcp_sysfs_unit_remove_store);
diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c
index 58e583b..aa2b60a 100644
--- a/drivers/sbus/char/envctrl.c
+++ b/drivers/sbus/char/envctrl.c
@@ -92,11 +92,11 @@
#define ENVCTRL_CPUTEMP_MON 1 /* cpu temperature monitor */
#define ENVCTRL_CPUVOLTAGE_MON 2 /* voltage monitor */
#define ENVCTRL_FANSTAT_MON 3 /* fan status monitor */
-#define ENVCTRL_ETHERTEMP_MON 4 /* ethernet temperarture */
+#define ENVCTRL_ETHERTEMP_MON 4 /* ethernet temperature */
/* monitor */
#define ENVCTRL_VOLTAGESTAT_MON 5 /* voltage status monitor */
#define ENVCTRL_MTHRBDTEMP_MON 6 /* motherboard temperature */
-#define ENVCTRL_SCSITEMP_MON 7 /* scsi temperarture */
+#define ENVCTRL_SCSITEMP_MON 7 /* scsi temperature */
#define ENVCTRL_GLOBALADDR_MON 8 /* global address */
/* Child device type.
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c
index 36c21b1..3bf7592 100644
--- a/drivers/scsi/3w-9xxx.c
+++ b/drivers/scsi/3w-9xxx.c
@@ -186,8 +186,12 @@ static ssize_t twa_show_stats(struct device *dev,
} /* End twa_show_stats() */
/* This function will set a devices queue depth */
-static int twa_change_queue_depth(struct scsi_device *sdev, int queue_depth)
+static int twa_change_queue_depth(struct scsi_device *sdev, int queue_depth,
+ int reason)
{
+ if (reason != SCSI_QDEPTH_DEFAULT)
+ return -EOPNOTSUPP;
+
if (queue_depth > TW_Q_LENGTH-2)
queue_depth = TW_Q_LENGTH-2;
scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
@@ -732,7 +736,7 @@ static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int
break;
case TW_IOCTL_GET_COMPATIBILITY_INFO:
tw_ioctl->driver_command.status = 0;
- /* Copy compatiblity struct into ioctl data buffer */
+ /* Copy compatibility struct into ioctl data buffer */
tw_compat_info = (TW_Compatibility_Info *)tw_ioctl->data_buffer;
memcpy(tw_compat_info, &tw_dev->tw_compat_info, sizeof(TW_Compatibility_Info));
break;
diff --git a/drivers/scsi/3w-sas.c b/drivers/scsi/3w-sas.c
new file mode 100644
index 0000000..4d314d7
--- /dev/null
+++ b/drivers/scsi/3w-sas.c
@@ -0,0 +1,1924 @@
+/*
+ 3w-sas.c -- LSI 3ware SAS/SATA-RAID Controller device driver for Linux.
+
+ Written By: Adam Radford <linuxraid@lsi.com>
+
+ Copyright (C) 2009 LSI Corporation.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; 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
+
+ Controllers supported by this driver:
+
+ LSI 3ware 9750 6Gb/s SAS/SATA-RAID
+
+ Bugs/Comments/Suggestions should be mailed to:
+ linuxraid@lsi.com
+
+ For more information, goto:
+ http://www.lsi.com
+
+ History
+ -------
+ 3.26.02.000 - Initial driver release.
+*/
+
+#include <linux/module.h>
+#include <linux/reboot.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/moduleparam.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/time.h>
+#include <linux/mutex.h>
+#include <linux/smp_lock.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_cmnd.h>
+#include "3w-sas.h"
+
+/* Globals */
+#define TW_DRIVER_VERSION "3.26.02.000"
+static TW_Device_Extension *twl_device_extension_list[TW_MAX_SLOT];
+static unsigned int twl_device_extension_count;
+static int twl_major = -1;
+extern struct timezone sys_tz;
+
+/* Module parameters */
+MODULE_AUTHOR ("LSI");
+MODULE_DESCRIPTION ("LSI 3ware SAS/SATA-RAID Linux Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(TW_DRIVER_VERSION);
+
+static int use_msi;
+module_param(use_msi, int, S_IRUGO);
+MODULE_PARM_DESC(use_msi, "Use Message Signaled Interrupts. Default: 0");
+
+/* Function prototypes */
+static int twl_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset);
+
+/* Functions */
+
+/* This function returns AENs through sysfs */
+static ssize_t twl_sysfs_aen_read(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *outbuf, loff_t offset, size_t count)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct Scsi_Host *shost = class_to_shost(dev);
+ TW_Device_Extension *tw_dev = (TW_Device_Extension *)shost->hostdata;
+ unsigned long flags = 0;
+ ssize_t ret;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ spin_lock_irqsave(tw_dev->host->host_lock, flags);
+ ret = memory_read_from_buffer(outbuf, count, &offset, tw_dev->event_queue[0], sizeof(TW_Event) * TW_Q_LENGTH);
+ spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
+
+ return ret;
+} /* End twl_sysfs_aen_read() */
+
+/* aen_read sysfs attribute initializer */
+static struct bin_attribute twl_sysfs_aen_read_attr = {
+ .attr = {
+ .name = "3ware_aen_read",
+ .mode = S_IRUSR,
+ },
+ .size = 0,
+ .read = twl_sysfs_aen_read
+};
+
+/* This function returns driver compatibility info through sysfs */
+static ssize_t twl_sysfs_compat_info(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *outbuf, loff_t offset, size_t count)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct Scsi_Host *shost = class_to_shost(dev);
+ TW_Device_Extension *tw_dev = (TW_Device_Extension *)shost->hostdata;
+ unsigned long flags = 0;
+ ssize_t ret;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ spin_lock_irqsave(tw_dev->host->host_lock, flags);
+ ret = memory_read_from_buffer(outbuf, count, &offset, &tw_dev->tw_compat_info, sizeof(TW_Compatibility_Info));
+ spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
+
+ return ret;
+} /* End twl_sysfs_compat_info() */
+
+/* compat_info sysfs attribute initializer */
+static struct bin_attribute twl_sysfs_compat_info_attr = {
+ .attr = {
+ .name = "3ware_compat_info",
+ .mode = S_IRUSR,
+ },
+ .size = 0,
+ .read = twl_sysfs_compat_info
+};
+
+/* Show some statistics about the card */
+static ssize_t twl_show_stats(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *host = class_to_shost(dev);
+ TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
+ unsigned long flags = 0;
+ ssize_t len;
+
+ spin_lock_irqsave(tw_dev->host->host_lock, flags);
+ len = snprintf(buf, PAGE_SIZE, "3w-sas Driver version: %s\n"
+ "Current commands posted: %4d\n"
+ "Max commands posted: %4d\n"
+ "Last sgl length: %4d\n"
+ "Max sgl length: %4d\n"
+ "Last sector count: %4d\n"
+ "Max sector count: %4d\n"
+ "SCSI Host Resets: %4d\n"
+ "AEN's: %4d\n",
+ TW_DRIVER_VERSION,
+ tw_dev->posted_request_count,
+ tw_dev->max_posted_request_count,
+ tw_dev->sgl_entries,
+ tw_dev->max_sgl_entries,
+ tw_dev->sector_count,
+ tw_dev->max_sector_count,
+ tw_dev->num_resets,
+ tw_dev->aen_count);
+ spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
+ return len;
+} /* End twl_show_stats() */
+
+/* This function will set a devices queue depth */
+static int twl_change_queue_depth(struct scsi_device *sdev, int queue_depth,
+ int reason)
+{
+ if (reason != SCSI_QDEPTH_DEFAULT)
+ return -EOPNOTSUPP;
+
+ if (queue_depth > TW_Q_LENGTH-2)
+ queue_depth = TW_Q_LENGTH-2;
+ scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
+ return queue_depth;
+} /* End twl_change_queue_depth() */
+
+/* stats sysfs attribute initializer */
+static struct device_attribute twl_host_stats_attr = {
+ .attr = {
+ .name = "3ware_stats",
+ .mode = S_IRUGO,
+ },
+ .show = twl_show_stats
+};
+
+/* Host attributes initializer */
+static struct device_attribute *twl_host_attrs[] = {
+ &twl_host_stats_attr,
+ NULL,
+};
+
+/* This function will look up an AEN severity string */
+static char *twl_aen_severity_lookup(unsigned char severity_code)
+{
+ char *retval = NULL;
+
+ if ((severity_code < (unsigned char) TW_AEN_SEVERITY_ERROR) ||
+ (severity_code > (unsigned char) TW_AEN_SEVERITY_DEBUG))
+ goto out;
+
+ retval = twl_aen_severity_table[severity_code];
+out:
+ return retval;
+} /* End twl_aen_severity_lookup() */
+
+/* This function will queue an event */
+static void twl_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_Header *header)
+{
+ u32 local_time;
+ struct timeval time;
+ TW_Event *event;
+ unsigned short aen;
+ char host[16];
+ char *error_str;
+
+ tw_dev->aen_count++;
+
+ /* Fill out event info */
+ event = tw_dev->event_queue[tw_dev->error_index];
+
+ host[0] = '\0';
+ if (tw_dev->host)
+ sprintf(host, " scsi%d:", tw_dev->host->host_no);
+
+ aen = le16_to_cpu(header->status_block.error);
+ memset(event, 0, sizeof(TW_Event));
+
+ event->severity = TW_SEV_OUT(header->status_block.severity__reserved);
+ do_gettimeofday(&time);
+ local_time = (u32)(time.tv_sec - (sys_tz.tz_minuteswest * 60));
+ event->time_stamp_sec = local_time;
+ event->aen_code = aen;
+ event->retrieved = TW_AEN_NOT_RETRIEVED;
+ event->sequence_id = tw_dev->error_sequence_id;
+ tw_dev->error_sequence_id++;
+
+ /* Check for embedded error string */
+ error_str = &(header->err_specific_desc[strlen(header->err_specific_desc)+1]);
+
+ header->err_specific_desc[sizeof(header->err_specific_desc) - 1] = '\0';
+ event->parameter_len = strlen(header->err_specific_desc);
+ memcpy(event->parameter_data, header->err_specific_desc, event->parameter_len + 1 + strlen(error_str));
+ if (event->severity != TW_AEN_SEVERITY_DEBUG)
+ printk(KERN_WARNING "3w-sas:%s AEN: %s (0x%02X:0x%04X): %s:%s.\n",
+ host,
+ twl_aen_severity_lookup(TW_SEV_OUT(header->status_block.severity__reserved)),
+ TW_MESSAGE_SOURCE_CONTROLLER_EVENT, aen, error_str,
+ header->err_specific_desc);
+ else
+ tw_dev->aen_count--;
+
+ tw_dev->error_index = (tw_dev->error_index + 1 ) % TW_Q_LENGTH;
+} /* End twl_aen_queue_event() */
+
+/* This function will attempt to post a command packet to the board */
+static int twl_post_command_packet(TW_Device_Extension *tw_dev, int request_id)
+{
+ dma_addr_t command_que_value;
+
+ command_que_value = tw_dev->command_packet_phys[request_id];
+ command_que_value += TW_COMMAND_OFFSET;
+
+ /* First write upper 4 bytes */
+ writel((u32)((u64)command_que_value >> 32), TWL_HIBQPH_REG_ADDR(tw_dev));
+ /* Then the lower 4 bytes */
+ writel((u32)(command_que_value | TWL_PULL_MODE), TWL_HIBQPL_REG_ADDR(tw_dev));
+
+ tw_dev->state[request_id] = TW_S_POSTED;
+ tw_dev->posted_request_count++;
+ if (tw_dev->posted_request_count > tw_dev->max_posted_request_count)
+ tw_dev->max_posted_request_count = tw_dev->posted_request_count;
+
+ return 0;
+} /* End twl_post_command_packet() */
+
+/* This function will perform a pci-dma mapping for a scatter gather list */
+static int twl_map_scsi_sg_data(TW_Device_Extension *tw_dev, int request_id)
+{
+ int use_sg;
+ struct scsi_cmnd *cmd = tw_dev->srb[request_id];
+
+ use_sg = scsi_dma_map(cmd);
+ if (!use_sg)
+ return 0;
+ else if (use_sg < 0) {
+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1, "Failed to map scatter gather list");
+ return 0;
+ }
+
+ cmd->SCp.phase = TW_PHASE_SGLIST;
+ cmd->SCp.have_data_in = use_sg;
+
+ return use_sg;
+} /* End twl_map_scsi_sg_data() */
+
+/* This function hands scsi cdb's to the firmware */
+static int twl_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry_ISO *sglistarg)
+{
+ TW_Command_Full *full_command_packet;
+ TW_Command_Apache *command_packet;
+ int i, sg_count;
+ struct scsi_cmnd *srb = NULL;
+ struct scatterlist *sglist = NULL, *sg;
+ int retval = 1;
+
+ if (tw_dev->srb[request_id]) {
+ srb = tw_dev->srb[request_id];
+ if (scsi_sglist(srb))
+ sglist = scsi_sglist(srb);
+ }
+
+ /* Initialize command packet */
+ full_command_packet = tw_dev->command_packet_virt[request_id];
+ full_command_packet->header.header_desc.size_header = 128;
+ full_command_packet->header.status_block.error = 0;
+ full_command_packet->header.status_block.severity__reserved = 0;
+
+ command_packet = &full_command_packet->command.newcommand;
+ command_packet->status = 0;
+ command_packet->opcode__reserved = TW_OPRES_IN(0, TW_OP_EXECUTE_SCSI);
+
+ /* We forced 16 byte cdb use earlier */
+ if (!cdb)
+ memcpy(command_packet->cdb, srb->cmnd, TW_MAX_CDB_LEN);
+ else
+ memcpy(command_packet->cdb, cdb, TW_MAX_CDB_LEN);
+
+ if (srb) {
+ command_packet->unit = srb->device->id;
+ command_packet->request_id__lunl =
+ cpu_to_le16(TW_REQ_LUN_IN(srb->device->lun, request_id));
+ } else {
+ command_packet->request_id__lunl =
+ cpu_to_le16(TW_REQ_LUN_IN(0, request_id));
+ command_packet->unit = 0;
+ }
+
+ command_packet->sgl_offset = 16;
+
+ if (!sglistarg) {
+ /* Map sglist from scsi layer to cmd packet */
+ if (scsi_sg_count(srb)) {
+ sg_count = twl_map_scsi_sg_data(tw_dev, request_id);
+ if (sg_count == 0)
+ goto out;
+
+ scsi_for_each_sg(srb, sg, sg_count, i) {
+ command_packet->sg_list[i].address = TW_CPU_TO_SGL(sg_dma_address(sg));
+ command_packet->sg_list[i].length = TW_CPU_TO_SGL(sg_dma_len(sg));
+ }
+ command_packet->sgl_entries__lunh = cpu_to_le16(TW_REQ_LUN_IN((srb->device->lun >> 4), scsi_sg_count(tw_dev->srb[request_id])));
+ }
+ } else {
+ /* Internal cdb post */
+ for (i = 0; i < use_sg; i++) {
+ command_packet->sg_list[i].address = TW_CPU_TO_SGL(sglistarg[i].address);
+ command_packet->sg_list[i].length = TW_CPU_TO_SGL(sglistarg[i].length);
+ }
+ command_packet->sgl_entries__lunh = cpu_to_le16(TW_REQ_LUN_IN(0, use_sg));
+ }
+
+ /* Update some stats */
+ if (srb) {
+ tw_dev->sector_count = scsi_bufflen(srb) / 512;
+ if (tw_dev->sector_count > tw_dev->max_sector_count)
+ tw_dev->max_sector_count = tw_dev->sector_count;
+ tw_dev->sgl_entries = scsi_sg_count(srb);
+ if (tw_dev->sgl_entries > tw_dev->max_sgl_entries)
+ tw_dev->max_sgl_entries = tw_dev->sgl_entries;
+ }
+
+ /* Now post the command to the board */
+ retval = twl_post_command_packet(tw_dev, request_id);
+
+out:
+ return retval;
+} /* End twl_scsiop_execute_scsi() */
+
+/* This function will read the aen queue from the isr */
+static int twl_aen_read_queue(TW_Device_Extension *tw_dev, int request_id)
+{
+ char cdb[TW_MAX_CDB_LEN];
+ TW_SG_Entry_ISO sglist[1];
+ TW_Command_Full *full_command_packet;
+ int retval = 1;
+
+ full_command_packet = tw_dev->command_packet_virt[request_id];
+ memset(full_command_packet, 0, sizeof(TW_Command_Full));
+
+ /* Initialize cdb */
+ memset(&cdb, 0, TW_MAX_CDB_LEN);
+ cdb[0] = REQUEST_SENSE; /* opcode */
+ cdb[4] = TW_ALLOCATION_LENGTH; /* allocation length */
+
+ /* Initialize sglist */
+ memset(&sglist, 0, sizeof(TW_SG_Entry_ISO));
+ sglist[0].length = TW_SECTOR_SIZE;
+ sglist[0].address = tw_dev->generic_buffer_phys[request_id];
+
+ /* Mark internal command */
+ tw_dev->srb[request_id] = NULL;
+
+ /* Now post the command packet */
+ if (twl_scsiop_execute_scsi(tw_dev, request_id, cdb, 1, sglist)) {
+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2, "Post failed while reading AEN queue");
+ goto out;
+ }
+ retval = 0;
+out:
+ return retval;
+} /* End twl_aen_read_queue() */
+
+/* This function will sync firmware time with the host time */
+static void twl_aen_sync_time(TW_Device_Extension *tw_dev, int request_id)
+{
+ u32 schedulertime;
+ struct timeval utc;
+ TW_Command_Full *full_command_packet;
+ TW_Command *command_packet;
+ TW_Param_Apache *param;
+ u32 local_time;
+
+ /* Fill out the command packet */
+ full_command_packet = tw_dev->command_packet_virt[request_id];
+ memset(full_command_packet, 0, sizeof(TW_Command_Full));
+ command_packet = &full_command_packet->command.oldcommand;
+ command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_SET_PARAM);
+ command_packet->request_id = request_id;
+ command_packet->byte8_offset.param.sgl[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]);
+ command_packet->byte8_offset.param.sgl[0].length = TW_CPU_TO_SGL(TW_SECTOR_SIZE);
+ command_packet->size = TW_COMMAND_SIZE;
+ command_packet->byte6_offset.parameter_count = cpu_to_le16(1);
+
+ /* Setup the param */
+ param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id];
+ memset(param, 0, TW_SECTOR_SIZE);
+ param->table_id = cpu_to_le16(TW_TIMEKEEP_TABLE | 0x8000); /* Controller time keep table */
+ param->parameter_id = cpu_to_le16(0x3); /* SchedulerTime */
+ param->parameter_size_bytes = cpu_to_le16(4);
+
+ /* Convert system time in UTC to local time seconds since last
+ Sunday 12:00AM */
+ do_gettimeofday(&utc);
+ local_time = (u32)(utc.tv_sec - (sys_tz.tz_minuteswest * 60));
+ schedulertime = local_time - (3 * 86400);
+ schedulertime = cpu_to_le32(schedulertime % 604800);
+
+ memcpy(param->data, &schedulertime, sizeof(u32));
+
+ /* Mark internal command */
+ tw_dev->srb[request_id] = NULL;
+
+ /* Now post the command */
+ twl_post_command_packet(tw_dev, request_id);
+} /* End twl_aen_sync_time() */
+
+/* This function will assign an available request id */
+static void twl_get_request_id(TW_Device_Extension *tw_dev, int *request_id)
+{
+ *request_id = tw_dev->free_queue[tw_dev->free_head];
+ tw_dev->free_head = (tw_dev->free_head + 1) % TW_Q_LENGTH;
+ tw_dev->state[*request_id] = TW_S_STARTED;
+} /* End twl_get_request_id() */
+
+/* This function will free a request id */
+static void twl_free_request_id(TW_Device_Extension *tw_dev, int request_id)
+{
+ tw_dev->free_queue[tw_dev->free_tail] = request_id;
+ tw_dev->state[request_id] = TW_S_FINISHED;
+ tw_dev->free_tail = (tw_dev->free_tail + 1) % TW_Q_LENGTH;
+} /* End twl_free_request_id() */
+
+/* This function will complete an aen request from the isr */
+static int twl_aen_complete(TW_Device_Extension *tw_dev, int request_id)
+{
+ TW_Command_Full *full_command_packet;
+ TW_Command *command_packet;
+ TW_Command_Apache_Header *header;
+ unsigned short aen;
+ int retval = 1;
+
+ header = (TW_Command_Apache_Header *)tw_dev->generic_buffer_virt[request_id];
+ tw_dev->posted_request_count--;
+ aen = le16_to_cpu(header->status_block.error);
+ full_command_packet = tw_dev->command_packet_virt[request_id];
+ command_packet = &full_command_packet->command.oldcommand;
+
+ /* First check for internal completion of set param for time sync */
+ if (TW_OP_OUT(command_packet->opcode__sgloffset) == TW_OP_SET_PARAM) {
+ /* Keep reading the queue in case there are more aen's */
+ if (twl_aen_read_queue(tw_dev, request_id))
+ goto out2;
+ else {
+ retval = 0;
+ goto out;
+ }
+ }
+
+ switch (aen) {
+ case TW_AEN_QUEUE_EMPTY:
+ /* Quit reading the queue if this is the last one */
+ break;
+ case TW_AEN_SYNC_TIME_WITH_HOST:
+ twl_aen_sync_time(tw_dev, request_id);
+ retval = 0;
+ goto out;
+ default:
+ twl_aen_queue_event(tw_dev, header);
+
+ /* If there are more aen's, keep reading the queue */
+ if (twl_aen_read_queue(tw_dev, request_id))
+ goto out2;
+ else {
+ retval = 0;
+ goto out;
+ }
+ }
+ retval = 0;
+out2:
+ tw_dev->state[request_id] = TW_S_COMPLETED;
+ twl_free_request_id(tw_dev, request_id);
+ clear_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags);
+out:
+ return retval;
+} /* End twl_aen_complete() */
+
+/* This function will poll for a response */
+static int twl_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds)
+{
+ unsigned long before;
+ dma_addr_t mfa;
+ u32 regh, regl;
+ u32 response;
+ int retval = 1;
+ int found = 0;
+
+ before = jiffies;
+
+ while (!found) {
+ if (sizeof(dma_addr_t) > 4) {
+ regh = readl(TWL_HOBQPH_REG_ADDR(tw_dev));
+ regl = readl(TWL_HOBQPL_REG_ADDR(tw_dev));
+ mfa = ((u64)regh << 32) | regl;
+ } else
+ mfa = readl(TWL_HOBQPL_REG_ADDR(tw_dev));
+
+ response = (u32)mfa;
+
+ if (TW_RESID_OUT(response) == request_id)
+ found = 1;
+
+ if (time_after(jiffies, before + HZ * seconds))
+ goto out;
+
+ msleep(50);
+ }
+ retval = 0;
+out:
+ return retval;
+} /* End twl_poll_response() */
+
+/* This function will drain the aen queue */
+static int twl_aen_drain_queue(TW_Device_Extension *tw_dev, int no_check_reset)
+{
+ int request_id = 0;
+ char cdb[TW_MAX_CDB_LEN];
+ TW_SG_Entry_ISO sglist[1];
+ int finished = 0, count = 0;
+ TW_Command_Full *full_command_packet;
+ TW_Command_Apache_Header *header;
+ unsigned short aen;
+ int first_reset = 0, queue = 0, retval = 1;
+
+ if (no_check_reset)
+ first_reset = 0;
+ else
+ first_reset = 1;
+
+ full_command_packet = tw_dev->command_packet_virt[request_id];
+ memset(full_command_packet, 0, sizeof(TW_Command_Full));
+
+ /* Initialize cdb */
+ memset(&cdb, 0, TW_MAX_CDB_LEN);
+ cdb[0] = REQUEST_SENSE; /* opcode */
+ cdb[4] = TW_ALLOCATION_LENGTH; /* allocation length */
+
+ /* Initialize sglist */
+ memset(&sglist, 0, sizeof(TW_SG_Entry_ISO));
+ sglist[0].length = TW_SECTOR_SIZE;
+ sglist[0].address = tw_dev->generic_buffer_phys[request_id];
+
+ /* Mark internal command */
+ tw_dev->srb[request_id] = NULL;
+
+ do {
+ /* Send command to the board */
+ if (twl_scsiop_execute_scsi(tw_dev, request_id, cdb, 1, sglist)) {
+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x3, "Error posting request sense");
+ goto out;
+ }
+
+ /* Now poll for completion */
+ if (twl_poll_response(tw_dev, request_id, 30)) {
+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x4, "No valid response while draining AEN queue");
+ tw_dev->posted_request_count--;
+ goto out;
+ }
+
+ tw_dev->posted_request_count--;
+ header = (TW_Command_Apache_Header *)tw_dev->generic_buffer_virt[request_id];
+ aen = le16_to_cpu(header->status_block.error);
+ queue = 0;
+ count++;
+
+ switch (aen) {
+ case TW_AEN_QUEUE_EMPTY:
+ if (first_reset != 1)
+ goto out;
+ else
+ finished = 1;
+ break;
+ case TW_AEN_SOFT_RESET:
+ if (first_reset == 0)
+ first_reset = 1;
+ else
+ queue = 1;
+ break;
+ case TW_AEN_SYNC_TIME_WITH_HOST:
+ break;
+ default:
+ queue = 1;
+ }
+
+ /* Now queue an event info */
+ if (queue)
+ twl_aen_queue_event(tw_dev, header);
+ } while ((finished == 0) && (count < TW_MAX_AEN_DRAIN));
+
+ if (count == TW_MAX_AEN_DRAIN)
+ goto out;
+
+ retval = 0;
+out:
+ tw_dev->state[request_id] = TW_S_INITIAL;
+ return retval;
+} /* End twl_aen_drain_queue() */
+
+/* This function will allocate memory and check if it is correctly aligned */
+static int twl_allocate_memory(TW_Device_Extension *tw_dev, int size, int which)
+{
+ int i;
+ dma_addr_t dma_handle;
+ unsigned long *cpu_addr;
+ int retval = 1;
+
+ cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, &dma_handle);
+ if (!cpu_addr) {
+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x5, "Memory allocation failed");
+ goto out;
+ }
+
+ memset(cpu_addr, 0, size*TW_Q_LENGTH);
+
+ for (i = 0; i < TW_Q_LENGTH; i++) {
+ switch(which) {
+ case 0:
+ tw_dev->command_packet_phys[i] = dma_handle+(i*size);
+ tw_dev->command_packet_virt[i] = (TW_Command_Full *)((unsigned char *)cpu_addr + (i*size));
+ break;
+ case 1:
+ tw_dev->generic_buffer_phys[i] = dma_handle+(i*size);
+ tw_dev->generic_buffer_virt[i] = (unsigned long *)((unsigned char *)cpu_addr + (i*size));
+ break;
+ case 2:
+ tw_dev->sense_buffer_phys[i] = dma_handle+(i*size);
+ tw_dev->sense_buffer_virt[i] = (TW_Command_Apache_Header *)((unsigned char *)cpu_addr + (i*size));
+ break;
+ }
+ }
+ retval = 0;
+out:
+ return retval;
+} /* End twl_allocate_memory() */
+
+/* This function will load the request id and various sgls for ioctls */
+static void twl_load_sgl(TW_Device_Extension *tw_dev, TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length)
+{
+ TW_Command *oldcommand;
+ TW_Command_Apache *newcommand;
+ TW_SG_Entry_ISO *sgl;
+ unsigned int pae = 0;
+
+ if ((sizeof(long) < 8) && (sizeof(dma_addr_t) > 4))
+ pae = 1;
+
+ if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) {
+ newcommand = &full_command_packet->command.newcommand;
+ newcommand->request_id__lunl =
+ cpu_to_le16(TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->request_id__lunl), request_id));
+ if (length) {
+ newcommand->sg_list[0].address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1);
+ newcommand->sg_list[0].length = TW_CPU_TO_SGL(length);
+ }
+ newcommand->sgl_entries__lunh =
+ cpu_to_le16(TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->sgl_entries__lunh), length ? 1 : 0));
+ } else {
+ oldcommand = &full_command_packet->command.oldcommand;
+ oldcommand->request_id = request_id;
+
+ if (TW_SGL_OUT(oldcommand->opcode__sgloffset)) {
+ /* Load the sg list */
+ sgl = (TW_SG_Entry_ISO *)((u32 *)oldcommand+oldcommand->size - (sizeof(TW_SG_Entry_ISO)/4) + pae + (sizeof(dma_addr_t) > 4 ? 1 : 0));
+ sgl->address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1);
+ sgl->length = TW_CPU_TO_SGL(length);
+ oldcommand->size += pae;
+ oldcommand->size += sizeof(dma_addr_t) > 4 ? 1 : 0;
+ }
+ }
+} /* End twl_load_sgl() */
+
+/* This function handles ioctl for the character device
+ This interface is used by smartmontools open source software */
+static int twl_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ long timeout;
+ unsigned long *cpu_addr, data_buffer_length_adjusted = 0, flags = 0;
+ dma_addr_t dma_handle;
+ int request_id = 0;
+ TW_Ioctl_Driver_Command driver_command;
+ TW_Ioctl_Buf_Apache *tw_ioctl;
+ TW_Command_Full *full_command_packet;
+ TW_Device_Extension *tw_dev = twl_device_extension_list[iminor(inode)];
+ int retval = -EFAULT;
+ void __user *argp = (void __user *)arg;
+
+ /* Only let one of these through at a time */
+ if (mutex_lock_interruptible(&tw_dev->ioctl_lock)) {
+ retval = -EINTR;
+ goto out;
+ }
+
+ /* First copy down the driver command */
+ if (copy_from_user(&driver_command, argp, sizeof(TW_Ioctl_Driver_Command)))
+ goto out2;
+
+ /* Check data buffer size */
+ if (driver_command.buffer_length > TW_MAX_SECTORS * 2048) {
+ retval = -EINVAL;
+ goto out2;
+ }
+
+ /* Hardware can only do multiple of 512 byte transfers */
+ data_buffer_length_adjusted = (driver_command.buffer_length + 511) & ~511;
+
+ /* Now allocate ioctl buf memory */
+ cpu_addr = dma_alloc_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, &dma_handle, GFP_KERNEL);
+ if (!cpu_addr) {
+ retval = -ENOMEM;
+ goto out2;
+ }
+
+ tw_ioctl = (TW_Ioctl_Buf_Apache *)cpu_addr;
+
+ /* Now copy down the entire ioctl */
+ if (copy_from_user(tw_ioctl, argp, driver_command.buffer_length + sizeof(TW_Ioctl_Buf_Apache) - 1))
+ goto out3;
+
+ /* See which ioctl we are doing */
+ switch (cmd) {
+ case TW_IOCTL_FIRMWARE_PASS_THROUGH:
+ spin_lock_irqsave(tw_dev->host->host_lock, flags);
+ twl_get_request_id(tw_dev, &request_id);
+
+ /* Flag internal command */
+ tw_dev->srb[request_id] = NULL;
+
+ /* Flag chrdev ioctl */
+ tw_dev->chrdev_request_id = request_id;
+
+ full_command_packet = (TW_Command_Full *)&tw_ioctl->firmware_command;
+
+ /* Load request id and sglist for both command types */
+ twl_load_sgl(tw_dev, full_command_packet, request_id, dma_handle, data_buffer_length_adjusted);
+
+ memcpy(tw_dev->command_packet_virt[request_id], &(tw_ioctl->firmware_command), sizeof(TW_Command_Full));
+
+ /* Now post the command packet to the controller */
+ twl_post_command_packet(tw_dev, request_id);
+ spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
+
+ timeout = TW_IOCTL_CHRDEV_TIMEOUT*HZ;
+
+ /* Now wait for command to complete */
+ timeout = wait_event_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout);
+
+ /* We timed out, and didn't get an interrupt */
+ if (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE) {
+ /* Now we need to reset the board */
+ printk(KERN_WARNING "3w-sas: scsi%d: WARNING: (0x%02X:0x%04X): Character ioctl (0x%x) timed out, resetting card.\n",
+ tw_dev->host->host_no, TW_DRIVER, 0x6,
+ cmd);
+ retval = -EIO;
+ twl_reset_device_extension(tw_dev, 1);
+ goto out3;
+ }
+
+ /* Now copy in the command packet response */
+ memcpy(&(tw_ioctl->firmware_command), tw_dev->command_packet_virt[request_id], sizeof(TW_Command_Full));
+
+ /* Now complete the io */
+ spin_lock_irqsave(tw_dev->host->host_lock, flags);
+ tw_dev->posted_request_count--;
+ tw_dev->state[request_id] = TW_S_COMPLETED;
+ twl_free_request_id(tw_dev, request_id);
+ spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
+ break;
+ default:
+ retval = -ENOTTY;
+ goto out3;
+ }
+
+ /* Now copy the entire response to userspace */
+ if (copy_to_user(argp, tw_ioctl, sizeof(TW_Ioctl_Buf_Apache) + driver_command.buffer_length - 1) == 0)
+ retval = 0;
+out3:
+ /* Now free ioctl buf memory */
+ dma_free_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, cpu_addr, dma_handle);
+out2:
+ mutex_unlock(&tw_dev->ioctl_lock);
+out:
+ return retval;
+} /* End twl_chrdev_ioctl() */
+
+/* This function handles open for the character device */
+static int twl_chrdev_open(struct inode *inode, struct file *file)
+{
+ unsigned int minor_number;
+ int retval = -ENODEV;
+
+ if (!capable(CAP_SYS_ADMIN)) {
+ retval = -EACCES;
+ goto out;
+ }
+
+ cycle_kernel_lock();
+ minor_number = iminor(inode);
+ if (minor_number >= twl_device_extension_count)
+ goto out;
+ retval = 0;
+out:
+ return retval;
+} /* End twl_chrdev_open() */
+
+/* File operations struct for character device */
+static const struct file_operations twl_fops = {
+ .owner = THIS_MODULE,
+ .ioctl = twl_chrdev_ioctl,
+ .open = twl_chrdev_open,
+ .release = NULL
+};
+
+/* This function passes sense data from firmware to scsi layer */
+static int twl_fill_sense(TW_Device_Extension *tw_dev, int i, int request_id, int copy_sense, int print_host)
+{
+ TW_Command_Apache_Header *header;
+ TW_Command_Full *full_command_packet;
+ unsigned short error;
+ char *error_str;
+ int retval = 1;
+
+ header = tw_dev->sense_buffer_virt[i];
+ full_command_packet = tw_dev->command_packet_virt[request_id];
+
+ /* Get embedded firmware error string */
+ error_str = &(header->err_specific_desc[strlen(header->err_specific_desc) + 1]);
+
+ /* Don't print error for Logical unit not supported during rollcall */
+ error = le16_to_cpu(header->status_block.error);
+ if ((error != TW_ERROR_LOGICAL_UNIT_NOT_SUPPORTED) && (error != TW_ERROR_UNIT_OFFLINE) && (error != TW_ERROR_INVALID_FIELD_IN_CDB)) {
+ if (print_host)
+ printk(KERN_WARNING "3w-sas: scsi%d: ERROR: (0x%02X:0x%04X): %s:%s.\n",
+ tw_dev->host->host_no,
+ TW_MESSAGE_SOURCE_CONTROLLER_ERROR,
+ header->status_block.error,
+ error_str,
+ header->err_specific_desc);
+ else
+ printk(KERN_WARNING "3w-sas: ERROR: (0x%02X:0x%04X): %s:%s.\n",
+ TW_MESSAGE_SOURCE_CONTROLLER_ERROR,
+ header->status_block.error,
+ error_str,
+ header->err_specific_desc);
+ }
+
+ if (copy_sense) {
+ memcpy(tw_dev->srb[request_id]->sense_buffer, header->sense_data, TW_SENSE_DATA_LENGTH);
+ tw_dev->srb[request_id]->result = (full_command_packet->command.newcommand.status << 1);
+ goto out;
+ }
+out:
+ return retval;
+} /* End twl_fill_sense() */
+
+/* This function will free up device extension resources */
+static void twl_free_device_extension(TW_Device_Extension *tw_dev)
+{
+ if (tw_dev->command_packet_virt[0])
+ pci_free_consistent(tw_dev->tw_pci_dev,
+ sizeof(TW_Command_Full)*TW_Q_LENGTH,
+ tw_dev->command_packet_virt[0],
+ tw_dev->command_packet_phys[0]);
+
+ if (tw_dev->generic_buffer_virt[0])
+ pci_free_consistent(tw_dev->tw_pci_dev,
+ TW_SECTOR_SIZE*TW_Q_LENGTH,
+ tw_dev->generic_buffer_virt[0],
+ tw_dev->generic_buffer_phys[0]);
+
+ if (tw_dev->sense_buffer_virt[0])
+ pci_free_consistent(tw_dev->tw_pci_dev,
+ sizeof(TW_Command_Apache_Header)*
+ TW_Q_LENGTH,
+ tw_dev->sense_buffer_virt[0],
+ tw_dev->sense_buffer_phys[0]);
+
+ kfree(tw_dev->event_queue[0]);
+} /* End twl_free_device_extension() */
+
+/* This function will get parameter table entries from the firmware */
+static void *twl_get_param(TW_Device_Extension *tw_dev, int request_id, int table_id, int parameter_id, int parameter_size_bytes)
+{
+ TW_Command_Full *full_command_packet;
+ TW_Command *command_packet;
+ TW_Param_Apache *param;
+ void *retval = NULL;
+
+ /* Setup the command packet */
+ full_command_packet = tw_dev->command_packet_virt[request_id];
+ memset(full_command_packet, 0, sizeof(TW_Command_Full));
+ command_packet = &full_command_packet->command.oldcommand;
+
+ command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM);
+ command_packet->size = TW_COMMAND_SIZE;
+ command_packet->request_id = request_id;
+ command_packet->byte6_offset.block_count = cpu_to_le16(1);
+
+ /* Now setup the param */
+ param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id];
+ memset(param, 0, TW_SECTOR_SIZE);
+ param->table_id = cpu_to_le16(table_id | 0x8000);
+ param->parameter_id = cpu_to_le16(parameter_id);
+ param->parameter_size_bytes = cpu_to_le16(parameter_size_bytes);
+
+ command_packet->byte8_offset.param.sgl[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]);
+ command_packet->byte8_offset.param.sgl[0].length = TW_CPU_TO_SGL(TW_SECTOR_SIZE);
+
+ /* Post the command packet to the board */
+ twl_post_command_packet(tw_dev, request_id);
+
+ /* Poll for completion */
+ if (twl_poll_response(tw_dev, request_id, 30))
+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x7, "No valid response during get param")
+ else
+ retval = (void *)&(param->data[0]);
+
+ tw_dev->posted_request_count--;
+ tw_dev->state[request_id] = TW_S_INITIAL;
+
+ return retval;
+} /* End twl_get_param() */
+
+/* This function will send an initconnection command to controller */
+static int twl_initconnection(TW_Device_Extension *tw_dev, int message_credits,
+ u32 set_features, unsigned short current_fw_srl,
+ unsigned short current_fw_arch_id,
+ unsigned short current_fw_branch,
+ unsigned short current_fw_build,
+ unsigned short *fw_on_ctlr_srl,
+ unsigned short *fw_on_ctlr_arch_id,
+ unsigned short *fw_on_ctlr_branch,
+ unsigned short *fw_on_ctlr_build,
+ u32 *init_connect_result)
+{
+ TW_Command_Full *full_command_packet;
+ TW_Initconnect *tw_initconnect;
+ int request_id = 0, retval = 1;
+
+ /* Initialize InitConnection command packet */
+ full_command_packet = tw_dev->command_packet_virt[request_id];
+ memset(full_command_packet, 0, sizeof(TW_Command_Full));
+ full_command_packet->header.header_desc.size_header = 128;
+
+ tw_initconnect = (TW_Initconnect *)&full_command_packet->command.oldcommand;
+ tw_initconnect->opcode__reserved = TW_OPRES_IN(0, TW_OP_INIT_CONNECTION);
+ tw_initconnect->request_id = request_id;
+ tw_initconnect->message_credits = cpu_to_le16(message_credits);
+ tw_initconnect->features = set_features;
+
+ /* Turn on 64-bit sgl support if we need to */
+ tw_initconnect->features |= sizeof(dma_addr_t) > 4 ? 1 : 0;
+
+ tw_initconnect->features = cpu_to_le32(tw_initconnect->features);
+
+ if (set_features & TW_EXTENDED_INIT_CONNECT) {
+ tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE_EXTENDED;
+ tw_initconnect->fw_srl = cpu_to_le16(current_fw_srl);
+ tw_initconnect->fw_arch_id = cpu_to_le16(current_fw_arch_id);
+ tw_initconnect->fw_branch = cpu_to_le16(current_fw_branch);
+ tw_initconnect->fw_build = cpu_to_le16(current_fw_build);
+ } else
+ tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE;
+
+ /* Send command packet to the board */
+ twl_post_command_packet(tw_dev, request_id);
+
+ /* Poll for completion */
+ if (twl_poll_response(tw_dev, request_id, 30)) {
+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x8, "No valid response during init connection");
+ } else {
+ if (set_features & TW_EXTENDED_INIT_CONNECT) {
+ *fw_on_ctlr_srl = le16_to_cpu(tw_initconnect->fw_srl);
+ *fw_on_ctlr_arch_id = le16_to_cpu(tw_initconnect->fw_arch_id);
+ *fw_on_ctlr_branch = le16_to_cpu(tw_initconnect->fw_branch);
+ *fw_on_ctlr_build = le16_to_cpu(tw_initconnect->fw_build);
+ *init_connect_result = le32_to_cpu(tw_initconnect->result);
+ }
+ retval = 0;
+ }
+
+ tw_dev->posted_request_count--;
+ tw_dev->state[request_id] = TW_S_INITIAL;
+
+ return retval;
+} /* End twl_initconnection() */
+
+/* This function will initialize the fields of a device extension */
+static int twl_initialize_device_extension(TW_Device_Extension *tw_dev)
+{
+ int i, retval = 1;
+
+ /* Initialize command packet buffers */
+ if (twl_allocate_memory(tw_dev, sizeof(TW_Command_Full), 0)) {
+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x9, "Command packet memory allocation failed");
+ goto out;
+ }
+
+ /* Initialize generic buffer */
+ if (twl_allocate_memory(tw_dev, TW_SECTOR_SIZE, 1)) {
+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0xa, "Generic memory allocation failed");
+ goto out;
+ }
+
+ /* Allocate sense buffers */
+ if (twl_allocate_memory(tw_dev, sizeof(TW_Command_Apache_Header), 2)) {
+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0xb, "Sense buffer allocation failed");
+ goto out;
+ }
+
+ /* Allocate event info space */
+ tw_dev->event_queue[0] = kcalloc(TW_Q_LENGTH, sizeof(TW_Event), GFP_KERNEL);
+ if (!tw_dev->event_queue[0]) {
+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0xc, "Event info memory allocation failed");
+ goto out;
+ }
+
+ for (i = 0; i < TW_Q_LENGTH; i++) {
+ tw_dev->event_queue[i] = (TW_Event *)((unsigned char *)tw_dev->event_queue[0] + (i * sizeof(TW_Event)));
+ tw_dev->free_queue[i] = i;
+ tw_dev->state[i] = TW_S_INITIAL;
+ }
+
+ tw_dev->free_head = TW_Q_START;
+ tw_dev->free_tail = TW_Q_START;
+ tw_dev->error_sequence_id = 1;
+ tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
+
+ mutex_init(&tw_dev->ioctl_lock);
+ init_waitqueue_head(&tw_dev->ioctl_wqueue);
+
+ retval = 0;
+out:
+ return retval;
+} /* End twl_initialize_device_extension() */
+
+/* This function will perform a pci-dma unmap */
+static void twl_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id)
+{
+ struct scsi_cmnd *cmd = tw_dev->srb[request_id];
+
+ if (cmd->SCp.phase == TW_PHASE_SGLIST)
+ scsi_dma_unmap(cmd);
+} /* End twl_unmap_scsi_data() */
+
+/* This function will handle attention interrupts */
+static int twl_handle_attention_interrupt(TW_Device_Extension *tw_dev)
+{
+ int retval = 1;
+ u32 request_id, doorbell;
+
+ /* Read doorbell status */
+ doorbell = readl(TWL_HOBDB_REG_ADDR(tw_dev));
+
+ /* Check for controller errors */
+ if (doorbell & TWL_DOORBELL_CONTROLLER_ERROR) {
+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0xd, "Microcontroller Error: clearing");
+ goto out;
+ }
+
+ /* Check if we need to perform an AEN drain */
+ if (doorbell & TWL_DOORBELL_ATTENTION_INTERRUPT) {
+ if (!(test_and_set_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags))) {
+ twl_get_request_id(tw_dev, &request_id);
+ if (twl_aen_read_queue(tw_dev, request_id)) {
+ tw_dev->state[request_id] = TW_S_COMPLETED;
+ twl_free_request_id(tw_dev, request_id);
+ clear_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags);
+ }
+ }
+ }
+
+ retval = 0;
+out:
+ /* Clear doorbell interrupt */
+ TWL_CLEAR_DB_INTERRUPT(tw_dev);
+
+ /* Make sure the clear was flushed by reading it back */
+ readl(TWL_HOBDBC_REG_ADDR(tw_dev));
+
+ return retval;
+} /* End twl_handle_attention_interrupt() */
+
+/* Interrupt service routine */
+static irqreturn_t twl_interrupt(int irq, void *dev_instance)
+{
+ TW_Device_Extension *tw_dev = (TW_Device_Extension *)dev_instance;
+ int i, handled = 0, error = 0;
+ dma_addr_t mfa = 0;
+ u32 reg, regl, regh, response, request_id = 0;
+ struct scsi_cmnd *cmd;
+ TW_Command_Full *full_command_packet;
+
+ spin_lock(tw_dev->host->host_lock);
+
+ /* Read host interrupt status */
+ reg = readl(TWL_HISTAT_REG_ADDR(tw_dev));
+
+ /* Check if this is our interrupt, otherwise bail */
+ if (!(reg & TWL_HISTATUS_VALID_INTERRUPT))
+ goto twl_interrupt_bail;
+
+ handled = 1;
+
+ /* If we are resetting, bail */
+ if (test_bit(TW_IN_RESET, &tw_dev->flags))
+ goto twl_interrupt_bail;
+
+ /* Attention interrupt */
+ if (reg & TWL_HISTATUS_ATTENTION_INTERRUPT) {
+ if (twl_handle_attention_interrupt(tw_dev)) {
+ TWL_MASK_INTERRUPTS(tw_dev);
+ goto twl_interrupt_bail;
+ }
+ }
+
+ /* Response interrupt */
+ while (reg & TWL_HISTATUS_RESPONSE_INTERRUPT) {
+ if (sizeof(dma_addr_t) > 4) {
+ regh = readl(TWL_HOBQPH_REG_ADDR(tw_dev));
+ regl = readl(TWL_HOBQPL_REG_ADDR(tw_dev));
+ mfa = ((u64)regh << 32) | regl;
+ } else
+ mfa = readl(TWL_HOBQPL_REG_ADDR(tw_dev));
+
+ error = 0;
+ response = (u32)mfa;
+
+ /* Check for command packet error */
+ if (!TW_NOTMFA_OUT(response)) {
+ for (i=0;i<TW_Q_LENGTH;i++) {
+ if (tw_dev->sense_buffer_phys[i] == mfa) {
+ request_id = le16_to_cpu(tw_dev->sense_buffer_virt[i]->header_desc.request_id);
+ if (tw_dev->srb[request_id] != NULL)
+ error = twl_fill_sense(tw_dev, i, request_id, 1, 1);
+ else {
+ /* Skip ioctl error prints */
+ if (request_id != tw_dev->chrdev_request_id)
+ error = twl_fill_sense(tw_dev, i, request_id, 0, 1);
+ else
+ memcpy(tw_dev->command_packet_virt[request_id], tw_dev->sense_buffer_virt[i], sizeof(TW_Command_Apache_Header));
+ }
+
+ /* Now re-post the sense buffer */
+ writel((u32)((u64)tw_dev->sense_buffer_phys[i] >> 32), TWL_HOBQPH_REG_ADDR(tw_dev));
+ writel((u32)tw_dev->sense_buffer_phys[i], TWL_HOBQPL_REG_ADDR(tw_dev));
+ break;
+ }
+ }
+ } else
+ request_id = TW_RESID_OUT(response);
+
+ full_command_packet = tw_dev->command_packet_virt[request_id];
+
+ /* Check for correct state */
+ if (tw_dev->state[request_id] != TW_S_POSTED) {
+ if (tw_dev->srb[request_id] != NULL) {
+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0xe, "Received a request id that wasn't posted");
+ TWL_MASK_INTERRUPTS(tw_dev);
+ goto twl_interrupt_bail;
+ }
+ }
+
+ /* Check for internal command completion */
+ if (tw_dev->srb[request_id] == NULL) {
+ if (request_id != tw_dev->chrdev_request_id) {
+ if (twl_aen_complete(tw_dev, request_id))
+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0xf, "Error completing AEN during attention interrupt");
+ } else {
+ tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
+ wake_up(&tw_dev->ioctl_wqueue);
+ }
+ } else {
+ cmd = tw_dev->srb[request_id];
+
+ if (!error)
+ cmd->result = (DID_OK << 16);
+
+ /* Report residual bytes for single sgl */
+ if ((scsi_sg_count(cmd) <= 1) && (full_command_packet->command.newcommand.status == 0)) {
+ if (full_command_packet->command.newcommand.sg_list[0].length < scsi_bufflen(tw_dev->srb[request_id]))
+ scsi_set_resid(cmd, scsi_bufflen(cmd) - full_command_packet->command.newcommand.sg_list[0].length);
+ }
+
+ /* Now complete the io */
+ tw_dev->state[request_id] = TW_S_COMPLETED;
+ twl_free_request_id(tw_dev, request_id);
+ tw_dev->posted_request_count--;
+ tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+ twl_unmap_scsi_data(tw_dev, request_id);
+ }
+
+ /* Check for another response interrupt */
+ reg = readl(TWL_HISTAT_REG_ADDR(tw_dev));
+ }
+
+twl_interrupt_bail:
+ spin_unlock(tw_dev->host->host_lock);
+ return IRQ_RETVAL(handled);
+} /* End twl_interrupt() */
+
+/* This function will poll for a register change */
+static int twl_poll_register(TW_Device_Extension *tw_dev, void *reg, u32 value, u32 result, int seconds)
+{
+ unsigned long before;
+ int retval = 1;
+ u32 reg_value;
+
+ reg_value = readl(reg);
+ before = jiffies;
+
+ while ((reg_value & value) != result) {
+ reg_value = readl(reg);
+ if (time_after(jiffies, before + HZ * seconds))
+ goto out;
+ msleep(50);
+ }
+ retval = 0;
+out:
+ return retval;
+} /* End twl_poll_register() */
+
+/* This function will reset a controller */
+static int twl_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset)
+{
+ int retval = 1;
+ int i = 0;
+ u32 status = 0;
+ unsigned short fw_on_ctlr_srl = 0, fw_on_ctlr_arch_id = 0;
+ unsigned short fw_on_ctlr_branch = 0, fw_on_ctlr_build = 0;
+ u32 init_connect_result = 0;
+ int tries = 0;
+ int do_soft_reset = soft_reset;
+
+ while (tries < TW_MAX_RESET_TRIES) {
+ /* Do a soft reset if one is needed */
+ if (do_soft_reset) {
+ TWL_SOFT_RESET(tw_dev);
+
+ /* Make sure controller is in a good state */
+ if (twl_poll_register(tw_dev, TWL_SCRPD3_REG_ADDR(tw_dev), TWL_CONTROLLER_READY, 0x0, 30)) {
+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x10, "Controller never went non-ready during reset sequence");
+ tries++;
+ continue;
+ }
+ if (twl_poll_register(tw_dev, TWL_SCRPD3_REG_ADDR(tw_dev), TWL_CONTROLLER_READY, TWL_CONTROLLER_READY, 60)) {
+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x11, "Controller not ready during reset sequence");
+ tries++;
+ continue;
+ }
+ }
+
+ /* Initconnect */
+ if (twl_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS,
+ TW_EXTENDED_INIT_CONNECT, TW_CURRENT_DRIVER_SRL,
+ TW_9750_ARCH_ID, TW_CURRENT_DRIVER_BRANCH,
+ TW_CURRENT_DRIVER_BUILD, &fw_on_ctlr_srl,
+ &fw_on_ctlr_arch_id, &fw_on_ctlr_branch,
+ &fw_on_ctlr_build, &init_connect_result)) {
+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x12, "Initconnection failed while checking SRL");
+ do_soft_reset = 1;
+ tries++;
+ continue;
+ }
+
+ /* Load sense buffers */
+ while (i < TW_Q_LENGTH) {
+ writel((u32)((u64)tw_dev->sense_buffer_phys[i] >> 32), TWL_HOBQPH_REG_ADDR(tw_dev));
+ writel((u32)tw_dev->sense_buffer_phys[i], TWL_HOBQPL_REG_ADDR(tw_dev));
+
+ /* Check status for over-run after each write */
+ status = readl(TWL_STATUS_REG_ADDR(tw_dev));
+ if (!(status & TWL_STATUS_OVERRUN_SUBMIT))
+ i++;
+ }
+
+ /* Now check status */
+ status = readl(TWL_STATUS_REG_ADDR(tw_dev));
+ if (status) {
+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x13, "Bad controller status after loading sense buffers");
+ do_soft_reset = 1;
+ tries++;
+ continue;
+ }
+
+ /* Drain the AEN queue */
+ if (twl_aen_drain_queue(tw_dev, soft_reset)) {
+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x14, "AEN drain failed during reset sequence");
+ do_soft_reset = 1;
+ tries++;
+ continue;
+ }
+
+ /* Load rest of compatibility struct */
+ strncpy(tw_dev->tw_compat_info.driver_version, TW_DRIVER_VERSION, strlen(TW_DRIVER_VERSION));
+ tw_dev->tw_compat_info.driver_srl_high = TW_CURRENT_DRIVER_SRL;
+ tw_dev->tw_compat_info.driver_branch_high = TW_CURRENT_DRIVER_BRANCH;
+ tw_dev->tw_compat_info.driver_build_high = TW_CURRENT_DRIVER_BUILD;
+ tw_dev->tw_compat_info.driver_srl_low = TW_BASE_FW_SRL;
+ tw_dev->tw_compat_info.driver_branch_low = TW_BASE_FW_BRANCH;
+ tw_dev->tw_compat_info.driver_build_low = TW_BASE_FW_BUILD;
+ tw_dev->tw_compat_info.fw_on_ctlr_srl = fw_on_ctlr_srl;
+ tw_dev->tw_compat_info.fw_on_ctlr_branch = fw_on_ctlr_branch;
+ tw_dev->tw_compat_info.fw_on_ctlr_build = fw_on_ctlr_build;
+
+ /* If we got here, controller is in a good state */
+ retval = 0;
+ goto out;
+ }
+out:
+ return retval;
+} /* End twl_reset_sequence() */
+
+/* This function will reset a device extension */
+static int twl_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset)
+{
+ int i = 0, retval = 1;
+ unsigned long flags = 0;
+
+ /* Block SCSI requests while we are resetting */
+ if (ioctl_reset)
+ scsi_block_requests(tw_dev->host);
+
+ set_bit(TW_IN_RESET, &tw_dev->flags);
+ TWL_MASK_INTERRUPTS(tw_dev);
+ TWL_CLEAR_DB_INTERRUPT(tw_dev);
+
+ spin_lock_irqsave(tw_dev->host->host_lock, flags);
+
+ /* Abort all requests that are in progress */
+ for (i = 0; i < TW_Q_LENGTH; i++) {
+ if ((tw_dev->state[i] != TW_S_FINISHED) &&
+ (tw_dev->state[i] != TW_S_INITIAL) &&
+ (tw_dev->state[i] != TW_S_COMPLETED)) {
+ if (tw_dev->srb[i]) {
+ tw_dev->srb[i]->result = (DID_RESET << 16);
+ tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
+ twl_unmap_scsi_data(tw_dev, i);
+ }
+ }
+ }
+
+ /* Reset queues and counts */
+ for (i = 0; i < TW_Q_LENGTH; i++) {
+ tw_dev->free_queue[i] = i;
+ tw_dev->state[i] = TW_S_INITIAL;
+ }
+ tw_dev->free_head = TW_Q_START;
+ tw_dev->free_tail = TW_Q_START;
+ tw_dev->posted_request_count = 0;
+
+ spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
+
+ if (twl_reset_sequence(tw_dev, 1))
+ goto out;
+
+ TWL_UNMASK_INTERRUPTS(tw_dev);
+
+ clear_bit(TW_IN_RESET, &tw_dev->flags);
+ tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
+
+ retval = 0;
+out:
+ if (ioctl_reset)
+ scsi_unblock_requests(tw_dev->host);
+ return retval;
+} /* End twl_reset_device_extension() */
+
+/* This funciton returns unit geometry in cylinders/heads/sectors */
+static int twl_scsi_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[])
+{
+ int heads, sectors;
+ TW_Device_Extension *tw_dev;
+
+ tw_dev = (TW_Device_Extension *)sdev->host->hostdata;
+
+ if (capacity >= 0x200000) {
+ heads = 255;
+ sectors = 63;
+ } else {
+ heads = 64;
+ sectors = 32;
+ }
+
+ geom[0] = heads;
+ geom[1] = sectors;
+ geom[2] = sector_div(capacity, heads * sectors); /* cylinders */
+
+ return 0;
+} /* End twl_scsi_biosparam() */
+
+/* This is the new scsi eh reset function */
+static int twl_scsi_eh_reset(struct scsi_cmnd *SCpnt)
+{
+ TW_Device_Extension *tw_dev = NULL;
+ int retval = FAILED;
+
+ tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
+
+ tw_dev->num_resets++;
+
+ sdev_printk(KERN_WARNING, SCpnt->device,
+ "WARNING: (0x%02X:0x%04X): Command (0x%x) timed out, resetting card.\n",
+ TW_DRIVER, 0x2c, SCpnt->cmnd[0]);
+
+ /* Make sure we are not issuing an ioctl or resetting from ioctl */
+ mutex_lock(&tw_dev->ioctl_lock);
+
+ /* Now reset the card and some of the device extension data */
+ if (twl_reset_device_extension(tw_dev, 0)) {
+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x15, "Controller reset failed during scsi host reset");
+ goto out;
+ }
+
+ retval = SUCCESS;
+out:
+ mutex_unlock(&tw_dev->ioctl_lock);
+ return retval;
+} /* End twl_scsi_eh_reset() */
+
+/* This is the main scsi queue function to handle scsi opcodes */
+static int twl_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+{
+ int request_id, retval;
+ TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
+
+ /* If we are resetting due to timed out ioctl, report as busy */
+ if (test_bit(TW_IN_RESET, &tw_dev->flags)) {
+ retval = SCSI_MLQUEUE_HOST_BUSY;
+ goto out;
+ }
+
+ /* Save done function into scsi_cmnd struct */
+ SCpnt->scsi_done = done;
+
+ /* Get a free request id */
+ twl_get_request_id(tw_dev, &request_id);
+
+ /* Save the scsi command for use by the ISR */
+ tw_dev->srb[request_id] = SCpnt;
+
+ /* Initialize phase to zero */
+ SCpnt->SCp.phase = TW_PHASE_INITIAL;
+
+ retval = twl_scsiop_execute_scsi(tw_dev, request_id, NULL, 0, NULL);
+ if (retval) {
+ tw_dev->state[request_id] = TW_S_COMPLETED;
+ twl_free_request_id(tw_dev, request_id);
+ SCpnt->result = (DID_ERROR << 16);
+ done(SCpnt);
+ retval = 0;
+ }
+out:
+ return retval;
+} /* End twl_scsi_queue() */
+
+/* This function tells the controller to shut down */
+static void __twl_shutdown(TW_Device_Extension *tw_dev)
+{
+ /* Disable interrupts */
+ TWL_MASK_INTERRUPTS(tw_dev);
+
+ /* Free up the IRQ */
+ free_irq(tw_dev->tw_pci_dev->irq, tw_dev);
+
+ printk(KERN_WARNING "3w-sas: Shutting down host %d.\n", tw_dev->host->host_no);
+
+ /* Tell the card we are shutting down */
+ if (twl_initconnection(tw_dev, 1, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL)) {
+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x16, "Connection shutdown failed");
+ } else {
+ printk(KERN_WARNING "3w-sas: Shutdown complete.\n");
+ }
+
+ /* Clear doorbell interrupt just before exit */
+ TWL_CLEAR_DB_INTERRUPT(tw_dev);
+} /* End __twl_shutdown() */
+
+/* Wrapper for __twl_shutdown */
+static void twl_shutdown(struct pci_dev *pdev)
+{
+ struct Scsi_Host *host = pci_get_drvdata(pdev);
+ TW_Device_Extension *tw_dev;
+
+ if (!host)
+ return;
+
+ tw_dev = (TW_Device_Extension *)host->hostdata;
+
+ if (tw_dev->online)
+ __twl_shutdown(tw_dev);
+} /* End twl_shutdown() */
+
+/* This function configures unit settings when a unit is coming on-line */
+static int twl_slave_configure(struct scsi_device *sdev)
+{
+ /* Force 60 second timeout */
+ blk_queue_rq_timeout(sdev->request_queue, 60 * HZ);
+
+ return 0;
+} /* End twl_slave_configure() */
+
+/* scsi_host_template initializer */
+static struct scsi_host_template driver_template = {
+ .module = THIS_MODULE,
+ .name = "3w-sas",
+ .queuecommand = twl_scsi_queue,
+ .eh_host_reset_handler = twl_scsi_eh_reset,
+ .bios_param = twl_scsi_biosparam,
+ .change_queue_depth = twl_change_queue_depth,
+ .can_queue = TW_Q_LENGTH-2,
+ .slave_configure = twl_slave_configure,
+ .this_id = -1,
+ .sg_tablesize = TW_LIBERATOR_MAX_SGL_LENGTH,
+ .max_sectors = TW_MAX_SECTORS,
+ .cmd_per_lun = TW_MAX_CMDS_PER_LUN,
+ .use_clustering = ENABLE_CLUSTERING,
+ .shost_attrs = twl_host_attrs,
+ .emulated = 1
+};
+
+/* This function will probe and initialize a card */
+static int __devinit twl_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
+{
+ struct Scsi_Host *host = NULL;
+ TW_Device_Extension *tw_dev;
+ int retval = -ENODEV;
+ int *ptr_phycount, phycount=0;
+
+ retval = pci_enable_device(pdev);
+ if (retval) {
+ TW_PRINTK(host, TW_DRIVER, 0x17, "Failed to enable pci device");
+ goto out_disable_device;
+ }
+
+ pci_set_master(pdev);
+ pci_try_set_mwi(pdev);
+
+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
+ || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)))
+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
+ || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
+ TW_PRINTK(host, TW_DRIVER, 0x18, "Failed to set dma mask");
+ retval = -ENODEV;
+ goto out_disable_device;
+ }
+
+ host = scsi_host_alloc(&driver_template, sizeof(TW_Device_Extension));
+ if (!host) {
+ TW_PRINTK(host, TW_DRIVER, 0x19, "Failed to allocate memory for device extension");
+ retval = -ENOMEM;
+ goto out_disable_device;
+ }
+ tw_dev = shost_priv(host);
+
+ /* Save values to device extension */
+ tw_dev->host = host;
+ tw_dev->tw_pci_dev = pdev;
+
+ if (twl_initialize_device_extension(tw_dev)) {
+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1a, "Failed to initialize device extension");
+ goto out_free_device_extension;
+ }
+
+ /* Request IO regions */
+ retval = pci_request_regions(pdev, "3w-sas");
+ if (retval) {
+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1b, "Failed to get mem region");
+ goto out_free_device_extension;
+ }
+
+ /* Save base address, use region 1 */
+ tw_dev->base_addr = pci_iomap(pdev, 1, 0);
+ if (!tw_dev->base_addr) {
+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1c, "Failed to ioremap");
+ goto out_release_mem_region;
+ }
+
+ /* Disable interrupts on the card */
+ TWL_MASK_INTERRUPTS(tw_dev);
+
+ /* Initialize the card */
+ if (twl_reset_sequence(tw_dev, 0)) {
+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1d, "Controller reset failed during probe");
+ goto out_iounmap;
+ }
+
+ /* Set host specific parameters */
+ host->max_id = TW_MAX_UNITS;
+ host->max_cmd_len = TW_MAX_CDB_LEN;
+ host->max_lun = TW_MAX_LUNS;
+ host->max_channel = 0;
+
+ /* Register the card with the kernel SCSI layer */
+ retval = scsi_add_host(host, &pdev->dev);
+ if (retval) {
+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1e, "scsi add host failed");
+ goto out_iounmap;
+ }
+
+ pci_set_drvdata(pdev, host);
+
+ printk(KERN_WARNING "3w-sas: scsi%d: Found an LSI 3ware %s Controller at 0x%llx, IRQ: %d.\n",
+ host->host_no,
+ (char *)twl_get_param(tw_dev, 1, TW_VERSION_TABLE,
+ TW_PARAM_MODEL, TW_PARAM_MODEL_LENGTH),
+ (u64)pci_resource_start(pdev, 1), pdev->irq);
+
+ ptr_phycount = twl_get_param(tw_dev, 2, TW_PARAM_PHY_SUMMARY_TABLE,
+ TW_PARAM_PHYCOUNT, TW_PARAM_PHYCOUNT_LENGTH);
+ if (ptr_phycount)
+ phycount = le32_to_cpu(*(int *)ptr_phycount);
+
+ printk(KERN_WARNING "3w-sas: scsi%d: Firmware %s, BIOS %s, Phys: %d.\n",
+ host->host_no,
+ (char *)twl_get_param(tw_dev, 1, TW_VERSION_TABLE,
+ TW_PARAM_FWVER, TW_PARAM_FWVER_LENGTH),
+ (char *)twl_get_param(tw_dev, 2, TW_VERSION_TABLE,
+ TW_PARAM_BIOSVER, TW_PARAM_BIOSVER_LENGTH),
+ phycount);
+
+ /* Try to enable MSI */
+ if (use_msi && !pci_enable_msi(pdev))
+ set_bit(TW_USING_MSI, &tw_dev->flags);
+
+ /* Now setup the interrupt handler */
+ retval = request_irq(pdev->irq, twl_interrupt, IRQF_SHARED, "3w-sas", tw_dev);
+ if (retval) {
+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1f, "Error requesting IRQ");
+ goto out_remove_host;
+ }
+
+ twl_device_extension_list[twl_device_extension_count] = tw_dev;
+ twl_device_extension_count++;
+
+ /* Re-enable interrupts on the card */
+ TWL_UNMASK_INTERRUPTS(tw_dev);
+
+ /* Finally, scan the host */
+ scsi_scan_host(host);
+
+ /* Add sysfs binary files */
+ if (sysfs_create_bin_file(&host->shost_dev.kobj, &twl_sysfs_aen_read_attr))
+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x20, "Failed to create sysfs binary file: 3ware_aen_read");
+ if (sysfs_create_bin_file(&host->shost_dev.kobj, &twl_sysfs_compat_info_attr))
+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x21, "Failed to create sysfs binary file: 3ware_compat_info");
+
+ if (twl_major == -1) {
+ if ((twl_major = register_chrdev (0, "twl", &twl_fops)) < 0)
+ TW_PRINTK(host, TW_DRIVER, 0x22, "Failed to register character device");
+ }
+ tw_dev->online = 1;
+ return 0;
+
+out_remove_host:
+ if (test_bit(TW_USING_MSI, &tw_dev->flags))
+ pci_disable_msi(pdev);
+ scsi_remove_host(host);
+out_iounmap:
+ iounmap(tw_dev->base_addr);
+out_release_mem_region:
+ pci_release_regions(pdev);
+out_free_device_extension:
+ twl_free_device_extension(tw_dev);
+ scsi_host_put(host);
+out_disable_device:
+ pci_disable_device(pdev);
+
+ return retval;
+} /* End twl_probe() */
+
+/* This function is called to remove a device */
+static void twl_remove(struct pci_dev *pdev)
+{
+ struct Scsi_Host *host = pci_get_drvdata(pdev);
+ TW_Device_Extension *tw_dev;
+
+ if (!host)
+ return;
+
+ tw_dev = (TW_Device_Extension *)host->hostdata;
+
+ if (!tw_dev->online)
+ return;
+
+ /* Remove sysfs binary files */
+ sysfs_remove_bin_file(&host->shost_dev.kobj, &twl_sysfs_aen_read_attr);
+ sysfs_remove_bin_file(&host->shost_dev.kobj, &twl_sysfs_compat_info_attr);
+
+ scsi_remove_host(tw_dev->host);
+
+ /* Unregister character device */
+ if (twl_major >= 0) {
+ unregister_chrdev(twl_major, "twl");
+ twl_major = -1;
+ }
+
+ /* Shutdown the card */
+ __twl_shutdown(tw_dev);
+
+ /* Disable MSI if enabled */
+ if (test_bit(TW_USING_MSI, &tw_dev->flags))
+ pci_disable_msi(pdev);
+
+ /* Free IO remapping */
+ iounmap(tw_dev->base_addr);
+
+ /* Free up the mem region */
+ pci_release_regions(pdev);
+
+ /* Free up device extension resources */
+ twl_free_device_extension(tw_dev);
+
+ scsi_host_put(tw_dev->host);
+ pci_disable_device(pdev);
+ twl_device_extension_count--;
+} /* End twl_remove() */
+
+#ifdef CONFIG_PM
+/* This function is called on PCI suspend */
+static int twl_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct Scsi_Host *host = pci_get_drvdata(pdev);
+ TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
+
+ printk(KERN_WARNING "3w-sas: Suspending host %d.\n", tw_dev->host->host_no);
+ /* Disable interrupts */
+ TWL_MASK_INTERRUPTS(tw_dev);
+
+ free_irq(tw_dev->tw_pci_dev->irq, tw_dev);
+
+ /* Tell the card we are shutting down */
+ if (twl_initconnection(tw_dev, 1, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL)) {
+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x23, "Connection shutdown failed during suspend");
+ } else {
+ printk(KERN_WARNING "3w-sas: Suspend complete.\n");
+ }
+
+ /* Clear doorbell interrupt */
+ TWL_CLEAR_DB_INTERRUPT(tw_dev);
+
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+ return 0;
+} /* End twl_suspend() */
+
+/* This function is called on PCI resume */
+static int twl_resume(struct pci_dev *pdev)
+{
+ int retval = 0;
+ struct Scsi_Host *host = pci_get_drvdata(pdev);
+ TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
+
+ printk(KERN_WARNING "3w-sas: Resuming host %d.\n", tw_dev->host->host_no);
+ pci_set_power_state(pdev, PCI_D0);
+ pci_enable_wake(pdev, PCI_D0, 0);
+ pci_restore_state(pdev);
+
+ retval = pci_enable_device(pdev);
+ if (retval) {
+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x24, "Enable device failed during resume");
+ return retval;
+ }
+
+ pci_set_master(pdev);
+ pci_try_set_mwi(pdev);
+
+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
+ || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)))
+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
+ || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
+ TW_PRINTK(host, TW_DRIVER, 0x25, "Failed to set dma mask during resume");
+ retval = -ENODEV;
+ goto out_disable_device;
+ }
+
+ /* Initialize the card */
+ if (twl_reset_sequence(tw_dev, 0)) {
+ retval = -ENODEV;
+ goto out_disable_device;
+ }
+
+ /* Now setup the interrupt handler */
+ retval = request_irq(pdev->irq, twl_interrupt, IRQF_SHARED, "3w-sas", tw_dev);
+ if (retval) {
+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x26, "Error requesting IRQ during resume");
+ retval = -ENODEV;
+ goto out_disable_device;
+ }
+
+ /* Now enable MSI if enabled */
+ if (test_bit(TW_USING_MSI, &tw_dev->flags))
+ pci_enable_msi(pdev);
+
+ /* Re-enable interrupts on the card */
+ TWL_UNMASK_INTERRUPTS(tw_dev);
+
+ printk(KERN_WARNING "3w-sas: Resume complete.\n");
+ return 0;
+
+out_disable_device:
+ scsi_remove_host(host);
+ pci_disable_device(pdev);
+
+ return retval;
+} /* End twl_resume() */
+#endif
+
+/* PCI Devices supported by this driver */
+static struct pci_device_id twl_pci_tbl[] __devinitdata = {
+ { PCI_VDEVICE(3WARE, PCI_DEVICE_ID_3WARE_9750) },
+ { }
+};
+MODULE_DEVICE_TABLE(pci, twl_pci_tbl);
+
+/* pci_driver initializer */
+static struct pci_driver twl_driver = {
+ .name = "3w-sas",
+ .id_table = twl_pci_tbl,
+ .probe = twl_probe,
+ .remove = twl_remove,
+#ifdef CONFIG_PM
+ .suspend = twl_suspend,
+ .resume = twl_resume,
+#endif
+ .shutdown = twl_shutdown
+};
+
+/* This function is called on driver initialization */
+static int __init twl_init(void)
+{
+ printk(KERN_INFO "LSI 3ware SAS/SATA-RAID Controller device driver for Linux v%s.\n", TW_DRIVER_VERSION);
+
+ return pci_register_driver(&twl_driver);
+} /* End twl_init() */
+
+/* This function is called on driver exit */
+static void __exit twl_exit(void)
+{
+ pci_unregister_driver(&twl_driver);
+} /* End twl_exit() */
+
+module_init(twl_init);
+module_exit(twl_exit);
+
diff --git a/drivers/scsi/3w-sas.h b/drivers/scsi/3w-sas.h
new file mode 100644
index 0000000..d474892
--- /dev/null
+++ b/drivers/scsi/3w-sas.h
@@ -0,0 +1,396 @@
+/*
+ 3w-sas.h -- LSI 3ware SAS/SATA-RAID Controller device driver for Linux.
+
+ Written By: Adam Radford <linuxraid@lsi.com>
+
+ Copyright (C) 2009 LSI Corporation.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; 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
+
+ Bugs/Comments/Suggestions should be mailed to:
+ linuxraid@lsi.com
+
+ For more information, goto:
+ http://www.lsi.com
+*/
+
+#ifndef _3W_SAS_H
+#define _3W_SAS_H
+
+/* AEN severity table */
+static char *twl_aen_severity_table[] =
+{
+ "None", "ERROR", "WARNING", "INFO", "DEBUG", NULL
+};
+
+/* Liberator register offsets */
+#define TWL_STATUS 0x0 /* Status */
+#define TWL_HIBDB 0x20 /* Inbound doorbell */
+#define TWL_HISTAT 0x30 /* Host interrupt status */
+#define TWL_HIMASK 0x34 /* Host interrupt mask */
+#define TWL_HOBDB 0x9C /* Outbound doorbell */
+#define TWL_HOBDBC 0xA0 /* Outbound doorbell clear */
+#define TWL_SCRPD3 0xBC /* Scratchpad */
+#define TWL_HIBQPL 0xC0 /* Host inbound Q low */
+#define TWL_HIBQPH 0xC4 /* Host inbound Q high */
+#define TWL_HOBQPL 0xC8 /* Host outbound Q low */
+#define TWL_HOBQPH 0xCC /* Host outbound Q high */
+#define TWL_HISTATUS_VALID_INTERRUPT 0xC
+#define TWL_HISTATUS_ATTENTION_INTERRUPT 0x4
+#define TWL_HISTATUS_RESPONSE_INTERRUPT 0x8
+#define TWL_STATUS_OVERRUN_SUBMIT 0x2000
+#define TWL_ISSUE_SOFT_RESET 0x100
+#define TWL_CONTROLLER_READY 0x2000
+#define TWL_DOORBELL_CONTROLLER_ERROR 0x200000
+#define TWL_DOORBELL_ATTENTION_INTERRUPT 0x40000
+#define TWL_PULL_MODE 0x1
+
+/* Command packet opcodes used by the driver */
+#define TW_OP_INIT_CONNECTION 0x1
+#define TW_OP_GET_PARAM 0x12
+#define TW_OP_SET_PARAM 0x13
+#define TW_OP_EXECUTE_SCSI 0x10
+
+/* Asynchronous Event Notification (AEN) codes used by the driver */
+#define TW_AEN_QUEUE_EMPTY 0x0000
+#define TW_AEN_SOFT_RESET 0x0001
+#define TW_AEN_SYNC_TIME_WITH_HOST 0x031
+#define TW_AEN_SEVERITY_ERROR 0x1
+#define TW_AEN_SEVERITY_DEBUG 0x4
+#define TW_AEN_NOT_RETRIEVED 0x1
+
+/* Command state defines */
+#define TW_S_INITIAL 0x1 /* Initial state */
+#define TW_S_STARTED 0x2 /* Id in use */
+#define TW_S_POSTED 0x4 /* Posted to the controller */
+#define TW_S_COMPLETED 0x8 /* Completed by isr */
+#define TW_S_FINISHED 0x10 /* I/O completely done */
+
+/* Compatibility defines */
+#define TW_9750_ARCH_ID 10
+#define TW_CURRENT_DRIVER_SRL 40
+#define TW_CURRENT_DRIVER_BUILD 0
+#define TW_CURRENT_DRIVER_BRANCH 0
+
+/* Phase defines */
+#define TW_PHASE_INITIAL 0
+#define TW_PHASE_SGLIST 2
+
+/* Misc defines */
+#define TW_SECTOR_SIZE 512
+#define TW_MAX_UNITS 32
+#define TW_INIT_MESSAGE_CREDITS 0x100
+#define TW_INIT_COMMAND_PACKET_SIZE 0x3
+#define TW_INIT_COMMAND_PACKET_SIZE_EXTENDED 0x6
+#define TW_EXTENDED_INIT_CONNECT 0x2
+#define TW_BASE_FW_SRL 24
+#define TW_BASE_FW_BRANCH 0
+#define TW_BASE_FW_BUILD 1
+#define TW_Q_LENGTH 256
+#define TW_Q_START 0
+#define TW_MAX_SLOT 32
+#define TW_MAX_RESET_TRIES 2
+#define TW_MAX_CMDS_PER_LUN 254
+#define TW_MAX_AEN_DRAIN 255
+#define TW_IN_RESET 2
+#define TW_USING_MSI 3
+#define TW_IN_ATTENTION_LOOP 4
+#define TW_MAX_SECTORS 256
+#define TW_MAX_CDB_LEN 16
+#define TW_IOCTL_CHRDEV_TIMEOUT 60 /* 60 seconds */
+#define TW_IOCTL_CHRDEV_FREE -1
+#define TW_COMMAND_OFFSET 128 /* 128 bytes */
+#define TW_VERSION_TABLE 0x0402
+#define TW_TIMEKEEP_TABLE 0x040A
+#define TW_INFORMATION_TABLE 0x0403
+#define TW_PARAM_FWVER 3
+#define TW_PARAM_FWVER_LENGTH 16
+#define TW_PARAM_BIOSVER 4
+#define TW_PARAM_BIOSVER_LENGTH 16
+#define TW_PARAM_MODEL 8
+#define TW_PARAM_MODEL_LENGTH 16
+#define TW_PARAM_PHY_SUMMARY_TABLE 1
+#define TW_PARAM_PHYCOUNT 2
+#define TW_PARAM_PHYCOUNT_LENGTH 1
+#define TW_IOCTL_FIRMWARE_PASS_THROUGH 0x108 // Used by smartmontools
+#define TW_ALLOCATION_LENGTH 128
+#define TW_SENSE_DATA_LENGTH 18
+#define TW_ERROR_LOGICAL_UNIT_NOT_SUPPORTED 0x10a
+#define TW_ERROR_INVALID_FIELD_IN_CDB 0x10d
+#define TW_ERROR_UNIT_OFFLINE 0x128
+#define TW_MESSAGE_SOURCE_CONTROLLER_ERROR 3
+#define TW_MESSAGE_SOURCE_CONTROLLER_EVENT 4
+#define TW_DRIVER 6
+#ifndef PCI_DEVICE_ID_3WARE_9750
+#define PCI_DEVICE_ID_3WARE_9750 0x1010
+#endif
+
+/* Bitmask macros to eliminate bitfields */
+
+/* opcode: 5, reserved: 3 */
+#define TW_OPRES_IN(x,y) ((x << 5) | (y & 0x1f))
+#define TW_OP_OUT(x) (x & 0x1f)
+
+/* opcode: 5, sgloffset: 3 */
+#define TW_OPSGL_IN(x,y) ((x << 5) | (y & 0x1f))
+#define TW_SGL_OUT(x) ((x >> 5) & 0x7)
+
+/* severity: 3, reserved: 5 */
+#define TW_SEV_OUT(x) (x & 0x7)
+
+/* not_mfa: 1, reserved: 7, status: 8, request_id: 16 */
+#define TW_RESID_OUT(x) ((x >> 16) & 0xffff)
+#define TW_NOTMFA_OUT(x) (x & 0x1)
+
+/* request_id: 12, lun: 4 */
+#define TW_REQ_LUN_IN(lun, request_id) (((lun << 12) & 0xf000) | (request_id & 0xfff))
+#define TW_LUN_OUT(lun) ((lun >> 12) & 0xf)
+
+/* Register access macros */
+#define TWL_STATUS_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_STATUS)
+#define TWL_HOBQPL_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HOBQPL)
+#define TWL_HOBQPH_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HOBQPH)
+#define TWL_HOBDB_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HOBDB)
+#define TWL_HOBDBC_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HOBDBC)
+#define TWL_HIMASK_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HIMASK)
+#define TWL_HISTAT_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HISTAT)
+#define TWL_HIBQPH_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HIBQPH)
+#define TWL_HIBQPL_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HIBQPL)
+#define TWL_HIBDB_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HIBDB)
+#define TWL_SCRPD3_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_SCRPD3)
+#define TWL_MASK_INTERRUPTS(x) (writel(~0, TWL_HIMASK_REG_ADDR(tw_dev)))
+#define TWL_UNMASK_INTERRUPTS(x) (writel(~TWL_HISTATUS_VALID_INTERRUPT, TWL_HIMASK_REG_ADDR(tw_dev)))
+#define TWL_CLEAR_DB_INTERRUPT(x) (writel(~0, TWL_HOBDBC_REG_ADDR(tw_dev)))
+#define TWL_SOFT_RESET(x) (writel(TWL_ISSUE_SOFT_RESET, TWL_HIBDB_REG_ADDR(tw_dev)))
+
+/* Macros */
+#define TW_PRINTK(h,a,b,c) { \
+if (h) \
+printk(KERN_WARNING "3w-sas: scsi%d: ERROR: (0x%02X:0x%04X): %s.\n",h->host_no,a,b,c); \
+else \
+printk(KERN_WARNING "3w-sas: ERROR: (0x%02X:0x%04X): %s.\n",a,b,c); \
+}
+#define TW_MAX_LUNS 16
+#define TW_COMMAND_SIZE (sizeof(dma_addr_t) > 4 ? 6 : 4)
+#define TW_LIBERATOR_MAX_SGL_LENGTH (sizeof(dma_addr_t) > 4 ? 46 : 92)
+#define TW_LIBERATOR_MAX_SGL_LENGTH_OLD (sizeof(dma_addr_t) > 4 ? 47 : 94)
+#define TW_PADDING_LENGTH_LIBERATOR 136
+#define TW_PADDING_LENGTH_LIBERATOR_OLD 132
+#define TW_CPU_TO_SGL(x) (sizeof(dma_addr_t) > 4 ? cpu_to_le64(x) : cpu_to_le32(x))
+
+#pragma pack(1)
+
+/* SGL entry */
+typedef struct TAG_TW_SG_Entry_ISO {
+ dma_addr_t address;
+ dma_addr_t length;
+} TW_SG_Entry_ISO;
+
+/* Old Command Packet with ISO SGL */
+typedef struct TW_Command {
+ unsigned char opcode__sgloffset;
+ unsigned char size;
+ unsigned char request_id;
+ unsigned char unit__hostid;
+ /* Second DWORD */
+ unsigned char status;
+ unsigned char flags;
+ union {
+ unsigned short block_count;
+ unsigned short parameter_count;
+ } byte6_offset;
+ union {
+ struct {
+ u32 lba;
+ TW_SG_Entry_ISO sgl[TW_LIBERATOR_MAX_SGL_LENGTH_OLD];
+ unsigned char padding[TW_PADDING_LENGTH_LIBERATOR_OLD];
+ } io;
+ struct {
+ TW_SG_Entry_ISO sgl[TW_LIBERATOR_MAX_SGL_LENGTH_OLD];
+ u32 padding;
+ unsigned char padding2[TW_PADDING_LENGTH_LIBERATOR_OLD];
+ } param;
+ } byte8_offset;
+} TW_Command;
+
+/* New Command Packet with ISO SGL */
+typedef struct TAG_TW_Command_Apache {
+ unsigned char opcode__reserved;
+ unsigned char unit;
+ unsigned short request_id__lunl;
+ unsigned char status;
+ unsigned char sgl_offset;
+ unsigned short sgl_entries__lunh;
+ unsigned char cdb[16];
+ TW_SG_Entry_ISO sg_list[TW_LIBERATOR_MAX_SGL_LENGTH];
+ unsigned char padding[TW_PADDING_LENGTH_LIBERATOR];
+} TW_Command_Apache;
+
+/* New command packet header */
+typedef struct TAG_TW_Command_Apache_Header {
+ unsigned char sense_data[TW_SENSE_DATA_LENGTH];
+ struct {
+ char reserved[4];
+ unsigned short error;
+ unsigned char padding;
+ unsigned char severity__reserved;
+ } status_block;
+ unsigned char err_specific_desc[98];
+ struct {
+ unsigned char size_header;
+ unsigned short request_id;
+ unsigned char size_sense;
+ } header_desc;
+} TW_Command_Apache_Header;
+
+/* This struct is a union of the 2 command packets */
+typedef struct TAG_TW_Command_Full {
+ TW_Command_Apache_Header header;
+ union {
+ TW_Command oldcommand;
+ TW_Command_Apache newcommand;
+ } command;
+} TW_Command_Full;
+
+/* Initconnection structure */
+typedef struct TAG_TW_Initconnect {
+ unsigned char opcode__reserved;
+ unsigned char size;
+ unsigned char request_id;
+ unsigned char res2;
+ unsigned char status;
+ unsigned char flags;
+ unsigned short message_credits;
+ u32 features;
+ unsigned short fw_srl;
+ unsigned short fw_arch_id;
+ unsigned short fw_branch;
+ unsigned short fw_build;
+ u32 result;
+} TW_Initconnect;
+
+/* Event info structure */
+typedef struct TAG_TW_Event
+{
+ unsigned int sequence_id;
+ unsigned int time_stamp_sec;
+ unsigned short aen_code;
+ unsigned char severity;
+ unsigned char retrieved;
+ unsigned char repeat_count;
+ unsigned char parameter_len;
+ unsigned char parameter_data[98];
+} TW_Event;
+
+typedef struct TAG_TW_Ioctl_Driver_Command {
+ unsigned int control_code;
+ unsigned int status;
+ unsigned int unique_id;
+ unsigned int sequence_id;
+ unsigned int os_specific;
+ unsigned int buffer_length;
+} TW_Ioctl_Driver_Command;
+
+typedef struct TAG_TW_Ioctl_Apache {
+ TW_Ioctl_Driver_Command driver_command;
+ char padding[488];
+ TW_Command_Full firmware_command;
+ char data_buffer[1];
+} TW_Ioctl_Buf_Apache;
+
+/* GetParam descriptor */
+typedef struct {
+ unsigned short table_id;
+ unsigned short parameter_id;
+ unsigned short parameter_size_bytes;
+ unsigned short actual_parameter_size_bytes;
+ unsigned char data[1];
+} TW_Param_Apache;
+
+/* Compatibility information structure */
+typedef struct TAG_TW_Compatibility_Info
+{
+ char driver_version[32];
+ unsigned short working_srl;
+ unsigned short working_branch;
+ unsigned short working_build;
+ unsigned short driver_srl_high;
+ unsigned short driver_branch_high;
+ unsigned short driver_build_high;
+ unsigned short driver_srl_low;
+ unsigned short driver_branch_low;
+ unsigned short driver_build_low;
+ unsigned short fw_on_ctlr_srl;
+ unsigned short fw_on_ctlr_branch;
+ unsigned short fw_on_ctlr_build;
+} TW_Compatibility_Info;
+
+#pragma pack()
+
+typedef struct TAG_TW_Device_Extension {
+ void __iomem *base_addr;
+ unsigned long *generic_buffer_virt[TW_Q_LENGTH];
+ dma_addr_t generic_buffer_phys[TW_Q_LENGTH];
+ TW_Command_Full *command_packet_virt[TW_Q_LENGTH];
+ dma_addr_t command_packet_phys[TW_Q_LENGTH];
+ TW_Command_Apache_Header *sense_buffer_virt[TW_Q_LENGTH];
+ dma_addr_t sense_buffer_phys[TW_Q_LENGTH];
+ struct pci_dev *tw_pci_dev;
+ struct scsi_cmnd *srb[TW_Q_LENGTH];
+ unsigned char free_queue[TW_Q_LENGTH];
+ unsigned char free_head;
+ unsigned char free_tail;
+ int state[TW_Q_LENGTH];
+ unsigned int posted_request_count;
+ unsigned int max_posted_request_count;
+ unsigned int max_sgl_entries;
+ unsigned int sgl_entries;
+ unsigned int num_resets;
+ unsigned int sector_count;
+ unsigned int max_sector_count;
+ unsigned int aen_count;
+ struct Scsi_Host *host;
+ long flags;
+ TW_Event *event_queue[TW_Q_LENGTH];
+ unsigned char error_index;
+ unsigned int error_sequence_id;
+ int chrdev_request_id;
+ wait_queue_head_t ioctl_wqueue;
+ struct mutex ioctl_lock;
+ TW_Compatibility_Info tw_compat_info;
+ char online;
+} TW_Device_Extension;
+
+#endif /* _3W_SAS_H */
+
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
index faa0fcf..f65a1e9 100644
--- a/drivers/scsi/3w-xxxx.c
+++ b/drivers/scsi/3w-xxxx.c
@@ -8,7 +8,7 @@
Copyright (C) 1999-2009 3ware Inc.
- Kernel compatiblity By: Andre Hedrick <andre@suse.com>
+ Kernel compatibility By: Andre Hedrick <andre@suse.com>
Non-Copyright (C) 2000 Andre Hedrick <andre@suse.com>
Further tiny build fixes and trivial hoovering Alan Cox
@@ -521,8 +521,12 @@ static ssize_t tw_show_stats(struct device *dev, struct device_attribute *attr,
} /* End tw_show_stats() */
/* This function will set a devices queue depth */
-static int tw_change_queue_depth(struct scsi_device *sdev, int queue_depth)
+static int tw_change_queue_depth(struct scsi_device *sdev, int queue_depth,
+ int reason)
{
+ if (reason != SCSI_QDEPTH_DEFAULT)
+ return -EOPNOTSUPP;
+
if (queue_depth > TW_Q_LENGTH-2)
queue_depth = TW_Q_LENGTH-2;
scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c
index f5a9add..9f4a911 100644
--- a/drivers/scsi/53c700.c
+++ b/drivers/scsi/53c700.c
@@ -175,7 +175,7 @@ STATIC void NCR_700_chip_reset(struct Scsi_Host *host);
STATIC int NCR_700_slave_alloc(struct scsi_device *SDpnt);
STATIC int NCR_700_slave_configure(struct scsi_device *SDpnt);
STATIC void NCR_700_slave_destroy(struct scsi_device *SDpnt);
-static int NCR_700_change_queue_depth(struct scsi_device *SDpnt, int depth);
+static int NCR_700_change_queue_depth(struct scsi_device *SDpnt, int depth, int reason);
static int NCR_700_change_queue_type(struct scsi_device *SDpnt, int depth);
STATIC struct device_attribute *NCR_700_dev_attrs[];
@@ -1491,7 +1491,7 @@ NCR_700_intr(int irq, void *dev_id)
unsigned long flags;
int handled = 0;
- /* Use the host lock to serialise acess to the 53c700
+ /* Use the host lock to serialise access to the 53c700
* hardware. Note: In future, we may need to take the queue
* lock to enter the done routines. When that happens, we
* need to ensure that for this driver, the host lock and the
@@ -2082,8 +2082,11 @@ NCR_700_slave_destroy(struct scsi_device *SDp)
}
static int
-NCR_700_change_queue_depth(struct scsi_device *SDp, int depth)
+NCR_700_change_queue_depth(struct scsi_device *SDp, int depth, int reason)
{
+ if (reason != SCSI_QDEPTH_DEFAULT)
+ return -EOPNOTSUPP;
+
if (depth > NCR_700_MAX_TAGS)
depth = NCR_700_MAX_TAGS;
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index e11cca4..36900c7 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -399,6 +399,17 @@ config SCSI_3W_9XXX
Please read the comments at the top of
<file:drivers/scsi/3w-9xxx.c>.
+config SCSI_3W_SAS
+ tristate "3ware 97xx SAS/SATA-RAID support"
+ depends on PCI && SCSI
+ help
+ This driver supports the LSI 3ware 9750 6Gb/s SAS/SATA-RAID cards.
+
+ <http://www.lsi.com>
+
+ Please read the comments at the top of
+ <file:drivers/scsi/3w-sas.c>.
+
config SCSI_7000FASST
tristate "7000FASST SCSI support"
depends on ISA && SCSI && ISA_DMA_API
@@ -621,6 +632,14 @@ config SCSI_FLASHPOINT
substantial, so users of MultiMaster Host Adapters may not
wish to include it.
+config VMWARE_PVSCSI
+ tristate "VMware PVSCSI driver support"
+ depends on PCI && SCSI && X86
+ help
+ This driver supports VMware's para virtualized SCSI HBA.
+ To compile this driver as a module, choose M here: the
+ module will be called vmw_pvscsi.
+
config LIBFC
tristate "LibFC module"
select SCSI_FC_ATTRS
@@ -644,7 +663,7 @@ config FCOE
config FCOE_FNIC
tristate "Cisco FNIC Driver"
depends on PCI && X86
- select LIBFC
+ select LIBFCOE
help
This is support for the Cisco PCI-Express FCoE HBA.
@@ -1818,6 +1837,14 @@ config SCSI_PMCRAID
---help---
This driver supports the PMC SIERRA MaxRAID adapters.
+config SCSI_PM8001
+ tristate "PMC-Sierra SPC 8001 SAS/SATA Based Host Adapter driver"
+ depends on PCI && SCSI
+ select SCSI_SAS_LIBSAS
+ help
+ This driver supports PMC-Sierra PCIE SAS/SATA 8x6G SPC 8001 chip
+ based host adapters.
+
config SCSI_SRP
tristate "SCSI RDMA Protocol helper library"
depends on SCSI && PCI
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 3ad61db..280d3c6 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -70,6 +70,7 @@ obj-$(CONFIG_SCSI_AIC79XX) += aic7xxx/
obj-$(CONFIG_SCSI_AACRAID) += aacraid/
obj-$(CONFIG_SCSI_AIC7XXX_OLD) += aic7xxx_old.o
obj-$(CONFIG_SCSI_AIC94XX) += aic94xx/
+obj-$(CONFIG_SCSI_PM8001) += pm8001/
obj-$(CONFIG_SCSI_IPS) += ips.o
obj-$(CONFIG_SCSI_FD_MCS) += fd_mcs.o
obj-$(CONFIG_SCSI_FUTURE_DOMAIN)+= fdomain.o
@@ -113,6 +114,7 @@ obj-$(CONFIG_SCSI_MESH) += mesh.o
obj-$(CONFIG_SCSI_MAC53C94) += mac53c94.o
obj-$(CONFIG_BLK_DEV_3W_XXXX_RAID) += 3w-xxxx.o
obj-$(CONFIG_SCSI_3W_9XXX) += 3w-9xxx.o
+obj-$(CONFIG_SCSI_3W_SAS) += 3w-sas.o
obj-$(CONFIG_SCSI_PPA) += ppa.o
obj-$(CONFIG_SCSI_IMM) += imm.o
obj-$(CONFIG_JAZZ_ESP) += esp_scsi.o jazz_esp.o
@@ -133,6 +135,7 @@ obj-$(CONFIG_SCSI_CXGB3_ISCSI) += libiscsi.o libiscsi_tcp.o cxgb3i/
obj-$(CONFIG_SCSI_BNX2_ISCSI) += libiscsi.o bnx2i/
obj-$(CONFIG_BE2ISCSI) += libiscsi.o be2iscsi/
obj-$(CONFIG_SCSI_PMCRAID) += pmcraid.o
+obj-$(CONFIG_VMWARE_PVSCSI) += vmw_pvscsi.o
obj-$(CONFIG_ARM) += arm/
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index cdbdec9..83986ed 100644
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -526,10 +526,10 @@ struct aac_driver_ident
/*
* The adapter interface specs all queues to be located in the same
- * physically contigous block. The host structure that defines the
+ * physically contiguous block. The host structure that defines the
* commuication queues will assume they are each a separate physically
- * contigous memory region that will support them all being one big
- * contigous block.
+ * contiguous memory region that will support them all being one big
+ * contiguous block.
* There is a command and response queue for each level and direction of
* commuication. These regions are accessed by both the host and adapter.
*/
diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c
index d598eba..666d515 100644
--- a/drivers/scsi/aacraid/comminit.c
+++ b/drivers/scsi/aacraid/comminit.c
@@ -226,7 +226,7 @@ static int aac_comm_init(struct aac_dev * dev)
spin_lock_init(&dev->fib_lock);
/*
- * Allocate the physically contigous space for the commuication
+ * Allocate the physically contiguous space for the commuication
* queue headers.
*/
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index 9b97c3e..e9373a2 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -472,8 +472,12 @@ static int aac_slave_configure(struct scsi_device *sdev)
* total capacity and the queue depth supported by the target device.
*/
-static int aac_change_queue_depth(struct scsi_device *sdev, int depth)
+static int aac_change_queue_depth(struct scsi_device *sdev, int depth,
+ int reason)
{
+ if (reason != SCSI_QDEPTH_DEFAULT)
+ return -EOPNOTSUPP;
+
if (sdev->tagged_supported && (sdev->type == TYPE_DISK) &&
(sdev_channel(sdev) == CONTAINER_CHANNEL)) {
struct scsi_device * dev;
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index b756041..22626ab 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -7969,7 +7969,7 @@ static int advansys_reset(struct scsi_cmnd *scp)
ASC_DBG(1, "before AscInitAsc1000Driver()\n");
status = AscInitAsc1000Driver(asc_dvc);
- /* Refer to ASC_IERR_* defintions for meaning of 'err_code'. */
+ /* Refer to ASC_IERR_* definitions 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);
diff --git a/drivers/scsi/aic7xxx/aic79xx.seq b/drivers/scsi/aic7xxx/aic79xx.seq
index 58bc175..2fb78e3 100644
--- a/drivers/scsi/aic7xxx/aic79xx.seq
+++ b/drivers/scsi/aic7xxx/aic79xx.seq
@@ -217,7 +217,7 @@ BEGIN_CRITICAL;
scbdma_tohost_done:
test CCSCBCTL, CCARREN jz fill_qoutfifo_dmadone;
/*
- * An SCB has been succesfully uploaded to the host.
+ * An SCB has been successfully uploaded to the host.
* If the SCB was uploaded for some reason other than
* bad SCSI status (currently only for underruns), we
* queue the SCB for normal completion. Otherwise, we
@@ -1281,7 +1281,7 @@ END_CRITICAL;
* Is it a disconnect message? Set a flag in the SCB to remind us
* and await the bus going free. If this is an untagged transaction
* store the SCB id for it in our untagged target table for lookup on
- * a reselction.
+ * a reselection.
*/
mesgin_disconnect:
/*
diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c
index 63b521d..4d419c1 100644
--- a/drivers/scsi/aic7xxx/aic79xx_core.c
+++ b/drivers/scsi/aic7xxx/aic79xx_core.c
@@ -2487,7 +2487,7 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
/*
* Although the driver does not care about the
* 'Selection in Progress' status bit, the busy
- * LED does. SELINGO is only cleared by a sucessfull
+ * LED does. SELINGO is only cleared by a successfull
* selection, so we must manually clear it to insure
* the LED turns off just incase no future successful
* selections occur (e.g. no devices on the bus).
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index 75b2331..1222a7a 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -2335,7 +2335,7 @@ ahd_linux_queue_abort_cmd(struct scsi_cmnd *cmd)
/*
* The sequencer will never re-reference the
* in-core SCB. To make sure we are notified
- * during reslection, set the MK_MESSAGE flag in
+ * during reselection, set the MK_MESSAGE flag in
* the card's copy of the SCB.
*/
ahd_outb(ahd, SCB_CONTROL,
diff --git a/drivers/scsi/aic7xxx/aic7xxx.seq b/drivers/scsi/aic7xxx/aic7xxx.seq
index 1519639..5a4cfc95 100644
--- a/drivers/scsi/aic7xxx/aic7xxx.seq
+++ b/drivers/scsi/aic7xxx/aic7xxx.seq
@@ -1693,7 +1693,7 @@ if ((ahc->flags & AHC_INITIATORROLE) != 0) {
* Is it a disconnect message? Set a flag in the SCB to remind us
* and await the bus going free. If this is an untagged transaction
* store the SCB id for it in our untagged target table for lookup on
- * a reselction.
+ * a reselection.
*/
mesgin_disconnect:
/*
diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c
index 8dfb59d..45aa728 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_core.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_core.c
@@ -1733,7 +1733,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
/*
* Although the driver does not care about the
* 'Selection in Progress' status bit, the busy
- * LED does. SELINGO is only cleared by a sucessfull
+ * LED does. SELINGO is only cleared by a successfull
* selection, so we must manually clear it to insure
* the LED turns off just incase no future successful
* selections occur (e.g. no devices on the bus).
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
index fd2b978..8cb05dc 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -2290,7 +2290,7 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag)
* In the non-paging case, the sequencer will
* never re-reference the in-core SCB.
* To make sure we are notified during
- * reslection, set the MK_MESSAGE flag in
+ * reselection, set the MK_MESSAGE flag in
* the card's copy of the SCB.
*/
if ((ahc->flags & AHC_PAGESCBS) == 0) {
diff --git a/drivers/scsi/aic94xx/aic94xx_reg_def.h b/drivers/scsi/aic94xx/aic94xx_reg_def.h
index a43e8cd..28aaf34 100644
--- a/drivers/scsi/aic94xx/aic94xx_reg_def.h
+++ b/drivers/scsi/aic94xx/aic94xx_reg_def.h
@@ -1,5 +1,5 @@
/*
- * Aic94xx SAS/SATA driver hardware registers defintions.
+ * Aic94xx SAS/SATA driver hardware registers definitions.
*
* Copyright (C) 2004 Adaptec, Inc. All rights reserved.
* Copyright (C) 2004 David Chaw <david_chaw@adaptec.com>
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index 80aac01..47d5d19 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -98,8 +98,11 @@ 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 int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev,
- int queue_depth)
+ int queue_depth, int reason)
{
+ if (reason != SCSI_QDEPTH_DEFAULT)
+ return -EOPNOTSUPP;
+
if (queue_depth > ARCMSR_MAX_CMD_PERLUN)
queue_depth = ARCMSR_MAX_CMD_PERLUN;
scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
diff --git a/drivers/scsi/be2iscsi/be.h b/drivers/scsi/be2iscsi/be.h
index b36020d..a93a504 100644
--- a/drivers/scsi/be2iscsi/be.h
+++ b/drivers/scsi/be2iscsi/be.h
@@ -20,8 +20,10 @@
#include <linux/pci.h>
#include <linux/if_vlan.h>
-
-#define FW_VER_LEN 32
+#include <linux/blk-iopoll.h>
+#define FW_VER_LEN 32
+#define MCC_Q_LEN 128
+#define MCC_CQ_LEN 256
struct be_dma_mem {
void *va;
@@ -74,18 +76,14 @@ static inline void queue_tail_inc(struct be_queue_info *q)
struct be_eq_obj {
struct be_queue_info q;
- char desc[32];
-
- /* Adaptive interrupt coalescing (AIC) info */
- bool enable_aic;
- u16 min_eqd; /* in usecs */
- u16 max_eqd; /* in usecs */
- u16 cur_eqd; /* in usecs */
+ struct beiscsi_hba *phba;
+ struct be_queue_info *cq;
+ struct blk_iopoll iopoll;
};
struct be_mcc_obj {
- struct be_queue_info *q;
- struct be_queue_info *cq;
+ struct be_queue_info q;
+ struct be_queue_info cq;
};
struct be_ctrl_info {
@@ -176,8 +174,4 @@ static inline void swap_dws(void *wrb, int len)
} while (len);
#endif /* __BIG_ENDIAN */
}
-
-extern void beiscsi_cq_notify(struct be_ctrl_info *ctrl, u16 qid, bool arm,
- u16 num_popped);
-
#endif /* BEISCSI_H */
diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c
index 08007b6..698a527 100644
--- a/drivers/scsi/be2iscsi/be_cmds.c
+++ b/drivers/scsi/be2iscsi/be_cmds.c
@@ -19,6 +19,16 @@
#include "be_mgmt.h"
#include "be_main.h"
+static void be_mcc_notify(struct beiscsi_hba *phba)
+{
+ struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
+ u32 val = 0;
+
+ val |= mccq->id & DB_MCCQ_RING_ID_MASK;
+ val |= 1 << DB_MCCQ_NUM_POSTED_SHIFT;
+ iowrite32(val, phba->db_va + DB_MCCQ_OFFSET);
+}
+
static inline bool be_mcc_compl_is_new(struct be_mcc_compl *compl)
{
if (compl->flags != 0) {
@@ -54,13 +64,56 @@ static int be_mcc_compl_process(struct be_ctrl_info *ctrl,
return 0;
}
+
static inline bool is_link_state_evt(u32 trailer)
{
return (((trailer >> ASYNC_TRAILER_EVENT_CODE_SHIFT) &
- ASYNC_TRAILER_EVENT_CODE_MASK) == ASYNC_EVENT_CODE_LINK_STATE);
+ ASYNC_TRAILER_EVENT_CODE_MASK) ==
+ ASYNC_EVENT_CODE_LINK_STATE);
+}
+
+static struct be_mcc_compl *be_mcc_compl_get(struct beiscsi_hba *phba)
+{
+ struct be_queue_info *mcc_cq = &phba->ctrl.mcc_obj.cq;
+ struct be_mcc_compl *compl = queue_tail_node(mcc_cq);
+
+ if (be_mcc_compl_is_new(compl)) {
+ queue_tail_inc(mcc_cq);
+ return compl;
+ }
+ return NULL;
+}
+
+static void be2iscsi_fail_session(struct iscsi_cls_session *cls_session)
+{
+ iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_CONN_FAILED);
+}
+
+static void beiscsi_async_link_state_process(struct beiscsi_hba *phba,
+ struct be_async_event_link_state *evt)
+{
+ switch (evt->port_link_status) {
+ case ASYNC_EVENT_LINK_DOWN:
+ SE_DEBUG(DBG_LVL_1, "Link Down on Physical Port %d \n",
+ evt->physical_port);
+ phba->state |= BE_ADAPTER_LINK_DOWN;
+ break;
+ case ASYNC_EVENT_LINK_UP:
+ phba->state = BE_ADAPTER_UP;
+ SE_DEBUG(DBG_LVL_1, "Link UP on Physical Port %d \n",
+ evt->physical_port);
+ iscsi_host_for_each_session(phba->shost,
+ be2iscsi_fail_session);
+ break;
+ default:
+ SE_DEBUG(DBG_LVL_1, "Unexpected Async Notification %d on"
+ "Physical Port %d \n",
+ evt->port_link_status,
+ evt->physical_port);
+ }
}
-void beiscsi_cq_notify(struct be_ctrl_info *ctrl, u16 qid, bool arm,
+static void beiscsi_cq_notify(struct beiscsi_hba *phba, u16 qid, bool arm,
u16 num_popped)
{
u32 val = 0;
@@ -68,7 +121,66 @@ void beiscsi_cq_notify(struct be_ctrl_info *ctrl, u16 qid, bool arm,
if (arm)
val |= 1 << DB_CQ_REARM_SHIFT;
val |= num_popped << DB_CQ_NUM_POPPED_SHIFT;
- iowrite32(val, ctrl->db + DB_CQ_OFFSET);
+ iowrite32(val, phba->db_va + DB_CQ_OFFSET);
+}
+
+
+int beiscsi_process_mcc(struct beiscsi_hba *phba)
+{
+ struct be_mcc_compl *compl;
+ int num = 0, status = 0;
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+
+ spin_lock_bh(&phba->ctrl.mcc_cq_lock);
+ while ((compl = be_mcc_compl_get(phba))) {
+ if (compl->flags & CQE_FLAGS_ASYNC_MASK) {
+ /* Interpret flags as an async trailer */
+ BUG_ON(!is_link_state_evt(compl->flags));
+
+ /* Interpret compl as a async link evt */
+ beiscsi_async_link_state_process(phba,
+ (struct be_async_event_link_state *) compl);
+ } else if (compl->flags & CQE_FLAGS_COMPLETED_MASK) {
+ status = be_mcc_compl_process(ctrl, compl);
+ atomic_dec(&phba->ctrl.mcc_obj.q.used);
+ }
+ be_mcc_compl_use(compl);
+ num++;
+ }
+
+ if (num)
+ beiscsi_cq_notify(phba, phba->ctrl.mcc_obj.cq.id, true, num);
+
+ spin_unlock_bh(&phba->ctrl.mcc_cq_lock);
+ return status;
+}
+
+/* Wait till no more pending mcc requests are present */
+static int be_mcc_wait_compl(struct beiscsi_hba *phba)
+{
+#define mcc_timeout 120000 /* 5s timeout */
+ int i, status;
+ for (i = 0; i < mcc_timeout; i++) {
+ status = beiscsi_process_mcc(phba);
+ if (status)
+ return status;
+
+ if (atomic_read(&phba->ctrl.mcc_obj.q.used) == 0)
+ break;
+ udelay(100);
+ }
+ if (i == mcc_timeout) {
+ dev_err(&phba->pcidev->dev, "mccq poll timed out\n");
+ return -1;
+ }
+ return 0;
+}
+
+/* Notify MCC requests and wait for completion */
+int be_mcc_notify_wait(struct beiscsi_hba *phba)
+{
+ be_mcc_notify(phba);
+ return be_mcc_wait_compl(phba);
}
static int be_mbox_db_ready_wait(struct be_ctrl_info *ctrl)
@@ -142,6 +254,52 @@ int be_mbox_notify(struct be_ctrl_info *ctrl)
return 0;
}
+/*
+ * Insert the mailbox address into the doorbell in two steps
+ * Polls on the mbox doorbell till a command completion (or a timeout) occurs
+ */
+static int be_mbox_notify_wait(struct beiscsi_hba *phba)
+{
+ int status;
+ u32 val = 0;
+ void __iomem *db = phba->ctrl.db + MPU_MAILBOX_DB_OFFSET;
+ struct be_dma_mem *mbox_mem = &phba->ctrl.mbox_mem;
+ struct be_mcc_mailbox *mbox = mbox_mem->va;
+ struct be_mcc_compl *compl = &mbox->compl;
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+
+ val |= MPU_MAILBOX_DB_HI_MASK;
+ /* at bits 2 - 31 place mbox dma addr msb bits 34 - 63 */
+ val |= (upper_32_bits(mbox_mem->dma) >> 2) << 2;
+ iowrite32(val, db);
+
+ /* wait for ready to be set */
+ status = be_mbox_db_ready_wait(ctrl);
+ if (status != 0)
+ return status;
+
+ val = 0;
+ /* at bits 2 - 31 place mbox dma addr lsb bits 4 - 33 */
+ val |= (u32)(mbox_mem->dma >> 4) << 2;
+ iowrite32(val, db);
+
+ status = be_mbox_db_ready_wait(ctrl);
+ if (status != 0)
+ return status;
+
+ /* A cq entry has been made now */
+ if (be_mcc_compl_is_new(compl)) {
+ status = be_mcc_compl_process(ctrl, &mbox->compl);
+ be_mcc_compl_use(compl);
+ if (status)
+ return status;
+ } else {
+ dev_err(&phba->pcidev->dev, "invalid mailbox completion\n");
+ return -1;
+ }
+ return 0;
+}
+
void be_wrb_hdr_prepare(struct be_mcc_wrb *wrb, int payload_len,
bool embedded, u8 sge_cnt)
{
@@ -203,6 +361,20 @@ struct be_mcc_wrb *wrb_from_mbox(struct be_dma_mem *mbox_mem)
return &((struct be_mcc_mailbox *)(mbox_mem->va))->wrb;
}
+struct be_mcc_wrb *wrb_from_mccq(struct beiscsi_hba *phba)
+{
+ struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
+ struct be_mcc_wrb *wrb;
+
+ BUG_ON(atomic_read(&mccq->used) >= mccq->len);
+ wrb = queue_head_node(mccq);
+ queue_head_inc(mccq);
+ atomic_inc(&mccq->used);
+ memset(wrb, 0, sizeof(*wrb));
+ return wrb;
+}
+
+
int beiscsi_cmd_eq_create(struct be_ctrl_info *ctrl,
struct be_queue_info *eq, int eq_delay)
{
@@ -212,6 +384,7 @@ int beiscsi_cmd_eq_create(struct be_ctrl_info *ctrl,
struct be_dma_mem *q_mem = &eq->dma_mem;
int status;
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_cmd_eq_create\n");
spin_lock(&ctrl->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
@@ -249,6 +422,7 @@ int be_cmd_fw_initialize(struct be_ctrl_info *ctrl)
int status;
u8 *endian_check;
+ SE_DEBUG(DBG_LVL_8, "In be_cmd_fw_initialize\n");
spin_lock(&ctrl->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
@@ -282,6 +456,7 @@ int beiscsi_cmd_cq_create(struct be_ctrl_info *ctrl,
void *ctxt = &req->context;
int status;
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_cmd_cq_create \n");
spin_lock(&ctrl->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
@@ -289,7 +464,6 @@ int beiscsi_cmd_cq_create(struct be_ctrl_info *ctrl,
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
OPCODE_COMMON_CQ_CREATE, sizeof(*req));
-
if (!q_mem->va)
SE_DEBUG(DBG_LVL_1, "uninitialized q_mem->va\n");
@@ -329,6 +503,53 @@ static u32 be_encoded_q_len(int q_len)
len_encoded = 0;
return len_encoded;
}
+
+int beiscsi_cmd_mccq_create(struct beiscsi_hba *phba,
+ struct be_queue_info *mccq,
+ struct be_queue_info *cq)
+{
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_req_mcc_create *req;
+ struct be_dma_mem *q_mem = &mccq->dma_mem;
+ struct be_ctrl_info *ctrl;
+ void *ctxt;
+ int status;
+
+ spin_lock(&phba->ctrl.mbox_lock);
+ ctrl = &phba->ctrl;
+ wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ req = embedded_payload(wrb);
+ ctxt = &req->context;
+
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_MCC_CREATE, sizeof(*req));
+
+ req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size);
+
+ AMAP_SET_BITS(struct amap_mcc_context, fid, ctxt,
+ PCI_FUNC(phba->pcidev->devfn));
+ AMAP_SET_BITS(struct amap_mcc_context, valid, ctxt, 1);
+ AMAP_SET_BITS(struct amap_mcc_context, ring_size, ctxt,
+ be_encoded_q_len(mccq->len));
+ AMAP_SET_BITS(struct amap_mcc_context, cq_id, ctxt, cq->id);
+
+ be_dws_cpu_to_le(ctxt, sizeof(req->context));
+
+ be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
+
+ status = be_mbox_notify_wait(phba);
+ if (!status) {
+ struct be_cmd_resp_mcc_create *resp = embedded_payload(wrb);
+ mccq->id = le16_to_cpu(resp->id);
+ mccq->created = true;
+ }
+ spin_unlock(&phba->ctrl.mbox_lock);
+
+ return status;
+}
+
int beiscsi_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q,
int queue_type)
{
@@ -337,6 +558,7 @@ int beiscsi_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q,
u8 subsys = 0, opcode = 0;
int status;
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_cmd_q_destroy \n");
spin_lock(&ctrl->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
@@ -350,6 +572,10 @@ int beiscsi_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q,
subsys = CMD_SUBSYSTEM_COMMON;
opcode = OPCODE_COMMON_CQ_DESTROY;
break;
+ case QTYPE_MCCQ:
+ subsys = CMD_SUBSYSTEM_COMMON;
+ opcode = OPCODE_COMMON_MCC_DESTROY;
+ break;
case QTYPE_WRBQ:
subsys = CMD_SUBSYSTEM_ISCSI;
opcode = OPCODE_COMMON_ISCSI_WRBQ_DESTROY;
@@ -377,30 +603,6 @@ int beiscsi_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q,
return status;
}
-int be_cmd_get_mac_addr(struct be_ctrl_info *ctrl, u8 *mac_addr)
-{
- struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
- struct be_cmd_req_get_mac_addr *req = embedded_payload(wrb);
- int status;
-
- spin_lock(&ctrl->mbox_lock);
- memset(wrb, 0, sizeof(*wrb));
- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
- be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
- OPCODE_COMMON_ISCSI_NTWK_GET_NIC_CONFIG,
- sizeof(*req));
-
- status = be_mbox_notify(ctrl);
- if (!status) {
- struct be_cmd_resp_get_mac_addr *resp = embedded_payload(wrb);
-
- memcpy(mac_addr, resp->mac_address, ETH_ALEN);
- }
-
- spin_unlock(&ctrl->mbox_lock);
- return status;
-}
-
int be_cmd_create_default_pdu_queue(struct be_ctrl_info *ctrl,
struct be_queue_info *cq,
struct be_queue_info *dq, int length,
@@ -412,6 +614,7 @@ int be_cmd_create_default_pdu_queue(struct be_ctrl_info *ctrl,
void *ctxt = &req->context;
int status;
+ SE_DEBUG(DBG_LVL_8, "In be_cmd_create_default_pdu_queue\n");
spin_lock(&ctrl->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
@@ -468,8 +671,10 @@ int be_cmd_wrbq_create(struct be_ctrl_info *ctrl, struct be_dma_mem *q_mem,
be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
status = be_mbox_notify(ctrl);
- if (!status)
+ if (!status) {
wrbq->id = le16_to_cpu(resp->cid);
+ wrbq->created = true;
+ }
spin_unlock(&ctrl->mbox_lock);
return status;
}
diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h
index c20d686..5de8acb 100644
--- a/drivers/scsi/be2iscsi/be_cmds.h
+++ b/drivers/scsi/be2iscsi/be_cmds.h
@@ -47,6 +47,8 @@ struct be_mcc_wrb {
#define CQE_FLAGS_VALID_MASK (1 << 31)
#define CQE_FLAGS_ASYNC_MASK (1 << 30)
+#define CQE_FLAGS_COMPLETED_MASK (1 << 28)
+#define CQE_FLAGS_CONSUMED_MASK (1 << 27)
/* Completion Status */
#define MCC_STATUS_SUCCESS 0x0
@@ -173,7 +175,7 @@ struct be_cmd_req_hdr {
u8 domain; /* dword 0 */
u32 timeout; /* dword 1 */
u32 request_length; /* dword 2 */
- u32 rsvd; /* dword 3 */
+ u32 rsvd0; /* dword 3 */
};
struct be_cmd_resp_hdr {
@@ -382,7 +384,6 @@ struct be_cmd_req_modify_eq_delay {
#define ETH_ALEN 6
-
struct be_cmd_req_get_mac_addr {
struct be_cmd_req_hdr hdr;
u32 nic_port_count;
@@ -417,14 +418,21 @@ int beiscsi_cmd_cq_create(struct be_ctrl_info *ctrl,
int beiscsi_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q,
int type);
+int beiscsi_cmd_mccq_create(struct beiscsi_hba *phba,
+ struct be_queue_info *mccq,
+ struct be_queue_info *cq);
+
int be_poll_mcc(struct be_ctrl_info *ctrl);
-unsigned char mgmt_check_supported_fw(struct be_ctrl_info *ctrl);
-int be_cmd_get_mac_addr(struct be_ctrl_info *ctrl, u8 *mac_addr);
+unsigned char mgmt_check_supported_fw(struct be_ctrl_info *ctrl,
+ struct beiscsi_hba *phba);
+int be_cmd_get_mac_addr(struct beiscsi_hba *phba, u8 *mac_addr);
/*ISCSI Functuions */
int be_cmd_fw_initialize(struct be_ctrl_info *ctrl);
struct be_mcc_wrb *wrb_from_mbox(struct be_dma_mem *mbox_mem);
+struct be_mcc_wrb *wrb_from_mccq(struct beiscsi_hba *phba);
+int be_mcc_notify_wait(struct beiscsi_hba *phba);
int be_mbox_notify(struct be_ctrl_info *ctrl);
@@ -531,6 +539,23 @@ struct amap_sol_cqe {
u8 valid; /* dword 3 */
} __packed;
+#define SOL_ICD_INDEX_MASK 0x0003FFC0
+struct amap_sol_cqe_ring {
+ u8 hw_sts[8]; /* dword 0 */
+ u8 i_sts[8]; /* dword 0 */
+ u8 i_resp[8]; /* dword 0 */
+ u8 i_flags[7]; /* dword 0 */
+ u8 s; /* dword 0 */
+ u8 i_exp_cmd_sn[32]; /* dword 1 */
+ u8 code[6]; /* dword 2 */
+ u8 icd_index[12]; /* dword 2 */
+ u8 rsvd[6]; /* dword 2 */
+ u8 i_cmd_wnd[8]; /* dword 2 */
+ u8 i_res_cnt[31]; /* dword 3 */
+ u8 valid; /* dword 3 */
+} __packed;
+
+
/**
* Post WRB Queue Doorbell Register used by the host Storage
@@ -664,8 +689,8 @@ struct be_fw_cfg {
#define OPCODE_COMMON_TCP_UPLOAD 56
#define OPCODE_COMMON_ISCSI_ERROR_RECOVERY_INVALIDATE_COMMANDS 1
/* --- CMD_ISCSI_INVALIDATE_CONNECTION_TYPE --- */
-#define CMD_ISCSI_CONNECTION_INVALIDATE 1
-#define CMD_ISCSI_CONNECTION_ISSUE_TCP_RST 2
+#define CMD_ISCSI_CONNECTION_INVALIDATE 0x8001
+#define CMD_ISCSI_CONNECTION_ISSUE_TCP_RST 0x8002
#define OPCODE_ISCSI_INI_DRIVER_INVALIDATE_CONNECTION 42
#define INI_WR_CMD 1 /* Initiator write command */
diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c
index 2fd2544..d587b03 100644
--- a/drivers/scsi/be2iscsi/be_iscsi.c
+++ b/drivers/scsi/be2iscsi/be_iscsi.c
@@ -67,11 +67,11 @@ struct iscsi_cls_session *beiscsi_session_create(struct iscsi_endpoint *ep,
cmds_max = beiscsi_ep->phba->params.wrbs_per_cxn;
}
- cls_session = iscsi_session_setup(&beiscsi_iscsi_transport,
- shost, cmds_max,
- sizeof(*beiscsi_sess),
- sizeof(*io_task),
- initial_cmdsn, ISCSI_MAX_TARGET);
+ cls_session = iscsi_session_setup(&beiscsi_iscsi_transport,
+ shost, cmds_max,
+ sizeof(*beiscsi_sess),
+ sizeof(*io_task),
+ initial_cmdsn, ISCSI_MAX_TARGET);
if (!cls_session)
return NULL;
sess = cls_session->dd_data;
@@ -297,7 +297,7 @@ int beiscsi_get_host_param(struct Scsi_Host *shost,
switch (param) {
case ISCSI_HOST_PARAM_HWADDRESS:
- be_cmd_get_mac_addr(&phba->ctrl, phba->mac_address);
+ be_cmd_get_mac_addr(phba, phba->mac_address);
len = sysfs_format_mac(buf, phba->mac_address, ETH_ALEN);
break;
default:
@@ -377,16 +377,12 @@ int beiscsi_conn_start(struct iscsi_cls_conn *cls_conn)
struct beiscsi_conn *beiscsi_conn = conn->dd_data;
struct beiscsi_endpoint *beiscsi_ep;
struct beiscsi_offload_params params;
- struct iscsi_session *session = conn->session;
- struct Scsi_Host *shost = iscsi_session_to_shost(session->cls_session);
- struct beiscsi_hba *phba = iscsi_host_priv(shost);
memset(&params, 0, sizeof(struct beiscsi_offload_params));
beiscsi_ep = beiscsi_conn->ep;
if (!beiscsi_ep)
SE_DEBUG(DBG_LVL_1, "In beiscsi_conn_start , no beiscsi_ep\n");
- free_mgmt_sgl_handle(phba, beiscsi_conn->plogin_sgl_handle);
beiscsi_conn->login_in_progress = 0;
beiscsi_set_params_for_offld(beiscsi_conn, &params);
beiscsi_offload_connection(beiscsi_conn, &params);
@@ -498,6 +494,13 @@ beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
SE_DEBUG(DBG_LVL_1, "shost is NULL \n");
return ERR_PTR(ret);
}
+
+ if (phba->state) {
+ ret = -EBUSY;
+ SE_DEBUG(DBG_LVL_1, "The Adapet state is Not UP \n");
+ return ERR_PTR(ret);
+ }
+
ep = iscsi_create_endpoint(sizeof(struct beiscsi_endpoint));
if (!ep) {
ret = -ENOMEM;
diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index 4f1aca3..1a557fa 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -39,7 +39,8 @@
static unsigned int be_iopoll_budget = 10;
static unsigned int be_max_phys_size = 64;
-static unsigned int enable_msix;
+static unsigned int enable_msix = 1;
+static unsigned int ring_mode;
MODULE_DEVICE_TABLE(pci, beiscsi_pci_id_table);
MODULE_DESCRIPTION(DRV_DESC " " BUILD_STR);
@@ -58,6 +59,17 @@ static int beiscsi_slave_configure(struct scsi_device *sdev)
return 0;
}
+/*------------------- PCI Driver operations and data ----------------- */
+static DEFINE_PCI_DEVICE_TABLE(beiscsi_pci_id_table) = {
+ { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID1) },
+ { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID1) },
+ { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID2) },
+ { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID3) },
+ { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID4) },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, beiscsi_pci_id_table);
+
static struct scsi_host_template beiscsi_sht = {
.module = THIS_MODULE,
.name = "ServerEngines 10Gbe open-iscsi Initiator Driver",
@@ -76,16 +88,8 @@ static struct scsi_host_template beiscsi_sht = {
.cmd_per_lun = BEISCSI_CMD_PER_LUN,
.use_clustering = ENABLE_CLUSTERING,
};
-static struct scsi_transport_template *beiscsi_scsi_transport;
-/*------------------- PCI Driver operations and data ----------------- */
-static DEFINE_PCI_DEVICE_TABLE(beiscsi_pci_id_table) = {
- { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID1) },
- { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID1) },
- { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID2) },
- { 0 }
-};
-MODULE_DEVICE_TABLE(pci, beiscsi_pci_id_table);
+static struct scsi_transport_template *beiscsi_scsi_transport;
static struct beiscsi_hba *beiscsi_hba_alloc(struct pci_dev *pcidev)
{
@@ -104,7 +108,6 @@ static struct beiscsi_hba *beiscsi_hba_alloc(struct pci_dev *pcidev)
shost->max_cmd_len = BEISCSI_MAX_CMD_LEN;
shost->max_lun = BEISCSI_NUM_MAX_LUN;
shost->transportt = beiscsi_scsi_transport;
-
phba = iscsi_host_priv(shost);
memset(phba, 0, sizeof(*phba));
phba->shost = shost;
@@ -181,6 +184,7 @@ static int beiscsi_enable_pci(struct pci_dev *pcidev)
return ret;
}
+ pci_set_master(pcidev);
if (pci_set_consistent_dma_mask(pcidev, DMA_BIT_MASK(64))) {
ret = pci_set_consistent_dma_mask(pcidev, DMA_BIT_MASK(32));
if (ret) {
@@ -203,7 +207,6 @@ static int be_ctrl_init(struct beiscsi_hba *phba, struct pci_dev *pdev)
status = beiscsi_map_pci_bars(phba, pdev);
if (status)
return status;
-
mbox_mem_alloc->size = sizeof(struct be_mcc_mailbox) + 16;
mbox_mem_alloc->va = pci_alloc_consistent(pdev,
mbox_mem_alloc->size,
@@ -219,6 +222,9 @@ static int be_ctrl_init(struct beiscsi_hba *phba, struct pci_dev *pdev)
mbox_mem_align->dma = PTR_ALIGN(mbox_mem_alloc->dma, 16);
memset(mbox_mem_align->va, 0, sizeof(struct be_mcc_mailbox));
spin_lock_init(&ctrl->mbox_lock);
+ spin_lock_init(&phba->ctrl.mcc_lock);
+ spin_lock_init(&phba->ctrl.mcc_cq_lock);
+
return status;
}
@@ -268,6 +274,113 @@ static void hwi_ring_eq_db(struct beiscsi_hba *phba,
}
/**
+ * be_isr_mcc - The isr routine of the driver.
+ * @irq: Not used
+ * @dev_id: Pointer to host adapter structure
+ */
+static irqreturn_t be_isr_mcc(int irq, void *dev_id)
+{
+ struct beiscsi_hba *phba;
+ struct be_eq_entry *eqe = NULL;
+ struct be_queue_info *eq;
+ struct be_queue_info *mcc;
+ unsigned int num_eq_processed;
+ struct be_eq_obj *pbe_eq;
+ unsigned long flags;
+
+ pbe_eq = dev_id;
+ eq = &pbe_eq->q;
+ phba = pbe_eq->phba;
+ mcc = &phba->ctrl.mcc_obj.cq;
+ eqe = queue_tail_node(eq);
+ if (!eqe)
+ SE_DEBUG(DBG_LVL_1, "eqe is NULL\n");
+
+ num_eq_processed = 0;
+
+ while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32]
+ & EQE_VALID_MASK) {
+ if (((eqe->dw[offsetof(struct amap_eq_entry,
+ resource_id) / 32] &
+ EQE_RESID_MASK) >> 16) == mcc->id) {
+ spin_lock_irqsave(&phba->isr_lock, flags);
+ phba->todo_mcc_cq = 1;
+ spin_unlock_irqrestore(&phba->isr_lock, flags);
+ }
+ AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
+ queue_tail_inc(eq);
+ eqe = queue_tail_node(eq);
+ num_eq_processed++;
+ }
+ if (phba->todo_mcc_cq)
+ queue_work(phba->wq, &phba->work_cqs);
+ if (num_eq_processed)
+ hwi_ring_eq_db(phba, eq->id, 1, num_eq_processed, 1, 1);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * be_isr_msix - The isr routine of the driver.
+ * @irq: Not used
+ * @dev_id: Pointer to host adapter structure
+ */
+static irqreturn_t be_isr_msix(int irq, void *dev_id)
+{
+ struct beiscsi_hba *phba;
+ struct be_eq_entry *eqe = NULL;
+ struct be_queue_info *eq;
+ struct be_queue_info *cq;
+ unsigned int num_eq_processed;
+ struct be_eq_obj *pbe_eq;
+ unsigned long flags;
+
+ pbe_eq = dev_id;
+ eq = &pbe_eq->q;
+ cq = pbe_eq->cq;
+ eqe = queue_tail_node(eq);
+ if (!eqe)
+ SE_DEBUG(DBG_LVL_1, "eqe is NULL\n");
+
+ phba = pbe_eq->phba;
+ num_eq_processed = 0;
+ if (blk_iopoll_enabled) {
+ while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32]
+ & EQE_VALID_MASK) {
+ if (!blk_iopoll_sched_prep(&pbe_eq->iopoll))
+ blk_iopoll_sched(&pbe_eq->iopoll);
+
+ AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
+ queue_tail_inc(eq);
+ eqe = queue_tail_node(eq);
+ num_eq_processed++;
+ }
+ if (num_eq_processed)
+ hwi_ring_eq_db(phba, eq->id, 1, num_eq_processed, 0, 1);
+
+ return IRQ_HANDLED;
+ } else {
+ while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32]
+ & EQE_VALID_MASK) {
+ spin_lock_irqsave(&phba->isr_lock, flags);
+ phba->todo_cq = 1;
+ spin_unlock_irqrestore(&phba->isr_lock, flags);
+ AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
+ queue_tail_inc(eq);
+ eqe = queue_tail_node(eq);
+ num_eq_processed++;
+ }
+ if (phba->todo_cq)
+ queue_work(phba->wq, &phba->work_cqs);
+
+ if (num_eq_processed)
+ hwi_ring_eq_db(phba, eq->id, 1, num_eq_processed, 1, 1);
+
+ return IRQ_HANDLED;
+ }
+}
+
+/**
* be_isr - The isr routine of the driver.
* @irq: Not used
* @dev_id: Pointer to host adapter structure
@@ -280,48 +393,70 @@ static irqreturn_t be_isr(int irq, void *dev_id)
struct be_eq_entry *eqe = NULL;
struct be_queue_info *eq;
struct be_queue_info *cq;
+ struct be_queue_info *mcc;
unsigned long flags, index;
- unsigned int num_eq_processed;
+ unsigned int num_mcceq_processed, num_ioeq_processed;
struct be_ctrl_info *ctrl;
+ struct be_eq_obj *pbe_eq;
int isr;
phba = dev_id;
- if (!enable_msix) {
- ctrl = &phba->ctrl;;
- isr = ioread32(ctrl->csr + CEV_ISR0_OFFSET +
- (PCI_FUNC(ctrl->pdev->devfn) * CEV_ISR_SIZE));
- if (!isr)
- return IRQ_NONE;
- }
+ ctrl = &phba->ctrl;;
+ isr = ioread32(ctrl->csr + CEV_ISR0_OFFSET +
+ (PCI_FUNC(ctrl->pdev->devfn) * CEV_ISR_SIZE));
+ if (!isr)
+ return IRQ_NONE;
phwi_ctrlr = phba->phwi_ctrlr;
phwi_context = phwi_ctrlr->phwi_ctxt;
- eq = &phwi_context->be_eq.q;
- cq = &phwi_context->be_cq;
+ pbe_eq = &phwi_context->be_eq[0];
+
+ eq = &phwi_context->be_eq[0].q;
+ mcc = &phba->ctrl.mcc_obj.cq;
index = 0;
eqe = queue_tail_node(eq);
if (!eqe)
SE_DEBUG(DBG_LVL_1, "eqe is NULL\n");
- num_eq_processed = 0;
+ num_ioeq_processed = 0;
+ num_mcceq_processed = 0;
if (blk_iopoll_enabled) {
while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32]
& EQE_VALID_MASK) {
- if (!blk_iopoll_sched_prep(&phba->iopoll))
- blk_iopoll_sched(&phba->iopoll);
-
+ if (((eqe->dw[offsetof(struct amap_eq_entry,
+ resource_id) / 32] &
+ EQE_RESID_MASK) >> 16) == mcc->id) {
+ spin_lock_irqsave(&phba->isr_lock, flags);
+ phba->todo_mcc_cq = 1;
+ spin_unlock_irqrestore(&phba->isr_lock, flags);
+ num_mcceq_processed++;
+ } else {
+ if (!blk_iopoll_sched_prep(&pbe_eq->iopoll))
+ blk_iopoll_sched(&pbe_eq->iopoll);
+ num_ioeq_processed++;
+ }
AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
queue_tail_inc(eq);
eqe = queue_tail_node(eq);
- num_eq_processed++;
- SE_DEBUG(DBG_LVL_8, "Valid EQE\n");
}
- if (num_eq_processed) {
- hwi_ring_eq_db(phba, eq->id, 0, num_eq_processed, 0, 1);
+ if (num_ioeq_processed || num_mcceq_processed) {
+ if (phba->todo_mcc_cq)
+ queue_work(phba->wq, &phba->work_cqs);
+
+ if ((num_mcceq_processed) && (!num_ioeq_processed))
+ hwi_ring_eq_db(phba, eq->id, 0,
+ (num_ioeq_processed +
+ num_mcceq_processed) , 1, 1);
+ else
+ hwi_ring_eq_db(phba, eq->id, 0,
+ (num_ioeq_processed +
+ num_mcceq_processed), 0, 1);
+
return IRQ_HANDLED;
} else
return IRQ_NONE;
} else {
+ cq = &phwi_context->be_cq[0];
while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32]
& EQE_VALID_MASK) {
@@ -339,13 +474,14 @@ static irqreturn_t be_isr(int irq, void *dev_id)
AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
queue_tail_inc(eq);
eqe = queue_tail_node(eq);
- num_eq_processed++;
+ num_ioeq_processed++;
}
if (phba->todo_cq || phba->todo_mcc_cq)
queue_work(phba->wq, &phba->work_cqs);
- if (num_eq_processed) {
- hwi_ring_eq_db(phba, eq->id, 0, num_eq_processed, 1, 1);
+ if (num_ioeq_processed) {
+ hwi_ring_eq_db(phba, eq->id, 0,
+ num_ioeq_processed, 1, 1);
return IRQ_HANDLED;
} else
return IRQ_NONE;
@@ -355,13 +491,32 @@ static irqreturn_t be_isr(int irq, void *dev_id)
static int beiscsi_init_irqs(struct beiscsi_hba *phba)
{
struct pci_dev *pcidev = phba->pcidev;
- int ret;
+ struct hwi_controller *phwi_ctrlr;
+ struct hwi_context_memory *phwi_context;
+ int ret, msix_vec, i = 0;
+ char desc[32];
- ret = request_irq(pcidev->irq, be_isr, IRQF_SHARED, "beiscsi", phba);
- if (ret) {
- shost_printk(KERN_ERR, phba->shost, "beiscsi_init_irqs-"
- "Failed to register irq\\n");
- return ret;
+ phwi_ctrlr = phba->phwi_ctrlr;
+ phwi_context = phwi_ctrlr->phwi_ctxt;
+
+ if (phba->msix_enabled) {
+ for (i = 0; i < phba->num_cpus; i++) {
+ sprintf(desc, "beiscsi_msix_%04x", i);
+ msix_vec = phba->msix_entries[i].vector;
+ ret = request_irq(msix_vec, be_isr_msix, 0, desc,
+ &phwi_context->be_eq[i]);
+ }
+ msix_vec = phba->msix_entries[i].vector;
+ ret = request_irq(msix_vec, be_isr_mcc, 0, "beiscsi_msix_mcc",
+ &phwi_context->be_eq[i]);
+ } else {
+ ret = request_irq(pcidev->irq, be_isr, IRQF_SHARED,
+ "beiscsi", phba);
+ if (ret) {
+ shost_printk(KERN_ERR, phba->shost, "beiscsi_init_irqs-"
+ "Failed to register irq\\n");
+ return ret;
+ }
}
return 0;
}
@@ -378,15 +533,6 @@ static void hwi_ring_cq_db(struct beiscsi_hba *phba,
iowrite32(val, phba->db_va + DB_CQ_OFFSET);
}
-/*
- * async pdus include
- * a. unsolicited NOP-In (target initiated NOP-In)
- * b. Async Messages
- * c. Reject PDU
- * d. Login response
- * These headers arrive unprocessed by the EP firmware and iSCSI layer
- * process them
- */
static unsigned int
beiscsi_process_async_pdu(struct beiscsi_conn *beiscsi_conn,
struct beiscsi_hba *phba,
@@ -397,6 +543,9 @@ beiscsi_process_async_pdu(struct beiscsi_conn *beiscsi_conn,
{
struct iscsi_conn *conn = beiscsi_conn->conn;
struct iscsi_session *session = conn->session;
+ struct iscsi_task *task;
+ struct beiscsi_io_task *io_task;
+ struct iscsi_hdr *login_hdr;
switch (ppdu->dw[offsetof(struct amap_pdu_base, opcode) / 32] &
PDUBASE_OPCODE_MASK) {
@@ -412,6 +561,10 @@ beiscsi_process_async_pdu(struct beiscsi_conn *beiscsi_conn,
SE_DEBUG(DBG_LVL_1, "In ISCSI_OP_REJECT\n");
break;
case ISCSI_OP_LOGIN_RSP:
+ task = conn->login_task;
+ io_task = task->dd_data;
+ login_hdr = (struct iscsi_hdr *)ppdu;
+ login_hdr->itt = io_task->libiscsi_itt;
break;
default:
shost_printk(KERN_WARNING, phba->shost,
@@ -440,7 +593,8 @@ static struct sgl_handle *alloc_io_sgl_handle(struct beiscsi_hba *phba)
io_sgl_alloc_index];
phba->io_sgl_hndl_base[phba->io_sgl_alloc_index] = NULL;
phba->io_sgl_hndl_avbl--;
- if (phba->io_sgl_alloc_index == (phba->params.ios_per_ctrl - 1))
+ if (phba->io_sgl_alloc_index == (phba->params.
+ ios_per_ctrl - 1))
phba->io_sgl_alloc_index = 0;
else
phba->io_sgl_alloc_index++;
@@ -490,9 +644,18 @@ struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid,
phwi_ctrlr = phba->phwi_ctrlr;
pwrb_context = &phwi_ctrlr->wrb_context[cid];
- pwrb_handle = pwrb_context->pwrb_handle_base[index];
- pwrb_handle->wrb_index = index;
- pwrb_handle->nxt_wrb_index = index;
+ if (pwrb_context->wrb_handles_available) {
+ pwrb_handle = pwrb_context->pwrb_handle_base[
+ pwrb_context->alloc_index];
+ pwrb_context->wrb_handles_available--;
+ pwrb_handle->nxt_wrb_index = pwrb_handle->wrb_index;
+ if (pwrb_context->alloc_index ==
+ (phba->params.wrbs_per_cxn - 1))
+ pwrb_context->alloc_index = 0;
+ else
+ pwrb_context->alloc_index++;
+ } else
+ pwrb_handle = NULL;
return pwrb_handle;
}
@@ -508,11 +671,20 @@ static void
free_wrb_handle(struct beiscsi_hba *phba, struct hwi_wrb_context *pwrb_context,
struct wrb_handle *pwrb_handle)
{
+ if (!ring_mode)
+ pwrb_context->pwrb_handle_base[pwrb_context->free_index] =
+ pwrb_handle;
+ pwrb_context->wrb_handles_available++;
+ if (pwrb_context->free_index == (phba->params.wrbs_per_cxn - 1))
+ pwrb_context->free_index = 0;
+ else
+ pwrb_context->free_index++;
+
SE_DEBUG(DBG_LVL_8,
- "FREE WRB: pwrb_handle=%p free_index=%d=0x%x"
+ "FREE WRB: pwrb_handle=%p free_index=0x%x"
"wrb_handles_available=%d \n",
pwrb_handle, pwrb_context->free_index,
- pwrb_context->free_index, pwrb_context->wrb_handles_available);
+ pwrb_context->wrb_handles_available);
}
static struct sgl_handle *alloc_mgmt_sgl_handle(struct beiscsi_hba *phba)
@@ -540,6 +712,8 @@ void
free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle)
{
+ SE_DEBUG(DBG_LVL_8, "In free_mgmt_sgl_handle,eh_sgl_free_index=%d \n",
+ phba->eh_sgl_free_index);
if (phba->eh_sgl_hndl_base[phba->eh_sgl_free_index]) {
/*
* this can happen if clean_task is called on a task that
@@ -572,10 +746,10 @@ be_complete_io(struct beiscsi_conn *beiscsi_conn,
u32 resid = 0, exp_cmdsn, max_cmdsn;
u8 rsp, status, flags;
- exp_cmdsn = be32_to_cpu(psol->
+ exp_cmdsn = (psol->
dw[offsetof(struct amap_sol_cqe, i_exp_cmd_sn) / 32]
& SOL_EXP_CMD_SN_MASK);
- max_cmdsn = be32_to_cpu((psol->
+ max_cmdsn = ((psol->
dw[offsetof(struct amap_sol_cqe, i_exp_cmd_sn) / 32]
& SOL_EXP_CMD_SN_MASK) +
((psol->dw[offsetof(struct amap_sol_cqe, i_cmd_wnd)
@@ -610,9 +784,9 @@ be_complete_io(struct beiscsi_conn *beiscsi_conn,
}
if (status == SAM_STAT_CHECK_CONDITION) {
+ unsigned short *slen = (unsigned short *)sts_bhs->sense_info;
sense = sts_bhs->sense_info + sizeof(unsigned short);
- sense_len =
- cpu_to_be16((unsigned short)(sts_bhs->sense_info[0]));
+ sense_len = cpu_to_be16(*slen);
memcpy(task->sc->sense_buffer, sense,
min_t(u16, sense_len, SCSI_SENSE_BUFFERSIZE));
}
@@ -620,8 +794,8 @@ be_complete_io(struct beiscsi_conn *beiscsi_conn,
if (psol->dw[offsetof(struct amap_sol_cqe, i_res_cnt) / 32]
& SOL_RES_CNT_MASK)
conn->rxdata_octets += (psol->
- dw[offsetof(struct amap_sol_cqe, i_res_cnt) / 32]
- & SOL_RES_CNT_MASK);
+ dw[offsetof(struct amap_sol_cqe, i_res_cnt) / 32]
+ & SOL_RES_CNT_MASK);
}
unmap:
scsi_dma_unmap(io_task->scsi_cmnd);
@@ -633,6 +807,7 @@ be_complete_logout(struct beiscsi_conn *beiscsi_conn,
struct iscsi_task *task, struct sol_cqe *psol)
{
struct iscsi_logout_rsp *hdr;
+ struct beiscsi_io_task *io_task = task->dd_data;
struct iscsi_conn *conn = beiscsi_conn->conn;
hdr = (struct iscsi_logout_rsp *)task->hdr;
@@ -651,7 +826,7 @@ be_complete_logout(struct beiscsi_conn *beiscsi_conn,
((psol->dw[offsetof(struct amap_sol_cqe, i_cmd_wnd)
/ 32] & SOL_CMD_WND_MASK) >> 24) - 1);
hdr->hlength = 0;
-
+ hdr->itt = io_task->libiscsi_itt;
__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0);
}
@@ -661,6 +836,7 @@ be_complete_tmf(struct beiscsi_conn *beiscsi_conn,
{
struct iscsi_tm_rsp *hdr;
struct iscsi_conn *conn = beiscsi_conn->conn;
+ struct beiscsi_io_task *io_task = task->dd_data;
hdr = (struct iscsi_tm_rsp *)task->hdr;
hdr->flags = ((psol->dw[offsetof(struct amap_sol_cqe, i_flags) / 32]
@@ -668,11 +844,12 @@ be_complete_tmf(struct beiscsi_conn *beiscsi_conn,
hdr->response = (psol->dw[offsetof(struct amap_sol_cqe, i_resp) /
32] & SOL_RESP_MASK);
hdr->exp_cmdsn = cpu_to_be32(psol->dw[offsetof(struct amap_sol_cqe,
- i_exp_cmd_sn) / 32] & SOL_EXP_CMD_SN_MASK);
+ i_exp_cmd_sn) / 32] & SOL_EXP_CMD_SN_MASK);
hdr->max_cmdsn = be32_to_cpu((psol->dw[offsetof(struct amap_sol_cqe,
i_exp_cmd_sn) / 32] & SOL_EXP_CMD_SN_MASK) +
((psol->dw[offsetof(struct amap_sol_cqe, i_cmd_wnd)
/ 32] & SOL_CMD_WND_MASK) >> 24) - 1);
+ hdr->itt = io_task->libiscsi_itt;
__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0);
}
@@ -681,18 +858,36 @@ hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn,
struct beiscsi_hba *phba, struct sol_cqe *psol)
{
struct hwi_wrb_context *pwrb_context;
- struct wrb_handle *pwrb_handle;
+ struct wrb_handle *pwrb_handle = NULL;
+ struct sgl_handle *psgl_handle = NULL;
struct hwi_controller *phwi_ctrlr;
+ struct iscsi_task *task;
+ struct beiscsi_io_task *io_task;
struct iscsi_conn *conn = beiscsi_conn->conn;
struct iscsi_session *session = conn->session;
phwi_ctrlr = phba->phwi_ctrlr;
- pwrb_context = &phwi_ctrlr->wrb_context[((psol->
+ if (ring_mode) {
+ psgl_handle = phba->sgl_hndl_array[((psol->
+ dw[offsetof(struct amap_sol_cqe_ring, icd_index) /
+ 32] & SOL_ICD_INDEX_MASK) >> 6)];
+ pwrb_context = &phwi_ctrlr->wrb_context[psgl_handle->cid];
+ task = psgl_handle->task;
+ pwrb_handle = NULL;
+ } else {
+ pwrb_context = &phwi_ctrlr->wrb_context[((psol->
dw[offsetof(struct amap_sol_cqe, cid) / 32] &
SOL_CID_MASK) >> 6)];
- pwrb_handle = pwrb_context->pwrb_handle_basestd[((psol->
+ pwrb_handle = pwrb_context->pwrb_handle_basestd[((psol->
dw[offsetof(struct amap_sol_cqe, wrb_index) /
32] & SOL_WRB_INDEX_MASK) >> 16)];
+ task = pwrb_handle->pio_handle;
+ }
+
+ io_task = task->dd_data;
+ spin_lock(&phba->mgmt_sgl_lock);
+ free_mgmt_sgl_handle(phba, io_task->psgl_handle);
+ spin_unlock(&phba->mgmt_sgl_lock);
spin_lock_bh(&session->lock);
free_wrb_handle(phba, pwrb_context, pwrb_handle);
spin_unlock_bh(&session->lock);
@@ -704,6 +899,7 @@ be_complete_nopin_resp(struct beiscsi_conn *beiscsi_conn,
{
struct iscsi_nopin *hdr;
struct iscsi_conn *conn = beiscsi_conn->conn;
+ struct beiscsi_io_task *io_task = task->dd_data;
hdr = (struct iscsi_nopin *)task->hdr;
hdr->flags = ((psol->dw[offsetof(struct amap_sol_cqe, i_flags) / 32]
@@ -715,6 +911,7 @@ be_complete_nopin_resp(struct beiscsi_conn *beiscsi_conn,
((psol->dw[offsetof(struct amap_sol_cqe, i_cmd_wnd)
/ 32] & SOL_CMD_WND_MASK) >> 24) - 1);
hdr->opcode = ISCSI_OP_NOOP_IN;
+ hdr->itt = io_task->libiscsi_itt;
__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0);
}
@@ -726,25 +923,33 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn,
struct iscsi_wrb *pwrb = NULL;
struct hwi_controller *phwi_ctrlr;
struct iscsi_task *task;
- struct beiscsi_io_task *io_task;
+ struct sgl_handle *psgl_handle = NULL;
+ unsigned int type;
struct iscsi_conn *conn = beiscsi_conn->conn;
struct iscsi_session *session = conn->session;
phwi_ctrlr = phba->phwi_ctrlr;
-
- pwrb_context = &phwi_ctrlr->
- wrb_context[((psol->dw[offsetof(struct amap_sol_cqe, cid) / 32]
- & SOL_CID_MASK) >> 6)];
- pwrb_handle = pwrb_context->pwrb_handle_basestd[((psol->
+ if (ring_mode) {
+ psgl_handle = phba->sgl_hndl_array[((psol->
+ dw[offsetof(struct amap_sol_cqe_ring, icd_index) /
+ 32] & SOL_ICD_INDEX_MASK) >> 6)];
+ task = psgl_handle->task;
+ type = psgl_handle->type;
+ } else {
+ pwrb_context = &phwi_ctrlr->
+ wrb_context[((psol->dw[offsetof
+ (struct amap_sol_cqe, cid) / 32]
+ & SOL_CID_MASK) >> 6)];
+ pwrb_handle = pwrb_context->pwrb_handle_basestd[((psol->
dw[offsetof(struct amap_sol_cqe, wrb_index) /
32] & SOL_WRB_INDEX_MASK) >> 16)];
-
- task = pwrb_handle->pio_handle;
- io_task = task->dd_data;
+ task = pwrb_handle->pio_handle;
+ pwrb = pwrb_handle->pwrb;
+ type = (pwrb->dw[offsetof(struct amap_iscsi_wrb, type) / 32] &
+ WRB_TYPE_MASK) >> 28;
+ }
spin_lock_bh(&session->lock);
- pwrb = pwrb_handle->pwrb;
- switch ((pwrb->dw[offsetof(struct amap_iscsi_wrb, type) / 32] &
- WRB_TYPE_MASK) >> 28) {
+ switch (type) {
case HWH_TYPE_IO:
case HWH_TYPE_IO_RD:
if ((task->hdr->opcode & ISCSI_OPCODE_MASK) ==
@@ -773,12 +978,21 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn,
break;
default:
- shost_printk(KERN_WARNING, phba->shost,
- "wrb_index 0x%x CID 0x%x\n",
- ((psol->dw[offsetof(struct amap_iscsi_wrb, type) /
- 32] & SOL_WRB_INDEX_MASK) >> 16),
- ((psol->dw[offsetof(struct amap_sol_cqe, cid) / 32]
- & SOL_CID_MASK) >> 6));
+ if (ring_mode)
+ shost_printk(KERN_WARNING, phba->shost,
+ "In hwi_complete_cmd, unknown type = %d"
+ "icd_index 0x%x CID 0x%x\n", type,
+ ((psol->dw[offsetof(struct amap_sol_cqe_ring,
+ icd_index) / 32] & SOL_ICD_INDEX_MASK) >> 6),
+ psgl_handle->cid);
+ else
+ shost_printk(KERN_WARNING, phba->shost,
+ "In hwi_complete_cmd, unknown type = %d"
+ "wrb_index 0x%x CID 0x%x\n", type,
+ ((psol->dw[offsetof(struct amap_iscsi_wrb,
+ type) / 32] & SOL_WRB_INDEX_MASK) >> 16),
+ ((psol->dw[offsetof(struct amap_sol_cqe,
+ cid) / 32] & SOL_CID_MASK) >> 6));
break;
}
@@ -1208,40 +1422,55 @@ static void hwi_process_default_pdu_ring(struct beiscsi_conn *beiscsi_conn,
hwi_post_async_buffers(phba, pasync_handle->is_header);
}
-static unsigned int beiscsi_process_cq(struct beiscsi_hba *phba)
+
+static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq)
{
- struct hwi_controller *phwi_ctrlr;
- struct hwi_context_memory *phwi_context;
struct be_queue_info *cq;
struct sol_cqe *sol;
struct dmsg_cqe *dmsg;
unsigned int num_processed = 0;
unsigned int tot_nump = 0;
struct beiscsi_conn *beiscsi_conn;
+ struct sgl_handle *psgl_handle = NULL;
+ struct beiscsi_hba *phba;
- phwi_ctrlr = phba->phwi_ctrlr;
- phwi_context = phwi_ctrlr->phwi_ctxt;
- cq = &phwi_context->be_cq;
+ cq = pbe_eq->cq;
sol = queue_tail_node(cq);
+ phba = pbe_eq->phba;
while (sol->dw[offsetof(struct amap_sol_cqe, valid) / 32] &
CQE_VALID_MASK) {
be_dws_le_to_cpu(sol, sizeof(struct sol_cqe));
- beiscsi_conn = phba->conn_table[(u32) (sol->
+ if (ring_mode) {
+ psgl_handle = phba->sgl_hndl_array[((sol->
+ dw[offsetof(struct amap_sol_cqe_ring,
+ icd_index) / 32] & SOL_ICD_INDEX_MASK)
+ >> 6)];
+ beiscsi_conn = phba->conn_table[psgl_handle->cid];
+ if (!beiscsi_conn || !beiscsi_conn->ep) {
+ shost_printk(KERN_WARNING, phba->shost,
+ "Connection table empty for cid = %d\n",
+ psgl_handle->cid);
+ return 0;
+ }
+
+ } else {
+ beiscsi_conn = phba->conn_table[(u32) (sol->
dw[offsetof(struct amap_sol_cqe, cid) / 32] &
SOL_CID_MASK) >> 6];
- if (!beiscsi_conn || !beiscsi_conn->ep) {
- shost_printk(KERN_WARNING, phba->shost,
+ if (!beiscsi_conn || !beiscsi_conn->ep) {
+ shost_printk(KERN_WARNING, phba->shost,
"Connection table empty for cid = %d\n",
(u32)(sol->dw[offsetof(struct amap_sol_cqe,
cid) / 32] & SOL_CID_MASK) >> 6);
- return 0;
+ return 0;
+ }
}
if (num_processed >= 32) {
- hwi_ring_cq_db(phba, phwi_context->be_cq.id,
+ hwi_ring_cq_db(phba, cq->id,
num_processed, 0, 0);
tot_nump += num_processed;
num_processed = 0;
@@ -1258,8 +1487,12 @@ static unsigned int beiscsi_process_cq(struct beiscsi_hba *phba)
hwi_complete_drvr_msgs(beiscsi_conn, phba, sol);
break;
case UNSOL_HDR_NOTIFY:
+ SE_DEBUG(DBG_LVL_8, "Received UNSOL_HDR_ NOTIFY\n");
+ hwi_process_default_pdu_ring(beiscsi_conn, phba,
+ (struct i_t_dpdu_cqe *)sol);
+ break;
case UNSOL_DATA_NOTIFY:
- SE_DEBUG(DBG_LVL_8, "Received UNSOL_HDR/DATA_NOTIFY\n");
+ SE_DEBUG(DBG_LVL_8, "Received UNSOL_DATA_NOTIFY\n");
hwi_process_default_pdu_ring(beiscsi_conn, phba,
(struct i_t_dpdu_cqe *)sol);
break;
@@ -1278,13 +1511,21 @@ static unsigned int beiscsi_process_cq(struct beiscsi_hba *phba)
case CMD_CXN_KILLED_ITT_INVALID:
case CMD_CXN_KILLED_SEQ_OUTOFORDER:
case CMD_CXN_KILLED_INVALID_DATASN_RCVD:
- SE_DEBUG(DBG_LVL_1,
+ if (ring_mode) {
+ SE_DEBUG(DBG_LVL_1,
+ "CQ Error notification for cmd.. "
+ "code %d cid 0x%x\n",
+ sol->dw[offsetof(struct amap_sol_cqe, code) /
+ 32] & CQE_CODE_MASK, psgl_handle->cid);
+ } else {
+ SE_DEBUG(DBG_LVL_1,
"CQ Error notification for cmd.. "
"code %d cid 0x%x\n",
sol->dw[offsetof(struct amap_sol_cqe, code) /
32] & CQE_CODE_MASK,
(sol->dw[offsetof(struct amap_sol_cqe, cid) /
32] & SOL_CID_MASK));
+ }
break;
case UNSOL_DATA_DIGEST_ERROR_NOTIFY:
SE_DEBUG(DBG_LVL_1,
@@ -1306,23 +1547,37 @@ static unsigned int beiscsi_process_cq(struct beiscsi_hba *phba)
case CXN_KILLED_OVER_RUN_RESIDUAL:
case CXN_KILLED_UNDER_RUN_RESIDUAL:
case CXN_KILLED_CMND_DATA_NOT_ON_SAME_CONN:
- SE_DEBUG(DBG_LVL_1, "CQ Error %d, resetting CID "
+ if (ring_mode) {
+ SE_DEBUG(DBG_LVL_1, "CQ Error %d, reset CID "
+ "0x%x...\n",
+ sol->dw[offsetof(struct amap_sol_cqe, code) /
+ 32] & CQE_CODE_MASK, psgl_handle->cid);
+ } else {
+ SE_DEBUG(DBG_LVL_1, "CQ Error %d, reset CID "
"0x%x...\n",
sol->dw[offsetof(struct amap_sol_cqe, code) /
32] & CQE_CODE_MASK,
sol->dw[offsetof(struct amap_sol_cqe, cid) /
32] & CQE_CID_MASK);
+ }
iscsi_conn_failure(beiscsi_conn->conn,
ISCSI_ERR_CONN_FAILED);
break;
case CXN_KILLED_RST_SENT:
case CXN_KILLED_RST_RCVD:
- SE_DEBUG(DBG_LVL_1, "CQ Error %d, reset received/sent "
- "on CID 0x%x...\n",
+ if (ring_mode) {
+ SE_DEBUG(DBG_LVL_1, "CQ Error %d, reset"
+ "received/sent on CID 0x%x...\n",
+ sol->dw[offsetof(struct amap_sol_cqe, code) /
+ 32] & CQE_CODE_MASK, psgl_handle->cid);
+ } else {
+ SE_DEBUG(DBG_LVL_1, "CQ Error %d, reset"
+ "received/sent on CID 0x%x...\n",
sol->dw[offsetof(struct amap_sol_cqe, code) /
32] & CQE_CODE_MASK,
sol->dw[offsetof(struct amap_sol_cqe, cid) /
32] & CQE_CID_MASK);
+ }
iscsi_conn_failure(beiscsi_conn->conn,
ISCSI_ERR_CONN_FAILED);
break;
@@ -1344,8 +1599,7 @@ static unsigned int beiscsi_process_cq(struct beiscsi_hba *phba)
if (num_processed > 0) {
tot_nump += num_processed;
- hwi_ring_cq_db(phba, phwi_context->be_cq.id, num_processed,
- 1, 0);
+ hwi_ring_cq_db(phba, cq->id, num_processed, 1, 0);
}
return tot_nump;
}
@@ -1353,21 +1607,30 @@ static unsigned int beiscsi_process_cq(struct beiscsi_hba *phba)
static void beiscsi_process_all_cqs(struct work_struct *work)
{
unsigned long flags;
+ struct hwi_controller *phwi_ctrlr;
+ struct hwi_context_memory *phwi_context;
+ struct be_eq_obj *pbe_eq;
struct beiscsi_hba *phba =
container_of(work, struct beiscsi_hba, work_cqs);
+ phwi_ctrlr = phba->phwi_ctrlr;
+ phwi_context = phwi_ctrlr->phwi_ctxt;
+ if (phba->msix_enabled)
+ pbe_eq = &phwi_context->be_eq[phba->num_cpus];
+ else
+ pbe_eq = &phwi_context->be_eq[0];
+
if (phba->todo_mcc_cq) {
spin_lock_irqsave(&phba->isr_lock, flags);
phba->todo_mcc_cq = 0;
spin_unlock_irqrestore(&phba->isr_lock, flags);
- SE_DEBUG(DBG_LVL_1, "MCC Interrupt Not expected \n");
}
if (phba->todo_cq) {
spin_lock_irqsave(&phba->isr_lock, flags);
phba->todo_cq = 0;
spin_unlock_irqrestore(&phba->isr_lock, flags);
- beiscsi_process_cq(phba);
+ beiscsi_process_cq(pbe_eq);
}
}
@@ -1375,19 +1638,15 @@ static int be_iopoll(struct blk_iopoll *iop, int budget)
{
static unsigned int ret;
struct beiscsi_hba *phba;
+ struct be_eq_obj *pbe_eq;
- phba = container_of(iop, struct beiscsi_hba, iopoll);
-
- ret = beiscsi_process_cq(phba);
+ pbe_eq = container_of(iop, struct be_eq_obj, iopoll);
+ ret = beiscsi_process_cq(pbe_eq);
if (ret < budget) {
- struct hwi_controller *phwi_ctrlr;
- struct hwi_context_memory *phwi_context;
-
- phwi_ctrlr = phba->phwi_ctrlr;
- phwi_context = phwi_ctrlr->phwi_ctxt;
+ phba = pbe_eq->phba;
blk_iopoll_complete(iop);
- hwi_ring_eq_db(phba, phwi_context->be_eq.q.id, 0,
- 0, 1, 1);
+ SE_DEBUG(DBG_LVL_8, "rearm pbe_eq->q.id =%d\n", pbe_eq->q.id);
+ hwi_ring_eq_db(phba, pbe_eq->q.id, 0, 0, 1, 1);
}
return ret;
}
@@ -1537,14 +1796,12 @@ static void hwi_write_buffer(struct iscsi_wrb *pwrb, struct iscsi_task *task)
static void beiscsi_find_mem_req(struct beiscsi_hba *phba)
{
- unsigned int num_cq_pages, num_eq_pages, num_async_pdu_buf_pages;
+ unsigned int num_cq_pages, num_async_pdu_buf_pages;
unsigned int num_async_pdu_data_pages, wrb_sz_per_cxn;
unsigned int num_async_pdu_buf_sgl_pages, num_async_pdu_data_sgl_pages;
num_cq_pages = PAGES_REQUIRED(phba->params.num_cq_entries * \
sizeof(struct sol_cqe));
- num_eq_pages = PAGES_REQUIRED(phba->params.num_eq_entries * \
- sizeof(struct be_eq_entry));
num_async_pdu_buf_pages =
PAGES_REQUIRED(phba->params.asyncpdus_per_ctrl * \
phba->params.defpdu_hdr_sz);
@@ -1565,8 +1822,6 @@ static void beiscsi_find_mem_req(struct beiscsi_hba *phba)
phba->mem_req[HWI_MEM_ADDN_CONTEXT] =
sizeof(struct hwi_context_memory);
- phba->mem_req[HWI_MEM_CQ] = num_cq_pages * PAGE_SIZE;
- phba->mem_req[HWI_MEM_EQ] = num_eq_pages * PAGE_SIZE;
phba->mem_req[HWI_MEM_WRB] = sizeof(struct iscsi_wrb)
* (phba->params.wrbs_per_cxn)
@@ -1751,8 +2006,6 @@ static void beiscsi_init_wrb_handle(struct beiscsi_hba *phba)
for (index = 0; index < phba->params.cxns_per_ctrl * 2; index += 2) {
pwrb_context = &phwi_ctrlr->wrb_context[index];
- SE_DEBUG(DBG_LVL_8, "cid=%d pwrb_context=%p \n", index,
- pwrb_context);
pwrb_context->pwrb_handle_base =
kzalloc(sizeof(struct wrb_handle *) *
phba->params.wrbs_per_cxn, GFP_KERNEL);
@@ -1767,6 +2020,7 @@ static void beiscsi_init_wrb_handle(struct beiscsi_hba *phba)
pwrb_context->pwrb_handle_basestd[j] =
pwrb_handle;
pwrb_context->wrb_handles_available++;
+ pwrb_handle->wrb_index = j;
pwrb_handle++;
}
pwrb_context->free_index = 0;
@@ -1785,6 +2039,7 @@ static void beiscsi_init_wrb_handle(struct beiscsi_hba *phba)
pwrb_context->pwrb_handle_basestd[j] =
pwrb_handle;
pwrb_context->wrb_handles_available++;
+ pwrb_handle->wrb_index = j;
pwrb_handle++;
}
pwrb_context->free_index = 0;
@@ -2042,79 +2297,126 @@ static int be_fill_queue(struct be_queue_info *q,
return 0;
}
-static int beiscsi_create_eq(struct beiscsi_hba *phba,
+static int beiscsi_create_eqs(struct beiscsi_hba *phba,
struct hwi_context_memory *phwi_context)
{
- unsigned int idx;
- int ret;
+ unsigned int i, num_eq_pages;
+ int ret, eq_for_mcc;
struct be_queue_info *eq;
struct be_dma_mem *mem;
- struct be_mem_descriptor *mem_descr;
void *eq_vaddress;
+ dma_addr_t paddr;
- idx = 0;
- eq = &phwi_context->be_eq.q;
- mem = &eq->dma_mem;
- mem_descr = phba->init_mem;
- mem_descr += HWI_MEM_EQ;
- eq_vaddress = mem_descr->mem_array[idx].virtual_address;
-
- ret = be_fill_queue(eq, phba->params.num_eq_entries,
- sizeof(struct be_eq_entry), eq_vaddress);
- if (ret) {
- shost_printk(KERN_ERR, phba->shost,
- "be_fill_queue Failed for EQ \n");
- return ret;
- }
+ num_eq_pages = PAGES_REQUIRED(phba->params.num_eq_entries * \
+ sizeof(struct be_eq_entry));
- mem->dma = mem_descr->mem_array[idx].bus_address.u.a64.address;
+ if (phba->msix_enabled)
+ eq_for_mcc = 1;
+ else
+ eq_for_mcc = 0;
+ for (i = 0; i < (phba->num_cpus + eq_for_mcc); i++) {
+ eq = &phwi_context->be_eq[i].q;
+ mem = &eq->dma_mem;
+ phwi_context->be_eq[i].phba = phba;
+ eq_vaddress = pci_alloc_consistent(phba->pcidev,
+ num_eq_pages * PAGE_SIZE,
+ &paddr);
+ if (!eq_vaddress)
+ goto create_eq_error;
+
+ mem->va = eq_vaddress;
+ ret = be_fill_queue(eq, phba->params.num_eq_entries,
+ sizeof(struct be_eq_entry), eq_vaddress);
+ if (ret) {
+ shost_printk(KERN_ERR, phba->shost,
+ "be_fill_queue Failed for EQ \n");
+ goto create_eq_error;
+ }
- ret = beiscsi_cmd_eq_create(&phba->ctrl, eq,
- phwi_context->be_eq.cur_eqd);
- if (ret) {
- shost_printk(KERN_ERR, phba->shost, "beiscsi_cmd_eq_create"
- "Failedfor EQ \n");
- return ret;
+ mem->dma = paddr;
+ ret = beiscsi_cmd_eq_create(&phba->ctrl, eq,
+ phwi_context->cur_eqd);
+ if (ret) {
+ shost_printk(KERN_ERR, phba->shost,
+ "beiscsi_cmd_eq_create"
+ "Failedfor EQ \n");
+ goto create_eq_error;
+ }
+ SE_DEBUG(DBG_LVL_8, "eqid = %d\n", phwi_context->be_eq[i].q.id);
}
- SE_DEBUG(DBG_LVL_8, "eq id is %d\n", phwi_context->be_eq.q.id);
return 0;
+create_eq_error:
+ for (i = 0; i < (phba->num_cpus + 1); i++) {
+ eq = &phwi_context->be_eq[i].q;
+ mem = &eq->dma_mem;
+ if (mem->va)
+ pci_free_consistent(phba->pcidev, num_eq_pages
+ * PAGE_SIZE,
+ mem->va, mem->dma);
+ }
+ return ret;
}
-static int beiscsi_create_cq(struct beiscsi_hba *phba,
+static int beiscsi_create_cqs(struct beiscsi_hba *phba,
struct hwi_context_memory *phwi_context)
{
- unsigned int idx;
+ unsigned int i, num_cq_pages;
int ret;
struct be_queue_info *cq, *eq;
struct be_dma_mem *mem;
- struct be_mem_descriptor *mem_descr;
+ struct be_eq_obj *pbe_eq;
void *cq_vaddress;
+ dma_addr_t paddr;
- idx = 0;
- cq = &phwi_context->be_cq;
- eq = &phwi_context->be_eq.q;
- mem = &cq->dma_mem;
- mem_descr = phba->init_mem;
- mem_descr += HWI_MEM_CQ;
- cq_vaddress = mem_descr->mem_array[idx].virtual_address;
- ret = be_fill_queue(cq, phba->params.icds_per_ctrl / 2,
- sizeof(struct sol_cqe), cq_vaddress);
- if (ret) {
- shost_printk(KERN_ERR, phba->shost,
- "be_fill_queue Failed for ISCSI CQ \n");
- return ret;
- }
+ num_cq_pages = PAGES_REQUIRED(phba->params.num_cq_entries * \
+ sizeof(struct sol_cqe));
- mem->dma = mem_descr->mem_array[idx].bus_address.u.a64.address;
- ret = beiscsi_cmd_cq_create(&phba->ctrl, cq, eq, false, false, 0);
- if (ret) {
- shost_printk(KERN_ERR, phba->shost,
- "beiscsi_cmd_eq_create Failed for ISCSI CQ \n");
- return ret;
+ for (i = 0; i < phba->num_cpus; i++) {
+ cq = &phwi_context->be_cq[i];
+ eq = &phwi_context->be_eq[i].q;
+ pbe_eq = &phwi_context->be_eq[i];
+ pbe_eq->cq = cq;
+ pbe_eq->phba = phba;
+ mem = &cq->dma_mem;
+ cq_vaddress = pci_alloc_consistent(phba->pcidev,
+ num_cq_pages * PAGE_SIZE,
+ &paddr);
+ if (!cq_vaddress)
+ goto create_cq_error;
+ ret = be_fill_queue(cq, phba->params.icds_per_ctrl / 2,
+ sizeof(struct sol_cqe), cq_vaddress);
+ if (ret) {
+ shost_printk(KERN_ERR, phba->shost,
+ "be_fill_queue Failed for ISCSI CQ \n");
+ goto create_cq_error;
+ }
+
+ mem->dma = paddr;
+ ret = beiscsi_cmd_cq_create(&phba->ctrl, cq, eq, false,
+ false, 0);
+ if (ret) {
+ shost_printk(KERN_ERR, phba->shost,
+ "beiscsi_cmd_eq_create"
+ "Failed for ISCSI CQ \n");
+ goto create_cq_error;
+ }
+ SE_DEBUG(DBG_LVL_8, "iscsi cq_id is %d for eq_id %d\n",
+ cq->id, eq->id);
+ SE_DEBUG(DBG_LVL_8, "ISCSI CQ CREATED\n");
}
- SE_DEBUG(DBG_LVL_8, "iscsi cq id is %d\n", phwi_context->be_cq.id);
- SE_DEBUG(DBG_LVL_8, "ISCSI CQ CREATED\n");
return 0;
+
+create_cq_error:
+ for (i = 0; i < phba->num_cpus; i++) {
+ cq = &phwi_context->be_cq[i];
+ mem = &cq->dma_mem;
+ if (mem->va)
+ pci_free_consistent(phba->pcidev, num_cq_pages
+ * PAGE_SIZE,
+ mem->va, mem->dma);
+ }
+ return ret;
+
}
static int
@@ -2132,7 +2434,7 @@ beiscsi_create_def_hdr(struct beiscsi_hba *phba,
idx = 0;
dq = &phwi_context->be_def_hdrq;
- cq = &phwi_context->be_cq;
+ cq = &phwi_context->be_cq[0];
mem = &dq->dma_mem;
mem_descr = phba->init_mem;
mem_descr += HWI_MEM_ASYNC_HEADER_RING;
@@ -2176,7 +2478,7 @@ beiscsi_create_def_data(struct beiscsi_hba *phba,
idx = 0;
dataq = &phwi_context->be_def_dataq;
- cq = &phwi_context->be_cq;
+ cq = &phwi_context->be_cq[0];
mem = &dataq->dma_mem;
mem_descr = phba->init_mem;
mem_descr += HWI_MEM_ASYNC_DATA_RING;
@@ -2239,6 +2541,30 @@ beiscsi_post_pages(struct beiscsi_hba *phba)
return 0;
}
+static void be_queue_free(struct beiscsi_hba *phba, struct be_queue_info *q)
+{
+ struct be_dma_mem *mem = &q->dma_mem;
+ if (mem->va)
+ pci_free_consistent(phba->pcidev, mem->size,
+ mem->va, mem->dma);
+}
+
+static int be_queue_alloc(struct beiscsi_hba *phba, struct be_queue_info *q,
+ u16 len, u16 entry_size)
+{
+ struct be_dma_mem *mem = &q->dma_mem;
+
+ memset(q, 0, sizeof(*q));
+ q->len = len;
+ q->entry_size = entry_size;
+ mem->size = len * entry_size;
+ mem->va = pci_alloc_consistent(phba->pcidev, mem->size, &mem->dma);
+ if (!mem->va)
+ return -1;
+ memset(mem->va, 0, mem->size);
+ return 0;
+}
+
static int
beiscsi_create_wrb_rings(struct beiscsi_hba *phba,
struct hwi_context_memory *phwi_context,
@@ -2328,13 +2654,29 @@ static void free_wrb_handles(struct beiscsi_hba *phba)
}
}
+static void be_mcc_queues_destroy(struct beiscsi_hba *phba)
+{
+ struct be_queue_info *q;
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+
+ q = &phba->ctrl.mcc_obj.q;
+ if (q->created)
+ beiscsi_cmd_q_destroy(ctrl, q, QTYPE_MCCQ);
+ be_queue_free(phba, q);
+
+ q = &phba->ctrl.mcc_obj.cq;
+ if (q->created)
+ beiscsi_cmd_q_destroy(ctrl, q, QTYPE_CQ);
+ be_queue_free(phba, q);
+}
+
static void hwi_cleanup(struct beiscsi_hba *phba)
{
struct be_queue_info *q;
struct be_ctrl_info *ctrl = &phba->ctrl;
struct hwi_controller *phwi_ctrlr;
struct hwi_context_memory *phwi_context;
- int i;
+ int i, eq_num;
phwi_ctrlr = phba->phwi_ctrlr;
phwi_context = phwi_ctrlr->phwi_ctxt;
@@ -2343,7 +2685,6 @@ static void hwi_cleanup(struct beiscsi_hba *phba)
if (q->created)
beiscsi_cmd_q_destroy(ctrl, q, QTYPE_WRBQ);
}
-
free_wrb_handles(phba);
q = &phwi_context->be_def_hdrq;
@@ -2356,13 +2697,76 @@ static void hwi_cleanup(struct beiscsi_hba *phba)
beiscsi_cmd_q_destroy(ctrl, NULL, QTYPE_SGL);
- q = &phwi_context->be_cq;
- if (q->created)
- beiscsi_cmd_q_destroy(ctrl, q, QTYPE_CQ);
+ for (i = 0; i < (phba->num_cpus); i++) {
+ q = &phwi_context->be_cq[i];
+ if (q->created)
+ beiscsi_cmd_q_destroy(ctrl, q, QTYPE_CQ);
+ }
+ if (phba->msix_enabled)
+ eq_num = 1;
+ else
+ eq_num = 0;
+ for (i = 0; i < (phba->num_cpus + eq_num); i++) {
+ q = &phwi_context->be_eq[i].q;
+ if (q->created)
+ beiscsi_cmd_q_destroy(ctrl, q, QTYPE_EQ);
+ }
+ be_mcc_queues_destroy(phba);
+}
- q = &phwi_context->be_eq.q;
- if (q->created)
- beiscsi_cmd_q_destroy(ctrl, q, QTYPE_EQ);
+static int be_mcc_queues_create(struct beiscsi_hba *phba,
+ struct hwi_context_memory *phwi_context)
+{
+ struct be_queue_info *q, *cq;
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+
+ /* Alloc MCC compl queue */
+ cq = &phba->ctrl.mcc_obj.cq;
+ if (be_queue_alloc(phba, cq, MCC_CQ_LEN,
+ sizeof(struct be_mcc_compl)))
+ goto err;
+ /* Ask BE to create MCC compl queue; */
+ if (phba->msix_enabled) {
+ if (beiscsi_cmd_cq_create(ctrl, cq, &phwi_context->be_eq
+ [phba->num_cpus].q, false, true, 0))
+ goto mcc_cq_free;
+ } else {
+ if (beiscsi_cmd_cq_create(ctrl, cq, &phwi_context->be_eq[0].q,
+ false, true, 0))
+ goto mcc_cq_free;
+ }
+
+ /* Alloc MCC queue */
+ q = &phba->ctrl.mcc_obj.q;
+ if (be_queue_alloc(phba, q, MCC_Q_LEN, sizeof(struct be_mcc_wrb)))
+ goto mcc_cq_destroy;
+
+ /* Ask BE to create MCC queue */
+ if (beiscsi_cmd_mccq_create(phba, q, cq))
+ goto mcc_q_free;
+
+ return 0;
+
+mcc_q_free:
+ be_queue_free(phba, q);
+mcc_cq_destroy:
+ beiscsi_cmd_q_destroy(ctrl, cq, QTYPE_CQ);
+mcc_cq_free:
+ be_queue_free(phba, cq);
+err:
+ return -1;
+}
+
+static int find_num_cpus(void)
+{
+ int num_cpus = 0;
+
+ num_cpus = num_online_cpus();
+ if (num_cpus >= MAX_CPUS)
+ num_cpus = MAX_CPUS - 1;
+
+ SE_DEBUG(DBG_LVL_8, "num_cpus = %d \n", num_cpus);
+ return num_cpus;
}
static int hwi_init_port(struct beiscsi_hba *phba)
@@ -2376,26 +2780,33 @@ static int hwi_init_port(struct beiscsi_hba *phba)
def_pdu_ring_sz =
phba->params.asyncpdus_per_ctrl * sizeof(struct phys_addr);
phwi_ctrlr = phba->phwi_ctrlr;
-
phwi_context = phwi_ctrlr->phwi_ctxt;
- phwi_context->be_eq.max_eqd = 0;
- phwi_context->be_eq.min_eqd = 0;
- phwi_context->be_eq.cur_eqd = 64;
- phwi_context->be_eq.enable_aic = false;
+ phwi_context->max_eqd = 0;
+ phwi_context->min_eqd = 0;
+ phwi_context->cur_eqd = 64;
be_cmd_fw_initialize(&phba->ctrl);
- status = beiscsi_create_eq(phba, phwi_context);
+
+ status = beiscsi_create_eqs(phba, phwi_context);
if (status != 0) {
shost_printk(KERN_ERR, phba->shost, "EQ not created \n");
goto error;
}
- status = mgmt_check_supported_fw(ctrl);
+ status = be_mcc_queues_create(phba, phwi_context);
+ if (status != 0)
+ goto error;
+
+ status = mgmt_check_supported_fw(ctrl, phba);
if (status != 0) {
shost_printk(KERN_ERR, phba->shost,
"Unsupported fw version \n");
goto error;
}
+ if (phba->fw_config.iscsi_features == 0x1)
+ ring_mode = 1;
+ else
+ ring_mode = 0;
status = mgmt_get_fw_config(ctrl, phba);
if (status != 0) {
shost_printk(KERN_ERR, phba->shost,
@@ -2403,7 +2814,7 @@ static int hwi_init_port(struct beiscsi_hba *phba)
goto error;
}
- status = beiscsi_create_cq(phba, phwi_context);
+ status = beiscsi_create_cqs(phba, phwi_context);
if (status != 0) {
shost_printk(KERN_ERR, phba->shost, "CQ not created\n");
goto error;
@@ -2447,7 +2858,6 @@ error:
return -ENOMEM;
}
-
static int hwi_init_controller(struct beiscsi_hba *phba)
{
struct hwi_controller *phwi_ctrlr;
@@ -2530,6 +2940,18 @@ static int beiscsi_init_sgl_handle(struct beiscsi_hba *phba)
phba->io_sgl_hndl_avbl = 0;
phba->eh_sgl_hndl_avbl = 0;
+
+ if (ring_mode) {
+ phba->sgl_hndl_array = kzalloc(sizeof(struct sgl_handle *) *
+ phba->params.icds_per_ctrl,
+ GFP_KERNEL);
+ if (!phba->sgl_hndl_array) {
+ shost_printk(KERN_ERR, phba->shost,
+ "Mem Alloc Failed. Failing to load\n");
+ return -ENOMEM;
+ }
+ }
+
mem_descr_sglh = phba->init_mem;
mem_descr_sglh += HWI_MEM_SGLH;
if (1 == mem_descr_sglh->num_elements) {
@@ -2537,6 +2959,8 @@ static int beiscsi_init_sgl_handle(struct beiscsi_hba *phba)
phba->params.ios_per_ctrl,
GFP_KERNEL);
if (!phba->io_sgl_hndl_base) {
+ if (ring_mode)
+ kfree(phba->sgl_hndl_array);
shost_printk(KERN_ERR, phba->shost,
"Mem Alloc Failed. Failing to load\n");
return -ENOMEM;
@@ -2656,13 +3080,12 @@ static unsigned char hwi_enable_intr(struct beiscsi_hba *phba)
struct hwi_context_memory *phwi_context;
struct be_queue_info *eq;
u8 __iomem *addr;
- u32 reg;
+ u32 reg, i;
u32 enabled;
phwi_ctrlr = phba->phwi_ctrlr;
phwi_context = phwi_ctrlr->phwi_ctxt;
- eq = &phwi_context->be_eq.q;
addr = (u8 __iomem *) ((u8 __iomem *) ctrl->pcicfg +
PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET);
reg = ioread32(addr);
@@ -2673,9 +3096,11 @@ static unsigned char hwi_enable_intr(struct beiscsi_hba *phba)
reg |= MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK;
SE_DEBUG(DBG_LVL_8, "reg =x%08x addr=%p \n", reg, addr);
iowrite32(reg, addr);
- SE_DEBUG(DBG_LVL_8, "eq->id=%d \n", eq->id);
-
- hwi_ring_eq_db(phba, eq->id, 0, 0, 1, 1);
+ for (i = 0; i <= phba->num_cpus; i++) {
+ eq = &phwi_context->be_eq[i].q;
+ SE_DEBUG(DBG_LVL_8, "eq->id=%d \n", eq->id);
+ hwi_ring_eq_db(phba, eq->id, 0, 0, 1, 1);
+ }
} else
shost_printk(KERN_WARNING, phba->shost,
"In hwi_enable_intr, Not Enabled \n");
@@ -2720,6 +3145,8 @@ static int beiscsi_init_port(struct beiscsi_hba *phba)
if (hba_setup_cid_tbls(phba)) {
shost_printk(KERN_ERR, phba->shost,
"Failed in hba_setup_cid_tbls\n");
+ if (ring_mode)
+ kfree(phba->sgl_hndl_array);
kfree(phba->io_sgl_hndl_base);
kfree(phba->eh_sgl_hndl_base);
goto do_cleanup_ctrlr;
@@ -2738,17 +3165,25 @@ static void hwi_purge_eq(struct beiscsi_hba *phba)
struct hwi_context_memory *phwi_context;
struct be_queue_info *eq;
struct be_eq_entry *eqe = NULL;
+ int i, eq_msix;
phwi_ctrlr = phba->phwi_ctrlr;
phwi_context = phwi_ctrlr->phwi_ctxt;
- eq = &phwi_context->be_eq.q;
- eqe = queue_tail_node(eq);
+ if (phba->msix_enabled)
+ eq_msix = 1;
+ else
+ eq_msix = 0;
- while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32]
- & EQE_VALID_MASK) {
- AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
- queue_tail_inc(eq);
+ for (i = 0; i < (phba->num_cpus + eq_msix); i++) {
+ eq = &phwi_context->be_eq[i].q;
eqe = queue_tail_node(eq);
+
+ while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32]
+ & EQE_VALID_MASK) {
+ AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
+ queue_tail_inc(eq);
+ eqe = queue_tail_node(eq);
+ }
}
}
@@ -2762,6 +3197,8 @@ static void beiscsi_clean_port(struct beiscsi_hba *phba)
"mgmt_epfw_cleanup FAILED \n");
hwi_cleanup(phba);
hwi_purge_eq(phba);
+ if (ring_mode)
+ kfree(phba->sgl_hndl_array);
kfree(phba->io_sgl_hndl_base);
kfree(phba->eh_sgl_hndl_base);
kfree(phba->cid_array);
@@ -2846,8 +3283,9 @@ beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn,
be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_target_context_update_wrb));
doorbell |= beiscsi_conn->beiscsi_conn_cid & DB_WRB_POST_CID_MASK;
- doorbell |= (pwrb_handle->wrb_index & DB_DEF_PDU_WRB_INDEX_MASK) <<
- DB_DEF_PDU_WRB_INDEX_SHIFT;
+ if (!ring_mode)
+ doorbell |= (pwrb_handle->wrb_index & DB_DEF_PDU_WRB_INDEX_MASK)
+ << DB_DEF_PDU_WRB_INDEX_SHIFT;
doorbell |= 1 << DB_DEF_PDU_NUM_POSTED_SHIFT;
iowrite32(doorbell, phba->db_va + DB_TXULP0_OFFSET);
@@ -2856,7 +3294,7 @@ beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn,
static void beiscsi_parse_pdu(struct iscsi_conn *conn, itt_t itt,
int *index, int *age)
{
- *index = be32_to_cpu(itt) >> 16;
+ *index = (int)itt;
if (age)
*age = conn->session->age;
}
@@ -2885,15 +3323,13 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
io_task->cmd_bhs = pci_pool_alloc(beiscsi_sess->bhs_pool,
GFP_KERNEL, &paddr);
-
if (!io_task->cmd_bhs)
return -ENOMEM;
-
io_task->bhs_pa.u.a64.address = paddr;
+ io_task->libiscsi_itt = (itt_t)task->itt;
io_task->pwrb_handle = alloc_wrb_handle(phba,
beiscsi_conn->beiscsi_conn_cid,
task->itt);
- io_task->pwrb_handle->pio_handle = task;
io_task->conn = beiscsi_conn;
task->hdr = (struct iscsi_hdr *)&io_task->cmd_bhs->iscsi_hdr;
@@ -2905,7 +3341,6 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
spin_unlock(&phba->io_sgl_lock);
if (!io_task->psgl_handle)
goto free_hndls;
-
} else {
io_task->scsi_cmnd = NULL;
if ((task->hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGIN) {
@@ -2932,8 +3367,18 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
goto free_hndls;
}
}
- itt = (itt_t) cpu_to_be32(((unsigned int)task->itt << 16) |
- (unsigned int)(io_task->psgl_handle->sgl_index));
+ itt = (itt_t) cpu_to_be32(((unsigned int)io_task->pwrb_handle->
+ wrb_index << 16) | (unsigned int)
+ (io_task->psgl_handle->sgl_index));
+ if (ring_mode) {
+ phba->sgl_hndl_array[io_task->psgl_handle->sgl_index -
+ phba->fw_config.iscsi_cid_start] =
+ io_task->psgl_handle;
+ io_task->psgl_handle->task = task;
+ io_task->psgl_handle->cid = beiscsi_conn->beiscsi_conn_cid;
+ } else
+ io_task->pwrb_handle->pio_handle = task;
+
io_task->cmd_bhs->iscsi_hdr.itt = itt;
return 0;
@@ -3006,7 +3451,6 @@ static int beiscsi_iotask(struct iscsi_task *task, struct scatterlist *sg,
io_task->bhs_len = sizeof(struct be_cmd_bhs);
if (writedir) {
- SE_DEBUG(DBG_LVL_4, " WRITE Command \t");
memset(&io_task->cmd_bhs->iscsi_data_pdu, 0, 48);
AMAP_SET_BITS(struct amap_pdu_data_out, itt,
&io_task->cmd_bhs->iscsi_data_pdu,
@@ -3016,11 +3460,18 @@ static int beiscsi_iotask(struct iscsi_task *task, struct scatterlist *sg,
ISCSI_OPCODE_SCSI_DATA_OUT);
AMAP_SET_BITS(struct amap_pdu_data_out, final_bit,
&io_task->cmd_bhs->iscsi_data_pdu, 1);
- AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, INI_WR_CMD);
+ if (ring_mode)
+ io_task->psgl_handle->type = INI_WR_CMD;
+ else
+ AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb,
+ INI_WR_CMD);
AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 1);
} else {
- SE_DEBUG(DBG_LVL_4, "READ Command \t");
- AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, INI_RD_CMD);
+ if (ring_mode)
+ io_task->psgl_handle->type = INI_RD_CMD;
+ else
+ AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb,
+ INI_RD_CMD);
AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 0);
}
memcpy(&io_task->cmd_bhs->iscsi_data_pdu.
@@ -3045,7 +3496,8 @@ static int beiscsi_iotask(struct iscsi_task *task, struct scatterlist *sg,
be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_wrb));
doorbell |= beiscsi_conn->beiscsi_conn_cid & DB_WRB_POST_CID_MASK;
- doorbell |= (io_task->pwrb_handle->wrb_index &
+ if (!ring_mode)
+ doorbell |= (io_task->pwrb_handle->wrb_index &
DB_DEF_PDU_WRB_INDEX_MASK) << DB_DEF_PDU_WRB_INDEX_SHIFT;
doorbell |= 1 << DB_DEF_PDU_NUM_POSTED_SHIFT;
@@ -3059,10 +3511,16 @@ static int beiscsi_mtask(struct iscsi_task *task)
struct iscsi_conn *conn = task->conn;
struct beiscsi_conn *beiscsi_conn = conn->dd_data;
struct beiscsi_hba *phba = beiscsi_conn->phba;
+ struct iscsi_session *session;
struct iscsi_wrb *pwrb = NULL;
+ struct hwi_controller *phwi_ctrlr;
+ struct hwi_wrb_context *pwrb_context;
+ struct wrb_handle *pwrb_handle;
unsigned int doorbell = 0;
+ unsigned int i, cid;
struct iscsi_task *aborted_task;
+ cid = beiscsi_conn->beiscsi_conn_cid;
pwrb = io_task->pwrb_handle->pwrb;
AMAP_SET_BITS(struct amap_iscsi_wrb, cmdsn_itt, pwrb,
be32_to_cpu(task->cmdsn));
@@ -3073,38 +3531,63 @@ static int beiscsi_mtask(struct iscsi_task *task)
switch (task->hdr->opcode & ISCSI_OPCODE_MASK) {
case ISCSI_OP_LOGIN:
- AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, TGT_DM_CMD);
+ if (ring_mode)
+ io_task->psgl_handle->type = TGT_DM_CMD;
+ else
+ AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb,
+ TGT_DM_CMD);
AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0);
AMAP_SET_BITS(struct amap_iscsi_wrb, cmdsn_itt, pwrb, 1);
hwi_write_buffer(pwrb, task);
break;
case ISCSI_OP_NOOP_OUT:
- AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, INI_RD_CMD);
+ if (ring_mode)
+ io_task->psgl_handle->type = INI_RD_CMD;
+ else
+ AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb,
+ INI_RD_CMD);
hwi_write_buffer(pwrb, task);
break;
case ISCSI_OP_TEXT:
- AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, INI_WR_CMD);
+ if (ring_mode)
+ io_task->psgl_handle->type = INI_WR_CMD;
+ else
+ AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb,
+ INI_WR_CMD);
AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 1);
hwi_write_buffer(pwrb, task);
break;
case ISCSI_OP_SCSI_TMFUNC:
- aborted_task = iscsi_itt_to_task(conn,
- ((struct iscsi_tm *)task->hdr)->rtt);
+ session = conn->session;
+ i = ((struct iscsi_tm *)task->hdr)->rtt;
+ phwi_ctrlr = phba->phwi_ctrlr;
+ pwrb_context = &phwi_ctrlr->wrb_context[cid];
+ pwrb_handle = pwrb_context->pwrb_handle_basestd[be32_to_cpu(i)
+ >> 16];
+ aborted_task = pwrb_handle->pio_handle;
if (!aborted_task)
return 0;
+
aborted_io_task = aborted_task->dd_data;
if (!aborted_io_task->scsi_cmnd)
return 0;
mgmt_invalidate_icds(phba,
aborted_io_task->psgl_handle->sgl_index,
- beiscsi_conn->beiscsi_conn_cid);
- AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, INI_TMF_CMD);
+ cid);
+ if (ring_mode)
+ io_task->psgl_handle->type = INI_TMF_CMD;
+ else
+ AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb,
+ INI_TMF_CMD);
AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0);
hwi_write_buffer(pwrb, task);
break;
case ISCSI_OP_LOGOUT:
AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0);
+ if (ring_mode)
+ io_task->psgl_handle->type = HWH_TYPE_LOGOUT;
+ else
AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb,
HWH_TYPE_LOGOUT);
hwi_write_buffer(pwrb, task);
@@ -3122,8 +3605,9 @@ static int beiscsi_mtask(struct iscsi_task *task)
io_task->pwrb_handle->nxt_wrb_index);
be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_wrb));
- doorbell |= beiscsi_conn->beiscsi_conn_cid & DB_WRB_POST_CID_MASK;
- doorbell |= (io_task->pwrb_handle->wrb_index &
+ doorbell |= cid & DB_WRB_POST_CID_MASK;
+ if (!ring_mode)
+ doorbell |= (io_task->pwrb_handle->wrb_index &
DB_DEF_PDU_WRB_INDEX_MASK) << DB_DEF_PDU_WRB_INDEX_SHIFT;
doorbell |= 1 << DB_DEF_PDU_NUM_POSTED_SHIFT;
iowrite32(doorbell, phba->db_va + DB_TXULP0_OFFSET);
@@ -3165,9 +3649,14 @@ static int beiscsi_task_xmit(struct iscsi_task *task)
return beiscsi_iotask(task, sg, num_sg, xferlen, writedir);
}
+
static void beiscsi_remove(struct pci_dev *pcidev)
{
struct beiscsi_hba *phba = NULL;
+ struct hwi_controller *phwi_ctrlr;
+ struct hwi_context_memory *phwi_context;
+ struct be_eq_obj *pbe_eq;
+ unsigned int i, msix_vec;
phba = (struct beiscsi_hba *)pci_get_drvdata(pcidev);
if (!phba) {
@@ -3175,12 +3664,24 @@ static void beiscsi_remove(struct pci_dev *pcidev)
return;
}
+ phwi_ctrlr = phba->phwi_ctrlr;
+ phwi_context = phwi_ctrlr->phwi_ctxt;
hwi_disable_intr(phba);
- if (phba->pcidev->irq)
- free_irq(phba->pcidev->irq, phba);
+ if (phba->msix_enabled) {
+ for (i = 0; i <= phba->num_cpus; i++) {
+ msix_vec = phba->msix_entries[i].vector;
+ free_irq(msix_vec, &phwi_context->be_eq[i]);
+ }
+ } else
+ if (phba->pcidev->irq)
+ free_irq(phba->pcidev->irq, phba);
+ pci_disable_msix(phba->pcidev);
destroy_workqueue(phba->wq);
if (blk_iopoll_enabled)
- blk_iopoll_disable(&phba->iopoll);
+ for (i = 0; i < phba->num_cpus; i++) {
+ pbe_eq = &phwi_context->be_eq[i];
+ blk_iopoll_disable(&pbe_eq->iopoll);
+ }
beiscsi_clean_port(phba);
beiscsi_free_mem(phba);
@@ -3194,11 +3695,29 @@ static void beiscsi_remove(struct pci_dev *pcidev)
iscsi_host_free(phba->shost);
}
+static void beiscsi_msix_enable(struct beiscsi_hba *phba)
+{
+ int i, status;
+
+ for (i = 0; i <= phba->num_cpus; i++)
+ phba->msix_entries[i].entry = i;
+
+ status = pci_enable_msix(phba->pcidev, phba->msix_entries,
+ (phba->num_cpus + 1));
+ if (!status)
+ phba->msix_enabled = true;
+
+ return;
+}
+
static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev,
const struct pci_device_id *id)
{
struct beiscsi_hba *phba = NULL;
- int ret;
+ struct hwi_controller *phwi_ctrlr;
+ struct hwi_context_memory *phwi_context;
+ struct be_eq_obj *pbe_eq;
+ int ret, msix_vec, num_cpus, i;
ret = beiscsi_enable_pci(pcidev);
if (ret < 0) {
@@ -3213,8 +3732,18 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev,
" Failed in beiscsi_hba_alloc \n");
goto disable_pci;
}
+ SE_DEBUG(DBG_LVL_8, " phba = %p \n", phba);
pci_set_drvdata(pcidev, phba);
+ if (enable_msix)
+ num_cpus = find_num_cpus();
+ else
+ num_cpus = 1;
+ phba->num_cpus = num_cpus;
+ SE_DEBUG(DBG_LVL_8, "num_cpus = %d \n", phba->num_cpus);
+
+ if (enable_msix)
+ beiscsi_msix_enable(phba);
ret = be_ctrl_init(phba, pcidev);
if (ret) {
shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-"
@@ -3235,7 +3764,7 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev,
snprintf(phba->wq_name, sizeof(phba->wq_name), "beiscsi_q_irq%u",
phba->shost->host_no);
- phba->wq = create_singlethread_workqueue(phba->wq_name);
+ phba->wq = create_workqueue(phba->wq_name);
if (!phba->wq) {
shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-"
"Failed to allocate work queue\n");
@@ -3244,11 +3773,16 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev,
INIT_WORK(&phba->work_cqs, beiscsi_process_all_cqs);
+ phwi_ctrlr = phba->phwi_ctrlr;
+ phwi_context = phwi_ctrlr->phwi_ctxt;
if (blk_iopoll_enabled) {
- blk_iopoll_init(&phba->iopoll, be_iopoll_budget, be_iopoll);
- blk_iopoll_enable(&phba->iopoll);
+ for (i = 0; i < phba->num_cpus; i++) {
+ pbe_eq = &phwi_context->be_eq[i];
+ blk_iopoll_init(&pbe_eq->iopoll, be_iopoll_budget,
+ be_iopoll);
+ blk_iopoll_enable(&pbe_eq->iopoll);
+ }
}
-
ret = beiscsi_init_irqs(phba);
if (ret < 0) {
shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-"
@@ -3261,17 +3795,26 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev,
"Failed to hwi_enable_intr\n");
goto free_ctrlr;
}
-
SE_DEBUG(DBG_LVL_8, "\n\n\n SUCCESS - DRIVER LOADED \n\n\n");
return 0;
free_ctrlr:
- if (phba->pcidev->irq)
- free_irq(phba->pcidev->irq, phba);
+ if (phba->msix_enabled) {
+ for (i = 0; i <= phba->num_cpus; i++) {
+ msix_vec = phba->msix_entries[i].vector;
+ free_irq(msix_vec, &phwi_context->be_eq[i]);
+ }
+ } else
+ if (phba->pcidev->irq)
+ free_irq(phba->pcidev->irq, phba);
+ pci_disable_msix(phba->pcidev);
free_blkenbld:
destroy_workqueue(phba->wq);
if (blk_iopoll_enabled)
- blk_iopoll_disable(&phba->iopoll);
+ for (i = 0; i < phba->num_cpus; i++) {
+ pbe_eq = &phwi_context->be_eq[i];
+ blk_iopoll_disable(&pbe_eq->iopoll);
+ }
free_twq:
beiscsi_clean_port(phba);
beiscsi_free_mem(phba);
@@ -3316,7 +3859,7 @@ struct iscsi_transport beiscsi_iscsi_transport = {
ISCSI_USERNAME | ISCSI_PASSWORD |
ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN |
ISCSI_FAST_ABORT | ISCSI_ABORT_TMO |
- ISCSI_LU_RESET_TMO |
+ ISCSI_LU_RESET_TMO | ISCSI_TGT_RESET_TMO |
ISCSI_PING_TMO | ISCSI_RECV_TMO |
ISCSI_IFACE_NAME | ISCSI_INITIATOR_NAME,
.host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS |
@@ -3351,6 +3894,7 @@ static struct pci_driver beiscsi_pci_driver = {
.id_table = beiscsi_pci_id_table
};
+
static int __init beiscsi_module_init(void)
{
int ret;
@@ -3373,6 +3917,7 @@ static int __init beiscsi_module_init(void)
"beiscsi pci driver.\n");
goto unregister_iscsi_transport;
}
+ ring_mode = 0;
return 0;
unregister_iscsi_transport:
diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h
index 53c9b70..25e6b20 100644
--- a/drivers/scsi/be2iscsi/be_main.h
+++ b/drivers/scsi/be2iscsi/be_main.h
@@ -21,11 +21,9 @@
#ifndef _BEISCSI_MAIN_
#define _BEISCSI_MAIN_
-
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/in.h>
-#include <linux/blk-iopoll.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
@@ -35,12 +33,8 @@
#include <scsi/scsi_transport_iscsi.h>
#include "be.h"
-
-
-
#define DRV_NAME "be2iscsi"
#define BUILD_STR "2.0.527.0"
-
#define BE_NAME "ServerEngines BladeEngine2" \
"Linux iSCSI Driver version" BUILD_STR
#define DRV_DESC BE_NAME " " "Driver"
@@ -49,6 +43,8 @@
#define BE_DEVICE_ID1 0x212
#define OC_DEVICE_ID1 0x702
#define OC_DEVICE_ID2 0x703
+#define OC_DEVICE_ID3 0x712
+#define OC_DEVICE_ID4 0x222
#define BE2_MAX_SESSIONS 64
#define BE2_CMDS_PER_CXN 128
@@ -63,6 +59,7 @@
#define BE2_IO_DEPTH \
(BE2_MAX_ICDS / 2 - (BE2_LOGOUTS + BE2_TMFS + BE2_NOPOUT_REQ))
+#define MAX_CPUS 31
#define BEISCSI_SGLIST_ELEMENTS BE2_SGE
#define BEISCSI_MAX_CMNDS 1024 /* Max IO's per Ctrlr sht->can_queue */
@@ -79,7 +76,7 @@
#define BE_SENSE_INFO_SIZE 258
#define BE_ISCSI_PDU_HEADER_SIZE 64
#define BE_MIN_MEM_SIZE 16384
-
+#define MAX_CMD_SZ 65536
#define IIOC_SCSI_DATA 0x05 /* Write Operation */
#define DBG_LVL 0x00000001
@@ -100,6 +97,8 @@ do { \
} \
} while (0);
+#define BE_ADAPTER_UP 0x00000000
+#define BE_ADAPTER_LINK_DOWN 0x00000001
/**
* hardware needs the async PDU buffers to be posted in multiples of 8
* So have atleast 8 of them by default
@@ -160,21 +159,19 @@ do { \
enum be_mem_enum {
HWI_MEM_ADDN_CONTEXT,
- HWI_MEM_CQ,
- HWI_MEM_EQ,
HWI_MEM_WRB,
HWI_MEM_WRBH,
- HWI_MEM_SGLH, /* 5 */
+ HWI_MEM_SGLH,
HWI_MEM_SGE,
- HWI_MEM_ASYNC_HEADER_BUF,
+ HWI_MEM_ASYNC_HEADER_BUF, /* 5 */
HWI_MEM_ASYNC_DATA_BUF,
HWI_MEM_ASYNC_HEADER_RING,
- HWI_MEM_ASYNC_DATA_RING, /* 10 */
+ HWI_MEM_ASYNC_DATA_RING,
HWI_MEM_ASYNC_HEADER_HANDLE,
- HWI_MEM_ASYNC_DATA_HANDLE,
+ HWI_MEM_ASYNC_DATA_HANDLE, /* 10 */
HWI_MEM_ASYNC_PDU_CONTEXT,
ISCSI_MEM_GLOBAL_HEADER,
- SE_MEM_MAX /* 15 */
+ SE_MEM_MAX
};
struct be_bus_address32 {
@@ -212,6 +209,9 @@ struct be_mem_descriptor {
struct sgl_handle {
unsigned int sgl_index;
+ unsigned int type;
+ unsigned int cid;
+ struct iscsi_task *task;
struct iscsi_sge *pfrag;
};
@@ -274,13 +274,17 @@ struct beiscsi_hba {
struct pci_dev *pcidev;
unsigned int state;
unsigned short asic_revision;
- struct blk_iopoll iopoll;
+ unsigned int num_cpus;
+ unsigned int nxt_cqid;
+ struct msix_entry msix_entries[MAX_CPUS + 1];
+ bool msix_enabled;
struct be_mem_descriptor *init_mem;
unsigned short io_sgl_alloc_index;
unsigned short io_sgl_free_index;
unsigned short io_sgl_hndl_avbl;
struct sgl_handle **io_sgl_hndl_base;
+ struct sgl_handle **sgl_hndl_array;
unsigned short eh_sgl_alloc_index;
unsigned short eh_sgl_free_index;
@@ -315,6 +319,7 @@ struct beiscsi_hba {
unsigned short cid_alloc;
unsigned short cid_free;
unsigned short avlbl_cids;
+ unsigned short iscsi_features;
spinlock_t cid_lock;
} fw_config;
@@ -343,6 +348,7 @@ struct beiscsi_conn {
unsigned short login_in_progress;
struct sgl_handle *plogin_sgl_handle;
struct beiscsi_session *beiscsi_sess;
+ struct iscsi_task *task;
};
/* This structure is used by the chip */
@@ -390,7 +396,7 @@ struct beiscsi_io_task {
unsigned int flags;
unsigned short cid;
unsigned short header_len;
-
+ itt_t libiscsi_itt;
struct be_cmd_bhs *cmd_bhs;
struct be_bus_address bhs_pa;
unsigned short bhs_len;
@@ -599,7 +605,6 @@ struct amap_cq_db {
void beiscsi_process_eq(struct beiscsi_hba *phba);
-
struct iscsi_wrb {
u32 dw[16];
} __packed;
@@ -820,10 +825,12 @@ struct wrb_handle {
};
struct hwi_context_memory {
- struct be_eq_obj be_eq;
- struct be_queue_info be_cq;
- struct be_queue_info be_mcc_cq;
- struct be_queue_info be_mcc;
+ /* Adaptive interrupt coalescing (AIC) info */
+ u16 min_eqd; /* in usecs */
+ u16 max_eqd; /* in usecs */
+ u16 cur_eqd; /* in usecs */
+ struct be_eq_obj be_eq[MAX_CPUS];
+ struct be_queue_info be_cq[MAX_CPUS];
struct be_queue_info be_def_hdrq;
struct be_queue_info be_def_dataq;
diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c
index 12e644f..79c2bd5 100644
--- a/drivers/scsi/be2iscsi/be_mgmt.c
+++ b/drivers/scsi/be2iscsi/be_mgmt.c
@@ -35,7 +35,6 @@ unsigned char mgmt_get_fw_config(struct be_ctrl_info *ctrl,
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
OPCODE_COMMON_QUERY_FIRMWARE_CONFIG, sizeof(*req));
-
status = be_mbox_notify(ctrl);
if (!status) {
struct be_fw_cfg *pfw_cfg;
@@ -58,7 +57,8 @@ unsigned char mgmt_get_fw_config(struct be_ctrl_info *ctrl,
return status;
}
-unsigned char mgmt_check_supported_fw(struct be_ctrl_info *ctrl)
+unsigned char mgmt_check_supported_fw(struct be_ctrl_info *ctrl,
+ struct beiscsi_hba *phba)
{
struct be_dma_mem nonemb_cmd;
struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
@@ -85,7 +85,6 @@ unsigned char mgmt_check_supported_fw(struct be_ctrl_info *ctrl)
sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd.dma));
sge->pa_lo = cpu_to_le32(nonemb_cmd.dma & 0xFFFFFFFF);
sge->len = cpu_to_le32(nonemb_cmd.size);
-
status = be_mbox_notify(ctrl);
if (!status) {
struct be_mgmt_controller_attributes_resp *resp = nonemb_cmd.va;
@@ -95,21 +94,25 @@ unsigned char mgmt_check_supported_fw(struct be_ctrl_info *ctrl)
resp->params.hba_attribs.firmware_version_string);
SE_DEBUG(DBG_LVL_8,
"Developer Build, not performing version check...\n");
-
+ phba->fw_config.iscsi_features =
+ resp->params.hba_attribs.iscsi_features;
+ SE_DEBUG(DBG_LVL_8, " phba->fw_config.iscsi_features = %d\n",
+ phba->fw_config.iscsi_features);
} else
SE_DEBUG(DBG_LVL_1, " Failed in mgmt_check_supported_fw\n");
+ spin_unlock(&ctrl->mbox_lock);
if (nonemb_cmd.va)
pci_free_consistent(ctrl->pdev, nonemb_cmd.size,
nonemb_cmd.va, nonemb_cmd.dma);
- spin_unlock(&ctrl->mbox_lock);
return status;
}
+
unsigned char mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute)
{
struct be_ctrl_info *ctrl = &phba->ctrl;
- struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_mcc_wrb *wrb = wrb_from_mccq(phba);
struct iscsi_cleanup_req *req = embedded_payload(wrb);
int status = 0;
@@ -124,7 +127,7 @@ unsigned char mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute)
req->hdr_ring_id = 0;
req->data_ring_id = 0;
- status = be_mbox_notify(ctrl);
+ status = be_mcc_notify_wait(phba);
if (status)
shost_printk(KERN_WARNING, phba->shost,
" mgmt_epfw_cleanup , FAILED\n");
@@ -137,7 +140,7 @@ unsigned char mgmt_invalidate_icds(struct beiscsi_hba *phba,
{
struct be_dma_mem nonemb_cmd;
struct be_ctrl_info *ctrl = &phba->ctrl;
- struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_mcc_wrb *wrb = wrb_from_mccq(phba);
struct be_sge *sge = nonembedded_sgl(wrb);
struct invalidate_commands_params_in *req;
int status = 0;
@@ -169,7 +172,7 @@ unsigned char mgmt_invalidate_icds(struct beiscsi_hba *phba,
sge->pa_lo = cpu_to_le32(nonemb_cmd.dma & 0xFFFFFFFF);
sge->len = cpu_to_le32(nonemb_cmd.size);
- status = be_mbox_notify(ctrl);
+ status = be_mcc_notify_wait(phba);
if (status)
SE_DEBUG(DBG_LVL_1, "ICDS Invalidation Failed\n");
spin_unlock(&ctrl->mbox_lock);
@@ -186,7 +189,7 @@ unsigned char mgmt_invalidate_connection(struct beiscsi_hba *phba,
unsigned short savecfg_flag)
{
struct be_ctrl_info *ctrl = &phba->ctrl;
- struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_mcc_wrb *wrb = wrb_from_mccq(phba);
struct iscsi_invalidate_connection_params_in *req =
embedded_payload(wrb);
int status = 0;
@@ -205,7 +208,7 @@ unsigned char mgmt_invalidate_connection(struct beiscsi_hba *phba,
else
req->cleanup_type = CMD_ISCSI_CONNECTION_INVALIDATE;
req->save_cfg = savecfg_flag;
- status = be_mbox_notify(ctrl);
+ status = be_mcc_notify_wait(phba);
if (status)
SE_DEBUG(DBG_LVL_1, "Invalidation Failed\n");
@@ -217,7 +220,7 @@ unsigned char mgmt_upload_connection(struct beiscsi_hba *phba,
unsigned short cid, unsigned int upload_flag)
{
struct be_ctrl_info *ctrl = &phba->ctrl;
- struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_mcc_wrb *wrb = wrb_from_mccq(phba);
struct tcp_upload_params_in *req = embedded_payload(wrb);
int status = 0;
@@ -229,7 +232,7 @@ unsigned char mgmt_upload_connection(struct beiscsi_hba *phba,
OPCODE_COMMON_TCP_UPLOAD, sizeof(*req));
req->id = (unsigned short)cid;
req->upload_type = (unsigned char)upload_flag;
- status = be_mbox_notify(ctrl);
+ status = be_mcc_notify_wait(phba);
if (status)
SE_DEBUG(DBG_LVL_1, "mgmt_upload_connection Failed\n");
spin_unlock(&ctrl->mbox_lock);
@@ -245,13 +248,14 @@ int mgmt_open_connection(struct beiscsi_hba *phba,
struct sockaddr_in *daddr_in = (struct sockaddr_in *)dst_addr;
struct sockaddr_in6 *daddr_in6 = (struct sockaddr_in6 *)dst_addr;
struct be_ctrl_info *ctrl = &phba->ctrl;
- struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_mcc_wrb *wrb = wrb_from_mccq(phba);
struct tcp_connect_and_offload_in *req = embedded_payload(wrb);
unsigned short def_hdr_id;
unsigned short def_data_id;
struct phys_addr template_address = { 0, 0 };
struct phys_addr *ptemplate_address;
int status = 0;
+ unsigned int i;
unsigned short cid = beiscsi_ep->ep_cid;
phwi_ctrlr = phba->phwi_ctrlr;
@@ -296,14 +300,18 @@ int mgmt_open_connection(struct beiscsi_hba *phba,
}
req->cid = cid;
- req->cq_id = phwi_context->be_cq.id;
+ i = phba->nxt_cqid++;
+ if (phba->nxt_cqid == phba->num_cpus)
+ phba->nxt_cqid = 0;
+ req->cq_id = phwi_context->be_cq[i].id;
+ SE_DEBUG(DBG_LVL_8, "i=%d cq_id=%d \n", i, req->cq_id);
req->defq_id = def_hdr_id;
req->hdr_ring_id = def_hdr_id;
req->data_ring_id = def_data_id;
req->do_offload = 1;
req->dataout_template_pa.lo = ptemplate_address->lo;
req->dataout_template_pa.hi = ptemplate_address->hi;
- status = be_mbox_notify(ctrl);
+ status = be_mcc_notify_wait(phba);
if (!status) {
struct iscsi_endpoint *ep;
struct tcp_connect_and_offload_out *ptcpcnct_out =
@@ -311,7 +319,7 @@ int mgmt_open_connection(struct beiscsi_hba *phba,
ep = phba->ep_array[ptcpcnct_out->cid];
beiscsi_ep = ep->dd_data;
- beiscsi_ep->fw_handle = 0;
+ beiscsi_ep->fw_handle = ptcpcnct_out->connection_handle;
beiscsi_ep->cid_vld = 1;
SE_DEBUG(DBG_LVL_8, "mgmt_open_connection Success\n");
} else
@@ -319,3 +327,30 @@ int mgmt_open_connection(struct beiscsi_hba *phba,
spin_unlock(&ctrl->mbox_lock);
return status;
}
+
+int be_cmd_get_mac_addr(struct beiscsi_hba *phba, u8 *mac_addr)
+{
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+ struct be_mcc_wrb *wrb = wrb_from_mccq(phba);
+ struct be_cmd_req_get_mac_addr *req = embedded_payload(wrb);
+ int status;
+
+ SE_DEBUG(DBG_LVL_8, "In be_cmd_get_mac_addr\n");
+ spin_lock(&ctrl->mbox_lock);
+ memset(wrb, 0, sizeof(*wrb));
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
+ OPCODE_COMMON_ISCSI_NTWK_GET_NIC_CONFIG,
+ sizeof(*req));
+
+ status = be_mcc_notify_wait(phba);
+ if (!status) {
+ struct be_cmd_resp_get_mac_addr *resp = embedded_payload(wrb);
+
+ memcpy(mac_addr, resp->mac_address, ETH_ALEN);
+ }
+
+ spin_unlock(&ctrl->mbox_lock);
+ return status;
+}
+
diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h
index 00e816e..24eaff9 100644
--- a/drivers/scsi/be2iscsi/be_mgmt.h
+++ b/drivers/scsi/be2iscsi/be_mgmt.h
@@ -175,7 +175,9 @@ struct mgmt_hba_attributes {
u8 phy_port;
u32 firmware_post_status;
u32 hba_mtu[8];
- u32 future_u32[4];
+ u8 iscsi_features;
+ u8 future_u8[3];
+ u32 future_u32[3];
} __packed;
struct mgmt_controller_attributes {
@@ -246,4 +248,8 @@ unsigned char mgmt_invalidate_connection(struct beiscsi_hba *phba,
unsigned short cid,
unsigned short issue_reset,
unsigned short savecfg_flag);
+
+unsigned char mgmt_fw_cmd(struct be_ctrl_info *ctrl,
+ struct beiscsi_hba *phba,
+ char *buf, unsigned int len);
#endif
diff --git a/drivers/scsi/bfa/bfa_cb_ioim_macros.h b/drivers/scsi/bfa/bfa_cb_ioim_macros.h
index 0050c83..961fe43 100644
--- a/drivers/scsi/bfa/bfa_cb_ioim_macros.h
+++ b/drivers/scsi/bfa/bfa_cb_ioim_macros.h
@@ -51,7 +51,7 @@ bfad_int_to_lun(u32 luno)
lun.bfa_lun = 0;
lun.scsi_lun[0] = bfa_os_htons(luno);
- return (lun.bfa_lun);
+ return lun.bfa_lun;
}
/**
@@ -68,7 +68,7 @@ bfa_cb_ioim_get_cdb(struct bfad_ioim_s *dio)
{
struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
- return ((u8 *) cmnd->cmnd);
+ return (u8 *) cmnd->cmnd;
}
/**
@@ -97,7 +97,7 @@ bfa_cb_ioim_get_size(struct bfad_ioim_s *dio)
{
struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
- return (scsi_bufflen(cmnd));
+ return scsi_bufflen(cmnd);
}
/**
@@ -129,7 +129,7 @@ bfa_cb_ioim_get_sgaddr(struct bfad_ioim_s *dio, int sgeid)
sge = (struct scatterlist *)scsi_sglist(cmnd) + sgeid;
addr = (u64) sg_dma_address(sge);
- return (*(union bfi_addr_u *) &addr);
+ return *((union bfi_addr_u *) &addr);
}
static inline u32
@@ -197,7 +197,7 @@ bfa_cb_ioim_get_cdblen(struct bfad_ioim_s *dio)
{
struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
- return (cmnd->cmd_len);
+ return cmnd->cmd_len;
}
diff --git a/drivers/scsi/bfa/bfa_cee.c b/drivers/scsi/bfa/bfa_cee.c
index 7a959c3..2b91779 100644
--- a/drivers/scsi/bfa/bfa_cee.c
+++ b/drivers/scsi/bfa/bfa_cee.c
@@ -228,7 +228,7 @@ bfa_cee_reset_stats_isr(struct bfa_cee_s *cee, bfa_status_t status)
u32
bfa_cee_meminfo(void)
{
- return (bfa_cee_attr_meminfo() + bfa_cee_stats_meminfo());
+ return bfa_cee_attr_meminfo() + bfa_cee_stats_meminfo();
}
/**
diff --git a/drivers/scsi/bfa/bfa_csdebug.c b/drivers/scsi/bfa/bfa_csdebug.c
index 1b71d34..caeb114 100644
--- a/drivers/scsi/bfa/bfa_csdebug.c
+++ b/drivers/scsi/bfa/bfa_csdebug.c
@@ -47,12 +47,12 @@ bfa_q_is_on_q_func(struct list_head *q, struct list_head *qe)
tqe = bfa_q_next(q);
while (tqe != q) {
if (tqe == qe)
- return (1);
+ return 1;
tqe = bfa_q_next(tqe);
if (tqe == NULL)
break;
}
- return (0);
+ return 0;
}
diff --git a/drivers/scsi/bfa/bfa_fcpim.c b/drivers/scsi/bfa/bfa_fcpim.c
index 401babe..790c945 100644
--- a/drivers/scsi/bfa/bfa_fcpim.c
+++ b/drivers/scsi/bfa/bfa_fcpim.c
@@ -131,7 +131,7 @@ bfa_fcpim_path_tov_get(struct bfa_s *bfa)
{
struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
- return (fcpim->path_tov / 1000);
+ return fcpim->path_tov / 1000;
}
bfa_status_t
@@ -169,7 +169,7 @@ bfa_fcpim_qdepth_get(struct bfa_s *bfa)
{
struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
- return (fcpim->q_depth);
+ return fcpim->q_depth;
}
diff --git a/drivers/scsi/bfa/bfa_fcpim_priv.h b/drivers/scsi/bfa/bfa_fcpim_priv.h
index 153206c..5cf4184 100644
--- a/drivers/scsi/bfa/bfa_fcpim_priv.h
+++ b/drivers/scsi/bfa/bfa_fcpim_priv.h
@@ -35,7 +35,7 @@
#define BFA_FCPIM_PATHTOV_MAX (90 * 1000) /* in millisecs */
#define bfa_fcpim_stats(__fcpim, __stats) \
- (__fcpim)->stats.__stats ++
+ ((__fcpim)->stats.__stats++)
struct bfa_fcpim_mod_s {
struct bfa_s *bfa;
@@ -143,7 +143,7 @@ struct bfa_itnim_s {
struct bfa_itnim_hal_stats_s stats;
};
-#define bfa_itnim_is_online(_itnim) (_itnim)->is_online
+#define bfa_itnim_is_online(_itnim) ((_itnim)->is_online)
#define BFA_FCPIM_MOD(_hal) (&(_hal)->modules.fcpim_mod)
#define BFA_IOIM_FROM_TAG(_fcpim, _iotag) \
(&fcpim->ioim_arr[_iotag])
diff --git a/drivers/scsi/bfa/bfa_fcport.c b/drivers/scsi/bfa/bfa_fcport.c
index 9924359..aef648b 100644
--- a/drivers/scsi/bfa/bfa_fcport.c
+++ b/drivers/scsi/bfa/bfa_fcport.c
@@ -388,32 +388,29 @@ bfa_pport_sm_linkup(struct bfa_pport_s *pport, enum bfa_pport_sm_event event)
bfa_pport_callback(pport, BFA_PPORT_LINKDOWN);
bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL,
BFA_PL_EID_PORT_ST_CHANGE, 0, "Port Linkdown");
- if (BFA_PORT_IS_DISABLED(pport->bfa)) {
+ if (BFA_PORT_IS_DISABLED(pport->bfa))
bfa_pport_aen_post(pport, BFA_PORT_AEN_OFFLINE);
- } else {
+ else
bfa_pport_aen_post(pport, BFA_PORT_AEN_DISCONNECT);
- }
break;
case BFA_PPORT_SM_STOP:
bfa_sm_set_state(pport, bfa_pport_sm_stopped);
bfa_pport_reset_linkinfo(pport);
- if (BFA_PORT_IS_DISABLED(pport->bfa)) {
+ if (BFA_PORT_IS_DISABLED(pport->bfa))
bfa_pport_aen_post(pport, BFA_PORT_AEN_OFFLINE);
- } else {
+ else
bfa_pport_aen_post(pport, BFA_PORT_AEN_DISCONNECT);
- }
break;
case BFA_PPORT_SM_HWFAIL:
bfa_sm_set_state(pport, bfa_pport_sm_iocdown);
bfa_pport_reset_linkinfo(pport);
bfa_pport_callback(pport, BFA_PPORT_LINKDOWN);
- if (BFA_PORT_IS_DISABLED(pport->bfa)) {
+ if (BFA_PORT_IS_DISABLED(pport->bfa))
bfa_pport_aen_post(pport, BFA_PORT_AEN_OFFLINE);
- } else {
+ else
bfa_pport_aen_post(pport, BFA_PORT_AEN_DISCONNECT);
- }
break;
default:
@@ -999,10 +996,10 @@ bfa_pport_enable(struct bfa_s *bfa)
struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
if (pport->diag_busy)
- return (BFA_STATUS_DIAG_BUSY);
+ return BFA_STATUS_DIAG_BUSY;
else if (bfa_sm_cmp_state
(BFA_PORT_MOD(bfa), bfa_pport_sm_disabling_qwait))
- return (BFA_STATUS_DEVBUSY);
+ return BFA_STATUS_DEVBUSY;
bfa_sm_send_event(BFA_PORT_MOD(bfa), BFA_PPORT_SM_ENABLE);
return BFA_STATUS_OK;
@@ -1032,7 +1029,7 @@ bfa_pport_cfg_speed(struct bfa_s *bfa, enum bfa_pport_speed speed)
pport->cfg.speed = speed;
- return (BFA_STATUS_OK);
+ return BFA_STATUS_OK;
}
/**
@@ -1068,7 +1065,7 @@ bfa_pport_cfg_topology(struct bfa_s *bfa, enum bfa_pport_topology topology)
}
pport->cfg.topology = topology;
- return (BFA_STATUS_OK);
+ return BFA_STATUS_OK;
}
/**
@@ -1094,7 +1091,7 @@ bfa_pport_cfg_hardalpa(struct bfa_s *bfa, u8 alpa)
pport->cfg.cfg_hardalpa = BFA_TRUE;
pport->cfg.hardalpa = alpa;
- return (BFA_STATUS_OK);
+ return BFA_STATUS_OK;
}
bfa_status_t
@@ -1106,7 +1103,7 @@ bfa_pport_clr_hardalpa(struct bfa_s *bfa)
bfa_trc(bfa, pport->cfg.hardalpa);
pport->cfg.cfg_hardalpa = BFA_FALSE;
- return (BFA_STATUS_OK);
+ return BFA_STATUS_OK;
}
bfa_boolean_t
@@ -1138,16 +1135,16 @@ bfa_pport_cfg_maxfrsize(struct bfa_s *bfa, u16 maxfrsize)
* with in range
*/
if ((maxfrsize > FC_MAX_PDUSZ) || (maxfrsize < FC_MIN_PDUSZ))
- return (BFA_STATUS_INVLD_DFSZ);
+ return BFA_STATUS_INVLD_DFSZ;
/*
* power of 2, if not the max frame size of 2112
*/
if ((maxfrsize != FC_MAX_PDUSZ) && (maxfrsize & (maxfrsize - 1)))
- return (BFA_STATUS_INVLD_DFSZ);
+ return BFA_STATUS_INVLD_DFSZ;
pport->cfg.maxfrsize = maxfrsize;
- return (BFA_STATUS_OK);
+ return BFA_STATUS_OK;
}
u16
@@ -1415,7 +1412,7 @@ bfa_pport_get_stats(struct bfa_s *bfa, union bfa_pport_stats_u *stats,
if (port->stats_busy) {
bfa_trc(bfa, port->stats_busy);
- return (BFA_STATUS_DEVBUSY);
+ return BFA_STATUS_DEVBUSY;
}
port->stats_busy = BFA_TRUE;
@@ -1427,7 +1424,7 @@ bfa_pport_get_stats(struct bfa_s *bfa, union bfa_pport_stats_u *stats,
bfa_timer_start(bfa, &port->timer, bfa_port_stats_timeout, port,
BFA_PORT_STATS_TOV);
- return (BFA_STATUS_OK);
+ return BFA_STATUS_OK;
}
bfa_status_t
@@ -1437,7 +1434,7 @@ bfa_pport_clear_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn, void *cbarg)
if (port->stats_busy) {
bfa_trc(bfa, port->stats_busy);
- return (BFA_STATUS_DEVBUSY);
+ return BFA_STATUS_DEVBUSY;
}
port->stats_busy = BFA_TRUE;
@@ -1448,7 +1445,7 @@ bfa_pport_clear_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn, void *cbarg)
bfa_timer_start(bfa, &port->timer, bfa_port_stats_clr_timeout, port,
BFA_PORT_STATS_TOV);
- return (BFA_STATUS_OK);
+ return BFA_STATUS_OK;
}
bfa_status_t
@@ -1515,7 +1512,7 @@ bfa_pport_get_qos_stats(struct bfa_s *bfa, union bfa_pport_stats_u *stats,
/*
* QoS stats is embedded in port stats
*/
- return (bfa_pport_get_stats(bfa, stats, cbfn, cbarg));
+ return bfa_pport_get_stats(bfa, stats, cbfn, cbarg);
}
bfa_status_t
@@ -1525,7 +1522,7 @@ bfa_pport_clear_qos_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn, void *cbarg)
if (port->stats_busy) {
bfa_trc(bfa, port->stats_busy);
- return (BFA_STATUS_DEVBUSY);
+ return BFA_STATUS_DEVBUSY;
}
port->stats_busy = BFA_TRUE;
@@ -1536,7 +1533,7 @@ bfa_pport_clear_qos_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn, void *cbarg)
bfa_timer_start(bfa, &port->timer, bfa_port_stats_clr_timeout, port,
BFA_PORT_STATS_TOV);
- return (BFA_STATUS_OK);
+ return BFA_STATUS_OK;
}
/**
@@ -1545,7 +1542,7 @@ bfa_pport_clear_qos_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn, void *cbarg)
bfa_status_t
bfa_pport_trunk_disable(struct bfa_s *bfa)
{
- return (BFA_STATUS_OK);
+ return BFA_STATUS_OK;
}
bfa_boolean_t
@@ -1562,8 +1559,8 @@ bfa_pport_is_disabled(struct bfa_s *bfa)
{
struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
- return (bfa_sm_to_state(hal_pport_sm_table, port->sm) ==
- BFA_PPORT_ST_DISABLED);
+ return bfa_sm_to_state(hal_pport_sm_table, port->sm) ==
+ BFA_PPORT_ST_DISABLED;
}
@@ -1572,7 +1569,7 @@ bfa_pport_is_ratelim(struct bfa_s *bfa)
{
struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
-return (pport->cfg.ratelimit ? BFA_TRUE : BFA_FALSE);
+ return pport->cfg.ratelimit ? BFA_TRUE : BFA_FALSE;
}
@@ -1620,7 +1617,7 @@ bfa_pport_cfg_ratelim_speed(struct bfa_s *bfa, enum bfa_pport_speed speed)
pport->cfg.trl_def_speed = speed;
- return (BFA_STATUS_OK);
+ return BFA_STATUS_OK;
}
/**
@@ -1632,7 +1629,7 @@ bfa_pport_get_ratelim_speed(struct bfa_s *bfa)
struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
bfa_trc(bfa, pport->cfg.trl_def_speed);
- return (pport->cfg.trl_def_speed);
+ return pport->cfg.trl_def_speed;
}
diff --git a/drivers/scsi/bfa/bfa_fcs_lport.c b/drivers/scsi/bfa/bfa_fcs_lport.c
index 8975ed0..c7ab257 100644
--- a/drivers/scsi/bfa/bfa_fcs_lport.c
+++ b/drivers/scsi/bfa/bfa_fcs_lport.c
@@ -568,11 +568,10 @@ bfa_fcs_port_offline_actions(struct bfa_fcs_port_s *port)
__port_action[port->fabric->fab_type].offline(port);
- if (bfa_fcs_fabric_is_online(port->fabric) == BFA_TRUE) {
+ if (bfa_fcs_fabric_is_online(port->fabric) == BFA_TRUE)
bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_DISCONNECT);
- } else {
+ else
bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_OFFLINE);
- }
bfa_fcb_port_offline(port->fcs->bfad, port->port_cfg.roles,
port->fabric->vf_drv,
(port->vport == NULL) ? NULL : port->vport->vport_drv);
@@ -777,7 +776,7 @@ bfa_fcs_port_get_rport_by_pwwn(struct bfa_fcs_port_s *port, wwn_t pwwn)
}
bfa_trc(port->fcs, pwwn);
- return (NULL);
+ return NULL;
}
/**
@@ -796,7 +795,7 @@ bfa_fcs_port_get_rport_by_nwwn(struct bfa_fcs_port_s *port, wwn_t nwwn)
}
bfa_trc(port->fcs, nwwn);
- return (NULL);
+ return NULL;
}
/**
@@ -870,7 +869,7 @@ bfa_fcs_port_lip(struct bfa_fcs_port_s *port)
bfa_boolean_t
bfa_fcs_port_is_online(struct bfa_fcs_port_s *port)
{
- return (bfa_sm_cmp_state(port, bfa_fcs_port_sm_online));
+ return bfa_sm_cmp_state(port, bfa_fcs_port_sm_online);
}
/**
diff --git a/drivers/scsi/bfa/bfa_fcxp.c b/drivers/scsi/bfa/bfa_fcxp.c
index 4754a0e..cf0ad67 100644
--- a/drivers/scsi/bfa/bfa_fcxp.c
+++ b/drivers/scsi/bfa/bfa_fcxp.c
@@ -199,7 +199,7 @@ bfa_fcxp_get(struct bfa_fcxp_mod_s *fm)
if (fcxp)
list_add_tail(&fcxp->qe, &fm->fcxp_active_q);
- return (fcxp);
+ return fcxp;
}
static void
@@ -503,7 +503,7 @@ bfa_fcxp_alloc(void *caller, struct bfa_s *bfa, int nreq_sgles,
fcxp = bfa_fcxp_get(BFA_FCXP_MOD(bfa));
if (fcxp == NULL)
- return (NULL);
+ return NULL;
bfa_trc(bfa, fcxp->fcxp_tag);
@@ -568,7 +568,7 @@ bfa_fcxp_alloc(void *caller, struct bfa_s *bfa, int nreq_sgles,
}
}
- return (fcxp);
+ return fcxp;
}
/**
@@ -709,7 +709,7 @@ bfa_status_t
bfa_fcxp_abort(struct bfa_fcxp_s *fcxp)
{
bfa_assert(0);
- return (BFA_STATUS_OK);
+ return BFA_STATUS_OK;
}
void
diff --git a/drivers/scsi/bfa/bfa_intr.c b/drivers/scsi/bfa/bfa_intr.c
index 0ca1257..b36540e 100644
--- a/drivers/scsi/bfa/bfa_intr.c
+++ b/drivers/scsi/bfa/bfa_intr.c
@@ -59,7 +59,7 @@ bfa_intx(struct bfa_s *bfa)
qintr = intr & __HFN_INT_RME_MASK;
bfa_reg_write(bfa->iocfc.bfa_regs.intr_status, qintr);
- for (queue = 0; queue < BFI_IOC_MAX_CQS_ASIC; queue ++) {
+ for (queue = 0; queue < BFI_IOC_MAX_CQS_ASIC; queue++) {
if (intr & (__HFN_INT_RME_Q0 << queue))
bfa_msix_rspq(bfa, queue & (BFI_IOC_MAX_CQS - 1));
}
diff --git a/drivers/scsi/bfa/bfa_intr_priv.h b/drivers/scsi/bfa/bfa_intr_priv.h
index 8ce6e6b..5fc301c 100644
--- a/drivers/scsi/bfa/bfa_intr_priv.h
+++ b/drivers/scsi/bfa/bfa_intr_priv.h
@@ -26,9 +26,9 @@ void bfa_isr_unhandled(struct bfa_s *bfa, struct bfi_msg_s *m);
void bfa_isr_bind(enum bfi_mclass mc, bfa_isr_func_t isr_func);
-#define bfa_reqq_pi(__bfa, __reqq) (__bfa)->iocfc.req_cq_pi[__reqq]
+#define bfa_reqq_pi(__bfa, __reqq) ((__bfa)->iocfc.req_cq_pi[__reqq])
#define bfa_reqq_ci(__bfa, __reqq) \
- *(u32 *)((__bfa)->iocfc.req_cq_shadow_ci[__reqq].kva)
+ (*(u32 *)((__bfa)->iocfc.req_cq_shadow_ci[__reqq].kva))
#define bfa_reqq_full(__bfa, __reqq) \
(((bfa_reqq_pi(__bfa, __reqq) + 1) & \
@@ -50,14 +50,16 @@ void bfa_isr_bind(enum bfi_mclass mc, bfa_isr_func_t isr_func);
} while (0)
#define bfa_rspq_pi(__bfa, __rspq) \
- *(u32 *)((__bfa)->iocfc.rsp_cq_shadow_pi[__rspq].kva)
+ (*(u32 *)((__bfa)->iocfc.rsp_cq_shadow_pi[__rspq].kva))
-#define bfa_rspq_ci(__bfa, __rspq) (__bfa)->iocfc.rsp_cq_ci[__rspq]
+#define bfa_rspq_ci(__bfa, __rspq) ((__bfa)->iocfc.rsp_cq_ci[__rspq])
#define bfa_rspq_elem(__bfa, __rspq, __ci) \
- &((struct bfi_msg_s *)((__bfa)->iocfc.rsp_cq_ba[__rspq].kva))[__ci]
+ (&((struct bfi_msg_s *)((__bfa)->iocfc.rsp_cq_ba[__rspq].kva))[__ci])
-#define CQ_INCR(__index, __size) \
- (__index)++; (__index) &= ((__size) - 1)
+#define CQ_INCR(__index, __size) do { \
+ (__index)++; \
+ (__index) &= ((__size) - 1); \
+} while (0)
/**
* Queue element to wait for room in request queue. FIFO order is
@@ -94,7 +96,7 @@ bfa_reqq_winit(struct bfa_reqq_wait_s *wqe, void (*qresume) (void *cbarg),
wqe->cbarg = cbarg;
}
-#define bfa_reqq(__bfa, __reqq) &(__bfa)->reqq_waitq[__reqq]
+#define bfa_reqq(__bfa, __reqq) (&(__bfa)->reqq_waitq[__reqq])
/**
* static inline void
diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c
index 1493489..397d7e9 100644
--- a/drivers/scsi/bfa/bfa_ioc.c
+++ b/drivers/scsi/bfa/bfa_ioc.c
@@ -51,7 +51,7 @@ BFA_TRC_FILE(HAL, IOC);
(sizeof(struct bfa_trc_mod_s) - \
BFA_TRC_MAX * sizeof(struct bfa_trc_s)))
#define BFA_DBG_FWTRC_OFF(_fn) (BFI_IOC_TRC_OFF + BFA_DBG_FWTRC_LEN * (_fn))
-#define bfa_ioc_stats(_ioc, _stats) (_ioc)->stats._stats ++
+#define bfa_ioc_stats(_ioc, _stats) ((_ioc)->stats._stats++)
#define BFA_FLASH_CHUNK_NO(off) (off / BFI_FLASH_CHUNK_SZ_WORDS)
#define BFA_FLASH_OFFSET_IN_CHUNK(off) (off % BFI_FLASH_CHUNK_SZ_WORDS)
@@ -1953,8 +1953,8 @@ bfa_ioc_error_isr(struct bfa_ioc_s *ioc)
bfa_boolean_t
bfa_ioc_is_disabled(struct bfa_ioc_s *ioc)
{
- return (bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabling)
- || bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabled));
+ return bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabling)
+ || bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabled);
}
/**
@@ -1963,9 +1963,9 @@ bfa_ioc_is_disabled(struct bfa_ioc_s *ioc)
bfa_boolean_t
bfa_ioc_fw_mismatch(struct bfa_ioc_s *ioc)
{
- return (bfa_fsm_cmp_state(ioc, bfa_ioc_sm_reset)
+ return bfa_fsm_cmp_state(ioc, bfa_ioc_sm_reset)
|| bfa_fsm_cmp_state(ioc, bfa_ioc_sm_fwcheck)
- || bfa_fsm_cmp_state(ioc, bfa_ioc_sm_mismatch));
+ || bfa_fsm_cmp_state(ioc, bfa_ioc_sm_mismatch);
}
#define bfa_ioc_state_disabled(__sm) \
diff --git a/drivers/scsi/bfa/bfa_ioc.h b/drivers/scsi/bfa/bfa_ioc.h
index 58efd4b..7c30f05 100644
--- a/drivers/scsi/bfa/bfa_ioc.h
+++ b/drivers/scsi/bfa/bfa_ioc.h
@@ -179,16 +179,16 @@ struct bfa_ioc_s {
struct bfa_ioc_mbox_mod_s mbox_mod;
};
-#define bfa_ioc_pcifn(__ioc) (__ioc)->pcidev.pci_func
-#define bfa_ioc_devid(__ioc) (__ioc)->pcidev.device_id
-#define bfa_ioc_bar0(__ioc) (__ioc)->pcidev.pci_bar_kva
+#define bfa_ioc_pcifn(__ioc) ((__ioc)->pcidev.pci_func)
+#define bfa_ioc_devid(__ioc) ((__ioc)->pcidev.device_id)
+#define bfa_ioc_bar0(__ioc) ((__ioc)->pcidev.pci_bar_kva)
#define bfa_ioc_portid(__ioc) ((__ioc)->port_id)
#define bfa_ioc_fetch_stats(__ioc, __stats) \
- ((__stats)->drv_stats) = (__ioc)->stats
+ (((__stats)->drv_stats) = (__ioc)->stats)
#define bfa_ioc_clr_stats(__ioc) \
bfa_os_memset(&(__ioc)->stats, 0, sizeof((__ioc)->stats))
-#define bfa_ioc_maxfrsize(__ioc) (__ioc)->attr->maxfrsize
-#define bfa_ioc_rx_bbcredit(__ioc) (__ioc)->attr->rx_bbcredit
+#define bfa_ioc_maxfrsize(__ioc) ((__ioc)->attr->maxfrsize)
+#define bfa_ioc_rx_bbcredit(__ioc) ((__ioc)->attr->rx_bbcredit)
#define bfa_ioc_speed_sup(__ioc) \
BFI_ADAPTER_GETP(SPEED, (__ioc)->attr->adapter_prop)
diff --git a/drivers/scsi/bfa/bfa_iocfc.c b/drivers/scsi/bfa/bfa_iocfc.c
index 12350b0..d7ab792 100644
--- a/drivers/scsi/bfa/bfa_iocfc.c
+++ b/drivers/scsi/bfa/bfa_iocfc.c
@@ -794,7 +794,7 @@ bfa_iocfc_get_stats(struct bfa_s *bfa, struct bfa_iocfc_stats_s *stats,
if (iocfc->stats_busy) {
bfa_trc(bfa, iocfc->stats_busy);
- return (BFA_STATUS_DEVBUSY);
+ return BFA_STATUS_DEVBUSY;
}
iocfc->stats_busy = BFA_TRUE;
@@ -804,7 +804,7 @@ bfa_iocfc_get_stats(struct bfa_s *bfa, struct bfa_iocfc_stats_s *stats,
bfa_iocfc_stats_query(bfa);
- return (BFA_STATUS_OK);
+ return BFA_STATUS_OK;
}
bfa_status_t
@@ -814,7 +814,7 @@ bfa_iocfc_clear_stats(struct bfa_s *bfa, bfa_cb_ioc_t cbfn, void *cbarg)
if (iocfc->stats_busy) {
bfa_trc(bfa, iocfc->stats_busy);
- return (BFA_STATUS_DEVBUSY);
+ return BFA_STATUS_DEVBUSY;
}
iocfc->stats_busy = BFA_TRUE;
@@ -822,7 +822,7 @@ bfa_iocfc_clear_stats(struct bfa_s *bfa, bfa_cb_ioc_t cbfn, void *cbarg)
iocfc->stats_cbarg = cbarg;
bfa_iocfc_stats_clear(bfa);
- return (BFA_STATUS_OK);
+ return BFA_STATUS_OK;
}
/**
diff --git a/drivers/scsi/bfa/bfa_iocfc.h b/drivers/scsi/bfa/bfa_iocfc.h
index 7ad177e..ce9a830 100644
--- a/drivers/scsi/bfa/bfa_iocfc.h
+++ b/drivers/scsi/bfa/bfa_iocfc.h
@@ -107,13 +107,13 @@ struct bfa_iocfc_s {
#define bfa_lpuid(__bfa) bfa_ioc_portid(&(__bfa)->ioc)
#define bfa_msix_init(__bfa, __nvecs) \
- (__bfa)->iocfc.hwif.hw_msix_init(__bfa, __nvecs)
+ ((__bfa)->iocfc.hwif.hw_msix_init(__bfa, __nvecs))
#define bfa_msix_install(__bfa) \
- (__bfa)->iocfc.hwif.hw_msix_install(__bfa)
+ ((__bfa)->iocfc.hwif.hw_msix_install(__bfa))
#define bfa_msix_uninstall(__bfa) \
- (__bfa)->iocfc.hwif.hw_msix_uninstall(__bfa)
+ ((__bfa)->iocfc.hwif.hw_msix_uninstall(__bfa))
#define bfa_isr_mode_set(__bfa, __msix) \
- (__bfa)->iocfc.hwif.hw_isr_mode_set(__bfa, __msix)
+ ((__bfa)->iocfc.hwif.hw_isr_mode_set(__bfa, __msix))
#define bfa_msix_getvecs(__bfa, __vecmap, __nvecs, __maxvec) \
(__bfa)->iocfc.hwif.hw_msix_getvecs(__bfa, __vecmap, __nvecs, __maxvec)
diff --git a/drivers/scsi/bfa/bfa_ioim.c b/drivers/scsi/bfa/bfa_ioim.c
index 7ae2552..f81d359 100644
--- a/drivers/scsi/bfa/bfa_ioim.c
+++ b/drivers/scsi/bfa/bfa_ioim.c
@@ -105,13 +105,13 @@ bfa_ioim_sm_uninit(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
list_del(&ioim->qe);
list_add_tail(&ioim->qe,
- &ioim->fcpim->ioim_comp_q);
+ &ioim->fcpim->ioim_comp_q);
bfa_cb_queue(ioim->bfa, &ioim->hcb_qe,
__bfa_cb_ioim_pathtov, ioim);
} else {
list_del(&ioim->qe);
list_add_tail(&ioim->qe,
- &ioim->itnim->pending_q);
+ &ioim->itnim->pending_q);
}
break;
}
diff --git a/drivers/scsi/bfa/bfa_itnim.c b/drivers/scsi/bfa/bfa_itnim.c
index 4d5c61a..eabf7d3 100644
--- a/drivers/scsi/bfa/bfa_itnim.c
+++ b/drivers/scsi/bfa/bfa_itnim.c
@@ -1029,7 +1029,7 @@ bfa_itnim_create(struct bfa_s *bfa, struct bfa_rport_s *rport, void *ditn)
bfa_stats(itnim, creates);
bfa_sm_send_event(itnim, BFA_ITNIM_SM_CREATE);
- return (itnim);
+ return itnim;
}
void
@@ -1061,7 +1061,7 @@ bfa_itnim_offline(struct bfa_itnim_s *itnim)
bfa_boolean_t
bfa_itnim_hold_io(struct bfa_itnim_s *itnim)
{
- return (
+ return
itnim->fcpim->path_tov && itnim->iotov_active &&
(bfa_sm_cmp_state(itnim, bfa_itnim_sm_fwcreate) ||
bfa_sm_cmp_state(itnim, bfa_itnim_sm_sler) ||
@@ -1069,7 +1069,7 @@ bfa_itnim_hold_io(struct bfa_itnim_s *itnim)
bfa_sm_cmp_state(itnim, bfa_itnim_sm_fwdelete) ||
bfa_sm_cmp_state(itnim, bfa_itnim_sm_offline) ||
bfa_sm_cmp_state(itnim, bfa_itnim_sm_iocdisable))
-);
+ ;
}
void
diff --git a/drivers/scsi/bfa/bfa_log.c b/drivers/scsi/bfa/bfa_log.c
index c2735e5..e751401 100644
--- a/drivers/scsi/bfa/bfa_log.c
+++ b/drivers/scsi/bfa/bfa_log.c
@@ -231,9 +231,9 @@ bfa_log_get_level(struct bfa_log_mod_s *log_mod, int mod_id)
return BFA_LOG_INVALID;
if (log_mod)
- return (log_mod->log_level[mod_id]);
+ return log_mod->log_level[mod_id];
else
- return (bfa_log_info[mod_id].level);
+ return bfa_log_info[mod_id].level;
}
enum bfa_log_severity
diff --git a/drivers/scsi/bfa/bfa_port_priv.h b/drivers/scsi/bfa/bfa_port_priv.h
index 4b97e27..51f698a 100644
--- a/drivers/scsi/bfa/bfa_port_priv.h
+++ b/drivers/scsi/bfa/bfa_port_priv.h
@@ -59,8 +59,8 @@ struct bfa_pport_s {
u8 *stats_kva;
u64 stats_pa;
union bfa_pport_stats_u *stats; /* pport stats */
- u32 mypid : 24;
- u32 rsvd_b : 8;
+ u32 mypid:24;
+ u32 rsvd_b:8;
struct bfa_timer_s timer; /* timer */
union bfa_pport_stats_u *stats_ret;
/* driver stats location */
diff --git a/drivers/scsi/bfa/bfa_rport.c b/drivers/scsi/bfa/bfa_rport.c
index 16da77a..3e1990a 100644
--- a/drivers/scsi/bfa/bfa_rport.c
+++ b/drivers/scsi/bfa/bfa_rport.c
@@ -677,7 +677,7 @@ bfa_rport_alloc(struct bfa_rport_mod_s *mod)
if (rport)
list_add_tail(&rport->qe, &mod->rp_active_q);
- return (rport);
+ return rport;
}
static void
@@ -834,7 +834,7 @@ bfa_rport_create(struct bfa_s *bfa, void *rport_drv)
rp = bfa_rport_alloc(BFA_RPORT_MOD(bfa));
if (rp == NULL)
- return (NULL);
+ return NULL;
rp->bfa = bfa;
rp->rport_drv = rport_drv;
@@ -843,7 +843,7 @@ bfa_rport_create(struct bfa_s *bfa, void *rport_drv)
bfa_assert(bfa_sm_cmp_state(rp, bfa_rport_sm_uninit));
bfa_sm_send_event(rp, BFA_RPORT_SM_CREATE);
- return (rp);
+ return rp;
}
void
diff --git a/drivers/scsi/bfa/bfa_tskim.c b/drivers/scsi/bfa/bfa_tskim.c
index 010d40d..ff7a4dc 100644
--- a/drivers/scsi/bfa/bfa_tskim.c
+++ b/drivers/scsi/bfa/bfa_tskim.c
@@ -23,13 +23,14 @@ BFA_TRC_FILE(HAL, TSKIM);
/**
* task management completion handling
*/
-#define bfa_tskim_qcomp(__tskim, __cbfn) do { \
- bfa_cb_queue((__tskim)->bfa, &(__tskim)->hcb_qe, __cbfn, (__tskim)); \
+#define bfa_tskim_qcomp(__tskim, __cbfn) do { \
+ bfa_cb_queue((__tskim)->bfa, &(__tskim)->hcb_qe, \
+ __cbfn, (__tskim)); \
bfa_tskim_notify_comp(__tskim); \
} while (0)
-#define bfa_tskim_notify_comp(__tskim) do { \
- if ((__tskim)->notify) \
+#define bfa_tskim_notify_comp(__tskim) do { \
+ if ((__tskim)->notify) \
bfa_itnim_tskdone((__tskim)->itnim); \
} while (0)
diff --git a/drivers/scsi/bfa/bfa_uf.c b/drivers/scsi/bfa/bfa_uf.c
index ff5f9de..4b3c241 100644
--- a/drivers/scsi/bfa/bfa_uf.c
+++ b/drivers/scsi/bfa/bfa_uf.c
@@ -185,7 +185,7 @@ bfa_uf_get(struct bfa_uf_mod_s *uf_mod)
struct bfa_uf_s *uf;
bfa_q_deq(&uf_mod->uf_free_q, &uf);
- return (uf);
+ return uf;
}
static void
diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c
index 6f2be5a..b52b773 100644
--- a/drivers/scsi/bfa/bfad.c
+++ b/drivers/scsi/bfa/bfad.c
@@ -188,8 +188,8 @@ static struct bfad_port_s *
bfad_get_drv_port(struct bfad_s *bfad, struct bfad_vf_s *vf_drv,
struct bfad_vport_s *vp_drv)
{
- return ((vp_drv) ? (&(vp_drv)->drv_port)
- : ((vf_drv) ? (&(vf_drv)->base_port) : (&(bfad)->pport)));
+ return (vp_drv) ? (&(vp_drv)->drv_port)
+ : ((vf_drv) ? (&(vf_drv)->base_port) : (&(bfad)->pport));
}
struct bfad_port_s *
@@ -716,7 +716,7 @@ bfad_drv_init(struct bfad_s *bfad)
if ((bfad->bfad_flags & BFAD_MSIX_ON)
&& bfad_install_msix_handler(bfad)) {
printk(KERN_WARNING "%s: install_msix failed, bfad%d\n",
- __FUNCTION__, bfad->inst_no);
+ __func__, bfad->inst_no);
}
bfad_init_timer(bfad);
diff --git a/drivers/scsi/bfa/bfad_fwimg.c b/drivers/scsi/bfa/bfad_fwimg.c
index bd34b0d..2ad65f2 100644
--- a/drivers/scsi/bfa/bfad_fwimg.c
+++ b/drivers/scsi/bfa/bfad_fwimg.c
@@ -65,10 +65,10 @@ bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image,
memcpy(*bfi_image, fw->data, fw->size);
*bfi_image_size = fw->size/sizeof(u32);
- return(*bfi_image);
+ return *bfi_image;
error:
- return(NULL);
+ return NULL;
}
u32 *
@@ -78,12 +78,12 @@ bfad_get_firmware_buf(struct pci_dev *pdev)
if (bfi_image_ct_size == 0)
bfad_read_firmware(pdev, &bfi_image_ct,
&bfi_image_ct_size, BFAD_FW_FILE_CT);
- return(bfi_image_ct);
+ return bfi_image_ct;
} else {
if (bfi_image_cb_size == 0)
bfad_read_firmware(pdev, &bfi_image_cb,
&bfi_image_cb_size, BFAD_FW_FILE_CB);
- return(bfi_image_cb);
+ return bfi_image_cb;
}
}
diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c
index 55d012a..f788c2a 100644
--- a/drivers/scsi/bfa/bfad_im.c
+++ b/drivers/scsi/bfa/bfad_im.c
@@ -1050,7 +1050,7 @@ bfad_im_itnim_work_handler(struct work_struct *work)
} else {
printk(KERN_WARNING
"%s: itnim %llx is already in online state\n",
- __FUNCTION__,
+ __func__,
bfa_fcs_itnim_get_pwwn(&itnim->fcs_itnim));
}
diff --git a/drivers/scsi/bfa/bfad_im_compat.h b/drivers/scsi/bfa/bfad_im_compat.h
index 1d3e74e..b36be15 100644
--- a/drivers/scsi/bfa/bfad_im_compat.h
+++ b/drivers/scsi/bfa/bfad_im_compat.h
@@ -31,7 +31,7 @@ u32 *bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image,
static inline u32 *
bfad_load_fwimg(struct pci_dev *pdev)
{
- return(bfad_get_firmware_buf(pdev));
+ return bfad_get_firmware_buf(pdev);
}
static inline void
diff --git a/drivers/scsi/bfa/bfad_intr.c b/drivers/scsi/bfa/bfad_intr.c
index f104e02..7de8832 100644
--- a/drivers/scsi/bfa/bfad_intr.c
+++ b/drivers/scsi/bfa/bfad_intr.c
@@ -23,13 +23,12 @@ BFA_TRC_FILE(LDRV, INTR);
/**
* bfa_isr BFA driver interrupt functions
*/
-irqreturn_t bfad_intx(int irq, void *dev_id);
static int msix_disable;
module_param(msix_disable, int, S_IRUGO | S_IWUSR);
/**
* Line based interrupt handler.
*/
-irqreturn_t
+static irqreturn_t
bfad_intx(int irq, void *dev_id)
{
struct bfad_s *bfad = dev_id;
diff --git a/drivers/scsi/bfa/fabric.c b/drivers/scsi/bfa/fabric.c
index a8b14c4..a4b5dd4 100644
--- a/drivers/scsi/bfa/fabric.c
+++ b/drivers/scsi/bfa/fabric.c
@@ -36,12 +36,12 @@ BFA_TRC_FILE(FCS, FABRIC);
#define BFA_FCS_FABRIC_RETRY_DELAY (2000) /* Milliseconds */
#define BFA_FCS_FABRIC_CLEANUP_DELAY (10000) /* Milliseconds */
-#define bfa_fcs_fabric_set_opertype(__fabric) do { \
- if (bfa_pport_get_topology((__fabric)->fcs->bfa) \
- == BFA_PPORT_TOPOLOGY_P2P) \
- (__fabric)->oper_type = BFA_PPORT_TYPE_NPORT; \
- else \
- (__fabric)->oper_type = BFA_PPORT_TYPE_NLPORT; \
+#define bfa_fcs_fabric_set_opertype(__fabric) do { \
+ if (bfa_pport_get_topology((__fabric)->fcs->bfa) \
+ == BFA_PPORT_TOPOLOGY_P2P) \
+ (__fabric)->oper_type = BFA_PPORT_TYPE_NPORT; \
+ else \
+ (__fabric)->oper_type = BFA_PPORT_TYPE_NLPORT; \
} while (0)
/*
@@ -887,7 +887,7 @@ bfa_fcs_fabric_modsusp(struct bfa_fcs_s *fcs)
bfa_boolean_t
bfa_fcs_fabric_is_loopback(struct bfa_fcs_fabric_s *fabric)
{
- return (bfa_sm_cmp_state(fabric, bfa_fcs_fabric_sm_loopback));
+ return bfa_sm_cmp_state(fabric, bfa_fcs_fabric_sm_loopback);
}
enum bfa_pport_type
@@ -974,7 +974,7 @@ bfa_fcs_fabric_port_delete_comp(struct bfa_fcs_fabric_s *fabric)
int
bfa_fcs_fabric_is_online(struct bfa_fcs_fabric_s *fabric)
{
- return (bfa_sm_cmp_state(fabric, bfa_fcs_fabric_sm_online));
+ return bfa_sm_cmp_state(fabric, bfa_fcs_fabric_sm_online);
}
@@ -1015,7 +1015,7 @@ bfa_fcs_fabric_vport_lookup(struct bfa_fcs_fabric_s *fabric, wwn_t pwwn)
u16
bfa_fcs_fabric_vport_count(struct bfa_fcs_fabric_s *fabric)
{
- return (fabric->num_vports);
+ return fabric->num_vports;
}
/**
diff --git a/drivers/scsi/bfa/fcbuild.c b/drivers/scsi/bfa/fcbuild.c
index d174706..fee5456 100644
--- a/drivers/scsi/bfa/fcbuild.c
+++ b/drivers/scsi/bfa/fcbuild.c
@@ -188,14 +188,14 @@ fc_els_rsp_parse(struct fchs_s *fchs, int len)
switch (els_cmd->els_code) {
case FC_ELS_LS_RJT:
if (ls_rjt->reason_code == FC_LS_RJT_RSN_LOGICAL_BUSY)
- return (FC_PARSE_BUSY);
+ return FC_PARSE_BUSY;
else
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
case FC_ELS_ACC:
- return (FC_PARSE_OK);
+ return FC_PARSE_OK;
}
- return (FC_PARSE_OK);
+ return FC_PARSE_OK;
}
static void
@@ -228,7 +228,7 @@ fc_plogi_x_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id,
bfa_os_memcpy(&plogi->port_name, &port_name, sizeof(wwn_t));
bfa_os_memcpy(&plogi->node_name, &node_name, sizeof(wwn_t));
- return (sizeof(struct fc_logi_s));
+ return sizeof(struct fc_logi_s);
}
u16
@@ -267,7 +267,7 @@ fc_flogi_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id,
flogi->csp.npiv_supp = 1; /* @todo. field name is not correct */
vvl_info[0] = bfa_os_htonl(FLOGI_VVL_BRCD);
- return (sizeof(struct fc_logi_s));
+ return sizeof(struct fc_logi_s);
}
u16
@@ -287,7 +287,7 @@ fc_flogi_acc_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id,
flogi->csp.bbcred = bfa_os_htons(local_bb_credits);
- return (sizeof(struct fc_logi_s));
+ return sizeof(struct fc_logi_s);
}
u16
@@ -306,7 +306,7 @@ fc_fdisc_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id,
flogi->port_name = port_name;
flogi->node_name = node_name;
- return (sizeof(struct fc_logi_s));
+ return sizeof(struct fc_logi_s);
}
u16
@@ -338,26 +338,26 @@ fc_plogi_rsp_parse(struct fchs_s *fchs, int len, wwn_t port_name)
case FC_ELS_LS_RJT:
ls_rjt = (struct fc_ls_rjt_s *) (fchs + 1);
if (ls_rjt->reason_code == FC_LS_RJT_RSN_LOGICAL_BUSY)
- return (FC_PARSE_BUSY);
+ return FC_PARSE_BUSY;
else
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
case FC_ELS_ACC:
plogi = (struct fc_logi_s *) (fchs + 1);
if (len < sizeof(struct fc_logi_s))
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
if (!wwn_is_equal(plogi->port_name, port_name))
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
if (!plogi->class3.class_valid)
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
if (bfa_os_ntohs(plogi->class3.rxsz) < (FC_MIN_PDUSZ))
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
- return (FC_PARSE_OK);
+ return FC_PARSE_OK;
default:
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
}
}
@@ -372,7 +372,7 @@ fc_plogi_parse(struct fchs_s *fchs)
if ((bfa_os_ntohs(plogi->class3.rxsz) < FC_MIN_PDUSZ)
|| (bfa_os_ntohs(plogi->class3.rxsz) > FC_MAX_PDUSZ)
|| (plogi->class3.rxsz == 0))
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
return FC_PARSE_OK;
}
@@ -393,7 +393,7 @@ fc_prli_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id,
prli->parampage.servparams.task_retry_id = 0;
prli->parampage.servparams.confirm = 1;
- return (sizeof(struct fc_prli_s));
+ return sizeof(struct fc_prli_s);
}
u16
@@ -414,41 +414,41 @@ fc_prli_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id,
prli->parampage.rspcode = FC_PRLI_ACC_XQTD;
- return (sizeof(struct fc_prli_s));
+ return sizeof(struct fc_prli_s);
}
enum fc_parse_status
fc_prli_rsp_parse(struct fc_prli_s *prli, int len)
{
if (len < sizeof(struct fc_prli_s))
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
if (prli->command != FC_ELS_ACC)
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
if ((prli->parampage.rspcode != FC_PRLI_ACC_XQTD)
&& (prli->parampage.rspcode != FC_PRLI_ACC_PREDEF_IMG))
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
if (prli->parampage.servparams.target != 1)
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
- return (FC_PARSE_OK);
+ return FC_PARSE_OK;
}
enum fc_parse_status
fc_prli_parse(struct fc_prli_s *prli)
{
if (prli->parampage.type != FC_TYPE_FCP)
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
if (!prli->parampage.imagepair)
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
if (!prli->parampage.servparams.initiator)
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
- return (FC_PARSE_OK);
+ return FC_PARSE_OK;
}
u16
@@ -462,7 +462,7 @@ fc_logo_build(struct fchs_s *fchs, struct fc_logo_s *logo, u32 d_id,
logo->nport_id = (s_id);
logo->orig_port_name = port_name;
- return (sizeof(struct fc_logo_s));
+ return sizeof(struct fc_logo_s);
}
static u16
@@ -484,7 +484,7 @@ fc_adisc_x_build(struct fchs_s *fchs, struct fc_adisc_s *adisc, u32 d_id,
adisc->orig_node_name = node_name;
adisc->nport_id = (s_id);
- return (sizeof(struct fc_adisc_s));
+ return sizeof(struct fc_adisc_s);
}
u16
@@ -511,15 +511,15 @@ fc_adisc_rsp_parse(struct fc_adisc_s *adisc, int len, wwn_t port_name,
{
if (len < sizeof(struct fc_adisc_s))
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
if (adisc->els_cmd.els_code != FC_ELS_ACC)
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
if (!wwn_is_equal(adisc->orig_port_name, port_name))
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
- return (FC_PARSE_OK);
+ return FC_PARSE_OK;
}
enum fc_parse_status
@@ -529,14 +529,14 @@ fc_adisc_parse(struct fchs_s *fchs, void *pld, u32 host_dap,
struct fc_adisc_s *adisc = (struct fc_adisc_s *) pld;
if (adisc->els_cmd.els_code != FC_ELS_ACC)
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
if ((adisc->nport_id == (host_dap))
&& wwn_is_equal(adisc->orig_port_name, port_name)
&& wwn_is_equal(adisc->orig_node_name, node_name))
- return (FC_PARSE_OK);
+ return FC_PARSE_OK;
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
}
enum fc_parse_status
@@ -550,13 +550,13 @@ fc_pdisc_parse(struct fchs_s *fchs, wwn_t node_name, wwn_t port_name)
if ((bfa_os_ntohs(pdisc->class3.rxsz) <
(FC_MIN_PDUSZ - sizeof(struct fchs_s)))
|| (pdisc->class3.rxsz == 0))
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
if (!wwn_is_equal(pdisc->port_name, port_name))
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
if (!wwn_is_equal(pdisc->node_name, node_name))
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
return FC_PARSE_OK;
}
@@ -570,7 +570,7 @@ fc_abts_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id)
fchs->s_id = (s_id);
fchs->ox_id = bfa_os_htons(ox_id);
- return (sizeof(struct fchs_s));
+ return sizeof(struct fchs_s);
}
enum fc_parse_status
@@ -578,9 +578,9 @@ fc_abts_rsp_parse(struct fchs_s *fchs, int len)
{
if ((fchs->cat_info == FC_CAT_BA_ACC)
|| (fchs->cat_info == FC_CAT_BA_RJT))
- return (FC_PARSE_OK);
+ return FC_PARSE_OK;
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
}
u16
@@ -597,7 +597,7 @@ fc_rrq_build(struct fchs_s *fchs, struct fc_rrq_s *rrq, u32 d_id,
rrq->ox_id = bfa_os_htons(rrq_oxid);
rrq->rx_id = FC_RXID_ANY;
- return (sizeof(struct fc_rrq_s));
+ return sizeof(struct fc_rrq_s);
}
u16
@@ -611,7 +611,7 @@ fc_logo_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id,
memset(acc, 0, sizeof(struct fc_els_cmd_s));
acc->els_code = FC_ELS_ACC;
- return (sizeof(struct fc_els_cmd_s));
+ return sizeof(struct fc_els_cmd_s);
}
u16
@@ -627,7 +627,7 @@ fc_ls_rjt_build(struct fchs_s *fchs, struct fc_ls_rjt_s *ls_rjt, u32 d_id,
ls_rjt->reason_code_expl = reason_code_expl;
ls_rjt->vendor_unique = 0x00;
- return (sizeof(struct fc_ls_rjt_s));
+ return sizeof(struct fc_ls_rjt_s);
}
u16
@@ -643,7 +643,7 @@ fc_ba_acc_build(struct fchs_s *fchs, struct fc_ba_acc_s *ba_acc, u32 d_id,
ba_acc->ox_id = fchs->ox_id;
ba_acc->rx_id = fchs->rx_id;
- return (sizeof(struct fc_ba_acc_s));
+ return sizeof(struct fc_ba_acc_s);
}
u16
@@ -654,7 +654,7 @@ fc_ls_acc_build(struct fchs_s *fchs, struct fc_els_cmd_s *els_cmd,
memset(els_cmd, 0, sizeof(struct fc_els_cmd_s));
els_cmd->els_code = FC_ELS_ACC;
- return (sizeof(struct fc_els_cmd_s));
+ return sizeof(struct fc_els_cmd_s);
}
int
@@ -696,7 +696,7 @@ fc_tprlo_acc_build(struct fchs_s *fchs, struct fc_tprlo_acc_s *tprlo_acc,
tprlo_acc->tprlo_acc_params[page].orig_process_assc = 0;
tprlo_acc->tprlo_acc_params[page].resp_process_assc = 0;
}
- return (bfa_os_ntohs(tprlo_acc->payload_len));
+ return bfa_os_ntohs(tprlo_acc->payload_len);
}
u16
@@ -721,7 +721,7 @@ fc_prlo_acc_build(struct fchs_s *fchs, struct fc_prlo_acc_s *prlo_acc,
prlo_acc->prlo_acc_params[page].resp_process_assc = 0;
}
- return (bfa_os_ntohs(prlo_acc->payload_len));
+ return bfa_os_ntohs(prlo_acc->payload_len);
}
u16
@@ -735,7 +735,7 @@ fc_rnid_build(struct fchs_s *fchs, struct fc_rnid_cmd_s *rnid, u32 d_id,
rnid->els_cmd.els_code = FC_ELS_RNID;
rnid->node_id_data_format = data_format;
- return (sizeof(struct fc_rnid_cmd_s));
+ return sizeof(struct fc_rnid_cmd_s);
}
u16
@@ -759,10 +759,10 @@ fc_rnid_acc_build(struct fchs_s *fchs, struct fc_rnid_acc_s *rnid_acc,
rnid_acc->specific_id_data_length =
sizeof(struct fc_rnid_general_topology_data_s);
bfa_os_assign(rnid_acc->gen_topology_data, *gen_topo_data);
- return (sizeof(struct fc_rnid_acc_s));
+ return sizeof(struct fc_rnid_acc_s);
} else {
- return (sizeof(struct fc_rnid_acc_s) -
- sizeof(struct fc_rnid_general_topology_data_s));
+ return sizeof(struct fc_rnid_acc_s) -
+ sizeof(struct fc_rnid_general_topology_data_s);
}
}
@@ -776,7 +776,7 @@ fc_rpsc_build(struct fchs_s *fchs, struct fc_rpsc_cmd_s *rpsc, u32 d_id,
memset(rpsc, 0, sizeof(struct fc_rpsc_cmd_s));
rpsc->els_cmd.els_code = FC_ELS_RPSC;
- return (sizeof(struct fc_rpsc_cmd_s));
+ return sizeof(struct fc_rpsc_cmd_s);
}
u16
@@ -797,8 +797,8 @@ fc_rpsc2_build(struct fchs_s *fchs, struct fc_rpsc2_cmd_s *rpsc2,
for (i = 0; i < npids; i++)
rpsc2->pid_list[i].pid = pid_list[i];
- return (sizeof(struct fc_rpsc2_cmd_s) + ((npids - 1) *
- (sizeof(u32))));
+ return sizeof(struct fc_rpsc2_cmd_s) + ((npids - 1) *
+ (sizeof(u32)));
}
u16
@@ -819,7 +819,7 @@ fc_rpsc_acc_build(struct fchs_s *fchs, struct fc_rpsc_acc_s *rpsc_acc,
rpsc_acc->speed_info[0].port_op_speed =
bfa_os_htons(oper_speed->port_op_speed);
- return (sizeof(struct fc_rpsc_acc_s));
+ return sizeof(struct fc_rpsc_acc_s);
}
@@ -856,7 +856,7 @@ fc_pdisc_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
pdisc->port_name = port_name;
pdisc->node_name = node_name;
- return (sizeof(struct fc_logi_s));
+ return sizeof(struct fc_logi_s);
}
u16
@@ -865,21 +865,21 @@ fc_pdisc_rsp_parse(struct fchs_s *fchs, int len, wwn_t port_name)
struct fc_logi_s *pdisc = (struct fc_logi_s *) (fchs + 1);
if (len < sizeof(struct fc_logi_s))
- return (FC_PARSE_LEN_INVAL);
+ return FC_PARSE_LEN_INVAL;
if (pdisc->els_cmd.els_code != FC_ELS_ACC)
- return (FC_PARSE_ACC_INVAL);
+ return FC_PARSE_ACC_INVAL;
if (!wwn_is_equal(pdisc->port_name, port_name))
- return (FC_PARSE_PWWN_NOT_EQUAL);
+ return FC_PARSE_PWWN_NOT_EQUAL;
if (!pdisc->class3.class_valid)
- return (FC_PARSE_NWWN_NOT_EQUAL);
+ return FC_PARSE_NWWN_NOT_EQUAL;
if (bfa_os_ntohs(pdisc->class3.rxsz) < (FC_MIN_PDUSZ))
- return (FC_PARSE_RXSZ_INVAL);
+ return FC_PARSE_RXSZ_INVAL;
- return (FC_PARSE_OK);
+ return FC_PARSE_OK;
}
u16
@@ -903,7 +903,7 @@ fc_prlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id,
prlo->prlo_params[page].resp_process_assc = 0;
}
- return (bfa_os_ntohs(prlo->payload_len));
+ return bfa_os_ntohs(prlo->payload_len);
}
u16
@@ -916,7 +916,7 @@ fc_prlo_rsp_parse(struct fchs_s *fchs, int len)
len = len;
if (prlo->command != FC_ELS_ACC)
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
num_pages = ((bfa_os_ntohs(prlo->payload_len)) - 4) / 16;
@@ -936,7 +936,7 @@ fc_prlo_rsp_parse(struct fchs_s *fchs, int len)
if (prlo->prlo_acc_params[page].resp_process_assc != 0)
return FC_PARSE_FAILURE;
}
- return (FC_PARSE_OK);
+ return FC_PARSE_OK;
}
@@ -968,7 +968,7 @@ fc_tprlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
}
}
- return (bfa_os_ntohs(tprlo->payload_len));
+ return bfa_os_ntohs(tprlo->payload_len);
}
u16
@@ -981,23 +981,23 @@ fc_tprlo_rsp_parse(struct fchs_s *fchs, int len)
len = len;
if (tprlo->command != FC_ELS_ACC)
- return (FC_PARSE_ACC_INVAL);
+ return FC_PARSE_ACC_INVAL;
num_pages = (bfa_os_ntohs(tprlo->payload_len) - 4) / 16;
for (page = 0; page < num_pages; page++) {
if (tprlo->tprlo_acc_params[page].type != FC_TYPE_FCP)
- return (FC_PARSE_NOT_FCP);
+ return FC_PARSE_NOT_FCP;
if (tprlo->tprlo_acc_params[page].opa_valid != 0)
- return (FC_PARSE_OPAFLAG_INVAL);
+ return FC_PARSE_OPAFLAG_INVAL;
if (tprlo->tprlo_acc_params[page].rpa_valid != 0)
- return (FC_PARSE_RPAFLAG_INVAL);
+ return FC_PARSE_RPAFLAG_INVAL;
if (tprlo->tprlo_acc_params[page].orig_process_assc != 0)
- return (FC_PARSE_OPA_INVAL);
+ return FC_PARSE_OPA_INVAL;
if (tprlo->tprlo_acc_params[page].resp_process_assc != 0)
- return (FC_PARSE_RPA_INVAL);
+ return FC_PARSE_RPA_INVAL;
}
- return (FC_PARSE_OK);
+ return FC_PARSE_OK;
}
enum fc_parse_status
@@ -1024,7 +1024,7 @@ fc_ba_rjt_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
fchs->cat_info = FC_CAT_BA_RJT;
ba_rjt->reason_code = reason_code;
ba_rjt->reason_expl = reason_expl;
- return (sizeof(struct fc_ba_rjt_s));
+ return sizeof(struct fc_ba_rjt_s);
}
static void
@@ -1073,7 +1073,7 @@ fc_gidpn_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
bfa_os_memset(gidpn, 0, sizeof(struct fcgs_gidpn_req_s));
gidpn->port_name = port_name;
- return (sizeof(struct fcgs_gidpn_req_s) + sizeof(struct ct_hdr_s));
+ return sizeof(struct fcgs_gidpn_req_s) + sizeof(struct ct_hdr_s);
}
u16
@@ -1090,7 +1090,7 @@ fc_gpnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
bfa_os_memset(gpnid, 0, sizeof(fcgs_gpnid_req_t));
gpnid->dap = port_id;
- return (sizeof(fcgs_gpnid_req_t) + sizeof(struct ct_hdr_s));
+ return sizeof(fcgs_gpnid_req_t) + sizeof(struct ct_hdr_s);
}
u16
@@ -1107,7 +1107,7 @@ fc_gnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
bfa_os_memset(gnnid, 0, sizeof(fcgs_gnnid_req_t));
gnnid->dap = port_id;
- return (sizeof(fcgs_gnnid_req_t) + sizeof(struct ct_hdr_s));
+ return sizeof(fcgs_gnnid_req_t) + sizeof(struct ct_hdr_s);
}
u16
@@ -1137,7 +1137,7 @@ fc_scr_build(struct fchs_s *fchs, struct fc_scr_s *scr, u8 set_br_reg,
if (set_br_reg)
scr->vu_reg_func = FC_VU_SCR_REG_FUNC_FABRIC_NAME_CHANGE;
- return (sizeof(struct fc_scr_s));
+ return sizeof(struct fc_scr_s);
}
u16
@@ -1157,7 +1157,7 @@ fc_rscn_build(struct fchs_s *fchs, struct fc_rscn_pl_s *rscn, u32 s_id,
rscn->event[0].format = FC_RSCN_FORMAT_PORTID;
rscn->event[0].portid = s_id;
- return (sizeof(struct fc_rscn_pl_s));
+ return sizeof(struct fc_rscn_pl_s);
}
u16
@@ -1188,7 +1188,7 @@ fc_rftid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
rftid->fc4_type[index] |= bfa_os_htonl(type_value);
}
- return (sizeof(struct fcgs_rftid_req_s) + sizeof(struct ct_hdr_s));
+ return sizeof(struct fcgs_rftid_req_s) + sizeof(struct ct_hdr_s);
}
u16
@@ -1210,7 +1210,7 @@ fc_rftid_build_sol(struct fchs_s *fchs, void *pyld, u32 s_id,
bfa_os_memcpy((void *)rftid->fc4_type, (void *)fc4_bitmap,
(bitmap_size < 32 ? bitmap_size : 32));
- return (sizeof(struct fcgs_rftid_req_s) + sizeof(struct ct_hdr_s));
+ return sizeof(struct fcgs_rftid_req_s) + sizeof(struct ct_hdr_s);
}
u16
@@ -1231,7 +1231,7 @@ fc_rffid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
rffid->fc4ftr_bits = fc4_ftrs;
rffid->fc4_type = fc4_type;
- return (sizeof(struct fcgs_rffid_req_s) + sizeof(struct ct_hdr_s));
+ return sizeof(struct fcgs_rffid_req_s) + sizeof(struct ct_hdr_s);
}
u16
@@ -1253,7 +1253,7 @@ fc_rspnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
rspnid->spn_len = (u8) strlen((char *)name);
strncpy((char *)rspnid->spn, (char *)name, rspnid->spn_len);
- return (sizeof(struct fcgs_rspnid_req_s) + sizeof(struct ct_hdr_s));
+ return sizeof(struct fcgs_rspnid_req_s) + sizeof(struct ct_hdr_s);
}
u16
@@ -1275,7 +1275,7 @@ fc_gid_ft_build(struct fchs_s *fchs, void *pyld, u32 s_id,
gidft->domain_id = 0;
gidft->area_id = 0;
- return (sizeof(struct fcgs_gidft_req_s) + sizeof(struct ct_hdr_s));
+ return sizeof(struct fcgs_gidft_req_s) + sizeof(struct ct_hdr_s);
}
u16
@@ -1294,7 +1294,7 @@ fc_rpnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id,
rpnid->port_id = port_id;
rpnid->port_name = port_name;
- return (sizeof(struct fcgs_rpnid_req_s) + sizeof(struct ct_hdr_s));
+ return sizeof(struct fcgs_rpnid_req_s) + sizeof(struct ct_hdr_s);
}
u16
@@ -1313,7 +1313,7 @@ fc_rnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id,
rnnid->port_id = port_id;
rnnid->node_name = node_name;
- return (sizeof(struct fcgs_rnnid_req_s) + sizeof(struct ct_hdr_s));
+ return sizeof(struct fcgs_rnnid_req_s) + sizeof(struct ct_hdr_s);
}
u16
@@ -1332,7 +1332,7 @@ fc_rcsid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id,
rcsid->port_id = port_id;
rcsid->cos = cos;
- return (sizeof(struct fcgs_rcsid_req_s) + sizeof(struct ct_hdr_s));
+ return sizeof(struct fcgs_rcsid_req_s) + sizeof(struct ct_hdr_s);
}
u16
@@ -1351,7 +1351,7 @@ fc_rptid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id,
rptid->port_id = port_id;
rptid->port_type = port_type;
- return (sizeof(struct fcgs_rptid_req_s) + sizeof(struct ct_hdr_s));
+ return sizeof(struct fcgs_rptid_req_s) + sizeof(struct ct_hdr_s);
}
u16
@@ -1368,7 +1368,7 @@ fc_ganxt_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id)
bfa_os_memset(ganxt, 0, sizeof(struct fcgs_ganxt_req_s));
ganxt->port_id = port_id;
- return (sizeof(struct ct_hdr_s) + sizeof(struct fcgs_ganxt_req_s));
+ return sizeof(struct ct_hdr_s) + sizeof(struct fcgs_ganxt_req_s);
}
/*
@@ -1385,7 +1385,7 @@ fc_fdmi_reqhdr_build(struct fchs_s *fchs, void *pyld, u32 s_id,
fc_gs_fchdr_build(fchs, d_id, s_id, 0);
fc_gs_fdmi_cthdr_build(cthdr, s_id, cmd_code);
- return (sizeof(struct ct_hdr_s));
+ return sizeof(struct ct_hdr_s);
}
/*
@@ -1425,7 +1425,7 @@ fc_gmal_req_build(struct fchs_s *fchs, void *pyld, u32 s_id, wwn_t wwn)
bfa_os_memset(gmal, 0, sizeof(fcgs_gmal_req_t));
gmal->wwn = wwn;
- return (sizeof(struct ct_hdr_s) + sizeof(fcgs_gmal_req_t));
+ return sizeof(struct ct_hdr_s) + sizeof(fcgs_gmal_req_t);
}
/*
@@ -1445,5 +1445,5 @@ fc_gfn_req_build(struct fchs_s *fchs, void *pyld, u32 s_id, wwn_t wwn)
bfa_os_memset(gfn, 0, sizeof(fcgs_gfn_req_t));
gfn->wwn = wwn;
- return (sizeof(struct ct_hdr_s) + sizeof(fcgs_gfn_req_t));
+ return sizeof(struct ct_hdr_s) + sizeof(fcgs_gfn_req_t);
}
diff --git a/drivers/scsi/bfa/fcbuild.h b/drivers/scsi/bfa/fcbuild.h
index 4d24842..8fa7f27 100644
--- a/drivers/scsi/bfa/fcbuild.h
+++ b/drivers/scsi/bfa/fcbuild.h
@@ -32,8 +32,8 @@
* Utility Macros/functions
*/
-#define fcif_sof_set(_ifhdr, _sof) (_ifhdr)->sof = FC_ ## _sof
-#define fcif_eof_set(_ifhdr, _eof) (_ifhdr)->eof = FC_ ## _eof
+#define fcif_sof_set(_ifhdr, _sof) ((_ifhdr)->sof = FC_ ## _sof)
+#define fcif_eof_set(_ifhdr, _eof) ((_ifhdr)->eof = FC_ ## _eof)
#define wwn_is_equal(_wwn1, _wwn2) \
(memcmp(&(_wwn1), &(_wwn2), sizeof(wwn_t)) == 0)
@@ -49,7 +49,7 @@
static inline u32
fc_get_ctresp_pyld_len(u32 resp_len)
{
- return (resp_len - sizeof(struct ct_hdr_s));
+ return resp_len - sizeof(struct ct_hdr_s);
}
/*
diff --git a/drivers/scsi/bfa/fcpim.c b/drivers/scsi/bfa/fcpim.c
index 8ce5d893..1f3c06e 100644
--- a/drivers/scsi/bfa/fcpim.c
+++ b/drivers/scsi/bfa/fcpim.c
@@ -286,11 +286,10 @@ bfa_fcs_itnim_sm_online(struct bfa_fcs_itnim_s *itnim,
bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_hcb_offline);
bfa_fcb_itnim_offline(itnim->itnim_drv);
bfa_itnim_offline(itnim->bfa_itnim);
- if (bfa_fcs_port_is_online(itnim->rport->port) == BFA_TRUE) {
+ if (bfa_fcs_port_is_online(itnim->rport->port) == BFA_TRUE)
bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_DISCONNECT);
- } else {
+ else
bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_OFFLINE);
- }
break;
case BFA_FCS_ITNIM_SM_DELETE:
@@ -732,7 +731,7 @@ bfa_fcs_itnim_lookup(struct bfa_fcs_port_s *port, wwn_t rpwwn)
return NULL;
bfa_assert(rport->itnim != NULL);
- return (rport->itnim);
+ return rport->itnim;
}
bfa_status_t
diff --git a/drivers/scsi/bfa/fcs.h b/drivers/scsi/bfa/fcs.h
index deee685..8d08230 100644
--- a/drivers/scsi/bfa/fcs.h
+++ b/drivers/scsi/bfa/fcs.h
@@ -23,7 +23,7 @@
#ifndef __FCS_H__
#define __FCS_H__
-#define __fcs_min_cfg(__fcs) (__fcs)->min_cfg
+#define __fcs_min_cfg(__fcs) ((__fcs)->min_cfg)
void bfa_fcs_modexit_comp(struct bfa_fcs_s *fcs);
diff --git a/drivers/scsi/bfa/fdmi.c b/drivers/scsi/bfa/fdmi.c
index b845eb2..df2a1e5 100644
--- a/drivers/scsi/bfa/fdmi.c
+++ b/drivers/scsi/bfa/fdmi.c
@@ -72,9 +72,9 @@ static u16 bfa_fcs_port_fdmi_build_rpa_pyld(
struct bfa_fcs_port_fdmi_s *fdmi, u8 *pyld);
static u16 bfa_fcs_port_fdmi_build_portattr_block(
struct bfa_fcs_port_fdmi_s *fdmi, u8 *pyld);
-void bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_port_fdmi_s *fdmi,
+static void bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_port_fdmi_s *fdmi,
struct bfa_fcs_fdmi_hba_attr_s *hba_attr);
-void bfa_fcs_fdmi_get_portattr(struct bfa_fcs_port_fdmi_s *fdmi,
+static void bfa_fcs_fdmi_get_portattr(struct bfa_fcs_port_fdmi_s *fdmi,
struct bfa_fcs_fdmi_port_attr_s *port_attr);
/**
* fcs_fdmi_sm FCS FDMI state machine
@@ -1091,7 +1091,7 @@ bfa_fcs_port_fdmi_timeout(void *arg)
bfa_sm_send_event(fdmi, FDMISM_EVENT_TIMEOUT);
}
-void
+static void
bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_port_fdmi_s *fdmi,
struct bfa_fcs_fdmi_hba_attr_s *hba_attr)
{
@@ -1145,7 +1145,7 @@ bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_port_fdmi_s *fdmi,
}
-void
+static void
bfa_fcs_fdmi_get_portattr(struct bfa_fcs_port_fdmi_s *fdmi,
struct bfa_fcs_fdmi_port_attr_s *port_attr)
{
diff --git a/drivers/scsi/bfa/include/aen/bfa_aen.h b/drivers/scsi/bfa/include/aen/bfa_aen.h
index da8cac0..d9cbc2a 100644
--- a/drivers/scsi/bfa/include/aen/bfa_aen.h
+++ b/drivers/scsi/bfa/include/aen/bfa_aen.h
@@ -54,7 +54,7 @@ bfa_aen_get_max_cfg_entry(void)
static inline s32
bfa_aen_get_meminfo(void)
{
- return (sizeof(struct bfa_aen_entry_s) * bfa_aen_get_max_cfg_entry());
+ return sizeof(struct bfa_aen_entry_s) * bfa_aen_get_max_cfg_entry();
}
static inline s32
diff --git a/drivers/scsi/bfa/include/bfa.h b/drivers/scsi/bfa/include/bfa.h
index 64c1412..d4bc0d9 100644
--- a/drivers/scsi/bfa/include/bfa.h
+++ b/drivers/scsi/bfa/include/bfa.h
@@ -76,11 +76,11 @@ struct bfa_meminfo_s {
struct bfa_mem_elem_s meminfo[BFA_MEM_TYPE_MAX];
};
#define bfa_meminfo_kva(_m) \
- (_m)->meminfo[BFA_MEM_TYPE_KVA - 1].kva_curp
+ ((_m)->meminfo[BFA_MEM_TYPE_KVA - 1].kva_curp)
#define bfa_meminfo_dma_virt(_m) \
- (_m)->meminfo[BFA_MEM_TYPE_DMA - 1].kva_curp
+ ((_m)->meminfo[BFA_MEM_TYPE_DMA - 1].kva_curp)
#define bfa_meminfo_dma_phys(_m) \
- (_m)->meminfo[BFA_MEM_TYPE_DMA - 1].dma_curp
+ ((_m)->meminfo[BFA_MEM_TYPE_DMA - 1].dma_curp)
/**
* Generic Scatter Gather Element used by driver
@@ -100,7 +100,7 @@ struct bfa_sge_s {
/*
* bfa stats interfaces
*/
-#define bfa_stats(_mod, _stats) (_mod)->stats._stats ++
+#define bfa_stats(_mod, _stats) ((_mod)->stats._stats++)
#define bfa_ioc_get_stats(__bfa, __ioc_stats) \
bfa_ioc_fetch_stats(&(__bfa)->ioc, __ioc_stats)
@@ -136,7 +136,7 @@ void bfa_isr_enable(struct bfa_s *bfa);
void bfa_isr_disable(struct bfa_s *bfa);
void bfa_msix_getvecs(struct bfa_s *bfa, u32 *msix_vecs_bmap,
u32 *num_vecs, u32 *max_vec_bit);
-#define bfa_msix(__bfa, __vec) (__bfa)->msix.handler[__vec](__bfa, __vec)
+#define bfa_msix(__bfa, __vec) ((__bfa)->msix.handler[__vec](__bfa, __vec))
void bfa_comp_deq(struct bfa_s *bfa, struct list_head *comp_q);
void bfa_comp_process(struct bfa_s *bfa, struct list_head *comp_q);
diff --git a/drivers/scsi/bfa/include/bfa_svc.h b/drivers/scsi/bfa/include/bfa_svc.h
index 0c80b74..268d956 100644
--- a/drivers/scsi/bfa/include/bfa_svc.h
+++ b/drivers/scsi/bfa/include/bfa_svc.h
@@ -34,10 +34,10 @@ struct bfa_fcxp_s;
*/
struct bfa_rport_info_s {
u16 max_frmsz; /* max rcv pdu size */
- u32 pid : 24, /* remote port ID */
- lp_tag : 8;
- u32 local_pid : 24, /* local port ID */
- cisc : 8; /* CIRO supported */
+ u32 pid:24, /* remote port ID */
+ lp_tag:8;
+ u32 local_pid:24, /* local port ID */
+ cisc:8; /* CIRO supported */
u8 fc_class; /* supported FC classes. enum fc_cos */
u8 vf_en; /* virtual fabric enable */
u16 vf_id; /* virtual fabric ID */
diff --git a/drivers/scsi/bfa/include/bfi/bfi.h b/drivers/scsi/bfa/include/bfi/bfi.h
index 6cadfe0..7042c18 100644
--- a/drivers/scsi/bfa/include/bfi/bfi.h
+++ b/drivers/scsi/bfa/include/bfi/bfi.h
@@ -93,13 +93,13 @@ union bfi_addr_u {
*/
struct bfi_sge_s {
#ifdef __BIGENDIAN
- u32 flags : 2,
- rsvd : 2,
- sg_len : 28;
+ u32 flags:2,
+ rsvd:2,
+ sg_len:28;
#else
- u32 sg_len : 28,
- rsvd : 2,
- flags : 2;
+ u32 sg_len:28,
+ rsvd:2,
+ flags:2;
#endif
union bfi_addr_u sga;
};
diff --git a/drivers/scsi/bfa/include/bfi/bfi_ioc.h b/drivers/scsi/bfa/include/bfi/bfi_ioc.h
index 026e9c0..96ef056 100644
--- a/drivers/scsi/bfa/include/bfi/bfi_ioc.h
+++ b/drivers/scsi/bfa/include/bfi/bfi_ioc.h
@@ -142,7 +142,7 @@ enum {
BFI_ADAPTER_UNSUPP = 0x400000, /* unknown adapter type */
};
-#define BFI_ADAPTER_GETP(__prop,__adap_prop) \
+#define BFI_ADAPTER_GETP(__prop, __adap_prop) \
(((__adap_prop) & BFI_ADAPTER_ ## __prop ## _MK) >> \
BFI_ADAPTER_ ## __prop ## _SH)
#define BFI_ADAPTER_SETP(__prop, __val) \
diff --git a/drivers/scsi/bfa/include/bfi/bfi_lps.h b/drivers/scsi/bfa/include/bfi/bfi_lps.h
index 414b0e3..c59d47b 100644
--- a/drivers/scsi/bfa/include/bfi/bfi_lps.h
+++ b/drivers/scsi/bfa/include/bfi/bfi_lps.h
@@ -55,8 +55,8 @@ struct bfi_lps_login_rsp_s {
u16 bb_credit;
u8 f_port;
u8 npiv_en;
- u32 lp_pid : 24;
- u32 auth_req : 8;
+ u32 lp_pid:24;
+ u32 auth_req:8;
mac_t lp_mac;
mac_t fcf_mac;
u8 ext_status;
diff --git a/drivers/scsi/bfa/include/bfi/bfi_rport.h b/drivers/scsi/bfa/include/bfi/bfi_rport.h
index 3520f55..e1cd83b 100644
--- a/drivers/scsi/bfa/include/bfi/bfi_rport.h
+++ b/drivers/scsi/bfa/include/bfi/bfi_rport.h
@@ -38,10 +38,10 @@ struct bfi_rport_create_req_s {
struct bfi_mhdr_s mh; /* common msg header */
u16 bfa_handle; /* host rport handle */
u16 max_frmsz; /* max rcv pdu size */
- u32 pid : 24, /* remote port ID */
- lp_tag : 8; /* local port tag */
- u32 local_pid : 24, /* local port ID */
- cisc : 8;
+ u32 pid:24, /* remote port ID */
+ lp_tag:8; /* local port tag */
+ u32 local_pid:24, /* local port ID */
+ cisc:8;
u8 fc_class; /* supported FC classes */
u8 vf_en; /* virtual fabric enable */
u16 vf_id; /* virtual fabric ID */
diff --git a/drivers/scsi/bfa/include/cs/bfa_checksum.h b/drivers/scsi/bfa/include/cs/bfa_checksum.h
index af8c1d5..650f8d0 100644
--- a/drivers/scsi/bfa/include/cs/bfa_checksum.h
+++ b/drivers/scsi/bfa/include/cs/bfa_checksum.h
@@ -31,7 +31,7 @@ bfa_checksum_u32(u32 *buf, int sz)
for (i = 0; i < m; i++)
sum ^= buf[i];
- return (sum);
+ return sum;
}
static inline u16
@@ -43,7 +43,7 @@ bfa_checksum_u16(u16 *buf, int sz)
for (i = 0; i < m; i++)
sum ^= buf[i];
- return (sum);
+ return sum;
}
static inline u8
@@ -55,6 +55,6 @@ bfa_checksum_u8(u8 *buf, int sz)
for (i = 0; i < sz; i++)
sum ^= buf[i];
- return (sum);
+ return sum;
}
#endif
diff --git a/drivers/scsi/bfa/include/cs/bfa_sm.h b/drivers/scsi/bfa/include/cs/bfa_sm.h
index 9877066..b0a92ba 100644
--- a/drivers/scsi/bfa/include/cs/bfa_sm.h
+++ b/drivers/scsi/bfa/include/cs/bfa_sm.h
@@ -24,8 +24,8 @@
typedef void (*bfa_sm_t)(void *sm, int event);
-#define bfa_sm_set_state(_sm, _state) (_sm)->sm = (bfa_sm_t)(_state)
-#define bfa_sm_send_event(_sm, _event) (_sm)->sm((_sm), (_event))
+#define bfa_sm_set_state(_sm, _state) ((_sm)->sm = (bfa_sm_t)(_state))
+#define bfa_sm_send_event(_sm, _event) ((_sm)->sm((_sm), (_event)))
#define bfa_sm_get_state(_sm) ((_sm)->sm)
#define bfa_sm_cmp_state(_sm, _state) ((_sm)->sm == (bfa_sm_t)(_state))
@@ -62,7 +62,7 @@ typedef void (*bfa_fsm_t)(void *fsm, int event);
} while (0)
#define bfa_fsm_send_event(_fsm, _event) \
- (_fsm)->fsm((_fsm), (_event))
+ ((_fsm)->fsm((_fsm), (_event)))
#define bfa_fsm_cmp_state(_fsm, _state) \
((_fsm)->fsm == (bfa_fsm_t)(_state))
diff --git a/drivers/scsi/bfa/include/cs/bfa_trc.h b/drivers/scsi/bfa/include/cs/bfa_trc.h
index 3e74392..310771c 100644
--- a/drivers/scsi/bfa/include/cs/bfa_trc.h
+++ b/drivers/scsi/bfa/include/cs/bfa_trc.h
@@ -24,7 +24,7 @@
#endif
#ifndef BFA_TRC_TS
-#define BFA_TRC_TS(_trcm) ((_trcm)->ticks ++)
+#define BFA_TRC_TS(_trcm) ((_trcm)->ticks++)
#endif
struct bfa_trc_s {
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_pport.h b/drivers/scsi/bfa/include/defs/bfa_defs_pport.h
index a000bc4..bf32041 100644
--- a/drivers/scsi/bfa/include/defs/bfa_defs_pport.h
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_pport.h
@@ -61,7 +61,7 @@ enum bfa_pport_speed {
* Port operational type (in sync with SNIA port type).
*/
enum bfa_pport_type {
- BFA_PPORT_TYPE_UNKNOWN = 1, /* port type is unkown */
+ BFA_PPORT_TYPE_UNKNOWN = 1, /* port type is unknown */
BFA_PPORT_TYPE_TRUNKED = 2, /* Trunked mode */
BFA_PPORT_TYPE_NPORT = 5, /* P2P with switched fabric */
BFA_PPORT_TYPE_NLPORT = 6, /* public loop */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_tsensor.h b/drivers/scsi/bfa/include/defs/bfa_defs_tsensor.h
index 31881d2..ade763db 100644
--- a/drivers/scsi/bfa/include/defs/bfa_defs_tsensor.h
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_tsensor.h
@@ -25,7 +25,7 @@
* Temperature sensor status values
*/
enum bfa_tsensor_status {
- BFA_TSENSOR_STATUS_UNKNOWN = 1, /* unkown status */
+ BFA_TSENSOR_STATUS_UNKNOWN = 1, /* unknown status */
BFA_TSENSOR_STATUS_FAULTY = 2, /* sensor is faulty */
BFA_TSENSOR_STATUS_BELOW_MIN = 3, /* temperature below mininum */
BFA_TSENSOR_STATUS_NOMINAL = 4, /* normal temperature */
diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_fabric.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_fabric.h
index 4ffd224..08b79d5 100644
--- a/drivers/scsi/bfa/include/fcs/bfa_fcs_fabric.h
+++ b/drivers/scsi/bfa/include/fcs/bfa_fcs_fabric.h
@@ -75,7 +75,7 @@ struct bfa_fcs_fabric_s {
*/
};
-#define bfa_fcs_fabric_npiv_capable(__f) (__f)->is_npiv
+#define bfa_fcs_fabric_npiv_capable(__f) ((__f)->is_npiv)
#define bfa_fcs_fabric_is_switched(__f) \
((__f)->fab_type == BFA_FCS_FABRIC_SWITCHED)
diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_lport.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_lport.h
index b85cba8..967ceb0 100644
--- a/drivers/scsi/bfa/include/fcs/bfa_fcs_lport.h
+++ b/drivers/scsi/bfa/include/fcs/bfa_fcs_lport.h
@@ -125,12 +125,12 @@ union bfa_fcs_port_topo_u {
struct bfa_fcs_port_s {
struct list_head qe; /* used by port/vport */
bfa_sm_t sm; /* state machine */
- struct bfa_fcs_fabric_s *fabric; /* parent fabric */
- struct bfa_port_cfg_s port_cfg; /* port configuration */
+ struct bfa_fcs_fabric_s *fabric;/* parent fabric */
+ struct bfa_port_cfg_s port_cfg;/* port configuration */
struct bfa_timer_s link_timer; /* timer for link offline */
- u32 pid : 24; /* FC address */
- u8 lp_tag; /* lport tag */
- u16 num_rports; /* Num of r-ports */
+ u32 pid:24; /* FC address */
+ u8 lp_tag; /* lport tag */
+ u16 num_rports; /* Num of r-ports */
struct list_head rport_q; /* queue of discovered r-ports */
struct bfa_fcs_s *fcs; /* FCS instance */
union bfa_fcs_port_topo_u port_topo; /* fabric/loop/n2n details */
@@ -188,13 +188,14 @@ bfa_fcs_port_get_drvport(struct bfa_fcs_port_s *port)
}
-#define bfa_fcs_port_get_opertype(_lport) (_lport)->fabric->oper_type
+#define bfa_fcs_port_get_opertype(_lport) ((_lport)->fabric->oper_type)
-#define bfa_fcs_port_get_fabric_name(_lport) (_lport)->fabric->fabric_name
+#define bfa_fcs_port_get_fabric_name(_lport) ((_lport)->fabric->fabric_name)
-#define bfa_fcs_port_get_fabric_ipaddr(_lport) (_lport)->fabric->fabric_ip_addr
+#define bfa_fcs_port_get_fabric_ipaddr(_lport) \
+ ((_lport)->fabric->fabric_ip_addr)
/**
* bfa fcs port public functions
diff --git a/drivers/scsi/bfa/include/protocol/ct.h b/drivers/scsi/bfa/include/protocol/ct.h
index c59d663..b82540a 100644
--- a/drivers/scsi/bfa/include/protocol/ct.h
+++ b/drivers/scsi/bfa/include/protocol/ct.h
@@ -82,7 +82,7 @@ enum {
};
/*
- * defintions for CT reason code
+ * definitions for CT reason code
*/
enum {
CT_RSN_INV_CMD = 0x01,
@@ -129,7 +129,7 @@ enum {
};
/*
- * defintions for the explanation code for all servers
+ * definitions for the explanation code for all servers
*/
enum {
CT_EXP_AUTH_EXCEPTION = 0xF1,
@@ -193,11 +193,11 @@ struct fcgs_rftid_req_s {
#define FC_GS_FCP_FC4_FEATURE_TARGET 0x01
struct fcgs_rffid_req_s{
- u32 rsvd :8;
- u32 dap :24; /* port identifier */
- u32 rsvd1 :16;
- u32 fc4ftr_bits :8; /* fc4 feature bits */
- u32 fc4_type :8; /* corresponding FC4 Type */
+ u32 rsvd:8;
+ u32 dap:24; /* port identifier */
+ u32 rsvd1:16;
+ u32 fc4ftr_bits:8; /* fc4 feature bits */
+ u32 fc4_type:8; /* corresponding FC4 Type */
};
/**
diff --git a/drivers/scsi/bfa/include/protocol/fc.h b/drivers/scsi/bfa/include/protocol/fc.h
index 3e39ba5..14969ee 100644
--- a/drivers/scsi/bfa/include/protocol/fc.h
+++ b/drivers/scsi/bfa/include/protocol/fc.h
@@ -486,14 +486,14 @@ struct fc_rsi_s {
* see FC-PH-X table 113 & 115 for explanation also FCP table 8
*/
struct fc_prli_params_s{
- u32 reserved: 16;
+ u32 reserved:16;
#ifdef __BIGENDIAN
- u32 reserved1: 5;
- u32 rec_support : 1;
- u32 task_retry_id : 1;
- u32 retry : 1;
+ u32 reserved1:5;
+ u32 rec_support:1;
+ u32 task_retry_id:1;
+ u32 retry:1;
- u32 confirm : 1;
+ u32 confirm:1;
u32 doverlay:1;
u32 initiator:1;
u32 target:1;
@@ -502,10 +502,10 @@ struct fc_prli_params_s{
u32 rxrdisab:1;
u32 wxrdisab:1;
#else
- u32 retry : 1;
- u32 task_retry_id : 1;
- u32 rec_support : 1;
- u32 reserved1: 5;
+ u32 retry:1;
+ u32 task_retry_id:1;
+ u32 rec_support:1;
+ u32 reserved1:5;
u32 wxrdisab:1;
u32 rxrdisab:1;
@@ -514,7 +514,7 @@ struct fc_prli_params_s{
u32 target:1;
u32 initiator:1;
u32 doverlay:1;
- u32 confirm : 1;
+ u32 confirm:1;
#endif
};
diff --git a/drivers/scsi/bfa/loop.c b/drivers/scsi/bfa/loop.c
index a418ded..f7c7f4f 100644
--- a/drivers/scsi/bfa/loop.c
+++ b/drivers/scsi/bfa/loop.c
@@ -58,49 +58,16 @@ static const u8 port_loop_alpa_map[] = {
/*
* Local Functions
*/
-bfa_status_t bfa_fcs_port_loop_send_plogi(struct bfa_fcs_port_s *port,
- u8 alpa);
-
-void bfa_fcs_port_loop_plogi_response(void *fcsarg,
- struct bfa_fcxp_s *fcxp,
- void *cbarg,
- bfa_status_t req_status,
- u32 rsp_len,
- u32 resid_len,
- struct fchs_s *rsp_fchs);
-
-bfa_status_t bfa_fcs_port_loop_send_adisc(struct bfa_fcs_port_s *port,
- u8 alpa);
-
-void bfa_fcs_port_loop_adisc_response(void *fcsarg,
- struct bfa_fcxp_s *fcxp,
- void *cbarg,
- bfa_status_t req_status,
- u32 rsp_len,
- u32 resid_len,
- struct fchs_s *rsp_fchs);
-
-bfa_status_t bfa_fcs_port_loop_send_plogi_acc(struct bfa_fcs_port_s *port,
- u8 alpa);
-
-void bfa_fcs_port_loop_plogi_acc_response(void *fcsarg,
- struct bfa_fcxp_s *fcxp,
- void *cbarg,
- bfa_status_t req_status,
- u32 rsp_len,
- u32 resid_len,
- struct fchs_s *rsp_fchs);
-
-bfa_status_t bfa_fcs_port_loop_send_adisc_acc(struct bfa_fcs_port_s *port,
- u8 alpa);
-
-void bfa_fcs_port_loop_adisc_acc_response(void *fcsarg,
- struct bfa_fcxp_s *fcxp,
- void *cbarg,
- bfa_status_t req_status,
- u32 rsp_len,
- u32 resid_len,
- struct fchs_s *rsp_fchs);
+static bfa_status_t bfa_fcs_port_loop_send_plogi(struct bfa_fcs_port_s *port,
+ u8 alpa);
+
+static void bfa_fcs_port_loop_plogi_response(void *fcsarg,
+ struct bfa_fcxp_s *fcxp,
+ void *cbarg,
+ bfa_status_t req_status,
+ u32 rsp_len,
+ u32 resid_len,
+ struct fchs_s *rsp_fchs);
/**
* Called by port to initializar in provate LOOP topology.
*/
@@ -179,7 +146,7 @@ bfa_fcs_port_loop_lip(struct bfa_fcs_port_s *port)
/**
* Local Functions.
*/
-bfa_status_t
+static bfa_status_t
bfa_fcs_port_loop_send_plogi(struct bfa_fcs_port_s *port, u8 alpa)
{
struct fchs_s fchs;
@@ -208,7 +175,7 @@ bfa_fcs_port_loop_send_plogi(struct bfa_fcs_port_s *port, u8 alpa)
/**
* Called by fcxp to notify the Plogi response
*/
-void
+static void
bfa_fcs_port_loop_plogi_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
void *cbarg, bfa_status_t req_status,
u32 rsp_len, u32 resid_len,
@@ -244,179 +211,3 @@ bfa_fcs_port_loop_plogi_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
bfa_assert(0);
}
}
-
-bfa_status_t
-bfa_fcs_port_loop_send_plogi_acc(struct bfa_fcs_port_s *port, u8 alpa)
-{
- struct fchs_s fchs;
- struct bfa_fcxp_s *fcxp;
- int len;
-
- bfa_trc(port->fcs, alpa);
-
- fcxp = bfa_fcxp_alloc(NULL, port->fcs->bfa, 0, 0, NULL, NULL, NULL,
- NULL);
- bfa_assert(fcxp);
-
- len = fc_plogi_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), alpa,
- bfa_fcs_port_get_fcid(port), 0,
- port->port_cfg.pwwn, port->port_cfg.nwwn,
- bfa_pport_get_maxfrsize(port->fcs->bfa));
-
- bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
- FC_CLASS_3, len, &fchs,
- bfa_fcs_port_loop_plogi_acc_response,
- (void *)port, FC_MAX_PDUSZ, 0); /* No response
- * expected
- */
-
- return BFA_STATUS_OK;
-}
-
-/*
- * Plogi Acc Response
- * We donot do any processing here.
- */
-void
-bfa_fcs_port_loop_plogi_acc_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
- void *cbarg, bfa_status_t req_status,
- u32 rsp_len, u32 resid_len,
- struct fchs_s *rsp_fchs)
-{
-
- struct bfa_fcs_port_s *port = (struct bfa_fcs_port_s *) cbarg;
-
- bfa_trc(port->fcs, port->pid);
-
- /*
- * Sanity Checks
- */
- if (req_status != BFA_STATUS_OK) {
- bfa_trc(port->fcs, req_status);
- return;
- }
-}
-
-bfa_status_t
-bfa_fcs_port_loop_send_adisc(struct bfa_fcs_port_s *port, u8 alpa)
-{
- struct fchs_s fchs;
- struct bfa_fcxp_s *fcxp;
- int len;
-
- bfa_trc(port->fcs, alpa);
-
- fcxp = bfa_fcxp_alloc(NULL, port->fcs->bfa, 0, 0, NULL, NULL, NULL,
- NULL);
- bfa_assert(fcxp);
-
- len = fc_adisc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), alpa,
- bfa_fcs_port_get_fcid(port), 0,
- port->port_cfg.pwwn, port->port_cfg.nwwn);
-
- bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
- FC_CLASS_3, len, &fchs,
- bfa_fcs_port_loop_adisc_response, (void *)port,
- FC_MAX_PDUSZ, FC_RA_TOV);
-
- return BFA_STATUS_OK;
-}
-
-/**
- * Called by fcxp to notify the ADISC response
- */
-void
-bfa_fcs_port_loop_adisc_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
- void *cbarg, bfa_status_t req_status,
- u32 rsp_len, u32 resid_len,
- struct fchs_s *rsp_fchs)
-{
- struct bfa_fcs_port_s *port = (struct bfa_fcs_port_s *) cbarg;
- struct bfa_fcs_rport_s *rport;
- struct fc_adisc_s *adisc_resp;
- struct fc_els_cmd_s *els_cmd;
- u32 pid = rsp_fchs->s_id;
-
- bfa_trc(port->fcs, req_status);
-
- /*
- * Sanity Checks
- */
- if (req_status != BFA_STATUS_OK) {
- /*
- * TBD : we may need to retry certain requests
- */
- bfa_fcxp_free(fcxp);
- return;
- }
-
- els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp);
- adisc_resp = (struct fc_adisc_s *) els_cmd;
-
- if (els_cmd->els_code == FC_ELS_ACC) {
- } else {
- bfa_trc(port->fcs, adisc_resp->els_cmd.els_code);
-
- /*
- * TBD: we may need to check for reject codes and retry
- */
- rport = bfa_fcs_port_get_rport_by_pid(port, pid);
- if (rport) {
- list_del(&rport->qe);
- bfa_fcs_rport_delete(rport);
- }
-
- }
- return;
-}
-
-bfa_status_t
-bfa_fcs_port_loop_send_adisc_acc(struct bfa_fcs_port_s *port, u8 alpa)
-{
- struct fchs_s fchs;
- struct bfa_fcxp_s *fcxp;
- int len;
-
- bfa_trc(port->fcs, alpa);
-
- fcxp = bfa_fcxp_alloc(NULL, port->fcs->bfa, 0, 0, NULL, NULL, NULL,
- NULL);
- bfa_assert(fcxp);
-
- len = fc_adisc_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), alpa,
- bfa_fcs_port_get_fcid(port), 0,
- port->port_cfg.pwwn, port->port_cfg.nwwn);
-
- bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
- FC_CLASS_3, len, &fchs,
- bfa_fcs_port_loop_adisc_acc_response,
- (void *)port, FC_MAX_PDUSZ, 0); /* no reponse
- * expected
- */
-
- return BFA_STATUS_OK;
-}
-
-/*
- * Adisc Acc Response
- * We donot do any processing here.
- */
-void
-bfa_fcs_port_loop_adisc_acc_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
- void *cbarg, bfa_status_t req_status,
- u32 rsp_len, u32 resid_len,
- struct fchs_s *rsp_fchs)
-{
-
- struct bfa_fcs_port_s *port = (struct bfa_fcs_port_s *) cbarg;
-
- bfa_trc(port->fcs, port->pid);
-
- /*
- * Sanity Checks
- */
- if (req_status != BFA_STATUS_OK) {
- bfa_trc(port->fcs, req_status);
- return;
- }
-}
diff --git a/drivers/scsi/bfa/lport_api.c b/drivers/scsi/bfa/lport_api.c
index 8f51a83..1e06792 100644
--- a/drivers/scsi/bfa/lport_api.c
+++ b/drivers/scsi/bfa/lport_api.c
@@ -43,7 +43,7 @@ bfa_fcs_cfg_base_port(struct bfa_fcs_s *fcs, struct bfa_port_cfg_s *port_cfg)
struct bfa_fcs_port_s *
bfa_fcs_get_base_port(struct bfa_fcs_s *fcs)
{
- return (&fcs->fabric.bport);
+ return &fcs->fabric.bport;
}
wwn_t
@@ -88,11 +88,10 @@ bfa_fcs_port_get_rport(struct bfa_fcs_port_s *port, wwn_t wwn, int index,
}
bfa_trc(fcs, i);
- if (rport) {
+ if (rport)
return rport->pwwn;
- } else {
+ else
return (wwn_t) 0;
- }
}
void
@@ -198,17 +197,17 @@ bfa_fcs_lookup_port(struct bfa_fcs_s *fcs, u16 vf_id, wwn_t lpwwn)
vf = bfa_fcs_vf_lookup(fcs, vf_id);
if (vf == NULL) {
bfa_trc(fcs, vf_id);
- return (NULL);
+ return NULL;
}
if (!lpwwn || (vf->bport.port_cfg.pwwn == lpwwn))
- return (&vf->bport);
+ return &vf->bport;
vport = bfa_fcs_fabric_vport_lookup(vf, lpwwn);
if (vport)
- return (&vport->lport);
+ return &vport->lport;
- return (NULL);
+ return NULL;
}
/*
diff --git a/drivers/scsi/bfa/ns.c b/drivers/scsi/bfa/ns.c
index 59fea99..2f8b880 100644
--- a/drivers/scsi/bfa/ns.c
+++ b/drivers/scsi/bfa/ns.c
@@ -932,11 +932,10 @@ bfa_fcs_port_ns_send_rff_id(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced)
}
ns->fcxp = fcxp;
- if (BFA_FCS_VPORT_IS_INITIATOR_MODE(ns->port)) {
+ if (BFA_FCS_VPORT_IS_INITIATOR_MODE(ns->port))
fc4_ftrs = FC_GS_FCP_FC4_FEATURE_INITIATOR;
- } else if (BFA_FCS_VPORT_IS_TARGET_MODE(ns->port)) {
+ else if (BFA_FCS_VPORT_IS_TARGET_MODE(ns->port))
fc4_ftrs = FC_GS_FCP_FC4_FEATURE_TARGET;
- }
len = fc_rffid_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
bfa_fcs_port_get_fcid(port), 0, FC_TYPE_FCP,
diff --git a/drivers/scsi/bfa/plog.c b/drivers/scsi/bfa/plog.c
index 86af818..fcb8864 100644
--- a/drivers/scsi/bfa/plog.c
+++ b/drivers/scsi/bfa/plog.c
@@ -180,5 +180,5 @@ bfa_plog_disable(struct bfa_plog_s *plog)
bfa_boolean_t
bfa_plog_get_setting(struct bfa_plog_s *plog)
{
- return((bfa_boolean_t)plog->plog_enabled);
+ return (bfa_boolean_t)plog->plog_enabled;
}
diff --git a/drivers/scsi/bfa/rport_ftrs.c b/drivers/scsi/bfa/rport_ftrs.c
index 8a1f59d..e1932c8 100644
--- a/drivers/scsi/bfa/rport_ftrs.c
+++ b/drivers/scsi/bfa/rport_ftrs.c
@@ -79,7 +79,7 @@ bfa_fcs_rpf_sm_uninit(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
bfa_trc(rport->fcs, event);
switch (event) {
- case RPFSM_EVENT_RPORT_ONLINE :
+ case RPFSM_EVENT_RPORT_ONLINE:
if (!BFA_FCS_PID_IS_WKA(rport->pid)) {
bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc_sending);
rpf->rpsc_retries = 0;
@@ -87,7 +87,7 @@ bfa_fcs_rpf_sm_uninit(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
break;
};
- case RPFSM_EVENT_RPORT_OFFLINE :
+ case RPFSM_EVENT_RPORT_OFFLINE:
break;
default:
@@ -107,7 +107,7 @@ bfa_fcs_rpf_sm_rpsc_sending(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc);
break;
- case RPFSM_EVENT_RPORT_OFFLINE :
+ case RPFSM_EVENT_RPORT_OFFLINE:
bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_offline);
bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rpf->fcxp_wqe);
rpf->rpsc_retries = 0;
@@ -130,11 +130,10 @@ bfa_fcs_rpf_sm_rpsc(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
case RPFSM_EVENT_RPSC_COMP:
bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_online);
/* Update speed info in f/w via BFA */
- if (rpf->rpsc_speed != BFA_PPORT_SPEED_UNKNOWN) {
+ if (rpf->rpsc_speed != BFA_PPORT_SPEED_UNKNOWN)
bfa_rport_speed(rport->bfa_rport, rpf->rpsc_speed);
- } else if (rpf->assigned_speed != BFA_PPORT_SPEED_UNKNOWN) {
+ else if (rpf->assigned_speed != BFA_PPORT_SPEED_UNKNOWN)
bfa_rport_speed(rport->bfa_rport, rpf->assigned_speed);
- }
break;
case RPFSM_EVENT_RPSC_FAIL:
@@ -154,7 +153,7 @@ bfa_fcs_rpf_sm_rpsc(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
}
break;
- case RPFSM_EVENT_RPORT_OFFLINE :
+ case RPFSM_EVENT_RPORT_OFFLINE:
bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_offline);
bfa_fcxp_discard(rpf->fcxp);
rpf->rpsc_retries = 0;
@@ -174,13 +173,13 @@ bfa_fcs_rpf_sm_rpsc_retry(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
bfa_trc(rport->fcs, event);
switch (event) {
- case RPFSM_EVENT_TIMEOUT :
+ case RPFSM_EVENT_TIMEOUT:
/* re-send the RPSC */
bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc_sending);
bfa_fcs_rpf_send_rpsc2(rpf, NULL);
break;
- case RPFSM_EVENT_RPORT_OFFLINE :
+ case RPFSM_EVENT_RPORT_OFFLINE:
bfa_timer_stop(&rpf->timer);
bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_offline);
rpf->rpsc_retries = 0;
@@ -201,7 +200,7 @@ bfa_fcs_rpf_sm_online(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
bfa_trc(rport->fcs, event);
switch (event) {
- case RPFSM_EVENT_RPORT_OFFLINE :
+ case RPFSM_EVENT_RPORT_OFFLINE:
bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_offline);
rpf->rpsc_retries = 0;
break;
@@ -221,12 +220,12 @@ bfa_fcs_rpf_sm_offline(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
bfa_trc(rport->fcs, event);
switch (event) {
- case RPFSM_EVENT_RPORT_ONLINE :
+ case RPFSM_EVENT_RPORT_ONLINE:
bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc_sending);
bfa_fcs_rpf_send_rpsc2(rpf, NULL);
break;
- case RPFSM_EVENT_RPORT_OFFLINE :
+ case RPFSM_EVENT_RPORT_OFFLINE:
break;
default:
@@ -366,10 +365,9 @@ bfa_fcs_rpf_rpsc2_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg,
bfa_trc(rport->fcs, ls_rjt->reason_code);
bfa_trc(rport->fcs, ls_rjt->reason_code_expl);
rport->stats.rpsc_rejects++;
- if (ls_rjt->reason_code == FC_LS_RJT_RSN_CMD_NOT_SUPP) {
+ if (ls_rjt->reason_code == FC_LS_RJT_RSN_CMD_NOT_SUPP)
bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_FAIL);
- } else {
+ else
bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_ERROR);
- }
}
}
diff --git a/drivers/scsi/bfa/vfapi.c b/drivers/scsi/bfa/vfapi.c
index 31d81fe..391a479 100644
--- a/drivers/scsi/bfa/vfapi.c
+++ b/drivers/scsi/bfa/vfapi.c
@@ -189,7 +189,7 @@ bfa_fcs_vf_lookup(struct bfa_fcs_s *fcs, u16 vf_id)
{
bfa_trc(fcs, vf_id);
if (vf_id == FC_VF_ID_NULL)
- return (&fcs->fabric);
+ return &fcs->fabric;
/**
* @todo vf support
diff --git a/drivers/scsi/bfa/vport.c b/drivers/scsi/bfa/vport.c
index c10af06..e90f1e3 100644
--- a/drivers/scsi/bfa/vport.c
+++ b/drivers/scsi/bfa/vport.c
@@ -31,13 +31,13 @@
BFA_TRC_FILE(FCS, VPORT);
-#define __vport_fcs(__vp) (__vp)->lport.fcs
-#define __vport_pwwn(__vp) (__vp)->lport.port_cfg.pwwn
-#define __vport_nwwn(__vp) (__vp)->lport.port_cfg.nwwn
-#define __vport_bfa(__vp) (__vp)->lport.fcs->bfa
-#define __vport_fcid(__vp) (__vp)->lport.pid
-#define __vport_fabric(__vp) (__vp)->lport.fabric
-#define __vport_vfid(__vp) (__vp)->lport.fabric->vf_id
+#define __vport_fcs(__vp) ((__vp)->lport.fcs)
+#define __vport_pwwn(__vp) ((__vp)->lport.port_cfg.pwwn)
+#define __vport_nwwn(__vp) ((__vp)->lport.port_cfg.nwwn)
+#define __vport_bfa(__vp) ((__vp)->lport.fcs->bfa)
+#define __vport_fcid(__vp) ((__vp)->lport.pid)
+#define __vport_fabric(__vp) ((__vp)->lport.fabric)
+#define __vport_vfid(__vp) ((__vp)->lport.fabric->vf_id)
#define BFA_FCS_VPORT_MAX_RETRIES 5
/*
@@ -641,9 +641,9 @@ bfa_fcs_vport_get_max(struct bfa_fcs_s *fcs)
bfa_get_attr(fcs->bfa, &ioc_attr);
if (ioc_attr.pci_attr.device_id == BFA_PCI_DEVICE_ID_CT)
- return (BFA_FCS_MAX_VPORTS_SUPP_CT);
+ return BFA_FCS_MAX_VPORTS_SUPP_CT;
else
- return (BFA_FCS_MAX_VPORTS_SUPP_CB);
+ return BFA_FCS_MAX_VPORTS_SUPP_CB;
}
@@ -675,7 +675,7 @@ bfa_fcs_vport_create(struct bfa_fcs_vport_s *vport, struct bfa_fcs_s *fcs,
struct bfad_vport_s *vport_drv)
{
if (vport_cfg->pwwn == 0)
- return (BFA_STATUS_INVALID_WWN);
+ return BFA_STATUS_INVALID_WWN;
if (bfa_fcs_port_get_pwwn(&fcs->fabric.bport) == vport_cfg->pwwn)
return BFA_STATUS_VPORT_WWN_BP;
diff --git a/drivers/scsi/bnx2i/bnx2i.h b/drivers/scsi/bnx2i/bnx2i.h
index 5edde1a..2b973f3 100644
--- a/drivers/scsi/bnx2i/bnx2i.h
+++ b/drivers/scsi/bnx2i/bnx2i.h
@@ -232,7 +232,6 @@ struct bnx2i_conn {
struct iscsi_cls_conn *cls_conn;
struct bnx2i_hba *hba;
struct completion cmd_cleanup_cmpl;
- int is_bound;
u32 iscsi_conn_cid;
#define BNX2I_CID_RESERVED 0x5AFF
diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c
index cafb888..132898c 100644
--- a/drivers/scsi/bnx2i/bnx2i_iscsi.c
+++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c
@@ -1161,9 +1161,6 @@ static int bnx2i_task_xmit(struct iscsi_task *task)
struct bnx2i_cmd *cmd = task->dd_data;
struct iscsi_cmd *hdr = (struct iscsi_cmd *) task->hdr;
- if (!bnx2i_conn->is_bound)
- return -ENOTCONN;
-
/*
* If there is no scsi_cmnd this must be a mgmt task
*/
@@ -1371,7 +1368,6 @@ static int bnx2i_conn_bind(struct iscsi_cls_session *cls_session,
bnx2i_conn->ep = bnx2i_ep;
bnx2i_conn->iscsi_conn_cid = bnx2i_ep->ep_iscsi_cid;
bnx2i_conn->fw_cid = bnx2i_ep->ep_cid;
- bnx2i_conn->is_bound = 1;
ret_code = bnx2i_bind_conn_to_iscsi_cid(hba, bnx2i_conn,
bnx2i_ep->ep_iscsi_cid);
@@ -1883,7 +1879,7 @@ static void bnx2i_ep_disconnect(struct iscsi_endpoint *ep)
bnx2i_ep = ep->dd_data;
- /* driver should not attempt connection cleanup untill TCP_CONNECT
+ /* driver should not attempt connection cleanup until TCP_CONNECT
* completes either successfully or fails. Timeout is 9-secs, so
* wait for it to complete
*/
@@ -1896,9 +1892,7 @@ static void bnx2i_ep_disconnect(struct iscsi_endpoint *ep)
conn = bnx2i_conn->cls_conn->dd_data;
session = conn->session;
- spin_lock_bh(&session->lock);
- bnx2i_conn->is_bound = 0;
- spin_unlock_bh(&session->lock);
+ iscsi_suspend_queue(conn);
}
hba = bnx2i_ep->hba;
@@ -2034,7 +2028,7 @@ struct iscsi_transport bnx2i_iscsi_transport = {
ISCSI_USERNAME | ISCSI_PASSWORD |
ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN |
ISCSI_FAST_ABORT | ISCSI_ABORT_TMO |
- ISCSI_LU_RESET_TMO |
+ ISCSI_LU_RESET_TMO | ISCSI_TGT_RESET_TMO |
ISCSI_PING_TMO | ISCSI_RECV_TMO |
ISCSI_IFACE_NAME | ISCSI_INITIATOR_NAME,
.host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_NETDEV_NAME,
diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c
index 63abb06..9129bcf 100644
--- a/drivers/scsi/constants.c
+++ b/drivers/scsi/constants.c
@@ -141,6 +141,7 @@ static const struct value_name_pair serv_out12_arr[] = {
static const struct value_name_pair serv_in16_arr[] = {
{0x10, "Read capacity(16)"},
{0x11, "Read long(16)"},
+ {0x12, "Get LBA status"},
};
#define SERV_IN16_SZ ARRAY_SIZE(serv_in16_arr)
diff --git a/drivers/scsi/cxgb3i/cxgb3i_iscsi.c b/drivers/scsi/cxgb3i/cxgb3i_iscsi.c
index 2631bdd..969c831 100644
--- a/drivers/scsi/cxgb3i/cxgb3i_iscsi.c
+++ b/drivers/scsi/cxgb3i/cxgb3i_iscsi.c
@@ -937,7 +937,7 @@ static struct iscsi_transport cxgb3i_iscsi_transport = {
ISCSI_USERNAME | ISCSI_PASSWORD |
ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN |
ISCSI_FAST_ABORT | ISCSI_ABORT_TMO |
- ISCSI_LU_RESET_TMO |
+ ISCSI_LU_RESET_TMO | ISCSI_TGT_RESET_TMO |
ISCSI_PING_TMO | ISCSI_RECV_TMO |
ISCSI_IFACE_NAME | ISCSI_INITIATOR_NAME,
.host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS |
diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c
index 075e239..6c59c02 100644
--- a/drivers/scsi/dc395x.c
+++ b/drivers/scsi/dc395x.c
@@ -1509,7 +1509,7 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb,
* Try anyway?
*
* We could, BUT: Sometimes the TRM_S1040 misses to produce a Selection
- * Timeout, a Disconnect or a Reselction IRQ, so we would be screwed!
+ * Timeout, a Disconnect or a Reselection IRQ, so we would be screwed!
* (This is likely to be a bug in the hardware. Obviously, most people
* only have one initiator per SCSI bus.)
* Instead let this fail and have the timer make sure the command is
diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c
index 3ee1cbc..e19a1a5 100644
--- a/drivers/scsi/device_handler/scsi_dh.c
+++ b/drivers/scsi/device_handler/scsi_dh.c
@@ -226,7 +226,7 @@ store_dh_state(struct device *dev, struct device_attribute *attr,
* Activate a device handler
*/
if (scsi_dh->activate)
- err = scsi_dh->activate(sdev);
+ err = scsi_dh->activate(sdev, NULL, NULL);
else
err = 0;
}
@@ -304,18 +304,15 @@ static int scsi_dh_notifier(struct notifier_block *nb,
sdev = to_scsi_device(dev);
if (action == BUS_NOTIFY_ADD_DEVICE) {
+ err = device_create_file(dev, &scsi_dh_state_attr);
+ /* don't care about err */
devinfo = device_handler_match(NULL, sdev);
- if (!devinfo)
- goto out;
-
- err = scsi_dh_handler_attach(sdev, devinfo);
- if (!err)
- err = device_create_file(dev, &scsi_dh_state_attr);
+ if (devinfo)
+ err = scsi_dh_handler_attach(sdev, devinfo);
} else if (action == BUS_NOTIFY_DEL_DEVICE) {
device_remove_file(dev, &scsi_dh_state_attr);
scsi_dh_handler_detach(sdev, NULL);
}
-out:
return err;
}
@@ -423,10 +420,17 @@ EXPORT_SYMBOL_GPL(scsi_unregister_device_handler);
/*
* scsi_dh_activate - activate the path associated with the scsi_device
* corresponding to the given request queue.
- * @q - Request queue that is associated with the scsi_device to be
- * activated.
+ * Returns immediately without waiting for activation to be completed.
+ * @q - Request queue that is associated with the scsi_device to be
+ * activated.
+ * @fn - Function to be called upon completion of the activation.
+ * Function fn is called with data (below) and the error code.
+ * Function fn may be called from the same calling context. So,
+ * do not hold the lock in the caller which may be needed in fn.
+ * @data - data passed to the function fn upon completion.
+ *
*/
-int scsi_dh_activate(struct request_queue *q)
+int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data)
{
int err = 0;
unsigned long flags;
@@ -445,7 +449,7 @@ int scsi_dh_activate(struct request_queue *q)
return err;
if (scsi_dh->activate)
- err = scsi_dh->activate(sdev);
+ err = scsi_dh->activate(sdev, fn, data);
put_device(&sdev->sdev_gendev);
return err;
}
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index b5cdefa..4f0d013 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -60,11 +60,17 @@ struct alua_dh_data {
int bufflen;
unsigned char sense[SCSI_SENSE_BUFFERSIZE];
int senselen;
+ struct scsi_device *sdev;
+ activate_complete callback_fn;
+ void *callback_data;
};
#define ALUA_POLICY_SWITCH_CURRENT 0
#define ALUA_POLICY_SWITCH_ALL 1
+static char print_alua_state(int);
+static int alua_check_sense(struct scsi_device *, struct scsi_sense_hdr *);
+
static inline struct alua_dh_data *get_alua_data(struct scsi_device *sdev)
{
struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data;
@@ -231,18 +237,71 @@ done:
}
/*
+ * alua_stpg - Evaluate SET TARGET GROUP STATES
+ * @sdev: the device to be evaluated
+ * @state: the new target group state
+ *
+ * Send a SET TARGET GROUP STATES command to the device.
+ * We only have to test here if we should resubmit the command;
+ * any other error is assumed as a failure.
+ */
+static void stpg_endio(struct request *req, int error)
+{
+ struct alua_dh_data *h = req->end_io_data;
+ struct scsi_sense_hdr sense_hdr;
+ unsigned err = SCSI_DH_IO;
+
+ if (error || host_byte(req->errors) != DID_OK ||
+ msg_byte(req->errors) != COMMAND_COMPLETE)
+ goto done;
+
+ if (err == SCSI_DH_IO && h->senselen > 0) {
+ err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
+ &sense_hdr);
+ if (!err) {
+ err = SCSI_DH_IO;
+ goto done;
+ }
+ err = alua_check_sense(h->sdev, &sense_hdr);
+ if (err == ADD_TO_MLQUEUE) {
+ err = SCSI_DH_RETRY;
+ goto done;
+ }
+ sdev_printk(KERN_INFO, h->sdev,
+ "%s: stpg sense code: %02x/%02x/%02x\n",
+ ALUA_DH_NAME, sense_hdr.sense_key,
+ sense_hdr.asc, sense_hdr.ascq);
+ err = SCSI_DH_IO;
+ }
+ if (err == SCSI_DH_OK) {
+ h->state = TPGS_STATE_OPTIMIZED;
+ sdev_printk(KERN_INFO, h->sdev,
+ "%s: port group %02x switched to state %c\n",
+ ALUA_DH_NAME, h->group_id,
+ print_alua_state(h->state));
+ }
+done:
+ blk_put_request(req);
+ if (h->callback_fn) {
+ h->callback_fn(h->callback_data, err);
+ h->callback_fn = h->callback_data = NULL;
+ }
+ return;
+}
+
+/*
* submit_stpg - Issue a SET TARGET GROUP STATES command
- * @sdev: sdev the command should be sent to
*
* Currently we're only setting the current target port group state
* to 'active/optimized' and let the array firmware figure out
* the states of the remaining groups.
*/
-static unsigned submit_stpg(struct scsi_device *sdev, struct alua_dh_data *h)
+static unsigned submit_stpg(struct alua_dh_data *h)
{
struct request *rq;
int err = SCSI_DH_RES_TEMP_UNAVAIL;
int stpg_len = 8;
+ struct scsi_device *sdev = h->sdev;
/* Prepare the data buffer */
memset(h->buff, 0, stpg_len);
@@ -252,7 +311,7 @@ static unsigned submit_stpg(struct scsi_device *sdev, struct alua_dh_data *h)
rq = get_alua_req(sdev, h->buff, stpg_len, WRITE);
if (!rq)
- goto done;
+ return SCSI_DH_RES_TEMP_UNAVAIL;
/* Prepare the command. */
rq->cmd[0] = MAINTENANCE_OUT;
@@ -266,17 +325,9 @@ static unsigned submit_stpg(struct scsi_device *sdev, struct alua_dh_data *h)
rq->sense = h->sense;
memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
rq->sense_len = h->senselen = 0;
+ rq->end_io_data = h;
- err = blk_execute_rq(rq->q, NULL, rq, 1);
- if (err == -EIO) {
- sdev_printk(KERN_INFO, sdev,
- "%s: stpg failed with %x\n",
- ALUA_DH_NAME, rq->errors);
- h->senselen = rq->sense_len;
- err = SCSI_DH_IO;
- }
- blk_put_request(rq);
-done:
+ blk_execute_rq_nowait(rq->q, NULL, rq, 1, stpg_endio);
return err;
}
@@ -477,50 +528,6 @@ static int alua_check_sense(struct scsi_device *sdev,
}
/*
- * alua_stpg - Evaluate SET TARGET GROUP STATES
- * @sdev: the device to be evaluated
- * @state: the new target group state
- *
- * Send a SET TARGET GROUP STATES command to the device.
- * We only have to test here if we should resubmit the command;
- * any other error is assumed as a failure.
- */
-static int alua_stpg(struct scsi_device *sdev, int state,
- struct alua_dh_data *h)
-{
- struct scsi_sense_hdr sense_hdr;
- unsigned err;
- int retry = ALUA_FAILOVER_RETRIES;
-
- retry:
- err = submit_stpg(sdev, h);
- if (err == SCSI_DH_IO && h->senselen > 0) {
- err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
- &sense_hdr);
- if (!err)
- return SCSI_DH_IO;
- err = alua_check_sense(sdev, &sense_hdr);
- if (retry > 0 && err == ADD_TO_MLQUEUE) {
- retry--;
- goto retry;
- }
- sdev_printk(KERN_INFO, sdev,
- "%s: stpg sense code: %02x/%02x/%02x\n",
- ALUA_DH_NAME, sense_hdr.sense_key,
- sense_hdr.asc, sense_hdr.ascq);
- err = SCSI_DH_IO;
- }
- if (err == SCSI_DH_OK) {
- h->state = state;
- sdev_printk(KERN_INFO, sdev,
- "%s: port group %02x switched to state %c\n",
- ALUA_DH_NAME, h->group_id,
- print_alua_state(h->state) );
- }
- return err;
-}
-
-/*
* alua_rtpg - Evaluate REPORT TARGET GROUP STATES
* @sdev: the device to be evaluated.
*
@@ -652,7 +659,8 @@ out:
* based on a certain policy. But until we actually encounter them it
* should be okay.
*/
-static int alua_activate(struct scsi_device *sdev)
+static int alua_activate(struct scsi_device *sdev,
+ activate_complete fn, void *data)
{
struct alua_dh_data *h = get_alua_data(sdev);
int err = SCSI_DH_OK;
@@ -663,11 +671,19 @@ static int alua_activate(struct scsi_device *sdev)
goto out;
}
- if (h->tpgs & TPGS_MODE_EXPLICIT && h->state != TPGS_STATE_OPTIMIZED)
- err = alua_stpg(sdev, TPGS_STATE_OPTIMIZED, h);
+ if (h->tpgs & TPGS_MODE_EXPLICIT && h->state != TPGS_STATE_OPTIMIZED) {
+ h->callback_fn = fn;
+ h->callback_data = data;
+ err = submit_stpg(h);
+ if (err == SCSI_DH_OK)
+ return 0;
+ h->callback_fn = h->callback_data = NULL;
+ }
out:
- return err;
+ if (fn)
+ fn(data, err);
+ return 0;
}
/*
@@ -745,6 +761,7 @@ static int alua_bus_attach(struct scsi_device *sdev)
h->rel_port = -1;
h->buff = h->inq;
h->bufflen = ALUA_INQUIRY_SIZE;
+ h->sdev = sdev;
err = alua_initialize(sdev, h);
if (err != SCSI_DH_OK)
diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c
index 0cffe84..61966750 100644
--- a/drivers/scsi/device_handler/scsi_dh_emc.c
+++ b/drivers/scsi/device_handler/scsi_dh_emc.c
@@ -528,7 +528,8 @@ retry:
return err;
}
-static int clariion_activate(struct scsi_device *sdev)
+static int clariion_activate(struct scsi_device *sdev,
+ activate_complete fn, void *data)
{
struct clariion_dh_data *csdev = get_clariion_data(sdev);
int result;
@@ -559,7 +560,9 @@ done:
csdev->port, lun_state[csdev->lun_state],
csdev->default_sp + 'A');
- return result;
+ if (fn)
+ fn(data, result);
+ return 0;
}
/*
* params - parameters in the following format
diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
index f7da753..857fdd6 100644
--- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c
+++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
@@ -39,8 +39,14 @@ struct hp_sw_dh_data {
unsigned char sense[SCSI_SENSE_BUFFERSIZE];
int path_state;
int retries;
+ int retry_cnt;
+ struct scsi_device *sdev;
+ activate_complete callback_fn;
+ void *callback_data;
};
+static int hp_sw_start_stop(struct hp_sw_dh_data *);
+
static inline struct hp_sw_dh_data *get_hp_sw_data(struct scsi_device *sdev)
{
struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data;
@@ -191,19 +197,53 @@ static int start_done(struct scsi_device *sdev, unsigned char *sense)
return rc;
}
+static void start_stop_endio(struct request *req, int error)
+{
+ struct hp_sw_dh_data *h = req->end_io_data;
+ unsigned err = SCSI_DH_OK;
+
+ if (error || host_byte(req->errors) != DID_OK ||
+ msg_byte(req->errors) != COMMAND_COMPLETE) {
+ sdev_printk(KERN_WARNING, h->sdev,
+ "%s: sending start_stop_unit failed with %x\n",
+ HP_SW_NAME, req->errors);
+ err = SCSI_DH_IO;
+ goto done;
+ }
+
+ if (req->sense_len > 0) {
+ err = start_done(h->sdev, h->sense);
+ if (err == SCSI_DH_RETRY) {
+ err = SCSI_DH_IO;
+ if (--h->retry_cnt) {
+ blk_put_request(req);
+ err = hp_sw_start_stop(h);
+ if (err == SCSI_DH_OK)
+ return;
+ }
+ }
+ }
+done:
+ blk_put_request(req);
+ if (h->callback_fn) {
+ h->callback_fn(h->callback_data, err);
+ h->callback_fn = h->callback_data = NULL;
+ }
+ return;
+
+}
+
/*
* hp_sw_start_stop - Send START STOP UNIT command
* @sdev: sdev command should be sent to
*
* Sending START STOP UNIT activates the SP.
*/
-static int hp_sw_start_stop(struct scsi_device *sdev, struct hp_sw_dh_data *h)
+static int hp_sw_start_stop(struct hp_sw_dh_data *h)
{
struct request *req;
- int ret, retry;
-retry:
- req = blk_get_request(sdev->request_queue, WRITE, GFP_NOIO);
+ req = blk_get_request(h->sdev->request_queue, WRITE, GFP_ATOMIC);
if (!req)
return SCSI_DH_RES_TEMP_UNAVAIL;
@@ -217,32 +257,10 @@ retry:
req->sense = h->sense;
memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE);
req->sense_len = 0;
- retry = h->retries;
-
- ret = blk_execute_rq(req->q, NULL, req, 1);
- if (ret == -EIO) {
- if (req->sense_len > 0) {
- ret = start_done(sdev, h->sense);
- } else {
- sdev_printk(KERN_WARNING, sdev,
- "%s: sending start_stop_unit failed with %x\n",
- HP_SW_NAME, req->errors);
- ret = SCSI_DH_IO;
- }
- } else
- ret = SCSI_DH_OK;
+ req->end_io_data = h;
- if (ret == SCSI_DH_RETRY) {
- if (--retry) {
- blk_put_request(req);
- goto retry;
- }
- ret = SCSI_DH_IO;
- }
-
- blk_put_request(req);
-
- return ret;
+ blk_execute_rq_nowait(req->q, NULL, req, 1, start_stop_endio);
+ return SCSI_DH_OK;
}
static int hp_sw_prep_fn(struct scsi_device *sdev, struct request *req)
@@ -268,7 +286,8 @@ static int hp_sw_prep_fn(struct scsi_device *sdev, struct request *req)
* activate the passive path (and deactivate the
* previously active one).
*/
-static int hp_sw_activate(struct scsi_device *sdev)
+static int hp_sw_activate(struct scsi_device *sdev,
+ activate_complete fn, void *data)
{
int ret = SCSI_DH_OK;
struct hp_sw_dh_data *h = get_hp_sw_data(sdev);
@@ -276,14 +295,18 @@ static int hp_sw_activate(struct scsi_device *sdev)
ret = hp_sw_tur(sdev, h);
if (ret == SCSI_DH_OK && h->path_state == HP_SW_PATH_PASSIVE) {
- ret = hp_sw_start_stop(sdev, h);
+ h->retry_cnt = h->retries;
+ h->callback_fn = fn;
+ h->callback_data = data;
+ ret = hp_sw_start_stop(h);
if (ret == SCSI_DH_OK)
- sdev_printk(KERN_INFO, sdev,
- "%s: activated path\n",
- HP_SW_NAME);
+ return 0;
+ h->callback_fn = h->callback_data = NULL;
}
- return ret;
+ if (fn)
+ fn(data, ret);
+ return 0;
}
static const struct scsi_dh_devlist hp_sw_dh_data_list[] = {
@@ -326,6 +349,7 @@ static int hp_sw_bus_attach(struct scsi_device *sdev)
h = (struct hp_sw_dh_data *) scsi_dh_data->buf;
h->path_state = HP_SW_PATH_UNINITIALIZED;
h->retries = HP_SW_RETRIES;
+ h->sdev = sdev;
ret = hp_sw_tur(sdev, h);
if (ret != SCSI_DH_OK || h->path_state == HP_SW_PATH_UNINITIALIZED)
diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c
index 268189d..47cfe1c 100644
--- a/drivers/scsi/device_handler/scsi_dh_rdac.c
+++ b/drivers/scsi/device_handler/scsi_dh_rdac.c
@@ -22,6 +22,7 @@
#include <scsi/scsi.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_dh.h>
+#include <linux/workqueue.h>
#define RDAC_NAME "rdac"
#define RDAC_RETRY_COUNT 5
@@ -138,7 +139,13 @@ struct rdac_controller {
} mode_select;
u8 index;
u8 array_name[ARRAY_LABEL_LEN];
+ spinlock_t ms_lock;
+ int ms_queued;
+ struct work_struct ms_work;
+ struct scsi_device *ms_sdev;
+ struct list_head ms_head;
};
+
struct c8_inquiry {
u8 peripheral_info;
u8 page_code; /* 0xC8 */
@@ -198,8 +205,17 @@ static const char *lun_state[] =
"owned (AVT mode)",
};
+struct rdac_queue_data {
+ struct list_head entry;
+ struct rdac_dh_data *h;
+ activate_complete callback_fn;
+ void *callback_data;
+};
+
static LIST_HEAD(ctlr_list);
static DEFINE_SPINLOCK(list_lock);
+static struct workqueue_struct *kmpath_rdacd;
+static void send_mode_select(struct work_struct *work);
/*
* module parameter to enable rdac debug logging.
@@ -281,7 +297,6 @@ static struct request *rdac_failover_get(struct scsi_device *sdev,
rdac_pg->subpage_code = 0x1;
rdac_pg->page_len[0] = 0x01;
rdac_pg->page_len[1] = 0x28;
- rdac_pg->lun_table[h->lun] = 0x81;
} else {
struct rdac_pg_legacy *rdac_pg;
@@ -291,7 +306,6 @@ static struct request *rdac_failover_get(struct scsi_device *sdev,
common = &rdac_pg->common;
rdac_pg->page_code = RDAC_PAGE_CODE_REDUNDANT_CONTROLLER;
rdac_pg->page_len = 0x68;
- rdac_pg->lun_table[h->lun] = 0x81;
}
common->rdac_mode[1] = RDAC_MODE_TRANSFER_SPECIFIED_LUNS;
common->quiescence_timeout = RDAC_QUIESCENCE_TIME;
@@ -325,6 +339,7 @@ static void release_controller(struct kref *kref)
struct rdac_controller *ctlr;
ctlr = container_of(kref, struct rdac_controller, kref);
+ flush_workqueue(kmpath_rdacd);
spin_lock(&list_lock);
list_del(&ctlr->node);
spin_unlock(&list_lock);
@@ -363,6 +378,11 @@ static struct rdac_controller *get_controller(u8 *subsys_id, u8 *slot_id,
kref_init(&ctlr->kref);
ctlr->use_ms10 = -1;
+ ctlr->ms_queued = 0;
+ ctlr->ms_sdev = NULL;
+ spin_lock_init(&ctlr->ms_lock);
+ INIT_WORK(&ctlr->ms_work, send_mode_select);
+ INIT_LIST_HEAD(&ctlr->ms_head);
list_add(&ctlr->node, &ctlr_list);
done:
spin_unlock(&list_lock);
@@ -490,7 +510,7 @@ static int set_mode_select(struct scsi_device *sdev, struct rdac_dh_data *h)
}
static int mode_select_handle_sense(struct scsi_device *sdev,
- unsigned char *sensebuf)
+ unsigned char *sensebuf)
{
struct scsi_sense_hdr sense_hdr;
int err = SCSI_DH_IO, ret;
@@ -533,11 +553,29 @@ done:
return err;
}
-static int send_mode_select(struct scsi_device *sdev, struct rdac_dh_data *h)
+static void send_mode_select(struct work_struct *work)
{
+ struct rdac_controller *ctlr =
+ container_of(work, struct rdac_controller, ms_work);
struct request *rq;
+ struct scsi_device *sdev = ctlr->ms_sdev;
+ struct rdac_dh_data *h = get_rdac_data(sdev);
struct request_queue *q = sdev->request_queue;
int err, retry_cnt = RDAC_RETRY_COUNT;
+ struct rdac_queue_data *tmp, *qdata;
+ LIST_HEAD(list);
+ u8 *lun_table;
+
+ spin_lock(&ctlr->ms_lock);
+ list_splice_init(&ctlr->ms_head, &list);
+ ctlr->ms_queued = 0;
+ ctlr->ms_sdev = NULL;
+ spin_unlock(&ctlr->ms_lock);
+
+ if (ctlr->use_ms10)
+ lun_table = ctlr->mode_select.expanded.lun_table;
+ else
+ lun_table = ctlr->mode_select.legacy.lun_table;
retry:
err = SCSI_DH_RES_TEMP_UNAVAIL;
@@ -545,6 +583,10 @@ retry:
if (!rq)
goto done;
+ list_for_each_entry(qdata, &list, entry) {
+ lun_table[qdata->h->lun] = 0x81;
+ }
+
RDAC_LOG(RDAC_LOG_FAILOVER, sdev, "array %s, ctlr %d, "
"%s MODE_SELECT command",
(char *) h->ctlr->array_name, h->ctlr->index,
@@ -565,10 +607,45 @@ retry:
}
done:
- return err;
+ list_for_each_entry_safe(qdata, tmp, &list, entry) {
+ list_del(&qdata->entry);
+ if (err == SCSI_DH_OK)
+ qdata->h->state = RDAC_STATE_ACTIVE;
+ if (qdata->callback_fn)
+ qdata->callback_fn(qdata->callback_data, err);
+ kfree(qdata);
+ }
+ return;
+}
+
+static int queue_mode_select(struct scsi_device *sdev,
+ activate_complete fn, void *data)
+{
+ struct rdac_queue_data *qdata;
+ struct rdac_controller *ctlr;
+
+ qdata = kzalloc(sizeof(*qdata), GFP_KERNEL);
+ if (!qdata)
+ return SCSI_DH_RETRY;
+
+ qdata->h = get_rdac_data(sdev);
+ qdata->callback_fn = fn;
+ qdata->callback_data = data;
+
+ ctlr = qdata->h->ctlr;
+ spin_lock(&ctlr->ms_lock);
+ list_add_tail(&qdata->entry, &ctlr->ms_head);
+ if (!ctlr->ms_queued) {
+ ctlr->ms_queued = 1;
+ ctlr->ms_sdev = sdev;
+ queue_work(kmpath_rdacd, &ctlr->ms_work);
+ }
+ spin_unlock(&ctlr->ms_lock);
+ return SCSI_DH_OK;
}
-static int rdac_activate(struct scsi_device *sdev)
+static int rdac_activate(struct scsi_device *sdev,
+ activate_complete fn, void *data)
{
struct rdac_dh_data *h = get_rdac_data(sdev);
int err = SCSI_DH_OK;
@@ -577,10 +654,15 @@ static int rdac_activate(struct scsi_device *sdev)
if (err != SCSI_DH_OK)
goto done;
- if (h->lun_state == RDAC_LUN_UNOWNED)
- err = send_mode_select(sdev, h);
+ if (h->lun_state == RDAC_LUN_UNOWNED) {
+ err = queue_mode_select(sdev, fn, data);
+ if (err == SCSI_DH_OK)
+ return 0;
+ }
done:
- return err;
+ if (fn)
+ fn(data, err);
+ return 0;
}
static int rdac_prep_fn(struct scsi_device *sdev, struct request *req)
@@ -790,13 +872,26 @@ static int __init rdac_init(void)
int r;
r = scsi_register_device_handler(&rdac_dh);
- if (r != 0)
+ if (r != 0) {
printk(KERN_ERR "Failed to register scsi device handler.");
+ goto done;
+ }
+
+ /*
+ * Create workqueue to handle mode selects for rdac
+ */
+ kmpath_rdacd = create_singlethread_workqueue("kmpath_rdacd");
+ if (!kmpath_rdacd) {
+ scsi_unregister_device_handler(&rdac_dh);
+ printk(KERN_ERR "kmpath_rdacd creation failed.\n");
+ }
+done:
return r;
}
static void __exit rdac_exit(void)
{
+ destroy_workqueue(kmpath_rdacd);
scsi_unregister_device_handler(&rdac_dh);
}
diff --git a/drivers/scsi/dmx3191d.c b/drivers/scsi/dmx3191d.c
index fa738ec..207352c 100644
--- a/drivers/scsi/dmx3191d.c
+++ b/drivers/scsi/dmx3191d.c
@@ -31,7 +31,7 @@
#include <scsi/scsi_host.h>
/*
- * Defintions for the generic 5380 driver.
+ * Definitions for the generic 5380 driver.
*/
#define AUTOSENSE
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index 704b8e0..a30ffaa 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -66,14 +66,14 @@ LIST_HEAD(fcoe_hostlist);
DEFINE_PER_CPU(struct fcoe_percpu_s, fcoe_percpu);
/* Function Prototypes */
-static int fcoe_reset(struct Scsi_Host *shost);
+static int fcoe_reset(struct Scsi_Host *);
static int fcoe_xmit(struct fc_lport *, struct fc_frame *);
static int fcoe_rcv(struct sk_buff *, struct net_device *,
struct packet_type *, struct net_device *);
-static int fcoe_percpu_receive_thread(void *arg);
-static void fcoe_clean_pending_queue(struct fc_lport *lp);
-static void fcoe_percpu_clean(struct fc_lport *lp);
-static int fcoe_link_ok(struct fc_lport *lp);
+static int fcoe_percpu_receive_thread(void *);
+static void fcoe_clean_pending_queue(struct fc_lport *);
+static void fcoe_percpu_clean(struct fc_lport *);
+static int fcoe_link_ok(struct fc_lport *);
static struct fc_lport *fcoe_hostlist_lookup(const struct net_device *);
static int fcoe_hostlist_add(const struct fc_lport *);
@@ -82,15 +82,69 @@ static void fcoe_check_wait_queue(struct fc_lport *, struct sk_buff *);
static int fcoe_device_notification(struct notifier_block *, ulong, void *);
static void fcoe_dev_setup(void);
static void fcoe_dev_cleanup(void);
-static struct fcoe_interface *
- fcoe_hostlist_lookup_port(const struct net_device *dev);
+static struct fcoe_interface
+*fcoe_hostlist_lookup_port(const struct net_device *);
+
+static int fcoe_fip_recv(struct sk_buff *, struct net_device *,
+ struct packet_type *, struct net_device *);
+
+static void fcoe_fip_send(struct fcoe_ctlr *, struct sk_buff *);
+static void fcoe_update_src_mac(struct fc_lport *, u8 *);
+static u8 *fcoe_get_src_mac(struct fc_lport *);
+static void fcoe_destroy_work(struct work_struct *);
+
+static int fcoe_ddp_setup(struct fc_lport *, u16, struct scatterlist *,
+ unsigned int);
+static int fcoe_ddp_done(struct fc_lport *, u16);
+
+static int fcoe_cpu_callback(struct notifier_block *, unsigned long, void *);
+
+static int fcoe_create(const char *, struct kernel_param *);
+static int fcoe_destroy(const char *, struct kernel_param *);
+
+static struct fc_seq *fcoe_elsct_send(struct fc_lport *,
+ u32 did, struct fc_frame *,
+ unsigned int op,
+ void (*resp)(struct fc_seq *,
+ struct fc_frame *,
+ void *),
+ void *, u32 timeout);
+static void fcoe_recv_frame(struct sk_buff *skb);
+
+static void fcoe_get_lesb(struct fc_lport *, struct fc_els_lesb *);
+
+module_param_call(create, fcoe_create, NULL, NULL, S_IWUSR);
+__MODULE_PARM_TYPE(create, "string");
+MODULE_PARM_DESC(create, "Create fcoe fcoe using net device passed in.");
+module_param_call(destroy, fcoe_destroy, NULL, NULL, S_IWUSR);
+__MODULE_PARM_TYPE(destroy, "string");
+MODULE_PARM_DESC(destroy, "Destroy fcoe fcoe");
-/* notification function from net device */
+/* notification function for packets from net device */
static struct notifier_block fcoe_notifier = {
.notifier_call = fcoe_device_notification,
};
-static struct scsi_transport_template *scsi_transport_fcoe_sw;
+/* notification function for CPU hotplug events */
+static struct notifier_block fcoe_cpu_notifier = {
+ .notifier_call = fcoe_cpu_callback,
+};
+
+static struct scsi_transport_template *fcoe_transport_template;
+static struct scsi_transport_template *fcoe_vport_transport_template;
+
+static int fcoe_vport_destroy(struct fc_vport *);
+static int fcoe_vport_create(struct fc_vport *, bool disabled);
+static int fcoe_vport_disable(struct fc_vport *, bool disable);
+static void fcoe_set_vport_symbolic_name(struct fc_vport *);
+
+static struct libfc_function_template fcoe_libfc_fcn_templ = {
+ .frame_send = fcoe_xmit,
+ .ddp_setup = fcoe_ddp_setup,
+ .ddp_done = fcoe_ddp_done,
+ .elsct_send = fcoe_elsct_send,
+ .get_lesb = fcoe_get_lesb,
+};
struct fc_function_template fcoe_transport_function = {
.show_host_node_name = 1,
@@ -123,6 +177,48 @@ struct fc_function_template fcoe_transport_function = {
.issue_fc_host_lip = fcoe_reset,
.terminate_rport_io = fc_rport_terminate_io,
+
+ .vport_create = fcoe_vport_create,
+ .vport_delete = fcoe_vport_destroy,
+ .vport_disable = fcoe_vport_disable,
+ .set_vport_symbolic_name = fcoe_set_vport_symbolic_name,
+
+ .bsg_request = fc_lport_bsg_request,
+};
+
+struct fc_function_template fcoe_vport_transport_function = {
+ .show_host_node_name = 1,
+ .show_host_port_name = 1,
+ .show_host_supported_classes = 1,
+ .show_host_supported_fc4s = 1,
+ .show_host_active_fc4s = 1,
+ .show_host_maxframe_size = 1,
+
+ .show_host_port_id = 1,
+ .show_host_supported_speeds = 1,
+ .get_host_speed = fc_get_host_speed,
+ .show_host_speed = 1,
+ .show_host_port_type = 1,
+ .get_host_port_state = fc_get_host_port_state,
+ .show_host_port_state = 1,
+ .show_host_symbolic_name = 1,
+
+ .dd_fcrport_size = sizeof(struct fc_rport_libfc_priv),
+ .show_rport_maxframe_size = 1,
+ .show_rport_supported_classes = 1,
+
+ .show_host_fabric_name = 1,
+ .show_starget_node_name = 1,
+ .show_starget_port_name = 1,
+ .show_starget_port_id = 1,
+ .set_rport_dev_loss_tmo = fc_set_rport_loss_tmo,
+ .show_rport_dev_loss_tmo = 1,
+ .get_fc_host_stats = fc_get_host_stats,
+ .issue_fc_host_lip = fcoe_reset,
+
+ .terminate_rport_io = fc_rport_terminate_io,
+
+ .bsg_request = fc_lport_bsg_request,
};
static struct scsi_host_template fcoe_shost_template = {
@@ -137,20 +233,17 @@ static struct scsi_host_template fcoe_shost_template = {
.change_queue_depth = fc_change_queue_depth,
.change_queue_type = fc_change_queue_type,
.this_id = -1,
- .cmd_per_lun = 32,
+ .cmd_per_lun = 3,
.can_queue = FCOE_MAX_OUTSTANDING_COMMANDS,
.use_clustering = ENABLE_CLUSTERING,
.sg_tablesize = SG_ALL,
.max_sectors = 0xffff,
};
-static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *ptype,
- struct net_device *orig_dev);
/**
- * fcoe_interface_setup()
- * @fcoe: new fcoe_interface
- * @netdev : ptr to the associated netdevice struct
+ * fcoe_interface_setup() - Setup a FCoE interface
+ * @fcoe: The new FCoE interface
+ * @netdev: The net device that the fcoe interface is on
*
* Returns : 0 for success
* Locking: must be called with the RTNL mutex held
@@ -160,23 +253,36 @@ static int fcoe_interface_setup(struct fcoe_interface *fcoe,
{
struct fcoe_ctlr *fip = &fcoe->ctlr;
struct netdev_hw_addr *ha;
+ struct net_device *real_dev;
u8 flogi_maddr[ETH_ALEN];
+ const struct net_device_ops *ops;
fcoe->netdev = netdev;
+ /* Let LLD initialize for FCoE */
+ ops = netdev->netdev_ops;
+ if (ops->ndo_fcoe_enable) {
+ if (ops->ndo_fcoe_enable(netdev))
+ FCOE_NETDEV_DBG(netdev, "Failed to enable FCoE"
+ " specific feature for LLD.\n");
+ }
+
/* Do not support for bonding device */
if ((netdev->priv_flags & IFF_MASTER_ALB) ||
(netdev->priv_flags & IFF_SLAVE_INACTIVE) ||
(netdev->priv_flags & IFF_MASTER_8023AD)) {
+ FCOE_NETDEV_DBG(netdev, "Bonded interfaces not supported\n");
return -EOPNOTSUPP;
}
/* look for SAN MAC address, if multiple SAN MACs exist, only
* use the first one for SPMA */
+ real_dev = (netdev->priv_flags & IFF_802_1Q_VLAN) ?
+ vlan_dev_real_dev(netdev) : netdev;
rcu_read_lock();
- for_each_dev_addr(netdev, ha) {
+ for_each_dev_addr(real_dev, ha) {
if ((ha->type == NETDEV_HW_ADDR_T_SAN) &&
- (is_valid_ether_addr(fip->ctl_src_addr))) {
+ (is_valid_ether_addr(ha->addr))) {
memcpy(fip->ctl_src_addr, ha->addr, ETH_ALEN);
fip->spma = 1;
break;
@@ -216,19 +322,16 @@ static int fcoe_interface_setup(struct fcoe_interface *fcoe,
return 0;
}
-static void fcoe_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb);
-static void fcoe_update_src_mac(struct fcoe_ctlr *fip, u8 *old, u8 *new);
-static void fcoe_destroy_work(struct work_struct *work);
-
/**
- * fcoe_interface_create()
- * @netdev: network interface
+ * fcoe_interface_create() - Create a FCoE interface on a net device
+ * @netdev: The net device to create the FCoE interface on
*
* Returns: pointer to a struct fcoe_interface or NULL on error
*/
static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev)
{
struct fcoe_interface *fcoe;
+ int err;
fcoe = kzalloc(sizeof(*fcoe), GFP_KERNEL);
if (!fcoe) {
@@ -245,15 +348,22 @@ static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev)
fcoe_ctlr_init(&fcoe->ctlr);
fcoe->ctlr.send = fcoe_fip_send;
fcoe->ctlr.update_mac = fcoe_update_src_mac;
+ fcoe->ctlr.get_src_addr = fcoe_get_src_mac;
- fcoe_interface_setup(fcoe, netdev);
+ err = fcoe_interface_setup(fcoe, netdev);
+ if (err) {
+ fcoe_ctlr_destroy(&fcoe->ctlr);
+ kfree(fcoe);
+ dev_put(netdev);
+ return NULL;
+ }
return fcoe;
}
/**
- * fcoe_interface_cleanup() - clean up netdev configurations
- * @fcoe:
+ * fcoe_interface_cleanup() - Clean up a FCoE interface
+ * @fcoe: The FCoE interface to be cleaned up
*
* Caller must be holding the RTNL mutex
*/
@@ -262,6 +372,7 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe)
struct net_device *netdev = fcoe->netdev;
struct fcoe_ctlr *fip = &fcoe->ctlr;
u8 flogi_maddr[ETH_ALEN];
+ const struct net_device_ops *ops;
/*
* Don't listen for Ethernet packets anymore.
@@ -276,16 +387,22 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe)
/* Delete secondary MAC addresses */
memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN);
dev_unicast_delete(netdev, flogi_maddr);
- if (!is_zero_ether_addr(fip->data_src_addr))
- dev_unicast_delete(netdev, fip->data_src_addr);
if (fip->spma)
dev_unicast_delete(netdev, fip->ctl_src_addr);
dev_mc_delete(netdev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0);
+
+ /* Tell the LLD we are done w/ FCoE */
+ ops = netdev->netdev_ops;
+ if (ops->ndo_fcoe_disable) {
+ if (ops->ndo_fcoe_disable(netdev))
+ FCOE_NETDEV_DBG(netdev, "Failed to disable FCoE"
+ " specific feature for LLD.\n");
+ }
}
/**
* fcoe_interface_release() - fcoe_port kref release function
- * @kref: embedded reference count in an fcoe_interface struct
+ * @kref: Embedded reference count in an fcoe_interface struct
*/
static void fcoe_interface_release(struct kref *kref)
{
@@ -301,8 +418,8 @@ static void fcoe_interface_release(struct kref *kref)
}
/**
- * fcoe_interface_get()
- * @fcoe:
+ * fcoe_interface_get() - Get a reference to a FCoE interface
+ * @fcoe: The FCoE interface to be held
*/
static inline void fcoe_interface_get(struct fcoe_interface *fcoe)
{
@@ -310,8 +427,8 @@ static inline void fcoe_interface_get(struct fcoe_interface *fcoe)
}
/**
- * fcoe_interface_put()
- * @fcoe:
+ * fcoe_interface_put() - Put a reference to a FCoE interface
+ * @fcoe: The FCoE interface to be released
*/
static inline void fcoe_interface_put(struct fcoe_interface *fcoe)
{
@@ -319,15 +436,16 @@ static inline void fcoe_interface_put(struct fcoe_interface *fcoe)
}
/**
- * fcoe_fip_recv - handle a received FIP frame.
- * @skb: the receive skb
- * @dev: associated &net_device
- * @ptype: the &packet_type structure which was used to register this handler.
- * @orig_dev: original receive &net_device, in case @dev is a bond.
+ * fcoe_fip_recv() - Handler for received FIP frames
+ * @skb: The receive skb
+ * @netdev: The associated net device
+ * @ptype: The packet_type structure which was used to register this handler
+ * @orig_dev: The original net_device the the skb was received on.
+ * (in case dev is a bond)
*
* Returns: 0 for success
*/
-static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *dev,
+static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *netdev,
struct packet_type *ptype,
struct net_device *orig_dev)
{
@@ -339,9 +457,9 @@ static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *dev,
}
/**
- * fcoe_fip_send() - send an Ethernet-encapsulated FIP frame.
- * @fip: FCoE controller.
- * @skb: FIP Packet.
+ * fcoe_fip_send() - Send an Ethernet-encapsulated FIP frame
+ * @fip: The FCoE controller
+ * @skb: The FIP packet to be sent
*/
static void fcoe_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb)
{
@@ -350,88 +468,101 @@ static void fcoe_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb)
}
/**
- * fcoe_update_src_mac() - Update Ethernet MAC filters.
- * @fip: FCoE controller.
- * @old: Unicast MAC address to delete if the MAC is non-zero.
- * @new: Unicast MAC address to add.
+ * fcoe_update_src_mac() - Update the Ethernet MAC filters
+ * @lport: The local port to update the source MAC on
+ * @addr: Unicast MAC address to add
*
* Remove any previously-set unicast MAC filter.
* Add secondary FCoE MAC address filter for our OUI.
*/
-static void fcoe_update_src_mac(struct fcoe_ctlr *fip, u8 *old, u8 *new)
+static void fcoe_update_src_mac(struct fc_lport *lport, u8 *addr)
{
- struct fcoe_interface *fcoe;
+ struct fcoe_port *port = lport_priv(lport);
+ struct fcoe_interface *fcoe = port->fcoe;
- fcoe = fcoe_from_ctlr(fip);
rtnl_lock();
- if (!is_zero_ether_addr(old))
- dev_unicast_delete(fcoe->netdev, old);
- dev_unicast_add(fcoe->netdev, new);
+ if (!is_zero_ether_addr(port->data_src_addr))
+ dev_unicast_delete(fcoe->netdev, port->data_src_addr);
+ if (!is_zero_ether_addr(addr))
+ dev_unicast_add(fcoe->netdev, addr);
+ memcpy(port->data_src_addr, addr, ETH_ALEN);
rtnl_unlock();
}
/**
- * fcoe_lport_config() - sets up the fc_lport
- * @lp: ptr to the fc_lport
+ * fcoe_get_src_mac() - return the Ethernet source address for an lport
+ * @lport: libfc lport
+ */
+static u8 *fcoe_get_src_mac(struct fc_lport *lport)
+{
+ struct fcoe_port *port = lport_priv(lport);
+
+ return port->data_src_addr;
+}
+
+/**
+ * fcoe_lport_config() - Set up a local port
+ * @lport: The local port to be setup
*
* Returns: 0 for success
*/
-static int fcoe_lport_config(struct fc_lport *lp)
+static int fcoe_lport_config(struct fc_lport *lport)
{
- lp->link_up = 0;
- lp->qfull = 0;
- lp->max_retry_count = 3;
- lp->max_rport_retry_count = 3;
- lp->e_d_tov = 2 * 1000; /* FC-FS default */
- lp->r_a_tov = 2 * 2 * 1000;
- lp->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS |
- FCP_SPPF_RETRY | FCP_SPPF_CONF_COMPL);
-
- fc_lport_init_stats(lp);
+ lport->link_up = 0;
+ lport->qfull = 0;
+ lport->max_retry_count = 3;
+ lport->max_rport_retry_count = 3;
+ lport->e_d_tov = 2 * 1000; /* FC-FS default */
+ lport->r_a_tov = 2 * 2 * 1000;
+ lport->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS |
+ FCP_SPPF_RETRY | FCP_SPPF_CONF_COMPL);
+ lport->does_npiv = 1;
+
+ fc_lport_init_stats(lport);
/* lport fc_lport related configuration */
- fc_lport_config(lp);
+ fc_lport_config(lport);
/* offload related configuration */
- lp->crc_offload = 0;
- lp->seq_offload = 0;
- lp->lro_enabled = 0;
- lp->lro_xid = 0;
- lp->lso_max = 0;
+ lport->crc_offload = 0;
+ lport->seq_offload = 0;
+ lport->lro_enabled = 0;
+ lport->lro_xid = 0;
+ lport->lso_max = 0;
return 0;
}
/**
- * fcoe_queue_timer() - fcoe queue timer
- * @lp: the fc_lport pointer
+ * fcoe_queue_timer() - The fcoe queue timer
+ * @lport: The local port
*
* Calls fcoe_check_wait_queue on timeout
- *
*/
-static void fcoe_queue_timer(ulong lp)
+static void fcoe_queue_timer(ulong lport)
{
- fcoe_check_wait_queue((struct fc_lport *)lp, NULL);
+ fcoe_check_wait_queue((struct fc_lport *)lport, NULL);
}
/**
- * fcoe_netdev_config() - Set up netdev for SW FCoE
- * @lp : ptr to the fc_lport
- * @netdev : ptr to the associated netdevice struct
+ * fcoe_netdev_config() - Set up net devive for SW FCoE
+ * @lport: The local port that is associated with the net device
+ * @netdev: The associated net device
*
- * Must be called after fcoe_lport_config() as it will use lport mutex
+ * Must be called after fcoe_lport_config() as it will use local port mutex
*
- * Returns : 0 for success
+ * Returns: 0 for success
*/
-static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev)
+static int fcoe_netdev_config(struct fc_lport *lport, struct net_device *netdev)
{
u32 mfs;
u64 wwnn, wwpn;
struct fcoe_interface *fcoe;
struct fcoe_port *port;
+ int vid = 0;
/* Setup lport private data to point to fcoe softc */
- port = lport_priv(lp);
+ port = lport_priv(lport);
fcoe = port->fcoe;
/*
@@ -439,86 +570,112 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev)
* user-configured limit. If the MFS is too low, fcoe_link_ok()
* will return 0, so do this first.
*/
- mfs = netdev->mtu - (sizeof(struct fcoe_hdr) +
- sizeof(struct fcoe_crc_eof));
- if (fc_set_mfs(lp, mfs))
+ mfs = netdev->mtu;
+ if (netdev->features & NETIF_F_FCOE_MTU) {
+ mfs = FCOE_MTU;
+ FCOE_NETDEV_DBG(netdev, "Supports FCOE_MTU of %d bytes\n", mfs);
+ }
+ mfs -= (sizeof(struct fcoe_hdr) + sizeof(struct fcoe_crc_eof));
+ if (fc_set_mfs(lport, mfs))
return -EINVAL;
/* offload features support */
if (netdev->features & NETIF_F_SG)
- lp->sg_supp = 1;
+ lport->sg_supp = 1;
if (netdev->features & NETIF_F_FCOE_CRC) {
- lp->crc_offload = 1;
+ lport->crc_offload = 1;
FCOE_NETDEV_DBG(netdev, "Supports FCCRC offload\n");
}
if (netdev->features & NETIF_F_FSO) {
- lp->seq_offload = 1;
- lp->lso_max = netdev->gso_max_size;
+ lport->seq_offload = 1;
+ lport->lso_max = netdev->gso_max_size;
FCOE_NETDEV_DBG(netdev, "Supports LSO for max len 0x%x\n",
- lp->lso_max);
+ lport->lso_max);
}
if (netdev->fcoe_ddp_xid) {
- lp->lro_enabled = 1;
- lp->lro_xid = netdev->fcoe_ddp_xid;
+ lport->lro_enabled = 1;
+ lport->lro_xid = netdev->fcoe_ddp_xid;
FCOE_NETDEV_DBG(netdev, "Supports LRO for max xid 0x%x\n",
- lp->lro_xid);
+ lport->lro_xid);
}
skb_queue_head_init(&port->fcoe_pending_queue);
port->fcoe_pending_queue_active = 0;
- setup_timer(&port->timer, fcoe_queue_timer, (unsigned long)lp);
+ setup_timer(&port->timer, fcoe_queue_timer, (unsigned long)lport);
- wwnn = fcoe_wwn_from_mac(netdev->dev_addr, 1, 0);
- fc_set_wwnn(lp, wwnn);
- /* XXX - 3rd arg needs to be vlan id */
- wwpn = fcoe_wwn_from_mac(netdev->dev_addr, 2, 0);
- fc_set_wwpn(lp, wwpn);
+ if (!lport->vport) {
+ /*
+ * Use NAA 1&2 (FC-FS Rev. 2.0, Sec. 15) to generate WWNN/WWPN:
+ * For WWNN, we use NAA 1 w/ bit 27-16 of word 0 as 0.
+ * For WWPN, we use NAA 2 w/ bit 27-16 of word 0 from VLAN ID
+ */
+ if (netdev->priv_flags & IFF_802_1Q_VLAN)
+ vid = vlan_dev_vlan_id(netdev);
+ wwnn = fcoe_wwn_from_mac(fcoe->ctlr.ctl_src_addr, 1, 0);
+ fc_set_wwnn(lport, wwnn);
+ wwpn = fcoe_wwn_from_mac(fcoe->ctlr.ctl_src_addr, 2, vid);
+ fc_set_wwpn(lport, wwpn);
+ }
return 0;
}
/**
- * fcoe_shost_config() - Sets up fc_lport->host
- * @lp : ptr to the fc_lport
- * @shost : ptr to the associated scsi host
- * @dev : device associated to scsi host
+ * fcoe_shost_config() - Set up the SCSI host associated with a local port
+ * @lport: The local port
+ * @shost: The SCSI host to associate with the local port
+ * @dev: The device associated with the SCSI host
*
* Must be called after fcoe_lport_config() and fcoe_netdev_config()
*
- * Returns : 0 for success
+ * Returns: 0 for success
*/
-static int fcoe_shost_config(struct fc_lport *lp, struct Scsi_Host *shost,
- struct device *dev)
+static int fcoe_shost_config(struct fc_lport *lport, struct Scsi_Host *shost,
+ struct device *dev)
{
int rc = 0;
/* lport scsi host config */
- lp->host = shost;
-
- lp->host->max_lun = FCOE_MAX_LUN;
- lp->host->max_id = FCOE_MAX_FCP_TARGET;
- lp->host->max_channel = 0;
- lp->host->transportt = scsi_transport_fcoe_sw;
+ lport->host->max_lun = FCOE_MAX_LUN;
+ lport->host->max_id = FCOE_MAX_FCP_TARGET;
+ lport->host->max_channel = 0;
+ if (lport->vport)
+ lport->host->transportt = fcoe_vport_transport_template;
+ else
+ lport->host->transportt = fcoe_transport_template;
/* add the new host to the SCSI-ml */
- rc = scsi_add_host(lp->host, dev);
+ rc = scsi_add_host(lport->host, dev);
if (rc) {
- FCOE_NETDEV_DBG(fcoe_netdev(lp), "fcoe_shost_config: "
+ FCOE_NETDEV_DBG(fcoe_netdev(lport), "fcoe_shost_config: "
"error on scsi_add_host\n");
return rc;
}
- sprintf(fc_host_symbolic_name(lp->host), "%s v%s over %s",
- FCOE_NAME, FCOE_VERSION,
- fcoe_netdev(lp)->name);
+
+ if (!lport->vport)
+ fc_host_max_npiv_vports(lport->host) = USHORT_MAX;
+
+ snprintf(fc_host_symbolic_name(lport->host), FC_SYMBOLIC_NAME_SIZE,
+ "%s v%s over %s", FCOE_NAME, FCOE_VERSION,
+ fcoe_netdev(lport)->name);
return 0;
}
-/*
- * fcoe_oem_match() - match for read types IO
- * @fp: the fc_frame for new IO.
+/**
+ * fcoe_oem_match() - The match routine for the offloaded exchange manager
+ * @fp: The I/O frame
+ *
+ * This routine will be associated with an exchange manager (EM). When
+ * the libfc exchange handling code is looking for an EM to use it will
+ * call this routine and pass it the frame that it wishes to send. This
+ * routine will return True if the associated EM is to be used and False
+ * if the echange code should continue looking for an EM.
*
- * Returns : true for read types IO, otherwise returns false.
+ * The offload EM that this routine is associated with will handle any
+ * packets that are for SCSI read requests.
+ *
+ * Returns: True for read types I/O, otherwise returns false.
*/
bool fcoe_oem_match(struct fc_frame *fp)
{
@@ -527,14 +684,14 @@ bool fcoe_oem_match(struct fc_frame *fp)
}
/**
- * fcoe_em_config() - allocates em for this lport
- * @lp: the fcoe that em is to allocated for
+ * fcoe_em_config() - Allocate and configure an exchange manager
+ * @lport: The local port that the new EM will be associated with
*
- * Returns : 0 on success
+ * Returns: 0 on success
*/
-static inline int fcoe_em_config(struct fc_lport *lp)
+static inline int fcoe_em_config(struct fc_lport *lport)
{
- struct fcoe_port *port = lport_priv(lp);
+ struct fcoe_port *port = lport_priv(lport);
struct fcoe_interface *fcoe = port->fcoe;
struct fcoe_interface *oldfcoe = NULL;
struct net_device *old_real_dev, *cur_real_dev;
@@ -545,8 +702,9 @@ static inline int fcoe_em_config(struct fc_lport *lp)
* Check if need to allocate an em instance for
* offload exchange ids to be shared across all VN_PORTs/lport.
*/
- if (!lp->lro_enabled || !lp->lro_xid || (lp->lro_xid >= max_xid)) {
- lp->lro_xid = 0;
+ if (!lport->lro_enabled || !lport->lro_xid ||
+ (lport->lro_xid >= max_xid)) {
+ lport->lro_xid = 0;
goto skip_oem;
}
@@ -572,16 +730,16 @@ static inline int fcoe_em_config(struct fc_lport *lp)
}
if (fcoe->oem) {
- if (!fc_exch_mgr_add(lp, fcoe->oem, fcoe_oem_match)) {
+ if (!fc_exch_mgr_add(lport, fcoe->oem, fcoe_oem_match)) {
printk(KERN_ERR "fcoe_em_config: failed to add "
"offload em:%p on interface:%s\n",
fcoe->oem, fcoe->netdev->name);
return -ENOMEM;
}
} else {
- fcoe->oem = fc_exch_mgr_alloc(lp, FC_CLASS_3,
- FCOE_MIN_XID, lp->lro_xid,
- fcoe_oem_match);
+ fcoe->oem = fc_exch_mgr_alloc(lport, FC_CLASS_3,
+ FCOE_MIN_XID, lport->lro_xid,
+ fcoe_oem_match);
if (!fcoe->oem) {
printk(KERN_ERR "fcoe_em_config: failed to allocate "
"em for offload exches on interface:%s\n",
@@ -593,10 +751,10 @@ static inline int fcoe_em_config(struct fc_lport *lp)
/*
* Exclude offload EM xid range from next EM xid range.
*/
- min_xid += lp->lro_xid + 1;
+ min_xid += lport->lro_xid + 1;
skip_oem:
- if (!fc_exch_mgr_alloc(lp, FC_CLASS_3, min_xid, max_xid, NULL)) {
+ if (!fc_exch_mgr_alloc(lport, FC_CLASS_3, min_xid, max_xid, NULL)) {
printk(KERN_ERR "fcoe_em_config: failed to "
"allocate em on interface %s\n", fcoe->netdev->name);
return -ENOMEM;
@@ -606,8 +764,8 @@ skip_oem:
}
/**
- * fcoe_if_destroy() - FCoE software HBA tear-down function
- * @lport: fc_lport to destroy
+ * fcoe_if_destroy() - Tear down a SW FCoE instance
+ * @lport: The local port to be destroyed
*/
static void fcoe_if_destroy(struct fc_lport *lport)
{
@@ -630,6 +788,11 @@ static void fcoe_if_destroy(struct fc_lport *lport)
/* Free existing transmit skbs */
fcoe_clean_pending_queue(lport);
+ rtnl_lock();
+ if (!is_zero_ether_addr(port->data_src_addr))
+ dev_unicast_delete(netdev, port->data_src_addr);
+ rtnl_unlock();
+
/* receives may not be stopped until after this */
fcoe_interface_put(fcoe);
@@ -650,82 +813,89 @@ static void fcoe_if_destroy(struct fc_lport *lport)
scsi_host_put(lport->host);
}
-/*
- * fcoe_ddp_setup - calls LLD's ddp_setup through net_device
- * @lp: the corresponding fc_lport
- * @xid: the exchange id for this ddp transfer
- * @sgl: the scatterlist describing this transfer
- * @sgc: number of sg items
+/**
+ * fcoe_ddp_setup() - Call a LLD's ddp_setup through the net device
+ * @lport: The local port to setup DDP for
+ * @xid: The exchange ID for this DDP transfer
+ * @sgl: The scatterlist describing this transfer
+ * @sgc: The number of sg items
*
- * Returns : 0 no ddp
+ * Returns: 0 if the DDP context was not configured
*/
-static int fcoe_ddp_setup(struct fc_lport *lp, u16 xid,
- struct scatterlist *sgl, unsigned int sgc)
+static int fcoe_ddp_setup(struct fc_lport *lport, u16 xid,
+ struct scatterlist *sgl, unsigned int sgc)
{
- struct net_device *n = fcoe_netdev(lp);
+ struct net_device *netdev = fcoe_netdev(lport);
- if (n->netdev_ops && n->netdev_ops->ndo_fcoe_ddp_setup)
- return n->netdev_ops->ndo_fcoe_ddp_setup(n, xid, sgl, sgc);
+ if (netdev->netdev_ops->ndo_fcoe_ddp_setup)
+ return netdev->netdev_ops->ndo_fcoe_ddp_setup(netdev,
+ xid, sgl,
+ sgc);
return 0;
}
-/*
- * fcoe_ddp_done - calls LLD's ddp_done through net_device
- * @lp: the corresponding fc_lport
- * @xid: the exchange id for this ddp transfer
+/**
+ * fcoe_ddp_done() - Call a LLD's ddp_done through the net device
+ * @lport: The local port to complete DDP on
+ * @xid: The exchange ID for this DDP transfer
*
- * Returns : the length of data that have been completed by ddp
+ * Returns: the length of data that have been completed by DDP
*/
-static int fcoe_ddp_done(struct fc_lport *lp, u16 xid)
+static int fcoe_ddp_done(struct fc_lport *lport, u16 xid)
{
- struct net_device *n = fcoe_netdev(lp);
+ struct net_device *netdev = fcoe_netdev(lport);
- if (n->netdev_ops && n->netdev_ops->ndo_fcoe_ddp_done)
- return n->netdev_ops->ndo_fcoe_ddp_done(n, xid);
+ if (netdev->netdev_ops->ndo_fcoe_ddp_done)
+ return netdev->netdev_ops->ndo_fcoe_ddp_done(netdev, xid);
return 0;
}
-static struct libfc_function_template fcoe_libfc_fcn_templ = {
- .frame_send = fcoe_xmit,
- .ddp_setup = fcoe_ddp_setup,
- .ddp_done = fcoe_ddp_done,
-};
-
/**
- * fcoe_if_create() - this function creates the fcoe port
- * @fcoe: fcoe_interface structure to create an fc_lport instance on
- * @parent: device pointer to be the parent in sysfs for the SCSI host
+ * fcoe_if_create() - Create a FCoE instance on an interface
+ * @fcoe: The FCoE interface to create a local port on
+ * @parent: The device pointer to be the parent in sysfs for the SCSI host
+ * @npiv: Indicates if the port is a vport or not
*
- * Creates fc_lport struct and scsi_host for lport, configures lport.
+ * Creates a fc_lport instance and a Scsi_Host instance and configure them.
*
- * Returns : The allocated fc_lport or an error pointer
+ * Returns: The allocated fc_lport or an error pointer
*/
static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe,
- struct device *parent)
+ struct device *parent, int npiv)
{
- int rc;
+ struct net_device *netdev = fcoe->netdev;
struct fc_lport *lport = NULL;
struct fcoe_port *port;
struct Scsi_Host *shost;
- struct net_device *netdev = fcoe->netdev;
+ int rc;
+ /*
+ * parent is only a vport if npiv is 1,
+ * but we'll only use vport in that case so go ahead and set it
+ */
+ struct fc_vport *vport = dev_to_vport(parent);
FCOE_NETDEV_DBG(netdev, "Create Interface\n");
- shost = libfc_host_alloc(&fcoe_shost_template,
- sizeof(struct fcoe_port));
- if (!shost) {
+ if (!npiv) {
+ lport = libfc_host_alloc(&fcoe_shost_template,
+ sizeof(struct fcoe_port));
+ } else {
+ lport = libfc_vport_create(vport,
+ sizeof(struct fcoe_port));
+ }
+ if (!lport) {
FCOE_NETDEV_DBG(netdev, "Could not allocate host structure\n");
rc = -ENOMEM;
goto out;
}
- lport = shost_priv(shost);
+ shost = lport->host;
port = lport_priv(lport);
port->lport = lport;
port->fcoe = fcoe;
INIT_WORK(&port->destroy_work, fcoe_destroy_work);
- /* configure fc_lport, e.g., em */
+ /* configure a fc_lport including the exchange manager */
rc = fcoe_lport_config(lport);
if (rc) {
FCOE_NETDEV_DBG(netdev, "Could not configure lport for the "
@@ -733,6 +903,13 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe,
goto out_host_put;
}
+ if (npiv) {
+ FCOE_NETDEV_DBG(netdev, "Setting vport names, 0x%llX 0x%llX\n",
+ vport->node_name, vport->port_name);
+ fc_set_wwnn(lport, vport->node_name);
+ fc_set_wwpn(lport, vport->port_name);
+ }
+
/* configure lport network properties */
rc = fcoe_netdev_config(lport, netdev);
if (rc) {
@@ -757,21 +934,24 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe,
goto out_lp_destroy;
}
- /*
- * fcoe_em_alloc() and fcoe_hostlist_add() both
- * need to be atomic with respect to other changes to the hostlist
- * since fcoe_em_alloc() looks for an existing EM
- * instance on host list updated by fcoe_hostlist_add().
- *
- * This is currently handled through the fcoe_config_mutex begin held.
- */
+ if (!npiv) {
+ /*
+ * fcoe_em_alloc() and fcoe_hostlist_add() both
+ * need to be atomic with respect to other changes to the
+ * hostlist since fcoe_em_alloc() looks for an existing EM
+ * instance on host list updated by fcoe_hostlist_add().
+ *
+ * This is currently handled through the fcoe_config_mutex
+ * begin held.
+ */
- /* lport exch manager allocation */
- rc = fcoe_em_config(lport);
- if (rc) {
- FCOE_NETDEV_DBG(netdev, "Could not configure the EM for the "
- "interface\n");
- goto out_lp_destroy;
+ /* lport exch manager allocation */
+ rc = fcoe_em_config(lport);
+ if (rc) {
+ FCOE_NETDEV_DBG(netdev, "Could not configure the EM "
+ "for the interface\n");
+ goto out_lp_destroy;
+ }
}
fcoe_interface_get(fcoe);
@@ -786,17 +966,20 @@ out:
}
/**
- * fcoe_if_init() - attach to scsi transport
+ * fcoe_if_init() - Initialization routine for fcoe.ko
+ *
+ * Attaches the SW FCoE transport to the FC transport
*
- * Returns : 0 on success
+ * Returns: 0 on success
*/
static int __init fcoe_if_init(void)
{
/* attach to scsi transport */
- scsi_transport_fcoe_sw =
- fc_attach_transport(&fcoe_transport_function);
+ fcoe_transport_template = fc_attach_transport(&fcoe_transport_function);
+ fcoe_vport_transport_template =
+ fc_attach_transport(&fcoe_vport_transport_function);
- if (!scsi_transport_fcoe_sw) {
+ if (!fcoe_transport_template) {
printk(KERN_ERR "fcoe: Failed to attach to the FC transport\n");
return -ENODEV;
}
@@ -805,20 +988,24 @@ static int __init fcoe_if_init(void)
}
/**
- * fcoe_if_exit() - detach from scsi transport
+ * fcoe_if_exit() - Tear down fcoe.ko
+ *
+ * Detaches the SW FCoE transport from the FC transport
*
- * Returns : 0 on success
+ * Returns: 0 on success
*/
int __exit fcoe_if_exit(void)
{
- fc_release_transport(scsi_transport_fcoe_sw);
- scsi_transport_fcoe_sw = NULL;
+ fc_release_transport(fcoe_transport_template);
+ fc_release_transport(fcoe_vport_transport_template);
+ fcoe_transport_template = NULL;
+ fcoe_vport_transport_template = NULL;
return 0;
}
/**
- * fcoe_percpu_thread_create() - Create a receive thread for an online cpu
- * @cpu: cpu index for the online cpu
+ * fcoe_percpu_thread_create() - Create a receive thread for an online CPU
+ * @cpu: The CPU index of the CPU to create a receive thread for
*/
static void fcoe_percpu_thread_create(unsigned int cpu)
{
@@ -841,8 +1028,8 @@ static void fcoe_percpu_thread_create(unsigned int cpu)
}
/**
- * fcoe_percpu_thread_destroy() - removes the rx thread for the given cpu
- * @cpu: cpu index the rx thread is to be removed
+ * fcoe_percpu_thread_destroy() - Remove the receive thread of a CPU
+ * @cpu: The CPU index of the CPU whose receive thread is to be destroyed
*
* Destroys a per-CPU Rx thread. Any pending skbs are moved to the
* current CPU's Rx thread. If the thread being destroyed is bound to
@@ -890,7 +1077,7 @@ static void fcoe_percpu_thread_destroy(unsigned int cpu)
} else {
/*
* The targeted CPU is not initialized and cannot accept
- * new skbs. Unlock the targeted CPU and drop the skbs
+ * new skbs. Unlock the targeted CPU and drop the skbs
* on the CPU that is going offline.
*/
while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL)
@@ -931,12 +1118,12 @@ static void fcoe_percpu_thread_destroy(unsigned int cpu)
}
/**
- * fcoe_cpu_callback() - fcoe cpu hotplug event callback
- * @nfb: callback data block
- * @action: event triggering the callback
- * @hcpu: index for the cpu of this event
+ * fcoe_cpu_callback() - Handler for CPU hotplug events
+ * @nfb: The callback data block
+ * @action: The event triggering the callback
+ * @hcpu: The index of the CPU that the event is for
*
- * This creates or destroys per cpu data for fcoe
+ * This creates or destroys per-CPU data for fcoe
*
* Returns NOTIFY_OK always.
*/
@@ -962,25 +1149,22 @@ static int fcoe_cpu_callback(struct notifier_block *nfb,
return NOTIFY_OK;
}
-static struct notifier_block fcoe_cpu_notifier = {
- .notifier_call = fcoe_cpu_callback,
-};
-
/**
- * fcoe_rcv() - this is the fcoe receive function called by NET_RX_SOFTIRQ
- * @skb: the receive skb
- * @dev: associated net device
- * @ptype: context
- * @olddev: last device
+ * fcoe_rcv() - Receive packets from a net device
+ * @skb: The received packet
+ * @netdev: The net device that the packet was received on
+ * @ptype: The packet type context
+ * @olddev: The last device net device
*
- * this function will receive the packet and build fc frame and pass it up
+ * This routine is called by NET_RX_SOFTIRQ. It receives a packet, builds a
+ * FC frame and passes the frame to libfc.
*
* Returns: 0 for success
*/
-int fcoe_rcv(struct sk_buff *skb, struct net_device *dev,
+int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev,
struct packet_type *ptype, struct net_device *olddev)
{
- struct fc_lport *lp;
+ struct fc_lport *lport;
struct fcoe_rcv_info *fr;
struct fcoe_interface *fcoe;
struct fc_frame_header *fh;
@@ -988,15 +1172,15 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *dev,
unsigned int cpu;
fcoe = container_of(ptype, struct fcoe_interface, fcoe_packet_type);
- lp = fcoe->ctlr.lp;
- if (unlikely(lp == NULL)) {
- FCOE_NETDEV_DBG(dev, "Cannot find hba structure");
+ lport = fcoe->ctlr.lp;
+ if (unlikely(!lport)) {
+ FCOE_NETDEV_DBG(netdev, "Cannot find hba structure");
goto err2;
}
- if (!lp->link_up)
+ if (!lport->link_up)
goto err2;
- FCOE_NETDEV_DBG(dev, "skb_info: len:%d data_len:%d head:%p "
+ FCOE_NETDEV_DBG(netdev, "skb_info: len:%d data_len:%d head:%p "
"data:%p tail:%p end:%p sum:%d dev:%s",
skb->len, skb->data_len, skb->head, skb->data,
skb_tail_pointer(skb), skb_end_pointer(skb),
@@ -1004,7 +1188,7 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *dev,
/* check for FCOE packet type */
if (unlikely(eth_hdr(skb)->h_proto != htons(ETH_P_FCOE))) {
- FCOE_NETDEV_DBG(dev, "Wrong FC type frame");
+ FCOE_NETDEV_DBG(netdev, "Wrong FC type frame");
goto err;
}
@@ -1013,14 +1197,14 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *dev,
* and FC headers are pulled into the linear data area.
*/
if (unlikely((skb->len < FCOE_MIN_FRAME) ||
- !pskb_may_pull(skb, FCOE_HEADER_LEN)))
+ !pskb_may_pull(skb, FCOE_HEADER_LEN)))
goto err;
skb_set_transport_header(skb, sizeof(struct fcoe_hdr));
fh = (struct fc_frame_header *) skb_transport_header(skb);
fr = fcoe_dev_from_skb(skb);
- fr->fr_dev = lp;
+ fr->fr_dev = lport;
fr->ptype = ptype;
/*
@@ -1042,7 +1226,7 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *dev,
* the first CPU now. For non-SMP systems this
* will check the same CPU twice.
*/
- FCOE_NETDEV_DBG(dev, "CPU is online, but no receive thread "
+ FCOE_NETDEV_DBG(netdev, "CPU is online, but no receive thread "
"ready for incoming skb- using first online "
"CPU.\n");
@@ -1061,15 +1245,29 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *dev,
* this skb. We also have this receive thread locked,
* so we're free to queue skbs into it's queue.
*/
- __skb_queue_tail(&fps->fcoe_rx_list, skb);
- if (fps->fcoe_rx_list.qlen == 1)
- wake_up_process(fps->thread);
- spin_unlock_bh(&fps->fcoe_rx_list.lock);
+ /* If this is a SCSI-FCP frame, and this is already executing on the
+ * correct CPU, and the queue for this CPU is empty, then go ahead
+ * and process the frame directly in the softirq context.
+ * This lets us process completions without context switching from the
+ * NET_RX softirq, to our receive processing thread, and then back to
+ * BLOCK softirq context.
+ */
+ if (fh->fh_type == FC_TYPE_FCP &&
+ cpu == smp_processor_id() &&
+ skb_queue_empty(&fps->fcoe_rx_list)) {
+ spin_unlock_bh(&fps->fcoe_rx_list.lock);
+ fcoe_recv_frame(skb);
+ } else {
+ __skb_queue_tail(&fps->fcoe_rx_list, skb);
+ if (fps->fcoe_rx_list.qlen == 1)
+ wake_up_process(fps->thread);
+ spin_unlock_bh(&fps->fcoe_rx_list.lock);
+ }
return 0;
err:
- fc_lport_get_stats(lp)->ErrorFrames++;
+ fc_lport_get_stats(lport)->ErrorFrames++;
err2:
kfree_skb(skb);
@@ -1077,17 +1275,21 @@ err2:
}
/**
- * fcoe_start_io() - pass to netdev to start xmit for fcoe
- * @skb: the skb to be xmitted
+ * fcoe_start_io() - Start FCoE I/O
+ * @skb: The packet to be transmitted
+ *
+ * This routine is called from the net device to start transmitting
+ * FCoE packets.
*
* Returns: 0 for success
*/
static inline int fcoe_start_io(struct sk_buff *skb)
{
+ struct sk_buff *nskb;
int rc;
- skb_get(skb);
- rc = dev_queue_xmit(skb);
+ nskb = skb_clone(skb, GFP_ATOMIC);
+ rc = dev_queue_xmit(nskb);
if (rc != 0)
return rc;
kfree_skb(skb);
@@ -1095,9 +1297,15 @@ static inline int fcoe_start_io(struct sk_buff *skb)
}
/**
- * fcoe_get_paged_crc_eof() - in case we need to alloc a page for crc_eof
- * @skb: the skb to be xmitted
- * @tlen: total len
+ * fcoe_get_paged_crc_eof() - Allocate a page to be used for the trailer CRC
+ * @skb: The packet to be transmitted
+ * @tlen: The total length of the trailer
+ *
+ * This routine allocates a page for frame trailers. The page is re-used if
+ * there is enough room left on it for the current trailer. If there isn't
+ * enough buffer left a new page is allocated for the trailer. Reference to
+ * the page from this function as well as the skbs using the page fragments
+ * ensure that the page is freed at the appropriate time.
*
* Returns: 0 for success
*/
@@ -1136,11 +1344,12 @@ static int fcoe_get_paged_crc_eof(struct sk_buff *skb, int tlen)
}
/**
- * fcoe_fc_crc() - calculates FC CRC in this fcoe skb
- * @fp: the fc_frame containing data to be checksummed
+ * fcoe_fc_crc() - Calculates the CRC for a given frame
+ * @fp: The frame to be checksumed
+ *
+ * This uses crc32() routine to calculate the CRC for a frame
*
- * This uses crc32() to calculate the crc for port frame
- * Return : 32 bit crc
+ * Return: The 32 bit CRC value
*/
u32 fcoe_fc_crc(struct fc_frame *fp)
{
@@ -1171,13 +1380,13 @@ u32 fcoe_fc_crc(struct fc_frame *fp)
}
/**
- * fcoe_xmit() - FCoE frame transmit function
- * @lp: the associated local fcoe
- * @fp: the fc_frame to be transmitted
+ * fcoe_xmit() - Transmit a FCoE frame
+ * @lport: The local port that the frame is to be transmitted for
+ * @fp: The frame to be transmitted
*
- * Return : 0 for success
+ * Return: 0 for success
*/
-int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp)
+int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp)
{
int wlen;
u32 crc;
@@ -1189,7 +1398,7 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp)
unsigned int hlen; /* header length implies the version */
unsigned int tlen; /* trailer length */
unsigned int elen; /* eth header, may include vlan */
- struct fcoe_port *port = lport_priv(lp);
+ struct fcoe_port *port = lport_priv(lport);
struct fcoe_interface *fcoe = port->fcoe;
u8 sof, eof;
struct fcoe_hdr *hp;
@@ -1200,13 +1409,13 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp)
skb = fp_skb(fp);
wlen = skb->len / FCOE_WORD_TO_BYTE;
- if (!lp->link_up) {
+ if (!lport->link_up) {
kfree_skb(skb);
return 0;
}
if (unlikely(fh->fh_r_ctl == FC_RCTL_ELS_REQ) &&
- fcoe_ctlr_els_send(&fcoe->ctlr, skb))
+ fcoe_ctlr_els_send(&fcoe->ctlr, lport, skb))
return 0;
sof = fr_sof(fp);
@@ -1218,7 +1427,7 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp)
wlen = (skb->len - tlen + sizeof(crc)) / FCOE_WORD_TO_BYTE;
/* crc offload */
- if (likely(lp->crc_offload)) {
+ if (likely(lport->crc_offload)) {
skb->ip_summed = CHECKSUM_PARTIAL;
skb->csum_start = skb_headroom(skb);
skb->csum_offset = skb->len;
@@ -1271,7 +1480,7 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp)
if (unlikely(fcoe->ctlr.flogi_oxid != FC_XID_UNKNOWN))
memcpy(eh->h_source, fcoe->ctlr.ctl_src_addr, ETH_ALEN);
else
- memcpy(eh->h_source, fcoe->ctlr.data_src_addr, ETH_ALEN);
+ memcpy(eh->h_source, port->data_src_addr, ETH_ALEN);
hp = (struct fcoe_hdr *)(eh + 1);
memset(hp, 0, sizeof(*hp));
@@ -1280,7 +1489,7 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp)
hp->fcoe_sof = sof;
/* fcoe lso, mss is in max_payload which is non-zero for FCP data */
- if (lp->seq_offload && fr_max_payload(fp)) {
+ if (lport->seq_offload && fr_max_payload(fp)) {
skb_shinfo(skb)->gso_type = SKB_GSO_FCOE;
skb_shinfo(skb)->gso_size = fr_max_payload(fp);
} else {
@@ -1288,23 +1497,23 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp)
skb_shinfo(skb)->gso_size = 0;
}
/* update tx stats: regardless if LLD fails */
- stats = fc_lport_get_stats(lp);
+ stats = fc_lport_get_stats(lport);
stats->TxFrames++;
stats->TxWords += wlen;
/* send down to lld */
- fr_dev(fp) = lp;
+ fr_dev(fp) = lport;
if (port->fcoe_pending_queue.qlen)
- fcoe_check_wait_queue(lp, skb);
+ fcoe_check_wait_queue(lport, skb);
else if (fcoe_start_io(skb))
- fcoe_check_wait_queue(lp, skb);
+ fcoe_check_wait_queue(lport, skb);
return 0;
}
/**
- * fcoe_percpu_flush_done() - Indicate percpu queue flush completion.
- * @skb: the skb being completed.
+ * fcoe_percpu_flush_done() - Indicate per-CPU queue flush completion
+ * @skb: The completed skb (argument required by destructor)
*/
static void fcoe_percpu_flush_done(struct sk_buff *skb)
{
@@ -1312,26 +1521,134 @@ static void fcoe_percpu_flush_done(struct sk_buff *skb)
}
/**
- * fcoe_percpu_receive_thread() - recv thread per cpu
- * @arg: ptr to the fcoe per cpu struct
- *
- * Return: 0 for success
+ * fcoe_recv_frame() - process a single received frame
+ * @skb: frame to process
*/
-int fcoe_percpu_receive_thread(void *arg)
+static void fcoe_recv_frame(struct sk_buff *skb)
{
- struct fcoe_percpu_s *p = arg;
u32 fr_len;
- struct fc_lport *lp;
+ struct fc_lport *lport;
struct fcoe_rcv_info *fr;
struct fcoe_dev_stats *stats;
struct fc_frame_header *fh;
- struct sk_buff *skb;
struct fcoe_crc_eof crc_eof;
struct fc_frame *fp;
u8 *mac = NULL;
struct fcoe_port *port;
struct fcoe_hdr *hp;
+ fr = fcoe_dev_from_skb(skb);
+ lport = fr->fr_dev;
+ if (unlikely(!lport)) {
+ if (skb->destructor != fcoe_percpu_flush_done)
+ FCOE_NETDEV_DBG(skb->dev, "NULL lport in skb");
+ kfree_skb(skb);
+ return;
+ }
+
+ FCOE_NETDEV_DBG(skb->dev, "skb_info: len:%d data_len:%d "
+ "head:%p data:%p tail:%p end:%p sum:%d dev:%s",
+ skb->len, skb->data_len,
+ skb->head, skb->data, skb_tail_pointer(skb),
+ skb_end_pointer(skb), skb->csum,
+ skb->dev ? skb->dev->name : "<NULL>");
+
+ /*
+ * Save source MAC address before discarding header.
+ */
+ port = lport_priv(lport);
+ if (skb_is_nonlinear(skb))
+ skb_linearize(skb); /* not ideal */
+ mac = eth_hdr(skb)->h_source;
+
+ /*
+ * Frame length checks and setting up the header pointers
+ * was done in fcoe_rcv already.
+ */
+ hp = (struct fcoe_hdr *) skb_network_header(skb);
+ fh = (struct fc_frame_header *) skb_transport_header(skb);
+
+ stats = fc_lport_get_stats(lport);
+ if (unlikely(FC_FCOE_DECAPS_VER(hp) != FC_FCOE_VER)) {
+ if (stats->ErrorFrames < 5)
+ printk(KERN_WARNING "fcoe: FCoE version "
+ "mismatch: The frame has "
+ "version %x, but the "
+ "initiator supports version "
+ "%x\n", FC_FCOE_DECAPS_VER(hp),
+ FC_FCOE_VER);
+ stats->ErrorFrames++;
+ kfree_skb(skb);
+ return;
+ }
+
+ skb_pull(skb, sizeof(struct fcoe_hdr));
+ fr_len = skb->len - sizeof(struct fcoe_crc_eof);
+
+ stats->RxFrames++;
+ stats->RxWords += fr_len / FCOE_WORD_TO_BYTE;
+
+ fp = (struct fc_frame *)skb;
+ fc_frame_init(fp);
+ fr_dev(fp) = lport;
+ fr_sof(fp) = hp->fcoe_sof;
+
+ /* Copy out the CRC and EOF trailer for access */
+ if (skb_copy_bits(skb, fr_len, &crc_eof, sizeof(crc_eof))) {
+ kfree_skb(skb);
+ return;
+ }
+ fr_eof(fp) = crc_eof.fcoe_eof;
+ fr_crc(fp) = crc_eof.fcoe_crc32;
+ if (pskb_trim(skb, fr_len)) {
+ kfree_skb(skb);
+ return;
+ }
+
+ /*
+ * We only check CRC if no offload is available and if it is
+ * it's solicited data, in which case, the FCP layer would
+ * check it during the copy.
+ */
+ if (lport->crc_offload &&
+ skb->ip_summed == CHECKSUM_UNNECESSARY)
+ fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED;
+ else
+ fr_flags(fp) |= FCPHF_CRC_UNCHECKED;
+
+ fh = fc_frame_header_get(fp);
+ if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA &&
+ fh->fh_type == FC_TYPE_FCP) {
+ fc_exch_recv(lport, fp);
+ return;
+ }
+ if (fr_flags(fp) & FCPHF_CRC_UNCHECKED) {
+ if (le32_to_cpu(fr_crc(fp)) !=
+ ~crc32(~0, skb->data, fr_len)) {
+ if (stats->InvalidCRCCount < 5)
+ printk(KERN_WARNING "fcoe: dropping "
+ "frame with CRC error\n");
+ stats->InvalidCRCCount++;
+ stats->ErrorFrames++;
+ fc_frame_free(fp);
+ return;
+ }
+ fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED;
+ }
+ fc_exch_recv(lport, fp);
+}
+
+/**
+ * fcoe_percpu_receive_thread() - The per-CPU packet receive thread
+ * @arg: The per-CPU context
+ *
+ * Return: 0 for success
+ */
+int fcoe_percpu_receive_thread(void *arg)
+{
+ struct fcoe_percpu_s *p = arg;
+ struct sk_buff *skb;
+
set_user_nice(current, -20);
while (!kthread_should_stop()) {
@@ -1347,129 +1664,27 @@ int fcoe_percpu_receive_thread(void *arg)
spin_lock_bh(&p->fcoe_rx_list.lock);
}
spin_unlock_bh(&p->fcoe_rx_list.lock);
- fr = fcoe_dev_from_skb(skb);
- lp = fr->fr_dev;
- if (unlikely(lp == NULL)) {
- if (skb->destructor != fcoe_percpu_flush_done)
- FCOE_NETDEV_DBG(skb->dev, "NULL lport in skb");
- kfree_skb(skb);
- continue;
- }
-
- FCOE_NETDEV_DBG(skb->dev, "skb_info: len:%d data_len:%d "
- "head:%p data:%p tail:%p end:%p sum:%d dev:%s",
- skb->len, skb->data_len,
- skb->head, skb->data, skb_tail_pointer(skb),
- skb_end_pointer(skb), skb->csum,
- skb->dev ? skb->dev->name : "<NULL>");
-
- /*
- * Save source MAC address before discarding header.
- */
- port = lport_priv(lp);
- if (skb_is_nonlinear(skb))
- skb_linearize(skb); /* not ideal */
- mac = eth_hdr(skb)->h_source;
-
- /*
- * Frame length checks and setting up the header pointers
- * was done in fcoe_rcv already.
- */
- hp = (struct fcoe_hdr *) skb_network_header(skb);
- fh = (struct fc_frame_header *) skb_transport_header(skb);
-
- stats = fc_lport_get_stats(lp);
- if (unlikely(FC_FCOE_DECAPS_VER(hp) != FC_FCOE_VER)) {
- if (stats->ErrorFrames < 5)
- printk(KERN_WARNING "fcoe: FCoE version "
- "mismatch: The frame has "
- "version %x, but the "
- "initiator supports version "
- "%x\n", FC_FCOE_DECAPS_VER(hp),
- FC_FCOE_VER);
- stats->ErrorFrames++;
- kfree_skb(skb);
- continue;
- }
-
- skb_pull(skb, sizeof(struct fcoe_hdr));
- fr_len = skb->len - sizeof(struct fcoe_crc_eof);
-
- stats->RxFrames++;
- stats->RxWords += fr_len / FCOE_WORD_TO_BYTE;
-
- fp = (struct fc_frame *)skb;
- fc_frame_init(fp);
- fr_dev(fp) = lp;
- fr_sof(fp) = hp->fcoe_sof;
-
- /* Copy out the CRC and EOF trailer for access */
- if (skb_copy_bits(skb, fr_len, &crc_eof, sizeof(crc_eof))) {
- kfree_skb(skb);
- continue;
- }
- fr_eof(fp) = crc_eof.fcoe_eof;
- fr_crc(fp) = crc_eof.fcoe_crc32;
- if (pskb_trim(skb, fr_len)) {
- kfree_skb(skb);
- continue;
- }
-
- /*
- * We only check CRC if no offload is available and if it is
- * it's solicited data, in which case, the FCP layer would
- * check it during the copy.
- */
- if (lp->crc_offload && skb->ip_summed == CHECKSUM_UNNECESSARY)
- fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED;
- else
- fr_flags(fp) |= FCPHF_CRC_UNCHECKED;
-
- fh = fc_frame_header_get(fp);
- if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA &&
- fh->fh_type == FC_TYPE_FCP) {
- fc_exch_recv(lp, fp);
- continue;
- }
- if (fr_flags(fp) & FCPHF_CRC_UNCHECKED) {
- if (le32_to_cpu(fr_crc(fp)) !=
- ~crc32(~0, skb->data, fr_len)) {
- if (stats->InvalidCRCCount < 5)
- printk(KERN_WARNING "fcoe: dropping "
- "frame with CRC error\n");
- stats->InvalidCRCCount++;
- stats->ErrorFrames++;
- fc_frame_free(fp);
- continue;
- }
- fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED;
- }
- if (unlikely(port->fcoe->ctlr.flogi_oxid != FC_XID_UNKNOWN) &&
- fcoe_ctlr_recv_flogi(&port->fcoe->ctlr, fp, mac)) {
- fc_frame_free(fp);
- continue;
- }
- fc_exch_recv(lp, fp);
+ fcoe_recv_frame(skb);
}
return 0;
}
/**
- * fcoe_check_wait_queue() - attempt to clear the transmit backlog
- * @lp: the fc_lport
+ * fcoe_check_wait_queue() - Attempt to clear the transmit backlog
+ * @lport: The local port whose backlog is to be cleared
*
- * This empties the wait_queue, dequeue the head of the wait_queue queue
- * and calls fcoe_start_io() for each packet, if all skb have been
- * transmitted, return qlen or -1 if a error occurs, then restore
- * wait_queue and try again later.
+ * This empties the wait_queue, dequeues the head of the wait_queue queue
+ * and calls fcoe_start_io() for each packet. If all skb have been
+ * transmitted it returns the qlen. If an error occurs it restores
+ * wait_queue (to try again later) and returns -1.
*
- * The wait_queue is used when the skb transmit fails. skb will go
- * in the wait_queue which will be emptied by the timer function or
+ * The wait_queue is used when the skb transmit fails. The failed skb
+ * will go in the wait_queue which will be emptied by the timer function or
* by the next skb transmit.
*/
-static void fcoe_check_wait_queue(struct fc_lport *lp, struct sk_buff *skb)
+static void fcoe_check_wait_queue(struct fc_lport *lport, struct sk_buff *skb)
{
- struct fcoe_port *port = lport_priv(lp);
+ struct fcoe_port *port = lport_priv(lport);
int rc;
spin_lock_bh(&port->fcoe_pending_queue.lock);
@@ -1501,19 +1716,19 @@ static void fcoe_check_wait_queue(struct fc_lport *lp, struct sk_buff *skb)
}
if (port->fcoe_pending_queue.qlen < FCOE_LOW_QUEUE_DEPTH)
- lp->qfull = 0;
+ lport->qfull = 0;
if (port->fcoe_pending_queue.qlen && !timer_pending(&port->timer))
mod_timer(&port->timer, jiffies + 2);
port->fcoe_pending_queue_active = 0;
out:
if (port->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH)
- lp->qfull = 1;
+ lport->qfull = 1;
spin_unlock_bh(&port->fcoe_pending_queue.lock);
return;
}
/**
- * fcoe_dev_setup() - setup link change notification interface
+ * fcoe_dev_setup() - Setup the link change notification interface
*/
static void fcoe_dev_setup(void)
{
@@ -1521,7 +1736,7 @@ static void fcoe_dev_setup(void)
}
/**
- * fcoe_dev_cleanup() - cleanup link change notification interface
+ * fcoe_dev_cleanup() - Cleanup the link change notification interface
*/
static void fcoe_dev_cleanup(void)
{
@@ -1529,19 +1744,19 @@ static void fcoe_dev_cleanup(void)
}
/**
- * fcoe_device_notification() - netdev event notification callback
- * @notifier: context of the notification
- * @event: type of event
- * @ptr: fixed array for output parsed ifname
+ * fcoe_device_notification() - Handler for net device events
+ * @notifier: The context of the notification
+ * @event: The type of event
+ * @ptr: The net device that the event was on
*
- * This function is called by the ethernet driver in case of link change event
+ * This function is called by the Ethernet driver in case of link change event.
*
* Returns: 0 for success
*/
static int fcoe_device_notification(struct notifier_block *notifier,
ulong event, void *ptr)
{
- struct fc_lport *lp = NULL;
+ struct fc_lport *lport = NULL;
struct net_device *netdev = ptr;
struct fcoe_interface *fcoe;
struct fcoe_port *port;
@@ -1552,11 +1767,11 @@ static int fcoe_device_notification(struct notifier_block *notifier,
list_for_each_entry(fcoe, &fcoe_hostlist, list) {
if (fcoe->netdev == netdev) {
- lp = fcoe->ctlr.lp;
+ lport = fcoe->ctlr.lp;
break;
}
}
- if (lp == NULL) {
+ if (!lport) {
rc = NOTIFY_DONE;
goto out;
}
@@ -1570,10 +1785,12 @@ static int fcoe_device_notification(struct notifier_block *notifier,
case NETDEV_CHANGE:
break;
case NETDEV_CHANGEMTU:
+ if (netdev->features & NETIF_F_FCOE_MTU)
+ break;
mfs = netdev->mtu - (sizeof(struct fcoe_hdr) +
sizeof(struct fcoe_crc_eof));
if (mfs >= FC_MIN_MAX_FRAME)
- fc_set_mfs(lp, mfs);
+ fc_set_mfs(lport, mfs);
break;
case NETDEV_REGISTER:
break;
@@ -1588,22 +1805,22 @@ static int fcoe_device_notification(struct notifier_block *notifier,
FCOE_NETDEV_DBG(netdev, "Unknown event %ld "
"from netdev netlink\n", event);
}
- if (link_possible && !fcoe_link_ok(lp))
+ if (link_possible && !fcoe_link_ok(lport))
fcoe_ctlr_link_up(&fcoe->ctlr);
else if (fcoe_ctlr_link_down(&fcoe->ctlr)) {
- stats = fc_lport_get_stats(lp);
+ stats = fc_lport_get_stats(lport);
stats->LinkFailureCount++;
- fcoe_clean_pending_queue(lp);
+ fcoe_clean_pending_queue(lport);
}
out:
return rc;
}
/**
- * fcoe_if_to_netdev() - parse a name buffer to get netdev
- * @buffer: incoming buffer to be copied
+ * fcoe_if_to_netdev() - Parse a name buffer to get a net device
+ * @buffer: The name of the net device
*
- * Returns: NULL or ptr to net_device
+ * Returns: NULL or a ptr to net_device
*/
static struct net_device *fcoe_if_to_netdev(const char *buffer)
{
@@ -1621,9 +1838,11 @@ static struct net_device *fcoe_if_to_netdev(const char *buffer)
}
/**
- * fcoe_destroy() - handles the destroy from sysfs
- * @buffer: expected to be an eth if name
- * @kp: associated kernel param
+ * fcoe_destroy() - Destroy a FCoE interface
+ * @buffer: The name of the Ethernet interface to be destroyed
+ * @kp: The associated kernel parameter
+ *
+ * Called from sysfs.
*
* Returns: 0 for success
*/
@@ -1631,7 +1850,7 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp)
{
struct fcoe_interface *fcoe;
struct net_device *netdev;
- int rc;
+ int rc = 0;
mutex_lock(&fcoe_config_mutex);
#ifdef CONFIG_FCOE_MODULE
@@ -1670,6 +1889,10 @@ out_nodev:
return rc;
}
+/**
+ * fcoe_destroy_work() - Destroy a FCoE port in a deferred work context
+ * @work: Handle to the FCoE port to be destroyed
+ */
static void fcoe_destroy_work(struct work_struct *work)
{
struct fcoe_port *port;
@@ -1681,9 +1904,11 @@ static void fcoe_destroy_work(struct work_struct *work)
}
/**
- * fcoe_create() - Handles the create call from sysfs
- * @buffer: expected to be an eth if name
- * @kp: associated kernel param
+ * fcoe_create() - Create a fcoe interface
+ * @buffer: The name of the Ethernet interface to create on
+ * @kp: The associated kernel param
+ *
+ * Called from sysfs.
*
* Returns: 0 for success
*/
@@ -1726,7 +1951,7 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp)
goto out_putdev;
}
- lport = fcoe_if_create(fcoe, &netdev->dev);
+ lport = fcoe_if_create(fcoe, &netdev->dev, 0);
if (IS_ERR(lport)) {
printk(KERN_ERR "fcoe: Failed to create interface (%s)\n",
netdev->name);
@@ -1762,16 +1987,9 @@ out_nodev:
return rc;
}
-module_param_call(create, fcoe_create, NULL, NULL, S_IWUSR);
-__MODULE_PARM_TYPE(create, "string");
-MODULE_PARM_DESC(create, "Create fcoe fcoe using net device passed in.");
-module_param_call(destroy, fcoe_destroy, NULL, NULL, S_IWUSR);
-__MODULE_PARM_TYPE(destroy, "string");
-MODULE_PARM_DESC(destroy, "Destroy fcoe fcoe");
-
/**
- * fcoe_link_ok() - Check if link is ok for the fc_lport
- * @lp: ptr to the fc_lport
+ * fcoe_link_ok() - Check if the link is OK for a local port
+ * @lport: The local port to check link on
*
* Any permanently-disqualifying conditions have been previously checked.
* This also updates the speed setting, which may change with link for 100/1000.
@@ -1783,26 +2001,26 @@ MODULE_PARM_DESC(destroy, "Destroy fcoe fcoe");
* Returns: 0 if link is OK for use by FCoE.
*
*/
-int fcoe_link_ok(struct fc_lport *lp)
+int fcoe_link_ok(struct fc_lport *lport)
{
- struct fcoe_port *port = lport_priv(lp);
- struct net_device *dev = port->fcoe->netdev;
+ struct fcoe_port *port = lport_priv(lport);
+ struct net_device *netdev = port->fcoe->netdev;
struct ethtool_cmd ecmd = { ETHTOOL_GSET };
- if ((dev->flags & IFF_UP) && netif_carrier_ok(dev) &&
- (!dev_ethtool_get_settings(dev, &ecmd))) {
- lp->link_supported_speeds &=
+ if ((netdev->flags & IFF_UP) && netif_carrier_ok(netdev) &&
+ (!dev_ethtool_get_settings(netdev, &ecmd))) {
+ lport->link_supported_speeds &=
~(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT);
if (ecmd.supported & (SUPPORTED_1000baseT_Half |
SUPPORTED_1000baseT_Full))
- lp->link_supported_speeds |= FC_PORTSPEED_1GBIT;
+ lport->link_supported_speeds |= FC_PORTSPEED_1GBIT;
if (ecmd.supported & SUPPORTED_10000baseT_Full)
- lp->link_supported_speeds |=
+ lport->link_supported_speeds |=
FC_PORTSPEED_10GBIT;
if (ecmd.speed == SPEED_1000)
- lp->link_speed = FC_PORTSPEED_1GBIT;
+ lport->link_speed = FC_PORTSPEED_1GBIT;
if (ecmd.speed == SPEED_10000)
- lp->link_speed = FC_PORTSPEED_10GBIT;
+ lport->link_speed = FC_PORTSPEED_10GBIT;
return 0;
}
@@ -1810,8 +2028,8 @@ int fcoe_link_ok(struct fc_lport *lp)
}
/**
- * fcoe_percpu_clean() - Clear the pending skbs for an lport
- * @lp: the fc_lport
+ * fcoe_percpu_clean() - Clear all pending skbs for an local port
+ * @lport: The local port whose skbs are to be cleared
*
* Must be called with fcoe_create_mutex held to single-thread completion.
*
@@ -1820,7 +2038,7 @@ int fcoe_link_ok(struct fc_lport *lp)
* there no packets that will be handled by the lport, but also that any
* threads already handling packet have returned.
*/
-void fcoe_percpu_clean(struct fc_lport *lp)
+void fcoe_percpu_clean(struct fc_lport *lport)
{
struct fcoe_percpu_s *pp;
struct fcoe_rcv_info *fr;
@@ -1838,7 +2056,7 @@ void fcoe_percpu_clean(struct fc_lport *lp)
skb = next) {
next = skb->next;
fr = fcoe_dev_from_skb(skb);
- if (fr->fr_dev == lp) {
+ if (fr->fr_dev == lport) {
__skb_unlink(skb, list);
kfree_skb(skb);
}
@@ -1867,13 +2085,11 @@ void fcoe_percpu_clean(struct fc_lport *lp)
/**
* fcoe_clean_pending_queue() - Dequeue a skb and free it
- * @lp: the corresponding fc_lport
- *
- * Returns: none
+ * @lport: The local port to dequeue a skb on
*/
-void fcoe_clean_pending_queue(struct fc_lport *lp)
+void fcoe_clean_pending_queue(struct fc_lport *lport)
{
- struct fcoe_port *port = lport_priv(lp);
+ struct fcoe_port *port = lport_priv(lport);
struct sk_buff *skb;
spin_lock_bh(&port->fcoe_pending_queue.lock);
@@ -1886,10 +2102,10 @@ void fcoe_clean_pending_queue(struct fc_lport *lp)
}
/**
- * fcoe_reset() - Resets the fcoe
- * @shost: shost the reset is from
+ * fcoe_reset() - Reset a local port
+ * @shost: The SCSI host associated with the local port to be reset
*
- * Returns: always 0
+ * Returns: Always 0 (return value required by FC transport template)
*/
int fcoe_reset(struct Scsi_Host *shost)
{
@@ -1899,30 +2115,33 @@ int fcoe_reset(struct Scsi_Host *shost)
}
/**
- * fcoe_hostlist_lookup_port() - find the corresponding lport by a given device
- * @dev: this is currently ptr to net_device
+ * fcoe_hostlist_lookup_port() - Find the FCoE interface associated with a net device
+ * @netdev: The net device used as a key
+ *
+ * Locking: Must be called with the RNL mutex held.
*
- * Returns: NULL or the located fcoe_port
- * Locking: must be called with the RNL mutex held
+ * Returns: NULL or the FCoE interface
*/
static struct fcoe_interface *
-fcoe_hostlist_lookup_port(const struct net_device *dev)
+fcoe_hostlist_lookup_port(const struct net_device *netdev)
{
struct fcoe_interface *fcoe;
list_for_each_entry(fcoe, &fcoe_hostlist, list) {
- if (fcoe->netdev == dev)
+ if (fcoe->netdev == netdev)
return fcoe;
}
return NULL;
}
/**
- * fcoe_hostlist_lookup() - Find the corresponding lport by netdev
- * @netdev: ptr to net_device
+ * fcoe_hostlist_lookup() - Find the local port associated with a
+ * given net device
+ * @netdev: The netdevice used as a key
*
- * Returns: 0 for success
- * Locking: must be called with the RTNL mutex held
+ * Locking: Must be called with the RTNL mutex held
+ *
+ * Returns: NULL or the local port
*/
static struct fc_lport *fcoe_hostlist_lookup(const struct net_device *netdev)
{
@@ -1933,11 +2152,13 @@ static struct fc_lport *fcoe_hostlist_lookup(const struct net_device *netdev)
}
/**
- * fcoe_hostlist_add() - Add a lport to lports list
- * @lp: ptr to the fc_lport to be added
+ * fcoe_hostlist_add() - Add the FCoE interface identified by a local
+ * port to the hostlist
+ * @lport: The local port that identifies the FCoE interface to be added
*
- * Returns: 0 for success
* Locking: must be called with the RTNL mutex held
+ *
+ * Returns: 0 for success
*/
static int fcoe_hostlist_add(const struct fc_lport *lport)
{
@@ -1954,15 +2175,15 @@ static int fcoe_hostlist_add(const struct fc_lport *lport)
}
/**
- * fcoe_init() - fcoe module loading initialization
+ * fcoe_init() - Initialize fcoe.ko
*
- * Returns 0 on success, negative on failure
+ * Returns: 0 on success, or a negative value on failure
*/
static int __init fcoe_init(void)
{
+ struct fcoe_percpu_s *p;
unsigned int cpu;
int rc = 0;
- struct fcoe_percpu_s *p;
mutex_lock(&fcoe_config_mutex);
@@ -1999,15 +2220,15 @@ out_free:
module_init(fcoe_init);
/**
- * fcoe_exit() - fcoe module unloading cleanup
+ * fcoe_exit() - Clean up fcoe.ko
*
- * Returns 0 on success, negative on failure
+ * Returns: 0 on success or a negative value on failure
*/
static void __exit fcoe_exit(void)
{
- unsigned int cpu;
struct fcoe_interface *fcoe, *tmp;
struct fcoe_port *port;
+ unsigned int cpu;
mutex_lock(&fcoe_config_mutex);
@@ -2033,9 +2254,238 @@ static void __exit fcoe_exit(void)
/* flush any asyncronous interface destroys,
* this should happen after the netdev notifier is unregistered */
flush_scheduled_work();
+ /* That will flush out all the N_Ports on the hostlist, but now we
+ * may have NPIV VN_Ports scheduled for destruction */
+ flush_scheduled_work();
/* detach from scsi transport
* must happen after all destroys are done, therefor after the flush */
fcoe_if_exit();
}
module_exit(fcoe_exit);
+
+/**
+ * fcoe_flogi_resp() - FCoE specific FLOGI and FDISC response handler
+ * @seq: active sequence in the FLOGI or FDISC exchange
+ * @fp: response frame, or error encoded in a pointer (timeout)
+ * @arg: pointer the the fcoe_ctlr structure
+ *
+ * This handles MAC address managment for FCoE, then passes control on to
+ * the libfc FLOGI response handler.
+ */
+static void fcoe_flogi_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg)
+{
+ struct fcoe_ctlr *fip = arg;
+ struct fc_exch *exch = fc_seq_exch(seq);
+ struct fc_lport *lport = exch->lp;
+ u8 *mac;
+
+ if (IS_ERR(fp))
+ goto done;
+
+ mac = fr_cb(fp)->granted_mac;
+ if (is_zero_ether_addr(mac)) {
+ /* pre-FIP */
+ if (fcoe_ctlr_recv_flogi(fip, lport, fp)) {
+ fc_frame_free(fp);
+ return;
+ }
+ }
+ fcoe_update_src_mac(lport, mac);
+done:
+ fc_lport_flogi_resp(seq, fp, lport);
+}
+
+/**
+ * fcoe_logo_resp() - FCoE specific LOGO response handler
+ * @seq: active sequence in the LOGO exchange
+ * @fp: response frame, or error encoded in a pointer (timeout)
+ * @arg: pointer the the fcoe_ctlr structure
+ *
+ * This handles MAC address managment for FCoE, then passes control on to
+ * the libfc LOGO response handler.
+ */
+static void fcoe_logo_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg)
+{
+ struct fc_lport *lport = arg;
+ static u8 zero_mac[ETH_ALEN] = { 0 };
+
+ if (!IS_ERR(fp))
+ fcoe_update_src_mac(lport, zero_mac);
+ fc_lport_logo_resp(seq, fp, lport);
+}
+
+/**
+ * fcoe_elsct_send - FCoE specific ELS handler
+ *
+ * This does special case handling of FIP encapsualted ELS exchanges for FCoE,
+ * using FCoE specific response handlers and passing the FIP controller as
+ * the argument (the lport is still available from the exchange).
+ *
+ * Most of the work here is just handed off to the libfc routine.
+ */
+static struct fc_seq *fcoe_elsct_send(struct fc_lport *lport, u32 did,
+ struct fc_frame *fp, unsigned int op,
+ void (*resp)(struct fc_seq *,
+ struct fc_frame *,
+ void *),
+ void *arg, u32 timeout)
+{
+ struct fcoe_port *port = lport_priv(lport);
+ struct fcoe_interface *fcoe = port->fcoe;
+ struct fcoe_ctlr *fip = &fcoe->ctlr;
+ struct fc_frame_header *fh = fc_frame_header_get(fp);
+
+ switch (op) {
+ case ELS_FLOGI:
+ case ELS_FDISC:
+ return fc_elsct_send(lport, did, fp, op, fcoe_flogi_resp,
+ fip, timeout);
+ case ELS_LOGO:
+ /* only hook onto fabric logouts, not port logouts */
+ if (ntoh24(fh->fh_d_id) != FC_FID_FLOGI)
+ break;
+ return fc_elsct_send(lport, did, fp, op, fcoe_logo_resp,
+ lport, timeout);
+ }
+ return fc_elsct_send(lport, did, fp, op, resp, arg, timeout);
+}
+
+/**
+ * fcoe_vport_create() - create an fc_host/scsi_host for a vport
+ * @vport: fc_vport object to create a new fc_host for
+ * @disabled: start the new fc_host in a disabled state by default?
+ *
+ * Returns: 0 for success
+ */
+static int fcoe_vport_create(struct fc_vport *vport, bool disabled)
+{
+ struct Scsi_Host *shost = vport_to_shost(vport);
+ struct fc_lport *n_port = shost_priv(shost);
+ struct fcoe_port *port = lport_priv(n_port);
+ struct fcoe_interface *fcoe = port->fcoe;
+ struct net_device *netdev = fcoe->netdev;
+ struct fc_lport *vn_port;
+
+ mutex_lock(&fcoe_config_mutex);
+ vn_port = fcoe_if_create(fcoe, &vport->dev, 1);
+ mutex_unlock(&fcoe_config_mutex);
+
+ if (IS_ERR(vn_port)) {
+ printk(KERN_ERR "fcoe: fcoe_vport_create(%s) failed\n",
+ netdev->name);
+ return -EIO;
+ }
+
+ if (disabled) {
+ fc_vport_set_state(vport, FC_VPORT_DISABLED);
+ } else {
+ vn_port->boot_time = jiffies;
+ fc_fabric_login(vn_port);
+ fc_vport_setlink(vn_port);
+ }
+ return 0;
+}
+
+/**
+ * fcoe_vport_destroy() - destroy the fc_host/scsi_host for a vport
+ * @vport: fc_vport object that is being destroyed
+ *
+ * Returns: 0 for success
+ */
+static int fcoe_vport_destroy(struct fc_vport *vport)
+{
+ struct Scsi_Host *shost = vport_to_shost(vport);
+ struct fc_lport *n_port = shost_priv(shost);
+ struct fc_lport *vn_port = vport->dd_data;
+ struct fcoe_port *port = lport_priv(vn_port);
+
+ mutex_lock(&n_port->lp_mutex);
+ list_del(&vn_port->list);
+ mutex_unlock(&n_port->lp_mutex);
+ schedule_work(&port->destroy_work);
+ return 0;
+}
+
+/**
+ * fcoe_vport_disable() - change vport state
+ * @vport: vport to bring online/offline
+ * @disable: should the vport be disabled?
+ */
+static int fcoe_vport_disable(struct fc_vport *vport, bool disable)
+{
+ struct fc_lport *lport = vport->dd_data;
+
+ if (disable) {
+ fc_vport_set_state(vport, FC_VPORT_DISABLED);
+ fc_fabric_logoff(lport);
+ } else {
+ lport->boot_time = jiffies;
+ fc_fabric_login(lport);
+ fc_vport_setlink(lport);
+ }
+
+ return 0;
+}
+
+/**
+ * fcoe_vport_set_symbolic_name() - append vport string to symbolic name
+ * @vport: fc_vport with a new symbolic name string
+ *
+ * After generating a new symbolic name string, a new RSPN_ID request is
+ * sent to the name server. There is no response handler, so if it fails
+ * for some reason it will not be retried.
+ */
+static void fcoe_set_vport_symbolic_name(struct fc_vport *vport)
+{
+ struct fc_lport *lport = vport->dd_data;
+ struct fc_frame *fp;
+ size_t len;
+
+ snprintf(fc_host_symbolic_name(lport->host), FC_SYMBOLIC_NAME_SIZE,
+ "%s v%s over %s : %s", FCOE_NAME, FCOE_VERSION,
+ fcoe_netdev(lport)->name, vport->symbolic_name);
+
+ if (lport->state != LPORT_ST_READY)
+ return;
+
+ len = strnlen(fc_host_symbolic_name(lport->host), 255);
+ fp = fc_frame_alloc(lport,
+ sizeof(struct fc_ct_hdr) +
+ sizeof(struct fc_ns_rspn) + len);
+ if (!fp)
+ return;
+ lport->tt.elsct_send(lport, FC_FID_DIR_SERV, fp, FC_NS_RSPN_ID,
+ NULL, NULL, 3 * lport->r_a_tov);
+}
+
+/**
+ * fcoe_get_lesb() - Fill the FCoE Link Error Status Block
+ * @lport: the local port
+ * @fc_lesb: the link error status block
+ */
+static void fcoe_get_lesb(struct fc_lport *lport,
+ struct fc_els_lesb *fc_lesb)
+{
+ unsigned int cpu;
+ u32 lfc, vlfc, mdac;
+ struct fcoe_dev_stats *devst;
+ struct fcoe_fc_els_lesb *lesb;
+ struct net_device *netdev = fcoe_netdev(lport);
+
+ lfc = 0;
+ vlfc = 0;
+ mdac = 0;
+ lesb = (struct fcoe_fc_els_lesb *)fc_lesb;
+ memset(lesb, 0, sizeof(*lesb));
+ for_each_possible_cpu(cpu) {
+ devst = per_cpu_ptr(lport->dev_stats, cpu);
+ lfc += devst->LinkFailureCount;
+ vlfc += devst->VLinkFailureCount;
+ mdac += devst->MissDiscAdvCount;
+ }
+ lesb->lesb_link_fail = htonl(lfc);
+ lesb->lesb_vlink_fail = htonl(vlfc);
+ lesb->lesb_miss_fka = htonl(mdac);
+ lesb->lesb_fcs_error = htonl(dev_get_stats(netdev)->rx_crc_errors);
+}
diff --git a/drivers/scsi/fcoe/fcoe.h b/drivers/scsi/fcoe/fcoe.h
index ce7f60f..c69b2c5 100644
--- a/drivers/scsi/fcoe/fcoe.h
+++ b/drivers/scsi/fcoe/fcoe.h
@@ -32,7 +32,7 @@
#define FCOE_NAME "fcoe"
#define FCOE_VENDOR "Open-FCoE.org"
-#define FCOE_MAX_LUN 255
+#define FCOE_MAX_LUN 0xFFFF
#define FCOE_MAX_FCP_TARGET 256
#define FCOE_MAX_OUTSTANDING_COMMANDS 1024
@@ -40,11 +40,17 @@
#define FCOE_MIN_XID 0x0000 /* the min xid supported by fcoe_sw */
#define FCOE_MAX_XID 0x0FFF /* the max xid supported by fcoe_sw */
+/*
+ * Max MTU for FCoE: 14 (FCoE header) + 24 (FC header) + 2112 (max FC payload)
+ * + 4 (FC CRC) + 4 (FCoE trailer) = 2158 bytes
+ */
+#define FCOE_MTU 2158
+
unsigned int fcoe_debug_logging;
module_param_named(debug_logging, fcoe_debug_logging, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels");
-#define FCOE_LOGGING 0x01 /* General logging, not categorized */
+#define FCOE_LOGGING 0x01 /* General logging, not categorized */
#define FCOE_NETDEV_LOGGING 0x02 /* Netdevice logging */
#define FCOE_CHECK_LOGGING(LEVEL, CMD) \
@@ -64,8 +70,13 @@ do { \
printk(KERN_INFO "fcoe: %s: " fmt, \
netdev->name, ##args);)
-/*
- * this percpu struct for fcoe
+/**
+ * struct fcoe_percpu_s - The per-CPU context for FCoE receive threads
+ * @thread: The thread context
+ * @fcoe_rx_list: The queue of pending packets to process
+ * @page: The memory page for calculating frame trailer CRCs
+ * @crc_eof_offset: The offset into the CRC page pointing to available
+ * memory for a new trailer
*/
struct fcoe_percpu_s {
struct task_struct *thread;
@@ -74,37 +85,62 @@ struct fcoe_percpu_s {
int crc_eof_offset;
};
-/*
- * an FCoE interface, 1:1 with netdev
+/**
+ * struct fcoe_interface - A FCoE interface
+ * @list: Handle for a list of FCoE interfaces
+ * @netdev: The associated net device
+ * @fcoe_packet_type: FCoE packet type
+ * @fip_packet_type: FIP packet type
+ * @ctlr: The FCoE controller (for FIP)
+ * @oem: The offload exchange manager for all local port
+ * instances associated with this port
+ * @kref: The kernel reference
+ *
+ * This structure is 1:1 with a net devive.
*/
struct fcoe_interface {
- struct list_head list;
- struct net_device *netdev;
- struct packet_type fcoe_packet_type;
- struct packet_type fip_packet_type;
- struct fcoe_ctlr ctlr;
- struct fc_exch_mgr *oem; /* offload exchange manager */
- struct kref kref;
+ struct list_head list;
+ struct net_device *netdev;
+ struct packet_type fcoe_packet_type;
+ struct packet_type fip_packet_type;
+ struct fcoe_ctlr ctlr;
+ struct fc_exch_mgr *oem;
+ struct kref kref;
};
-/*
- * the FCoE private structure that's allocated along with the
- * Scsi_Host and libfc fc_lport structures
+/**
+ * struct fcoe_port - The FCoE private structure
+ * @fcoe: The associated fcoe interface
+ * @lport: The associated local port
+ * @fcoe_pending_queue: The pending Rx queue of skbs
+ * @fcoe_pending_queue_active: Indicates if the pending queue is active
+ * @timer: The queue timer
+ * @destroy_work: Handle for work context
+ * (to prevent RTNL deadlocks)
+ * @data_srt_addr: Source address for data
+ *
+ * An instance of this structure is to be allocated along with the
+ * Scsi_Host and libfc fc_lport structures.
*/
struct fcoe_port {
struct fcoe_interface *fcoe;
- struct fc_lport *lport;
- struct sk_buff_head fcoe_pending_queue;
- u8 fcoe_pending_queue_active;
- struct timer_list timer; /* queue timer */
- struct work_struct destroy_work; /* to prevent rtnl deadlocks */
+ struct fc_lport *lport;
+ struct sk_buff_head fcoe_pending_queue;
+ u8 fcoe_pending_queue_active;
+ struct timer_list timer;
+ struct work_struct destroy_work;
+ u8 data_src_addr[ETH_ALEN];
};
#define fcoe_from_ctlr(fip) container_of(fip, struct fcoe_interface, ctlr)
-static inline struct net_device *fcoe_netdev(const struct fc_lport *lp)
+/**
+ * fcoe_netdev() - Return the net device associated with a local port
+ * @lport: The local port to get the net device from
+ */
+static inline struct net_device *fcoe_netdev(const struct fc_lport *lport)
{
- return ((struct fcoe_port *)lport_priv(lp))->fcoe->netdev;
+ return ((struct fcoe_port *)lport_priv(lport))->fcoe->netdev;
}
#endif /* _FCOE_H_ */
diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c
index 11ae5c9..9823291 100644
--- a/drivers/scsi/fcoe/libfcoe.c
+++ b/drivers/scsi/fcoe/libfcoe.c
@@ -59,26 +59,30 @@ unsigned int libfcoe_debug_logging;
module_param_named(debug_logging, libfcoe_debug_logging, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels");
-#define LIBFCOE_LOGGING 0x01 /* General logging, not categorized */
+#define LIBFCOE_LOGGING 0x01 /* General logging, not categorized */
#define LIBFCOE_FIP_LOGGING 0x02 /* FIP logging */
-#define LIBFCOE_CHECK_LOGGING(LEVEL, CMD) \
-do { \
- if (unlikely(libfcoe_debug_logging & LEVEL)) \
- do { \
- CMD; \
- } while (0); \
+#define LIBFCOE_CHECK_LOGGING(LEVEL, CMD) \
+do { \
+ if (unlikely(libfcoe_debug_logging & LEVEL)) \
+ do { \
+ CMD; \
+ } while (0); \
} while (0)
#define LIBFCOE_DBG(fmt, args...) \
LIBFCOE_CHECK_LOGGING(LIBFCOE_LOGGING, \
printk(KERN_INFO "libfcoe: " fmt, ##args);)
-#define LIBFCOE_FIP_DBG(fmt, args...) \
+#define LIBFCOE_FIP_DBG(fip, fmt, args...) \
LIBFCOE_CHECK_LOGGING(LIBFCOE_FIP_LOGGING, \
- printk(KERN_INFO "fip: " fmt, ##args);)
+ printk(KERN_INFO "host%d: fip: " fmt, \
+ (fip)->lp->host->host_no, ##args);)
-/*
+/**
+ * fcoe_ctlr_mtu_valid() - Check if a FCF's MTU is valid
+ * @fcf: The FCF to check
+ *
* Return non-zero if FCF fcoe_size has been validated.
*/
static inline int fcoe_ctlr_mtu_valid(const struct fcoe_fcf *fcf)
@@ -86,7 +90,10 @@ static inline int fcoe_ctlr_mtu_valid(const struct fcoe_fcf *fcf)
return (fcf->flags & FIP_FL_SOL) != 0;
}
-/*
+/**
+ * fcoe_ctlr_fcf_usable() - Check if a FCF is usable
+ * @fcf: The FCF to check
+ *
* Return non-zero if the FCF is usable.
*/
static inline int fcoe_ctlr_fcf_usable(struct fcoe_fcf *fcf)
@@ -97,12 +104,13 @@ static inline int fcoe_ctlr_fcf_usable(struct fcoe_fcf *fcf)
}
/**
- * fcoe_ctlr_init() - Initialize the FCoE Controller instance.
- * @fip: FCoE controller.
+ * fcoe_ctlr_init() - Initialize the FCoE Controller instance
+ * @fip: The FCoE controller to initialize
*/
void fcoe_ctlr_init(struct fcoe_ctlr *fip)
{
fip->state = FIP_ST_LINK_WAIT;
+ fip->mode = FIP_ST_AUTO;
INIT_LIST_HEAD(&fip->fcfs);
spin_lock_init(&fip->lock);
fip->flogi_oxid = FC_XID_UNKNOWN;
@@ -114,8 +122,8 @@ void fcoe_ctlr_init(struct fcoe_ctlr *fip)
EXPORT_SYMBOL(fcoe_ctlr_init);
/**
- * fcoe_ctlr_reset_fcfs() - Reset and free all FCFs for a controller.
- * @fip: FCoE controller.
+ * fcoe_ctlr_reset_fcfs() - Reset and free all FCFs for a controller
+ * @fip: The FCoE controller whose FCFs are to be reset
*
* Called with &fcoe_ctlr lock held.
*/
@@ -134,8 +142,8 @@ static void fcoe_ctlr_reset_fcfs(struct fcoe_ctlr *fip)
}
/**
- * fcoe_ctlr_destroy() - Disable and tear-down the FCoE controller.
- * @fip: FCoE controller.
+ * fcoe_ctlr_destroy() - Disable and tear down a FCoE controller
+ * @fip: The FCoE controller to tear down
*
* This is called by FCoE drivers before freeing the &fcoe_ctlr.
*
@@ -148,9 +156,7 @@ static void fcoe_ctlr_reset_fcfs(struct fcoe_ctlr *fip)
void fcoe_ctlr_destroy(struct fcoe_ctlr *fip)
{
cancel_work_sync(&fip->recv_work);
- spin_lock_bh(&fip->fip_recv_list.lock);
- __skb_queue_purge(&fip->fip_recv_list);
- spin_unlock_bh(&fip->fip_recv_list.lock);
+ skb_queue_purge(&fip->fip_recv_list);
spin_lock_bh(&fip->lock);
fip->state = FIP_ST_DISABLED;
@@ -162,8 +168,8 @@ void fcoe_ctlr_destroy(struct fcoe_ctlr *fip)
EXPORT_SYMBOL(fcoe_ctlr_destroy);
/**
- * fcoe_ctlr_fcoe_size() - Return the maximum FCoE size required for VN_Port.
- * @fip: FCoE controller.
+ * fcoe_ctlr_fcoe_size() - Return the maximum FCoE size required for VN_Port
+ * @fip: The FCoE controller to get the maximum FCoE size from
*
* Returns the maximum packet size including the FCoE header and trailer,
* but not including any Ethernet or VLAN headers.
@@ -180,9 +186,9 @@ static inline u32 fcoe_ctlr_fcoe_size(struct fcoe_ctlr *fip)
}
/**
- * fcoe_ctlr_solicit() - Send a solicitation.
- * @fip: FCoE controller.
- * @fcf: Destination FCF. If NULL, a multicast solicitation is sent.
+ * fcoe_ctlr_solicit() - Send a FIP solicitation
+ * @fip: The FCoE controller to send the solicitation on
+ * @fcf: The destination FCF (if NULL, a multicast solicitation is sent)
*/
static void fcoe_ctlr_solicit(struct fcoe_ctlr *fip, struct fcoe_fcf *fcf)
{
@@ -241,8 +247,8 @@ static void fcoe_ctlr_solicit(struct fcoe_ctlr *fip, struct fcoe_fcf *fcf)
}
/**
- * fcoe_ctlr_link_up() - Start FCoE controller.
- * @fip: FCoE controller.
+ * fcoe_ctlr_link_up() - Start FCoE controller
+ * @fip: The FCoE controller to start
*
* Called from the LLD when the network link is ready.
*/
@@ -255,11 +261,12 @@ void fcoe_ctlr_link_up(struct fcoe_ctlr *fip)
spin_unlock_bh(&fip->lock);
fc_linkup(fip->lp);
} else if (fip->state == FIP_ST_LINK_WAIT) {
- fip->state = FIP_ST_AUTO;
+ fip->state = fip->mode;
fip->last_link = 1;
fip->link = 1;
spin_unlock_bh(&fip->lock);
- LIBFCOE_FIP_DBG("%s", "setting AUTO mode.\n");
+ if (fip->state == FIP_ST_AUTO)
+ LIBFCOE_FIP_DBG(fip, "%s", "setting AUTO mode.\n");
fc_linkup(fip->lp);
fcoe_ctlr_solicit(fip, NULL);
} else
@@ -268,45 +275,23 @@ void fcoe_ctlr_link_up(struct fcoe_ctlr *fip)
EXPORT_SYMBOL(fcoe_ctlr_link_up);
/**
- * fcoe_ctlr_reset() - Reset FIP.
- * @fip: FCoE controller.
- * @new_state: FIP state to be entered.
- *
- * Returns non-zero if the link was up and now isn't.
+ * fcoe_ctlr_reset() - Reset a FCoE controller
+ * @fip: The FCoE controller to reset
*/
-static int fcoe_ctlr_reset(struct fcoe_ctlr *fip, enum fip_state new_state)
+static void fcoe_ctlr_reset(struct fcoe_ctlr *fip)
{
- struct fc_lport *lp = fip->lp;
- int link_dropped;
-
- spin_lock_bh(&fip->lock);
fcoe_ctlr_reset_fcfs(fip);
del_timer(&fip->timer);
- fip->state = new_state;
fip->ctlr_ka_time = 0;
fip->port_ka_time = 0;
fip->sol_time = 0;
fip->flogi_oxid = FC_XID_UNKNOWN;
fip->map_dest = 0;
- fip->last_link = 0;
- link_dropped = fip->link;
- fip->link = 0;
- spin_unlock_bh(&fip->lock);
-
- if (link_dropped)
- fc_linkdown(lp);
-
- if (new_state == FIP_ST_ENABLED) {
- fcoe_ctlr_solicit(fip, NULL);
- fc_linkup(lp);
- link_dropped = 0;
- }
- return link_dropped;
}
/**
- * fcoe_ctlr_link_down() - Stop FCoE controller.
- * @fip: FCoE controller.
+ * fcoe_ctlr_link_down() - Stop a FCoE controller
+ * @fip: The FCoE controller to be stopped
*
* Returns non-zero if the link was up and now isn't.
*
@@ -315,15 +300,29 @@ static int fcoe_ctlr_reset(struct fcoe_ctlr *fip, enum fip_state new_state)
*/
int fcoe_ctlr_link_down(struct fcoe_ctlr *fip)
{
- return fcoe_ctlr_reset(fip, FIP_ST_LINK_WAIT);
+ int link_dropped;
+
+ LIBFCOE_FIP_DBG(fip, "link down.\n");
+ spin_lock_bh(&fip->lock);
+ fcoe_ctlr_reset(fip);
+ link_dropped = fip->link;
+ fip->link = 0;
+ fip->last_link = 0;
+ fip->state = FIP_ST_LINK_WAIT;
+ spin_unlock_bh(&fip->lock);
+
+ if (link_dropped)
+ fc_linkdown(fip->lp);
+ return link_dropped;
}
EXPORT_SYMBOL(fcoe_ctlr_link_down);
/**
- * fcoe_ctlr_send_keep_alive() - Send a keep-alive to the selected FCF.
- * @fip: FCoE controller.
- * @ports: 0 for controller keep-alive, 1 for port keep-alive.
- * @sa: source MAC address.
+ * fcoe_ctlr_send_keep_alive() - Send a keep-alive to the selected FCF
+ * @fip: The FCoE controller to send the FKA on
+ * @lport: libfc fc_lport to send from
+ * @ports: 0 for controller keep-alive, 1 for port keep-alive
+ * @sa: The source MAC address
*
* A controller keep-alive is sent every fka_period (typically 8 seconds).
* The source MAC is the native MAC address.
@@ -332,7 +331,9 @@ EXPORT_SYMBOL(fcoe_ctlr_link_down);
* The source MAC is the assigned mapped source address.
* The destination is the FCF's F-port.
*/
-static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip, int ports, u8 *sa)
+static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip,
+ struct fc_lport *lport,
+ int ports, u8 *sa)
{
struct sk_buff *skb;
struct fip_kal {
@@ -350,8 +351,7 @@ static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip, int ports, u8 *sa)
if (!fcf || !fc_host_port_id(lp->host))
return;
- len = fcoe_ctlr_fcoe_size(fip) + sizeof(struct ethhdr);
- BUG_ON(len < sizeof(*kal) + sizeof(*vn));
+ len = sizeof(*kal) + ports * sizeof(*vn);
skb = dev_alloc_skb(len);
if (!skb)
return;
@@ -366,7 +366,7 @@ static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip, int ports, u8 *sa)
kal->fip.fip_op = htons(FIP_OP_CTRL);
kal->fip.fip_subcode = FIP_SC_KEEP_ALIVE;
kal->fip.fip_dl_len = htons((sizeof(kal->mac) +
- ports * sizeof(*vn)) / FIP_BPW);
+ ports * sizeof(*vn)) / FIP_BPW);
kal->fip.fip_flags = htons(FIP_FL_FPMA);
if (fip->spma)
kal->fip.fip_flags |= htons(FIP_FL_SPMA);
@@ -374,16 +374,14 @@ static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip, int ports, u8 *sa)
kal->mac.fd_desc.fip_dtype = FIP_DT_MAC;
kal->mac.fd_desc.fip_dlen = sizeof(kal->mac) / FIP_BPW;
memcpy(kal->mac.fd_mac, fip->ctl_src_addr, ETH_ALEN);
-
if (ports) {
vn = (struct fip_vn_desc *)(kal + 1);
vn->fd_desc.fip_dtype = FIP_DT_VN_ID;
vn->fd_desc.fip_dlen = sizeof(*vn) / FIP_BPW;
- memcpy(vn->fd_mac, fip->data_src_addr, ETH_ALEN);
+ memcpy(vn->fd_mac, fip->get_src_addr(lport), ETH_ALEN);
hton24(vn->fd_fc_id, fc_host_port_id(lp->host));
put_unaligned_be64(lp->wwpn, &vn->fd_wwpn);
}
-
skb_put(skb, len);
skb->protocol = htons(ETH_P_FIP);
skb_reset_mac_header(skb);
@@ -392,10 +390,10 @@ static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip, int ports, u8 *sa)
}
/**
- * fcoe_ctlr_encaps() - Encapsulate an ELS frame for FIP, without sending it.
- * @fip: FCoE controller.
- * @dtype: FIP descriptor type for the frame.
- * @skb: FCoE ELS frame including FC header but no FCoE headers.
+ * fcoe_ctlr_encaps() - Encapsulate an ELS frame for FIP, without sending it
+ * @fip: The FCoE controller for the ELS frame
+ * @dtype: The FIP descriptor type for the frame
+ * @skb: The FCoE ELS frame including FC header but no FCoE headers
*
* Returns non-zero error code on failure.
*
@@ -405,7 +403,7 @@ static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip, int ports, u8 *sa)
* Headroom includes the FIP encapsulation description, FIP header, and
* Ethernet header. The tailroom is for the FIP MAC descriptor.
*/
-static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip,
+static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, struct fc_lport *lport,
u8 dtype, struct sk_buff *skb)
{
struct fip_encaps_head {
@@ -449,8 +447,8 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip,
memset(mac, 0, sizeof(mac));
mac->fd_desc.fip_dtype = FIP_DT_MAC;
mac->fd_desc.fip_dlen = sizeof(*mac) / FIP_BPW;
- if (dtype != FIP_DT_FLOGI)
- memcpy(mac->fd_mac, fip->data_src_addr, ETH_ALEN);
+ if (dtype != FIP_DT_FLOGI && dtype != FIP_DT_FDISC)
+ memcpy(mac->fd_mac, fip->get_src_addr(lport), ETH_ALEN);
else if (fip->spma)
memcpy(mac->fd_mac, fip->ctl_src_addr, ETH_ALEN);
@@ -463,6 +461,7 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip,
/**
* fcoe_ctlr_els_send() - Send an ELS frame encapsulated by FIP if appropriate.
* @fip: FCoE controller.
+ * @lport: libfc fc_lport to send from
* @skb: FCoE ELS frame including FC header but no FCoE headers.
*
* Returns a non-zero error code if the frame should not be sent.
@@ -471,11 +470,13 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip,
* The caller must check that the length is a multiple of 4.
* The SKB must have enough headroom (28 bytes) and tailroom (8 bytes).
*/
-int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct sk_buff *skb)
+int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct fc_lport *lport,
+ struct sk_buff *skb)
{
struct fc_frame_header *fh;
u16 old_xid;
u8 op;
+ u8 mac[ETH_ALEN];
fh = (struct fc_frame_header *)skb->data;
op = *(u8 *)(fh + 1);
@@ -498,6 +499,8 @@ int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct sk_buff *skb)
if (fip->state == FIP_ST_NON_FIP)
return 0;
+ if (!fip->sel_fcf)
+ goto drop;
switch (op) {
case ELS_FLOGI:
@@ -530,14 +533,15 @@ int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct sk_buff *skb)
* FLOGI.
*/
fip->flogi_oxid = FC_XID_UNKNOWN;
- fc_fcoe_set_mac(fip->data_src_addr, fh->fh_s_id);
+ fc_fcoe_set_mac(mac, fh->fh_d_id);
+ fip->update_mac(lport, mac);
return 0;
default:
if (fip->state != FIP_ST_ENABLED)
goto drop;
return 0;
}
- if (fcoe_ctlr_encaps(fip, op, skb))
+ if (fcoe_ctlr_encaps(fip, lport, op, skb))
goto drop;
fip->send(fip, skb);
return -EINPROGRESS;
@@ -547,9 +551,9 @@ drop:
}
EXPORT_SYMBOL(fcoe_ctlr_els_send);
-/*
- * fcoe_ctlr_age_fcfs() - Reset and free all old FCFs for a controller.
- * @fip: FCoE controller.
+/**
+ * fcoe_ctlr_age_fcfs() - Reset and free all old FCFs for a controller
+ * @fip: The FCoE controller to free FCFs on
*
* Called with lock held.
*
@@ -558,14 +562,28 @@ EXPORT_SYMBOL(fcoe_ctlr_els_send);
* times its keep-alive period including fuzz.
*
* In addition, determine the time when an FCF selection can occur.
+ *
+ * Also, increment the MissDiscAdvCount when no advertisement is received
+ * for the corresponding FCF for 1.5 * FKA_ADV_PERIOD (FC-BB-5 LESB).
*/
static void fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)
{
struct fcoe_fcf *fcf;
struct fcoe_fcf *next;
unsigned long sel_time = 0;
+ unsigned long mda_time = 0;
list_for_each_entry_safe(fcf, next, &fip->fcfs, list) {
+ mda_time = fcf->fka_period + (fcf->fka_period >> 1);
+ if ((fip->sel_fcf == fcf) &&
+ (time_after(jiffies, fcf->time + mda_time))) {
+ mod_timer(&fip->timer, jiffies + mda_time);
+ fc_lport_get_stats(fip->lp)->MissDiscAdvCount++;
+ printk(KERN_INFO "libfcoe: host%d: Missing Discovery "
+ "Advertisement for fab %llx count %lld\n",
+ fip->lp->host->host_no, fcf->fabric_name,
+ fc_lport_get_stats(fip->lp)->MissDiscAdvCount);
+ }
if (time_after(jiffies, fcf->time + fcf->fka_period * 3 +
msecs_to_jiffies(FIP_FCF_FUZZ * 3))) {
if (fip->sel_fcf == fcf)
@@ -574,6 +592,7 @@ static void fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)
WARN_ON(!fip->fcf_count);
fip->fcf_count--;
kfree(fcf);
+ fc_lport_get_stats(fip->lp)->VLinkFailureCount++;
} else if (fcoe_ctlr_mtu_valid(fcf) &&
(!sel_time || time_before(sel_time, fcf->time))) {
sel_time = fcf->time;
@@ -590,14 +609,16 @@ static void fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)
}
/**
- * fcoe_ctlr_parse_adv() - Decode a FIP advertisement into a new FCF entry.
- * @skb: received FIP advertisement frame
- * @fcf: resulting FCF entry.
+ * fcoe_ctlr_parse_adv() - Decode a FIP advertisement into a new FCF entry
+ * @fip: The FCoE controller receiving the advertisement
+ * @skb: The received FIP advertisement frame
+ * @fcf: The resulting FCF entry
*
* Returns zero on a valid parsed advertisement,
* otherwise returns non zero value.
*/
-static int fcoe_ctlr_parse_adv(struct sk_buff *skb, struct fcoe_fcf *fcf)
+static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip,
+ struct sk_buff *skb, struct fcoe_fcf *fcf)
{
struct fip_header *fiph;
struct fip_desc *desc = NULL;
@@ -636,7 +657,7 @@ static int fcoe_ctlr_parse_adv(struct sk_buff *skb, struct fcoe_fcf *fcf)
((struct fip_mac_desc *)desc)->fd_mac,
ETH_ALEN);
if (!is_valid_ether_addr(fcf->fcf_mac)) {
- LIBFCOE_FIP_DBG("Invalid MAC address "
+ LIBFCOE_FIP_DBG(fip, "Invalid MAC address "
"in FIP adv\n");
return -EINVAL;
}
@@ -659,6 +680,8 @@ static int fcoe_ctlr_parse_adv(struct sk_buff *skb, struct fcoe_fcf *fcf)
if (dlen != sizeof(struct fip_fka_desc))
goto len_err;
fka = (struct fip_fka_desc *)desc;
+ if (fka->fd_flags & FIP_FKA_ADV_D)
+ fcf->fd_flags = 1;
t = ntohl(fka->fd_fka_period);
if (t >= FCOE_CTLR_MIN_FKA)
fcf->fka_period = msecs_to_jiffies(t);
@@ -670,7 +693,7 @@ static int fcoe_ctlr_parse_adv(struct sk_buff *skb, struct fcoe_fcf *fcf)
case FIP_DT_LOGO:
case FIP_DT_ELP:
default:
- LIBFCOE_FIP_DBG("unexpected descriptor type %x "
+ LIBFCOE_FIP_DBG(fip, "unexpected descriptor type %x "
"in FIP adv\n", desc->fip_dtype);
/* standard says ignore unknown descriptors >= 128 */
if (desc->fip_dtype < FIP_DT_VENDOR_BASE)
@@ -687,15 +710,15 @@ static int fcoe_ctlr_parse_adv(struct sk_buff *skb, struct fcoe_fcf *fcf)
return 0;
len_err:
- LIBFCOE_FIP_DBG("FIP length error in descriptor type %x len %zu\n",
+ LIBFCOE_FIP_DBG(fip, "FIP length error in descriptor type %x len %zu\n",
desc->fip_dtype, dlen);
return -EINVAL;
}
/**
- * fcoe_ctlr_recv_adv() - Handle an incoming advertisement.
- * @fip: FCoE controller.
- * @skb: Received FIP packet.
+ * fcoe_ctlr_recv_adv() - Handle an incoming advertisement
+ * @fip: The FCoE controller receiving the advertisement
+ * @skb: The received FIP packet
*/
static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb)
{
@@ -706,7 +729,7 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb)
int first = 0;
int mtu_valid;
- if (fcoe_ctlr_parse_adv(skb, &new))
+ if (fcoe_ctlr_parse_adv(fip, skb, &new))
return;
spin_lock_bh(&fip->lock);
@@ -752,7 +775,7 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb)
mtu_valid = fcoe_ctlr_mtu_valid(fcf);
fcf->time = jiffies;
if (!found) {
- LIBFCOE_FIP_DBG("New FCF for fab %llx map %x val %d\n",
+ LIBFCOE_FIP_DBG(fip, "New FCF for fab %llx map %x val %d\n",
fcf->fabric_name, fcf->fc_map, mtu_valid);
}
@@ -778,7 +801,7 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb)
*/
if (mtu_valid && !fip->sel_time && fcoe_ctlr_fcf_usable(fcf)) {
fip->sel_time = jiffies +
- msecs_to_jiffies(FCOE_CTLR_START_DELAY);
+ msecs_to_jiffies(FCOE_CTLR_START_DELAY);
if (!timer_pending(&fip->timer) ||
time_before(fip->sel_time, fip->timer.expires))
mod_timer(&fip->timer, fip->sel_time);
@@ -788,15 +811,15 @@ out:
}
/**
- * fcoe_ctlr_recv_els() - Handle an incoming FIP-encapsulated ELS frame.
- * @fip: FCoE controller.
- * @skb: Received FIP packet.
+ * fcoe_ctlr_recv_els() - Handle an incoming FIP encapsulated ELS frame
+ * @fip: The FCoE controller which received the packet
+ * @skb: The received FIP packet
*/
static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
{
- struct fc_lport *lp = fip->lp;
+ struct fc_lport *lport = fip->lp;
struct fip_header *fiph;
- struct fc_frame *fp;
+ struct fc_frame *fp = (struct fc_frame *)skb;
struct fc_frame_header *fh = NULL;
struct fip_desc *desc;
struct fip_encaps *els;
@@ -831,10 +854,11 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
((struct fip_mac_desc *)desc)->fd_mac,
ETH_ALEN);
if (!is_valid_ether_addr(granted_mac)) {
- LIBFCOE_FIP_DBG("Invalid MAC address "
+ LIBFCOE_FIP_DBG(fip, "Invalid MAC address "
"in FIP ELS\n");
goto drop;
}
+ memcpy(fr_cb(fp)->granted_mac, granted_mac, ETH_ALEN);
break;
case FIP_DT_FLOGI:
case FIP_DT_FDISC:
@@ -850,7 +874,7 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
els_dtype = desc->fip_dtype;
break;
default:
- LIBFCOE_FIP_DBG("unexpected descriptor type %x "
+ LIBFCOE_FIP_DBG(fip, "unexpected descriptor type %x "
"in FIP adv\n", desc->fip_dtype);
/* standard says ignore unknown descriptors >= 128 */
if (desc->fip_dtype < FIP_DT_VENDOR_BASE)
@@ -867,11 +891,8 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
if (els_dtype == FIP_DT_FLOGI && sub == FIP_SC_REP &&
fip->flogi_oxid == ntohs(fh->fh_ox_id) &&
- els_op == ELS_LS_ACC && is_valid_ether_addr(granted_mac)) {
+ els_op == ELS_LS_ACC && is_valid_ether_addr(granted_mac))
fip->flogi_oxid = FC_XID_UNKNOWN;
- fip->update_mac(fip, fip->data_src_addr, granted_mac);
- memcpy(fip->data_src_addr, granted_mac, ETH_ALEN);
- }
/*
* Convert skb into an fc_frame containing only the ELS.
@@ -882,32 +903,32 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
fc_frame_init(fp);
fr_sof(fp) = FC_SOF_I3;
fr_eof(fp) = FC_EOF_T;
- fr_dev(fp) = lp;
+ fr_dev(fp) = lport;
- stats = fc_lport_get_stats(lp);
+ stats = fc_lport_get_stats(lport);
stats->RxFrames++;
stats->RxWords += skb->len / FIP_BPW;
- fc_exch_recv(lp, fp);
+ fc_exch_recv(lport, fp);
return;
len_err:
- LIBFCOE_FIP_DBG("FIP length error in descriptor type %x len %zu\n",
+ LIBFCOE_FIP_DBG(fip, "FIP length error in descriptor type %x len %zu\n",
desc->fip_dtype, dlen);
drop:
kfree_skb(skb);
}
/**
- * fcoe_ctlr_recv_els() - Handle an incoming link reset frame.
- * @fip: FCoE controller.
- * @fh: Received FIP header.
+ * fcoe_ctlr_recv_els() - Handle an incoming link reset frame
+ * @fip: The FCoE controller that received the frame
+ * @fh: The received FIP header
*
* There may be multiple VN_Port descriptors.
* The overall length has already been checked.
*/
static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
- struct fip_header *fh)
+ struct fip_header *fh)
{
struct fip_desc *desc;
struct fip_mac_desc *mp;
@@ -916,13 +937,13 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
size_t rlen;
size_t dlen;
struct fcoe_fcf *fcf = fip->sel_fcf;
- struct fc_lport *lp = fip->lp;
+ struct fc_lport *lport = fip->lp;
u32 desc_mask;
- LIBFCOE_FIP_DBG("Clear Virtual Link received\n");
+ LIBFCOE_FIP_DBG(fip, "Clear Virtual Link received\n");
if (!fcf)
return;
- if (!fcf || !fc_host_port_id(lp->host))
+ if (!fcf || !fc_host_port_id(lport->host))
return;
/*
@@ -958,9 +979,10 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
if (dlen < sizeof(*vp))
return;
if (compare_ether_addr(vp->fd_mac,
- fip->data_src_addr) == 0 &&
- get_unaligned_be64(&vp->fd_wwpn) == lp->wwpn &&
- ntoh24(vp->fd_fc_id) == fc_host_port_id(lp->host))
+ fip->get_src_addr(lport)) == 0 &&
+ get_unaligned_be64(&vp->fd_wwpn) == lport->wwpn &&
+ ntoh24(vp->fd_fc_id) ==
+ fc_host_port_id(lport->host))
desc_mask &= ~BIT(FIP_DT_VN_ID);
break;
default:
@@ -977,33 +999,39 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
* reset only if all required descriptors were present and valid.
*/
if (desc_mask) {
- LIBFCOE_FIP_DBG("missing descriptors mask %x\n", desc_mask);
+ LIBFCOE_FIP_DBG(fip, "missing descriptors mask %x\n",
+ desc_mask);
} else {
- LIBFCOE_FIP_DBG("performing Clear Virtual Link\n");
- fcoe_ctlr_reset(fip, FIP_ST_ENABLED);
+ LIBFCOE_FIP_DBG(fip, "performing Clear Virtual Link\n");
+
+ spin_lock_bh(&fip->lock);
+ fc_lport_get_stats(lport)->VLinkFailureCount++;
+ fcoe_ctlr_reset(fip);
+ spin_unlock_bh(&fip->lock);
+
+ fc_lport_reset(fip->lp);
+ fcoe_ctlr_solicit(fip, NULL);
}
}
/**
- * fcoe_ctlr_recv() - Receive a FIP frame.
- * @fip: FCoE controller.
- * @skb: Received FIP packet.
+ * fcoe_ctlr_recv() - Receive a FIP packet
+ * @fip: The FCoE controller that received the packet
+ * @skb: The received FIP packet
*
- * This is called from NET_RX_SOFTIRQ.
+ * This may be called from either NET_RX_SOFTIRQ or IRQ.
*/
void fcoe_ctlr_recv(struct fcoe_ctlr *fip, struct sk_buff *skb)
{
- spin_lock_bh(&fip->fip_recv_list.lock);
- __skb_queue_tail(&fip->fip_recv_list, skb);
- spin_unlock_bh(&fip->fip_recv_list.lock);
+ skb_queue_tail(&fip->fip_recv_list, skb);
schedule_work(&fip->recv_work);
}
EXPORT_SYMBOL(fcoe_ctlr_recv);
/**
- * fcoe_ctlr_recv_handler() - Receive a FIP frame.
- * @fip: FCoE controller.
- * @skb: Received FIP packet.
+ * fcoe_ctlr_recv_handler() - Receive a FIP frame
+ * @fip: The FCoE controller that received the frame
+ * @skb: The received FIP frame
*
* Returns non-zero if the frame is dropped.
*/
@@ -1038,7 +1066,7 @@ static int fcoe_ctlr_recv_handler(struct fcoe_ctlr *fip, struct sk_buff *skb)
fip->map_dest = 0;
fip->state = FIP_ST_ENABLED;
state = FIP_ST_ENABLED;
- LIBFCOE_FIP_DBG("Using FIP mode\n");
+ LIBFCOE_FIP_DBG(fip, "Using FIP mode\n");
}
spin_unlock_bh(&fip->lock);
if (state != FIP_ST_ENABLED)
@@ -1060,8 +1088,8 @@ drop:
}
/**
- * fcoe_ctlr_select() - Select the best FCF, if possible.
- * @fip: FCoE controller.
+ * fcoe_ctlr_select() - Select the best FCF (if possible)
+ * @fip: The FCoE controller
*
* If there are conflicting advertisements, no FCF can be chosen.
*
@@ -1073,11 +1101,11 @@ static void fcoe_ctlr_select(struct fcoe_ctlr *fip)
struct fcoe_fcf *best = NULL;
list_for_each_entry(fcf, &fip->fcfs, list) {
- LIBFCOE_FIP_DBG("consider FCF for fab %llx VFID %d map %x "
+ LIBFCOE_FIP_DBG(fip, "consider FCF for fab %llx VFID %d map %x "
"val %d\n", fcf->fabric_name, fcf->vfid,
fcf->fc_map, fcoe_ctlr_mtu_valid(fcf));
if (!fcoe_ctlr_fcf_usable(fcf)) {
- LIBFCOE_FIP_DBG("FCF for fab %llx map %x %svalid "
+ LIBFCOE_FIP_DBG(fip, "FCF for fab %llx map %x %svalid "
"%savailable\n", fcf->fabric_name,
fcf->fc_map, (fcf->flags & FIP_FL_SOL)
? "" : "in", (fcf->flags & FIP_FL_AVAIL)
@@ -1091,7 +1119,7 @@ static void fcoe_ctlr_select(struct fcoe_ctlr *fip)
if (fcf->fabric_name != best->fabric_name ||
fcf->vfid != best->vfid ||
fcf->fc_map != best->fc_map) {
- LIBFCOE_FIP_DBG("Conflicting fabric, VFID, "
+ LIBFCOE_FIP_DBG(fip, "Conflicting fabric, VFID, "
"or FC-MAP\n");
return;
}
@@ -1102,8 +1130,8 @@ static void fcoe_ctlr_select(struct fcoe_ctlr *fip)
}
/**
- * fcoe_ctlr_timeout() - FIP timer function.
- * @arg: &fcoe_ctlr pointer.
+ * fcoe_ctlr_timeout() - FIP timeout handler
+ * @arg: The FCoE controller that timed out
*
* Ages FCFs. Triggers FCF selection if possible. Sends keep-alives.
*/
@@ -1113,8 +1141,6 @@ static void fcoe_ctlr_timeout(unsigned long arg)
struct fcoe_fcf *sel;
struct fcoe_fcf *fcf;
unsigned long next_timer = jiffies + msecs_to_jiffies(FIP_VN_KA_PERIOD);
- u8 send_ctlr_ka;
- u8 send_port_ka;
spin_lock_bh(&fip->lock);
if (fip->state == FIP_ST_DISABLED) {
@@ -1140,53 +1166,47 @@ static void fcoe_ctlr_timeout(unsigned long arg)
fip->lp->host->host_no, sel->fcf_mac);
memcpy(fip->dest_addr, sel->fcf_mac, ETH_ALEN);
fip->port_ka_time = jiffies +
- msecs_to_jiffies(FIP_VN_KA_PERIOD);
+ msecs_to_jiffies(FIP_VN_KA_PERIOD);
fip->ctlr_ka_time = jiffies + sel->fka_period;
- fip->link = 1;
} else {
printk(KERN_NOTICE "libfcoe: host%d: "
- "FIP Fibre-Channel Forwarder timed out. "
+ "FIP Fibre-Channel Forwarder timed out. "
"Starting FCF discovery.\n",
fip->lp->host->host_no);
- fip->link = 0;
+ fip->reset_req = 1;
+ schedule_work(&fip->link_work);
}
- schedule_work(&fip->link_work);
}
- send_ctlr_ka = 0;
- send_port_ka = 0;
- if (sel) {
+ if (sel && !sel->fd_flags) {
if (time_after_eq(jiffies, fip->ctlr_ka_time)) {
fip->ctlr_ka_time = jiffies + sel->fka_period;
- send_ctlr_ka = 1;
+ fip->send_ctlr_ka = 1;
}
if (time_after(next_timer, fip->ctlr_ka_time))
next_timer = fip->ctlr_ka_time;
if (time_after_eq(jiffies, fip->port_ka_time)) {
fip->port_ka_time += jiffies +
- msecs_to_jiffies(FIP_VN_KA_PERIOD);
- send_port_ka = 1;
+ msecs_to_jiffies(FIP_VN_KA_PERIOD);
+ fip->send_port_ka = 1;
}
if (time_after(next_timer, fip->port_ka_time))
next_timer = fip->port_ka_time;
mod_timer(&fip->timer, next_timer);
} else if (fip->sel_time) {
next_timer = fip->sel_time +
- msecs_to_jiffies(FCOE_CTLR_START_DELAY);
+ msecs_to_jiffies(FCOE_CTLR_START_DELAY);
mod_timer(&fip->timer, next_timer);
}
+ if (fip->send_ctlr_ka || fip->send_port_ka)
+ schedule_work(&fip->link_work);
spin_unlock_bh(&fip->lock);
-
- if (send_ctlr_ka)
- fcoe_ctlr_send_keep_alive(fip, 0, fip->ctl_src_addr);
- if (send_port_ka)
- fcoe_ctlr_send_keep_alive(fip, 1, fip->data_src_addr);
}
/**
- * fcoe_ctlr_link_work() - worker thread function for link changes.
- * @work: pointer to link_work member inside &fcoe_ctlr.
+ * fcoe_ctlr_link_work() - Worker thread function for link changes
+ * @work: Handle to a FCoE controller
*
* See if the link status has changed and if so, report it.
*
@@ -1196,27 +1216,49 @@ static void fcoe_ctlr_timeout(unsigned long arg)
static void fcoe_ctlr_link_work(struct work_struct *work)
{
struct fcoe_ctlr *fip;
+ struct fc_lport *vport;
+ u8 *mac;
int link;
int last_link;
+ int reset;
fip = container_of(work, struct fcoe_ctlr, link_work);
spin_lock_bh(&fip->lock);
last_link = fip->last_link;
link = fip->link;
fip->last_link = link;
+ reset = fip->reset_req;
+ fip->reset_req = 0;
spin_unlock_bh(&fip->lock);
if (last_link != link) {
if (link)
fc_linkup(fip->lp);
else
- fcoe_ctlr_reset(fip, FIP_ST_LINK_WAIT);
+ fc_linkdown(fip->lp);
+ } else if (reset && link)
+ fc_lport_reset(fip->lp);
+
+ if (fip->send_ctlr_ka) {
+ fip->send_ctlr_ka = 0;
+ fcoe_ctlr_send_keep_alive(fip, NULL, 0, fip->ctl_src_addr);
+ }
+ if (fip->send_port_ka) {
+ fip->send_port_ka = 0;
+ mutex_lock(&fip->lp->lp_mutex);
+ mac = fip->get_src_addr(fip->lp);
+ fcoe_ctlr_send_keep_alive(fip, fip->lp, 1, mac);
+ list_for_each_entry(vport, &fip->lp->vports, list) {
+ mac = fip->get_src_addr(vport);
+ fcoe_ctlr_send_keep_alive(fip, vport, 1, mac);
+ }
+ mutex_unlock(&fip->lp->lp_mutex);
}
}
/**
- * fcoe_ctlr_recv_work() - Worker thread function for receiving FIP frames.
- * @recv_work: pointer to recv_work member inside &fcoe_ctlr.
+ * fcoe_ctlr_recv_work() - Worker thread function for receiving FIP frames
+ * @recv_work: Handle to a FCoE controller
*/
static void fcoe_ctlr_recv_work(struct work_struct *recv_work)
{
@@ -1224,20 +1266,14 @@ static void fcoe_ctlr_recv_work(struct work_struct *recv_work)
struct sk_buff *skb;
fip = container_of(recv_work, struct fcoe_ctlr, recv_work);
- spin_lock_bh(&fip->fip_recv_list.lock);
- while ((skb = __skb_dequeue(&fip->fip_recv_list))) {
- spin_unlock_bh(&fip->fip_recv_list.lock);
+ while ((skb = skb_dequeue(&fip->fip_recv_list)))
fcoe_ctlr_recv_handler(fip, skb);
- spin_lock_bh(&fip->fip_recv_list.lock);
- }
- spin_unlock_bh(&fip->fip_recv_list.lock);
}
/**
- * fcoe_ctlr_recv_flogi() - snoop Pre-FIP receipt of FLOGI response or request.
- * @fip: FCoE controller.
- * @fp: FC frame.
- * @sa: Ethernet source MAC address from received FCoE frame.
+ * fcoe_ctlr_recv_flogi() - Snoop pre-FIP receipt of FLOGI response
+ * @fip: The FCoE controller
+ * @fp: The FC frame to snoop
*
* Snoop potential response to FLOGI or even incoming FLOGI.
*
@@ -1245,15 +1281,18 @@ static void fcoe_ctlr_recv_work(struct work_struct *recv_work)
* by fip->flogi_oxid != FC_XID_UNKNOWN.
*
* The caller is responsible for freeing the frame.
+ * Fill in the granted_mac address.
*
* Return non-zero if the frame should not be delivered to libfc.
*/
-int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_frame *fp, u8 *sa)
+int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_lport *lport,
+ struct fc_frame *fp)
{
struct fc_frame_header *fh;
u8 op;
- u8 mac[ETH_ALEN];
+ u8 *sa;
+ sa = eth_hdr(&fp->skb)->h_source;
fh = fc_frame_header_get(fp);
if (fh->fh_type != FC_TYPE_ELS)
return 0;
@@ -1268,7 +1307,8 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_frame *fp, u8 *sa)
return -EINVAL;
}
fip->state = FIP_ST_NON_FIP;
- LIBFCOE_FIP_DBG("received FLOGI LS_ACC using non-FIP mode\n");
+ LIBFCOE_FIP_DBG(fip,
+ "received FLOGI LS_ACC using non-FIP mode\n");
/*
* FLOGI accepted.
@@ -1283,11 +1323,8 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_frame *fp, u8 *sa)
fip->map_dest = 0;
}
fip->flogi_oxid = FC_XID_UNKNOWN;
- memcpy(mac, fip->data_src_addr, ETH_ALEN);
- fc_fcoe_set_mac(fip->data_src_addr, fh->fh_d_id);
spin_unlock_bh(&fip->lock);
-
- fip->update_mac(fip, mac, fip->data_src_addr);
+ fc_fcoe_set_mac(fr_cb(fp)->granted_mac, fh->fh_d_id);
} else if (op == ELS_FLOGI && fh->fh_r_ctl == FC_RCTL_ELS_REQ && sa) {
/*
* Save source MAC for point-to-point responses.
@@ -1297,7 +1334,7 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_frame *fp, u8 *sa)
memcpy(fip->dest_addr, sa, ETH_ALEN);
fip->map_dest = 0;
if (fip->state == FIP_ST_NON_FIP)
- LIBFCOE_FIP_DBG("received FLOGI REQ, "
+ LIBFCOE_FIP_DBG(fip, "received FLOGI REQ, "
"using non-FIP mode\n");
fip->state = FIP_ST_NON_FIP;
}
@@ -1308,10 +1345,10 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_frame *fp, u8 *sa)
EXPORT_SYMBOL(fcoe_ctlr_recv_flogi);
/**
- * fcoe_wwn_from_mac() - Converts 48-bit IEEE MAC address to 64-bit FC WWN.
- * @mac: mac address
- * @scheme: check port
- * @port: port indicator for converting
+ * fcoe_wwn_from_mac() - Converts a 48-bit IEEE MAC address to a 64-bit FC WWN
+ * @mac: The MAC address to convert
+ * @scheme: The scheme to use when converting
+ * @port: The port indicator for converting
*
* Returns: u64 fc world wide name
*/
@@ -1349,24 +1386,26 @@ u64 fcoe_wwn_from_mac(unsigned char mac[MAX_ADDR_LEN],
EXPORT_SYMBOL_GPL(fcoe_wwn_from_mac);
/**
- * fcoe_libfc_config() - sets up libfc related properties for lport
- * @lp: ptr to the fc_lport
- * @tt: libfc function template
+ * fcoe_libfc_config() - Sets up libfc related properties for local port
+ * @lp: The local port to configure libfc for
+ * @tt: The libfc function template
*
* Returns : 0 for success
*/
-int fcoe_libfc_config(struct fc_lport *lp, struct libfc_function_template *tt)
+int fcoe_libfc_config(struct fc_lport *lport,
+ struct libfc_function_template *tt)
{
/* Set the function pointers set by the LLDD */
- memcpy(&lp->tt, tt, sizeof(*tt));
- if (fc_fcp_init(lp))
+ memcpy(&lport->tt, tt, sizeof(*tt));
+ if (fc_fcp_init(lport))
return -ENOMEM;
- fc_exch_init(lp);
- fc_elsct_init(lp);
- fc_lport_init(lp);
- fc_rport_init(lp);
- fc_disc_init(lp);
+ fc_exch_init(lport);
+ fc_elsct_init(lport);
+ fc_lport_init(lport);
+ fc_rport_init(lport);
+ fc_disc_init(lport);
return 0;
}
EXPORT_SYMBOL_GPL(fcoe_libfc_config);
+
diff --git a/drivers/scsi/fnic/fnic.h b/drivers/scsi/fnic/fnic.h
index e4c0a3d..bb208a6 100644
--- a/drivers/scsi/fnic/fnic.h
+++ b/drivers/scsi/fnic/fnic.h
@@ -22,6 +22,7 @@
#include <linux/netdevice.h>
#include <linux/workqueue.h>
#include <scsi/libfc.h>
+#include <scsi/libfcoe.h>
#include "fnic_io.h"
#include "fnic_res.h"
#include "vnic_dev.h"
@@ -44,7 +45,7 @@
#define FNIC_IO_LOCKS 64 /* IO locks: power of 2 */
#define FNIC_DFLT_QUEUE_DEPTH 32
#define FNIC_STATS_RATE_LIMIT 4 /* limit rate at which stats are pulled up */
-
+#define FNIC_MAX_CMD_LEN 16 /* Supported CDB length */
/*
* Tag bits used for special requests.
*/
@@ -145,6 +146,7 @@ struct mempool;
/* Per-instance private data structure */
struct fnic {
struct fc_lport *lport;
+ struct fcoe_ctlr ctlr; /* FIP FCoE controller structure */
struct vnic_dev_bar bar0;
struct msix_entry msix_entry[FNIC_MSIX_INTR_MAX];
@@ -162,23 +164,16 @@ struct fnic {
unsigned int wq_count;
unsigned int cq_count;
- u32 fcoui_mode:1; /* use fcoui address*/
u32 vlan_hw_insert:1; /* let hw insert the tag */
u32 in_remove:1; /* fnic device in removal */
u32 stop_rx_link_events:1; /* stop proc. rx frames, link events */
struct completion *remove_wait; /* device remove thread blocks */
- struct fc_frame *flogi;
- struct fc_frame *flogi_resp;
- u16 flogi_oxid;
- unsigned long s_id;
enum fnic_state state;
spinlock_t fnic_lock;
u16 vlan_id; /* VLAN tag including priority */
- u8 mac_addr[ETH_ALEN];
- u8 dest_addr[ETH_ALEN];
u8 data_src_addr[ETH_ALEN];
u64 fcp_input_bytes; /* internal statistic */
u64 fcp_output_bytes; /* internal statistic */
@@ -205,6 +200,7 @@ struct fnic {
struct work_struct link_work;
struct work_struct frame_work;
struct sk_buff_head frame_queue;
+ struct sk_buff_head tx_queue;
/* copy work queue cache line section */
____cacheline_aligned struct vnic_wq_copy wq_copy[FNIC_WQ_COPY_MAX];
@@ -224,6 +220,11 @@ struct fnic {
____cacheline_aligned struct vnic_intr intr[FNIC_MSIX_INTR_MAX];
};
+static inline struct fnic *fnic_from_ctlr(struct fcoe_ctlr *fip)
+{
+ return container_of(fip, struct fnic, ctlr);
+}
+
extern struct workqueue_struct *fnic_event_queue;
extern struct device_attribute *fnic_attrs[];
@@ -239,7 +240,11 @@ void fnic_handle_link(struct work_struct *work);
int fnic_rq_cmpl_handler(struct fnic *fnic, int);
int fnic_alloc_rq_frame(struct vnic_rq *rq);
void fnic_free_rq_buf(struct vnic_rq *rq, struct vnic_rq_buf *buf);
-int fnic_send_frame(struct fnic *fnic, struct fc_frame *fp);
+void fnic_flush_tx(struct fnic *);
+void fnic_eth_send(struct fcoe_ctlr *, struct sk_buff *skb);
+void fnic_set_port_id(struct fc_lport *, u32, struct fc_frame *);
+void fnic_update_mac(struct fc_lport *, u8 *new);
+void fnic_update_mac_locked(struct fnic *, u8 *new);
int fnic_queuecommand(struct scsi_cmnd *, void (*done)(struct scsi_cmnd *));
int fnic_abort_cmd(struct scsi_cmnd *);
@@ -252,7 +257,7 @@ void fnic_empty_scsi_cleanup(struct fc_lport *);
void fnic_exch_mgr_reset(struct fc_lport *, u32, u32);
int fnic_wq_copy_cmpl_handler(struct fnic *fnic, int);
int fnic_wq_cmpl_handler(struct fnic *fnic, int);
-int fnic_flogi_reg_handler(struct fnic *fnic);
+int fnic_flogi_reg_handler(struct fnic *fnic, u32);
void fnic_wq_copy_cleanup_handler(struct vnic_wq_copy *wq,
struct fcpio_host_req *desc);
int fnic_fw_reset_handler(struct fnic *fnic);
diff --git a/drivers/scsi/fnic/fnic_fcs.c b/drivers/scsi/fnic/fnic_fcs.c
index 50db3e3..54f8d0e 100644
--- a/drivers/scsi/fnic/fnic_fcs.c
+++ b/drivers/scsi/fnic/fnic_fcs.c
@@ -23,6 +23,7 @@
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
#include <linux/workqueue.h>
+#include <scsi/fc/fc_fip.h>
#include <scsi/fc/fc_els.h>
#include <scsi/fc/fc_fcoe.h>
#include <scsi/fc_frame.h>
@@ -34,6 +35,8 @@
struct workqueue_struct *fnic_event_queue;
+static void fnic_set_eth_mode(struct fnic *);
+
void fnic_handle_link(struct work_struct *work)
{
struct fnic *fnic = container_of(work, struct fnic, link_work);
@@ -64,10 +67,10 @@ void fnic_handle_link(struct work_struct *work)
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host,
"link down\n");
- fc_linkdown(fnic->lport);
+ fcoe_ctlr_link_down(&fnic->ctlr);
FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host,
"link up\n");
- fc_linkup(fnic->lport);
+ fcoe_ctlr_link_up(&fnic->ctlr);
} else
/* UP -> UP */
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
@@ -76,13 +79,13 @@ void fnic_handle_link(struct work_struct *work)
/* DOWN -> UP */
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, "link up\n");
- fc_linkup(fnic->lport);
+ fcoe_ctlr_link_up(&fnic->ctlr);
} else {
/* UP -> DOWN */
fnic->lport->host_stats.link_failure_count++;
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, "link down\n");
- fc_linkdown(fnic->lport);
+ fcoe_ctlr_link_down(&fnic->ctlr);
}
}
@@ -107,197 +110,179 @@ void fnic_handle_frame(struct work_struct *work)
return;
}
fp = (struct fc_frame *)skb;
- /* if Flogi resp frame, register the address */
- if (fr_flags(fp)) {
- vnic_dev_add_addr(fnic->vdev,
- fnic->data_src_addr);
- fr_flags(fp) = 0;
+
+ /*
+ * If we're in a transitional state, just re-queue and return.
+ * The queue will be serviced when we get to a stable state.
+ */
+ if (fnic->state != FNIC_IN_FC_MODE &&
+ fnic->state != FNIC_IN_ETH_MODE) {
+ skb_queue_head(&fnic->frame_queue, skb);
+ spin_unlock_irqrestore(&fnic->fnic_lock, flags);
+ return;
}
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
fc_exch_recv(lp, fp);
}
-
-}
-
-static inline void fnic_import_rq_fc_frame(struct sk_buff *skb,
- u32 len, u8 sof, u8 eof)
-{
- struct fc_frame *fp = (struct fc_frame *)skb;
-
- skb_trim(skb, len);
- fr_eof(fp) = eof;
- fr_sof(fp) = sof;
}
-
-static inline int fnic_import_rq_eth_pkt(struct sk_buff *skb, u32 len)
+/**
+ * fnic_import_rq_eth_pkt() - handle received FCoE or FIP frame.
+ * @fnic: fnic instance.
+ * @skb: Ethernet Frame.
+ */
+static inline int fnic_import_rq_eth_pkt(struct fnic *fnic, struct sk_buff *skb)
{
struct fc_frame *fp;
struct ethhdr *eh;
- struct vlan_ethhdr *vh;
struct fcoe_hdr *fcoe_hdr;
struct fcoe_crc_eof *ft;
- u32 transport_len = 0;
+ /*
+ * Undo VLAN encapsulation if present.
+ */
eh = (struct ethhdr *)skb->data;
- vh = (struct vlan_ethhdr *)skb->data;
- if (vh->h_vlan_proto == htons(ETH_P_8021Q) &&
- vh->h_vlan_encapsulated_proto == htons(ETH_P_FCOE)) {
- skb_pull(skb, sizeof(struct vlan_ethhdr));
- transport_len += sizeof(struct vlan_ethhdr);
- } else if (eh->h_proto == htons(ETH_P_FCOE)) {
- transport_len += sizeof(struct ethhdr);
- skb_pull(skb, sizeof(struct ethhdr));
- } else
- return -1;
+ if (eh->h_proto == htons(ETH_P_8021Q)) {
+ memmove((u8 *)eh + VLAN_HLEN, eh, ETH_ALEN * 2);
+ eh = (struct ethhdr *)skb_pull(skb, VLAN_HLEN);
+ skb_reset_mac_header(skb);
+ }
+ if (eh->h_proto == htons(ETH_P_FIP)) {
+ skb_pull(skb, sizeof(*eh));
+ fcoe_ctlr_recv(&fnic->ctlr, skb);
+ return 1; /* let caller know packet was used */
+ }
+ if (eh->h_proto != htons(ETH_P_FCOE))
+ goto drop;
+ skb_set_network_header(skb, sizeof(*eh));
+ skb_pull(skb, sizeof(*eh));
fcoe_hdr = (struct fcoe_hdr *)skb->data;
if (FC_FCOE_DECAPS_VER(fcoe_hdr) != FC_FCOE_VER)
- return -1;
+ goto drop;
fp = (struct fc_frame *)skb;
fc_frame_init(fp);
fr_sof(fp) = fcoe_hdr->fcoe_sof;
skb_pull(skb, sizeof(struct fcoe_hdr));
- transport_len += sizeof(struct fcoe_hdr);
+ skb_reset_transport_header(skb);
- ft = (struct fcoe_crc_eof *)(skb->data + len -
- transport_len - sizeof(*ft));
+ ft = (struct fcoe_crc_eof *)(skb->data + skb->len - sizeof(*ft));
fr_eof(fp) = ft->fcoe_eof;
- skb_trim(skb, len - transport_len - sizeof(*ft));
+ skb_trim(skb, skb->len - sizeof(*ft));
return 0;
+drop:
+ dev_kfree_skb_irq(skb);
+ return -1;
}
-static inline int fnic_handle_flogi_resp(struct fnic *fnic,
- struct fc_frame *fp)
+/**
+ * fnic_update_mac_locked() - set data MAC address and filters.
+ * @fnic: fnic instance.
+ * @new: newly-assigned FCoE MAC address.
+ *
+ * Called with the fnic lock held.
+ */
+void fnic_update_mac_locked(struct fnic *fnic, u8 *new)
{
- u8 mac[ETH_ALEN] = FC_FCOE_FLOGI_MAC;
- struct ethhdr *eth_hdr;
- struct fc_frame_header *fh;
- int ret = 0;
- unsigned long flags;
- struct fc_frame *old_flogi_resp = NULL;
+ u8 *ctl = fnic->ctlr.ctl_src_addr;
+ u8 *data = fnic->data_src_addr;
- fh = (struct fc_frame_header *)fr_hdr(fp);
+ if (is_zero_ether_addr(new))
+ new = ctl;
+ if (!compare_ether_addr(data, new))
+ return;
+ FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, "update_mac %pM\n", new);
+ if (!is_zero_ether_addr(data) && compare_ether_addr(data, ctl))
+ vnic_dev_del_addr(fnic->vdev, data);
+ memcpy(data, new, ETH_ALEN);
+ if (compare_ether_addr(new, ctl))
+ vnic_dev_add_addr(fnic->vdev, new);
+}
- spin_lock_irqsave(&fnic->fnic_lock, flags);
+/**
+ * fnic_update_mac() - set data MAC address and filters.
+ * @lport: local port.
+ * @new: newly-assigned FCoE MAC address.
+ */
+void fnic_update_mac(struct fc_lport *lport, u8 *new)
+{
+ struct fnic *fnic = lport_priv(lport);
- if (fnic->state == FNIC_IN_ETH_MODE) {
+ spin_lock_irq(&fnic->fnic_lock);
+ fnic_update_mac_locked(fnic, new);
+ spin_unlock_irq(&fnic->fnic_lock);
+}
- /*
- * Check if oxid matches on taking the lock. A new Flogi
- * issued by libFC might have changed the fnic cached oxid
- */
- if (fnic->flogi_oxid != ntohs(fh->fh_ox_id)) {
- FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host,
- "Flogi response oxid not"
- " matching cached oxid, dropping frame"
- "\n");
- ret = -1;
- spin_unlock_irqrestore(&fnic->fnic_lock, flags);
- dev_kfree_skb_irq(fp_skb(fp));
- goto handle_flogi_resp_end;
- }
+/**
+ * fnic_set_port_id() - set the port_ID after successful FLOGI.
+ * @lport: local port.
+ * @port_id: assigned FC_ID.
+ * @fp: received frame containing the FLOGI accept or NULL.
+ *
+ * This is called from libfc when a new FC_ID has been assigned.
+ * This causes us to reset the firmware to FC_MODE and setup the new MAC
+ * address and FC_ID.
+ *
+ * It is also called with FC_ID 0 when we're logged off.
+ *
+ * If the FC_ID is due to point-to-point, fp may be NULL.
+ */
+void fnic_set_port_id(struct fc_lport *lport, u32 port_id, struct fc_frame *fp)
+{
+ struct fnic *fnic = lport_priv(lport);
+ u8 *mac;
+ int ret;
- /* Drop older cached flogi response frame, cache this frame */
- old_flogi_resp = fnic->flogi_resp;
- fnic->flogi_resp = fp;
- fnic->flogi_oxid = FC_XID_UNKNOWN;
+ FNIC_FCS_DBG(KERN_DEBUG, lport->host, "set port_id %x fp %p\n",
+ port_id, fp);
- /*
- * this frame is part of flogi get the src mac addr from this
- * frame if the src mac is fcoui based then we mark the
- * address mode flag to use fcoui base for dst mac addr
- * otherwise we have to store the fcoe gateway addr
- */
- eth_hdr = (struct ethhdr *)skb_mac_header(fp_skb(fp));
- memcpy(mac, eth_hdr->h_source, ETH_ALEN);
+ /*
+ * If we're clearing the FC_ID, change to use the ctl_src_addr.
+ * Set ethernet mode to send FLOGI.
+ */
+ if (!port_id) {
+ fnic_update_mac(lport, fnic->ctlr.ctl_src_addr);
+ fnic_set_eth_mode(fnic);
+ return;
+ }
- if (ntoh24(mac) == FC_FCOE_OUI)
- fnic->fcoui_mode = 1;
- else {
- fnic->fcoui_mode = 0;
- memcpy(fnic->dest_addr, mac, ETH_ALEN);
+ if (fp) {
+ mac = fr_cb(fp)->granted_mac;
+ if (is_zero_ether_addr(mac)) {
+ /* non-FIP - FLOGI already accepted - ignore return */
+ fcoe_ctlr_recv_flogi(&fnic->ctlr, lport, fp);
}
+ fnic_update_mac(lport, mac);
+ }
- /*
- * Except for Flogi frame, all outbound frames from us have the
- * Eth Src address as FC_FCOE_OUI"our_sid". Flogi frame uses
- * the vnic MAC address as the Eth Src address
- */
- fc_fcoe_set_mac(fnic->data_src_addr, fh->fh_d_id);
-
- /* We get our s_id from the d_id of the flogi resp frame */
- fnic->s_id = ntoh24(fh->fh_d_id);
-
- /* Change state to reflect transition from Eth to FC mode */
+ /* Change state to reflect transition to FC mode */
+ spin_lock_irq(&fnic->fnic_lock);
+ if (fnic->state == FNIC_IN_ETH_MODE || fnic->state == FNIC_IN_FC_MODE)
fnic->state = FNIC_IN_ETH_TRANS_FC_MODE;
-
- } else {
+ else {
FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host,
"Unexpected fnic state %s while"
" processing flogi resp\n",
fnic_state_to_str(fnic->state));
- ret = -1;
- spin_unlock_irqrestore(&fnic->fnic_lock, flags);
- dev_kfree_skb_irq(fp_skb(fp));
- goto handle_flogi_resp_end;
+ spin_unlock_irq(&fnic->fnic_lock);
+ return;
}
-
- spin_unlock_irqrestore(&fnic->fnic_lock, flags);
-
- /* Drop older cached frame */
- if (old_flogi_resp)
- dev_kfree_skb_irq(fp_skb(old_flogi_resp));
+ spin_unlock_irq(&fnic->fnic_lock);
/*
- * send flogi reg request to firmware, this will put the fnic in
- * in FC mode
+ * Send FLOGI registration to firmware to set up FC mode.
+ * The new address will be set up when registration completes.
*/
- ret = fnic_flogi_reg_handler(fnic);
+ ret = fnic_flogi_reg_handler(fnic, port_id);
if (ret < 0) {
- int free_fp = 1;
- spin_lock_irqsave(&fnic->fnic_lock, flags);
- /*
- * free the frame is some other thread is not
- * pointing to it
- */
- if (fnic->flogi_resp != fp)
- free_fp = 0;
- else
- fnic->flogi_resp = NULL;
-
+ spin_lock_irq(&fnic->fnic_lock);
if (fnic->state == FNIC_IN_ETH_TRANS_FC_MODE)
fnic->state = FNIC_IN_ETH_MODE;
- spin_unlock_irqrestore(&fnic->fnic_lock, flags);
- if (free_fp)
- dev_kfree_skb_irq(fp_skb(fp));
+ spin_unlock_irq(&fnic->fnic_lock);
}
-
- handle_flogi_resp_end:
- return ret;
-}
-
-/* Returns 1 for a response that matches cached flogi oxid */
-static inline int is_matching_flogi_resp_frame(struct fnic *fnic,
- struct fc_frame *fp)
-{
- struct fc_frame_header *fh;
- int ret = 0;
- u32 f_ctl;
-
- fh = fc_frame_header_get(fp);
- f_ctl = ntoh24(fh->fh_f_ctl);
-
- if (fnic->flogi_oxid == ntohs(fh->fh_ox_id) &&
- fh->fh_r_ctl == FC_RCTL_ELS_REP &&
- (f_ctl & (FC_FC_EX_CTX | FC_FC_SEQ_CTX)) == FC_FC_EX_CTX &&
- fh->fh_type == FC_TYPE_ELS)
- ret = 1;
-
- return ret;
}
static void fnic_rq_cmpl_frame_recv(struct vnic_rq *rq, struct cq_desc
@@ -326,6 +311,7 @@ static void fnic_rq_cmpl_frame_recv(struct vnic_rq *rq, struct cq_desc
pci_unmap_single(fnic->pdev, buf->dma_addr, buf->len,
PCI_DMA_FROMDEVICE);
skb = buf->os_buf;
+ fp = (struct fc_frame *)skb;
buf->os_buf = NULL;
cq_desc_dec(cq_desc, &type, &color, &q_number, &completed_index);
@@ -338,6 +324,9 @@ static void fnic_rq_cmpl_frame_recv(struct vnic_rq *rq, struct cq_desc
&fcoe_enc_error, &fcs_ok, &vlan_stripped,
&vlan);
eth_hdrs_stripped = 1;
+ skb_trim(skb, fcp_bytes_written);
+ fr_sof(fp) = sof;
+ fr_eof(fp) = eof;
} else if (type == CQ_DESC_TYPE_RQ_ENET) {
cq_enet_rq_desc_dec((struct cq_enet_rq_desc *)cq_desc,
@@ -352,6 +341,14 @@ static void fnic_rq_cmpl_frame_recv(struct vnic_rq *rq, struct cq_desc
&ipv4_csum_ok, &ipv6, &ipv4,
&ipv4_fragment, &fcs_ok);
eth_hdrs_stripped = 0;
+ skb_trim(skb, bytes_written);
+ if (!fcs_ok) {
+ FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host,
+ "fcs error. dropping packet.\n");
+ goto drop;
+ }
+ if (fnic_import_rq_eth_pkt(fnic, skb))
+ return;
} else {
/* wrong CQ type*/
@@ -370,43 +367,11 @@ static void fnic_rq_cmpl_frame_recv(struct vnic_rq *rq, struct cq_desc
goto drop;
}
- if (eth_hdrs_stripped)
- fnic_import_rq_fc_frame(skb, fcp_bytes_written, sof, eof);
- else if (fnic_import_rq_eth_pkt(skb, bytes_written))
- goto drop;
-
- fp = (struct fc_frame *)skb;
-
- /*
- * If frame is an ELS response that matches the cached FLOGI OX_ID,
- * and is accept, issue flogi_reg_request copy wq request to firmware
- * to register the S_ID and determine whether FC_OUI mode or GW mode.
- */
- if (is_matching_flogi_resp_frame(fnic, fp)) {
- if (!eth_hdrs_stripped) {
- if (fc_frame_payload_op(fp) == ELS_LS_ACC) {
- fnic_handle_flogi_resp(fnic, fp);
- return;
- }
- /*
- * Recd. Flogi reject. No point registering
- * with fw, but forward to libFC
- */
- goto forward;
- }
- goto drop;
- }
- if (!eth_hdrs_stripped)
- goto drop;
-
-forward:
spin_lock_irqsave(&fnic->fnic_lock, flags);
if (fnic->stop_rx_link_events) {
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
goto drop;
}
- /* Use fr_flags to indicate whether succ. flogi resp or not */
- fr_flags(fp) = 0;
fr_dev(fp) = fnic->lport;
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
@@ -494,12 +459,49 @@ void fnic_free_rq_buf(struct vnic_rq *rq, struct vnic_rq_buf *buf)
buf->os_buf = NULL;
}
-static inline int is_flogi_frame(struct fc_frame_header *fh)
+/**
+ * fnic_eth_send() - Send Ethernet frame.
+ * @fip: fcoe_ctlr instance.
+ * @skb: Ethernet Frame, FIP, without VLAN encapsulation.
+ */
+void fnic_eth_send(struct fcoe_ctlr *fip, struct sk_buff *skb)
{
- return fh->fh_r_ctl == FC_RCTL_ELS_REQ && *(u8 *)(fh + 1) == ELS_FLOGI;
+ struct fnic *fnic = fnic_from_ctlr(fip);
+ struct vnic_wq *wq = &fnic->wq[0];
+ dma_addr_t pa;
+ struct ethhdr *eth_hdr;
+ struct vlan_ethhdr *vlan_hdr;
+ unsigned long flags;
+
+ if (!fnic->vlan_hw_insert) {
+ eth_hdr = (struct ethhdr *)skb_mac_header(skb);
+ vlan_hdr = (struct vlan_ethhdr *)skb_push(skb,
+ sizeof(*vlan_hdr) - sizeof(*eth_hdr));
+ memcpy(vlan_hdr, eth_hdr, 2 * ETH_ALEN);
+ vlan_hdr->h_vlan_proto = htons(ETH_P_8021Q);
+ vlan_hdr->h_vlan_encapsulated_proto = eth_hdr->h_proto;
+ vlan_hdr->h_vlan_TCI = htons(fnic->vlan_id);
+ }
+
+ pa = pci_map_single(fnic->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
+
+ spin_lock_irqsave(&fnic->wq_lock[0], flags);
+ if (!vnic_wq_desc_avail(wq)) {
+ pci_unmap_single(fnic->pdev, pa, skb->len, PCI_DMA_TODEVICE);
+ spin_unlock_irqrestore(&fnic->wq_lock[0], flags);
+ kfree_skb(skb);
+ return;
+ }
+
+ fnic_queue_wq_eth_desc(wq, skb, pa, skb->len,
+ fnic->vlan_hw_insert, fnic->vlan_id, 1);
+ spin_unlock_irqrestore(&fnic->wq_lock[0], flags);
}
-int fnic_send_frame(struct fnic *fnic, struct fc_frame *fp)
+/*
+ * Send FC frame.
+ */
+static int fnic_send_frame(struct fnic *fnic, struct fc_frame *fp)
{
struct vnic_wq *wq = &fnic->wq[0];
struct sk_buff *skb;
@@ -515,6 +517,10 @@ int fnic_send_frame(struct fnic *fnic, struct fc_frame *fp)
fh = fc_frame_header_get(fp);
skb = fp_skb(fp);
+ if (unlikely(fh->fh_r_ctl == FC_RCTL_ELS_REQ) &&
+ fcoe_ctlr_els_send(&fnic->ctlr, fnic->lport, skb))
+ return 0;
+
if (!fnic->vlan_hw_insert) {
eth_hdr_len = sizeof(*vlan_hdr) + sizeof(*fcoe_hdr);
vlan_hdr = (struct vlan_ethhdr *)skb_push(skb, eth_hdr_len);
@@ -530,16 +536,11 @@ int fnic_send_frame(struct fnic *fnic, struct fc_frame *fp)
fcoe_hdr = (struct fcoe_hdr *)(eth_hdr + 1);
}
- if (is_flogi_frame(fh)) {
+ if (fnic->ctlr.map_dest)
fc_fcoe_set_mac(eth_hdr->h_dest, fh->fh_d_id);
- memcpy(eth_hdr->h_source, fnic->mac_addr, ETH_ALEN);
- } else {
- if (fnic->fcoui_mode)
- fc_fcoe_set_mac(eth_hdr->h_dest, fh->fh_d_id);
- else
- memcpy(eth_hdr->h_dest, fnic->dest_addr, ETH_ALEN);
- memcpy(eth_hdr->h_source, fnic->data_src_addr, ETH_ALEN);
- }
+ else
+ memcpy(eth_hdr->h_dest, fnic->ctlr.dest_addr, ETH_ALEN);
+ memcpy(eth_hdr->h_source, fnic->data_src_addr, ETH_ALEN);
tot_len = skb->len;
BUG_ON(tot_len % 4);
@@ -578,109 +579,85 @@ fnic_send_frame_end:
int fnic_send(struct fc_lport *lp, struct fc_frame *fp)
{
struct fnic *fnic = lport_priv(lp);
- struct fc_frame_header *fh;
- int ret = 0;
- enum fnic_state old_state;
unsigned long flags;
- struct fc_frame *old_flogi = NULL;
- struct fc_frame *old_flogi_resp = NULL;
if (fnic->in_remove) {
dev_kfree_skb(fp_skb(fp));
- ret = -1;
- goto fnic_send_end;
+ return -1;
}
- fh = fc_frame_header_get(fp);
- /* if not an Flogi frame, send it out, this is the common case */
- if (!is_flogi_frame(fh))
- return fnic_send_frame(fnic, fp);
+ /*
+ * Queue frame if in a transitional state.
+ * This occurs while registering the Port_ID / MAC address after FLOGI.
+ */
+ spin_lock_irqsave(&fnic->fnic_lock, flags);
+ if (fnic->state != FNIC_IN_FC_MODE && fnic->state != FNIC_IN_ETH_MODE) {
+ skb_queue_tail(&fnic->tx_queue, fp_skb(fp));
+ spin_unlock_irqrestore(&fnic->fnic_lock, flags);
+ return 0;
+ }
+ spin_unlock_irqrestore(&fnic->fnic_lock, flags);
- /* Flogi frame, now enter the state machine */
+ return fnic_send_frame(fnic, fp);
+}
- spin_lock_irqsave(&fnic->fnic_lock, flags);
-again:
- /* Get any old cached frames, free them after dropping lock */
- old_flogi = fnic->flogi;
- fnic->flogi = NULL;
- old_flogi_resp = fnic->flogi_resp;
- fnic->flogi_resp = NULL;
+/**
+ * fnic_flush_tx() - send queued frames.
+ * @fnic: fnic device
+ *
+ * Send frames that were waiting to go out in FC or Ethernet mode.
+ * Whenever changing modes we purge queued frames, so these frames should
+ * be queued for the stable mode that we're in, either FC or Ethernet.
+ *
+ * Called without fnic_lock held.
+ */
+void fnic_flush_tx(struct fnic *fnic)
+{
+ struct sk_buff *skb;
+ struct fc_frame *fp;
- fnic->flogi_oxid = FC_XID_UNKNOWN;
+ while ((skb = skb_dequeue(&fnic->frame_queue))) {
+ fp = (struct fc_frame *)skb;
+ fnic_send_frame(fnic, fp);
+ }
+}
+/**
+ * fnic_set_eth_mode() - put fnic into ethernet mode.
+ * @fnic: fnic device
+ *
+ * Called without fnic lock held.
+ */
+static void fnic_set_eth_mode(struct fnic *fnic)
+{
+ unsigned long flags;
+ enum fnic_state old_state;
+ int ret;
+
+ spin_lock_irqsave(&fnic->fnic_lock, flags);
+again:
old_state = fnic->state;
switch (old_state) {
case FNIC_IN_FC_MODE:
case FNIC_IN_ETH_TRANS_FC_MODE:
default:
fnic->state = FNIC_IN_FC_TRANS_ETH_MODE;
- vnic_dev_del_addr(fnic->vdev, fnic->data_src_addr);
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
- if (old_flogi) {
- dev_kfree_skb(fp_skb(old_flogi));
- old_flogi = NULL;
- }
- if (old_flogi_resp) {
- dev_kfree_skb(fp_skb(old_flogi_resp));
- old_flogi_resp = NULL;
- }
-
ret = fnic_fw_reset_handler(fnic);
spin_lock_irqsave(&fnic->fnic_lock, flags);
if (fnic->state != FNIC_IN_FC_TRANS_ETH_MODE)
goto again;
- if (ret) {
+ if (ret)
fnic->state = old_state;
- spin_unlock_irqrestore(&fnic->fnic_lock, flags);
- dev_kfree_skb(fp_skb(fp));
- goto fnic_send_end;
- }
- old_flogi = fnic->flogi;
- fnic->flogi = fp;
- fnic->flogi_oxid = ntohs(fh->fh_ox_id);
- old_flogi_resp = fnic->flogi_resp;
- fnic->flogi_resp = NULL;
- spin_unlock_irqrestore(&fnic->fnic_lock, flags);
break;
case FNIC_IN_FC_TRANS_ETH_MODE:
- /*
- * A reset is pending with the firmware. Store the flogi
- * and its oxid. The transition out of this state happens
- * only when Firmware completes the reset, either with
- * success or failed. If success, transition to
- * FNIC_IN_ETH_MODE, if fail, then transition to
- * FNIC_IN_FC_MODE
- */
- fnic->flogi = fp;
- fnic->flogi_oxid = ntohs(fh->fh_ox_id);
- spin_unlock_irqrestore(&fnic->fnic_lock, flags);
- break;
-
case FNIC_IN_ETH_MODE:
- /*
- * The fw/hw is already in eth mode. Store the oxid,
- * and send the flogi frame out. The transition out of this
- * state happens only we receive flogi response from the
- * network, and the oxid matches the cached oxid when the
- * flogi frame was sent out. If they match, then we issue
- * a flogi_reg request and transition to state
- * FNIC_IN_ETH_TRANS_FC_MODE
- */
- fnic->flogi_oxid = ntohs(fh->fh_ox_id);
- spin_unlock_irqrestore(&fnic->fnic_lock, flags);
- ret = fnic_send_frame(fnic, fp);
break;
}
-
-fnic_send_end:
- if (old_flogi)
- dev_kfree_skb(fp_skb(old_flogi));
- if (old_flogi_resp)
- dev_kfree_skb(fp_skb(old_flogi_resp));
- return ret;
+ spin_unlock_irqrestore(&fnic->fnic_lock, flags);
}
static void fnic_wq_complete_frame_send(struct vnic_wq *wq,
diff --git a/drivers/scsi/fnic/fnic_isr.c b/drivers/scsi/fnic/fnic_isr.c
index 2b30648..5c1f223 100644
--- a/drivers/scsi/fnic/fnic_isr.c
+++ b/drivers/scsi/fnic/fnic_isr.c
@@ -48,9 +48,9 @@ static irqreturn_t fnic_isr_legacy(int irq, void *data)
}
if (pba & (1 << FNIC_INTX_WQ_RQ_COPYWQ)) {
- work_done += fnic_wq_copy_cmpl_handler(fnic, 8);
- work_done += fnic_wq_cmpl_handler(fnic, 4);
- work_done += fnic_rq_cmpl_handler(fnic, 4);
+ work_done += fnic_wq_copy_cmpl_handler(fnic, -1);
+ work_done += fnic_wq_cmpl_handler(fnic, -1);
+ work_done += fnic_rq_cmpl_handler(fnic, -1);
vnic_intr_return_credits(&fnic->intr[FNIC_INTX_WQ_RQ_COPYWQ],
work_done,
@@ -66,9 +66,9 @@ static irqreturn_t fnic_isr_msi(int irq, void *data)
struct fnic *fnic = data;
unsigned long work_done = 0;
- work_done += fnic_wq_copy_cmpl_handler(fnic, 8);
- work_done += fnic_wq_cmpl_handler(fnic, 4);
- work_done += fnic_rq_cmpl_handler(fnic, 4);
+ work_done += fnic_wq_copy_cmpl_handler(fnic, -1);
+ work_done += fnic_wq_cmpl_handler(fnic, -1);
+ work_done += fnic_rq_cmpl_handler(fnic, -1);
vnic_intr_return_credits(&fnic->intr[0],
work_done,
@@ -83,7 +83,7 @@ static irqreturn_t fnic_isr_msix_rq(int irq, void *data)
struct fnic *fnic = data;
unsigned long rq_work_done = 0;
- rq_work_done = fnic_rq_cmpl_handler(fnic, 4);
+ rq_work_done = fnic_rq_cmpl_handler(fnic, -1);
vnic_intr_return_credits(&fnic->intr[FNIC_MSIX_RQ],
rq_work_done,
1 /* unmask intr */,
@@ -97,7 +97,7 @@ static irqreturn_t fnic_isr_msix_wq(int irq, void *data)
struct fnic *fnic = data;
unsigned long wq_work_done = 0;
- wq_work_done = fnic_wq_cmpl_handler(fnic, 4);
+ wq_work_done = fnic_wq_cmpl_handler(fnic, -1);
vnic_intr_return_credits(&fnic->intr[FNIC_MSIX_WQ],
wq_work_done,
1 /* unmask intr */,
@@ -110,7 +110,7 @@ static irqreturn_t fnic_isr_msix_wq_copy(int irq, void *data)
struct fnic *fnic = data;
unsigned long wq_copy_work_done = 0;
- wq_copy_work_done = fnic_wq_copy_cmpl_handler(fnic, 8);
+ wq_copy_work_done = fnic_wq_copy_cmpl_handler(fnic, -1);
vnic_intr_return_credits(&fnic->intr[FNIC_MSIX_WQ_COPY],
wq_copy_work_done,
1 /* unmask intr */,
diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c
index 71c7bbe..fe1b1031 100644
--- a/drivers/scsi/fnic/fnic_main.c
+++ b/drivers/scsi/fnic/fnic_main.c
@@ -25,6 +25,8 @@
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
+#include <linux/if_ether.h>
+#include <scsi/fc/fc_fip.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_transport.h>
#include <scsi/scsi_transport_fc.h>
@@ -68,6 +70,7 @@ MODULE_PARM_DESC(fnic_log_level, "bit mask of fnic logging levels");
static struct libfc_function_template fnic_transport_template = {
.frame_send = fnic_send,
+ .lport_set_port_id = fnic_set_port_id,
.fcp_abort_io = fnic_empty_scsi_cleanup,
.fcp_cleanup = fnic_empty_scsi_cleanup,
.exch_mgr_reset = fnic_exch_mgr_reset
@@ -140,6 +143,7 @@ static struct fc_function_template fnic_fc_functions = {
.get_fc_host_stats = fnic_get_stats,
.dd_fcrport_size = sizeof(struct fc_rport_libfc_priv),
.terminate_rport_io = fnic_terminate_rport_io,
+ .bsg_request = fc_lport_bsg_request,
};
static void fnic_get_host_speed(struct Scsi_Host *shost)
@@ -324,9 +328,6 @@ static int fnic_cleanup(struct fnic *fnic)
{
unsigned int i;
int err;
- unsigned long flags;
- struct fc_frame *flogi = NULL;
- struct fc_frame *flogi_resp = NULL;
vnic_dev_disable(fnic->vdev);
for (i = 0; i < fnic->intr_count; i++)
@@ -367,24 +368,6 @@ static int fnic_cleanup(struct fnic *fnic)
for (i = 0; i < fnic->intr_count; i++)
vnic_intr_clean(&fnic->intr[i]);
- /*
- * Remove cached flogi and flogi resp frames if any
- * These frames are not in any queue, and therefore queue
- * cleanup does not clean them. So clean them explicitly
- */
- spin_lock_irqsave(&fnic->fnic_lock, flags);
- flogi = fnic->flogi;
- fnic->flogi = NULL;
- flogi_resp = fnic->flogi_resp;
- fnic->flogi_resp = NULL;
- spin_unlock_irqrestore(&fnic->fnic_lock, flags);
-
- if (flogi)
- dev_kfree_skb(fp_skb(flogi));
-
- if (flogi_resp)
- dev_kfree_skb(fp_skb(flogi_resp));
-
mempool_destroy(fnic->io_req_pool);
for (i = 0; i < FNIC_SGL_NUM_CACHES; i++)
mempool_destroy(fnic->io_sgl_pool[i]);
@@ -409,6 +392,17 @@ static void *fnic_alloc_slab_dma(gfp_t gfp_mask, void *pool_data)
return kmem_cache_alloc(mem, gfp_mask | GFP_ATOMIC | GFP_DMA);
}
+/**
+ * fnic_get_mac() - get assigned data MAC address for FIP code.
+ * @lport: local port.
+ */
+static u8 *fnic_get_mac(struct fc_lport *lport)
+{
+ struct fnic *fnic = lport_priv(lport);
+
+ return fnic->data_src_addr;
+}
+
static int __devinit fnic_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -424,17 +418,16 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
* Allocate SCSI Host and set up association between host,
* local port, and fnic
*/
- host = scsi_host_alloc(&fnic_host_template,
- sizeof(struct fc_lport) + sizeof(struct fnic));
- if (!host) {
- printk(KERN_ERR PFX "Unable to alloc SCSI host\n");
+ lp = libfc_host_alloc(&fnic_host_template, sizeof(struct fnic));
+ if (!lp) {
+ printk(KERN_ERR PFX "Unable to alloc libfc local port\n");
err = -ENOMEM;
goto err_out;
}
- lp = shost_priv(host);
- lp->host = host;
+ host = lp->host;
fnic = lport_priv(lp);
fnic->lport = lp;
+ fnic->ctlr.lp = lp;
snprintf(fnic->name, sizeof(fnic->name) - 1, "%s%d", DRV_NAME,
host->host_no);
@@ -543,12 +536,14 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
goto err_out_dev_close;
}
- err = vnic_dev_mac_addr(fnic->vdev, fnic->mac_addr);
+ err = vnic_dev_mac_addr(fnic->vdev, fnic->ctlr.ctl_src_addr);
if (err) {
shost_printk(KERN_ERR, fnic->lport->host,
"vNIC get MAC addr failed \n");
goto err_out_dev_close;
}
+ /* set data_src for point-to-point mode and to keep it non-zero */
+ memcpy(fnic->data_src_addr, fnic->ctlr.ctl_src_addr, ETH_ALEN);
/* Get vNIC configuration */
err = fnic_get_vnic_config(fnic);
@@ -560,6 +555,7 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
}
host->max_lun = fnic->config.luns_per_tgt;
host->max_id = FNIC_MAX_FCP_TARGET;
+ host->max_cmd_len = FNIC_MAX_CMD_LEN;
fnic_get_res_counts(fnic);
@@ -571,19 +567,12 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
goto err_out_dev_close;
}
- err = fnic_request_intr(fnic);
- if (err) {
- shost_printk(KERN_ERR, fnic->lport->host,
- "Unable to request irq.\n");
- goto err_out_clear_intr;
- }
-
err = fnic_alloc_vnic_resources(fnic);
if (err) {
shost_printk(KERN_ERR, fnic->lport->host,
"Failed to alloc vNIC resources, "
"aborting.\n");
- goto err_out_free_intr;
+ goto err_out_clear_intr;
}
@@ -623,9 +612,21 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
fnic->vlan_hw_insert = 1;
fnic->vlan_id = 0;
- fnic->flogi_oxid = FC_XID_UNKNOWN;
- fnic->flogi = NULL;
- fnic->flogi_resp = NULL;
+ /* Initialize the FIP fcoe_ctrl struct */
+ fnic->ctlr.send = fnic_eth_send;
+ fnic->ctlr.update_mac = fnic_update_mac;
+ fnic->ctlr.get_src_addr = fnic_get_mac;
+ fcoe_ctlr_init(&fnic->ctlr);
+ if (fnic->config.flags & VFCF_FIP_CAPABLE) {
+ shost_printk(KERN_INFO, fnic->lport->host,
+ "firmware supports FIP\n");
+ vnic_dev_add_addr(fnic->vdev, FIP_ALL_ENODE_MACS);
+ vnic_dev_add_addr(fnic->vdev, fnic->ctlr.ctl_src_addr);
+ } else {
+ shost_printk(KERN_INFO, fnic->lport->host,
+ "firmware uses non-FIP mode\n");
+ fnic->ctlr.mode = FIP_ST_NON_FIP;
+ }
fnic->state = FNIC_IN_FC_MODE;
/* Enable hardware stripping of vlan header on ingress */
@@ -716,6 +717,7 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
INIT_WORK(&fnic->link_work, fnic_handle_link);
INIT_WORK(&fnic->frame_work, fnic_handle_frame);
skb_queue_head_init(&fnic->frame_queue);
+ skb_queue_head_init(&fnic->tx_queue);
/* Enable all queues */
for (i = 0; i < fnic->raw_wq_count; i++)
@@ -728,6 +730,14 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
fc_fabric_login(lp);
vnic_dev_enable(fnic->vdev);
+
+ err = fnic_request_intr(fnic);
+ if (err) {
+ shost_printk(KERN_ERR, fnic->lport->host,
+ "Unable to request irq.\n");
+ goto err_out_free_exch_mgr;
+ }
+
for (i = 0; i < fnic->intr_count; i++)
vnic_intr_unmask(&fnic->intr[i]);
@@ -738,8 +748,8 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
err_out_free_exch_mgr:
fc_exch_mgr_free(lp);
err_out_remove_scsi_host:
- fc_remove_host(fnic->lport->host);
- scsi_remove_host(fnic->lport->host);
+ fc_remove_host(lp->host);
+ scsi_remove_host(lp->host);
err_out_free_rq_buf:
for (i = 0; i < fnic->rq_count; i++)
vnic_rq_clean(&fnic->rq[i], fnic_free_rq_buf);
@@ -752,8 +762,6 @@ err_out_free_ioreq_pool:
mempool_destroy(fnic->io_req_pool);
err_out_free_resources:
fnic_free_vnic_resources(fnic);
-err_out_free_intr:
- fnic_free_intr(fnic);
err_out_clear_intr:
fnic_clear_intr_mode(fnic);
err_out_dev_close:
@@ -775,6 +783,7 @@ err_out:
static void __devexit fnic_remove(struct pci_dev *pdev)
{
struct fnic *fnic = pci_get_drvdata(pdev);
+ struct fc_lport *lp = fnic->lport;
unsigned long flags;
/*
@@ -796,6 +805,7 @@ static void __devexit fnic_remove(struct pci_dev *pdev)
*/
flush_workqueue(fnic_event_queue);
skb_queue_purge(&fnic->frame_queue);
+ skb_queue_purge(&fnic->tx_queue);
/*
* Log off the fabric. This stops all remote ports, dns port,
@@ -808,7 +818,8 @@ static void __devexit fnic_remove(struct pci_dev *pdev)
fnic->in_remove = 1;
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
- fc_lport_destroy(fnic->lport);
+ fcoe_ctlr_destroy(&fnic->ctlr);
+ fc_lport_destroy(lp);
/*
* This stops the fnic device, masks all interrupts. Completed
@@ -818,6 +829,7 @@ static void __devexit fnic_remove(struct pci_dev *pdev)
fnic_cleanup(fnic);
BUG_ON(!skb_queue_empty(&fnic->frame_queue));
+ BUG_ON(!skb_queue_empty(&fnic->tx_queue));
spin_lock_irqsave(&fnic_list_lock, flags);
list_del(&fnic->list);
@@ -827,8 +839,8 @@ static void __devexit fnic_remove(struct pci_dev *pdev)
scsi_remove_host(fnic->lport->host);
fc_exch_mgr_free(fnic->lport);
vnic_dev_notify_unset(fnic->vdev);
- fnic_free_vnic_resources(fnic);
fnic_free_intr(fnic);
+ fnic_free_vnic_resources(fnic);
fnic_clear_intr_mode(fnic);
vnic_dev_close(fnic->vdev);
vnic_dev_unregister(fnic->vdev);
@@ -836,7 +848,7 @@ static void __devexit fnic_remove(struct pci_dev *pdev)
pci_release_regions(pdev);
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
- scsi_host_put(fnic->lport->host);
+ scsi_host_put(lp->host);
}
static struct pci_driver fnic_driver = {
diff --git a/drivers/scsi/fnic/fnic_res.c b/drivers/scsi/fnic/fnic_res.c
index 7ba61ec..50488f8 100644
--- a/drivers/scsi/fnic/fnic_res.c
+++ b/drivers/scsi/fnic/fnic_res.c
@@ -144,10 +144,9 @@ int fnic_get_vnic_config(struct fnic *fnic)
c->intr_timer_type = c->intr_timer_type;
shost_printk(KERN_INFO, fnic->lport->host,
- "vNIC MAC addr %02x:%02x:%02x:%02x:%02x:%02x "
+ "vNIC MAC addr %pM "
"wq/wq_copy/rq %d/%d/%d\n",
- fnic->mac_addr[0], fnic->mac_addr[1], fnic->mac_addr[2],
- fnic->mac_addr[3], fnic->mac_addr[4], fnic->mac_addr[5],
+ fnic->ctlr.ctl_src_addr,
c->wq_enet_desc_count, c->wq_copy_desc_count,
c->rq_desc_count);
shost_printk(KERN_INFO, fnic->lport->host,
diff --git a/drivers/scsi/fnic/fnic_res.h b/drivers/scsi/fnic/fnic_res.h
index b6f3102..ef8aaf2 100644
--- a/drivers/scsi/fnic/fnic_res.h
+++ b/drivers/scsi/fnic/fnic_res.h
@@ -51,6 +51,31 @@ static inline void fnic_queue_wq_desc(struct vnic_wq *wq,
vnic_wq_post(wq, os_buf, dma_addr, len, sop, eop);
}
+static inline void fnic_queue_wq_eth_desc(struct vnic_wq *wq,
+ void *os_buf, dma_addr_t dma_addr,
+ unsigned int len,
+ int vlan_tag_insert,
+ unsigned int vlan_tag,
+ int cq_entry)
+{
+ struct wq_enet_desc *desc = vnic_wq_next_desc(wq);
+
+ wq_enet_desc_enc(desc,
+ (u64)dma_addr | VNIC_PADDR_TARGET,
+ (u16)len,
+ 0, /* mss_or_csum_offset */
+ 0, /* fc_eof */
+ 0, /* offload_mode */
+ 1, /* eop */
+ (u8)cq_entry,
+ 0, /* fcoe_encap */
+ (u8)vlan_tag_insert,
+ (u16)vlan_tag,
+ 0 /* loopback */);
+
+ vnic_wq_post(wq, os_buf, dma_addr, len, 1, 1);
+}
+
static inline void fnic_queue_wq_copy_desc_icmnd_16(struct vnic_wq_copy *wq,
u32 req_id,
u32 lunmap_id, u8 spl_flags,
@@ -58,6 +83,7 @@ static inline void fnic_queue_wq_copy_desc_icmnd_16(struct vnic_wq_copy *wq,
u64 sgl_addr, u64 sns_addr,
u8 crn, u8 pri_ta,
u8 flags, u8 *scsi_cdb,
+ u8 cdb_len,
u32 data_len, u8 *lun,
u32 d_id, u16 mss,
u32 ratov, u32 edtov)
@@ -82,7 +108,8 @@ static inline void fnic_queue_wq_copy_desc_icmnd_16(struct vnic_wq_copy *wq,
desc->u.icmnd_16.pri_ta = pri_ta; /* SCSI Pri & Task attribute */
desc->u.icmnd_16._resvd1 = 0; /* reserved: should be 0 */
desc->u.icmnd_16.flags = flags; /* command flags */
- memcpy(desc->u.icmnd_16.scsi_cdb, scsi_cdb, CDB_16); /* SCSI CDB */
+ memset(desc->u.icmnd_16.scsi_cdb, 0, CDB_16);
+ memcpy(desc->u.icmnd_16.scsi_cdb, scsi_cdb, cdb_len); /* SCSI CDB */
desc->u.icmnd_16.data_len = data_len; /* length of data expected */
memcpy(desc->u.icmnd_16.lun, lun, LUN_ADDRESS); /* LUN address */
desc->u.icmnd_16._resvd2 = 0; /* reserved */
@@ -132,12 +159,37 @@ static inline void fnic_queue_wq_copy_desc_flogi_reg(struct vnic_wq_copy *wq,
desc->hdr.tag.u.req_id = req_id; /* id for this request */
desc->u.flogi_reg.format = format;
+ desc->u.flogi_reg._resvd = 0;
hton24(desc->u.flogi_reg.s_id, s_id);
memcpy(desc->u.flogi_reg.gateway_mac, gw_mac, ETH_ALEN);
vnic_wq_copy_post(wq);
}
+static inline void fnic_queue_wq_copy_desc_fip_reg(struct vnic_wq_copy *wq,
+ u32 req_id, u32 s_id,
+ u8 *fcf_mac, u8 *ha_mac,
+ u32 r_a_tov, u32 e_d_tov)
+{
+ struct fcpio_host_req *desc = vnic_wq_copy_next_desc(wq);
+
+ desc->hdr.type = FCPIO_FLOGI_FIP_REG; /* enum fcpio_type */
+ desc->hdr.status = 0; /* header status entry */
+ desc->hdr._resvd = 0; /* reserved */
+ desc->hdr.tag.u.req_id = req_id; /* id for this request */
+
+ desc->u.flogi_fip_reg._resvd0 = 0;
+ hton24(desc->u.flogi_fip_reg.s_id, s_id);
+ memcpy(desc->u.flogi_fip_reg.fcf_mac, fcf_mac, ETH_ALEN);
+ desc->u.flogi_fip_reg._resvd1 = 0;
+ desc->u.flogi_fip_reg.r_a_tov = r_a_tov;
+ desc->u.flogi_fip_reg.e_d_tov = e_d_tov;
+ memcpy(desc->u.flogi_fip_reg.ha_mac, ha_mac, ETH_ALEN);
+ desc->u.flogi_fip_reg._resvd2 = 0;
+
+ vnic_wq_copy_post(wq);
+}
+
static inline void fnic_queue_wq_copy_desc_fw_reset(struct vnic_wq_copy *wq,
u32 req_id)
{
diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c
index bfc9969..65a39b0 100644
--- a/drivers/scsi/fnic/fnic_scsi.c
+++ b/drivers/scsi/fnic/fnic_scsi.c
@@ -174,6 +174,9 @@ int fnic_fw_reset_handler(struct fnic *fnic)
int ret = 0;
unsigned long flags;
+ skb_queue_purge(&fnic->frame_queue);
+ skb_queue_purge(&fnic->tx_queue);
+
spin_lock_irqsave(&fnic->wq_copy_lock[0], flags);
if (vnic_wq_copy_desc_avail(wq) <= fnic->wq_copy_desc_low[0])
@@ -200,9 +203,11 @@ int fnic_fw_reset_handler(struct fnic *fnic)
* fnic_flogi_reg_handler
* Routine to send flogi register msg to fw
*/
-int fnic_flogi_reg_handler(struct fnic *fnic)
+int fnic_flogi_reg_handler(struct fnic *fnic, u32 fc_id)
{
struct vnic_wq_copy *wq = &fnic->wq_copy[0];
+ enum fcpio_flogi_reg_format_type format;
+ struct fc_lport *lp = fnic->lport;
u8 gw_mac[ETH_ALEN];
int ret = 0;
unsigned long flags;
@@ -217,23 +222,32 @@ int fnic_flogi_reg_handler(struct fnic *fnic)
goto flogi_reg_ioreq_end;
}
- if (fnic->fcoui_mode)
+ if (fnic->ctlr.map_dest) {
memset(gw_mac, 0xff, ETH_ALEN);
- else
- memcpy(gw_mac, fnic->dest_addr, ETH_ALEN);
+ format = FCPIO_FLOGI_REG_DEF_DEST;
+ } else {
+ memcpy(gw_mac, fnic->ctlr.dest_addr, ETH_ALEN);
+ format = FCPIO_FLOGI_REG_GW_DEST;
+ }
- fnic_queue_wq_copy_desc_flogi_reg(wq, SCSI_NO_TAG,
- FCPIO_FLOGI_REG_GW_DEST,
- fnic->s_id,
- gw_mac);
+ if ((fnic->config.flags & VFCF_FIP_CAPABLE) && !fnic->ctlr.map_dest) {
+ fnic_queue_wq_copy_desc_fip_reg(wq, SCSI_NO_TAG,
+ fc_id, gw_mac,
+ fnic->data_src_addr,
+ lp->r_a_tov, lp->e_d_tov);
+ FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host,
+ "FLOGI FIP reg issued fcid %x src %pM dest %pM\n",
+ fc_id, fnic->data_src_addr, gw_mac);
+ } else {
+ fnic_queue_wq_copy_desc_flogi_reg(wq, SCSI_NO_TAG,
+ format, fc_id, gw_mac);
+ FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host,
+ "FLOGI reg issued fcid %x map %d dest %pM\n",
+ fc_id, fnic->ctlr.map_dest, gw_mac);
+ }
flogi_reg_ioreq_end:
spin_unlock_irqrestore(&fnic->wq_copy_lock[0], flags);
-
- if (!ret)
- FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host,
- "flog reg issued\n");
-
return ret;
}
@@ -319,7 +333,8 @@ static inline int fnic_queue_wq_copy_desc(struct fnic *fnic,
0, /* scsi cmd ref, always 0 */
pri_tag, /* scsi pri and tag */
flags, /* command flags */
- sc->cmnd, scsi_bufflen(sc),
+ sc->cmnd, sc->cmd_len,
+ scsi_bufflen(sc),
fc_lun.scsi_lun, io_req->port_id,
rport->maxframe_size, rp->r_a_tov,
rp->e_d_tov);
@@ -452,7 +467,6 @@ static int fnic_fcpio_fw_reset_cmpl_handler(struct fnic *fnic,
u8 hdr_status;
struct fcpio_tag tag;
int ret = 0;
- struct fc_frame *flogi;
unsigned long flags;
fcpio_header_dec(&desc->hdr, &type, &hdr_status, &tag);
@@ -462,9 +476,6 @@ static int fnic_fcpio_fw_reset_cmpl_handler(struct fnic *fnic,
spin_lock_irqsave(&fnic->fnic_lock, flags);
- flogi = fnic->flogi;
- fnic->flogi = NULL;
-
/* fnic should be in FC_TRANS_ETH_MODE */
if (fnic->state == FNIC_IN_FC_TRANS_ETH_MODE) {
/* Check status of reset completion */
@@ -505,17 +516,14 @@ static int fnic_fcpio_fw_reset_cmpl_handler(struct fnic *fnic,
* free the flogi frame. Else, send it out
*/
if (fnic->remove_wait || ret) {
- fnic->flogi_oxid = FC_XID_UNKNOWN;
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
- if (flogi)
- dev_kfree_skb_irq(fp_skb(flogi));
+ skb_queue_purge(&fnic->tx_queue);
goto reset_cmpl_handler_end;
}
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
- if (flogi)
- ret = fnic_send_frame(fnic, flogi);
+ fnic_flush_tx(fnic);
reset_cmpl_handler_end:
return ret;
@@ -532,18 +540,13 @@ static int fnic_fcpio_flogi_reg_cmpl_handler(struct fnic *fnic,
u8 hdr_status;
struct fcpio_tag tag;
int ret = 0;
- struct fc_frame *flogi_resp = NULL;
unsigned long flags;
- struct sk_buff *skb;
fcpio_header_dec(&desc->hdr, &type, &hdr_status, &tag);
/* Update fnic state based on status of flogi reg completion */
spin_lock_irqsave(&fnic->fnic_lock, flags);
- flogi_resp = fnic->flogi_resp;
- fnic->flogi_resp = NULL;
-
if (fnic->state == FNIC_IN_ETH_TRANS_FC_MODE) {
/* Check flogi registration completion status */
@@ -567,25 +570,17 @@ static int fnic_fcpio_flogi_reg_cmpl_handler(struct fnic *fnic,
ret = -1;
}
- /* Successful flogi reg cmpl, pass frame to LibFC */
- if (!ret && flogi_resp) {
+ if (!ret) {
if (fnic->stop_rx_link_events) {
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
goto reg_cmpl_handler_end;
}
- skb = (struct sk_buff *)flogi_resp;
- /* Use fr_flags to indicate whether flogi resp or not */
- fr_flags(flogi_resp) = 1;
- fr_dev(flogi_resp) = fnic->lport;
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
- skb_queue_tail(&fnic->frame_queue, skb);
+ fnic_flush_tx(fnic);
queue_work(fnic_event_queue, &fnic->frame_work);
-
} else {
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
- if (flogi_resp)
- dev_kfree_skb_irq(fp_skb(flogi_resp));
}
reg_cmpl_handler_end:
@@ -907,6 +902,7 @@ static int fnic_fcpio_cmpl_handler(struct vnic_dev *vdev,
break;
case FCPIO_FLOGI_REG_CMPL: /* fw completed flogi_reg */
+ case FCPIO_FLOGI_FIP_REG_CMPL: /* fw completed flogi_fip_reg */
ret = fnic_fcpio_flogi_reg_cmpl_handler(fnic, desc);
break;
@@ -1224,22 +1220,6 @@ void fnic_terminate_rport_io(struct fc_rport *rport)
}
-static void fnic_block_error_handler(struct scsi_cmnd *sc)
-{
- struct Scsi_Host *shost = sc->device->host;
- struct fc_rport *rport = starget_to_rport(scsi_target(sc->device));
- unsigned long flags;
-
- spin_lock_irqsave(shost->host_lock, flags);
- while (rport->port_state == FC_PORTSTATE_BLOCKED) {
- spin_unlock_irqrestore(shost->host_lock, flags);
- msleep(1000);
- spin_lock_irqsave(shost->host_lock, flags);
- }
- spin_unlock_irqrestore(shost->host_lock, flags);
-
-}
-
/*
* This function is exported to SCSI for sending abort cmnds.
* A SCSI IO is represented by a io_req in the driver.
@@ -1259,7 +1239,7 @@ int fnic_abort_cmd(struct scsi_cmnd *sc)
DECLARE_COMPLETION_ONSTACK(tm_done);
/* Wait for rport to unblock */
- fnic_block_error_handler(sc);
+ fc_block_scsi_eh(sc);
/* Get local-port, check ready and link up */
lp = shost_priv(sc->device->host);
@@ -1541,7 +1521,7 @@ int fnic_device_reset(struct scsi_cmnd *sc)
DECLARE_COMPLETION_ONSTACK(tm_done);
/* Wait for rport to unblock */
- fnic_block_error_handler(sc);
+ fc_block_scsi_eh(sc);
/* Get local-port, check ready and link up */
lp = shost_priv(sc->device->host);
@@ -1762,7 +1742,7 @@ void fnic_scsi_abort_io(struct fc_lport *lp)
fnic->remove_wait = &remove_wait;
old_state = fnic->state;
fnic->state = FNIC_IN_FC_TRANS_ETH_MODE;
- vnic_dev_del_addr(fnic->vdev, fnic->data_src_addr);
+ fnic_update_mac_locked(fnic, fnic->ctlr.ctl_src_addr);
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
err = fnic_fw_reset_handler(fnic);
@@ -1802,7 +1782,7 @@ void fnic_scsi_cleanup(struct fc_lport *lp)
spin_lock_irqsave(&fnic->fnic_lock, flags);
old_state = fnic->state;
fnic->state = FNIC_IN_FC_TRANS_ETH_MODE;
- vnic_dev_del_addr(fnic->vdev, fnic->data_src_addr);
+ fnic_update_mac_locked(fnic, fnic->ctlr.ctl_src_addr);
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
if (fnic_fw_reset_handler(fnic)) {
diff --git a/drivers/scsi/fnic/vnic_scsi.h b/drivers/scsi/fnic/vnic_scsi.h
index 46baa52..fbb5536 100644
--- a/drivers/scsi/fnic/vnic_scsi.h
+++ b/drivers/scsi/fnic/vnic_scsi.h
@@ -95,5 +95,6 @@ struct vnic_fc_config {
#define VFCF_FCP_SEQ_LVL_ERR 0x1 /* Enable FCP-2 Error Recovery */
#define VFCF_PERBI 0x2 /* persistent binding info available */
+#define VFCF_FIP_CAPABLE 0x4 /* firmware can handle FIP */
#endif /* _VNIC_SCSI_H_ */
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index c968cc3..554626e 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -180,14 +180,20 @@ void scsi_remove_host(struct Scsi_Host *shost)
EXPORT_SYMBOL(scsi_remove_host);
/**
- * scsi_add_host - add a scsi host
+ * scsi_add_host_with_dma - add a scsi host with dma device
* @shost: scsi host pointer to add
* @dev: a struct device of type scsi class
+ * @dma_dev: dma device for the host
+ *
+ * Note: You rarely need to worry about this unless you're in a
+ * virtualised host environments, so use the simpler scsi_add_host()
+ * function instead.
*
* Return value:
* 0 on success / != 0 for error
**/
-int scsi_add_host(struct Scsi_Host *shost, struct device *dev)
+int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
+ struct device *dma_dev)
{
struct scsi_host_template *sht = shost->hostt;
int error = -EINVAL;
@@ -207,6 +213,7 @@ int scsi_add_host(struct Scsi_Host *shost, struct device *dev)
if (!shost->shost_gendev.parent)
shost->shost_gendev.parent = dev ? dev : &platform_bus;
+ shost->dma_dev = dma_dev;
error = device_add(&shost->shost_gendev);
if (error)
@@ -262,7 +269,7 @@ int scsi_add_host(struct Scsi_Host *shost, struct device *dev)
fail:
return error;
}
-EXPORT_SYMBOL(scsi_add_host);
+EXPORT_SYMBOL(scsi_add_host_with_dma);
static void scsi_host_dev_release(struct device *dev)
{
diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c
index a0e7e71..4f05565 100644
--- a/drivers/scsi/hptiop.c
+++ b/drivers/scsi/hptiop.c
@@ -834,7 +834,7 @@ static int hptiop_reset_hba(struct hptiop_hba *hba)
atomic_read(&hba->resetting) == 0, 60 * HZ);
if (atomic_read(&hba->resetting)) {
- /* IOP is in unkown state, abort reset */
+ /* IOP is in unknown state, abort reset */
printk(KERN_ERR "scsi%d: reset failed\n", hba->host->host_no);
return -1;
}
@@ -861,10 +861,13 @@ static int hptiop_reset(struct scsi_cmnd *scp)
}
static int hptiop_adjust_disk_queue_depth(struct scsi_device *sdev,
- int queue_depth)
+ int queue_depth, int reason)
{
struct hptiop_hba *hba = (struct hptiop_hba *)sdev->host->hostdata;
+ if (reason != SCSI_QDEPTH_DEFAULT)
+ return -EOPNOTSUPP;
+
if (queue_depth > hba->max_requests)
queue_depth = hba->max_requests;
scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c
index bb2c696..87b536a 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc.c
@@ -39,6 +39,7 @@
#include <scsi/scsi_device.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_transport_fc.h>
+#include <scsi/scsi_bsg_fc.h>
#include "ibmvfc.h"
static unsigned int init_timeout = IBMVFC_INIT_TIMEOUT;
@@ -558,12 +559,11 @@ static void ibmvfc_link_down(struct ibmvfc_host *vhost,
/**
* ibmvfc_init_host - Start host initialization
* @vhost: ibmvfc host struct
- * @relogin: is this a re-login?
*
* Return value:
* nothing
**/
-static void ibmvfc_init_host(struct ibmvfc_host *vhost, int relogin)
+static void ibmvfc_init_host(struct ibmvfc_host *vhost)
{
struct ibmvfc_target *tgt;
@@ -577,10 +577,8 @@ static void ibmvfc_init_host(struct ibmvfc_host *vhost, int relogin)
}
if (!ibmvfc_set_host_state(vhost, IBMVFC_INITIALIZING)) {
- if (!relogin) {
- memset(vhost->async_crq.msgs, 0, PAGE_SIZE);
- vhost->async_crq.cur = 0;
- }
+ memset(vhost->async_crq.msgs, 0, PAGE_SIZE);
+ vhost->async_crq.cur = 0;
list_for_each_entry(tgt, &vhost->targets, queue)
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
@@ -1678,6 +1676,276 @@ static void ibmvfc_sync_completion(struct ibmvfc_event *evt)
}
/**
+ * ibmvfc_bsg_timeout_done - Completion handler for cancelling BSG commands
+ * @evt: struct ibmvfc_event
+ *
+ **/
+static void ibmvfc_bsg_timeout_done(struct ibmvfc_event *evt)
+{
+ struct ibmvfc_host *vhost = evt->vhost;
+
+ ibmvfc_free_event(evt);
+ vhost->aborting_passthru = 0;
+ dev_info(vhost->dev, "Passthru command cancelled\n");
+}
+
+/**
+ * ibmvfc_bsg_timeout - Handle a BSG timeout
+ * @job: struct fc_bsg_job that timed out
+ *
+ * Returns:
+ * 0 on success / other on failure
+ **/
+static int ibmvfc_bsg_timeout(struct fc_bsg_job *job)
+{
+ struct ibmvfc_host *vhost = shost_priv(job->shost);
+ unsigned long port_id = (unsigned long)job->dd_data;
+ struct ibmvfc_event *evt;
+ struct ibmvfc_tmf *tmf;
+ unsigned long flags;
+ int rc;
+
+ ENTER;
+ spin_lock_irqsave(vhost->host->host_lock, flags);
+ if (vhost->aborting_passthru || vhost->state != IBMVFC_ACTIVE) {
+ __ibmvfc_reset_host(vhost);
+ spin_unlock_irqrestore(vhost->host->host_lock, flags);
+ return 0;
+ }
+
+ vhost->aborting_passthru = 1;
+ evt = ibmvfc_get_event(vhost);
+ ibmvfc_init_event(evt, ibmvfc_bsg_timeout_done, IBMVFC_MAD_FORMAT);
+
+ tmf = &evt->iu.tmf;
+ memset(tmf, 0, sizeof(*tmf));
+ tmf->common.version = 1;
+ tmf->common.opcode = IBMVFC_TMF_MAD;
+ tmf->common.length = sizeof(*tmf);
+ tmf->scsi_id = port_id;
+ tmf->cancel_key = IBMVFC_PASSTHRU_CANCEL_KEY;
+ tmf->my_cancel_key = IBMVFC_INTERNAL_CANCEL_KEY;
+ rc = ibmvfc_send_event(evt, vhost, default_timeout);
+
+ if (rc != 0) {
+ vhost->aborting_passthru = 0;
+ dev_err(vhost->dev, "Failed to send cancel event. rc=%d\n", rc);
+ rc = -EIO;
+ } else
+ dev_info(vhost->dev, "Cancelling passthru command to port id 0x%lx\n",
+ port_id);
+
+ spin_unlock_irqrestore(vhost->host->host_lock, flags);
+
+ LEAVE;
+ return rc;
+}
+
+/**
+ * ibmvfc_bsg_plogi - PLOGI into a target to handle a BSG command
+ * @vhost: struct ibmvfc_host to send command
+ * @port_id: port ID to send command
+ *
+ * Returns:
+ * 0 on success / other on failure
+ **/
+static int ibmvfc_bsg_plogi(struct ibmvfc_host *vhost, unsigned int port_id)
+{
+ struct ibmvfc_port_login *plogi;
+ struct ibmvfc_target *tgt;
+ struct ibmvfc_event *evt;
+ union ibmvfc_iu rsp_iu;
+ unsigned long flags;
+ int rc = 0, issue_login = 1;
+
+ ENTER;
+ spin_lock_irqsave(vhost->host->host_lock, flags);
+ list_for_each_entry(tgt, &vhost->targets, queue) {
+ if (tgt->scsi_id == port_id) {
+ issue_login = 0;
+ break;
+ }
+ }
+
+ if (!issue_login)
+ goto unlock_out;
+ if (unlikely((rc = ibmvfc_host_chkready(vhost))))
+ goto unlock_out;
+
+ evt = ibmvfc_get_event(vhost);
+ ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_MAD_FORMAT);
+ plogi = &evt->iu.plogi;
+ memset(plogi, 0, sizeof(*plogi));
+ plogi->common.version = 1;
+ plogi->common.opcode = IBMVFC_PORT_LOGIN;
+ plogi->common.length = sizeof(*plogi);
+ plogi->scsi_id = port_id;
+ evt->sync_iu = &rsp_iu;
+ init_completion(&evt->comp);
+
+ rc = ibmvfc_send_event(evt, vhost, default_timeout);
+ spin_unlock_irqrestore(vhost->host->host_lock, flags);
+
+ if (rc)
+ return -EIO;
+
+ wait_for_completion(&evt->comp);
+
+ if (rsp_iu.plogi.common.status)
+ rc = -EIO;
+
+ spin_lock_irqsave(vhost->host->host_lock, flags);
+ ibmvfc_free_event(evt);
+unlock_out:
+ spin_unlock_irqrestore(vhost->host->host_lock, flags);
+ LEAVE;
+ return rc;
+}
+
+/**
+ * ibmvfc_bsg_request - Handle a BSG request
+ * @job: struct fc_bsg_job to be executed
+ *
+ * Returns:
+ * 0 on success / other on failure
+ **/
+static int ibmvfc_bsg_request(struct fc_bsg_job *job)
+{
+ struct ibmvfc_host *vhost = shost_priv(job->shost);
+ struct fc_rport *rport = job->rport;
+ struct ibmvfc_passthru_mad *mad;
+ struct ibmvfc_event *evt;
+ union ibmvfc_iu rsp_iu;
+ unsigned long flags, port_id = -1;
+ unsigned int code = job->request->msgcode;
+ int rc = 0, req_seg, rsp_seg, issue_login = 0;
+ u32 fc_flags, rsp_len;
+
+ ENTER;
+ job->reply->reply_payload_rcv_len = 0;
+ if (rport)
+ port_id = rport->port_id;
+
+ switch (code) {
+ case FC_BSG_HST_ELS_NOLOGIN:
+ port_id = (job->request->rqst_data.h_els.port_id[0] << 16) |
+ (job->request->rqst_data.h_els.port_id[1] << 8) |
+ job->request->rqst_data.h_els.port_id[2];
+ case FC_BSG_RPT_ELS:
+ fc_flags = IBMVFC_FC_ELS;
+ break;
+ case FC_BSG_HST_CT:
+ issue_login = 1;
+ port_id = (job->request->rqst_data.h_ct.port_id[0] << 16) |
+ (job->request->rqst_data.h_ct.port_id[1] << 8) |
+ job->request->rqst_data.h_ct.port_id[2];
+ case FC_BSG_RPT_CT:
+ fc_flags = IBMVFC_FC_CT_IU;
+ break;
+ default:
+ return -ENOTSUPP;
+ };
+
+ if (port_id == -1)
+ return -EINVAL;
+ if (!mutex_trylock(&vhost->passthru_mutex))
+ return -EBUSY;
+
+ job->dd_data = (void *)port_id;
+ req_seg = dma_map_sg(vhost->dev, job->request_payload.sg_list,
+ job->request_payload.sg_cnt, DMA_TO_DEVICE);
+
+ if (!req_seg) {
+ mutex_unlock(&vhost->passthru_mutex);
+ return -ENOMEM;
+ }
+
+ rsp_seg = dma_map_sg(vhost->dev, job->reply_payload.sg_list,
+ job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+
+ if (!rsp_seg) {
+ dma_unmap_sg(vhost->dev, job->request_payload.sg_list,
+ job->request_payload.sg_cnt, DMA_TO_DEVICE);
+ mutex_unlock(&vhost->passthru_mutex);
+ return -ENOMEM;
+ }
+
+ if (req_seg > 1 || rsp_seg > 1) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ if (issue_login)
+ rc = ibmvfc_bsg_plogi(vhost, port_id);
+
+ spin_lock_irqsave(vhost->host->host_lock, flags);
+
+ if (unlikely(rc || (rport && (rc = fc_remote_port_chkready(rport)))) ||
+ unlikely((rc = ibmvfc_host_chkready(vhost)))) {
+ spin_unlock_irqrestore(vhost->host->host_lock, flags);
+ goto out;
+ }
+
+ evt = ibmvfc_get_event(vhost);
+ ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_MAD_FORMAT);
+ mad = &evt->iu.passthru;
+
+ memset(mad, 0, sizeof(*mad));
+ mad->common.version = 1;
+ mad->common.opcode = IBMVFC_PASSTHRU;
+ mad->common.length = sizeof(*mad) - sizeof(mad->fc_iu) - sizeof(mad->iu);
+
+ mad->cmd_ioba.va = (u64)evt->crq.ioba +
+ offsetof(struct ibmvfc_passthru_mad, iu);
+ mad->cmd_ioba.len = sizeof(mad->iu);
+
+ mad->iu.cmd_len = job->request_payload.payload_len;
+ mad->iu.rsp_len = job->reply_payload.payload_len;
+ mad->iu.flags = fc_flags;
+ mad->iu.cancel_key = IBMVFC_PASSTHRU_CANCEL_KEY;
+
+ mad->iu.cmd.va = sg_dma_address(job->request_payload.sg_list);
+ mad->iu.cmd.len = sg_dma_len(job->request_payload.sg_list);
+ mad->iu.rsp.va = sg_dma_address(job->reply_payload.sg_list);
+ mad->iu.rsp.len = sg_dma_len(job->reply_payload.sg_list);
+ mad->iu.scsi_id = port_id;
+ mad->iu.tag = (u64)evt;
+ rsp_len = mad->iu.rsp.len;
+
+ evt->sync_iu = &rsp_iu;
+ init_completion(&evt->comp);
+ rc = ibmvfc_send_event(evt, vhost, 0);
+ spin_unlock_irqrestore(vhost->host->host_lock, flags);
+
+ if (rc) {
+ rc = -EIO;
+ goto out;
+ }
+
+ wait_for_completion(&evt->comp);
+
+ if (rsp_iu.passthru.common.status)
+ rc = -EIO;
+ else
+ job->reply->reply_payload_rcv_len = rsp_len;
+
+ spin_lock_irqsave(vhost->host->host_lock, flags);
+ ibmvfc_free_event(evt);
+ spin_unlock_irqrestore(vhost->host->host_lock, flags);
+ job->reply->result = rc;
+ job->job_done(job);
+ rc = 0;
+out:
+ dma_unmap_sg(vhost->dev, job->request_payload.sg_list,
+ job->request_payload.sg_cnt, DMA_TO_DEVICE);
+ dma_unmap_sg(vhost->dev, job->reply_payload.sg_list,
+ job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+ mutex_unlock(&vhost->passthru_mutex);
+ LEAVE;
+ return rc;
+}
+
+/**
* ibmvfc_reset_device - Reset the device with the specified reset type
* @sdev: scsi device to reset
* @type: reset type
@@ -1731,7 +1999,10 @@ static int ibmvfc_reset_device(struct scsi_device *sdev, int type, char *desc)
sdev_printk(KERN_INFO, sdev, "Resetting %s\n", desc);
wait_for_completion(&evt->comp);
- if (rsp_iu.cmd.status) {
+ if (rsp_iu.cmd.status)
+ rsp_code = ibmvfc_get_err_result(&rsp_iu.cmd);
+
+ if (rsp_code) {
if (fc_rsp->flags & FCP_RSP_LEN_VALID)
rsp_code = fc_rsp->data.info.rsp_code;
@@ -1820,7 +2091,10 @@ static int ibmvfc_abort_task_set(struct scsi_device *sdev)
sdev_printk(KERN_INFO, sdev, "Aborting outstanding commands\n");
wait_for_completion(&evt->comp);
- if (rsp_iu.cmd.status) {
+ if (rsp_iu.cmd.status)
+ rsp_code = ibmvfc_get_err_result(&rsp_iu.cmd);
+
+ if (rsp_code) {
if (fc_rsp->flags & FCP_RSP_LEN_VALID)
rsp_code = fc_rsp->data.info.rsp_code;
@@ -2061,12 +2335,24 @@ static int ibmvfc_eh_device_reset_handler(struct scsi_cmnd *cmd)
}
/**
- * ibmvfc_dev_cancel_all - Device iterated cancel all function
+ * ibmvfc_dev_cancel_all_abts - Device iterated cancel all function
* @sdev: scsi device struct
* @data: return code
*
**/
-static void ibmvfc_dev_cancel_all(struct scsi_device *sdev, void *data)
+static void ibmvfc_dev_cancel_all_abts(struct scsi_device *sdev, void *data)
+{
+ unsigned long *rc = data;
+ *rc |= ibmvfc_cancel_all(sdev, IBMVFC_TMF_ABORT_TASK_SET);
+}
+
+/**
+ * ibmvfc_dev_cancel_all_reset - Device iterated cancel all function
+ * @sdev: scsi device struct
+ * @data: return code
+ *
+ **/
+static void ibmvfc_dev_cancel_all_reset(struct scsi_device *sdev, void *data)
{
unsigned long *rc = data;
*rc |= ibmvfc_cancel_all(sdev, IBMVFC_TMF_TGT_RESET);
@@ -2102,7 +2388,7 @@ static int ibmvfc_eh_target_reset_handler(struct scsi_cmnd *cmd)
ENTER;
ibmvfc_wait_while_resetting(vhost);
- starget_for_each_device(starget, &cancel_rc, ibmvfc_dev_cancel_all);
+ starget_for_each_device(starget, &cancel_rc, ibmvfc_dev_cancel_all_reset);
reset_rc = ibmvfc_reset_device(sdev, IBMVFC_TARGET_RESET, "target");
if (!cancel_rc && !reset_rc)
@@ -2144,7 +2430,7 @@ static void ibmvfc_terminate_rport_io(struct fc_rport *rport)
int rc = FAILED;
ENTER;
- starget_for_each_device(starget, &cancel_rc, ibmvfc_dev_cancel_all);
+ starget_for_each_device(starget, &cancel_rc, ibmvfc_dev_cancel_all_abts);
starget_for_each_device(starget, &abort_rc, ibmvfc_dev_abort_all);
if (!cancel_rc && !abort_rc)
@@ -2297,13 +2583,13 @@ static void ibmvfc_handle_crq(struct ibmvfc_crq *crq, struct ibmvfc_host *vhost)
/* Send back a response */
rc = ibmvfc_send_crq_init_complete(vhost);
if (rc == 0)
- ibmvfc_init_host(vhost, 0);
+ ibmvfc_init_host(vhost);
else
dev_err(vhost->dev, "Unable to send init rsp. rc=%ld\n", rc);
break;
case IBMVFC_CRQ_INIT_COMPLETE:
dev_info(vhost->dev, "Partner initialization complete\n");
- ibmvfc_init_host(vhost, 0);
+ ibmvfc_init_host(vhost);
break;
default:
dev_err(vhost->dev, "Unknown crq message type: %d\n", crq->format);
@@ -2478,12 +2764,17 @@ static int ibmvfc_slave_configure(struct scsi_device *sdev)
* ibmvfc_change_queue_depth - Change the device's queue depth
* @sdev: scsi device struct
* @qdepth: depth to set
+ * @reason: calling context
*
* Return value:
* actual depth set
**/
-static int ibmvfc_change_queue_depth(struct scsi_device *sdev, int qdepth)
+static int ibmvfc_change_queue_depth(struct scsi_device *sdev, int qdepth,
+ int reason)
{
+ if (reason != SCSI_QDEPTH_DEFAULT)
+ return -EOPNOTSUPP;
+
if (qdepth > IBMVFC_MAX_CMDS_PER_LUN)
qdepth = IBMVFC_MAX_CMDS_PER_LUN;
@@ -3725,7 +4016,7 @@ static void ibmvfc_npiv_logout_done(struct ibmvfc_event *evt)
case IBMVFC_MAD_SUCCESS:
if (list_empty(&vhost->sent) &&
vhost->action == IBMVFC_HOST_ACTION_LOGO_WAIT) {
- ibmvfc_init_host(vhost, 0);
+ ibmvfc_init_host(vhost);
return;
}
break;
@@ -3903,6 +4194,8 @@ static void ibmvfc_tgt_add_rport(struct ibmvfc_target *tgt)
rport->supported_classes |= FC_COS_CLASS2;
if (tgt->service_parms.class3_parms[0] & 0x80000000)
rport->supported_classes |= FC_COS_CLASS3;
+ if (rport->rqst_q)
+ blk_queue_max_hw_segments(rport->rqst_q, 1);
} else
tgt_dbg(tgt, "rport add failed\n");
spin_unlock_irqrestore(vhost->host->host_lock, flags);
@@ -4342,6 +4635,7 @@ static int ibmvfc_probe(struct vio_dev *vdev, const struct vio_device_id *id)
init_waitqueue_head(&vhost->work_wait_q);
init_waitqueue_head(&vhost->init_wait_q);
INIT_WORK(&vhost->rport_add_work_q, ibmvfc_rport_add_thread);
+ mutex_init(&vhost->passthru_mutex);
if ((rc = ibmvfc_alloc_mem(vhost)))
goto free_scsi_host;
@@ -4374,6 +4668,8 @@ static int ibmvfc_probe(struct vio_dev *vdev, const struct vio_device_id *id)
goto remove_shost;
}
+ if (shost_to_fc_host(shost)->rqst_q)
+ blk_queue_max_hw_segments(shost_to_fc_host(shost)->rqst_q, 1);
dev_set_drvdata(dev, vhost);
spin_lock(&ibmvfc_driver_lock);
list_add_tail(&vhost->queue, &ibmvfc_head);
@@ -4414,7 +4710,11 @@ static int ibmvfc_remove(struct vio_dev *vdev)
ENTER;
ibmvfc_remove_trace_file(&vhost->host->shost_dev.kobj, &ibmvfc_trace_attr);
+
+ spin_lock_irqsave(vhost->host->host_lock, flags);
ibmvfc_link_down(vhost, IBMVFC_HOST_OFFLINE);
+ spin_unlock_irqrestore(vhost->host->host_lock, flags);
+
ibmvfc_wait_while_resetting(vhost);
ibmvfc_release_crq_queue(vhost);
kthread_stop(vhost->work_thread);
@@ -4498,6 +4798,9 @@ static struct fc_function_template ibmvfc_transport_functions = {
.get_starget_port_id = ibmvfc_get_starget_port_id,
.show_starget_port_id = 1,
+
+ .bsg_request = ibmvfc_bsg_request,
+ .bsg_timeout = ibmvfc_bsg_timeout,
};
/**
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h
index 007fa1c9..d25106a 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.h
+++ b/drivers/scsi/ibmvscsi/ibmvfc.h
@@ -29,8 +29,8 @@
#include "viosrp.h"
#define IBMVFC_NAME "ibmvfc"
-#define IBMVFC_DRIVER_VERSION "1.0.6"
-#define IBMVFC_DRIVER_DATE "(May 28, 2009)"
+#define IBMVFC_DRIVER_VERSION "1.0.7"
+#define IBMVFC_DRIVER_DATE "(October 16, 2009)"
#define IBMVFC_DEFAULT_TIMEOUT 60
#define IBMVFC_ADISC_CANCEL_TIMEOUT 45
@@ -58,9 +58,10 @@
* 1 for ERP
* 1 for initialization
* 1 for NPIV Logout
+ * 2 for BSG passthru
* 2 for each discovery thread
*/
-#define IBMVFC_NUM_INTERNAL_REQ (1 + 1 + 1 + (disc_threads * 2))
+#define IBMVFC_NUM_INTERNAL_REQ (1 + 1 + 1 + 2 + (disc_threads * 2))
#define IBMVFC_MAD_SUCCESS 0x00
#define IBMVFC_MAD_NOT_SUPPORTED 0xF1
@@ -466,7 +467,10 @@ struct ibmvfc_passthru_iu {
u16 error;
u32 flags;
#define IBMVFC_FC_ELS 0x01
+#define IBMVFC_FC_CT_IU 0x02
u32 cancel_key;
+#define IBMVFC_PASSTHRU_CANCEL_KEY 0x80000000
+#define IBMVFC_INTERNAL_CANCEL_KEY 0x80000001
u32 reserved;
struct srp_direct_buf cmd;
struct srp_direct_buf rsp;
@@ -693,6 +697,7 @@ struct ibmvfc_host {
int disc_buf_sz;
int log_level;
struct ibmvfc_discover_targets_buf *disc_buf;
+ struct mutex passthru_mutex;
int task_set;
int init_retries;
int discovery_threads;
@@ -702,6 +707,7 @@ struct ibmvfc_host {
int delay_init;
int scan_complete;
int logged_in;
+ int aborting_passthru;
int events_to_log;
#define IBMVFC_AE_LINKUP 0x0001
#define IBMVFC_AE_LINKDOWN 0x0002
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index d9b0e9d..e475b79 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -1637,12 +1637,17 @@ static int ibmvscsi_slave_configure(struct scsi_device *sdev)
* ibmvscsi_change_queue_depth - Change the device's queue depth
* @sdev: scsi device struct
* @qdepth: depth to set
+ * @reason: calling context
*
* Return value:
* actual depth set
**/
-static int ibmvscsi_change_queue_depth(struct scsi_device *sdev, int qdepth)
+static int ibmvscsi_change_queue_depth(struct scsi_device *sdev, int qdepth,
+ int reason)
{
+ if (reason != SCSI_QDEPTH_DEFAULT)
+ return -EOPNOTSUPP;
+
if (qdepth > IBMVSCSI_MAX_CMDS_PER_LUN)
qdepth = IBMVSCSI_MAX_CMDS_PER_LUN;
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 76d294f..206c2fa 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -3367,16 +3367,21 @@ static int ipr_free_dump(struct ipr_ioa_cfg *ioa_cfg) { return 0; };
* ipr_change_queue_depth - Change the device's queue depth
* @sdev: scsi device struct
* @qdepth: depth to set
+ * @reason: calling context
*
* Return value:
* actual depth set
**/
-static int ipr_change_queue_depth(struct scsi_device *sdev, int qdepth)
+static int ipr_change_queue_depth(struct scsi_device *sdev, int qdepth,
+ int reason)
{
struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)sdev->host->hostdata;
struct ipr_resource_entry *res;
unsigned long lock_flags = 0;
+ if (reason != SCSI_QDEPTH_DEFAULT)
+ return -EOPNOTSUPP;
+
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
res = (struct ipr_resource_entry *)sdev->hostdata;
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index edc49ca..517da3f 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -903,7 +903,7 @@ static struct iscsi_transport iscsi_sw_tcp_transport = {
ISCSI_USERNAME | ISCSI_PASSWORD |
ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN |
ISCSI_FAST_ABORT | ISCSI_ABORT_TMO |
- ISCSI_LU_RESET_TMO |
+ ISCSI_LU_RESET_TMO | ISCSI_TGT_RESET_TMO |
ISCSI_PING_TMO | ISCSI_RECV_TMO |
ISCSI_IFACE_NAME | ISCSI_INITIATOR_NAME,
.host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS |
diff --git a/drivers/scsi/libfc/Makefile b/drivers/scsi/libfc/Makefile
index 55f982d..4bb23ac 100644
--- a/drivers/scsi/libfc/Makefile
+++ b/drivers/scsi/libfc/Makefile
@@ -3,10 +3,12 @@
obj-$(CONFIG_LIBFC) += libfc.o
libfc-objs := \
+ fc_libfc.o \
fc_disc.o \
fc_exch.o \
fc_elsct.o \
fc_frame.o \
fc_lport.o \
fc_rport.o \
- fc_fcp.o
+ fc_fcp.o \
+ fc_npiv.o
diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c
index c48799e..9b0a519 100644
--- a/drivers/scsi/libfc/fc_disc.c
+++ b/drivers/scsi/libfc/fc_disc.c
@@ -40,6 +40,8 @@
#include <scsi/libfc.h>
+#include "fc_libfc.h"
+
#define FC_DISC_RETRY_LIMIT 3 /* max retries */
#define FC_DISC_RETRY_DELAY 500UL /* (msecs) delay */
@@ -51,8 +53,8 @@ static int fc_disc_single(struct fc_lport *, struct fc_disc_port *);
static void fc_disc_restart(struct fc_disc *);
/**
- * fc_disc_stop_rports() - delete all the remote ports associated with the lport
- * @disc: The discovery job to stop rports on
+ * fc_disc_stop_rports() - Delete all the remote ports associated with the lport
+ * @disc: The discovery job to stop remote ports on
*
* Locking Note: This function expects that the lport mutex is locked before
* calling it.
@@ -72,9 +74,9 @@ void fc_disc_stop_rports(struct fc_disc *disc)
/**
* fc_disc_recv_rscn_req() - Handle Registered State Change Notification (RSCN)
- * @sp: Current sequence of the RSCN exchange
- * @fp: RSCN Frame
- * @lport: Fibre Channel host port instance
+ * @sp: The sequence of the RSCN exchange
+ * @fp: The RSCN frame
+ * @lport: The local port that the request will be sent on
*
* Locking Note: This function expects that the disc_mutex is locked
* before it is called.
@@ -183,9 +185,9 @@ reject:
/**
* fc_disc_recv_req() - Handle incoming requests
- * @sp: Current sequence of the request exchange
- * @fp: The frame
- * @lport: The FC local port
+ * @sp: The sequence of the request exchange
+ * @fp: The request frame
+ * @lport: The local port receiving the request
*
* Locking Note: This function is called from the EM and will lock
* the disc_mutex before calling the handler for the
@@ -213,7 +215,7 @@ static void fc_disc_recv_req(struct fc_seq *sp, struct fc_frame *fp,
/**
* fc_disc_restart() - Restart discovery
- * @lport: FC discovery context
+ * @disc: The discovery object to be restarted
*
* Locking Note: This function expects that the disc mutex
* is already locked.
@@ -240,9 +242,9 @@ static void fc_disc_restart(struct fc_disc *disc)
}
/**
- * fc_disc_start() - Fibre Channel Target discovery
- * @lport: FC local port
- * @disc_callback: function to be called when discovery is complete
+ * fc_disc_start() - Start discovery on a local port
+ * @lport: The local port to have discovery started on
+ * @disc_callback: Callback function to be called when discovery is complete
*/
static void fc_disc_start(void (*disc_callback)(struct fc_lport *,
enum fc_disc_event),
@@ -263,8 +265,8 @@ static void fc_disc_start(void (*disc_callback)(struct fc_lport *,
/**
* fc_disc_done() - Discovery has been completed
- * @disc: FC discovery context
- * @event: discovery completion status
+ * @disc: The discovery context
+ * @event: The discovery completion status
*
* Locking Note: This function expects that the disc mutex is locked before
* it is called. The discovery callback is then made with the lock released,
@@ -284,8 +286,8 @@ static void fc_disc_done(struct fc_disc *disc, enum fc_disc_event event)
}
/*
- * Go through all remote ports. If they were found in the latest
- * discovery, reverify or log them in. Otherwise, log them out.
+ * Go through all remote ports. If they were found in the latest
+ * discovery, reverify or log them in. Otherwise, log them out.
* Skip ports which were never discovered. These are the dNS port
* and ports which were created by PLOGI.
*/
@@ -305,8 +307,8 @@ static void fc_disc_done(struct fc_disc *disc, enum fc_disc_event event)
/**
* fc_disc_error() - Handle error on dNS request
- * @disc: FC discovery context
- * @fp: The frame pointer
+ * @disc: The discovery context
+ * @fp: The error code encoded as a frame pointer
*/
static void fc_disc_error(struct fc_disc *disc, struct fc_frame *fp)
{
@@ -342,7 +344,7 @@ static void fc_disc_error(struct fc_disc *disc, struct fc_frame *fp)
/**
* fc_disc_gpn_ft_req() - Send Get Port Names by FC-4 type (GPN_FT) request
- * @lport: FC discovery context
+ * @lport: The discovery context
*
* Locking Note: This function expects that the disc_mutex is locked
* before it is called.
@@ -368,17 +370,17 @@ static void fc_disc_gpn_ft_req(struct fc_disc *disc)
if (lport->tt.elsct_send(lport, 0, fp,
FC_NS_GPN_FT,
fc_disc_gpn_ft_resp,
- disc, lport->e_d_tov))
+ disc, 3 * lport->r_a_tov))
return;
err:
- fc_disc_error(disc, fp);
+ fc_disc_error(disc, NULL);
}
/**
* fc_disc_gpn_ft_parse() - Parse the body of the dNS GPN_FT response.
- * @lport: Fibre Channel host port instance
- * @buf: GPN_FT response buffer
- * @len: size of response buffer
+ * @lport: The local port the GPN_FT was received on
+ * @buf: The GPN_FT response buffer
+ * @len: The size of response buffer
*
* Goes through the list of IDs and names resulting from a request.
*/
@@ -477,10 +479,8 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len)
}
/**
- * fc_disc_timeout() - Retry handler for the disc component
- * @work: Structure holding disc obj that needs retry discovery
- *
- * Handle retry of memory allocation for remote ports.
+ * fc_disc_timeout() - Handler for discovery timeouts
+ * @work: Structure holding discovery context that needs to retry discovery
*/
static void fc_disc_timeout(struct work_struct *work)
{
@@ -494,9 +494,9 @@ static void fc_disc_timeout(struct work_struct *work)
/**
* fc_disc_gpn_ft_resp() - Handle a response frame from Get Port Names (GPN_FT)
- * @sp: Current sequence of GPN_FT exchange
- * @fp: response frame
- * @lp_arg: Fibre Channel host port instance
+ * @sp: The sequence that the GPN_FT response was received on
+ * @fp: The GPN_FT response frame
+ * @lp_arg: The discovery context
*
* Locking Note: This function is called without disc mutex held, and
* should do all its processing with the mutex held
@@ -567,9 +567,9 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp,
/**
* fc_disc_gpn_id_resp() - Handle a response frame from Get Port Names (GPN_ID)
- * @sp: exchange sequence
- * @fp: response frame
- * @rdata_arg: remote port private data
+ * @sp: The sequence the GPN_ID is on
+ * @fp: The response frame
+ * @rdata_arg: The remote port that sent the GPN_ID response
*
* Locking Note: This function is called without disc mutex held.
*/
@@ -637,7 +637,7 @@ out:
/**
* fc_disc_gpn_id_req() - Send Get Port Names by ID (GPN_ID) request
- * @lport: local port
+ * @lport: The local port to initiate discovery on
* @rdata: remote port private data
*
* Locking Note: This function expects that the disc_mutex is locked
@@ -654,7 +654,8 @@ static int fc_disc_gpn_id_req(struct fc_lport *lport,
if (!fp)
return -ENOMEM;
if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, FC_NS_GPN_ID,
- fc_disc_gpn_id_resp, rdata, lport->e_d_tov))
+ fc_disc_gpn_id_resp, rdata,
+ 3 * lport->r_a_tov))
return -ENOMEM;
kref_get(&rdata->kref);
return 0;
@@ -662,8 +663,8 @@ static int fc_disc_gpn_id_req(struct fc_lport *lport,
/**
* fc_disc_single() - Discover the directory information for a single target
- * @lport: local port
- * @dp: The port to rediscover
+ * @lport: The local port the remote port is associated with
+ * @dp: The port to rediscover
*
* Locking Note: This function expects that the disc_mutex is locked
* before it is called.
@@ -681,7 +682,7 @@ static int fc_disc_single(struct fc_lport *lport, struct fc_disc_port *dp)
/**
* fc_disc_stop() - Stop discovery for a given lport
- * @lport: The lport that discovery should stop for
+ * @lport: The local port that discovery should stop on
*/
void fc_disc_stop(struct fc_lport *lport)
{
@@ -695,7 +696,7 @@ void fc_disc_stop(struct fc_lport *lport)
/**
* fc_disc_stop_final() - Stop discovery for a given lport
- * @lport: The lport that discovery should stop for
+ * @lport: The lport that discovery should stop on
*
* This function will block until discovery has been
* completely stopped and all rports have been deleted.
@@ -707,8 +708,8 @@ void fc_disc_stop_final(struct fc_lport *lport)
}
/**
- * fc_disc_init() - Initialize the discovery block
- * @lport: FC local port
+ * fc_disc_init() - Initialize the discovery layer for a local port
+ * @lport: The local port that needs the discovery layer to be initialized
*/
int fc_disc_init(struct fc_lport *lport)
{
diff --git a/drivers/scsi/libfc/fc_elsct.c b/drivers/scsi/libfc/fc_elsct.c
index 5cfa687..53748724 100644
--- a/drivers/scsi/libfc/fc_elsct.c
+++ b/drivers/scsi/libfc/fc_elsct.c
@@ -28,17 +28,22 @@
#include <scsi/libfc.h>
#include <scsi/fc_encode.h>
-/*
- * fc_elsct_send - sends ELS/CT frame
+/**
+ * fc_elsct_send() - Send an ELS or CT frame
+ * @lport: The local port to send the frame on
+ * @did: The destination ID for the frame
+ * @fp: The frame to be sent
+ * @op: The operational code
+ * @resp: The callback routine when the response is received
+ * @arg: The argument to pass to the response callback routine
+ * @timer_msec: The timeout period for the frame (in msecs)
*/
-static struct fc_seq *fc_elsct_send(struct fc_lport *lport,
- u32 did,
- struct fc_frame *fp,
- unsigned int op,
- void (*resp)(struct fc_seq *,
- struct fc_frame *fp,
- void *arg),
- void *arg, u32 timer_msec)
+struct fc_seq *fc_elsct_send(struct fc_lport *lport, u32 did,
+ struct fc_frame *fp, unsigned int op,
+ void (*resp)(struct fc_seq *,
+ struct fc_frame *,
+ void *),
+ void *arg, u32 timer_msec)
{
enum fc_rctl r_ctl;
enum fc_fh_type fh_type;
@@ -53,15 +58,22 @@ static struct fc_seq *fc_elsct_send(struct fc_lport *lport,
did = FC_FID_DIR_SERV;
}
- if (rc)
+ if (rc) {
+ fc_frame_free(fp);
return NULL;
+ }
fc_fill_fc_hdr(fp, r_ctl, did, fc_host_port_id(lport->host), fh_type,
FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
return lport->tt.exch_seq_send(lport, fp, resp, NULL, arg, timer_msec);
}
+EXPORT_SYMBOL(fc_elsct_send);
+/**
+ * fc_elsct_init() - Initialize the ELS/CT layer
+ * @lport: The local port to initialize the ELS/CT layer for
+ */
int fc_elsct_init(struct fc_lport *lport)
{
if (!lport->tt.elsct_send)
@@ -72,12 +84,15 @@ int fc_elsct_init(struct fc_lport *lport)
EXPORT_SYMBOL(fc_elsct_init);
/**
- * fc_els_resp_type() - return string describing ELS response for debug.
- * @fp: frame pointer with possible error code.
+ * fc_els_resp_type() - Return a string describing the ELS response
+ * @fp: The frame pointer or possible error code
*/
const char *fc_els_resp_type(struct fc_frame *fp)
{
const char *msg;
+ struct fc_frame_header *fh;
+ struct fc_ct_hdr *ct;
+
if (IS_ERR(fp)) {
switch (-PTR_ERR(fp)) {
case FC_NO_ERR:
@@ -94,15 +109,41 @@ const char *fc_els_resp_type(struct fc_frame *fp)
break;
}
} else {
- switch (fc_frame_payload_op(fp)) {
- case ELS_LS_ACC:
- msg = "accept";
+ fh = fc_frame_header_get(fp);
+ switch (fh->fh_type) {
+ case FC_TYPE_ELS:
+ switch (fc_frame_payload_op(fp)) {
+ case ELS_LS_ACC:
+ msg = "accept";
+ break;
+ case ELS_LS_RJT:
+ msg = "reject";
+ break;
+ default:
+ msg = "response unknown ELS";
+ break;
+ }
break;
- case ELS_LS_RJT:
- msg = "reject";
+ case FC_TYPE_CT:
+ ct = fc_frame_payload_get(fp, sizeof(*ct));
+ if (ct) {
+ switch (ntohs(ct->ct_cmd)) {
+ case FC_FS_ACC:
+ msg = "CT accept";
+ break;
+ case FC_FS_RJT:
+ msg = "CT reject";
+ break;
+ default:
+ msg = "response unknown CT";
+ break;
+ }
+ } else {
+ msg = "short CT response";
+ }
break;
default:
- msg = "response unknown ELS";
+ msg = "response not ELS or CT";
break;
}
}
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c
index c1c1574..19d711c 100644
--- a/drivers/scsi/libfc/fc_exch.c
+++ b/drivers/scsi/libfc/fc_exch.c
@@ -32,10 +32,13 @@
#include <scsi/libfc.h>
#include <scsi/fc_encode.h>
+#include "fc_libfc.h"
+
u16 fc_cpu_mask; /* cpu mask for possible cpus */
EXPORT_SYMBOL(fc_cpu_mask);
static u16 fc_cpu_order; /* 2's power to represent total possible cpus */
-static struct kmem_cache *fc_em_cachep; /* cache for exchanges */
+static struct kmem_cache *fc_em_cachep; /* cache for exchanges */
+struct workqueue_struct *fc_exch_workqueue;
/*
* Structure and function definitions for managing Fibre Channel Exchanges
@@ -50,35 +53,46 @@ static struct kmem_cache *fc_em_cachep; /* cache for exchanges */
* fc_seq holds the state for an individual sequence.
*/
-/*
- * Per cpu exchange pool
+/**
+ * struct fc_exch_pool - Per cpu exchange pool
+ * @next_index: Next possible free exchange index
+ * @total_exches: Total allocated exchanges
+ * @lock: Exch pool lock
+ * @ex_list: List of exchanges
*
* This structure manages per cpu exchanges in array of exchange pointers.
* This array is allocated followed by struct fc_exch_pool memory for
* assigned range of exchanges to per cpu pool.
*/
struct fc_exch_pool {
- u16 next_index; /* next possible free exchange index */
- u16 total_exches; /* total allocated exchanges */
- spinlock_t lock; /* exch pool lock */
- struct list_head ex_list; /* allocated exchanges list */
+ u16 next_index;
+ u16 total_exches;
+ spinlock_t lock;
+ struct list_head ex_list;
};
-/*
- * Exchange manager.
+/**
+ * struct fc_exch_mgr - The Exchange Manager (EM).
+ * @class: Default class for new sequences
+ * @kref: Reference counter
+ * @min_xid: Minimum exchange ID
+ * @max_xid: Maximum exchange ID
+ * @ep_pool: Reserved exchange pointers
+ * @pool_max_index: Max exch array index in exch pool
+ * @pool: Per cpu exch pool
+ * @stats: Statistics structure
*
* This structure is the center for creating exchanges and sequences.
* It manages the allocation of exchange IDs.
*/
struct fc_exch_mgr {
- enum fc_class class; /* default class for sequences */
- struct kref kref; /* exchange mgr reference count */
- u16 min_xid; /* min exchange ID */
- u16 max_xid; /* max exchange ID */
- struct list_head ex_list; /* allocated exchanges list */
- mempool_t *ep_pool; /* reserve ep's */
- u16 pool_max_index; /* max exch array index in exch pool */
- struct fc_exch_pool *pool; /* per cpu exch pool */
+ enum fc_class class;
+ struct kref kref;
+ u16 min_xid;
+ u16 max_xid;
+ mempool_t *ep_pool;
+ u16 pool_max_index;
+ struct fc_exch_pool *pool;
/*
* currently exchange mgr stats are updated but not used.
@@ -96,6 +110,18 @@ struct fc_exch_mgr {
};
#define fc_seq_exch(sp) container_of(sp, struct fc_exch, seq)
+/**
+ * struct fc_exch_mgr_anchor - primary structure for list of EMs
+ * @ema_list: Exchange Manager Anchor list
+ * @mp: Exchange Manager associated with this anchor
+ * @match: Routine to determine if this anchor's EM should be used
+ *
+ * When walking the list of anchors the match routine will be called
+ * for each anchor to determine if that EM should be used. The last
+ * anchor in the list will always match to handle any exchanges not
+ * handled by other EMs. The non-default EMs would be added to the
+ * anchor list by HW that provides FCoE offloads.
+ */
struct fc_exch_mgr_anchor {
struct list_head ema_list;
struct fc_exch_mgr *mp;
@@ -108,7 +134,6 @@ static void fc_seq_ls_rjt(struct fc_seq *, enum fc_els_rjt_reason,
enum fc_els_rjt_explan);
static void fc_exch_els_rec(struct fc_seq *, struct fc_frame *);
static void fc_exch_els_rrq(struct fc_seq *, struct fc_frame *);
-static struct fc_seq *fc_seq_start_next_locked(struct fc_seq *sp);
/*
* Internal implementation notes.
@@ -196,6 +221,15 @@ static char *fc_exch_rctl_names[] = FC_RCTL_NAMES_INIT;
#define FC_TABLE_SIZE(x) (sizeof(x) / sizeof(x[0]))
+/**
+ * fc_exch_name_lookup() - Lookup name by opcode
+ * @op: Opcode to be looked up
+ * @table: Opcode/name table
+ * @max_index: Index not to be exceeded
+ *
+ * This routine is used to determine a human-readable string identifying
+ * a R_CTL opcode.
+ */
static inline const char *fc_exch_name_lookup(unsigned int op, char **table,
unsigned int max_index)
{
@@ -208,25 +242,34 @@ static inline const char *fc_exch_name_lookup(unsigned int op, char **table,
return name;
}
+/**
+ * fc_exch_rctl_name() - Wrapper routine for fc_exch_name_lookup()
+ * @op: The opcode to be looked up
+ */
static const char *fc_exch_rctl_name(unsigned int op)
{
return fc_exch_name_lookup(op, fc_exch_rctl_names,
FC_TABLE_SIZE(fc_exch_rctl_names));
}
-/*
- * Hold an exchange - keep it from being freed.
+/**
+ * fc_exch_hold() - Increment an exchange's reference count
+ * @ep: Echange to be held
*/
-static void fc_exch_hold(struct fc_exch *ep)
+static inline void fc_exch_hold(struct fc_exch *ep)
{
atomic_inc(&ep->ex_refcnt);
}
-/*
- * setup fc hdr by initializing few more FC header fields and sof/eof.
- * Initialized fields by this func:
- * - fh_ox_id, fh_rx_id, fh_seq_id, fh_seq_cnt
- * - sof and eof
+/**
+ * fc_exch_setup_hdr() - Initialize a FC header by initializing some fields
+ * and determine SOF and EOF.
+ * @ep: The exchange to that will use the header
+ * @fp: The frame whose header is to be modified
+ * @f_ctl: F_CTL bits that will be used for the frame header
+ *
+ * The fields initialized by this routine are: fh_ox_id, fh_rx_id,
+ * fh_seq_id, fh_seq_cnt and the SOF and EOF.
*/
static void fc_exch_setup_hdr(struct fc_exch *ep, struct fc_frame *fp,
u32 f_ctl)
@@ -243,7 +286,7 @@ static void fc_exch_setup_hdr(struct fc_exch *ep, struct fc_frame *fp,
if (fc_sof_needs_ack(ep->class))
fr_eof(fp) = FC_EOF_N;
/*
- * Form f_ctl.
+ * From F_CTL.
* The number of fill bytes to make the length a 4-byte
* multiple is the low order 2-bits of the f_ctl.
* The fill itself will have been cleared by the frame
@@ -273,10 +316,12 @@ static void fc_exch_setup_hdr(struct fc_exch *ep, struct fc_frame *fp,
fh->fh_seq_cnt = htons(ep->seq.cnt);
}
-
-/*
- * Release a reference to an exchange.
- * If the refcnt goes to zero and the exchange is complete, it is freed.
+/**
+ * fc_exch_release() - Decrement an exchange's reference count
+ * @ep: Exchange to be released
+ *
+ * If the reference count reaches zero and the exchange is complete,
+ * it is freed.
*/
static void fc_exch_release(struct fc_exch *ep)
{
@@ -291,6 +336,10 @@ static void fc_exch_release(struct fc_exch *ep)
}
}
+/**
+ * fc_exch_done_locked() - Complete an exchange with the exchange lock held
+ * @ep: The exchange that is complete
+ */
static int fc_exch_done_locked(struct fc_exch *ep)
{
int rc = 1;
@@ -315,6 +364,15 @@ static int fc_exch_done_locked(struct fc_exch *ep)
return rc;
}
+/**
+ * fc_exch_ptr_get() - Return an exchange from an exchange pool
+ * @pool: Exchange Pool to get an exchange from
+ * @index: Index of the exchange within the pool
+ *
+ * Use the index to get an exchange from within an exchange pool. exches
+ * will point to an array of exchange pointers. The index will select
+ * the exchange within the array.
+ */
static inline struct fc_exch *fc_exch_ptr_get(struct fc_exch_pool *pool,
u16 index)
{
@@ -322,12 +380,22 @@ static inline struct fc_exch *fc_exch_ptr_get(struct fc_exch_pool *pool,
return exches[index];
}
+/**
+ * fc_exch_ptr_set() - Assign an exchange to a slot in an exchange pool
+ * @pool: The pool to assign the exchange to
+ * @index: The index in the pool where the exchange will be assigned
+ * @ep: The exchange to assign to the pool
+ */
static inline void fc_exch_ptr_set(struct fc_exch_pool *pool, u16 index,
struct fc_exch *ep)
{
((struct fc_exch **)(pool + 1))[index] = ep;
}
+/**
+ * fc_exch_delete() - Delete an exchange
+ * @ep: The exchange to be deleted
+ */
static void fc_exch_delete(struct fc_exch *ep)
{
struct fc_exch_pool *pool;
@@ -343,8 +411,14 @@ static void fc_exch_delete(struct fc_exch *ep)
fc_exch_release(ep); /* drop hold for exch in mp */
}
-/*
- * Internal version of fc_exch_timer_set - used with lock held.
+/**
+ * fc_exch_timer_set_locked() - Start a timer for an exchange w/ the
+ * the exchange lock held
+ * @ep: The exchange whose timer will start
+ * @timer_msec: The timeout period
+ *
+ * Used for upper level protocols to time out the exchange.
+ * The timer is cancelled when it fires or when the exchange completes.
*/
static inline void fc_exch_timer_set_locked(struct fc_exch *ep,
unsigned int timer_msec)
@@ -354,17 +428,15 @@ static inline void fc_exch_timer_set_locked(struct fc_exch *ep,
FC_EXCH_DBG(ep, "Exchange timer armed\n");
- if (schedule_delayed_work(&ep->timeout_work,
- msecs_to_jiffies(timer_msec)))
+ if (queue_delayed_work(fc_exch_workqueue, &ep->timeout_work,
+ msecs_to_jiffies(timer_msec)))
fc_exch_hold(ep); /* hold for timer */
}
-/*
- * Set timer for an exchange.
- * The time is a minimum delay in milliseconds until the timer fires.
- * Used for upper level protocols to time out the exchange.
- * The timer is cancelled when it fires or when the exchange completes.
- * Returns non-zero if a timer couldn't be allocated.
+/**
+ * fc_exch_timer_set() - Lock the exchange and set the timer
+ * @ep: The exchange whose timer will start
+ * @timer_msec: The timeout period
*/
static void fc_exch_timer_set(struct fc_exch *ep, unsigned int timer_msec)
{
@@ -373,7 +445,115 @@ static void fc_exch_timer_set(struct fc_exch *ep, unsigned int timer_msec)
spin_unlock_bh(&ep->ex_lock);
}
-int fc_seq_exch_abort(const struct fc_seq *req_sp, unsigned int timer_msec)
+/**
+ * fc_seq_send() - Send a frame using existing sequence/exchange pair
+ * @lport: The local port that the exchange will be sent on
+ * @sp: The sequence to be sent
+ * @fp: The frame to be sent on the exchange
+ */
+static int fc_seq_send(struct fc_lport *lport, struct fc_seq *sp,
+ struct fc_frame *fp)
+{
+ struct fc_exch *ep;
+ struct fc_frame_header *fh = fc_frame_header_get(fp);
+ int error;
+ u32 f_ctl;
+
+ ep = fc_seq_exch(sp);
+ WARN_ON((ep->esb_stat & ESB_ST_SEQ_INIT) != ESB_ST_SEQ_INIT);
+
+ f_ctl = ntoh24(fh->fh_f_ctl);
+ fc_exch_setup_hdr(ep, fp, f_ctl);
+
+ /*
+ * update sequence count if this frame is carrying
+ * multiple FC frames when sequence offload is enabled
+ * by LLD.
+ */
+ if (fr_max_payload(fp))
+ sp->cnt += DIV_ROUND_UP((fr_len(fp) - sizeof(*fh)),
+ fr_max_payload(fp));
+ else
+ sp->cnt++;
+
+ /*
+ * Send the frame.
+ */
+ error = lport->tt.frame_send(lport, fp);
+
+ /*
+ * Update the exchange and sequence flags,
+ * assuming all frames for the sequence have been sent.
+ * We can only be called to send once for each sequence.
+ */
+ spin_lock_bh(&ep->ex_lock);
+ ep->f_ctl = f_ctl & ~FC_FC_FIRST_SEQ; /* not first seq */
+ if (f_ctl & (FC_FC_END_SEQ | FC_FC_SEQ_INIT))
+ ep->esb_stat &= ~ESB_ST_SEQ_INIT;
+ spin_unlock_bh(&ep->ex_lock);
+ return error;
+}
+
+/**
+ * fc_seq_alloc() - Allocate a sequence for a given exchange
+ * @ep: The exchange to allocate a new sequence for
+ * @seq_id: The sequence ID to be used
+ *
+ * We don't support multiple originated sequences on the same exchange.
+ * By implication, any previously originated sequence on this exchange
+ * is complete, and we reallocate the same sequence.
+ */
+static struct fc_seq *fc_seq_alloc(struct fc_exch *ep, u8 seq_id)
+{
+ struct fc_seq *sp;
+
+ sp = &ep->seq;
+ sp->ssb_stat = 0;
+ sp->cnt = 0;
+ sp->id = seq_id;
+ return sp;
+}
+
+/**
+ * fc_seq_start_next_locked() - Allocate a new sequence on the same
+ * exchange as the supplied sequence
+ * @sp: The sequence/exchange to get a new sequence for
+ */
+static struct fc_seq *fc_seq_start_next_locked(struct fc_seq *sp)
+{
+ struct fc_exch *ep = fc_seq_exch(sp);
+
+ sp = fc_seq_alloc(ep, ep->seq_id++);
+ FC_EXCH_DBG(ep, "f_ctl %6x seq %2x\n",
+ ep->f_ctl, sp->id);
+ return sp;
+}
+
+/**
+ * fc_seq_start_next() - Lock the exchange and get a new sequence
+ * for a given sequence/exchange pair
+ * @sp: The sequence/exchange to get a new exchange for
+ */
+static struct fc_seq *fc_seq_start_next(struct fc_seq *sp)
+{
+ struct fc_exch *ep = fc_seq_exch(sp);
+
+ spin_lock_bh(&ep->ex_lock);
+ sp = fc_seq_start_next_locked(sp);
+ spin_unlock_bh(&ep->ex_lock);
+
+ return sp;
+}
+
+/**
+ * fc_seq_exch_abort() - Abort an exchange and sequence
+ * @req_sp: The sequence to be aborted
+ * @timer_msec: The period of time to wait before aborting
+ *
+ * Generally called because of a timeout or an abort from the upper layer.
+ */
+static int fc_seq_exch_abort(const struct fc_seq *req_sp,
+ unsigned int timer_msec)
{
struct fc_seq *sp;
struct fc_exch *ep;
@@ -422,11 +602,10 @@ int fc_seq_exch_abort(const struct fc_seq *req_sp, unsigned int timer_msec)
error = -ENOBUFS;
return error;
}
-EXPORT_SYMBOL(fc_seq_exch_abort);
-/*
- * Exchange timeout - handle exchange timer expiration.
- * The timer will have been cancelled before this is called.
+/**
+ * fc_exch_timeout() - Handle exchange timer expiration
+ * @work: The work_struct identifying the exchange that timed out
*/
static void fc_exch_timeout(struct work_struct *work)
{
@@ -474,28 +653,10 @@ done:
fc_exch_release(ep);
}
-/*
- * Allocate a sequence.
- *
- * We don't support multiple originated sequences on the same exchange.
- * By implication, any previously originated sequence on this exchange
- * is complete, and we reallocate the same sequence.
- */
-static struct fc_seq *fc_seq_alloc(struct fc_exch *ep, u8 seq_id)
-{
- struct fc_seq *sp;
-
- sp = &ep->seq;
- sp->ssb_stat = 0;
- sp->cnt = 0;
- sp->id = seq_id;
- return sp;
-}
-
/**
- * fc_exch_em_alloc() - allocate an exchange from a specified EM.
- * @lport: ptr to the local port
- * @mp: ptr to the exchange manager
+ * fc_exch_em_alloc() - Allocate an exchange from a specified EM.
+ * @lport: The local port that the exchange is for
+ * @mp: The exchange manager that will allocate the exchange
*
* Returns pointer to allocated fc_exch with exch lock held.
*/
@@ -563,16 +724,18 @@ err:
}
/**
- * fc_exch_alloc() - allocate an exchange.
- * @lport: ptr to the local port
- * @fp: ptr to the FC frame
+ * fc_exch_alloc() - Allocate an exchange from an EM on a
+ * local port's list of EMs.
+ * @lport: The local port that will own the exchange
+ * @fp: The FC frame that the exchange will be for
*
- * This function walks the list of the exchange manager(EM)
- * anchors to select a EM for new exchange allocation. The
- * EM is selected having either a NULL match function pointer
- * or call to match function returning true.
+ * This function walks the list of exchange manager(EM)
+ * anchors to select an EM for a new exchange allocation. The
+ * EM is selected when a NULL match function pointer is encountered
+ * or when a call to a match function returns true.
*/
-struct fc_exch *fc_exch_alloc(struct fc_lport *lport, struct fc_frame *fp)
+static struct fc_exch *fc_exch_alloc(struct fc_lport *lport,
+ struct fc_frame *fp)
{
struct fc_exch_mgr_anchor *ema;
struct fc_exch *ep;
@@ -586,10 +749,11 @@ struct fc_exch *fc_exch_alloc(struct fc_lport *lport, struct fc_frame *fp)
}
return NULL;
}
-EXPORT_SYMBOL(fc_exch_alloc);
-/*
- * Lookup and hold an exchange.
+/**
+ * fc_exch_find() - Lookup and hold an exchange
+ * @mp: The exchange manager to lookup the exchange from
+ * @xid: The XID of the exchange to look up
*/
static struct fc_exch *fc_exch_find(struct fc_exch_mgr *mp, u16 xid)
{
@@ -609,7 +773,13 @@ static struct fc_exch *fc_exch_find(struct fc_exch_mgr *mp, u16 xid)
return ep;
}
-void fc_exch_done(struct fc_seq *sp)
+
+/**
+ * fc_exch_done() - Indicate that an exchange/sequence tuple is complete and
+ * the memory allocated for the related objects may be freed.
+ * @sp: The sequence that has completed
+ */
+static void fc_exch_done(struct fc_seq *sp)
{
struct fc_exch *ep = fc_seq_exch(sp);
int rc;
@@ -620,10 +790,13 @@ void fc_exch_done(struct fc_seq *sp)
if (!rc)
fc_exch_delete(ep);
}
-EXPORT_SYMBOL(fc_exch_done);
-/*
- * Allocate a new exchange as responder.
+/**
+ * fc_exch_resp() - Allocate a new exchange for a response frame
+ * @lport: The local port that the exchange was for
+ * @mp: The exchange manager to allocate the exchange from
+ * @fp: The response frame
+ *
* Sets the responder ID in the frame header.
*/
static struct fc_exch *fc_exch_resp(struct fc_lport *lport,
@@ -664,8 +837,13 @@ static struct fc_exch *fc_exch_resp(struct fc_lport *lport,
return ep;
}
-/*
- * Find a sequence for receive where the other end is originating the sequence.
+/**
+ * fc_seq_lookup_recip() - Find a sequence where the other end
+ * originated the sequence
+ * @lport: The local port that the frame was sent to
+ * @mp: The Exchange Manager to lookup the exchange from
+ * @fp: The frame associated with the sequence we're looking for
+ *
* If fc_pf_rjt_reason is FC_RJT_NONE then this function will have a hold
* on the ep that should be released by the caller.
*/
@@ -771,10 +949,12 @@ rel:
return reject;
}
-/*
- * Find the sequence for a frame being received.
- * We originated the sequence, so it should be found.
- * We may or may not have originated the exchange.
+/**
+ * fc_seq_lookup_orig() - Find a sequence where this end
+ * originated the sequence
+ * @mp: The Exchange Manager to lookup the exchange from
+ * @fp: The frame associated with the sequence we're looking for
+ *
* Does not hold the sequence for the caller.
*/
static struct fc_seq *fc_seq_lookup_orig(struct fc_exch_mgr *mp,
@@ -806,8 +986,12 @@ static struct fc_seq *fc_seq_lookup_orig(struct fc_exch_mgr *mp,
return sp;
}
-/*
- * Set addresses for an exchange.
+/**
+ * fc_exch_set_addr() - Set the source and destination IDs for an exchange
+ * @ep: The exchange to set the addresses for
+ * @orig_id: The originator's ID
+ * @resp_id: The responder's ID
+ *
* Note this must be done before the first sequence of the exchange is sent.
*/
static void fc_exch_set_addr(struct fc_exch *ep,
@@ -823,76 +1007,15 @@ static void fc_exch_set_addr(struct fc_exch *ep,
}
}
-static struct fc_seq *fc_seq_start_next_locked(struct fc_seq *sp)
-{
- struct fc_exch *ep = fc_seq_exch(sp);
-
- sp = fc_seq_alloc(ep, ep->seq_id++);
- FC_EXCH_DBG(ep, "f_ctl %6x seq %2x\n",
- ep->f_ctl, sp->id);
- return sp;
-}
-/*
- * Allocate a new sequence on the same exchange as the supplied sequence.
- * This will never return NULL.
+/**
+ * fc_seq_els_rsp_send() - Send an ELS response using infomation from
+ * the existing sequence/exchange.
+ * @sp: The sequence/exchange to get information from
+ * @els_cmd: The ELS command to be sent
+ * @els_data: The ELS data to be sent
*/
-struct fc_seq *fc_seq_start_next(struct fc_seq *sp)
-{
- struct fc_exch *ep = fc_seq_exch(sp);
-
- spin_lock_bh(&ep->ex_lock);
- sp = fc_seq_start_next_locked(sp);
- spin_unlock_bh(&ep->ex_lock);
-
- return sp;
-}
-EXPORT_SYMBOL(fc_seq_start_next);
-
-int fc_seq_send(struct fc_lport *lp, struct fc_seq *sp, struct fc_frame *fp)
-{
- struct fc_exch *ep;
- struct fc_frame_header *fh = fc_frame_header_get(fp);
- int error;
- u32 f_ctl;
-
- ep = fc_seq_exch(sp);
- WARN_ON((ep->esb_stat & ESB_ST_SEQ_INIT) != ESB_ST_SEQ_INIT);
-
- f_ctl = ntoh24(fh->fh_f_ctl);
- fc_exch_setup_hdr(ep, fp, f_ctl);
-
- /*
- * update sequence count if this frame is carrying
- * multiple FC frames when sequence offload is enabled
- * by LLD.
- */
- if (fr_max_payload(fp))
- sp->cnt += DIV_ROUND_UP((fr_len(fp) - sizeof(*fh)),
- fr_max_payload(fp));
- else
- sp->cnt++;
-
- /*
- * Send the frame.
- */
- error = lp->tt.frame_send(lp, fp);
-
- /*
- * Update the exchange and sequence flags,
- * assuming all frames for the sequence have been sent.
- * We can only be called to send once for each sequence.
- */
- spin_lock_bh(&ep->ex_lock);
- ep->f_ctl = f_ctl & ~FC_FC_FIRST_SEQ; /* not first seq */
- if (f_ctl & (FC_FC_END_SEQ | FC_FC_SEQ_INIT))
- ep->esb_stat &= ~ESB_ST_SEQ_INIT;
- spin_unlock_bh(&ep->ex_lock);
- return error;
-}
-EXPORT_SYMBOL(fc_seq_send);
-
-void fc_seq_els_rsp_send(struct fc_seq *sp, enum fc_els_cmd els_cmd,
- struct fc_seq_els_data *els_data)
+static void fc_seq_els_rsp_send(struct fc_seq *sp, enum fc_els_cmd els_cmd,
+ struct fc_seq_els_data *els_data)
{
switch (els_cmd) {
case ELS_LS_RJT:
@@ -911,10 +1034,13 @@ void fc_seq_els_rsp_send(struct fc_seq *sp, enum fc_els_cmd els_cmd,
FC_EXCH_DBG(fc_seq_exch(sp), "Invalid ELS CMD:%x\n", els_cmd);
}
}
-EXPORT_SYMBOL(fc_seq_els_rsp_send);
-/*
- * Send a sequence, which is also the last sequence in the exchange.
+/**
+ * fc_seq_send_last() - Send a sequence that is the last in the exchange
+ * @sp: The sequence that is to be sent
+ * @fp: The frame that will be sent on the sequence
+ * @rctl: The R_CTL information to be sent
+ * @fh_type: The frame header type
*/
static void fc_seq_send_last(struct fc_seq *sp, struct fc_frame *fp,
enum fc_rctl rctl, enum fc_fh_type fh_type)
@@ -928,9 +1054,12 @@ static void fc_seq_send_last(struct fc_seq *sp, struct fc_frame *fp,
fc_seq_send(ep->lp, sp, fp);
}
-/*
+/**
+ * fc_seq_send_ack() - Send an acknowledgement that we've received a frame
+ * @sp: The sequence to send the ACK on
+ * @rx_fp: The received frame that is being acknoledged
+ *
* Send ACK_1 (or equiv.) indicating we received something.
- * The frame we're acking is supplied.
*/
static void fc_seq_send_ack(struct fc_seq *sp, const struct fc_frame *rx_fp)
{
@@ -938,14 +1067,14 @@ static void fc_seq_send_ack(struct fc_seq *sp, const struct fc_frame *rx_fp)
struct fc_frame_header *rx_fh;
struct fc_frame_header *fh;
struct fc_exch *ep = fc_seq_exch(sp);
- struct fc_lport *lp = ep->lp;
+ struct fc_lport *lport = ep->lp;
unsigned int f_ctl;
/*
* Don't send ACKs for class 3.
*/
if (fc_sof_needs_ack(fr_sof(rx_fp))) {
- fp = fc_frame_alloc(lp, 0);
+ fp = fc_frame_alloc(lport, 0);
if (!fp)
return;
@@ -980,12 +1109,16 @@ static void fc_seq_send_ack(struct fc_seq *sp, const struct fc_frame *rx_fp)
else
fr_eof(fp) = FC_EOF_N;
- (void) lp->tt.frame_send(lp, fp);
+ lport->tt.frame_send(lport, fp);
}
}
-/*
- * Send BLS Reject.
+/**
+ * fc_exch_send_ba_rjt() - Send BLS Reject
+ * @rx_fp: The frame being rejected
+ * @reason: The reason the frame is being rejected
+ * @explan: The explaination for the rejection
+ *
* This is for rejecting BA_ABTS only.
*/
static void fc_exch_send_ba_rjt(struct fc_frame *rx_fp,
@@ -996,11 +1129,11 @@ static void fc_exch_send_ba_rjt(struct fc_frame *rx_fp,
struct fc_frame_header *rx_fh;
struct fc_frame_header *fh;
struct fc_ba_rjt *rp;
- struct fc_lport *lp;
+ struct fc_lport *lport;
unsigned int f_ctl;
- lp = fr_dev(rx_fp);
- fp = fc_frame_alloc(lp, sizeof(*rp));
+ lport = fr_dev(rx_fp);
+ fp = fc_frame_alloc(lport, sizeof(*rp));
if (!fp)
return;
fh = fc_frame_header_get(fp);
@@ -1045,13 +1178,17 @@ static void fc_exch_send_ba_rjt(struct fc_frame *rx_fp,
if (fc_sof_needs_ack(fr_sof(fp)))
fr_eof(fp) = FC_EOF_N;
- (void) lp->tt.frame_send(lp, fp);
+ lport->tt.frame_send(lport, fp);
}
-/*
- * Handle an incoming ABTS. This would be for target mode usually,
- * but could be due to lost FCP transfer ready, confirm or RRQ.
- * We always handle this as an exchange abort, ignoring the parameter.
+/**
+ * fc_exch_recv_abts() - Handle an incoming ABTS
+ * @ep: The exchange the abort was on
+ * @rx_fp: The ABTS frame
+ *
+ * This would be for target mode usually, but could be due to lost
+ * FCP transfer ready, confirm or RRQ. We always handle this as an
+ * exchange abort, ignoring the parameter.
*/
static void fc_exch_recv_abts(struct fc_exch *ep, struct fc_frame *rx_fp)
{
@@ -1100,10 +1237,14 @@ free:
fc_frame_free(rx_fp);
}
-/*
- * Handle receive where the other end is originating the sequence.
+/**
+ * fc_exch_recv_req() - Handler for an incoming request where is other
+ * end is originating the sequence
+ * @lport: The local port that received the request
+ * @mp: The EM that the exchange is on
+ * @fp: The request frame
*/
-static void fc_exch_recv_req(struct fc_lport *lp, struct fc_exch_mgr *mp,
+static void fc_exch_recv_req(struct fc_lport *lport, struct fc_exch_mgr *mp,
struct fc_frame *fp)
{
struct fc_frame_header *fh = fc_frame_header_get(fp);
@@ -1114,8 +1255,17 @@ static void fc_exch_recv_req(struct fc_lport *lp, struct fc_exch_mgr *mp,
u32 f_ctl;
enum fc_pf_rjt_reason reject;
+ /* We can have the wrong fc_lport at this point with NPIV, which is a
+ * problem now that we know a new exchange needs to be allocated
+ */
+ lport = fc_vport_id_lookup(lport, ntoh24(fh->fh_d_id));
+ if (!lport) {
+ fc_frame_free(fp);
+ return;
+ }
+
fr_seq(fp) = NULL;
- reject = fc_seq_lookup_recip(lp, mp, fp);
+ reject = fc_seq_lookup_recip(lport, mp, fp);
if (reject == FC_RJT_NONE) {
sp = fr_seq(fp); /* sequence will be held */
ep = fc_seq_exch(sp);
@@ -1138,17 +1288,21 @@ static void fc_exch_recv_req(struct fc_lport *lp, struct fc_exch_mgr *mp,
if (ep->resp)
ep->resp(sp, fp, ep->arg);
else
- lp->tt.lport_recv(lp, sp, fp);
+ lport->tt.lport_recv(lport, sp, fp);
fc_exch_release(ep); /* release from lookup */
} else {
- FC_LPORT_DBG(lp, "exch/seq lookup failed: reject %x\n", reject);
+ FC_LPORT_DBG(lport, "exch/seq lookup failed: reject %x\n",
+ reject);
fc_frame_free(fp);
}
}
-/*
- * Handle receive where the other end is originating the sequence in
- * response to our exchange.
+/**
+ * fc_exch_recv_seq_resp() - Handler for an incoming response where the other
+ * end is the originator of the sequence that is a
+ * response to our initial exchange
+ * @mp: The EM that the exchange is on
+ * @fp: The response frame
*/
static void fc_exch_recv_seq_resp(struct fc_exch_mgr *mp, struct fc_frame *fp)
{
@@ -1239,8 +1393,11 @@ out:
fc_frame_free(fp);
}
-/*
- * Handle receive for a sequence where other end is responding to our sequence.
+/**
+ * fc_exch_recv_resp() - Handler for a sequence where other end is
+ * responding to our sequence
+ * @mp: The EM that the exchange is on
+ * @fp: The response frame
*/
static void fc_exch_recv_resp(struct fc_exch_mgr *mp, struct fc_frame *fp)
{
@@ -1256,9 +1413,13 @@ static void fc_exch_recv_resp(struct fc_exch_mgr *mp, struct fc_frame *fp)
fc_frame_free(fp);
}
-/*
- * Handle the response to an ABTS for exchange or sequence.
- * This can be BA_ACC or BA_RJT.
+/**
+ * fc_exch_abts_resp() - Handler for a response to an ABT
+ * @ep: The exchange that the frame is on
+ * @fp: The response frame
+ *
+ * This response would be to an ABTS cancelling an exchange or sequence.
+ * The response can be either BA_ACC or BA_RJT
*/
static void fc_exch_abts_resp(struct fc_exch *ep, struct fc_frame *fp)
{
@@ -1333,9 +1494,12 @@ static void fc_exch_abts_resp(struct fc_exch *ep, struct fc_frame *fp)
}
-/*
- * Receive BLS sequence.
- * This is always a sequence initiated by the remote side.
+/**
+ * fc_exch_recv_bls() - Handler for a BLS sequence
+ * @mp: The EM that the exchange is on
+ * @fp: The request frame
+ *
+ * The BLS frame is always a sequence initiated by the remote side.
* We may be either the originator or recipient of the exchange.
*/
static void fc_exch_recv_bls(struct fc_exch_mgr *mp, struct fc_frame *fp)
@@ -1392,8 +1556,10 @@ static void fc_exch_recv_bls(struct fc_exch_mgr *mp, struct fc_frame *fp)
fc_exch_release(ep); /* release hold taken by fc_exch_find */
}
-/*
- * Accept sequence with LS_ACC.
+/**
+ * fc_seq_ls_acc() - Accept sequence with LS_ACC
+ * @req_sp: The request sequence
+ *
* If this fails due to allocation or transmit congestion, assume the
* originator will repeat the sequence.
*/
@@ -1413,8 +1579,12 @@ static void fc_seq_ls_acc(struct fc_seq *req_sp)
}
}
-/*
- * Reject sequence with ELS LS_RJT.
+/**
+ * fc_seq_ls_rjt() - Reject a sequence with ELS LS_RJT
+ * @req_sp: The request sequence
+ * @reason: The reason the sequence is being rejected
+ * @explan: The explaination for the rejection
+ *
* If this fails due to allocation or transmit congestion, assume the
* originator will repeat the sequence.
*/
@@ -1437,6 +1607,10 @@ static void fc_seq_ls_rjt(struct fc_seq *req_sp, enum fc_els_rjt_reason reason,
}
}
+/**
+ * fc_exch_reset() - Reset an exchange
+ * @ep: The exchange to be reset
+ */
static void fc_exch_reset(struct fc_exch *ep)
{
struct fc_seq *sp;
@@ -1446,12 +1620,6 @@ static void fc_exch_reset(struct fc_exch *ep)
spin_lock_bh(&ep->ex_lock);
ep->state |= FC_EX_RST_CLEANUP;
- /*
- * we really want to call del_timer_sync, but cannot due
- * to the lport calling with the lport lock held (some resp
- * functions can also grab the lport lock which could cause
- * a deadlock).
- */
if (cancel_delayed_work(&ep->timeout_work))
atomic_dec(&ep->ex_refcnt); /* drop hold for timer */
resp = ep->resp;
@@ -1471,16 +1639,16 @@ static void fc_exch_reset(struct fc_exch *ep)
}
/**
- * fc_exch_pool_reset() - Resets an per cpu exches pool.
- * @lport: ptr to the local port
- * @pool: ptr to the per cpu exches pool
- * @sid: source FC ID
- * @did: destination FC ID
+ * fc_exch_pool_reset() - Reset a per cpu exchange pool
+ * @lport: The local port that the exchange pool is on
+ * @pool: The exchange pool to be reset
+ * @sid: The source ID
+ * @did: The destination ID
*
- * Resets an per cpu exches pool, releasing its all sequences
- * and exchanges. If sid is non-zero, then reset only exchanges
- * we sourced from that FID. If did is non-zero, reset only
- * exchanges destined to that FID.
+ * Resets a per cpu exches pool, releasing all of its sequences
+ * and exchanges. If sid is non-zero then reset only exchanges
+ * we sourced from the local port's FID. If did is non-zero then
+ * only reset exchanges destined for the local port's FID.
*/
static void fc_exch_pool_reset(struct fc_lport *lport,
struct fc_exch_pool *pool,
@@ -1514,15 +1682,15 @@ restart:
}
/**
- * fc_exch_mgr_reset() - Resets all EMs of a lport
- * @lport: ptr to the local port
- * @sid: source FC ID
- * @did: destination FC ID
+ * fc_exch_mgr_reset() - Reset all EMs of a local port
+ * @lport: The local port whose EMs are to be reset
+ * @sid: The source ID
+ * @did: The destination ID
*
- * Reset all EMs of a lport, releasing its all sequences and
- * exchanges. If sid is non-zero, then reset only exchanges
- * we sourced from that FID. If did is non-zero, reset only
- * exchanges destined to that FID.
+ * Reset all EMs associated with a given local port. Release all
+ * sequences and exchanges. If sid is non-zero then reset only the
+ * exchanges sent from the local port's FID. If did is non-zero then
+ * reset only exchanges destined for the local port's FID.
*/
void fc_exch_mgr_reset(struct fc_lport *lport, u32 sid, u32 did)
{
@@ -1538,8 +1706,11 @@ void fc_exch_mgr_reset(struct fc_lport *lport, u32 sid, u32 did)
}
EXPORT_SYMBOL(fc_exch_mgr_reset);
-/*
- * Handle incoming ELS REC - Read Exchange Concise.
+/**
+ * fc_exch_els_rec() - Handler for ELS REC (Read Exchange Concise) requests
+ * @sp: The sequence the REC is on
+ * @rfp: The REC frame
+ *
* Note that the requesting port may be different than the S_ID in the request.
*/
static void fc_exch_els_rec(struct fc_seq *sp, struct fc_frame *rfp)
@@ -1621,10 +1792,11 @@ reject:
fc_frame_free(rfp);
}
-/*
- * Handle response from RRQ.
- * Not much to do here, really.
- * Should report errors.
+/**
+ * fc_exch_rrq_resp() - Handler for RRQ responses
+ * @sp: The sequence that the RRQ is on
+ * @fp: The RRQ frame
+ * @arg: The exchange that the RRQ is on
*
* TODO: fix error handler.
*/
@@ -1664,21 +1836,99 @@ cleanup:
fc_exch_release(aborted_ep);
}
-/*
- * Send ELS RRQ - Reinstate Recovery Qualifier.
+
+/**
+ * fc_exch_seq_send() - Send a frame using a new exchange and sequence
+ * @lport: The local port to send the frame on
+ * @fp: The frame to be sent
+ * @resp: The response handler for this request
+ * @destructor: The destructor for the exchange
+ * @arg: The argument to be passed to the response handler
+ * @timer_msec: The timeout period for the exchange
+ *
+ * The frame pointer with some of the header's fields must be
+ * filled before calling this routine, those fields are:
+ *
+ * - routing control
+ * - FC port did
+ * - FC port sid
+ * - FC header type
+ * - frame control
+ * - parameter or relative offset
+ */
+static struct fc_seq *fc_exch_seq_send(struct fc_lport *lport,
+ struct fc_frame *fp,
+ void (*resp)(struct fc_seq *,
+ struct fc_frame *fp,
+ void *arg),
+ void (*destructor)(struct fc_seq *,
+ void *),
+ void *arg, u32 timer_msec)
+{
+ struct fc_exch *ep;
+ struct fc_seq *sp = NULL;
+ struct fc_frame_header *fh;
+ int rc = 1;
+
+ ep = fc_exch_alloc(lport, fp);
+ if (!ep) {
+ fc_frame_free(fp);
+ return NULL;
+ }
+ ep->esb_stat |= ESB_ST_SEQ_INIT;
+ fh = fc_frame_header_get(fp);
+ fc_exch_set_addr(ep, ntoh24(fh->fh_s_id), ntoh24(fh->fh_d_id));
+ ep->resp = resp;
+ ep->destructor = destructor;
+ ep->arg = arg;
+ ep->r_a_tov = FC_DEF_R_A_TOV;
+ ep->lp = lport;
+ sp = &ep->seq;
+
+ ep->fh_type = fh->fh_type; /* save for possbile timeout handling */
+ ep->f_ctl = ntoh24(fh->fh_f_ctl);
+ fc_exch_setup_hdr(ep, fp, ep->f_ctl);
+ sp->cnt++;
+
+ if (ep->xid <= lport->lro_xid)
+ fc_fcp_ddp_setup(fr_fsp(fp), ep->xid);
+
+ if (unlikely(lport->tt.frame_send(lport, fp)))
+ goto err;
+
+ if (timer_msec)
+ fc_exch_timer_set_locked(ep, timer_msec);
+ ep->f_ctl &= ~FC_FC_FIRST_SEQ; /* not first seq */
+
+ if (ep->f_ctl & FC_FC_SEQ_INIT)
+ ep->esb_stat &= ~ESB_ST_SEQ_INIT;
+ spin_unlock_bh(&ep->ex_lock);
+ return sp;
+err:
+ rc = fc_exch_done_locked(ep);
+ spin_unlock_bh(&ep->ex_lock);
+ if (!rc)
+ fc_exch_delete(ep);
+ return NULL;
+}
+
+/**
+ * fc_exch_rrq() - Send an ELS RRQ (Reinstate Recovery Qualifier) command
+ * @ep: The exchange to send the RRQ on
+ *
* This tells the remote port to stop blocking the use of
* the exchange and the seq_cnt range.
*/
static void fc_exch_rrq(struct fc_exch *ep)
{
- struct fc_lport *lp;
+ struct fc_lport *lport;
struct fc_els_rrq *rrq;
struct fc_frame *fp;
u32 did;
- lp = ep->lp;
+ lport = ep->lp;
- fp = fc_frame_alloc(lp, sizeof(*rrq));
+ fp = fc_frame_alloc(lport, sizeof(*rrq));
if (!fp)
goto retry;
@@ -1694,10 +1944,11 @@ static void fc_exch_rrq(struct fc_exch *ep)
did = ep->sid;
fc_fill_fc_hdr(fp, FC_RCTL_ELS_REQ, did,
- fc_host_port_id(lp->host), FC_TYPE_ELS,
+ fc_host_port_id(lport->host), FC_TYPE_ELS,
FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
- if (fc_exch_seq_send(lp, fp, fc_exch_rrq_resp, NULL, ep, lp->e_d_tov))
+ if (fc_exch_seq_send(lport, fp, fc_exch_rrq_resp, NULL, ep,
+ lport->e_d_tov))
return;
retry:
@@ -1714,12 +1965,14 @@ retry:
}
-/*
- * Handle incoming ELS RRQ - Reset Recovery Qualifier.
+/**
+ * fc_exch_els_rrq() - Handler for ELS RRQ (Reset Recovery Qualifier) requests
+ * @sp: The sequence that the RRQ is on
+ * @fp: The RRQ frame
*/
static void fc_exch_els_rrq(struct fc_seq *sp, struct fc_frame *fp)
{
- struct fc_exch *ep; /* request or subject exchange */
+ struct fc_exch *ep = NULL; /* request or subject exchange */
struct fc_els_rrq *rp;
u32 sid;
u16 xid;
@@ -1769,17 +2022,24 @@ static void fc_exch_els_rrq(struct fc_seq *sp, struct fc_frame *fp)
* Send LS_ACC.
*/
fc_seq_ls_acc(sp);
- fc_frame_free(fp);
- return;
+ goto out;
unlock_reject:
spin_unlock_bh(&ep->ex_lock);
- fc_exch_release(ep); /* drop hold from fc_exch_find */
reject:
fc_seq_ls_rjt(sp, ELS_RJT_LOGIC, explan);
+out:
fc_frame_free(fp);
+ if (ep)
+ fc_exch_release(ep); /* drop hold from fc_exch_find */
}
+/**
+ * fc_exch_mgr_add() - Add an exchange manager to a local port's list of EMs
+ * @lport: The local port to add the exchange manager to
+ * @mp: The exchange manager to be added to the local port
+ * @match: The match routine that indicates when this EM should be used
+ */
struct fc_exch_mgr_anchor *fc_exch_mgr_add(struct fc_lport *lport,
struct fc_exch_mgr *mp,
bool (*match)(struct fc_frame *))
@@ -1799,6 +2059,10 @@ struct fc_exch_mgr_anchor *fc_exch_mgr_add(struct fc_lport *lport,
}
EXPORT_SYMBOL(fc_exch_mgr_add);
+/**
+ * fc_exch_mgr_destroy() - Destroy an exchange manager
+ * @kref: The reference to the EM to be destroyed
+ */
static void fc_exch_mgr_destroy(struct kref *kref)
{
struct fc_exch_mgr *mp = container_of(kref, struct fc_exch_mgr, kref);
@@ -1808,6 +2072,10 @@ static void fc_exch_mgr_destroy(struct kref *kref)
kfree(mp);
}
+/**
+ * fc_exch_mgr_del() - Delete an EM from a local port's list
+ * @ema: The exchange manager anchor identifying the EM to be deleted
+ */
void fc_exch_mgr_del(struct fc_exch_mgr_anchor *ema)
{
/* remove EM anchor from EM anchors list */
@@ -1817,7 +2085,35 @@ void fc_exch_mgr_del(struct fc_exch_mgr_anchor *ema)
}
EXPORT_SYMBOL(fc_exch_mgr_del);
-struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp,
+/**
+ * fc_exch_mgr_list_clone() - Share all exchange manager objects
+ * @src: Source lport to clone exchange managers from
+ * @dst: New lport that takes references to all the exchange managers
+ */
+int fc_exch_mgr_list_clone(struct fc_lport *src, struct fc_lport *dst)
+{
+ struct fc_exch_mgr_anchor *ema, *tmp;
+
+ list_for_each_entry(ema, &src->ema_list, ema_list) {
+ if (!fc_exch_mgr_add(dst, ema->mp, ema->match))
+ goto err;
+ }
+ return 0;
+err:
+ list_for_each_entry_safe(ema, tmp, &dst->ema_list, ema_list)
+ fc_exch_mgr_del(ema);
+ return -ENOMEM;
+}
+
+/**
+ * fc_exch_mgr_alloc() - Allocate an exchange manager
+ * @lport: The local port that the new EM will be associated with
+ * @class: The default FC class for new exchanges
+ * @min_xid: The minimum XID for exchanges from the new EM
+ * @max_xid: The maximum XID for exchanges from the new EM
+ * @match: The match routine for the new EM
+ */
+struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lport,
enum fc_class class,
u16 min_xid, u16 max_xid,
bool (*match)(struct fc_frame *))
@@ -1830,7 +2126,7 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp,
if (max_xid <= min_xid || max_xid == FC_XID_UNKNOWN ||
(min_xid & fc_cpu_mask) != 0) {
- FC_LPORT_DBG(lp, "Invalid min_xid 0x:%x and max_xid 0x:%x\n",
+ FC_LPORT_DBG(lport, "Invalid min_xid 0x:%x and max_xid 0x:%x\n",
min_xid, max_xid);
return NULL;
}
@@ -1873,7 +2169,7 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp,
}
kref_init(&mp->kref);
- if (!fc_exch_mgr_add(lp, mp, match)) {
+ if (!fc_exch_mgr_add(lport, mp, match)) {
free_percpu(mp->pool);
goto free_mempool;
}
@@ -1894,76 +2190,26 @@ free_mp:
}
EXPORT_SYMBOL(fc_exch_mgr_alloc);
+/**
+ * fc_exch_mgr_free() - Free all exchange managers on a local port
+ * @lport: The local port whose EMs are to be freed
+ */
void fc_exch_mgr_free(struct fc_lport *lport)
{
struct fc_exch_mgr_anchor *ema, *next;
+ flush_workqueue(fc_exch_workqueue);
list_for_each_entry_safe(ema, next, &lport->ema_list, ema_list)
fc_exch_mgr_del(ema);
}
EXPORT_SYMBOL(fc_exch_mgr_free);
-
-struct fc_seq *fc_exch_seq_send(struct fc_lport *lp,
- struct fc_frame *fp,
- void (*resp)(struct fc_seq *,
- struct fc_frame *fp,
- void *arg),
- void (*destructor)(struct fc_seq *, void *),
- void *arg, u32 timer_msec)
-{
- struct fc_exch *ep;
- struct fc_seq *sp = NULL;
- struct fc_frame_header *fh;
- int rc = 1;
-
- ep = fc_exch_alloc(lp, fp);
- if (!ep) {
- fc_frame_free(fp);
- return NULL;
- }
- ep->esb_stat |= ESB_ST_SEQ_INIT;
- fh = fc_frame_header_get(fp);
- fc_exch_set_addr(ep, ntoh24(fh->fh_s_id), ntoh24(fh->fh_d_id));
- ep->resp = resp;
- ep->destructor = destructor;
- ep->arg = arg;
- ep->r_a_tov = FC_DEF_R_A_TOV;
- ep->lp = lp;
- sp = &ep->seq;
-
- ep->fh_type = fh->fh_type; /* save for possbile timeout handling */
- ep->f_ctl = ntoh24(fh->fh_f_ctl);
- fc_exch_setup_hdr(ep, fp, ep->f_ctl);
- sp->cnt++;
-
- if (ep->xid <= lp->lro_xid)
- fc_fcp_ddp_setup(fr_fsp(fp), ep->xid);
-
- if (unlikely(lp->tt.frame_send(lp, fp)))
- goto err;
-
- if (timer_msec)
- fc_exch_timer_set_locked(ep, timer_msec);
- ep->f_ctl &= ~FC_FC_FIRST_SEQ; /* not first seq */
-
- if (ep->f_ctl & FC_FC_SEQ_INIT)
- ep->esb_stat &= ~ESB_ST_SEQ_INIT;
- spin_unlock_bh(&ep->ex_lock);
- return sp;
-err:
- rc = fc_exch_done_locked(ep);
- spin_unlock_bh(&ep->ex_lock);
- if (!rc)
- fc_exch_delete(ep);
- return NULL;
-}
-EXPORT_SYMBOL(fc_exch_seq_send);
-
-/*
- * Receive a frame
+/**
+ * fc_exch_recv() - Handler for received frames
+ * @lport: The local port the frame was received on
+ * @fp: The received frame
*/
-void fc_exch_recv(struct fc_lport *lp, struct fc_frame *fp)
+void fc_exch_recv(struct fc_lport *lport, struct fc_frame *fp)
{
struct fc_frame_header *fh = fc_frame_header_get(fp);
struct fc_exch_mgr_anchor *ema;
@@ -1971,8 +2217,8 @@ void fc_exch_recv(struct fc_lport *lp, struct fc_frame *fp)
u16 oxid;
/* lport lock ? */
- if (!lp || lp->state == LPORT_ST_DISABLED) {
- FC_LPORT_DBG(lp, "Receiving frames for an lport that "
+ if (!lport || lport->state == LPORT_ST_DISABLED) {
+ FC_LPORT_DBG(lport, "Receiving frames for an lport that "
"has not been initialized correctly\n");
fc_frame_free(fp);
return;
@@ -1981,7 +2227,7 @@ void fc_exch_recv(struct fc_lport *lp, struct fc_frame *fp)
f_ctl = ntoh24(fh->fh_f_ctl);
oxid = ntohs(fh->fh_ox_id);
if (f_ctl & FC_FC_EX_CTX) {
- list_for_each_entry(ema, &lp->ema_list, ema_list) {
+ list_for_each_entry(ema, &lport->ema_list, ema_list) {
if ((oxid >= ema->mp->min_xid) &&
(oxid <= ema->mp->max_xid)) {
found = 1;
@@ -1990,13 +2236,13 @@ void fc_exch_recv(struct fc_lport *lp, struct fc_frame *fp)
}
if (!found) {
- FC_LPORT_DBG(lp, "Received response for out "
+ FC_LPORT_DBG(lport, "Received response for out "
"of range oxid:%hx\n", oxid);
fc_frame_free(fp);
return;
}
} else
- ema = list_entry(lp->ema_list.prev, typeof(*ema), ema_list);
+ ema = list_entry(lport->ema_list.prev, typeof(*ema), ema_list);
/*
* If frame is marked invalid, just drop it.
@@ -2015,37 +2261,56 @@ void fc_exch_recv(struct fc_lport *lp, struct fc_frame *fp)
else if (f_ctl & FC_FC_SEQ_CTX)
fc_exch_recv_resp(ema->mp, fp);
else
- fc_exch_recv_req(lp, ema->mp, fp);
+ fc_exch_recv_req(lport, ema->mp, fp);
break;
default:
- FC_LPORT_DBG(lp, "dropping invalid frame (eof %x)", fr_eof(fp));
+ FC_LPORT_DBG(lport, "dropping invalid frame (eof %x)",
+ fr_eof(fp));
fc_frame_free(fp);
}
}
EXPORT_SYMBOL(fc_exch_recv);
-int fc_exch_init(struct fc_lport *lp)
+/**
+ * fc_exch_init() - Initialize the exchange layer for a local port
+ * @lport: The local port to initialize the exchange layer for
+ */
+int fc_exch_init(struct fc_lport *lport)
{
- if (!lp->tt.seq_start_next)
- lp->tt.seq_start_next = fc_seq_start_next;
+ if (!lport->tt.seq_start_next)
+ lport->tt.seq_start_next = fc_seq_start_next;
- if (!lp->tt.exch_seq_send)
- lp->tt.exch_seq_send = fc_exch_seq_send;
+ if (!lport->tt.exch_seq_send)
+ lport->tt.exch_seq_send = fc_exch_seq_send;
- if (!lp->tt.seq_send)
- lp->tt.seq_send = fc_seq_send;
+ if (!lport->tt.seq_send)
+ lport->tt.seq_send = fc_seq_send;
- if (!lp->tt.seq_els_rsp_send)
- lp->tt.seq_els_rsp_send = fc_seq_els_rsp_send;
+ if (!lport->tt.seq_els_rsp_send)
+ lport->tt.seq_els_rsp_send = fc_seq_els_rsp_send;
- if (!lp->tt.exch_done)
- lp->tt.exch_done = fc_exch_done;
+ if (!lport->tt.exch_done)
+ lport->tt.exch_done = fc_exch_done;
- if (!lp->tt.exch_mgr_reset)
- lp->tt.exch_mgr_reset = fc_exch_mgr_reset;
+ if (!lport->tt.exch_mgr_reset)
+ lport->tt.exch_mgr_reset = fc_exch_mgr_reset;
- if (!lp->tt.seq_exch_abort)
- lp->tt.seq_exch_abort = fc_seq_exch_abort;
+ if (!lport->tt.seq_exch_abort)
+ lport->tt.seq_exch_abort = fc_seq_exch_abort;
+
+ return 0;
+}
+EXPORT_SYMBOL(fc_exch_init);
+
+/**
+ * fc_setup_exch_mgr() - Setup an exchange manager
+ */
+int fc_setup_exch_mgr()
+{
+ fc_em_cachep = kmem_cache_create("libfc_em", sizeof(struct fc_exch),
+ 0, SLAB_HWCACHE_ALIGN, NULL);
+ if (!fc_em_cachep)
+ return -ENOMEM;
/*
* Initialize fc_cpu_mask and fc_cpu_order. The
@@ -2069,20 +2334,17 @@ int fc_exch_init(struct fc_lport *lp)
}
fc_cpu_mask--;
- return 0;
-}
-EXPORT_SYMBOL(fc_exch_init);
-
-int fc_setup_exch_mgr(void)
-{
- fc_em_cachep = kmem_cache_create("libfc_em", sizeof(struct fc_exch),
- 0, SLAB_HWCACHE_ALIGN, NULL);
- if (!fc_em_cachep)
+ fc_exch_workqueue = create_singlethread_workqueue("fc_exch_workqueue");
+ if (!fc_exch_workqueue)
return -ENOMEM;
return 0;
}
-void fc_destroy_exch_mgr(void)
+/**
+ * fc_destroy_exch_mgr() - Destroy an exchange manager
+ */
+void fc_destroy_exch_mgr()
{
+ destroy_workqueue(fc_exch_workqueue);
kmem_cache_destroy(fc_em_cachep);
}
diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c
index 59a4408..c4b58d0 100644
--- a/drivers/scsi/libfc/fc_fcp.c
+++ b/drivers/scsi/libfc/fc_fcp.c
@@ -39,15 +39,9 @@
#include <scsi/libfc.h>
#include <scsi/fc_encode.h>
-MODULE_AUTHOR("Open-FCoE.org");
-MODULE_DESCRIPTION("libfc");
-MODULE_LICENSE("GPL v2");
+#include "fc_libfc.h"
-unsigned int fc_debug_logging;
-module_param_named(debug_logging, fc_debug_logging, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels");
-
-static struct kmem_cache *scsi_pkt_cachep;
+struct kmem_cache *scsi_pkt_cachep;
/* SRB state definitions */
#define FC_SRB_FREE 0 /* cmd is free */
@@ -58,7 +52,6 @@ static struct kmem_cache *scsi_pkt_cachep;
#define FC_SRB_DISCONTIG (1 << 4) /* non-sequential data recvd */
#define FC_SRB_COMPL (1 << 5) /* fc_io_compl has been run */
#define FC_SRB_FCP_PROCESSING_TMO (1 << 6) /* timer function processing */
-#define FC_SRB_NOMEM (1 << 7) /* dropped to out of mem */
#define FC_SRB_READ (1 << 1)
#define FC_SRB_WRITE (1 << 0)
@@ -73,10 +66,20 @@ static struct kmem_cache *scsi_pkt_cachep;
#define CMD_SCSI_STATUS(Cmnd) ((Cmnd)->SCp.Status)
#define CMD_RESID_LEN(Cmnd) ((Cmnd)->SCp.buffers_residual)
+/**
+ * struct fc_fcp_internal - FCP layer internal data
+ * @scsi_pkt_pool: Memory pool to draw FCP packets from
+ * @scsi_pkt_queue: Current FCP packets
+ * @last_can_queue_ramp_down_time: ramp down time
+ * @last_can_queue_ramp_up_time: ramp up time
+ * @max_can_queue: max can_queue size
+ */
struct fc_fcp_internal {
- mempool_t *scsi_pkt_pool;
+ mempool_t *scsi_pkt_pool;
struct list_head scsi_pkt_queue;
- u8 throttled;
+ unsigned long last_can_queue_ramp_down_time;
+ unsigned long last_can_queue_ramp_up_time;
+ int max_can_queue;
};
#define fc_get_scsi_internal(x) ((struct fc_fcp_internal *)(x)->scsi_priv)
@@ -90,9 +93,9 @@ static void fc_fcp_recv(struct fc_seq *, struct fc_frame *, void *);
static void fc_fcp_resp(struct fc_fcp_pkt *, struct fc_frame *);
static void fc_fcp_complete_locked(struct fc_fcp_pkt *);
static void fc_tm_done(struct fc_seq *, struct fc_frame *, void *);
-static void fc_fcp_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp);
+static void fc_fcp_error(struct fc_fcp_pkt *, struct fc_frame *);
static void fc_timeout_error(struct fc_fcp_pkt *);
-static void fc_fcp_timeout(unsigned long data);
+static void fc_fcp_timeout(unsigned long);
static void fc_fcp_rec(struct fc_fcp_pkt *);
static void fc_fcp_rec_error(struct fc_fcp_pkt *, struct fc_frame *);
static void fc_fcp_rec_resp(struct fc_seq *, struct fc_frame *, void *);
@@ -124,6 +127,7 @@ static void fc_fcp_srr_error(struct fc_fcp_pkt *, struct fc_frame *);
#define FC_SCSI_TM_TOV (10 * HZ)
#define FC_SCSI_REC_TOV (2 * HZ)
#define FC_HOST_RESET_TIMEOUT (30 * HZ)
+#define FC_CAN_QUEUE_PERIOD (60 * HZ)
#define FC_MAX_ERROR_CNT 5
#define FC_MAX_RECOV_RETRY 3
@@ -131,23 +135,22 @@ static void fc_fcp_srr_error(struct fc_fcp_pkt *, struct fc_frame *);
#define FC_FCP_DFLT_QUEUE_DEPTH 32
/**
- * fc_fcp_pkt_alloc - allocation routine for scsi_pkt packet
- * @lp: fc lport struct
- * @gfp: gfp flags for allocation
+ * fc_fcp_pkt_alloc() - Allocate a fcp_pkt
+ * @lport: The local port that the FCP packet is for
+ * @gfp: GFP flags for allocation
*
- * This is used by upper layer scsi driver.
- * Return Value : scsi_pkt structure or null on allocation failure.
- * Context : call from process context. no locking required.
+ * Return value: fcp_pkt structure or null on allocation failure.
+ * Context: Can be called from process context, no lock is required.
*/
-static struct fc_fcp_pkt *fc_fcp_pkt_alloc(struct fc_lport *lp, gfp_t gfp)
+static struct fc_fcp_pkt *fc_fcp_pkt_alloc(struct fc_lport *lport, gfp_t gfp)
{
- struct fc_fcp_internal *si = fc_get_scsi_internal(lp);
+ struct fc_fcp_internal *si = fc_get_scsi_internal(lport);
struct fc_fcp_pkt *fsp;
fsp = mempool_alloc(si->scsi_pkt_pool, gfp);
if (fsp) {
memset(fsp, 0, sizeof(*fsp));
- fsp->lp = lp;
+ fsp->lp = lport;
atomic_set(&fsp->ref_cnt, 1);
init_timer(&fsp->timer);
INIT_LIST_HEAD(&fsp->list);
@@ -157,12 +160,11 @@ static struct fc_fcp_pkt *fc_fcp_pkt_alloc(struct fc_lport *lp, gfp_t gfp)
}
/**
- * fc_fcp_pkt_release() - release hold on scsi_pkt packet
- * @fsp: fcp packet struct
+ * fc_fcp_pkt_release() - Release hold on a fcp_pkt
+ * @fsp: The FCP packet to be released
*
- * This is used by upper layer scsi driver.
- * Context : call from process and interrupt context.
- * no locking required
+ * Context: Can be called from process or interrupt context,
+ * no lock is required.
*/
static void fc_fcp_pkt_release(struct fc_fcp_pkt *fsp)
{
@@ -173,20 +175,25 @@ static void fc_fcp_pkt_release(struct fc_fcp_pkt *fsp)
}
}
+/**
+ * fc_fcp_pkt_hold() - Hold a fcp_pkt
+ * @fsp: The FCP packet to be held
+ */
static void fc_fcp_pkt_hold(struct fc_fcp_pkt *fsp)
{
atomic_inc(&fsp->ref_cnt);
}
/**
- * fc_fcp_pkt_destory() - release hold on scsi_pkt packet
- * @seq: exchange sequence
- * @fsp: fcp packet struct
+ * fc_fcp_pkt_destory() - Release hold on a fcp_pkt
+ * @seq: The sequence that the FCP packet is on (required by destructor API)
+ * @fsp: The FCP packet to be released
+ *
+ * This routine is called by a destructor callback in the exch_seq_send()
+ * routine of the libfc Transport Template. The 'struct fc_seq' is a required
+ * argument even though it is not used by this routine.
*
- * Release hold on scsi_pkt packet set to keep scsi_pkt
- * till EM layer exch resource is not freed.
- * Context : called from from EM layer.
- * no locking required
+ * Context: No locking required.
*/
static void fc_fcp_pkt_destroy(struct fc_seq *seq, void *fsp)
{
@@ -194,10 +201,10 @@ static void fc_fcp_pkt_destroy(struct fc_seq *seq, void *fsp)
}
/**
- * fc_fcp_lock_pkt() - lock a packet and get a ref to it.
- * @fsp: fcp packet
+ * fc_fcp_lock_pkt() - Lock a fcp_pkt and increase its reference count
+ * @fsp: The FCP packet to be locked and incremented
*
- * We should only return error if we return a command to scsi-ml before
+ * We should only return error if we return a command to SCSI-ml before
* getting a response. This can happen in cases where we send a abort, but
* do not wait for the response and the abort and command can be passing
* each other on the wire/network-layer.
@@ -222,18 +229,33 @@ static inline int fc_fcp_lock_pkt(struct fc_fcp_pkt *fsp)
return 0;
}
+/**
+ * fc_fcp_unlock_pkt() - Release a fcp_pkt's lock and decrement its
+ * reference count
+ * @fsp: The FCP packet to be unlocked and decremented
+ */
static inline void fc_fcp_unlock_pkt(struct fc_fcp_pkt *fsp)
{
spin_unlock_bh(&fsp->scsi_pkt_lock);
fc_fcp_pkt_release(fsp);
}
+/**
+ * fc_fcp_timer_set() - Start a timer for a fcp_pkt
+ * @fsp: The FCP packet to start a timer for
+ * @delay: The timeout period for the timer
+ */
static void fc_fcp_timer_set(struct fc_fcp_pkt *fsp, unsigned long delay)
{
if (!(fsp->state & FC_SRB_COMPL))
mod_timer(&fsp->timer, jiffies + delay);
}
+/**
+ * fc_fcp_send_abort() - Send an abort for exchanges associated with a
+ * fcp_pkt
+ * @fsp: The FCP packet to abort exchanges on
+ */
static int fc_fcp_send_abort(struct fc_fcp_pkt *fsp)
{
if (!fsp->seq_ptr)
@@ -243,9 +265,14 @@ static int fc_fcp_send_abort(struct fc_fcp_pkt *fsp)
return fsp->lp->tt.seq_exch_abort(fsp->seq_ptr, 0);
}
-/*
- * Retry command.
- * An abort isn't needed.
+/**
+ * fc_fcp_retry_cmd() - Retry a fcp_pkt
+ * @fsp: The FCP packet to be retried
+ *
+ * Sets the status code to be FC_ERROR and then calls
+ * fc_fcp_complete_locked() which in turn calls fc_io_compl().
+ * fc_io_compl() will notify the SCSI-ml that the I/O is done.
+ * The SCSI-ml will retry the command.
*/
static void fc_fcp_retry_cmd(struct fc_fcp_pkt *fsp)
{
@@ -260,64 +287,146 @@ static void fc_fcp_retry_cmd(struct fc_fcp_pkt *fsp)
fc_fcp_complete_locked(fsp);
}
-/*
- * fc_fcp_ddp_setup - calls to LLD's ddp_setup to set up DDP
- * transfer for a read I/O indicated by the fc_fcp_pkt.
- * @fsp: ptr to the fc_fcp_pkt
- *
- * This is called in exch_seq_send() when we have a newly allocated
- * exchange with a valid exchange id to setup ddp.
- *
- * returns: none
+/**
+ * fc_fcp_ddp_setup() - Calls a LLD's ddp_setup routine to set up DDP context
+ * @fsp: The FCP packet that will manage the DDP frames
+ * @xid: The XID that will be used for the DDP exchange
*/
void fc_fcp_ddp_setup(struct fc_fcp_pkt *fsp, u16 xid)
{
- struct fc_lport *lp;
+ struct fc_lport *lport;
if (!fsp)
return;
- lp = fsp->lp;
+ lport = fsp->lp;
if ((fsp->req_flags & FC_SRB_READ) &&
- (lp->lro_enabled) && (lp->tt.ddp_setup)) {
- if (lp->tt.ddp_setup(lp, xid, scsi_sglist(fsp->cmd),
- scsi_sg_count(fsp->cmd)))
+ (lport->lro_enabled) && (lport->tt.ddp_setup)) {
+ if (lport->tt.ddp_setup(lport, xid, scsi_sglist(fsp->cmd),
+ scsi_sg_count(fsp->cmd)))
fsp->xfer_ddp = xid;
}
}
-EXPORT_SYMBOL(fc_fcp_ddp_setup);
-/*
- * fc_fcp_ddp_done - calls to LLD's ddp_done to release any
- * DDP related resources for this I/O if it is initialized
- * as a ddp transfer
- * @fsp: ptr to the fc_fcp_pkt
- *
- * returns: none
+/**
+ * fc_fcp_ddp_done() - Calls a LLD's ddp_done routine to release any
+ * DDP related resources for a fcp_pkt
+ * @fsp: The FCP packet that DDP had been used on
*/
static void fc_fcp_ddp_done(struct fc_fcp_pkt *fsp)
{
- struct fc_lport *lp;
+ struct fc_lport *lport;
if (!fsp)
return;
- lp = fsp->lp;
- if (fsp->xfer_ddp && lp->tt.ddp_done) {
- fsp->xfer_len = lp->tt.ddp_done(lp, fsp->xfer_ddp);
- fsp->xfer_ddp = 0;
+ if (fsp->xfer_ddp == FC_XID_UNKNOWN)
+ return;
+
+ lport = fsp->lp;
+ if (lport->tt.ddp_done) {
+ fsp->xfer_len = lport->tt.ddp_done(lport, fsp->xfer_ddp);
+ fsp->xfer_ddp = FC_XID_UNKNOWN;
}
}
+/**
+ * fc_fcp_can_queue_ramp_up() - increases can_queue
+ * @lport: lport to ramp up can_queue
+ *
+ * Locking notes: Called with Scsi_Host lock held
+ */
+static void fc_fcp_can_queue_ramp_up(struct fc_lport *lport)
+{
+ struct fc_fcp_internal *si = fc_get_scsi_internal(lport);
+ int can_queue;
+
+ if (si->last_can_queue_ramp_up_time &&
+ (time_before(jiffies, si->last_can_queue_ramp_up_time +
+ FC_CAN_QUEUE_PERIOD)))
+ return;
+
+ if (time_before(jiffies, si->last_can_queue_ramp_down_time +
+ FC_CAN_QUEUE_PERIOD))
+ return;
+
+ si->last_can_queue_ramp_up_time = jiffies;
+
+ can_queue = lport->host->can_queue << 1;
+ if (can_queue >= si->max_can_queue) {
+ can_queue = si->max_can_queue;
+ si->last_can_queue_ramp_down_time = 0;
+ }
+ lport->host->can_queue = can_queue;
+ shost_printk(KERN_ERR, lport->host, "libfc: increased "
+ "can_queue to %d.\n", can_queue);
+}
+
+/**
+ * fc_fcp_can_queue_ramp_down() - reduces can_queue
+ * @lport: lport to reduce can_queue
+ *
+ * If we are getting memory allocation failures, then we may
+ * be trying to execute too many commands. We let the running
+ * commands complete or timeout, then try again with a reduced
+ * can_queue. Eventually we will hit the point where we run
+ * on all reserved structs.
+ *
+ * Locking notes: Called with Scsi_Host lock held
+ */
+static void fc_fcp_can_queue_ramp_down(struct fc_lport *lport)
+{
+ struct fc_fcp_internal *si = fc_get_scsi_internal(lport);
+ int can_queue;
+
+ if (si->last_can_queue_ramp_down_time &&
+ (time_before(jiffies, si->last_can_queue_ramp_down_time +
+ FC_CAN_QUEUE_PERIOD)))
+ return;
+
+ si->last_can_queue_ramp_down_time = jiffies;
+
+ can_queue = lport->host->can_queue;
+ can_queue >>= 1;
+ if (!can_queue)
+ can_queue = 1;
+ lport->host->can_queue = can_queue;
+ shost_printk(KERN_ERR, lport->host, "libfc: Could not allocate frame.\n"
+ "Reducing can_queue to %d.\n", can_queue);
+}
/*
- * Receive SCSI data from target.
- * Called after receiving solicited data.
+ * fc_fcp_frame_alloc() - Allocates fc_frame structure and buffer.
+ * @lport: fc lport struct
+ * @len: payload length
+ *
+ * Allocates fc_frame structure and buffer but if fails to allocate
+ * then reduce can_queue.
+ */
+static inline struct fc_frame *fc_fcp_frame_alloc(struct fc_lport *lport,
+ size_t len)
+{
+ struct fc_frame *fp;
+ unsigned long flags;
+
+ fp = fc_frame_alloc(lport, len);
+ if (!fp) {
+ spin_lock_irqsave(lport->host->host_lock, flags);
+ fc_fcp_can_queue_ramp_down(lport);
+ spin_unlock_irqrestore(lport->host->host_lock, flags);
+ }
+ return fp;
+}
+
+/**
+ * fc_fcp_recv_data() - Handler for receiving SCSI-FCP data from a target
+ * @fsp: The FCP packet the data is on
+ * @fp: The data frame
*/
static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
{
struct scsi_cmnd *sc = fsp->cmd;
- struct fc_lport *lp = fsp->lp;
+ struct fc_lport *lport = fsp->lp;
struct fcoe_dev_stats *stats;
struct fc_frame_header *fh;
size_t start_offset;
@@ -327,7 +436,7 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
size_t len;
void *buf;
struct scatterlist *sg;
- size_t remaining;
+ u32 nents;
fh = fc_frame_header_get(fp);
offset = ntohl(fh->fh_parm_offset);
@@ -351,65 +460,29 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
if (offset != fsp->xfer_len)
fsp->state |= FC_SRB_DISCONTIG;
- crc = 0;
- if (fr_flags(fp) & FCPHF_CRC_UNCHECKED)
- crc = crc32(~0, (u8 *) fh, sizeof(*fh));
-
sg = scsi_sglist(sc);
- remaining = len;
-
- while (remaining > 0 && sg) {
- size_t off;
- void *page_addr;
- size_t sg_bytes;
+ nents = scsi_sg_count(sc);
- if (offset >= sg->length) {
- offset -= sg->length;
- sg = sg_next(sg);
- continue;
- }
- sg_bytes = min(remaining, sg->length - offset);
-
- /*
- * The scatterlist item may be bigger than PAGE_SIZE,
- * but we are limited to mapping PAGE_SIZE at a time.
- */
- off = offset + sg->offset;
- sg_bytes = min(sg_bytes, (size_t)
- (PAGE_SIZE - (off & ~PAGE_MASK)));
- page_addr = kmap_atomic(sg_page(sg) + (off >> PAGE_SHIFT),
- KM_SOFTIRQ0);
- if (!page_addr)
- break; /* XXX panic? */
-
- if (fr_flags(fp) & FCPHF_CRC_UNCHECKED)
- crc = crc32(crc, buf, sg_bytes);
- memcpy((char *)page_addr + (off & ~PAGE_MASK), buf,
- sg_bytes);
-
- kunmap_atomic(page_addr, KM_SOFTIRQ0);
- buf += sg_bytes;
- offset += sg_bytes;
- remaining -= sg_bytes;
- copy_len += sg_bytes;
- }
-
- if (fr_flags(fp) & FCPHF_CRC_UNCHECKED) {
+ if (!(fr_flags(fp) & FCPHF_CRC_UNCHECKED)) {
+ copy_len = fc_copy_buffer_to_sglist(buf, len, sg, &nents,
+ &offset, KM_SOFTIRQ0, NULL);
+ } else {
+ crc = crc32(~0, (u8 *) fh, sizeof(*fh));
+ copy_len = fc_copy_buffer_to_sglist(buf, len, sg, &nents,
+ &offset, KM_SOFTIRQ0, &crc);
buf = fc_frame_payload_get(fp, 0);
- if (len % 4) {
+ if (len % 4)
crc = crc32(crc, buf + len, 4 - (len % 4));
- len += 4 - (len % 4);
- }
if (~crc != le32_to_cpu(fr_crc(fp))) {
crc_err:
- stats = fc_lport_get_stats(lp);
+ stats = fc_lport_get_stats(lport);
stats->ErrorFrames++;
/* FIXME - per cpu count, not total count! */
if (stats->InvalidCRCCount++ < 5)
printk(KERN_WARNING "libfc: CRC error on data "
"frame for port (%6x)\n",
- fc_host_port_id(lp->host));
+ fc_host_port_id(lport->host));
/*
* Assume the frame is total garbage.
* We may have copied it over the good part
@@ -437,18 +510,17 @@ crc_err:
}
/**
- * fc_fcp_send_data() - Send SCSI data to target.
- * @fsp: ptr to fc_fcp_pkt
- * @sp: ptr to this sequence
- * @offset: starting offset for this data request
- * @seq_blen: the burst length for this data request
+ * fc_fcp_send_data() - Send SCSI data to a target
+ * @fsp: The FCP packet the data is on
+ * @sp: The sequence the data is to be sent on
+ * @offset: The starting offset for this data request
+ * @seq_blen: The burst length for this data request
*
* Called after receiving a Transfer Ready data descriptor.
- * if LLD is capable of seq offload then send down seq_blen
- * size of data in single frame, otherwise send multiple FC
- * frames of max FC frame payload supported by target port.
- *
- * Returns : 0 for success.
+ * If the LLD is capable of sequence offload then send down the
+ * seq_blen ammount of data in single frame, otherwise send
+ * multiple frames of the maximum frame payload supported by
+ * the target port.
*/
static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq,
size_t offset, size_t seq_blen)
@@ -457,16 +529,18 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq,
struct scsi_cmnd *sc;
struct scatterlist *sg;
struct fc_frame *fp = NULL;
- struct fc_lport *lp = fsp->lp;
+ struct fc_lport *lport = fsp->lp;
+ struct page *page;
size_t remaining;
size_t t_blen;
size_t tlen;
size_t sg_bytes;
size_t frame_offset, fh_parm_offset;
+ size_t off;
int error;
void *data = NULL;
void *page_addr;
- int using_sg = lp->sg_supp;
+ int using_sg = lport->sg_supp;
u32 f_ctl;
WARN_ON(seq_blen <= 0);
@@ -488,10 +562,10 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq,
* to max FC frame payload previously set in fsp->max_payload.
*/
t_blen = fsp->max_payload;
- if (lp->seq_offload) {
- t_blen = min(seq_blen, (size_t)lp->lso_max);
+ if (lport->seq_offload) {
+ t_blen = min(seq_blen, (size_t)lport->lso_max);
FC_FCP_DBG(fsp, "fsp=%p:lso:blen=%zx lso_max=0x%x t_blen=%zx\n",
- fsp, seq_blen, lp->lso_max, t_blen);
+ fsp, seq_blen, lport->lso_max, t_blen);
}
WARN_ON(t_blen < FC_MIN_MAX_PAYLOAD);
@@ -503,7 +577,7 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq,
remaining = seq_blen;
fh_parm_offset = frame_offset = offset;
tlen = 0;
- seq = lp->tt.seq_start_next(seq);
+ seq = lport->tt.seq_start_next(seq);
f_ctl = FC_FC_REL_OFF;
WARN_ON(!seq);
@@ -525,43 +599,34 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq,
*/
if (tlen % 4)
using_sg = 0;
- if (using_sg) {
- fp = _fc_frame_alloc(lp, 0);
- if (!fp)
- return -ENOMEM;
- } else {
- fp = fc_frame_alloc(lp, tlen);
- if (!fp)
- return -ENOMEM;
+ fp = fc_frame_alloc(lport, using_sg ? 0 : tlen);
+ if (!fp)
+ return -ENOMEM;
- data = (void *)(fr_hdr(fp)) +
- sizeof(struct fc_frame_header);
- }
+ data = fc_frame_header_get(fp) + 1;
fh_parm_offset = frame_offset;
fr_max_payload(fp) = fsp->max_payload;
}
+
+ off = offset + sg->offset;
sg_bytes = min(tlen, sg->length - offset);
+ sg_bytes = min(sg_bytes,
+ (size_t) (PAGE_SIZE - (off & ~PAGE_MASK)));
+ page = sg_page(sg) + (off >> PAGE_SHIFT);
if (using_sg) {
- get_page(sg_page(sg));
+ get_page(page);
skb_fill_page_desc(fp_skb(fp),
skb_shinfo(fp_skb(fp))->nr_frags,
- sg_page(sg), sg->offset + offset,
- sg_bytes);
+ page, off & ~PAGE_MASK, sg_bytes);
fp_skb(fp)->data_len += sg_bytes;
fr_len(fp) += sg_bytes;
fp_skb(fp)->truesize += PAGE_SIZE;
} else {
- size_t off = offset + sg->offset;
-
/*
* The scatterlist item may be bigger than PAGE_SIZE,
* but we must not cross pages inside the kmap.
*/
- sg_bytes = min(sg_bytes, (size_t) (PAGE_SIZE -
- (off & ~PAGE_MASK)));
- page_addr = kmap_atomic(sg_page(sg) +
- (off >> PAGE_SHIFT),
- KM_SOFTIRQ0);
+ page_addr = kmap_atomic(page, KM_SOFTIRQ0);
memcpy(data, (char *)page_addr + (off & ~PAGE_MASK),
sg_bytes);
kunmap_atomic(page_addr, KM_SOFTIRQ0);
@@ -572,7 +637,8 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq,
tlen -= sg_bytes;
remaining -= sg_bytes;
- if (tlen)
+ if ((skb_shinfo(fp_skb(fp))->nr_frags < FC_FRAME_SG_LEN) &&
+ (tlen))
continue;
/*
@@ -589,7 +655,7 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq,
/*
* send fragment using for a sequence.
*/
- error = lp->tt.seq_send(lp, seq, fp);
+ error = lport->tt.seq_send(lport, seq, fp);
if (error) {
WARN_ON(1); /* send error should be rare */
fc_fcp_retry_cmd(fsp);
@@ -601,6 +667,11 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq,
return 0;
}
+/**
+ * fc_fcp_abts_resp() - Send an ABTS response
+ * @fsp: The FCP packet that is being aborted
+ * @fp: The response frame
+ */
static void fc_fcp_abts_resp(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
{
int ba_done = 1;
@@ -637,46 +708,13 @@ static void fc_fcp_abts_resp(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
}
/**
- * fc_fcp_reduce_can_queue() - drop can_queue
- * @lp: lport to drop queueing for
- *
- * If we are getting memory allocation failures, then we may
- * be trying to execute too many commands. We let the running
- * commands complete or timeout, then try again with a reduced
- * can_queue. Eventually we will hit the point where we run
- * on all reserved structs.
- */
-static void fc_fcp_reduce_can_queue(struct fc_lport *lp)
-{
- struct fc_fcp_internal *si = fc_get_scsi_internal(lp);
- unsigned long flags;
- int can_queue;
-
- spin_lock_irqsave(lp->host->host_lock, flags);
- if (si->throttled)
- goto done;
- si->throttled = 1;
-
- can_queue = lp->host->can_queue;
- can_queue >>= 1;
- if (!can_queue)
- can_queue = 1;
- lp->host->can_queue = can_queue;
- shost_printk(KERN_ERR, lp->host, "libfc: Could not allocate frame.\n"
- "Reducing can_queue to %d.\n", can_queue);
-done:
- spin_unlock_irqrestore(lp->host->host_lock, flags);
-}
-
-/**
- * fc_fcp_recv() - Reveive FCP frames
+ * fc_fcp_recv() - Reveive an FCP frame
* @seq: The sequence the frame is on
- * @fp: The FC frame
+ * @fp: The received frame
* @arg: The related FCP packet
*
- * Return : None
- * Context : called from Soft IRQ context
- * can not called holding list lock
+ * Context: Called from Soft IRQ context. Can not be called
+ * holding the FCP packet list lock.
*/
static void fc_fcp_recv(struct fc_seq *seq, struct fc_frame *fp, void *arg)
{
@@ -687,8 +725,10 @@ static void fc_fcp_recv(struct fc_seq *seq, struct fc_frame *fp, void *arg)
u8 r_ctl;
int rc = 0;
- if (IS_ERR(fp))
- goto errout;
+ if (IS_ERR(fp)) {
+ fc_fcp_error(fsp, fp);
+ return;
+ }
fh = fc_frame_header_get(fp);
r_ctl = fh->fh_r_ctl;
@@ -721,8 +761,6 @@ static void fc_fcp_recv(struct fc_seq *seq, struct fc_frame *fp, void *arg)
(size_t) ntohl(dd->ft_burst_len));
if (!rc)
seq->rec_data = fsp->xfer_len;
- else if (rc == -ENOMEM)
- fsp->state |= FC_SRB_NOMEM;
} else if (r_ctl == FC_RCTL_DD_SOL_DATA) {
/*
* received a DATA frame
@@ -742,13 +780,13 @@ unlock:
fc_fcp_unlock_pkt(fsp);
out:
fc_frame_free(fp);
-errout:
- if (IS_ERR(fp))
- fc_fcp_error(fsp, fp);
- else if (rc == -ENOMEM)
- fc_fcp_reduce_can_queue(lport);
}
+/**
+ * fc_fcp_resp() - Handler for FCP responses
+ * @fsp: The FCP packet the response is for
+ * @fp: The response frame
+ */
static void fc_fcp_resp(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
{
struct fc_frame_header *fh;
@@ -862,15 +900,16 @@ err:
}
/**
- * fc_fcp_complete_locked() - complete processing of a fcp packet
- * @fsp: fcp packet
+ * fc_fcp_complete_locked() - Complete processing of a fcp_pkt with the
+ * fcp_pkt lock held
+ * @fsp: The FCP packet to be completed
*
* This function may sleep if a timer is pending. The packet lock must be
* held, and the host lock must not be held.
*/
static void fc_fcp_complete_locked(struct fc_fcp_pkt *fsp)
{
- struct fc_lport *lp = fsp->lp;
+ struct fc_lport *lport = fsp->lp;
struct fc_seq *seq;
struct fc_exch *ep;
u32 f_ctl;
@@ -901,8 +940,8 @@ static void fc_fcp_complete_locked(struct fc_fcp_pkt *fsp)
struct fc_frame *conf_frame;
struct fc_seq *csp;
- csp = lp->tt.seq_start_next(seq);
- conf_frame = fc_frame_alloc(fsp->lp, 0);
+ csp = lport->tt.seq_start_next(seq);
+ conf_frame = fc_fcp_frame_alloc(fsp->lp, 0);
if (conf_frame) {
f_ctl = FC_FC_SEQ_INIT;
f_ctl |= FC_FC_LAST_SEQ | FC_FC_END_SEQ;
@@ -910,43 +949,48 @@ static void fc_fcp_complete_locked(struct fc_fcp_pkt *fsp)
fc_fill_fc_hdr(conf_frame, FC_RCTL_DD_SOL_CTL,
ep->did, ep->sid,
FC_TYPE_FCP, f_ctl, 0);
- lp->tt.seq_send(lp, csp, conf_frame);
+ lport->tt.seq_send(lport, csp, conf_frame);
}
}
- lp->tt.exch_done(seq);
+ lport->tt.exch_done(seq);
}
fc_io_compl(fsp);
}
+/**
+ * fc_fcp_cleanup_cmd() - Cancel the active exchange on a fcp_pkt
+ * @fsp: The FCP packet whose exchanges should be canceled
+ * @error: The reason for the cancellation
+ */
static void fc_fcp_cleanup_cmd(struct fc_fcp_pkt *fsp, int error)
{
- struct fc_lport *lp = fsp->lp;
+ struct fc_lport *lport = fsp->lp;
if (fsp->seq_ptr) {
- lp->tt.exch_done(fsp->seq_ptr);
+ lport->tt.exch_done(fsp->seq_ptr);
fsp->seq_ptr = NULL;
}
fsp->status_code = error;
}
/**
- * fc_fcp_cleanup_each_cmd() - Cleanup active commads
- * @lp: logical port
- * @id: target id
- * @lun: lun
- * @error: fsp status code
+ * fc_fcp_cleanup_each_cmd() - Cancel all exchanges on a local port
+ * @lport: The local port whose exchanges should be canceled
+ * @id: The target's ID
+ * @lun: The LUN
+ * @error: The reason for cancellation
*
* If lun or id is -1, they are ignored.
*/
-static void fc_fcp_cleanup_each_cmd(struct fc_lport *lp, unsigned int id,
+static void fc_fcp_cleanup_each_cmd(struct fc_lport *lport, unsigned int id,
unsigned int lun, int error)
{
- struct fc_fcp_internal *si = fc_get_scsi_internal(lp);
+ struct fc_fcp_internal *si = fc_get_scsi_internal(lport);
struct fc_fcp_pkt *fsp;
struct scsi_cmnd *sc_cmd;
unsigned long flags;
- spin_lock_irqsave(lp->host->host_lock, flags);
+ spin_lock_irqsave(lport->host->host_lock, flags);
restart:
list_for_each_entry(fsp, &si->scsi_pkt_queue, list) {
sc_cmd = fsp->cmd;
@@ -957,7 +1001,7 @@ restart:
continue;
fc_fcp_pkt_hold(fsp);
- spin_unlock_irqrestore(lp->host->host_lock, flags);
+ spin_unlock_irqrestore(lport->host->host_lock, flags);
if (!fc_fcp_lock_pkt(fsp)) {
fc_fcp_cleanup_cmd(fsp, error);
@@ -966,35 +1010,36 @@ restart:
}
fc_fcp_pkt_release(fsp);
- spin_lock_irqsave(lp->host->host_lock, flags);
+ spin_lock_irqsave(lport->host->host_lock, flags);
/*
* while we dropped the lock multiple pkts could
* have been released, so we have to start over.
*/
goto restart;
}
- spin_unlock_irqrestore(lp->host->host_lock, flags);
+ spin_unlock_irqrestore(lport->host->host_lock, flags);
}
-static void fc_fcp_abort_io(struct fc_lport *lp)
+/**
+ * fc_fcp_abort_io() - Abort all FCP-SCSI exchanges on a local port
+ * @lport: The local port whose exchanges are to be aborted
+ */
+static void fc_fcp_abort_io(struct fc_lport *lport)
{
- fc_fcp_cleanup_each_cmd(lp, -1, -1, FC_HRD_ERROR);
+ fc_fcp_cleanup_each_cmd(lport, -1, -1, FC_HRD_ERROR);
}
/**
- * fc_fcp_pkt_send() - send a fcp packet to the lower level.
- * @lp: fc lport
- * @fsp: fc packet.
+ * fc_fcp_pkt_send() - Send a fcp_pkt
+ * @lport: The local port to send the FCP packet on
+ * @fsp: The FCP packet to send
*
- * This is called by upper layer protocol.
- * Return : zero for success and -1 for failure
- * Context : called from queuecommand which can be called from process
- * or scsi soft irq.
- * Locks : called with the host lock and irqs disabled.
+ * Return: Zero for success and -1 for failure
+ * Locks: Called with the host lock and irqs disabled.
*/
-static int fc_fcp_pkt_send(struct fc_lport *lp, struct fc_fcp_pkt *fsp)
+static int fc_fcp_pkt_send(struct fc_lport *lport, struct fc_fcp_pkt *fsp)
{
- struct fc_fcp_internal *si = fc_get_scsi_internal(lp);
+ struct fc_fcp_internal *si = fc_get_scsi_internal(lport);
int rc;
fsp->cmd->SCp.ptr = (char *)fsp;
@@ -1006,16 +1051,22 @@ static int fc_fcp_pkt_send(struct fc_lport *lp, struct fc_fcp_pkt *fsp)
memcpy(fsp->cdb_cmd.fc_cdb, fsp->cmd->cmnd, fsp->cmd->cmd_len);
list_add_tail(&fsp->list, &si->scsi_pkt_queue);
- spin_unlock_irq(lp->host->host_lock);
- rc = lp->tt.fcp_cmd_send(lp, fsp, fc_fcp_recv);
- spin_lock_irq(lp->host->host_lock);
+ spin_unlock_irq(lport->host->host_lock);
+ rc = lport->tt.fcp_cmd_send(lport, fsp, fc_fcp_recv);
+ spin_lock_irq(lport->host->host_lock);
if (rc)
list_del(&fsp->list);
return rc;
}
-static int fc_fcp_cmd_send(struct fc_lport *lp, struct fc_fcp_pkt *fsp,
+/**
+ * fc_fcp_cmd_send() - Send a FCP command
+ * @lport: The local port to send the command on
+ * @fsp: The FCP packet the command is on
+ * @resp: The handler for the response
+ */
+static int fc_fcp_cmd_send(struct fc_lport *lport, struct fc_fcp_pkt *fsp,
void (*resp)(struct fc_seq *,
struct fc_frame *fp,
void *arg))
@@ -1023,14 +1074,14 @@ static int fc_fcp_cmd_send(struct fc_lport *lp, struct fc_fcp_pkt *fsp,
struct fc_frame *fp;
struct fc_seq *seq;
struct fc_rport *rport;
- struct fc_rport_libfc_priv *rp;
+ struct fc_rport_libfc_priv *rpriv;
const size_t len = sizeof(fsp->cdb_cmd);
int rc = 0;
if (fc_fcp_lock_pkt(fsp))
return 0;
- fp = fc_frame_alloc(lp, sizeof(fsp->cdb_cmd));
+ fp = fc_fcp_frame_alloc(lport, sizeof(fsp->cdb_cmd));
if (!fp) {
rc = -1;
goto unlock;
@@ -1040,15 +1091,15 @@ static int fc_fcp_cmd_send(struct fc_lport *lp, struct fc_fcp_pkt *fsp,
fr_fsp(fp) = fsp;
rport = fsp->rport;
fsp->max_payload = rport->maxframe_size;
- rp = rport->dd_data;
+ rpriv = rport->dd_data;
fc_fill_fc_hdr(fp, FC_RCTL_DD_UNSOL_CMD, rport->port_id,
- fc_host_port_id(rp->local_port->host), FC_TYPE_FCP,
+ fc_host_port_id(rpriv->local_port->host), FC_TYPE_FCP,
FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
- seq = lp->tt.exch_seq_send(lp, fp, resp, fc_fcp_pkt_destroy, fsp, 0);
+ seq = lport->tt.exch_seq_send(lport, fp, resp, fc_fcp_pkt_destroy,
+ fsp, 0);
if (!seq) {
- fc_frame_free(fp);
rc = -1;
goto unlock;
}
@@ -1065,8 +1116,10 @@ unlock:
return rc;
}
-/*
- * transport error handler
+/**
+ * fc_fcp_error() - Handler for FCP layer errors
+ * @fsp: The FCP packet the error is on
+ * @fp: The frame that has errored
*/
static void fc_fcp_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
{
@@ -1091,11 +1144,13 @@ unlock:
fc_fcp_unlock_pkt(fsp);
}
-/*
- * Scsi abort handler- calls to send an abort
- * and then wait for abort completion
+/**
+ * fc_fcp_pkt_abort() - Abort a fcp_pkt
+ * @fsp: The FCP packet to abort on
+ *
+ * Called to send an abort and then wait for abort completion
*/
-static int fc_fcp_pkt_abort(struct fc_lport *lp, struct fc_fcp_pkt *fsp)
+static int fc_fcp_pkt_abort(struct fc_fcp_pkt *fsp)
{
int rc = FAILED;
@@ -1122,14 +1177,15 @@ static int fc_fcp_pkt_abort(struct fc_lport *lp, struct fc_fcp_pkt *fsp)
return rc;
}
-/*
- * Retry LUN reset after resource allocation failed.
+/**
+ * fc_lun_reset_send() - Send LUN reset command
+ * @data: The FCP packet that identifies the LUN to be reset
*/
static void fc_lun_reset_send(unsigned long data)
{
struct fc_fcp_pkt *fsp = (struct fc_fcp_pkt *)data;
- struct fc_lport *lp = fsp->lp;
- if (lp->tt.fcp_cmd_send(lp, fsp, fc_tm_done)) {
+ struct fc_lport *lport = fsp->lp;
+ if (lport->tt.fcp_cmd_send(lport, fsp, fc_tm_done)) {
if (fsp->recov_retry++ >= FC_MAX_RECOV_RETRY)
return;
if (fc_fcp_lock_pkt(fsp))
@@ -1140,11 +1196,15 @@ static void fc_lun_reset_send(unsigned long data)
}
}
-/*
- * Scsi device reset handler- send a LUN RESET to the device
- * and wait for reset reply
+/**
+ * fc_lun_reset() - Send a LUN RESET command to a device
+ * and wait for the reply
+ * @lport: The local port to sent the comand on
+ * @fsp: The FCP packet that identifies the LUN to be reset
+ * @id: The SCSI command ID
+ * @lun: The LUN ID to be reset
*/
-static int fc_lun_reset(struct fc_lport *lp, struct fc_fcp_pkt *fsp,
+static int fc_lun_reset(struct fc_lport *lport, struct fc_fcp_pkt *fsp,
unsigned int id, unsigned int lun)
{
int rc;
@@ -1172,14 +1232,14 @@ static int fc_lun_reset(struct fc_lport *lp, struct fc_fcp_pkt *fsp,
spin_lock_bh(&fsp->scsi_pkt_lock);
if (fsp->seq_ptr) {
- lp->tt.exch_done(fsp->seq_ptr);
+ lport->tt.exch_done(fsp->seq_ptr);
fsp->seq_ptr = NULL;
}
fsp->wait_for_comp = 0;
spin_unlock_bh(&fsp->scsi_pkt_lock);
if (!rc) {
- FC_SCSI_DBG(lp, "lun reset failed\n");
+ FC_SCSI_DBG(lport, "lun reset failed\n");
return FAILED;
}
@@ -1187,13 +1247,16 @@ static int fc_lun_reset(struct fc_lport *lp, struct fc_fcp_pkt *fsp,
if (fsp->cdb_status != FCP_TMF_CMPL)
return FAILED;
- FC_SCSI_DBG(lp, "lun reset to lun %u completed\n", lun);
- fc_fcp_cleanup_each_cmd(lp, id, lun, FC_CMD_ABORTED);
+ FC_SCSI_DBG(lport, "lun reset to lun %u completed\n", lun);
+ fc_fcp_cleanup_each_cmd(lport, id, lun, FC_CMD_ABORTED);
return SUCCESS;
}
-/*
- * Task Managment response handler
+/**
+ * fc_tm_done() - Task Managment response handler
+ * @seq: The sequence that the response is on
+ * @fp: The response frame
+ * @arg: The FCP packet the response is for
*/
static void fc_tm_done(struct fc_seq *seq, struct fc_frame *fp, void *arg)
{
@@ -1230,34 +1293,31 @@ static void fc_tm_done(struct fc_seq *seq, struct fc_frame *fp, void *arg)
fc_fcp_unlock_pkt(fsp);
}
-static void fc_fcp_cleanup(struct fc_lport *lp)
+/**
+ * fc_fcp_cleanup() - Cleanup all FCP exchanges on a local port
+ * @lport: The local port to be cleaned up
+ */
+static void fc_fcp_cleanup(struct fc_lport *lport)
{
- fc_fcp_cleanup_each_cmd(lp, -1, -1, FC_ERROR);
+ fc_fcp_cleanup_each_cmd(lport, -1, -1, FC_ERROR);
}
-/*
- * fc_fcp_timeout: called by OS timer function.
- *
- * The timer has been inactivated and must be reactivated if desired
- * using fc_fcp_timer_set().
- *
- * Algorithm:
- *
- * If REC is supported, just issue it, and return. The REC exchange will
- * complete or time out, and recovery can continue at that point.
- *
- * Otherwise, if the response has been received without all the data,
- * it has been ER_TIMEOUT since the response was received.
+/**
+ * fc_fcp_timeout() - Handler for fcp_pkt timeouts
+ * @data: The FCP packet that has timed out
*
- * If the response has not been received,
- * we see if data was received recently. If it has been, we continue waiting,
- * otherwise, we abort the command.
+ * If REC is supported then just issue it and return. The REC exchange will
+ * complete or time out and recovery can continue at that point. Otherwise,
+ * if the response has been received without all the data it has been
+ * ER_TIMEOUT since the response was received. If the response has not been
+ * received we see if data was received recently. If it has been then we
+ * continue waiting, otherwise, we abort the command.
*/
static void fc_fcp_timeout(unsigned long data)
{
struct fc_fcp_pkt *fsp = (struct fc_fcp_pkt *)data;
struct fc_rport *rport = fsp->rport;
- struct fc_rport_libfc_priv *rp = rport->dd_data;
+ struct fc_rport_libfc_priv *rpriv = rport->dd_data;
if (fc_fcp_lock_pkt(fsp))
return;
@@ -1267,7 +1327,7 @@ static void fc_fcp_timeout(unsigned long data)
fsp->state |= FC_SRB_FCP_PROCESSING_TMO;
- if (rp->flags & FC_RP_FLAGS_REC_SUPPORTED)
+ if (rpriv->flags & FC_RP_FLAGS_REC_SUPPORTED)
fc_fcp_rec(fsp);
else if (time_after_eq(fsp->last_pkt_time + (FC_SCSI_ER_TIMEOUT / 2),
jiffies))
@@ -1281,39 +1341,40 @@ unlock:
fc_fcp_unlock_pkt(fsp);
}
-/*
- * Send a REC ELS request
+/**
+ * fc_fcp_rec() - Send a REC ELS request
+ * @fsp: The FCP packet to send the REC request on
*/
static void fc_fcp_rec(struct fc_fcp_pkt *fsp)
{
- struct fc_lport *lp;
+ struct fc_lport *lport;
struct fc_frame *fp;
struct fc_rport *rport;
- struct fc_rport_libfc_priv *rp;
+ struct fc_rport_libfc_priv *rpriv;
- lp = fsp->lp;
+ lport = fsp->lp;
rport = fsp->rport;
- rp = rport->dd_data;
- if (!fsp->seq_ptr || rp->rp_state != RPORT_ST_READY) {
+ rpriv = rport->dd_data;
+ if (!fsp->seq_ptr || rpriv->rp_state != RPORT_ST_READY) {
fsp->status_code = FC_HRD_ERROR;
fsp->io_status = 0;
fc_fcp_complete_locked(fsp);
return;
}
- fp = fc_frame_alloc(lp, sizeof(struct fc_els_rec));
+ fp = fc_fcp_frame_alloc(lport, sizeof(struct fc_els_rec));
if (!fp)
goto retry;
fr_seq(fp) = fsp->seq_ptr;
fc_fill_fc_hdr(fp, FC_RCTL_ELS_REQ, rport->port_id,
- fc_host_port_id(rp->local_port->host), FC_TYPE_ELS,
+ fc_host_port_id(rpriv->local_port->host), FC_TYPE_ELS,
FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
- if (lp->tt.elsct_send(lp, rport->port_id, fp, ELS_REC, fc_fcp_rec_resp,
- fsp, jiffies_to_msecs(FC_SCSI_REC_TOV))) {
+ if (lport->tt.elsct_send(lport, rport->port_id, fp, ELS_REC,
+ fc_fcp_rec_resp, fsp,
+ jiffies_to_msecs(FC_SCSI_REC_TOV))) {
fc_fcp_pkt_hold(fsp); /* hold while REC outstanding */
return;
}
- fc_frame_free(fp);
retry:
if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY)
fc_fcp_timer_set(fsp, FC_SCSI_REC_TOV);
@@ -1321,12 +1382,16 @@ retry:
fc_timeout_error(fsp);
}
-/*
- * Receive handler for REC ELS frame
- * if it is a reject then let the scsi layer to handle
- * the timeout. if it is a LS_ACC then if the io was not completed
- * then set the timeout and return otherwise complete the exchange
- * and tell the scsi layer to restart the I/O.
+/**
+ * fc_fcp_rec_resp() - Handler for REC ELS responses
+ * @seq: The sequence the response is on
+ * @fp: The response frame
+ * @arg: The FCP packet the response is on
+ *
+ * If the response is a reject then the scsi layer will handle
+ * the timeout. If the response is a LS_ACC then if the I/O was not completed
+ * set the timeout and return. If the I/O was completed then complete the
+ * exchange and tell the SCSI layer.
*/
static void fc_fcp_rec_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg)
{
@@ -1338,7 +1403,7 @@ static void fc_fcp_rec_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg)
u32 offset;
enum dma_data_direction data_dir;
enum fc_rctl r_ctl;
- struct fc_rport_libfc_priv *rp;
+ struct fc_rport_libfc_priv *rpriv;
if (IS_ERR(fp)) {
fc_fcp_rec_error(fsp, fp);
@@ -1361,13 +1426,13 @@ static void fc_fcp_rec_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg)
/* fall through */
case ELS_RJT_UNSUP:
FC_FCP_DBG(fsp, "device does not support REC\n");
- rp = fsp->rport->dd_data;
+ rpriv = fsp->rport->dd_data;
/*
* if we do not spport RECs or got some bogus
* reason then resetup timer so we check for
* making progress.
*/
- rp->flags &= ~FC_RP_FLAGS_REC_SUPPORTED;
+ rpriv->flags &= ~FC_RP_FLAGS_REC_SUPPORTED;
fc_fcp_timer_set(fsp, FC_SCSI_ER_TIMEOUT);
break;
case ELS_RJT_LOGIC:
@@ -1464,8 +1529,10 @@ out:
fc_frame_free(fp);
}
-/*
- * Handle error response or timeout for REC exchange.
+/**
+ * fc_fcp_rec_error() - Handler for REC errors
+ * @fsp: The FCP packet the error is on
+ * @fp: The REC frame
*/
static void fc_fcp_rec_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
{
@@ -1504,10 +1571,9 @@ out:
fc_fcp_pkt_release(fsp); /* drop hold for outstanding REC */
}
-/*
- * Time out error routine:
- * abort's the I/O close the exchange and
- * send completion notification to scsi layer
+/**
+ * fc_timeout_error() - Handler for fcp_pkt timeouts
+ * @fsp: The FCP packt that has timed out
*/
static void fc_timeout_error(struct fc_fcp_pkt *fsp)
{
@@ -1521,16 +1587,18 @@ static void fc_timeout_error(struct fc_fcp_pkt *fsp)
fc_fcp_send_abort(fsp);
}
-/*
- * Sequence retransmission request.
+/**
+ * fc_fcp_srr() - Send a SRR request (Sequence Retransmission Request)
+ * @fsp: The FCP packet the SRR is to be sent on
+ * @r_ctl: The R_CTL field for the SRR request
* This is called after receiving status but insufficient data, or
* when expecting status but the request has timed out.
*/
static void fc_fcp_srr(struct fc_fcp_pkt *fsp, enum fc_rctl r_ctl, u32 offset)
{
- struct fc_lport *lp = fsp->lp;
+ struct fc_lport *lport = fsp->lp;
struct fc_rport *rport;
- struct fc_rport_libfc_priv *rp;
+ struct fc_rport_libfc_priv *rpriv;
struct fc_exch *ep = fc_seq_exch(fsp->seq_ptr);
struct fc_seq *seq;
struct fcp_srr *srr;
@@ -1538,12 +1606,13 @@ static void fc_fcp_srr(struct fc_fcp_pkt *fsp, enum fc_rctl r_ctl, u32 offset)
u8 cdb_op;
rport = fsp->rport;
- rp = rport->dd_data;
+ rpriv = rport->dd_data;
cdb_op = fsp->cdb_cmd.fc_cdb[0];
- if (!(rp->flags & FC_RP_FLAGS_RETRY) || rp->rp_state != RPORT_ST_READY)
+ if (!(rpriv->flags & FC_RP_FLAGS_RETRY) ||
+ rpriv->rp_state != RPORT_ST_READY)
goto retry; /* shouldn't happen */
- fp = fc_frame_alloc(lp, sizeof(*srr));
+ fp = fc_fcp_frame_alloc(lport, sizeof(*srr));
if (!fp)
goto retry;
@@ -1556,15 +1625,14 @@ static void fc_fcp_srr(struct fc_fcp_pkt *fsp, enum fc_rctl r_ctl, u32 offset)
srr->srr_rel_off = htonl(offset);
fc_fill_fc_hdr(fp, FC_RCTL_ELS4_REQ, rport->port_id,
- fc_host_port_id(rp->local_port->host), FC_TYPE_FCP,
+ fc_host_port_id(rpriv->local_port->host), FC_TYPE_FCP,
FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
- seq = lp->tt.exch_seq_send(lp, fp, fc_fcp_srr_resp, NULL,
- fsp, jiffies_to_msecs(FC_SCSI_REC_TOV));
- if (!seq) {
- fc_frame_free(fp);
+ seq = lport->tt.exch_seq_send(lport, fp, fc_fcp_srr_resp, NULL,
+ fsp, jiffies_to_msecs(FC_SCSI_REC_TOV));
+ if (!seq)
goto retry;
- }
+
fsp->recov_seq = seq;
fsp->xfer_len = offset;
fsp->xfer_contig_end = offset;
@@ -1575,8 +1643,11 @@ retry:
fc_fcp_retry_cmd(fsp);
}
-/*
- * Handle response from SRR.
+/**
+ * fc_fcp_srr_resp() - Handler for SRR response
+ * @seq: The sequence the SRR is on
+ * @fp: The SRR frame
+ * @arg: The FCP packet the SRR is on
*/
static void fc_fcp_srr_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg)
{
@@ -1622,6 +1693,11 @@ out:
fc_fcp_pkt_release(fsp); /* drop hold for outstanding SRR */
}
+/**
+ * fc_fcp_srr_error() - Handler for SRR errors
+ * @fsp: The FCP packet that the SRR error is on
+ * @fp: The SRR frame
+ */
static void fc_fcp_srr_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
{
if (fc_fcp_lock_pkt(fsp))
@@ -1646,31 +1722,36 @@ out:
fc_fcp_pkt_release(fsp); /* drop hold for outstanding SRR */
}
-static inline int fc_fcp_lport_queue_ready(struct fc_lport *lp)
+/**
+ * fc_fcp_lport_queue_ready() - Determine if the lport and it's queue is ready
+ * @lport: The local port to be checked
+ */
+static inline int fc_fcp_lport_queue_ready(struct fc_lport *lport)
{
/* lock ? */
- return (lp->state == LPORT_ST_READY) && lp->link_up && !lp->qfull;
+ return (lport->state == LPORT_ST_READY) &&
+ lport->link_up && !lport->qfull;
}
/**
- * fc_queuecommand - The queuecommand function of the scsi template
- * @cmd: struct scsi_cmnd to be executed
- * @done: Callback function to be called when cmd is completed
+ * fc_queuecommand() - The queuecommand function of the SCSI template
+ * @cmd: The scsi_cmnd to be executed
+ * @done: The callback function to be called when the scsi_cmnd is complete
*
- * this is the i/o strategy routine, called by the scsi layer
- * this routine is called with holding the host_lock.
+ * This is the i/o strategy routine, called by the SCSI layer. This routine
+ * is called with the host_lock held.
*/
int fc_queuecommand(struct scsi_cmnd *sc_cmd, void (*done)(struct scsi_cmnd *))
{
- struct fc_lport *lp;
+ struct fc_lport *lport;
struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device));
struct fc_fcp_pkt *fsp;
- struct fc_rport_libfc_priv *rp;
+ struct fc_rport_libfc_priv *rpriv;
int rval;
int rc = 0;
struct fcoe_dev_stats *stats;
- lp = shost_priv(sc_cmd->device->host);
+ lport = shost_priv(sc_cmd->device->host);
rval = fc_remote_port_chkready(rport);
if (rval) {
@@ -1689,14 +1770,16 @@ int fc_queuecommand(struct scsi_cmnd *sc_cmd, void (*done)(struct scsi_cmnd *))
goto out;
}
- rp = rport->dd_data;
+ rpriv = rport->dd_data;
- if (!fc_fcp_lport_queue_ready(lp)) {
+ if (!fc_fcp_lport_queue_ready(lport)) {
+ if (lport->qfull)
+ fc_fcp_can_queue_ramp_down(lport);
rc = SCSI_MLQUEUE_HOST_BUSY;
goto out;
}
- fsp = fc_fcp_pkt_alloc(lp, GFP_ATOMIC);
+ fsp = fc_fcp_pkt_alloc(lport, GFP_ATOMIC);
if (fsp == NULL) {
rc = SCSI_MLQUEUE_HOST_BUSY;
goto out;
@@ -1706,8 +1789,9 @@ int fc_queuecommand(struct scsi_cmnd *sc_cmd, void (*done)(struct scsi_cmnd *))
* build the libfc request pkt
*/
fsp->cmd = sc_cmd; /* save the cmd */
- fsp->lp = lp; /* save the softc ptr */
+ fsp->lp = lport; /* save the softc ptr */
fsp->rport = rport; /* set the remote port ptr */
+ fsp->xfer_ddp = FC_XID_UNKNOWN;
sc_cmd->scsi_done = done;
/*
@@ -1719,7 +1803,7 @@ int fc_queuecommand(struct scsi_cmnd *sc_cmd, void (*done)(struct scsi_cmnd *))
/*
* setup the data direction
*/
- stats = fc_lport_get_stats(lp);
+ stats = fc_lport_get_stats(lport);
if (sc_cmd->sc_data_direction == DMA_FROM_DEVICE) {
fsp->req_flags = FC_SRB_READ;
stats->InputRequests++;
@@ -1733,7 +1817,7 @@ int fc_queuecommand(struct scsi_cmnd *sc_cmd, void (*done)(struct scsi_cmnd *))
stats->ControlRequests++;
}
- fsp->tgt_flags = rp->flags;
+ fsp->tgt_flags = rpriv->flags;
init_timer(&fsp->timer);
fsp->timer.data = (unsigned long)fsp;
@@ -1743,7 +1827,7 @@ int fc_queuecommand(struct scsi_cmnd *sc_cmd, void (*done)(struct scsi_cmnd *))
* if we get -1 return then put the request in the pending
* queue.
*/
- rval = fc_fcp_pkt_send(lp, fsp);
+ rval = fc_fcp_pkt_send(lport, fsp);
if (rval != 0) {
fsp->state = FC_SRB_FREE;
fc_fcp_pkt_release(fsp);
@@ -1755,18 +1839,17 @@ out:
EXPORT_SYMBOL(fc_queuecommand);
/**
- * fc_io_compl() - Handle responses for completed commands
- * @fsp: scsi packet
- *
- * Translates a error to a Linux SCSI error.
+ * fc_io_compl() - Handle responses for completed commands
+ * @fsp: The FCP packet that is complete
*
+ * Translates fcp_pkt errors to a Linux SCSI errors.
* The fcp packet lock must be held when calling.
*/
static void fc_io_compl(struct fc_fcp_pkt *fsp)
{
struct fc_fcp_internal *si;
struct scsi_cmnd *sc_cmd;
- struct fc_lport *lp;
+ struct fc_lport *lport;
unsigned long flags;
/* release outstanding ddp context */
@@ -1779,28 +1862,26 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
spin_lock_bh(&fsp->scsi_pkt_lock);
}
- lp = fsp->lp;
- si = fc_get_scsi_internal(lp);
- spin_lock_irqsave(lp->host->host_lock, flags);
+ lport = fsp->lp;
+ si = fc_get_scsi_internal(lport);
+ spin_lock_irqsave(lport->host->host_lock, flags);
if (!fsp->cmd) {
- spin_unlock_irqrestore(lp->host->host_lock, flags);
+ spin_unlock_irqrestore(lport->host->host_lock, flags);
return;
}
/*
- * if a command timed out while we had to try and throttle IO
- * and it is now getting cleaned up, then we are about to
- * try again so clear the throttled flag incase we get more
- * time outs.
+ * if can_queue ramp down is done then try can_queue ramp up
+ * since commands are completing now.
*/
- if (si->throttled && fsp->state & FC_SRB_NOMEM)
- si->throttled = 0;
+ if (si->last_can_queue_ramp_down_time)
+ fc_fcp_can_queue_ramp_up(lport);
sc_cmd = fsp->cmd;
fsp->cmd = NULL;
if (!sc_cmd->SCp.ptr) {
- spin_unlock_irqrestore(lp->host->host_lock, flags);
+ spin_unlock_irqrestore(lport->host->host_lock, flags);
return;
}
@@ -1814,21 +1895,6 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
sc_cmd->result = DID_OK << 16;
if (fsp->scsi_resid)
CMD_RESID_LEN(sc_cmd) = fsp->scsi_resid;
- } else if (fsp->cdb_status == QUEUE_FULL) {
- struct scsi_device *tmp_sdev;
- struct scsi_device *sdev = sc_cmd->device;
-
- shost_for_each_device(tmp_sdev, sdev->host) {
- if (tmp_sdev->id != sdev->id)
- continue;
-
- if (tmp_sdev->queue_depth > 1) {
- scsi_track_queue_full(tmp_sdev,
- tmp_sdev->
- queue_depth - 1);
- }
- }
- sc_cmd->result = (DID_OK << 16) | fsp->cdb_status;
} else {
/*
* transport level I/O was ok but scsi
@@ -1846,7 +1912,8 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
* scsi status is good but transport level
* underrun.
*/
- sc_cmd->result = DID_OK << 16;
+ sc_cmd->result = (fsp->state & FC_SRB_RCV_STATUS ?
+ DID_OK : DID_ERROR) << 16;
} else {
/*
* scsi got underrun, this is an error
@@ -1881,60 +1948,42 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
list_del(&fsp->list);
sc_cmd->SCp.ptr = NULL;
sc_cmd->scsi_done(sc_cmd);
- spin_unlock_irqrestore(lp->host->host_lock, flags);
+ spin_unlock_irqrestore(lport->host->host_lock, flags);
/* release ref from initial allocation in queue command */
fc_fcp_pkt_release(fsp);
}
/**
- * fc_fcp_complete() - complete processing of a fcp packet
- * @fsp: fcp packet
- *
- * This function may sleep if a fsp timer is pending.
- * The host lock must not be held by caller.
- */
-void fc_fcp_complete(struct fc_fcp_pkt *fsp)
-{
- if (fc_fcp_lock_pkt(fsp))
- return;
-
- fc_fcp_complete_locked(fsp);
- fc_fcp_unlock_pkt(fsp);
-}
-EXPORT_SYMBOL(fc_fcp_complete);
-
-/**
* fc_eh_abort() - Abort a command
- * @sc_cmd: scsi command to abort
+ * @sc_cmd: The SCSI command to abort
*
- * From scsi host template.
- * send ABTS to the target device and wait for the response
- * sc_cmd is the pointer to the command to be aborted.
+ * From SCSI host template.
+ * Send an ABTS to the target device and wait for the response.
*/
int fc_eh_abort(struct scsi_cmnd *sc_cmd)
{
struct fc_fcp_pkt *fsp;
- struct fc_lport *lp;
+ struct fc_lport *lport;
int rc = FAILED;
unsigned long flags;
- lp = shost_priv(sc_cmd->device->host);
- if (lp->state != LPORT_ST_READY)
+ lport = shost_priv(sc_cmd->device->host);
+ if (lport->state != LPORT_ST_READY)
return rc;
- else if (!lp->link_up)
+ else if (!lport->link_up)
return rc;
- spin_lock_irqsave(lp->host->host_lock, flags);
+ spin_lock_irqsave(lport->host->host_lock, flags);
fsp = CMD_SP(sc_cmd);
if (!fsp) {
/* command completed while scsi eh was setting up */
- spin_unlock_irqrestore(lp->host->host_lock, flags);
+ spin_unlock_irqrestore(lport->host->host_lock, flags);
return SUCCESS;
}
/* grab a ref so the fsp and sc_cmd cannot be relased from under us */
fc_fcp_pkt_hold(fsp);
- spin_unlock_irqrestore(lp->host->host_lock, flags);
+ spin_unlock_irqrestore(lport->host->host_lock, flags);
if (fc_fcp_lock_pkt(fsp)) {
/* completed while we were waiting for timer to be deleted */
@@ -1942,7 +1991,7 @@ int fc_eh_abort(struct scsi_cmnd *sc_cmd)
goto release_pkt;
}
- rc = fc_fcp_pkt_abort(lp, fsp);
+ rc = fc_fcp_pkt_abort(fsp);
fc_fcp_unlock_pkt(fsp);
release_pkt:
@@ -1952,37 +2001,34 @@ release_pkt:
EXPORT_SYMBOL(fc_eh_abort);
/**
- * fc_eh_device_reset() Reset a single LUN
- * @sc_cmd: scsi command
+ * fc_eh_device_reset() - Reset a single LUN
+ * @sc_cmd: The SCSI command which identifies the device whose
+ * LUN is to be reset
*
- * Set from scsi host template to send tm cmd to the target and wait for the
- * response.
+ * Set from SCSI host template.
*/
int fc_eh_device_reset(struct scsi_cmnd *sc_cmd)
{
- struct fc_lport *lp;
+ struct fc_lport *lport;
struct fc_fcp_pkt *fsp;
struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device));
int rc = FAILED;
- struct fc_rport_libfc_priv *rp;
int rval;
rval = fc_remote_port_chkready(rport);
if (rval)
goto out;
- rp = rport->dd_data;
- lp = shost_priv(sc_cmd->device->host);
+ lport = shost_priv(sc_cmd->device->host);
- if (lp->state != LPORT_ST_READY)
+ if (lport->state != LPORT_ST_READY)
return rc;
- FC_SCSI_DBG(lp, "Resetting rport (%6x)\n", rport->port_id);
+ FC_SCSI_DBG(lport, "Resetting rport (%6x)\n", rport->port_id);
- fsp = fc_fcp_pkt_alloc(lp, GFP_NOIO);
+ fsp = fc_fcp_pkt_alloc(lport, GFP_NOIO);
if (fsp == NULL) {
printk(KERN_WARNING "libfc: could not allocate scsi_pkt\n");
- sc_cmd->result = DID_NO_CONNECT << 16;
goto out;
}
@@ -1991,13 +2037,13 @@ int fc_eh_device_reset(struct scsi_cmnd *sc_cmd)
* the sc passed in is not setup for execution like when sent
* through the queuecommand callout.
*/
- fsp->lp = lp; /* save the softc ptr */
+ fsp->lp = lport; /* save the softc ptr */
fsp->rport = rport; /* set the remote port ptr */
/*
* flush outstanding commands
*/
- rc = fc_lun_reset(lp, fsp, scmd_id(sc_cmd), sc_cmd->device->lun);
+ rc = fc_lun_reset(lport, fsp, scmd_id(sc_cmd), sc_cmd->device->lun);
fsp->state = FC_SRB_FREE;
fc_fcp_pkt_release(fsp);
@@ -2007,38 +2053,39 @@ out:
EXPORT_SYMBOL(fc_eh_device_reset);
/**
- * fc_eh_host_reset() - The reset function will reset the ports on the host.
- * @sc_cmd: scsi command
+ * fc_eh_host_reset() - Reset a Scsi_Host.
+ * @sc_cmd: The SCSI command that identifies the SCSI host to be reset
*/
int fc_eh_host_reset(struct scsi_cmnd *sc_cmd)
{
struct Scsi_Host *shost = sc_cmd->device->host;
- struct fc_lport *lp = shost_priv(shost);
+ struct fc_lport *lport = shost_priv(shost);
unsigned long wait_tmo;
- FC_SCSI_DBG(lp, "Resetting host\n");
+ FC_SCSI_DBG(lport, "Resetting host\n");
- lp->tt.lport_reset(lp);
+ lport->tt.lport_reset(lport);
wait_tmo = jiffies + FC_HOST_RESET_TIMEOUT;
- while (!fc_fcp_lport_queue_ready(lp) && time_before(jiffies, wait_tmo))
+ while (!fc_fcp_lport_queue_ready(lport) && time_before(jiffies,
+ wait_tmo))
msleep(1000);
- if (fc_fcp_lport_queue_ready(lp)) {
+ if (fc_fcp_lport_queue_ready(lport)) {
shost_printk(KERN_INFO, shost, "libfc: Host reset succeeded "
- "on port (%6x)\n", fc_host_port_id(lp->host));
+ "on port (%6x)\n", fc_host_port_id(lport->host));
return SUCCESS;
} else {
shost_printk(KERN_INFO, shost, "libfc: Host reset failed, "
"port (%6x) is not ready.\n",
- fc_host_port_id(lp->host));
+ fc_host_port_id(lport->host));
return FAILED;
}
}
EXPORT_SYMBOL(fc_eh_host_reset);
/**
- * fc_slave_alloc() - configure queue depth
- * @sdev: scsi device
+ * fc_slave_alloc() - Configure the queue depth of a Scsi_Host
+ * @sdev: The SCSI device that identifies the SCSI host
*
* Configures queue depth based on host's cmd_per_len. If not set
* then we use the libfc default.
@@ -2046,29 +2093,50 @@ EXPORT_SYMBOL(fc_eh_host_reset);
int fc_slave_alloc(struct scsi_device *sdev)
{
struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
- int queue_depth;
if (!rport || fc_remote_port_chkready(rport))
return -ENXIO;
- if (sdev->tagged_supported) {
- if (sdev->host->hostt->cmd_per_lun)
- queue_depth = sdev->host->hostt->cmd_per_lun;
- else
- queue_depth = FC_FCP_DFLT_QUEUE_DEPTH;
- scsi_activate_tcq(sdev, queue_depth);
- }
+ if (sdev->tagged_supported)
+ scsi_activate_tcq(sdev, FC_FCP_DFLT_QUEUE_DEPTH);
+ else
+ scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev),
+ FC_FCP_DFLT_QUEUE_DEPTH);
+
return 0;
}
EXPORT_SYMBOL(fc_slave_alloc);
-int fc_change_queue_depth(struct scsi_device *sdev, int qdepth)
+/**
+ * fc_change_queue_depth() - Change a device's queue depth
+ * @sdev: The SCSI device whose queue depth is to change
+ * @qdepth: The new queue depth
+ * @reason: The resason for the change
+ */
+int fc_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
{
- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
+ switch (reason) {
+ case SCSI_QDEPTH_DEFAULT:
+ scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
+ break;
+ case SCSI_QDEPTH_QFULL:
+ scsi_track_queue_full(sdev, qdepth);
+ break;
+ case SCSI_QDEPTH_RAMP_UP:
+ scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
return sdev->queue_depth;
}
EXPORT_SYMBOL(fc_change_queue_depth);
+/**
+ * fc_change_queue_type() - Change a device's queue type
+ * @sdev: The SCSI device whose queue depth is to change
+ * @tag_type: Identifier for queue type
+ */
int fc_change_queue_type(struct scsi_device *sdev, int tag_type)
{
if (sdev->tagged_supported) {
@@ -2084,38 +2152,69 @@ int fc_change_queue_type(struct scsi_device *sdev, int tag_type)
}
EXPORT_SYMBOL(fc_change_queue_type);
-void fc_fcp_destroy(struct fc_lport *lp)
+/**
+ * fc_fcp_destory() - Tear down the FCP layer for a given local port
+ * @lport: The local port that no longer needs the FCP layer
+ */
+void fc_fcp_destroy(struct fc_lport *lport)
{
- struct fc_fcp_internal *si = fc_get_scsi_internal(lp);
+ struct fc_fcp_internal *si = fc_get_scsi_internal(lport);
if (!list_empty(&si->scsi_pkt_queue))
printk(KERN_ERR "libfc: Leaked SCSI packets when destroying "
- "port (%6x)\n", fc_host_port_id(lp->host));
+ "port (%6x)\n", fc_host_port_id(lport->host));
mempool_destroy(si->scsi_pkt_pool);
kfree(si);
- lp->scsi_priv = NULL;
+ lport->scsi_priv = NULL;
}
EXPORT_SYMBOL(fc_fcp_destroy);
-int fc_fcp_init(struct fc_lport *lp)
+int fc_setup_fcp()
+{
+ int rc = 0;
+
+ scsi_pkt_cachep = kmem_cache_create("libfc_fcp_pkt",
+ sizeof(struct fc_fcp_pkt),
+ 0, SLAB_HWCACHE_ALIGN, NULL);
+ if (!scsi_pkt_cachep) {
+ printk(KERN_ERR "libfc: Unable to allocate SRB cache, "
+ "module load failed!");
+ rc = -ENOMEM;
+ }
+
+ return rc;
+}
+
+void fc_destroy_fcp()
+{
+ if (scsi_pkt_cachep)
+ kmem_cache_destroy(scsi_pkt_cachep);
+}
+
+/**
+ * fc_fcp_init() - Initialize the FCP layer for a local port
+ * @lport: The local port to initialize the exchange layer for
+ */
+int fc_fcp_init(struct fc_lport *lport)
{
int rc;
struct fc_fcp_internal *si;
- if (!lp->tt.fcp_cmd_send)
- lp->tt.fcp_cmd_send = fc_fcp_cmd_send;
+ if (!lport->tt.fcp_cmd_send)
+ lport->tt.fcp_cmd_send = fc_fcp_cmd_send;
- if (!lp->tt.fcp_cleanup)
- lp->tt.fcp_cleanup = fc_fcp_cleanup;
+ if (!lport->tt.fcp_cleanup)
+ lport->tt.fcp_cleanup = fc_fcp_cleanup;
- if (!lp->tt.fcp_abort_io)
- lp->tt.fcp_abort_io = fc_fcp_abort_io;
+ if (!lport->tt.fcp_abort_io)
+ lport->tt.fcp_abort_io = fc_fcp_abort_io;
si = kzalloc(sizeof(struct fc_fcp_internal), GFP_KERNEL);
if (!si)
return -ENOMEM;
- lp->scsi_priv = si;
+ lport->scsi_priv = si;
+ si->max_can_queue = lport->host->can_queue;
INIT_LIST_HEAD(&si->scsi_pkt_queue);
si->scsi_pkt_pool = mempool_create_slab_pool(2, scsi_pkt_cachep);
@@ -2130,42 +2229,3 @@ free_internal:
return rc;
}
EXPORT_SYMBOL(fc_fcp_init);
-
-static int __init libfc_init(void)
-{
- int rc;
-
- scsi_pkt_cachep = kmem_cache_create("libfc_fcp_pkt",
- sizeof(struct fc_fcp_pkt),
- 0, SLAB_HWCACHE_ALIGN, NULL);
- if (scsi_pkt_cachep == NULL) {
- printk(KERN_ERR "libfc: Unable to allocate SRB cache, "
- "module load failed!");
- return -ENOMEM;
- }
-
- rc = fc_setup_exch_mgr();
- if (rc)
- goto destroy_pkt_cache;
-
- rc = fc_setup_rport();
- if (rc)
- goto destroy_em;
-
- return rc;
-destroy_em:
- fc_destroy_exch_mgr();
-destroy_pkt_cache:
- kmem_cache_destroy(scsi_pkt_cachep);
- return rc;
-}
-
-static void __exit libfc_exit(void)
-{
- kmem_cache_destroy(scsi_pkt_cachep);
- fc_destroy_exch_mgr();
- fc_destroy_rport();
-}
-
-module_init(libfc_init);
-module_exit(libfc_exit);
diff --git a/drivers/scsi/libfc/fc_frame.c b/drivers/scsi/libfc/fc_frame.c
index 63fe00c..6da01c6 100644
--- a/drivers/scsi/libfc/fc_frame.c
+++ b/drivers/scsi/libfc/fc_frame.c
@@ -51,24 +51,24 @@ EXPORT_SYMBOL(fc_frame_crc_check);
* Allocate a frame intended to be sent via fcoe_xmit.
* Get an sk_buff for the frame and set the length.
*/
-struct fc_frame *__fc_frame_alloc(size_t len)
+struct fc_frame *_fc_frame_alloc(size_t len)
{
struct fc_frame *fp;
struct sk_buff *skb;
WARN_ON((len % sizeof(u32)) != 0);
len += sizeof(struct fc_frame_header);
- skb = dev_alloc_skb(len + FC_FRAME_HEADROOM + FC_FRAME_TAILROOM);
+ skb = alloc_skb_fclone(len + FC_FRAME_HEADROOM + FC_FRAME_TAILROOM +
+ NET_SKB_PAD, GFP_ATOMIC);
if (!skb)
return NULL;
+ skb_reserve(skb, NET_SKB_PAD + FC_FRAME_HEADROOM);
fp = (struct fc_frame *) skb;
fc_frame_init(fp);
- skb_reserve(skb, FC_FRAME_HEADROOM);
skb_put(skb, len);
return fp;
}
-EXPORT_SYMBOL(__fc_frame_alloc);
-
+EXPORT_SYMBOL(_fc_frame_alloc);
struct fc_frame *fc_frame_alloc_fill(struct fc_lport *lp, size_t payload_len)
{
@@ -78,7 +78,7 @@ struct fc_frame *fc_frame_alloc_fill(struct fc_lport *lp, size_t payload_len)
fill = payload_len % 4;
if (fill != 0)
fill = 4 - fill;
- fp = __fc_frame_alloc(payload_len + fill);
+ fp = _fc_frame_alloc(payload_len + fill);
if (fp) {
memset((char *) fr_hdr(fp) + payload_len, 0, fill);
/* trim is OK, we just allocated it so there are no fragments */
@@ -87,3 +87,4 @@ struct fc_frame *fc_frame_alloc_fill(struct fc_lport *lp, size_t payload_len)
}
return fp;
}
+EXPORT_SYMBOL(fc_frame_alloc_fill);
diff --git a/drivers/scsi/libfc/fc_libfc.c b/drivers/scsi/libfc/fc_libfc.c
new file mode 100644
index 0000000..39f4b6a
--- /dev/null
+++ b/drivers/scsi/libfc/fc_libfc.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright(c) 2009 Intel Corporation. All rights reserved.
+ *
+ * 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Maintained at www.Open-FCoE.org
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/scatterlist.h>
+#include <linux/crc32.h>
+
+#include <scsi/libfc.h>
+
+#include "fc_libfc.h"
+
+MODULE_AUTHOR("Open-FCoE.org");
+MODULE_DESCRIPTION("libfc");
+MODULE_LICENSE("GPL v2");
+
+unsigned int fc_debug_logging;
+module_param_named(debug_logging, fc_debug_logging, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels");
+
+/**
+ * libfc_init() - Initialize libfc.ko
+ */
+static int __init libfc_init(void)
+{
+ int rc = 0;
+
+ rc = fc_setup_fcp();
+ if (rc)
+ return rc;
+
+ rc = fc_setup_exch_mgr();
+ if (rc)
+ goto destroy_pkt_cache;
+
+ rc = fc_setup_rport();
+ if (rc)
+ goto destroy_em;
+
+ return rc;
+destroy_em:
+ fc_destroy_exch_mgr();
+destroy_pkt_cache:
+ fc_destroy_fcp();
+ return rc;
+}
+module_init(libfc_init);
+
+/**
+ * libfc_exit() - Tear down libfc.ko
+ */
+static void __exit libfc_exit(void)
+{
+ fc_destroy_fcp();
+ fc_destroy_exch_mgr();
+ fc_destroy_rport();
+}
+module_exit(libfc_exit);
+
+/**
+ * fc_copy_buffer_to_sglist() - This routine copies the data of a buffer
+ * into a scatter-gather list (SG list).
+ *
+ * @buf: pointer to the data buffer.
+ * @len: the byte-length of the data buffer.
+ * @sg: pointer to the pointer of the SG list.
+ * @nents: pointer to the remaining number of entries in the SG list.
+ * @offset: pointer to the current offset in the SG list.
+ * @km_type: dedicated page table slot type for kmap_atomic.
+ * @crc: pointer to the 32-bit crc value.
+ * If crc is NULL, CRC is not calculated.
+ */
+u32 fc_copy_buffer_to_sglist(void *buf, size_t len,
+ struct scatterlist *sg,
+ u32 *nents, size_t *offset,
+ enum km_type km_type, u32 *crc)
+{
+ size_t remaining = len;
+ u32 copy_len = 0;
+
+ while (remaining > 0 && sg) {
+ size_t off, sg_bytes;
+ void *page_addr;
+
+ if (*offset >= sg->length) {
+ /*
+ * Check for end and drop resources
+ * from the last iteration.
+ */
+ if (!(*nents))
+ break;
+ --(*nents);
+ *offset -= sg->length;
+ sg = sg_next(sg);
+ continue;
+ }
+ sg_bytes = min(remaining, sg->length - *offset);
+
+ /*
+ * The scatterlist item may be bigger than PAGE_SIZE,
+ * but we are limited to mapping PAGE_SIZE at a time.
+ */
+ off = *offset + sg->offset;
+ sg_bytes = min(sg_bytes,
+ (size_t)(PAGE_SIZE - (off & ~PAGE_MASK)));
+ page_addr = kmap_atomic(sg_page(sg) + (off >> PAGE_SHIFT),
+ km_type);
+ if (crc)
+ *crc = crc32(*crc, buf, sg_bytes);
+ memcpy((char *)page_addr + (off & ~PAGE_MASK), buf, sg_bytes);
+ kunmap_atomic(page_addr, km_type);
+ buf += sg_bytes;
+ *offset += sg_bytes;
+ remaining -= sg_bytes;
+ copy_len += sg_bytes;
+ }
+ return copy_len;
+}
diff --git a/drivers/scsi/libfc/fc_libfc.h b/drivers/scsi/libfc/fc_libfc.h
new file mode 100644
index 0000000..741fd5c
--- /dev/null
+++ b/drivers/scsi/libfc/fc_libfc.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright(c) 2009 Intel Corporation. All rights reserved.
+ *
+ * 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Maintained at www.Open-FCoE.org
+ */
+
+#ifndef _FC_LIBFC_H_
+#define _FC_LIBFC_H_
+
+#define FC_LIBFC_LOGGING 0x01 /* General logging, not categorized */
+#define FC_LPORT_LOGGING 0x02 /* lport layer logging */
+#define FC_DISC_LOGGING 0x04 /* discovery layer logging */
+#define FC_RPORT_LOGGING 0x08 /* rport layer logging */
+#define FC_FCP_LOGGING 0x10 /* I/O path logging */
+#define FC_EM_LOGGING 0x20 /* Exchange Manager logging */
+#define FC_EXCH_LOGGING 0x40 /* Exchange/Sequence logging */
+#define FC_SCSI_LOGGING 0x80 /* SCSI logging (mostly error handling) */
+
+extern unsigned int fc_debug_logging;
+
+#define FC_CHECK_LOGGING(LEVEL, CMD) \
+ do { \
+ if (unlikely(fc_debug_logging & LEVEL)) \
+ do { \
+ CMD; \
+ } while (0); \
+ } while (0)
+
+#define FC_LIBFC_DBG(fmt, args...) \
+ FC_CHECK_LOGGING(FC_LIBFC_LOGGING, \
+ printk(KERN_INFO "libfc: " fmt, ##args))
+
+#define FC_LPORT_DBG(lport, fmt, args...) \
+ FC_CHECK_LOGGING(FC_LPORT_LOGGING, \
+ printk(KERN_INFO "host%u: lport %6x: " fmt, \
+ (lport)->host->host_no, \
+ fc_host_port_id((lport)->host), ##args))
+
+#define FC_DISC_DBG(disc, fmt, args...) \
+ FC_CHECK_LOGGING(FC_DISC_LOGGING, \
+ printk(KERN_INFO "host%u: disc: " fmt, \
+ (disc)->lport->host->host_no, \
+ ##args))
+
+#define FC_RPORT_ID_DBG(lport, port_id, fmt, args...) \
+ FC_CHECK_LOGGING(FC_RPORT_LOGGING, \
+ printk(KERN_INFO "host%u: rport %6x: " fmt, \
+ (lport)->host->host_no, \
+ (port_id), ##args))
+
+#define FC_RPORT_DBG(rdata, fmt, args...) \
+ FC_RPORT_ID_DBG((rdata)->local_port, (rdata)->ids.port_id, fmt, ##args)
+
+#define FC_FCP_DBG(pkt, fmt, args...) \
+ FC_CHECK_LOGGING(FC_FCP_LOGGING, \
+ printk(KERN_INFO "host%u: fcp: %6x: " fmt, \
+ (pkt)->lp->host->host_no, \
+ pkt->rport->port_id, ##args))
+
+#define FC_EXCH_DBG(exch, fmt, args...) \
+ FC_CHECK_LOGGING(FC_EXCH_LOGGING, \
+ printk(KERN_INFO "host%u: xid %4x: " fmt, \
+ (exch)->lp->host->host_no, \
+ exch->xid, ##args))
+
+#define FC_SCSI_DBG(lport, fmt, args...) \
+ FC_CHECK_LOGGING(FC_SCSI_LOGGING, \
+ printk(KERN_INFO "host%u: scsi: " fmt, \
+ (lport)->host->host_no, ##args))
+
+/*
+ * Set up direct-data placement for this I/O request
+ */
+void fc_fcp_ddp_setup(struct fc_fcp_pkt *fsp, u16 xid);
+
+/*
+ * Module setup functions
+ */
+int fc_setup_exch_mgr(void);
+void fc_destroy_exch_mgr(void);
+int fc_setup_rport(void);
+void fc_destroy_rport(void);
+int fc_setup_fcp(void);
+void fc_destroy_fcp(void);
+
+/*
+ * Internal libfc functions
+ */
+const char *fc_els_resp_type(struct fc_frame *);
+
+/*
+ * Copies a buffer into an sg list
+ */
+u32 fc_copy_buffer_to_sglist(void *buf, size_t len,
+ struct scatterlist *sg,
+ u32 *nents, size_t *offset,
+ enum km_type km_type, u32 *crc);
+
+#endif /* _FC_LIBFC_H_ */
diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c
index bd2f771..74338c8 100644
--- a/drivers/scsi/libfc/fc_lport.c
+++ b/drivers/scsi/libfc/fc_lport.c
@@ -56,7 +56,7 @@
* at the same time.
*
* When discovery succeeds or fails a callback is made to the lport as
- * notification. Currently, succesful discovery causes the lport to take no
+ * notification. Currently, successful discovery causes the lport to take no
* action. A failure will cause the lport to reset. There is likely a circular
* locking problem with this implementation.
*/
@@ -94,6 +94,9 @@
#include <scsi/libfc.h>
#include <scsi/fc_encode.h>
+#include <linux/scatterlist.h>
+
+#include "fc_libfc.h"
/* Fabric IDs to use for point-to-point mode, chosen on whims. */
#define FC_LOCAL_PTP_FID_LO 0x010101
@@ -106,8 +109,7 @@ static void fc_lport_error(struct fc_lport *, struct fc_frame *);
static void fc_lport_enter_reset(struct fc_lport *);
static void fc_lport_enter_flogi(struct fc_lport *);
static void fc_lport_enter_dns(struct fc_lport *);
-static void fc_lport_enter_rpn_id(struct fc_lport *);
-static void fc_lport_enter_rft_id(struct fc_lport *);
+static void fc_lport_enter_ns(struct fc_lport *, enum fc_lport_state);
static void fc_lport_enter_scr(struct fc_lport *);
static void fc_lport_enter_ready(struct fc_lport *);
static void fc_lport_enter_logo(struct fc_lport *);
@@ -116,14 +118,40 @@ static const char *fc_lport_state_names[] = {
[LPORT_ST_DISABLED] = "disabled",
[LPORT_ST_FLOGI] = "FLOGI",
[LPORT_ST_DNS] = "dNS",
- [LPORT_ST_RPN_ID] = "RPN_ID",
+ [LPORT_ST_RNN_ID] = "RNN_ID",
+ [LPORT_ST_RSNN_NN] = "RSNN_NN",
+ [LPORT_ST_RSPN_ID] = "RSPN_ID",
[LPORT_ST_RFT_ID] = "RFT_ID",
+ [LPORT_ST_RFF_ID] = "RFF_ID",
[LPORT_ST_SCR] = "SCR",
[LPORT_ST_READY] = "Ready",
[LPORT_ST_LOGO] = "LOGO",
[LPORT_ST_RESET] = "reset",
};
+/**
+ * struct fc_bsg_info - FC Passthrough managemet structure
+ * @job: The passthrough job
+ * @lport: The local port to pass through a command
+ * @rsp_code: The expected response code
+ * @sg: job->reply_payload.sg_list
+ * @nents: job->reply_payload.sg_cnt
+ * @offset: The offset into the response data
+ */
+struct fc_bsg_info {
+ struct fc_bsg_job *job;
+ struct fc_lport *lport;
+ u16 rsp_code;
+ struct scatterlist *sg;
+ u32 nents;
+ size_t offset;
+};
+
+/**
+ * fc_frame_drop() - Dummy frame handler
+ * @lport: The local port the frame was received on
+ * @fp: The received frame
+ */
static int fc_frame_drop(struct fc_lport *lport, struct fc_frame *fp)
{
fc_frame_free(fp);
@@ -150,8 +178,8 @@ static void fc_lport_rport_callback(struct fc_lport *lport,
switch (event) {
case RPORT_EV_READY:
if (lport->state == LPORT_ST_DNS) {
- lport->dns_rp = rdata;
- fc_lport_enter_rpn_id(lport);
+ lport->dns_rdata = rdata;
+ fc_lport_enter_ns(lport, LPORT_ST_RNN_ID);
} else {
FC_LPORT_DBG(lport, "Received an READY event "
"on port (%6x) for the directory "
@@ -165,7 +193,7 @@ static void fc_lport_rport_callback(struct fc_lport *lport,
case RPORT_EV_LOGO:
case RPORT_EV_FAILED:
case RPORT_EV_STOP:
- lport->dns_rp = NULL;
+ lport->dns_rdata = NULL;
break;
case RPORT_EV_NONE:
break;
@@ -189,8 +217,8 @@ static const char *fc_lport_state(struct fc_lport *lport)
/**
* fc_lport_ptp_setup() - Create an rport for point-to-point mode
- * @lport: The lport to attach the ptp rport to
- * @fid: The FID of the ptp rport
+ * @lport: The lport to attach the ptp rport to
+ * @remote_fid: The FID of the ptp rport
* @remote_wwpn: The WWPN of the ptp rport
* @remote_wwnn: The WWNN of the ptp rport
*/
@@ -199,18 +227,22 @@ static void fc_lport_ptp_setup(struct fc_lport *lport,
u64 remote_wwnn)
{
mutex_lock(&lport->disc.disc_mutex);
- if (lport->ptp_rp)
- lport->tt.rport_logoff(lport->ptp_rp);
- lport->ptp_rp = lport->tt.rport_create(lport, remote_fid);
- lport->ptp_rp->ids.port_name = remote_wwpn;
- lport->ptp_rp->ids.node_name = remote_wwnn;
+ if (lport->ptp_rdata)
+ lport->tt.rport_logoff(lport->ptp_rdata);
+ lport->ptp_rdata = lport->tt.rport_create(lport, remote_fid);
+ lport->ptp_rdata->ids.port_name = remote_wwpn;
+ lport->ptp_rdata->ids.node_name = remote_wwnn;
mutex_unlock(&lport->disc.disc_mutex);
- lport->tt.rport_login(lport->ptp_rp);
+ lport->tt.rport_login(lport->ptp_rdata);
fc_lport_enter_ready(lport);
}
+/**
+ * fc_get_host_port_type() - Return the port type of the given Scsi_Host
+ * @shost: The SCSI host whose port type is to be determined
+ */
void fc_get_host_port_type(struct Scsi_Host *shost)
{
/* TODO - currently just NPORT */
@@ -218,17 +250,33 @@ void fc_get_host_port_type(struct Scsi_Host *shost)
}
EXPORT_SYMBOL(fc_get_host_port_type);
+/**
+ * fc_get_host_port_state() - Return the port state of the given Scsi_Host
+ * @shost: The SCSI host whose port state is to be determined
+ */
void fc_get_host_port_state(struct Scsi_Host *shost)
{
- struct fc_lport *lp = shost_priv(shost);
+ struct fc_lport *lport = shost_priv(shost);
- if (lp->link_up)
- fc_host_port_state(shost) = FC_PORTSTATE_ONLINE;
+ mutex_lock(&lport->lp_mutex);
+ if (!lport->link_up)
+ fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN;
else
- fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE;
+ switch (lport->state) {
+ case LPORT_ST_READY:
+ fc_host_port_state(shost) = FC_PORTSTATE_ONLINE;
+ break;
+ default:
+ fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE;
+ }
+ mutex_unlock(&lport->lp_mutex);
}
EXPORT_SYMBOL(fc_get_host_port_state);
+/**
+ * fc_get_host_speed() - Return the speed of the given Scsi_Host
+ * @shost: The SCSI host whose port speed is to be determined
+ */
void fc_get_host_speed(struct Scsi_Host *shost)
{
struct fc_lport *lport = shost_priv(shost);
@@ -237,24 +285,28 @@ void fc_get_host_speed(struct Scsi_Host *shost)
}
EXPORT_SYMBOL(fc_get_host_speed);
+/**
+ * fc_get_host_stats() - Return the Scsi_Host's statistics
+ * @shost: The SCSI host whose statistics are to be returned
+ */
struct fc_host_statistics *fc_get_host_stats(struct Scsi_Host *shost)
{
struct fc_host_statistics *fcoe_stats;
- struct fc_lport *lp = shost_priv(shost);
+ struct fc_lport *lport = shost_priv(shost);
struct timespec v0, v1;
unsigned int cpu;
- fcoe_stats = &lp->host_stats;
+ fcoe_stats = &lport->host_stats;
memset(fcoe_stats, 0, sizeof(struct fc_host_statistics));
jiffies_to_timespec(jiffies, &v0);
- jiffies_to_timespec(lp->boot_time, &v1);
+ jiffies_to_timespec(lport->boot_time, &v1);
fcoe_stats->seconds_since_last_reset = (v0.tv_sec - v1.tv_sec);
for_each_possible_cpu(cpu) {
struct fcoe_dev_stats *stats;
- stats = per_cpu_ptr(lp->dev_stats, cpu);
+ stats = per_cpu_ptr(lport->dev_stats, cpu);
fcoe_stats->tx_frames += stats->TxFrames;
fcoe_stats->tx_words += stats->TxWords;
@@ -279,12 +331,15 @@ struct fc_host_statistics *fc_get_host_stats(struct Scsi_Host *shost)
}
EXPORT_SYMBOL(fc_get_host_stats);
-/*
- * Fill in FLOGI command for request.
+/**
+ * fc_lport_flogi_fill() - Fill in FLOGI command for request
+ * @lport: The local port the FLOGI is for
+ * @flogi: The FLOGI command
+ * @op: The opcode
*/
-static void
-fc_lport_flogi_fill(struct fc_lport *lport, struct fc_els_flogi *flogi,
- unsigned int op)
+static void fc_lport_flogi_fill(struct fc_lport *lport,
+ struct fc_els_flogi *flogi,
+ unsigned int op)
{
struct fc_els_csp *sp;
struct fc_els_cssp *cp;
@@ -312,8 +367,10 @@ fc_lport_flogi_fill(struct fc_lport *lport, struct fc_els_flogi *flogi,
}
}
-/*
- * Add a supported FC-4 type.
+/**
+ * fc_lport_add_fc4_type() - Add a supported FC-4 type to a local port
+ * @lport: The local port to add a new FC-4 type to
+ * @type: The new FC-4 type
*/
static void fc_lport_add_fc4_type(struct fc_lport *lport, enum fc_fh_type type)
{
@@ -325,11 +382,11 @@ static void fc_lport_add_fc4_type(struct fc_lport *lport, enum fc_fh_type type)
/**
* fc_lport_recv_rlir_req() - Handle received Registered Link Incident Report.
+ * @sp: The sequence in the RLIR exchange
+ * @fp: The RLIR request frame
* @lport: Fibre Channel local port recieving the RLIR
- * @sp: current sequence in the RLIR exchange
- * @fp: RLIR request frame
*
- * Locking Note: The lport lock is exected to be held before calling
+ * Locking Note: The lport lock is expected to be held before calling
* this function.
*/
static void fc_lport_recv_rlir_req(struct fc_seq *sp, struct fc_frame *fp,
@@ -344,11 +401,11 @@ static void fc_lport_recv_rlir_req(struct fc_seq *sp, struct fc_frame *fp,
/**
* fc_lport_recv_echo_req() - Handle received ECHO request
- * @lport: Fibre Channel local port recieving the ECHO
- * @sp: current sequence in the ECHO exchange
- * @fp: ECHO request frame
+ * @sp: The sequence in the ECHO exchange
+ * @fp: ECHO request frame
+ * @lport: The local port recieving the ECHO
*
- * Locking Note: The lport lock is exected to be held before calling
+ * Locking Note: The lport lock is expected to be held before calling
* this function.
*/
static void fc_lport_recv_echo_req(struct fc_seq *sp, struct fc_frame *in_fp,
@@ -361,7 +418,7 @@ static void fc_lport_recv_echo_req(struct fc_seq *sp, struct fc_frame *in_fp,
void *dp;
u32 f_ctl;
- FC_LPORT_DBG(lport, "Received RLIR request while in state %s\n",
+ FC_LPORT_DBG(lport, "Received ECHO request while in state %s\n",
fc_lport_state(lport));
len = fr_len(in_fp) - sizeof(struct fc_frame_header);
@@ -374,7 +431,7 @@ static void fc_lport_recv_echo_req(struct fc_seq *sp, struct fc_frame *in_fp,
if (fp) {
dp = fc_frame_payload_get(fp, len);
memcpy(dp, pp, len);
- *((u32 *)dp) = htonl(ELS_LS_ACC << 24);
+ *((__be32 *)dp) = htonl(ELS_LS_ACC << 24);
sp = lport->tt.seq_start_next(sp);
f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ;
fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
@@ -385,12 +442,12 @@ static void fc_lport_recv_echo_req(struct fc_seq *sp, struct fc_frame *in_fp,
}
/**
- * fc_lport_recv_echo_req() - Handle received Request Node ID data request
- * @lport: Fibre Channel local port recieving the RNID
- * @sp: current sequence in the RNID exchange
- * @fp: RNID request frame
+ * fc_lport_recv_rnid_req() - Handle received Request Node ID data request
+ * @sp: The sequence in the RNID exchange
+ * @fp: The RNID request frame
+ * @lport: The local port recieving the RNID
*
- * Locking Note: The lport lock is exected to be held before calling
+ * Locking Note: The lport lock is expected to be held before calling
* this function.
*/
static void fc_lport_recv_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp,
@@ -453,9 +510,9 @@ static void fc_lport_recv_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp,
/**
* fc_lport_recv_logo_req() - Handle received fabric LOGO request
- * @lport: Fibre Channel local port recieving the LOGO
- * @sp: current sequence in the LOGO exchange
- * @fp: LOGO request frame
+ * @sp: The sequence in the LOGO exchange
+ * @fp: The LOGO request frame
+ * @lport: The local port recieving the LOGO
*
* Locking Note: The lport lock is exected to be held before calling
* this function.
@@ -470,7 +527,7 @@ static void fc_lport_recv_logo_req(struct fc_seq *sp, struct fc_frame *fp,
/**
* fc_fabric_login() - Start the lport state machine
- * @lport: The lport that should log into the fabric
+ * @lport: The local port that should log into the fabric
*
* Locking Note: This function should not be called
* with the lport lock held.
@@ -491,47 +548,69 @@ int fc_fabric_login(struct fc_lport *lport)
EXPORT_SYMBOL(fc_fabric_login);
/**
- * fc_linkup() - Handler for transport linkup events
+ * __fc_linkup() - Handler for transport linkup events
* @lport: The lport whose link is up
+ *
+ * Locking: must be called with the lp_mutex held
*/
-void fc_linkup(struct fc_lport *lport)
+void __fc_linkup(struct fc_lport *lport)
{
- printk(KERN_INFO "libfc: Link up on port (%6x)\n",
- fc_host_port_id(lport->host));
-
- mutex_lock(&lport->lp_mutex);
if (!lport->link_up) {
lport->link_up = 1;
if (lport->state == LPORT_ST_RESET)
fc_lport_enter_flogi(lport);
}
+}
+
+/**
+ * fc_linkup() - Handler for transport linkup events
+ * @lport: The local port whose link is up
+ */
+void fc_linkup(struct fc_lport *lport)
+{
+ printk(KERN_INFO "host%d: libfc: Link up on port (%6x)\n",
+ lport->host->host_no, fc_host_port_id(lport->host));
+
+ mutex_lock(&lport->lp_mutex);
+ __fc_linkup(lport);
mutex_unlock(&lport->lp_mutex);
}
EXPORT_SYMBOL(fc_linkup);
/**
- * fc_linkdown() - Handler for transport linkdown events
+ * __fc_linkdown() - Handler for transport linkdown events
* @lport: The lport whose link is down
+ *
+ * Locking: must be called with the lp_mutex held
*/
-void fc_linkdown(struct fc_lport *lport)
+void __fc_linkdown(struct fc_lport *lport)
{
- mutex_lock(&lport->lp_mutex);
- printk(KERN_INFO "libfc: Link down on port (%6x)\n",
- fc_host_port_id(lport->host));
-
if (lport->link_up) {
lport->link_up = 0;
fc_lport_enter_reset(lport);
lport->tt.fcp_cleanup(lport);
}
+}
+
+/**
+ * fc_linkdown() - Handler for transport linkdown events
+ * @lport: The local port whose link is down
+ */
+void fc_linkdown(struct fc_lport *lport)
+{
+ printk(KERN_INFO "host%d: libfc: Link down on port (%6x)\n",
+ lport->host->host_no, fc_host_port_id(lport->host));
+
+ mutex_lock(&lport->lp_mutex);
+ __fc_linkdown(lport);
mutex_unlock(&lport->lp_mutex);
}
EXPORT_SYMBOL(fc_linkdown);
/**
* fc_fabric_logoff() - Logout of the fabric
- * @lport: fc_lport pointer to logoff the fabric
+ * @lport: The local port to logoff the fabric
*
* Return value:
* 0 for success, -1 for failure
@@ -540,8 +619,8 @@ int fc_fabric_logoff(struct fc_lport *lport)
{
lport->tt.disc_stop_final(lport);
mutex_lock(&lport->lp_mutex);
- if (lport->dns_rp)
- lport->tt.rport_logoff(lport->dns_rp);
+ if (lport->dns_rdata)
+ lport->tt.rport_logoff(lport->dns_rdata);
mutex_unlock(&lport->lp_mutex);
lport->tt.rport_flush_queue();
mutex_lock(&lport->lp_mutex);
@@ -553,11 +632,9 @@ int fc_fabric_logoff(struct fc_lport *lport)
EXPORT_SYMBOL(fc_fabric_logoff);
/**
- * fc_lport_destroy() - unregister a fc_lport
- * @lport: fc_lport pointer to unregister
+ * fc_lport_destroy() - Unregister a fc_lport
+ * @lport: The local port to unregister
*
- * Return value:
- * None
* Note:
* exit routine for fc_lport instance
* clean-up all the allocated memory
@@ -580,13 +657,9 @@ int fc_lport_destroy(struct fc_lport *lport)
EXPORT_SYMBOL(fc_lport_destroy);
/**
- * fc_set_mfs() - sets up the mfs for the corresponding fc_lport
- * @lport: fc_lport pointer to unregister
- * @mfs: the new mfs for fc_lport
- *
- * Set mfs for the given fc_lport to the new mfs.
- *
- * Return: 0 for success
+ * fc_set_mfs() - Set the maximum frame size for a local port
+ * @lport: The local port to set the MFS for
+ * @mfs: The new MFS
*/
int fc_set_mfs(struct fc_lport *lport, u32 mfs)
{
@@ -617,7 +690,7 @@ EXPORT_SYMBOL(fc_set_mfs);
/**
* fc_lport_disc_callback() - Callback for discovery events
- * @lport: FC local port
+ * @lport: The local port receiving the event
* @event: The discovery event
*/
void fc_lport_disc_callback(struct fc_lport *lport, enum fc_disc_event event)
@@ -627,8 +700,9 @@ void fc_lport_disc_callback(struct fc_lport *lport, enum fc_disc_event event)
FC_LPORT_DBG(lport, "Discovery succeeded\n");
break;
case DISC_EV_FAILED:
- printk(KERN_ERR "libfc: Discovery failed for port (%6x)\n",
- fc_host_port_id(lport->host));
+ printk(KERN_ERR "host%d: libfc: "
+ "Discovery failed for port (%6x)\n",
+ lport->host->host_no, fc_host_port_id(lport->host));
mutex_lock(&lport->lp_mutex);
fc_lport_enter_reset(lport);
mutex_unlock(&lport->lp_mutex);
@@ -641,7 +715,7 @@ void fc_lport_disc_callback(struct fc_lport *lport, enum fc_disc_event event)
/**
* fc_rport_enter_ready() - Enter the ready state and start discovery
- * @lport: Fibre Channel local port that is ready
+ * @lport: The local port that is ready
*
* Locking Note: The lport lock is expected to be held before calling
* this routine.
@@ -652,22 +726,46 @@ static void fc_lport_enter_ready(struct fc_lport *lport)
fc_lport_state(lport));
fc_lport_state_enter(lport, LPORT_ST_READY);
+ if (lport->vport)
+ fc_vport_set_state(lport->vport, FC_VPORT_ACTIVE);
+ fc_vports_linkchange(lport);
- if (!lport->ptp_rp)
+ if (!lport->ptp_rdata)
lport->tt.disc_start(fc_lport_disc_callback, lport);
}
/**
+ * fc_lport_set_port_id() - set the local port Port ID
+ * @lport: The local port which will have its Port ID set.
+ * @port_id: The new port ID.
+ * @fp: The frame containing the incoming request, or NULL.
+ *
+ * Locking Note: The lport lock is expected to be held before calling
+ * this function.
+ */
+static void fc_lport_set_port_id(struct fc_lport *lport, u32 port_id,
+ struct fc_frame *fp)
+{
+ if (port_id)
+ printk(KERN_INFO "host%d: Assigned Port ID %6x\n",
+ lport->host->host_no, port_id);
+
+ fc_host_port_id(lport->host) = port_id;
+ if (lport->tt.lport_set_port_id)
+ lport->tt.lport_set_port_id(lport, port_id, fp);
+}
+
+/**
* fc_lport_recv_flogi_req() - Receive a FLOGI request
* @sp_in: The sequence the FLOGI is on
- * @rx_fp: The frame the FLOGI is in
- * @lport: The lport that recieved the request
+ * @rx_fp: The FLOGI frame
+ * @lport: The local port that recieved the request
*
* A received FLOGI request indicates a point-to-point connection.
* Accept it with the common service parameters indicating our N port.
* Set up to do a PLOGI if we have the higher-number WWPN.
*
- * Locking Note: The lport lock is exected to be held before calling
+ * Locking Note: The lport lock is expected to be held before calling
* this function.
*/
static void fc_lport_recv_flogi_req(struct fc_seq *sp_in,
@@ -695,8 +793,9 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in,
goto out;
remote_wwpn = get_unaligned_be64(&flp->fl_wwpn);
if (remote_wwpn == lport->wwpn) {
- printk(KERN_WARNING "libfc: Received FLOGI from port "
- "with same WWPN %llx\n", remote_wwpn);
+ printk(KERN_WARNING "host%d: libfc: Received FLOGI from port "
+ "with same WWPN %llx\n",
+ lport->host->host_no, remote_wwpn);
goto out;
}
FC_LPORT_DBG(lport, "FLOGI from port WWPN %llx\n", remote_wwpn);
@@ -715,7 +814,7 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in,
remote_fid = FC_LOCAL_PTP_FID_HI;
}
- fc_host_port_id(lport->host) = local_fid;
+ fc_lport_set_port_id(lport, local_fid, rx_fp);
fp = fc_frame_alloc(lport, sizeof(*flp));
if (fp) {
@@ -747,9 +846,9 @@ out:
/**
* fc_lport_recv_req() - The generic lport request handler
- * @lport: The lport that received the request
- * @sp: The sequence the request is on
- * @fp: The frame the request is in
+ * @lport: The local port that received the request
+ * @sp: The sequence the request is on
+ * @fp: The request frame
*
* This function will see if the lport handles the request or
* if an rport should handle the request.
@@ -817,8 +916,8 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp,
}
/**
- * fc_lport_reset() - Reset an lport
- * @lport: The lport which should be reset
+ * fc_lport_reset() - Reset a local port
+ * @lport: The local port which should be reset
*
* Locking Note: This functions should not be called with the
* lport lock held.
@@ -834,29 +933,31 @@ int fc_lport_reset(struct fc_lport *lport)
EXPORT_SYMBOL(fc_lport_reset);
/**
- * fc_lport_reset_locked() - Reset the local port
- * @lport: Fibre Channel local port to be reset
+ * fc_lport_reset_locked() - Reset the local port w/ the lport lock held
+ * @lport: The local port to be reset
*
* Locking Note: The lport lock is expected to be held before calling
* this routine.
*/
static void fc_lport_reset_locked(struct fc_lport *lport)
{
- if (lport->dns_rp)
- lport->tt.rport_logoff(lport->dns_rp);
+ if (lport->dns_rdata)
+ lport->tt.rport_logoff(lport->dns_rdata);
- lport->ptp_rp = NULL;
+ lport->ptp_rdata = NULL;
lport->tt.disc_stop(lport);
lport->tt.exch_mgr_reset(lport, 0, 0);
fc_host_fabric_name(lport->host) = 0;
- fc_host_port_id(lport->host) = 0;
+
+ if (fc_host_port_id(lport->host))
+ fc_lport_set_port_id(lport, 0, NULL);
}
/**
* fc_lport_enter_reset() - Reset the local port
- * @lport: Fibre Channel local port to be reset
+ * @lport: The local port to be reset
*
* Locking Note: The lport lock is expected to be held before calling
* this routine.
@@ -866,15 +967,22 @@ static void fc_lport_enter_reset(struct fc_lport *lport)
FC_LPORT_DBG(lport, "Entered RESET state from %s state\n",
fc_lport_state(lport));
+ if (lport->vport) {
+ if (lport->link_up)
+ fc_vport_set_state(lport->vport, FC_VPORT_INITIALIZING);
+ else
+ fc_vport_set_state(lport->vport, FC_VPORT_LINKDOWN);
+ }
fc_lport_state_enter(lport, LPORT_ST_RESET);
+ fc_vports_linkchange(lport);
fc_lport_reset_locked(lport);
if (lport->link_up)
fc_lport_enter_flogi(lport);
}
/**
- * fc_lport_enter_disabled() - disable the local port
- * @lport: Fibre Channel local port to be reset
+ * fc_lport_enter_disabled() - Disable the local port
+ * @lport: The local port to be reset
*
* Locking Note: The lport lock is expected to be held before calling
* this routine.
@@ -885,13 +993,14 @@ static void fc_lport_enter_disabled(struct fc_lport *lport)
fc_lport_state(lport));
fc_lport_state_enter(lport, LPORT_ST_DISABLED);
+ fc_vports_linkchange(lport);
fc_lport_reset_locked(lport);
}
/**
* fc_lport_error() - Handler for any errors
- * @lport: The fc_lport object
- * @fp: The frame pointer
+ * @lport: The local port that the error was on
+ * @fp: The error code encoded in a frame pointer
*
* If the error was caused by a resource allocation failure
* then wait for half a second and retry, otherwise retry
@@ -922,8 +1031,11 @@ static void fc_lport_error(struct fc_lport *lport, struct fc_frame *fp)
case LPORT_ST_DISABLED:
case LPORT_ST_READY:
case LPORT_ST_RESET:
- case LPORT_ST_RPN_ID:
+ case LPORT_ST_RNN_ID:
+ case LPORT_ST_RSNN_NN:
+ case LPORT_ST_RSPN_ID:
case LPORT_ST_RFT_ID:
+ case LPORT_ST_RFF_ID:
case LPORT_ST_SCR:
case LPORT_ST_DNS:
case LPORT_ST_FLOGI:
@@ -936,33 +1048,33 @@ static void fc_lport_error(struct fc_lport *lport, struct fc_frame *fp)
}
/**
- * fc_lport_rft_id_resp() - Handle response to Register Fibre
- * Channel Types by ID (RPN_ID) request
- * @sp: current sequence in RPN_ID exchange
- * @fp: response frame
+ * fc_lport_ns_resp() - Handle response to a name server
+ * registration exchange
+ * @sp: current sequence in exchange
+ * @fp: response frame
* @lp_arg: Fibre Channel host port instance
*
* Locking Note: This function will be called without the lport lock
- * held, but it will lock, call an _enter_* function or fc_lport_error
+ * held, but it will lock, call an _enter_* function or fc_lport_error()
* and then unlock the lport.
*/
-static void fc_lport_rft_id_resp(struct fc_seq *sp, struct fc_frame *fp,
- void *lp_arg)
+static void fc_lport_ns_resp(struct fc_seq *sp, struct fc_frame *fp,
+ void *lp_arg)
{
struct fc_lport *lport = lp_arg;
struct fc_frame_header *fh;
struct fc_ct_hdr *ct;
- FC_LPORT_DBG(lport, "Received a RFT_ID %s\n", fc_els_resp_type(fp));
+ FC_LPORT_DBG(lport, "Received a ns %s\n", fc_els_resp_type(fp));
if (fp == ERR_PTR(-FC_EX_CLOSED))
return;
mutex_lock(&lport->lp_mutex);
- if (lport->state != LPORT_ST_RFT_ID) {
- FC_LPORT_DBG(lport, "Received a RFT_ID response, but in state "
- "%s\n", fc_lport_state(lport));
+ if (lport->state < LPORT_ST_RNN_ID || lport->state > LPORT_ST_RFF_ID) {
+ FC_LPORT_DBG(lport, "Received a name server response, "
+ "but in state %s\n", fc_lport_state(lport));
if (IS_ERR(fp))
goto err;
goto out;
@@ -980,63 +1092,28 @@ static void fc_lport_rft_id_resp(struct fc_seq *sp, struct fc_frame *fp,
ct->ct_fs_type == FC_FST_DIR &&
ct->ct_fs_subtype == FC_NS_SUBTYPE &&
ntohs(ct->ct_cmd) == FC_FS_ACC)
- fc_lport_enter_scr(lport);
- else
- fc_lport_error(lport, fp);
-out:
- fc_frame_free(fp);
-err:
- mutex_unlock(&lport->lp_mutex);
-}
-
-/**
- * fc_lport_rpn_id_resp() - Handle response to Register Port
- * Name by ID (RPN_ID) request
- * @sp: current sequence in RPN_ID exchange
- * @fp: response frame
- * @lp_arg: Fibre Channel host port instance
- *
- * Locking Note: This function will be called without the lport lock
- * held, but it will lock, call an _enter_* function or fc_lport_error
- * and then unlock the lport.
- */
-static void fc_lport_rpn_id_resp(struct fc_seq *sp, struct fc_frame *fp,
- void *lp_arg)
-{
- struct fc_lport *lport = lp_arg;
- struct fc_frame_header *fh;
- struct fc_ct_hdr *ct;
-
- FC_LPORT_DBG(lport, "Received a RPN_ID %s\n", fc_els_resp_type(fp));
-
- if (fp == ERR_PTR(-FC_EX_CLOSED))
- return;
-
- mutex_lock(&lport->lp_mutex);
-
- if (lport->state != LPORT_ST_RPN_ID) {
- FC_LPORT_DBG(lport, "Received a RPN_ID response, but in state "
- "%s\n", fc_lport_state(lport));
- if (IS_ERR(fp))
- goto err;
- goto out;
- }
-
- if (IS_ERR(fp)) {
- fc_lport_error(lport, fp);
- goto err;
- }
-
- fh = fc_frame_header_get(fp);
- ct = fc_frame_payload_get(fp, sizeof(*ct));
- if (fh && ct && fh->fh_type == FC_TYPE_CT &&
- ct->ct_fs_type == FC_FST_DIR &&
- ct->ct_fs_subtype == FC_NS_SUBTYPE &&
- ntohs(ct->ct_cmd) == FC_FS_ACC)
- fc_lport_enter_rft_id(lport);
+ switch (lport->state) {
+ case LPORT_ST_RNN_ID:
+ fc_lport_enter_ns(lport, LPORT_ST_RSNN_NN);
+ break;
+ case LPORT_ST_RSNN_NN:
+ fc_lport_enter_ns(lport, LPORT_ST_RSPN_ID);
+ break;
+ case LPORT_ST_RSPN_ID:
+ fc_lport_enter_ns(lport, LPORT_ST_RFT_ID);
+ break;
+ case LPORT_ST_RFT_ID:
+ fc_lport_enter_ns(lport, LPORT_ST_RFF_ID);
+ break;
+ case LPORT_ST_RFF_ID:
+ fc_lport_enter_scr(lport);
+ break;
+ default:
+ /* should have already been caught by state checks */
+ break;
+ }
else
fc_lport_error(lport, fp);
-
out:
fc_frame_free(fp);
err:
@@ -1045,8 +1122,8 @@ err:
/**
* fc_lport_scr_resp() - Handle response to State Change Register (SCR) request
- * @sp: current sequence in SCR exchange
- * @fp: response frame
+ * @sp: current sequence in SCR exchange
+ * @fp: response frame
* @lp_arg: Fibre Channel lport port instance that sent the registration request
*
* Locking Note: This function will be called without the lport lock
@@ -1092,8 +1169,8 @@ err:
}
/**
- * fc_lport_enter_scr() - Send a State Change Register (SCR) request
- * @lport: Fibre Channel local port to register for state changes
+ * fc_lport_enter_scr() - Send a SCR (State Change Register) request
+ * @lport: The local port to register for state changes
*
* Locking Note: The lport lock is expected to be held before calling
* this routine.
@@ -1114,78 +1191,74 @@ static void fc_lport_enter_scr(struct fc_lport *lport)
}
if (!lport->tt.elsct_send(lport, FC_FID_FCTRL, fp, ELS_SCR,
- fc_lport_scr_resp, lport, lport->e_d_tov))
- fc_lport_error(lport, fp);
+ fc_lport_scr_resp, lport,
+ 2 * lport->r_a_tov))
+ fc_lport_error(lport, NULL);
}
/**
- * fc_lport_enter_rft_id() - Register FC4-types with the name server
+ * fc_lport_enter_ns() - register some object with the name server
* @lport: Fibre Channel local port to register
*
* Locking Note: The lport lock is expected to be held before calling
* this routine.
*/
-static void fc_lport_enter_rft_id(struct fc_lport *lport)
+static void fc_lport_enter_ns(struct fc_lport *lport, enum fc_lport_state state)
{
struct fc_frame *fp;
- struct fc_ns_fts *lps;
- int i;
+ enum fc_ns_req cmd;
+ int size = sizeof(struct fc_ct_hdr);
+ size_t len;
- FC_LPORT_DBG(lport, "Entered RFT_ID state from %s state\n",
+ FC_LPORT_DBG(lport, "Entered %s state from %s state\n",
+ fc_lport_state_names[state],
fc_lport_state(lport));
- fc_lport_state_enter(lport, LPORT_ST_RFT_ID);
-
- lps = &lport->fcts;
- i = sizeof(lps->ff_type_map) / sizeof(lps->ff_type_map[0]);
- while (--i >= 0)
- if (ntohl(lps->ff_type_map[i]) != 0)
- break;
- if (i < 0) {
- /* nothing to register, move on to SCR */
- fc_lport_enter_scr(lport);
- return;
- }
+ fc_lport_state_enter(lport, state);
- fp = fc_frame_alloc(lport, sizeof(struct fc_ct_hdr) +
- sizeof(struct fc_ns_rft));
- if (!fp) {
- fc_lport_error(lport, fp);
+ switch (state) {
+ case LPORT_ST_RNN_ID:
+ cmd = FC_NS_RNN_ID;
+ size += sizeof(struct fc_ns_rn_id);
+ break;
+ case LPORT_ST_RSNN_NN:
+ len = strnlen(fc_host_symbolic_name(lport->host), 255);
+ /* if there is no symbolic name, skip to RFT_ID */
+ if (!len)
+ return fc_lport_enter_ns(lport, LPORT_ST_RFT_ID);
+ cmd = FC_NS_RSNN_NN;
+ size += sizeof(struct fc_ns_rsnn) + len;
+ break;
+ case LPORT_ST_RSPN_ID:
+ len = strnlen(fc_host_symbolic_name(lport->host), 255);
+ /* if there is no symbolic name, skip to RFT_ID */
+ if (!len)
+ return fc_lport_enter_ns(lport, LPORT_ST_RFT_ID);
+ cmd = FC_NS_RSPN_ID;
+ size += sizeof(struct fc_ns_rspn) + len;
+ break;
+ case LPORT_ST_RFT_ID:
+ cmd = FC_NS_RFT_ID;
+ size += sizeof(struct fc_ns_rft);
+ break;
+ case LPORT_ST_RFF_ID:
+ cmd = FC_NS_RFF_ID;
+ size += sizeof(struct fc_ns_rff_id);
+ break;
+ default:
+ fc_lport_error(lport, NULL);
return;
}
- if (!lport->tt.elsct_send(lport, FC_FID_DIR_SERV, fp, FC_NS_RFT_ID,
- fc_lport_rft_id_resp,
- lport, lport->e_d_tov))
- fc_lport_error(lport, fp);
-}
-
-/**
- * fc_rport_enter_rft_id() - Register port name with the name server
- * @lport: Fibre Channel local port to register
- *
- * Locking Note: The lport lock is expected to be held before calling
- * this routine.
- */
-static void fc_lport_enter_rpn_id(struct fc_lport *lport)
-{
- struct fc_frame *fp;
-
- FC_LPORT_DBG(lport, "Entered RPN_ID state from %s state\n",
- fc_lport_state(lport));
-
- fc_lport_state_enter(lport, LPORT_ST_RPN_ID);
-
- fp = fc_frame_alloc(lport, sizeof(struct fc_ct_hdr) +
- sizeof(struct fc_ns_rn_id));
+ fp = fc_frame_alloc(lport, size);
if (!fp) {
fc_lport_error(lport, fp);
return;
}
- if (!lport->tt.elsct_send(lport, FC_FID_DIR_SERV, fp, FC_NS_RPN_ID,
- fc_lport_rpn_id_resp,
- lport, lport->e_d_tov))
+ if (!lport->tt.elsct_send(lport, FC_FID_DIR_SERV, fp, cmd,
+ fc_lport_ns_resp,
+ lport, 3 * lport->r_a_tov))
fc_lport_error(lport, fp);
}
@@ -1194,8 +1267,8 @@ static struct fc_rport_operations fc_lport_rport_ops = {
};
/**
- * fc_rport_enter_dns() - Create a rport to the name server
- * @lport: Fibre Channel local port requesting a rport for the name server
+ * fc_rport_enter_dns() - Create a fc_rport for the name server
+ * @lport: The local port requesting a remote port for the name server
*
* Locking Note: The lport lock is expected to be held before calling
* this routine.
@@ -1224,8 +1297,8 @@ err:
}
/**
- * fc_lport_timeout() - Handler for the retry_work timer.
- * @work: The work struct of the fc_lport
+ * fc_lport_timeout() - Handler for the retry_work timer
+ * @work: The work struct of the local port
*/
static void fc_lport_timeout(struct work_struct *work)
{
@@ -1237,21 +1310,25 @@ static void fc_lport_timeout(struct work_struct *work)
switch (lport->state) {
case LPORT_ST_DISABLED:
+ WARN_ON(1);
+ break;
case LPORT_ST_READY:
- case LPORT_ST_RESET:
WARN_ON(1);
break;
+ case LPORT_ST_RESET:
+ break;
case LPORT_ST_FLOGI:
fc_lport_enter_flogi(lport);
break;
case LPORT_ST_DNS:
fc_lport_enter_dns(lport);
break;
- case LPORT_ST_RPN_ID:
- fc_lport_enter_rpn_id(lport);
- break;
+ case LPORT_ST_RNN_ID:
+ case LPORT_ST_RSNN_NN:
+ case LPORT_ST_RSPN_ID:
case LPORT_ST_RFT_ID:
- fc_lport_enter_rft_id(lport);
+ case LPORT_ST_RFF_ID:
+ fc_lport_enter_ns(lport, lport->state);
break;
case LPORT_ST_SCR:
fc_lport_enter_scr(lport);
@@ -1266,16 +1343,16 @@ static void fc_lport_timeout(struct work_struct *work)
/**
* fc_lport_logo_resp() - Handle response to LOGO request
- * @sp: current sequence in LOGO exchange
- * @fp: response frame
- * @lp_arg: Fibre Channel lport port instance that sent the LOGO request
+ * @sp: The sequence that the LOGO was on
+ * @fp: The LOGO frame
+ * @lp_arg: The lport port that received the LOGO request
*
* Locking Note: This function will be called without the lport lock
- * held, but it will lock, call an _enter_* function or fc_lport_error
+ * held, but it will lock, call an _enter_* function or fc_lport_error()
* and then unlock the lport.
*/
-static void fc_lport_logo_resp(struct fc_seq *sp, struct fc_frame *fp,
- void *lp_arg)
+void fc_lport_logo_resp(struct fc_seq *sp, struct fc_frame *fp,
+ void *lp_arg)
{
struct fc_lport *lport = lp_arg;
u8 op;
@@ -1311,10 +1388,11 @@ out:
err:
mutex_unlock(&lport->lp_mutex);
}
+EXPORT_SYMBOL(fc_lport_logo_resp);
/**
* fc_rport_enter_logo() - Logout of the fabric
- * @lport: Fibre Channel local port to be logged out
+ * @lport: The local port to be logged out
*
* Locking Note: The lport lock is expected to be held before calling
* this routine.
@@ -1328,6 +1406,7 @@ static void fc_lport_enter_logo(struct fc_lport *lport)
fc_lport_state(lport));
fc_lport_state_enter(lport, LPORT_ST_LOGO);
+ fc_vports_linkchange(lport);
fp = fc_frame_alloc(lport, sizeof(*logo));
if (!fp) {
@@ -1336,22 +1415,23 @@ static void fc_lport_enter_logo(struct fc_lport *lport)
}
if (!lport->tt.elsct_send(lport, FC_FID_FLOGI, fp, ELS_LOGO,
- fc_lport_logo_resp, lport, lport->e_d_tov))
- fc_lport_error(lport, fp);
+ fc_lport_logo_resp, lport,
+ 2 * lport->r_a_tov))
+ fc_lport_error(lport, NULL);
}
/**
* fc_lport_flogi_resp() - Handle response to FLOGI request
- * @sp: current sequence in FLOGI exchange
- * @fp: response frame
- * @lp_arg: Fibre Channel lport port instance that sent the FLOGI request
+ * @sp: The sequence that the FLOGI was on
+ * @fp: The FLOGI response frame
+ * @lp_arg: The lport port that received the FLOGI response
*
* Locking Note: This function will be called without the lport lock
- * held, but it will lock, call an _enter_* function or fc_lport_error
+ * held, but it will lock, call an _enter_* function or fc_lport_error()
* and then unlock the lport.
*/
-static void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
- void *lp_arg)
+void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
+ void *lp_arg)
{
struct fc_lport *lport = lp_arg;
struct fc_frame_header *fh;
@@ -1385,11 +1465,6 @@ static void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
fh = fc_frame_header_get(fp);
did = ntoh24(fh->fh_d_id);
if (fc_frame_payload_op(fp) == ELS_LS_ACC && did != 0) {
-
- printk(KERN_INFO "libfc: Assigned FID (%6x) in FLOGI response\n",
- did);
- fc_host_port_id(lport->host) = did;
-
flp = fc_frame_payload_get(fp, sizeof(*flp));
if (flp) {
mfs = ntohs(flp->fl_csp.sp_bb_data) &
@@ -1402,12 +1477,18 @@ static void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
e_d_tov = ntohl(flp->fl_csp.sp_e_d_tov);
if (csp_flags & FC_SP_FT_EDTR)
e_d_tov /= 1000000;
+
+ lport->npiv_enabled = !!(csp_flags & FC_SP_FT_NPIV_ACC);
+
if ((csp_flags & FC_SP_FT_FPORT) == 0) {
if (e_d_tov > lport->e_d_tov)
lport->e_d_tov = e_d_tov;
lport->r_a_tov = 2 * e_d_tov;
- printk(KERN_INFO "libfc: Port (%6x) entered "
- "point to point mode\n", did);
+ fc_lport_set_port_id(lport, did, fp);
+ printk(KERN_INFO "host%d: libfc: "
+ "Port (%6x) entered "
+ "point-to-point mode\n",
+ lport->host->host_no, did);
fc_lport_ptp_setup(lport, ntoh24(fh->fh_s_id),
get_unaligned_be64(
&flp->fl_wwpn),
@@ -1418,6 +1499,7 @@ static void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
lport->r_a_tov = r_a_tov;
fc_host_fabric_name(lport->host) =
get_unaligned_be64(&flp->fl_wwnn);
+ fc_lport_set_port_id(lport, did, fp);
fc_lport_enter_dns(lport);
}
}
@@ -1430,6 +1512,7 @@ out:
err:
mutex_unlock(&lport->lp_mutex);
}
+EXPORT_SYMBOL(fc_lport_flogi_resp);
/**
* fc_rport_enter_flogi() - Send a FLOGI request to the fabric manager
@@ -1451,12 +1534,18 @@ void fc_lport_enter_flogi(struct fc_lport *lport)
if (!fp)
return fc_lport_error(lport, fp);
- if (!lport->tt.elsct_send(lport, FC_FID_FLOGI, fp, ELS_FLOGI,
- fc_lport_flogi_resp, lport, lport->e_d_tov))
- fc_lport_error(lport, fp);
+ if (!lport->tt.elsct_send(lport, FC_FID_FLOGI, fp,
+ lport->vport ? ELS_FDISC : ELS_FLOGI,
+ fc_lport_flogi_resp, lport,
+ lport->vport ? 2 * lport->r_a_tov :
+ lport->e_d_tov))
+ fc_lport_error(lport, NULL);
}
-/* Configure a fc_lport */
+/**
+ * fc_lport_config() - Configure a fc_lport
+ * @lport: The local port to be configured
+ */
int fc_lport_config(struct fc_lport *lport)
{
INIT_DELAYED_WORK(&lport->retry_work, fc_lport_timeout);
@@ -1471,6 +1560,10 @@ int fc_lport_config(struct fc_lport *lport)
}
EXPORT_SYMBOL(fc_lport_config);
+/**
+ * fc_lport_init() - Initialize the lport layer for a local port
+ * @lport: The local port to initialize the exchange layer for
+ */
int fc_lport_init(struct fc_lport *lport)
{
if (!lport->tt.lport_recv)
@@ -1500,7 +1593,253 @@ int fc_lport_init(struct fc_lport *lport)
if (lport->link_supported_speeds & FC_PORTSPEED_10GBIT)
fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_10GBIT;
- INIT_LIST_HEAD(&lport->ema_list);
return 0;
}
EXPORT_SYMBOL(fc_lport_init);
+
+/**
+ * fc_lport_bsg_resp() - The common response handler for FC Passthrough requests
+ * @sp: The sequence for the FC Passthrough response
+ * @fp: The response frame
+ * @info_arg: The BSG info that the response is for
+ */
+static void fc_lport_bsg_resp(struct fc_seq *sp, struct fc_frame *fp,
+ void *info_arg)
+{
+ struct fc_bsg_info *info = info_arg;
+ struct fc_bsg_job *job = info->job;
+ struct fc_lport *lport = info->lport;
+ struct fc_frame_header *fh;
+ size_t len;
+ void *buf;
+
+ if (IS_ERR(fp)) {
+ job->reply->result = (PTR_ERR(fp) == -FC_EX_CLOSED) ?
+ -ECONNABORTED : -ETIMEDOUT;
+ job->reply_len = sizeof(uint32_t);
+ job->state_flags |= FC_RQST_STATE_DONE;
+ job->job_done(job);
+ kfree(info);
+ return;
+ }
+
+ mutex_lock(&lport->lp_mutex);
+ fh = fc_frame_header_get(fp);
+ len = fr_len(fp) - sizeof(*fh);
+ buf = fc_frame_payload_get(fp, 0);
+
+ if (fr_sof(fp) == FC_SOF_I3 && !ntohs(fh->fh_seq_cnt)) {
+ /* Get the response code from the first frame payload */
+ unsigned short cmd = (info->rsp_code == FC_FS_ACC) ?
+ ntohs(((struct fc_ct_hdr *)buf)->ct_cmd) :
+ (unsigned short)fc_frame_payload_op(fp);
+
+ /* Save the reply status of the job */
+ job->reply->reply_data.ctels_reply.status =
+ (cmd == info->rsp_code) ?
+ FC_CTELS_STATUS_OK : FC_CTELS_STATUS_REJECT;
+ }
+
+ job->reply->reply_payload_rcv_len +=
+ fc_copy_buffer_to_sglist(buf, len, info->sg, &info->nents,
+ &info->offset, KM_BIO_SRC_IRQ, NULL);
+
+ if (fr_eof(fp) == FC_EOF_T &&
+ (ntoh24(fh->fh_f_ctl) & (FC_FC_LAST_SEQ | FC_FC_END_SEQ)) ==
+ (FC_FC_LAST_SEQ | FC_FC_END_SEQ)) {
+ if (job->reply->reply_payload_rcv_len >
+ job->reply_payload.payload_len)
+ job->reply->reply_payload_rcv_len =
+ job->reply_payload.payload_len;
+ job->reply->result = 0;
+ job->state_flags |= FC_RQST_STATE_DONE;
+ job->job_done(job);
+ kfree(info);
+ }
+ fc_frame_free(fp);
+ mutex_unlock(&lport->lp_mutex);
+}
+
+/**
+ * fc_lport_els_request() - Send ELS passthrough request
+ * @job: The BSG Passthrough job
+ * @lport: The local port sending the request
+ * @did: The destination port id
+ *
+ * Locking Note: The lport lock is expected to be held before calling
+ * this routine.
+ */
+static int fc_lport_els_request(struct fc_bsg_job *job,
+ struct fc_lport *lport,
+ u32 did, u32 tov)
+{
+ struct fc_bsg_info *info;
+ struct fc_frame *fp;
+ struct fc_frame_header *fh;
+ char *pp;
+ int len;
+
+ fp = fc_frame_alloc(lport, job->request_payload.payload_len);
+ if (!fp)
+ return -ENOMEM;
+
+ len = job->request_payload.payload_len;
+ pp = fc_frame_payload_get(fp, len);
+
+ sg_copy_to_buffer(job->request_payload.sg_list,
+ job->request_payload.sg_cnt,
+ pp, len);
+
+ fh = fc_frame_header_get(fp);
+ fh->fh_r_ctl = FC_RCTL_ELS_REQ;
+ hton24(fh->fh_d_id, did);
+ hton24(fh->fh_s_id, fc_host_port_id(lport->host));
+ fh->fh_type = FC_TYPE_ELS;
+ hton24(fh->fh_f_ctl, FC_FC_FIRST_SEQ |
+ FC_FC_END_SEQ | FC_FC_SEQ_INIT);
+ fh->fh_cs_ctl = 0;
+ fh->fh_df_ctl = 0;
+ fh->fh_parm_offset = 0;
+
+ info = kzalloc(sizeof(struct fc_bsg_info), GFP_KERNEL);
+ if (!info) {
+ fc_frame_free(fp);
+ return -ENOMEM;
+ }
+
+ info->job = job;
+ info->lport = lport;
+ info->rsp_code = ELS_LS_ACC;
+ info->nents = job->reply_payload.sg_cnt;
+ info->sg = job->reply_payload.sg_list;
+
+ if (!lport->tt.exch_seq_send(lport, fp, fc_lport_bsg_resp,
+ NULL, info, tov))
+ return -ECOMM;
+ return 0;
+}
+
+/**
+ * fc_lport_ct_request() - Send CT Passthrough request
+ * @job: The BSG Passthrough job
+ * @lport: The local port sending the request
+ * @did: The destination FC-ID
+ * @tov: The timeout period to wait for the response
+ *
+ * Locking Note: The lport lock is expected to be held before calling
+ * this routine.
+ */
+static int fc_lport_ct_request(struct fc_bsg_job *job,
+ struct fc_lport *lport, u32 did, u32 tov)
+{
+ struct fc_bsg_info *info;
+ struct fc_frame *fp;
+ struct fc_frame_header *fh;
+ struct fc_ct_req *ct;
+ size_t len;
+
+ fp = fc_frame_alloc(lport, sizeof(struct fc_ct_hdr) +
+ job->request_payload.payload_len);
+ if (!fp)
+ return -ENOMEM;
+
+ len = job->request_payload.payload_len;
+ ct = fc_frame_payload_get(fp, len);
+
+ sg_copy_to_buffer(job->request_payload.sg_list,
+ job->request_payload.sg_cnt,
+ ct, len);
+
+ fh = fc_frame_header_get(fp);
+ fh->fh_r_ctl = FC_RCTL_DD_UNSOL_CTL;
+ hton24(fh->fh_d_id, did);
+ hton24(fh->fh_s_id, fc_host_port_id(lport->host));
+ fh->fh_type = FC_TYPE_CT;
+ hton24(fh->fh_f_ctl, FC_FC_FIRST_SEQ |
+ FC_FC_END_SEQ | FC_FC_SEQ_INIT);
+ fh->fh_cs_ctl = 0;
+ fh->fh_df_ctl = 0;
+ fh->fh_parm_offset = 0;
+
+ info = kzalloc(sizeof(struct fc_bsg_info), GFP_KERNEL);
+ if (!info) {
+ fc_frame_free(fp);
+ return -ENOMEM;
+ }
+
+ info->job = job;
+ info->lport = lport;
+ info->rsp_code = FC_FS_ACC;
+ info->nents = job->reply_payload.sg_cnt;
+ info->sg = job->reply_payload.sg_list;
+
+ if (!lport->tt.exch_seq_send(lport, fp, fc_lport_bsg_resp,
+ NULL, info, tov))
+ return -ECOMM;
+ return 0;
+}
+
+/**
+ * fc_lport_bsg_request() - The common entry point for sending
+ * FC Passthrough requests
+ * @job: The BSG passthrough job
+ */
+int fc_lport_bsg_request(struct fc_bsg_job *job)
+{
+ struct request *rsp = job->req->next_rq;
+ struct Scsi_Host *shost = job->shost;
+ struct fc_lport *lport = shost_priv(shost);
+ struct fc_rport *rport;
+ struct fc_rport_priv *rdata;
+ int rc = -EINVAL;
+ u32 did;
+
+ job->reply->reply_payload_rcv_len = 0;
+ rsp->resid_len = job->reply_payload.payload_len;
+
+ mutex_lock(&lport->lp_mutex);
+
+ switch (job->request->msgcode) {
+ case FC_BSG_RPT_ELS:
+ rport = job->rport;
+ if (!rport)
+ break;
+
+ rdata = rport->dd_data;
+ rc = fc_lport_els_request(job, lport, rport->port_id,
+ rdata->e_d_tov);
+ break;
+
+ case FC_BSG_RPT_CT:
+ rport = job->rport;
+ if (!rport)
+ break;
+
+ rdata = rport->dd_data;
+ rc = fc_lport_ct_request(job, lport, rport->port_id,
+ rdata->e_d_tov);
+ break;
+
+ case FC_BSG_HST_CT:
+ did = ntoh24(job->request->rqst_data.h_ct.port_id);
+ if (did == FC_FID_DIR_SERV)
+ rdata = lport->dns_rdata;
+ else
+ rdata = lport->tt.rport_lookup(lport, did);
+
+ if (!rdata)
+ break;
+
+ rc = fc_lport_ct_request(job, lport, did, rdata->e_d_tov);
+ break;
+
+ case FC_BSG_HST_ELS_NOLOGIN:
+ did = ntoh24(job->request->rqst_data.h_els.port_id);
+ rc = fc_lport_els_request(job, lport, did, lport->e_d_tov);
+ break;
+ }
+
+ mutex_unlock(&lport->lp_mutex);
+ return rc;
+}
+EXPORT_SYMBOL(fc_lport_bsg_request);
diff --git a/drivers/scsi/libfc/fc_npiv.c b/drivers/scsi/libfc/fc_npiv.c
new file mode 100644
index 0000000..c68f6c7
--- /dev/null
+++ b/drivers/scsi/libfc/fc_npiv.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright(c) 2009 Intel Corporation. All rights reserved.
+ *
+ * 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Maintained at www.Open-FCoE.org
+ */
+
+/*
+ * NPIV VN_Port helper functions for libfc
+ */
+
+#include <scsi/libfc.h>
+
+/**
+ * fc_vport_create() - Create a new NPIV vport instance
+ * @vport: fc_vport structure from scsi_transport_fc
+ * @privsize: driver private data size to allocate along with the Scsi_Host
+ */
+
+struct fc_lport *libfc_vport_create(struct fc_vport *vport, int privsize)
+{
+ struct Scsi_Host *shost = vport_to_shost(vport);
+ struct fc_lport *n_port = shost_priv(shost);
+ struct fc_lport *vn_port;
+
+ vn_port = libfc_host_alloc(shost->hostt, privsize);
+ if (!vn_port)
+ goto err_out;
+ if (fc_exch_mgr_list_clone(n_port, vn_port))
+ goto err_put;
+
+ vn_port->vport = vport;
+ vport->dd_data = vn_port;
+
+ mutex_lock(&n_port->lp_mutex);
+ list_add_tail(&vn_port->list, &n_port->vports);
+ mutex_unlock(&n_port->lp_mutex);
+
+ return vn_port;
+
+err_put:
+ scsi_host_put(vn_port->host);
+err_out:
+ return NULL;
+}
+EXPORT_SYMBOL(libfc_vport_create);
+
+/**
+ * fc_vport_id_lookup() - find NPIV lport that matches a given fabric ID
+ * @n_port: Top level N_Port which may have multiple NPIV VN_Ports
+ * @port_id: Fabric ID to find a match for
+ *
+ * Returns: matching lport pointer or NULL if there is no match
+ */
+struct fc_lport *fc_vport_id_lookup(struct fc_lport *n_port, u32 port_id)
+{
+ struct fc_lport *lport = NULL;
+ struct fc_lport *vn_port;
+
+ if (fc_host_port_id(n_port->host) == port_id)
+ return n_port;
+
+ mutex_lock(&n_port->lp_mutex);
+ list_for_each_entry(vn_port, &n_port->vports, list) {
+ if (fc_host_port_id(vn_port->host) == port_id) {
+ lport = vn_port;
+ break;
+ }
+ }
+ mutex_unlock(&n_port->lp_mutex);
+
+ return lport;
+}
+
+/*
+ * When setting the link state of vports during an lport state change, it's
+ * necessary to hold the lp_mutex of both the N_Port and the VN_Port.
+ * This tells the lockdep engine to treat the nested locking of the VN_Port
+ * as a different lock class.
+ */
+enum libfc_lport_mutex_class {
+ LPORT_MUTEX_NORMAL = 0,
+ LPORT_MUTEX_VN_PORT = 1,
+};
+
+/**
+ * __fc_vport_setlink() - update link and status on a VN_Port
+ * @n_port: parent N_Port
+ * @vn_port: VN_Port to update
+ *
+ * Locking: must be called with both the N_Port and VN_Port lp_mutex held
+ */
+static void __fc_vport_setlink(struct fc_lport *n_port,
+ struct fc_lport *vn_port)
+{
+ struct fc_vport *vport = vn_port->vport;
+
+ if (vn_port->state == LPORT_ST_DISABLED)
+ return;
+
+ if (n_port->state == LPORT_ST_READY) {
+ if (n_port->npiv_enabled) {
+ fc_vport_set_state(vport, FC_VPORT_INITIALIZING);
+ __fc_linkup(vn_port);
+ } else {
+ fc_vport_set_state(vport, FC_VPORT_NO_FABRIC_SUPP);
+ __fc_linkdown(vn_port);
+ }
+ } else {
+ fc_vport_set_state(vport, FC_VPORT_LINKDOWN);
+ __fc_linkdown(vn_port);
+ }
+}
+
+/**
+ * fc_vport_setlink() - update link and status on a VN_Port
+ * @vn_port: virtual port to update
+ */
+void fc_vport_setlink(struct fc_lport *vn_port)
+{
+ struct fc_vport *vport = vn_port->vport;
+ struct Scsi_Host *shost = vport_to_shost(vport);
+ struct fc_lport *n_port = shost_priv(shost);
+
+ mutex_lock(&n_port->lp_mutex);
+ mutex_lock_nested(&vn_port->lp_mutex, LPORT_MUTEX_VN_PORT);
+ __fc_vport_setlink(n_port, vn_port);
+ mutex_unlock(&vn_port->lp_mutex);
+ mutex_unlock(&n_port->lp_mutex);
+}
+EXPORT_SYMBOL(fc_vport_setlink);
+
+/**
+ * fc_vports_linkchange() - change the link state of all vports
+ * @n_port: Parent N_Port that has changed state
+ *
+ * Locking: called with the n_port lp_mutex held
+ */
+void fc_vports_linkchange(struct fc_lport *n_port)
+{
+ struct fc_lport *vn_port;
+
+ list_for_each_entry(vn_port, &n_port->vports, list) {
+ mutex_lock_nested(&vn_port->lp_mutex, LPORT_MUTEX_VN_PORT);
+ __fc_vport_setlink(n_port, vn_port);
+ mutex_unlock(&vn_port->lp_mutex);
+ }
+}
+
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c
index 03ea674..35ca0e7 100644
--- a/drivers/scsi/libfc/fc_rport.c
+++ b/drivers/scsi/libfc/fc_rport.c
@@ -55,6 +55,8 @@
#include <scsi/libfc.h>
#include <scsi/fc_encode.h>
+#include "fc_libfc.h"
+
struct workqueue_struct *rport_event_queue;
static void fc_rport_enter_plogi(struct fc_rport_priv *);
@@ -86,12 +88,13 @@ static const char *fc_rport_state_names[] = {
[RPORT_ST_LOGO] = "LOGO",
[RPORT_ST_ADISC] = "ADISC",
[RPORT_ST_DELETE] = "Delete",
+ [RPORT_ST_RESTART] = "Restart",
};
/**
- * fc_rport_lookup() - lookup a remote port by port_id
- * @lport: Fibre Channel host port instance
- * @port_id: remote port port_id to match
+ * fc_rport_lookup() - Lookup a remote port by port_id
+ * @lport: The local port to lookup the remote port on
+ * @port_id: The remote port ID to look up
*/
static struct fc_rport_priv *fc_rport_lookup(const struct fc_lport *lport,
u32 port_id)
@@ -99,16 +102,17 @@ static struct fc_rport_priv *fc_rport_lookup(const struct fc_lport *lport,
struct fc_rport_priv *rdata;
list_for_each_entry(rdata, &lport->disc.rports, peers)
- if (rdata->ids.port_id == port_id &&
- rdata->rp_state != RPORT_ST_DELETE)
+ if (rdata->ids.port_id == port_id)
return rdata;
return NULL;
}
/**
* fc_rport_create() - Create a new remote port
- * @lport: The local port that the new remote port is for
- * @port_id: The port ID for the new remote port
+ * @lport: The local port this remote port will be associated with
+ * @ids: The identifiers for the new remote port
+ *
+ * The remote port will start in the INIT state.
*
* Locking note: must be called with the disc_mutex held.
*/
@@ -147,8 +151,8 @@ static struct fc_rport_priv *fc_rport_create(struct fc_lport *lport,
}
/**
- * fc_rport_destroy() - free a remote port after last reference is released.
- * @kref: pointer to kref inside struct fc_rport_priv
+ * fc_rport_destroy() - Free a remote port after last reference is released
+ * @kref: The remote port's kref
*/
static void fc_rport_destroy(struct kref *kref)
{
@@ -159,8 +163,8 @@ static void fc_rport_destroy(struct kref *kref)
}
/**
- * fc_rport_state() - return a string for the state the rport is in
- * @rdata: remote port private data
+ * fc_rport_state() - Return a string identifying the remote port's state
+ * @rdata: The remote port
*/
static const char *fc_rport_state(struct fc_rport_priv *rdata)
{
@@ -173,9 +177,9 @@ static const char *fc_rport_state(struct fc_rport_priv *rdata)
}
/**
- * fc_set_rport_loss_tmo() - Set the remote port loss timeout in seconds.
- * @rport: Pointer to Fibre Channel remote port structure
- * @timeout: timeout in seconds
+ * fc_set_rport_loss_tmo() - Set the remote port loss timeout
+ * @rport: The remote port that gets a new timeout value
+ * @timeout: The new timeout value (in seconds)
*/
void fc_set_rport_loss_tmo(struct fc_rport *rport, u32 timeout)
{
@@ -187,9 +191,11 @@ void fc_set_rport_loss_tmo(struct fc_rport *rport, u32 timeout)
EXPORT_SYMBOL(fc_set_rport_loss_tmo);
/**
- * fc_plogi_get_maxframe() - Get max payload from the common service parameters
- * @flp: FLOGI payload structure
- * @maxval: upper limit, may be less than what is in the service parameters
+ * fc_plogi_get_maxframe() - Get the maximum payload from the common service
+ * parameters in a FLOGI frame
+ * @flp: The FLOGI payload
+ * @maxval: The maximum frame size upper limit; this may be less than what
+ * is in the service parameters
*/
static unsigned int fc_plogi_get_maxframe(struct fc_els_flogi *flp,
unsigned int maxval)
@@ -210,9 +216,9 @@ static unsigned int fc_plogi_get_maxframe(struct fc_els_flogi *flp,
}
/**
- * fc_rport_state_enter() - Change the rport's state
- * @rdata: The rport whose state should change
- * @new: The new state of the rport
+ * fc_rport_state_enter() - Change the state of a remote port
+ * @rdata: The remote port whose state should change
+ * @new: The new state
*
* Locking Note: Called with the rport lock held
*/
@@ -224,17 +230,22 @@ static void fc_rport_state_enter(struct fc_rport_priv *rdata,
rdata->rp_state = new;
}
+/**
+ * fc_rport_work() - Handler for remote port events in the rport_event_queue
+ * @work: Handle to the remote port being dequeued
+ */
static void fc_rport_work(struct work_struct *work)
{
u32 port_id;
struct fc_rport_priv *rdata =
container_of(work, struct fc_rport_priv, event_work);
- struct fc_rport_libfc_priv *rp;
+ struct fc_rport_libfc_priv *rpriv;
enum fc_rport_event event;
struct fc_lport *lport = rdata->local_port;
struct fc_rport_operations *rport_ops;
struct fc_rport_identifiers ids;
struct fc_rport *rport;
+ int restart = 0;
mutex_lock(&rdata->rp_mutex);
event = rdata->event;
@@ -265,12 +276,12 @@ static void fc_rport_work(struct work_struct *work)
rport->maxframe_size = rdata->maxframe_size;
rport->supported_classes = rdata->supported_classes;
- rp = rport->dd_data;
- rp->local_port = lport;
- rp->rp_state = rdata->rp_state;
- rp->flags = rdata->flags;
- rp->e_d_tov = rdata->e_d_tov;
- rp->r_a_tov = rdata->r_a_tov;
+ rpriv = rport->dd_data;
+ rpriv->local_port = lport;
+ rpriv->rp_state = rdata->rp_state;
+ rpriv->flags = rdata->flags;
+ rpriv->e_d_tov = rdata->e_d_tov;
+ rpriv->r_a_tov = rdata->r_a_tov;
mutex_unlock(&rdata->rp_mutex);
if (rport_ops && rport_ops->event_callback) {
@@ -287,8 +298,19 @@ static void fc_rport_work(struct work_struct *work)
mutex_unlock(&rdata->rp_mutex);
if (port_id != FC_FID_DIR_SERV) {
+ /*
+ * We must drop rp_mutex before taking disc_mutex.
+ * Re-evaluate state to allow for restart.
+ * A transition to RESTART state must only happen
+ * while disc_mutex is held and rdata is on the list.
+ */
mutex_lock(&lport->disc.disc_mutex);
- list_del(&rdata->peers);
+ mutex_lock(&rdata->rp_mutex);
+ if (rdata->rp_state == RPORT_ST_RESTART)
+ restart = 1;
+ else
+ list_del(&rdata->peers);
+ mutex_unlock(&rdata->rp_mutex);
mutex_unlock(&lport->disc.disc_mutex);
}
@@ -305,14 +327,20 @@ static void fc_rport_work(struct work_struct *work)
lport->tt.exch_mgr_reset(lport, port_id, 0);
if (rport) {
- rp = rport->dd_data;
- rp->rp_state = RPORT_ST_DELETE;
+ rpriv = rport->dd_data;
+ rpriv->rp_state = RPORT_ST_DELETE;
mutex_lock(&rdata->rp_mutex);
rdata->rport = NULL;
mutex_unlock(&rdata->rp_mutex);
fc_remote_port_delete(rport);
}
- kref_put(&rdata->kref, lport->tt.rport_destroy);
+ if (restart) {
+ mutex_lock(&rdata->rp_mutex);
+ FC_RPORT_DBG(rdata, "work restart\n");
+ fc_rport_enter_plogi(rdata);
+ mutex_unlock(&rdata->rp_mutex);
+ } else
+ kref_put(&rdata->kref, lport->tt.rport_destroy);
break;
default:
@@ -323,7 +351,7 @@ static void fc_rport_work(struct work_struct *work)
/**
* fc_rport_login() - Start the remote port login state machine
- * @rdata: private remote port
+ * @rdata: The remote port to be logged in to
*
* Locking Note: Called without the rport lock held. This
* function will hold the rport lock, call an _enter_*
@@ -342,6 +370,12 @@ int fc_rport_login(struct fc_rport_priv *rdata)
FC_RPORT_DBG(rdata, "ADISC port\n");
fc_rport_enter_adisc(rdata);
break;
+ case RPORT_ST_RESTART:
+ break;
+ case RPORT_ST_DELETE:
+ FC_RPORT_DBG(rdata, "Restart deleted port\n");
+ fc_rport_state_enter(rdata, RPORT_ST_RESTART);
+ break;
default:
FC_RPORT_DBG(rdata, "Login to port\n");
fc_rport_enter_plogi(rdata);
@@ -353,9 +387,9 @@ int fc_rport_login(struct fc_rport_priv *rdata)
}
/**
- * fc_rport_enter_delete() - schedule a remote port to be deleted.
- * @rdata: private remote port
- * @event: event to report as the reason for deletion
+ * fc_rport_enter_delete() - Schedule a remote port to be deleted
+ * @rdata: The remote port to be deleted
+ * @event: The event to report as the reason for deletion
*
* Locking Note: Called with the rport lock held.
*
@@ -382,8 +416,8 @@ static void fc_rport_enter_delete(struct fc_rport_priv *rdata,
}
/**
- * fc_rport_logoff() - Logoff and remove an rport
- * @rdata: private remote port
+ * fc_rport_logoff() - Logoff and remove a remote port
+ * @rdata: The remote port to be logged off of
*
* Locking Note: Called without the rport lock held. This
* function will hold the rport lock, call an _enter_*
@@ -397,26 +431,27 @@ int fc_rport_logoff(struct fc_rport_priv *rdata)
if (rdata->rp_state == RPORT_ST_DELETE) {
FC_RPORT_DBG(rdata, "Port in Delete state, not removing\n");
- mutex_unlock(&rdata->rp_mutex);
goto out;
}
- fc_rport_enter_logo(rdata);
+ if (rdata->rp_state == RPORT_ST_RESTART)
+ FC_RPORT_DBG(rdata, "Port in Restart state, deleting\n");
+ else
+ fc_rport_enter_logo(rdata);
/*
* Change the state to Delete so that we discard
* the response.
*/
fc_rport_enter_delete(rdata, RPORT_EV_STOP);
- mutex_unlock(&rdata->rp_mutex);
-
out:
+ mutex_unlock(&rdata->rp_mutex);
return 0;
}
/**
- * fc_rport_enter_ready() - The rport is ready
- * @rdata: private remote port
+ * fc_rport_enter_ready() - Transition to the RPORT_ST_READY state
+ * @rdata: The remote port that is ready
*
* Locking Note: The rport lock is expected to be held before calling
* this routine.
@@ -433,8 +468,8 @@ static void fc_rport_enter_ready(struct fc_rport_priv *rdata)
}
/**
- * fc_rport_timeout() - Handler for the retry_work timer.
- * @work: The work struct of the fc_rport_priv
+ * fc_rport_timeout() - Handler for the retry_work timer
+ * @work: Handle to the remote port that has timed out
*
* Locking Note: Called without the rport lock held. This
* function will hold the rport lock, call an _enter_*
@@ -466,6 +501,7 @@ static void fc_rport_timeout(struct work_struct *work)
case RPORT_ST_READY:
case RPORT_ST_INIT:
case RPORT_ST_DELETE:
+ case RPORT_ST_RESTART:
break;
}
@@ -474,8 +510,8 @@ static void fc_rport_timeout(struct work_struct *work)
/**
* fc_rport_error() - Error handler, called once retries have been exhausted
- * @rdata: private remote port
- * @fp: The frame pointer
+ * @rdata: The remote port the error is happened on
+ * @fp: The error code encapsulated in a frame pointer
*
* Locking Note: The rport lock is expected to be held before
* calling this routine
@@ -499,6 +535,7 @@ static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp)
fc_rport_enter_logo(rdata);
break;
case RPORT_ST_DELETE:
+ case RPORT_ST_RESTART:
case RPORT_ST_READY:
case RPORT_ST_INIT:
break;
@@ -506,9 +543,9 @@ static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp)
}
/**
- * fc_rport_error_retry() - Error handler when retries are desired
- * @rdata: private remote port data
- * @fp: The frame pointer
+ * fc_rport_error_retry() - Handler for remote port state retries
+ * @rdata: The remote port whose state is to be retried
+ * @fp: The error code encapsulated in a frame pointer
*
* If the error was an exchange timeout retry immediately,
* otherwise wait for E_D_TOV.
@@ -540,10 +577,10 @@ static void fc_rport_error_retry(struct fc_rport_priv *rdata,
}
/**
- * fc_rport_plogi_recv_resp() - Handle incoming ELS PLOGI response
- * @sp: current sequence in the PLOGI exchange
- * @fp: response frame
- * @rdata_arg: private remote port data
+ * fc_rport_plogi_recv_resp() - Handler for ELS PLOGI responses
+ * @sp: The sequence the PLOGI is on
+ * @fp: The PLOGI response frame
+ * @rdata_arg: The remote port that sent the PLOGI response
*
* Locking Note: This function will be called without the rport lock
* held, but it will lock, call an _enter_* function or fc_rport_error
@@ -606,8 +643,8 @@ err:
}
/**
- * fc_rport_enter_plogi() - Send Port Login (PLOGI) request to peer
- * @rdata: private remote port data
+ * fc_rport_enter_plogi() - Send Port Login (PLOGI) request
+ * @rdata: The remote port to send a PLOGI to
*
* Locking Note: The rport lock is expected to be held before calling
* this routine.
@@ -631,17 +668,18 @@ static void fc_rport_enter_plogi(struct fc_rport_priv *rdata)
rdata->e_d_tov = lport->e_d_tov;
if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_PLOGI,
- fc_rport_plogi_resp, rdata, lport->e_d_tov))
- fc_rport_error_retry(rdata, fp);
+ fc_rport_plogi_resp, rdata,
+ 2 * lport->r_a_tov))
+ fc_rport_error_retry(rdata, NULL);
else
kref_get(&rdata->kref);
}
/**
* fc_rport_prli_resp() - Process Login (PRLI) response handler
- * @sp: current sequence in the PRLI exchange
- * @fp: response frame
- * @rdata_arg: private remote port data
+ * @sp: The sequence the PRLI response was on
+ * @fp: The PRLI response frame
+ * @rdata_arg: The remote port that sent the PRLI response
*
* Locking Note: This function will be called without the rport lock
* held, but it will lock, call an _enter_* function or fc_rport_error
@@ -710,10 +748,10 @@ err:
}
/**
- * fc_rport_logo_resp() - Logout (LOGO) response handler
- * @sp: current sequence in the LOGO exchange
- * @fp: response frame
- * @rdata_arg: private remote port data
+ * fc_rport_logo_resp() - Handler for logout (LOGO) responses
+ * @sp: The sequence the LOGO was on
+ * @fp: The LOGO response frame
+ * @rdata_arg: The remote port that sent the LOGO response
*
* Locking Note: This function will be called without the rport lock
* held, but it will lock, call an _enter_* function or fc_rport_error
@@ -756,8 +794,8 @@ err:
}
/**
- * fc_rport_enter_prli() - Send Process Login (PRLI) request to peer
- * @rdata: private remote port data
+ * fc_rport_enter_prli() - Send Process Login (PRLI) request
+ * @rdata: The remote port to send the PRLI request to
*
* Locking Note: The rport lock is expected to be held before calling
* this routine.
@@ -792,17 +830,18 @@ static void fc_rport_enter_prli(struct fc_rport_priv *rdata)
}
if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_PRLI,
- fc_rport_prli_resp, rdata, lport->e_d_tov))
- fc_rport_error_retry(rdata, fp);
+ fc_rport_prli_resp, rdata,
+ 2 * lport->r_a_tov))
+ fc_rport_error_retry(rdata, NULL);
else
kref_get(&rdata->kref);
}
/**
- * fc_rport_els_rtv_resp() - Request Timeout Value response handler
- * @sp: current sequence in the RTV exchange
- * @fp: response frame
- * @rdata_arg: private remote port data
+ * fc_rport_els_rtv_resp() - Handler for Request Timeout Value (RTV) responses
+ * @sp: The sequence the RTV was on
+ * @fp: The RTV response frame
+ * @rdata_arg: The remote port that sent the RTV response
*
* Many targets don't seem to support this.
*
@@ -865,8 +904,8 @@ err:
}
/**
- * fc_rport_enter_rtv() - Send Request Timeout Value (RTV) request to peer
- * @rdata: private remote port data
+ * fc_rport_enter_rtv() - Send Request Timeout Value (RTV) request
+ * @rdata: The remote port to send the RTV request to
*
* Locking Note: The rport lock is expected to be held before calling
* this routine.
@@ -888,15 +927,16 @@ static void fc_rport_enter_rtv(struct fc_rport_priv *rdata)
}
if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_RTV,
- fc_rport_rtv_resp, rdata, lport->e_d_tov))
- fc_rport_error_retry(rdata, fp);
+ fc_rport_rtv_resp, rdata,
+ 2 * lport->r_a_tov))
+ fc_rport_error_retry(rdata, NULL);
else
kref_get(&rdata->kref);
}
/**
- * fc_rport_enter_logo() - Send Logout (LOGO) request to peer
- * @rdata: private remote port data
+ * fc_rport_enter_logo() - Send a logout (LOGO) request
+ * @rdata: The remote port to send the LOGO request to
*
* Locking Note: The rport lock is expected to be held before calling
* this routine.
@@ -918,24 +958,25 @@ static void fc_rport_enter_logo(struct fc_rport_priv *rdata)
}
if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_LOGO,
- fc_rport_logo_resp, rdata, lport->e_d_tov))
- fc_rport_error_retry(rdata, fp);
+ fc_rport_logo_resp, rdata,
+ 2 * lport->r_a_tov))
+ fc_rport_error_retry(rdata, NULL);
else
kref_get(&rdata->kref);
}
/**
- * fc_rport_els_adisc_resp() - Address Discovery response handler
- * @sp: current sequence in the ADISC exchange
- * @fp: response frame
- * @rdata_arg: remote port private.
+ * fc_rport_els_adisc_resp() - Handler for Address Discovery (ADISC) responses
+ * @sp: The sequence the ADISC response was on
+ * @fp: The ADISC response frame
+ * @rdata_arg: The remote port that sent the ADISC response
*
* Locking Note: This function will be called without the rport lock
* held, but it will lock, call an _enter_* function or fc_rport_error
* and then unlock the rport.
*/
static void fc_rport_adisc_resp(struct fc_seq *sp, struct fc_frame *fp,
- void *rdata_arg)
+ void *rdata_arg)
{
struct fc_rport_priv *rdata = rdata_arg;
struct fc_els_adisc *adisc;
@@ -983,8 +1024,8 @@ err:
}
/**
- * fc_rport_enter_adisc() - Send Address Discover (ADISC) request to peer
- * @rdata: remote port private data
+ * fc_rport_enter_adisc() - Send Address Discover (ADISC) request
+ * @rdata: The remote port to send the ADISC request to
*
* Locking Note: The rport lock is expected to be held before calling
* this routine.
@@ -1005,17 +1046,18 @@ static void fc_rport_enter_adisc(struct fc_rport_priv *rdata)
return;
}
if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_ADISC,
- fc_rport_adisc_resp, rdata, lport->e_d_tov))
- fc_rport_error_retry(rdata, fp);
+ fc_rport_adisc_resp, rdata,
+ 2 * lport->r_a_tov))
+ fc_rport_error_retry(rdata, NULL);
else
kref_get(&rdata->kref);
}
/**
- * fc_rport_recv_adisc_req() - Handle incoming Address Discovery (ADISC) Request
- * @rdata: remote port private
- * @sp: current sequence in the ADISC exchange
- * @in_fp: ADISC request frame
+ * fc_rport_recv_adisc_req() - Handler for Address Discovery (ADISC) requests
+ * @rdata: The remote port that sent the ADISC request
+ * @sp: The sequence the ADISC request was on
+ * @in_fp: The ADISC request frame
*
* Locking Note: Called with the lport and rport locks held.
*/
@@ -1056,10 +1098,82 @@ drop:
}
/**
- * fc_rport_recv_els_req() - handle a validated ELS request.
- * @lport: Fibre Channel local port
- * @sp: current sequence in the PLOGI exchange
- * @fp: response frame
+ * fc_rport_recv_rls_req() - Handle received Read Link Status request
+ * @rdata: The remote port that sent the RLS request
+ * @sp: The sequence that the RLS was on
+ * @rx_fp: The PRLI request frame
+ *
+ * Locking Note: The rport lock is expected to be held before calling
+ * this function.
+ */
+static void fc_rport_recv_rls_req(struct fc_rport_priv *rdata,
+ struct fc_seq *sp, struct fc_frame *rx_fp)
+
+{
+ struct fc_lport *lport = rdata->local_port;
+ struct fc_frame *fp;
+ struct fc_exch *ep = fc_seq_exch(sp);
+ struct fc_els_rls *rls;
+ struct fc_els_rls_resp *rsp;
+ struct fc_els_lesb *lesb;
+ struct fc_seq_els_data rjt_data;
+ struct fc_host_statistics *hst;
+ u32 f_ctl;
+
+ FC_RPORT_DBG(rdata, "Received RLS request while in state %s\n",
+ fc_rport_state(rdata));
+
+ rls = fc_frame_payload_get(rx_fp, sizeof(*rls));
+ if (!rls) {
+ rjt_data.reason = ELS_RJT_PROT;
+ rjt_data.explan = ELS_EXPL_INV_LEN;
+ goto out_rjt;
+ }
+
+ fp = fc_frame_alloc(lport, sizeof(*rsp));
+ if (!fp) {
+ rjt_data.reason = ELS_RJT_UNAB;
+ rjt_data.explan = ELS_EXPL_INSUF_RES;
+ goto out_rjt;
+ }
+
+ rsp = fc_frame_payload_get(fp, sizeof(*rsp));
+ memset(rsp, 0, sizeof(*rsp));
+ rsp->rls_cmd = ELS_LS_ACC;
+ lesb = &rsp->rls_lesb;
+ if (lport->tt.get_lesb) {
+ /* get LESB from LLD if it supports it */
+ lport->tt.get_lesb(lport, lesb);
+ } else {
+ fc_get_host_stats(lport->host);
+ hst = &lport->host_stats;
+ lesb->lesb_link_fail = htonl(hst->link_failure_count);
+ lesb->lesb_sync_loss = htonl(hst->loss_of_sync_count);
+ lesb->lesb_sig_loss = htonl(hst->loss_of_signal_count);
+ lesb->lesb_prim_err = htonl(hst->prim_seq_protocol_err_count);
+ lesb->lesb_inv_word = htonl(hst->invalid_tx_word_count);
+ lesb->lesb_inv_crc = htonl(hst->invalid_crc_count);
+ }
+
+ sp = lport->tt.seq_start_next(sp);
+ f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ;
+ fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
+ FC_TYPE_ELS, f_ctl, 0);
+ lport->tt.seq_send(lport, sp, fp);
+ goto out;
+
+out_rjt:
+ rjt_data.fp = NULL;
+ lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
+out:
+ fc_frame_free(rx_fp);
+}
+
+/**
+ * fc_rport_recv_els_req() - Handler for validated ELS requests
+ * @lport: The local port that received the ELS request
+ * @sp: The sequence that the ELS request was on
+ * @fp: The ELS request frame
*
* Handle incoming ELS requests that require port login.
* The ELS opcode has already been validated by the caller.
@@ -1117,6 +1231,9 @@ static void fc_rport_recv_els_req(struct fc_lport *lport,
els_data.fp = fp;
lport->tt.seq_els_rsp_send(sp, ELS_REC, &els_data);
break;
+ case ELS_RLS:
+ fc_rport_recv_rls_req(rdata, sp, fp);
+ break;
default:
fc_frame_free(fp); /* can't happen */
break;
@@ -1131,10 +1248,10 @@ reject:
}
/**
- * fc_rport_recv_req() - Handle a received ELS request from a rport
- * @sp: current sequence in the PLOGI exchange
- * @fp: response frame
- * @lport: Fibre Channel local port
+ * fc_rport_recv_req() - Handler for requests
+ * @sp: The sequence the request was on
+ * @fp: The request frame
+ * @lport: The local port that received the request
*
* Locking Note: Called with the lport lock held.
*/
@@ -1161,6 +1278,7 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp,
case ELS_ADISC:
case ELS_RRQ:
case ELS_REC:
+ case ELS_RLS:
fc_rport_recv_els_req(lport, sp, fp);
break;
default:
@@ -1174,10 +1292,10 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp,
}
/**
- * fc_rport_recv_plogi_req() - Handle incoming Port Login (PLOGI) request
- * @lport: local port
- * @sp: current sequence in the PLOGI exchange
- * @fp: PLOGI request frame
+ * fc_rport_recv_plogi_req() - Handler for Port Login (PLOGI) requests
+ * @lport: The local port that received the PLOGI request
+ * @sp: The sequence that the PLOGI request was on
+ * @rx_fp: The PLOGI request frame
*
* Locking Note: The rport lock is held before calling this function.
*/
@@ -1248,6 +1366,7 @@ static void fc_rport_recv_plogi_req(struct fc_lport *lport,
}
break;
case RPORT_ST_PRLI:
+ case RPORT_ST_RTV:
case RPORT_ST_READY:
case RPORT_ST_ADISC:
FC_RPORT_DBG(rdata, "Received PLOGI in logged-in state %d "
@@ -1255,11 +1374,14 @@ static void fc_rport_recv_plogi_req(struct fc_lport *lport,
/* XXX TBD - should reset */
break;
case RPORT_ST_DELETE:
- default:
- FC_RPORT_DBG(rdata, "Received PLOGI in unexpected state %d\n",
- rdata->rp_state);
- fc_frame_free(rx_fp);
- goto out;
+ case RPORT_ST_LOGO:
+ case RPORT_ST_RESTART:
+ FC_RPORT_DBG(rdata, "Received PLOGI in state %s - send busy\n",
+ fc_rport_state(rdata));
+ mutex_unlock(&rdata->rp_mutex);
+ rjt_data.reason = ELS_RJT_BUSY;
+ rjt_data.explan = ELS_EXPL_NONE;
+ goto reject;
}
/*
@@ -1295,10 +1417,10 @@ reject:
}
/**
- * fc_rport_recv_prli_req() - Handle incoming Process Login (PRLI) request
- * @rdata: private remote port data
- * @sp: current sequence in the PRLI exchange
- * @fp: PRLI request frame
+ * fc_rport_recv_prli_req() - Handler for process login (PRLI) requests
+ * @rdata: The remote port that sent the PRLI request
+ * @sp: The sequence that the PRLI was on
+ * @rx_fp: The PRLI request frame
*
* Locking Note: The rport lock is exected to be held before calling
* this function.
@@ -1402,7 +1524,7 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,
break;
case FC_TYPE_FCP:
fcp_parm = ntohl(rspp->spp_params);
- if (fcp_parm * FCP_SPPF_RETRY)
+ if (fcp_parm & FCP_SPPF_RETRY)
rdata->flags |= FC_RP_FLAGS_RETRY;
rdata->supported_classes = FC_COS_CLASS3;
if (fcp_parm & FCP_SPPF_INIT_FCN)
@@ -1452,10 +1574,10 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,
}
/**
- * fc_rport_recv_prlo_req() - Handle incoming Process Logout (PRLO) request
- * @rdata: private remote port data
- * @sp: current sequence in the PRLO exchange
- * @fp: PRLO request frame
+ * fc_rport_recv_prlo_req() - Handler for process logout (PRLO) requests
+ * @rdata: The remote port that sent the PRLO request
+ * @sp: The sequence that the PRLO was on
+ * @fp: The PRLO request frame
*
* Locking Note: The rport lock is exected to be held before calling
* this function.
@@ -1482,10 +1604,10 @@ static void fc_rport_recv_prlo_req(struct fc_rport_priv *rdata,
}
/**
- * fc_rport_recv_logo_req() - Handle incoming Logout (LOGO) request
- * @lport: local port.
- * @sp: current sequence in the LOGO exchange
- * @fp: LOGO request frame
+ * fc_rport_recv_logo_req() - Handler for logout (LOGO) requests
+ * @lport: The local port that received the LOGO request
+ * @sp: The sequence that the LOGO request was on
+ * @fp: The LOGO request frame
*
* Locking Note: The rport lock is exected to be held before calling
* this function.
@@ -1510,14 +1632,14 @@ static void fc_rport_recv_logo_req(struct fc_lport *lport,
FC_RPORT_DBG(rdata, "Received LOGO request while in state %s\n",
fc_rport_state(rdata));
+ fc_rport_enter_delete(rdata, RPORT_EV_LOGO);
+
/*
- * If the remote port was created due to discovery,
- * log back in. It may have seen a stale RSCN about us.
+ * If the remote port was created due to discovery, set state
+ * to log back in. It may have seen a stale RSCN about us.
*/
- if (rdata->rp_state != RPORT_ST_DELETE && rdata->disc_id)
- fc_rport_enter_plogi(rdata);
- else
- fc_rport_enter_delete(rdata, RPORT_EV_LOGO);
+ if (rdata->disc_id)
+ fc_rport_state_enter(rdata, RPORT_ST_RESTART);
mutex_unlock(&rdata->rp_mutex);
} else
FC_RPORT_ID_DBG(lport, sid,
@@ -1526,11 +1648,18 @@ static void fc_rport_recv_logo_req(struct fc_lport *lport,
fc_frame_free(fp);
}
+/**
+ * fc_rport_flush_queue() - Flush the rport_event_queue
+ */
static void fc_rport_flush_queue(void)
{
flush_workqueue(rport_event_queue);
}
+/**
+ * fc_rport_init() - Initialize the remote port layer for a local port
+ * @lport: The local port to initialize the remote port layer for
+ */
int fc_rport_init(struct fc_lport *lport)
{
if (!lport->tt.rport_lookup)
@@ -1558,25 +1687,33 @@ int fc_rport_init(struct fc_lport *lport)
}
EXPORT_SYMBOL(fc_rport_init);
-int fc_setup_rport(void)
+/**
+ * fc_setup_rport() - Initialize the rport_event_queue
+ */
+int fc_setup_rport()
{
rport_event_queue = create_singlethread_workqueue("fc_rport_eq");
if (!rport_event_queue)
return -ENOMEM;
return 0;
}
-EXPORT_SYMBOL(fc_setup_rport);
-void fc_destroy_rport(void)
+/**
+ * fc_destroy_rport() - Destroy the rport_event_queue
+ */
+void fc_destroy_rport()
{
destroy_workqueue(rport_event_queue);
}
-EXPORT_SYMBOL(fc_destroy_rport);
+/**
+ * fc_rport_terminate_io() - Stop all outstanding I/O on a remote port
+ * @rport: The remote port whose I/O should be terminated
+ */
void fc_rport_terminate_io(struct fc_rport *rport)
{
- struct fc_rport_libfc_priv *rp = rport->dd_data;
- struct fc_lport *lport = rp->local_port;
+ struct fc_rport_libfc_priv *rpriv = rport->dd_data;
+ struct fc_lport *lport = rpriv->local_port;
lport->tt.exch_mgr_reset(lport, 0, rport->port_id);
lport->tt.exch_mgr_reset(lport, rport->port_id, 0);
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index f1a4246..b7689f3 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -266,6 +266,88 @@ static int iscsi_prep_bidi_ahs(struct iscsi_task *task)
}
/**
+ * iscsi_check_tmf_restrictions - check if a task is affected by TMF
+ * @task: iscsi task
+ * @opcode: opcode to check for
+ *
+ * During TMF a task has to be checked if it's affected.
+ * All unrelated I/O can be passed through, but I/O to the
+ * affected LUN should be restricted.
+ * If 'fast_abort' is set we won't be sending any I/O to the
+ * affected LUN.
+ * Otherwise the target is waiting for all TTTs to be completed,
+ * so we have to send all outstanding Data-Out PDUs to the target.
+ */
+static int iscsi_check_tmf_restrictions(struct iscsi_task *task, int opcode)
+{
+ struct iscsi_conn *conn = task->conn;
+ struct iscsi_tm *tmf = &conn->tmhdr;
+ unsigned int hdr_lun;
+
+ if (conn->tmf_state == TMF_INITIAL)
+ return 0;
+
+ if ((tmf->opcode & ISCSI_OPCODE_MASK) != ISCSI_OP_SCSI_TMFUNC)
+ return 0;
+
+ switch (ISCSI_TM_FUNC_VALUE(tmf)) {
+ case ISCSI_TM_FUNC_LOGICAL_UNIT_RESET:
+ /*
+ * Allow PDUs for unrelated LUNs
+ */
+ hdr_lun = scsilun_to_int((struct scsi_lun *)tmf->lun);
+ if (hdr_lun != task->sc->device->lun)
+ return 0;
+ /* fall through */
+ case ISCSI_TM_FUNC_TARGET_WARM_RESET:
+ /*
+ * Fail all SCSI cmd PDUs
+ */
+ if (opcode != ISCSI_OP_SCSI_DATA_OUT) {
+ iscsi_conn_printk(KERN_INFO, conn,
+ "task [op %x/%x itt "
+ "0x%x/0x%x] "
+ "rejected.\n",
+ task->hdr->opcode, opcode,
+ task->itt, task->hdr_itt);
+ return -EACCES;
+ }
+ /*
+ * And also all data-out PDUs in response to R2T
+ * if fast_abort is set.
+ */
+ if (conn->session->fast_abort) {
+ iscsi_conn_printk(KERN_INFO, conn,
+ "task [op %x/%x itt "
+ "0x%x/0x%x] fast abort.\n",
+ task->hdr->opcode, opcode,
+ task->itt, task->hdr_itt);
+ return -EACCES;
+ }
+ break;
+ case ISCSI_TM_FUNC_ABORT_TASK:
+ /*
+ * the caller has already checked if the task
+ * they want to abort was in the pending queue so if
+ * we are here the cmd pdu has gone out already, and
+ * we will only hit this for data-outs
+ */
+ if (opcode == ISCSI_OP_SCSI_DATA_OUT &&
+ task->hdr_itt == tmf->rtt) {
+ ISCSI_DBG_SESSION(conn->session,
+ "Preventing task %x/%x from sending "
+ "data-out due to abort task in "
+ "progress\n", task->itt,
+ task->hdr_itt);
+ return -EACCES;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+/**
* iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu
* @task: iscsi task
*
@@ -282,6 +364,10 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
itt_t itt;
int rc;
+ rc = iscsi_check_tmf_restrictions(task, ISCSI_OP_SCSI_CMD);
+ if (rc)
+ return rc;
+
if (conn->session->tt->alloc_pdu) {
rc = conn->session->tt->alloc_pdu(task, ISCSI_OP_SCSI_CMD);
if (rc)
@@ -577,12 +663,12 @@ static int iscsi_prep_mgmt_task(struct iscsi_conn *conn,
struct iscsi_session *session = conn->session;
struct iscsi_hdr *hdr = task->hdr;
struct iscsi_nopout *nop = (struct iscsi_nopout *)hdr;
+ uint8_t opcode = hdr->opcode & ISCSI_OPCODE_MASK;
if (conn->session->state == ISCSI_STATE_LOGGING_OUT)
return -ENOTCONN;
- if (hdr->opcode != (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) &&
- hdr->opcode != (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE))
+ if (opcode != ISCSI_OP_LOGIN && opcode != ISCSI_OP_TEXT)
nop->exp_statsn = cpu_to_be32(conn->exp_statsn);
/*
* pre-format CmdSN for outgoing PDU.
@@ -590,9 +676,12 @@ static int iscsi_prep_mgmt_task(struct iscsi_conn *conn,
nop->cmdsn = cpu_to_be32(session->cmdsn);
if (hdr->itt != RESERVED_ITT) {
/*
- * TODO: We always use immediate, so we never hit this.
+ * TODO: We always use immediate for normal session pdus.
* If we start to send tmfs or nops as non-immediate then
* we should start checking the cmdsn numbers for mgmt tasks.
+ *
+ * During discovery sessions iscsid sends TEXT as non immediate,
+ * but we always only send one PDU at a time.
*/
if (conn->c_stage == ISCSI_CONN_STARTED &&
!(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
@@ -620,22 +709,28 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
{
struct iscsi_session *session = conn->session;
struct iscsi_host *ihost = shost_priv(session->host);
+ uint8_t opcode = hdr->opcode & ISCSI_OPCODE_MASK;
struct iscsi_task *task;
itt_t itt;
if (session->state == ISCSI_STATE_TERMINATE)
return NULL;
- if (hdr->opcode == (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) ||
- hdr->opcode == (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE))
+ if (opcode == ISCSI_OP_LOGIN || opcode == ISCSI_OP_TEXT) {
/*
* Login and Text are sent serially, in
* request-followed-by-response sequence.
* Same task can be used. Same ITT must be used.
* Note that login_task is preallocated at conn_create().
*/
+ if (conn->login_task->state != ISCSI_TASK_FREE) {
+ iscsi_conn_printk(KERN_ERR, conn, "Login/Text in "
+ "progress. Cannot start new task.\n");
+ return NULL;
+ }
+
task = conn->login_task;
- else {
+ } else {
if (session->state != ISCSI_STATE_LOGGED_IN)
return NULL;
@@ -1357,6 +1452,7 @@ EXPORT_SYMBOL_GPL(iscsi_requeue_task);
**/
static int iscsi_data_xmit(struct iscsi_conn *conn)
{
+ struct iscsi_task *task;
int rc = 0;
spin_lock_bh(&conn->session->lock);
@@ -1394,11 +1490,8 @@ check_mgmt:
/* process pending command queue */
while (!list_empty(&conn->cmdqueue)) {
- if (conn->tmf_state == TMF_QUEUED)
- break;
-
- conn->task = list_entry(conn->cmdqueue.next,
- struct iscsi_task, running);
+ conn->task = list_entry(conn->cmdqueue.next, struct iscsi_task,
+ running);
list_del_init(&conn->task->running);
if (conn->session->state == ISCSI_STATE_LOGGING_OUT) {
fail_scsi_task(conn->task, DID_IMM_RETRY);
@@ -1406,7 +1499,7 @@ check_mgmt:
}
rc = iscsi_prep_scsi_cmd_pdu(conn->task);
if (rc) {
- if (rc == -ENOMEM) {
+ if (rc == -ENOMEM || rc == -EACCES) {
list_add_tail(&conn->task->running,
&conn->cmdqueue);
conn->task = NULL;
@@ -1428,17 +1521,18 @@ check_mgmt:
}
while (!list_empty(&conn->requeue)) {
- if (conn->session->fast_abort && conn->tmf_state != TMF_INITIAL)
- break;
-
/*
* we always do fastlogout - conn stop code will clean up.
*/
if (conn->session->state == ISCSI_STATE_LOGGING_OUT)
break;
- conn->task = list_entry(conn->requeue.next,
- struct iscsi_task, running);
+ task = list_entry(conn->requeue.next, struct iscsi_task,
+ running);
+ if (iscsi_check_tmf_restrictions(task, ISCSI_OP_SCSI_DATA_OUT))
+ break;
+
+ conn->task = task;
list_del_init(&conn->task->running);
conn->task->state = ISCSI_TASK_RUNNING;
rc = iscsi_xmit_task(conn);
@@ -1591,7 +1685,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
if (!ihost->workq) {
reason = iscsi_prep_scsi_cmd_pdu(task);
if (reason) {
- if (reason == -ENOMEM) {
+ if (reason == -ENOMEM || reason == -EACCES) {
reason = FAILURE_OOM;
goto prepd_reject;
} else {
@@ -1643,9 +1737,21 @@ fault:
}
EXPORT_SYMBOL_GPL(iscsi_queuecommand);
-int iscsi_change_queue_depth(struct scsi_device *sdev, int depth)
+int iscsi_change_queue_depth(struct scsi_device *sdev, int depth, int reason)
{
- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
+ switch (reason) {
+ case SCSI_QDEPTH_DEFAULT:
+ scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
+ break;
+ case SCSI_QDEPTH_QFULL:
+ scsi_track_queue_full(sdev, depth);
+ break;
+ case SCSI_QDEPTH_RAMP_UP:
+ scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
return sdev->queue_depth;
}
EXPORT_SYMBOL_GPL(iscsi_change_queue_depth);
@@ -1660,72 +1766,6 @@ int iscsi_target_alloc(struct scsi_target *starget)
}
EXPORT_SYMBOL_GPL(iscsi_target_alloc);
-void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session)
-{
- struct iscsi_session *session = cls_session->dd_data;
-
- spin_lock_bh(&session->lock);
- if (session->state != ISCSI_STATE_LOGGED_IN) {
- session->state = ISCSI_STATE_RECOVERY_FAILED;
- if (session->leadconn)
- wake_up(&session->leadconn->ehwait);
- }
- spin_unlock_bh(&session->lock);
-}
-EXPORT_SYMBOL_GPL(iscsi_session_recovery_timedout);
-
-int iscsi_eh_target_reset(struct scsi_cmnd *sc)
-{
- struct iscsi_cls_session *cls_session;
- struct iscsi_session *session;
- struct iscsi_conn *conn;
-
- cls_session = starget_to_session(scsi_target(sc->device));
- session = cls_session->dd_data;
- conn = session->leadconn;
-
- mutex_lock(&session->eh_mutex);
- spin_lock_bh(&session->lock);
- if (session->state == ISCSI_STATE_TERMINATE) {
-failed:
- ISCSI_DBG_EH(session,
- "failing target reset: Could not log back into "
- "target [age %d]\n",
- session->age);
- spin_unlock_bh(&session->lock);
- mutex_unlock(&session->eh_mutex);
- return FAILED;
- }
-
- spin_unlock_bh(&session->lock);
- mutex_unlock(&session->eh_mutex);
- /*
- * we drop the lock here but the leadconn cannot be destoyed while
- * we are in the scsi eh
- */
- iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
-
- ISCSI_DBG_EH(session, "wait for relogin\n");
- wait_event_interruptible(conn->ehwait,
- session->state == ISCSI_STATE_TERMINATE ||
- session->state == ISCSI_STATE_LOGGED_IN ||
- session->state == ISCSI_STATE_RECOVERY_FAILED);
- if (signal_pending(current))
- flush_signals(current);
-
- mutex_lock(&session->eh_mutex);
- spin_lock_bh(&session->lock);
- if (session->state == ISCSI_STATE_LOGGED_IN) {
- ISCSI_DBG_EH(session,
- "target reset succeeded\n");
- } else
- goto failed;
- spin_unlock_bh(&session->lock);
- mutex_unlock(&session->eh_mutex);
- return SUCCESS;
-}
-EXPORT_SYMBOL_GPL(iscsi_eh_target_reset);
-
static void iscsi_tmf_timedout(unsigned long data)
{
struct iscsi_conn *conn = (struct iscsi_conn *)data;
@@ -2108,6 +2148,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
spin_lock_bh(&session->lock);
fail_scsi_task(task, DID_ABORT);
conn->tmf_state = TMF_INITIAL;
+ memset(hdr, 0, sizeof(*hdr));
spin_unlock_bh(&session->lock);
iscsi_start_tx(conn);
goto success_unlocked;
@@ -2118,6 +2159,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
case TMF_NOT_FOUND:
if (!sc->SCp.ptr) {
conn->tmf_state = TMF_INITIAL;
+ memset(hdr, 0, sizeof(*hdr));
/* task completed before tmf abort response */
ISCSI_DBG_EH(session, "sc completed while abort in "
"progress\n");
@@ -2212,6 +2254,7 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc)
iscsi_suspend_tx(conn);
spin_lock_bh(&session->lock);
+ memset(hdr, 0, sizeof(*hdr));
fail_scsi_tasks(conn, sc->device->lun, DID_ERROR);
conn->tmf_state = TMF_INITIAL;
spin_unlock_bh(&session->lock);
@@ -2229,6 +2272,172 @@ done:
}
EXPORT_SYMBOL_GPL(iscsi_eh_device_reset);
+void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session)
+{
+ struct iscsi_session *session = cls_session->dd_data;
+
+ spin_lock_bh(&session->lock);
+ if (session->state != ISCSI_STATE_LOGGED_IN) {
+ session->state = ISCSI_STATE_RECOVERY_FAILED;
+ if (session->leadconn)
+ wake_up(&session->leadconn->ehwait);
+ }
+ spin_unlock_bh(&session->lock);
+}
+EXPORT_SYMBOL_GPL(iscsi_session_recovery_timedout);
+
+/**
+ * iscsi_eh_session_reset - drop session and attempt relogin
+ * @sc: scsi command
+ *
+ * This function will wait for a relogin, session termination from
+ * userspace, or a recovery/replacement timeout.
+ */
+static int iscsi_eh_session_reset(struct scsi_cmnd *sc)
+{
+ struct iscsi_cls_session *cls_session;
+ struct iscsi_session *session;
+ struct iscsi_conn *conn;
+
+ cls_session = starget_to_session(scsi_target(sc->device));
+ session = cls_session->dd_data;
+ conn = session->leadconn;
+
+ mutex_lock(&session->eh_mutex);
+ spin_lock_bh(&session->lock);
+ if (session->state == ISCSI_STATE_TERMINATE) {
+failed:
+ ISCSI_DBG_EH(session,
+ "failing session reset: Could not log back into "
+ "%s, %s [age %d]\n", session->targetname,
+ conn->persistent_address, session->age);
+ spin_unlock_bh(&session->lock);
+ mutex_unlock(&session->eh_mutex);
+ return FAILED;
+ }
+
+ spin_unlock_bh(&session->lock);
+ mutex_unlock(&session->eh_mutex);
+ /*
+ * we drop the lock here but the leadconn cannot be destoyed while
+ * we are in the scsi eh
+ */
+ iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+
+ ISCSI_DBG_EH(session, "wait for relogin\n");
+ wait_event_interruptible(conn->ehwait,
+ session->state == ISCSI_STATE_TERMINATE ||
+ session->state == ISCSI_STATE_LOGGED_IN ||
+ session->state == ISCSI_STATE_RECOVERY_FAILED);
+ if (signal_pending(current))
+ flush_signals(current);
+
+ mutex_lock(&session->eh_mutex);
+ spin_lock_bh(&session->lock);
+ if (session->state == ISCSI_STATE_LOGGED_IN) {
+ ISCSI_DBG_EH(session,
+ "session reset succeeded for %s,%s\n",
+ session->targetname, conn->persistent_address);
+ } else
+ goto failed;
+ spin_unlock_bh(&session->lock);
+ mutex_unlock(&session->eh_mutex);
+ return SUCCESS;
+}
+
+static void iscsi_prep_tgt_reset_pdu(struct scsi_cmnd *sc, struct iscsi_tm *hdr)
+{
+ memset(hdr, 0, sizeof(*hdr));
+ hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE;
+ hdr->flags = ISCSI_TM_FUNC_TARGET_WARM_RESET & ISCSI_FLAG_TM_FUNC_MASK;
+ hdr->flags |= ISCSI_FLAG_CMD_FINAL;
+ hdr->rtt = RESERVED_ITT;
+}
+
+/**
+ * iscsi_eh_target_reset - reset target
+ * @sc: scsi command
+ *
+ * This will attempt to send a warm target reset. If that fails
+ * then we will drop the session and attempt ERL0 recovery.
+ */
+int iscsi_eh_target_reset(struct scsi_cmnd *sc)
+{
+ struct iscsi_cls_session *cls_session;
+ struct iscsi_session *session;
+ struct iscsi_conn *conn;
+ struct iscsi_tm *hdr;
+ int rc = FAILED;
+
+ cls_session = starget_to_session(scsi_target(sc->device));
+ session = cls_session->dd_data;
+
+ ISCSI_DBG_EH(session, "tgt Reset [sc %p tgt %s]\n", sc,
+ session->targetname);
+
+ mutex_lock(&session->eh_mutex);
+ spin_lock_bh(&session->lock);
+ /*
+ * Just check if we are not logged in. We cannot check for
+ * the phase because the reset could come from a ioctl.
+ */
+ if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN)
+ goto unlock;
+ conn = session->leadconn;
+
+ /* only have one tmf outstanding at a time */
+ if (conn->tmf_state != TMF_INITIAL)
+ goto unlock;
+ conn->tmf_state = TMF_QUEUED;
+
+ hdr = &conn->tmhdr;
+ iscsi_prep_tgt_reset_pdu(sc, hdr);
+
+ if (iscsi_exec_task_mgmt_fn(conn, hdr, session->age,
+ session->tgt_reset_timeout)) {
+ rc = FAILED;
+ goto unlock;
+ }
+
+ switch (conn->tmf_state) {
+ case TMF_SUCCESS:
+ break;
+ case TMF_TIMEDOUT:
+ spin_unlock_bh(&session->lock);
+ iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+ goto done;
+ default:
+ conn->tmf_state = TMF_INITIAL;
+ goto unlock;
+ }
+
+ rc = SUCCESS;
+ spin_unlock_bh(&session->lock);
+
+ iscsi_suspend_tx(conn);
+
+ spin_lock_bh(&session->lock);
+ memset(hdr, 0, sizeof(*hdr));
+ fail_scsi_tasks(conn, -1, DID_ERROR);
+ conn->tmf_state = TMF_INITIAL;
+ spin_unlock_bh(&session->lock);
+
+ iscsi_start_tx(conn);
+ goto done;
+
+unlock:
+ spin_unlock_bh(&session->lock);
+done:
+ ISCSI_DBG_EH(session, "tgt %s reset result = %s\n", session->targetname,
+ rc == SUCCESS ? "SUCCESS" : "FAILED");
+ mutex_unlock(&session->eh_mutex);
+
+ if (rc == FAILED)
+ rc = iscsi_eh_session_reset(sc);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(iscsi_eh_target_reset);
+
/*
* Pre-allocate a pool of @max items of @item_size. By default, the pool
* should be accessed via kfifo_{get,put} on q->queue.
@@ -2495,6 +2704,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
session->host = shost;
session->state = ISCSI_STATE_FREE;
session->fast_abort = 1;
+ session->tgt_reset_timeout = 30;
session->lu_reset_timeout = 15;
session->abort_timeout = 10;
session->scsi_cmds_max = scsi_cmds;
@@ -2856,6 +3066,7 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
spin_lock_bh(&session->lock);
fail_scsi_tasks(conn, -1, DID_TRANSPORT_DISRUPTED);
fail_mgmt_tasks(session, conn);
+ memset(&conn->tmhdr, 0, sizeof(conn->tmhdr));
spin_unlock_bh(&session->lock);
mutex_unlock(&session->eh_mutex);
}
@@ -2932,6 +3143,9 @@ int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
case ISCSI_PARAM_LU_RESET_TMO:
sscanf(buf, "%d", &session->lu_reset_timeout);
break;
+ case ISCSI_PARAM_TGT_RESET_TMO:
+ sscanf(buf, "%d", &session->tgt_reset_timeout);
+ break;
case ISCSI_PARAM_PING_TMO:
sscanf(buf, "%d", &conn->ping_timeout);
break;
@@ -3031,6 +3245,9 @@ int iscsi_session_get_param(struct iscsi_cls_session *cls_session,
case ISCSI_PARAM_LU_RESET_TMO:
len = sprintf(buf, "%d\n", session->lu_reset_timeout);
break;
+ case ISCSI_PARAM_TGT_RESET_TMO:
+ len = sprintf(buf, "%d\n", session->tgt_reset_timeout);
+ break;
case ISCSI_PARAM_INITIAL_R2T_EN:
len = sprintf(buf, "%d\n", session->initial_r2t_en);
break;
diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c
index 2e0746d..ca25ee5 100644
--- a/drivers/scsi/libiscsi_tcp.c
+++ b/drivers/scsi/libiscsi_tcp.c
@@ -1004,7 +1004,7 @@ static struct iscsi_r2t_info *iscsi_tcp_get_curr_r2t(struct iscsi_task *task)
* iscsi_tcp_task_xmit - xmit normal PDU task
* @task: iscsi command task
*
- * We're expected to return 0 when everything was transmitted succesfully,
+ * We're expected to return 0 when everything was transmitted successfully,
* -EAGAIN if there's still data in the queue, or != 0 for any other kind
* of error.
*/
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index 1c558d3..14b1319 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -820,10 +820,14 @@ void sas_slave_destroy(struct scsi_device *scsi_dev)
ata_port_disable(dev->sata_dev.ap);
}
-int sas_change_queue_depth(struct scsi_device *scsi_dev, int new_depth)
+int sas_change_queue_depth(struct scsi_device *scsi_dev, int new_depth,
+ int reason)
{
int res = min(new_depth, SAS_MAX_QD);
+ if (reason != SCSI_QDEPTH_DEFAULT)
+ return -EOPNOTSUPP;
+
if (scsi_dev->tagged_supported)
scsi_adjust_queue_depth(scsi_dev, scsi_get_tag_type(scsi_dev),
res);
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index aa10f79..1cc23a6 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -109,7 +109,8 @@ struct hbq_dmabuf {
struct lpfc_dmabuf dbuf;
uint32_t size;
uint32_t tag;
- struct lpfc_rcqe rcqe;
+ struct lpfc_cq_event cq_event;
+ unsigned long time_stamp;
};
/* Priority bit. Set value to exceed low water mark in lpfc_mem. */
@@ -201,6 +202,7 @@ struct lpfc_stats {
uint32_t elsRcvLIRR;
uint32_t elsRcvRPS;
uint32_t elsRcvRPL;
+ uint32_t elsRcvRRQ;
uint32_t elsXmitFLOGI;
uint32_t elsXmitFDISC;
uint32_t elsXmitPLOGI;
@@ -289,8 +291,8 @@ struct lpfc_vport {
uint16_t vpi;
uint16_t vfi;
- uint8_t vfi_state;
-#define LPFC_VFI_REGISTERED 0x1
+ uint8_t vpi_state;
+#define LPFC_VPI_REGISTERED 0x1
uint32_t fc_flag; /* FC flags */
/* Several of these flags are HBA centric and should be moved to
@@ -405,6 +407,7 @@ struct lpfc_vport {
uint8_t stat_data_enabled;
uint8_t stat_data_blocked;
struct list_head rcv_buffer_list;
+ unsigned long rcv_buffer_time_stamp;
uint32_t vport_flag;
#define STATIC_VPORT 1
};
@@ -527,13 +530,16 @@ struct lpfc_hba {
#define HBA_ERATT_HANDLED 0x1 /* This flag is set when eratt handled */
#define DEFER_ERATT 0x2 /* Deferred error attention in progress */
#define HBA_FCOE_SUPPORT 0x4 /* HBA function supports FCOE */
-#define HBA_RECEIVE_BUFFER 0x8 /* Rcv buffer posted to worker thread */
+#define HBA_SP_QUEUE_EVT 0x8 /* Slow-path qevt posted to worker thread*/
#define HBA_POST_RECEIVE_BUFFER 0x10 /* Rcv buffers need to be posted */
#define FCP_XRI_ABORT_EVENT 0x20
#define ELS_XRI_ABORT_EVENT 0x40
#define ASYNC_EVENT 0x80
#define LINK_DISABLED 0x100 /* Link disabled by user */
#define FCF_DISC_INPROGRESS 0x200 /* FCF discovery in progress */
+#define HBA_FIP_SUPPORT 0x400 /* FIP support in HBA */
+#define HBA_AER_ENABLED 0x800 /* AER enabled with HBA */
+ uint32_t fcp_ring_in_use; /* When polling test if intr-hndlr active*/
struct lpfc_dmabuf slim2p;
MAILBOX_t *mbox;
@@ -551,6 +557,7 @@ struct lpfc_hba {
uint8_t fc_linkspeed; /* Link speed after last READ_LA */
uint32_t fc_eventTag; /* event tag for link attention */
+ uint32_t link_events;
/* These fields used to be binfo */
uint32_t fc_pref_DID; /* preferred D_ID */
@@ -604,8 +611,8 @@ struct lpfc_hba {
uint32_t cfg_enable_hba_reset;
uint32_t cfg_enable_hba_heartbeat;
uint32_t cfg_enable_bg;
- uint32_t cfg_enable_fip;
uint32_t cfg_log_verbose;
+ uint32_t cfg_aer_support;
lpfc_vpd_t vpd; /* vital product data */
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index e1a30a1..91542f7 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -23,12 +23,14 @@
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
+#include <linux/aer.h>
#include <scsi/scsi.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_transport_fc.h>
+#include <scsi/fc/fc_fs.h>
#include "lpfc_hw4.h"
#include "lpfc_hw.h"
@@ -98,6 +100,28 @@ lpfc_drvr_version_show(struct device *dev, struct device_attribute *attr,
return snprintf(buf, PAGE_SIZE, LPFC_MODULE_DESC "\n");
}
+/**
+ * lpfc_enable_fip_show - Return the fip mode of the HBA
+ * @dev: class unused variable.
+ * @attr: device attribute, not used.
+ * @buf: on return contains the module description text.
+ *
+ * Returns: size of formatted string.
+ **/
+static ssize_t
+lpfc_enable_fip_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+
+ if (phba->hba_flag & HBA_FIP_SUPPORT)
+ return snprintf(buf, PAGE_SIZE, "1\n");
+ else
+ return snprintf(buf, PAGE_SIZE, "0\n");
+}
+
static ssize_t
lpfc_bg_info_show(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -654,7 +678,7 @@ lpfc_selective_reset(struct lpfc_hba *phba)
* Notes:
* Assumes any error from lpfc_selective_reset() will be negative.
* If lpfc_selective_reset() returns zero then the length of the buffer
- * is returned which indicates succcess
+ * is returned which indicates success
*
* Returns:
* -EINVAL if the buffer does not contain the string "selective"
@@ -762,9 +786,15 @@ lpfc_board_mode_store(struct device *dev, struct device_attribute *attr,
} else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0)
status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
else if (strncmp(buf, "warm", sizeof("warm") - 1) == 0)
- status = lpfc_do_offline(phba, LPFC_EVT_WARM_START);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ return -EINVAL;
+ else
+ status = lpfc_do_offline(phba, LPFC_EVT_WARM_START);
else if (strncmp(buf, "error", sizeof("error") - 1) == 0)
- status = lpfc_do_offline(phba, LPFC_EVT_KILL);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ return -EINVAL;
+ else
+ status = lpfc_do_offline(phba, LPFC_EVT_KILL);
else
return -EINVAL;
@@ -1126,6 +1156,9 @@ lpfc_poll_store(struct device *dev, struct device_attribute *attr,
if ((val & 0x3) != val)
return -EINVAL;
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ val = 0;
+
spin_lock_irq(&phba->hbalock);
old_val = phba->cfg_poll;
@@ -1589,6 +1622,7 @@ static DEVICE_ATTR(num_discovered_ports, S_IRUGO,
static DEVICE_ATTR(menlo_mgmt_mode, S_IRUGO, lpfc_mlomgmt_show, NULL);
static DEVICE_ATTR(nport_evt_cnt, S_IRUGO, lpfc_nport_evt_cnt_show, NULL);
static DEVICE_ATTR(lpfc_drvr_version, S_IRUGO, lpfc_drvr_version_show, NULL);
+static DEVICE_ATTR(lpfc_enable_fip, S_IRUGO, lpfc_enable_fip_show, NULL);
static DEVICE_ATTR(board_mode, S_IRUGO | S_IWUSR,
lpfc_board_mode_show, lpfc_board_mode_store);
static DEVICE_ATTR(issue_reset, S_IWUSR, NULL, lpfc_issue_reset);
@@ -2759,6 +2793,196 @@ static DEVICE_ATTR(lpfc_link_speed, S_IRUGO | S_IWUSR,
lpfc_link_speed_show, lpfc_link_speed_store);
/*
+# lpfc_aer_support: Support PCIe device Advanced Error Reporting (AER)
+# 0 = aer disabled or not supported
+# 1 = aer supported and enabled (default)
+# Value range is [0,1]. Default value is 1.
+*/
+
+/**
+ * lpfc_aer_support_store - Set the adapter for aer support
+ *
+ * @dev: class device that is converted into a Scsi_host.
+ * @attr: device attribute, not used.
+ * @buf: containing the string "selective".
+ * @count: unused variable.
+ *
+ * Description:
+ * If the val is 1 and currently the device's AER capability was not
+ * enabled, invoke the kernel's enable AER helper routine, trying to
+ * enable the device's AER capability. If the helper routine enabling
+ * AER returns success, update the device's cfg_aer_support flag to
+ * indicate AER is supported by the device; otherwise, if the device
+ * AER capability is already enabled to support AER, then do nothing.
+ *
+ * If the val is 0 and currently the device's AER support was enabled,
+ * invoke the kernel's disable AER helper routine. After that, update
+ * the device's cfg_aer_support flag to indicate AER is not supported
+ * by the device; otherwise, if the device AER capability is already
+ * disabled from supporting AER, then do nothing.
+ *
+ * Returns:
+ * length of the buf on success if val is in range the intended mode
+ * is supported.
+ * -EINVAL if val out of range or intended mode is not supported.
+ **/
+static ssize_t
+lpfc_aer_support_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ int val = 0, rc = -EINVAL;
+
+ /* AER not supported on OC devices yet */
+ if (phba->pci_dev_grp == LPFC_PCI_DEV_OC)
+ return -EPERM;
+ if (!isdigit(buf[0]))
+ return -EINVAL;
+ if (sscanf(buf, "%i", &val) != 1)
+ return -EINVAL;
+
+ switch (val) {
+ case 0:
+ if (phba->hba_flag & HBA_AER_ENABLED) {
+ rc = pci_disable_pcie_error_reporting(phba->pcidev);
+ if (!rc) {
+ spin_lock_irq(&phba->hbalock);
+ phba->hba_flag &= ~HBA_AER_ENABLED;
+ spin_unlock_irq(&phba->hbalock);
+ phba->cfg_aer_support = 0;
+ rc = strlen(buf);
+ } else
+ rc = -EPERM;
+ } else {
+ phba->cfg_aer_support = 0;
+ rc = strlen(buf);
+ }
+ break;
+ case 1:
+ if (!(phba->hba_flag & HBA_AER_ENABLED)) {
+ rc = pci_enable_pcie_error_reporting(phba->pcidev);
+ if (!rc) {
+ spin_lock_irq(&phba->hbalock);
+ phba->hba_flag |= HBA_AER_ENABLED;
+ spin_unlock_irq(&phba->hbalock);
+ phba->cfg_aer_support = 1;
+ rc = strlen(buf);
+ } else
+ rc = -EPERM;
+ } else {
+ phba->cfg_aer_support = 1;
+ rc = strlen(buf);
+ }
+ break;
+ default:
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+
+static int lpfc_aer_support = 1;
+module_param(lpfc_aer_support, int, 1);
+MODULE_PARM_DESC(lpfc_aer_support, "Enable PCIe device AER support");
+lpfc_param_show(aer_support)
+
+/**
+ * lpfc_aer_support_init - Set the initial adapters aer support flag
+ * @phba: lpfc_hba pointer.
+ * @val: link speed value.
+ *
+ * Description:
+ * If val is in a valid range [0,1], then set the adapter's initial
+ * cfg_aer_support field. It will be up to the driver's probe_one
+ * routine to determine whether the device's AER support can be set
+ * or not.
+ *
+ * Notes:
+ * If the value is not in range log a kernel error message, and
+ * choose the default value of setting AER support and return.
+ *
+ * Returns:
+ * zero if val saved.
+ * -EINVAL val out of range
+ **/
+static int
+lpfc_aer_support_init(struct lpfc_hba *phba, int val)
+{
+ /* AER not supported on OC devices yet */
+ if (phba->pci_dev_grp == LPFC_PCI_DEV_OC) {
+ phba->cfg_aer_support = 0;
+ return -EPERM;
+ }
+
+ if (val == 0 || val == 1) {
+ phba->cfg_aer_support = val;
+ return 0;
+ }
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2712 lpfc_aer_support attribute value %d out "
+ "of range, allowed values are 0|1, setting it "
+ "to default value of 1\n", val);
+ /* By default, try to enable AER on a device */
+ phba->cfg_aer_support = 1;
+ return -EINVAL;
+}
+
+static DEVICE_ATTR(lpfc_aer_support, S_IRUGO | S_IWUSR,
+ lpfc_aer_support_show, lpfc_aer_support_store);
+
+/**
+ * lpfc_aer_cleanup_state - Clean up aer state to the aer enabled device
+ * @dev: class device that is converted into a Scsi_host.
+ * @attr: device attribute, not used.
+ * @buf: containing the string "selective".
+ * @count: unused variable.
+ *
+ * Description:
+ * If the @buf contains 1 and the device currently has the AER support
+ * enabled, then invokes the kernel AER helper routine
+ * pci_cleanup_aer_uncorrect_error_status to clean up the uncorrectable
+ * error status register.
+ *
+ * Notes:
+ *
+ * Returns:
+ * -EINVAL if the buf does not contain the 1 or the device is not currently
+ * enabled with the AER support.
+ **/
+static ssize_t
+lpfc_aer_cleanup_state(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ int val, rc = -1;
+
+ /* AER not supported on OC devices yet */
+ if (phba->pci_dev_grp == LPFC_PCI_DEV_OC)
+ return -EPERM;
+ if (!isdigit(buf[0]))
+ return -EINVAL;
+ if (sscanf(buf, "%i", &val) != 1)
+ return -EINVAL;
+ if (val != 1)
+ return -EINVAL;
+
+ if (phba->hba_flag & HBA_AER_ENABLED)
+ rc = pci_cleanup_aer_uncorrect_error_status(phba->pcidev);
+
+ if (rc == 0)
+ return strlen(buf);
+ else
+ return -EPERM;
+}
+
+static DEVICE_ATTR(lpfc_aer_state_cleanup, S_IWUSR, NULL,
+ lpfc_aer_cleanup_state);
+
+/*
# lpfc_fcp_class: Determines FC class to use for the FCP protocol.
# Value range is [2,3]. Default value is 3.
*/
@@ -2846,7 +3070,7 @@ LPFC_ATTR_R(multi_ring_support, 1, 1, 2, "Determines number of primary "
# identifies what rctl value to configure the additional ring for.
# Value range is [1,0xff]. Default value is 4 (Unsolicated Data).
*/
-LPFC_ATTR_R(multi_ring_rctl, FC_UNSOL_DATA, 1,
+LPFC_ATTR_R(multi_ring_rctl, FC_RCTL_DD_UNSOL_DATA, 1,
255, "Identifies RCTL for additional ring configuration");
/*
@@ -2854,7 +3078,7 @@ LPFC_ATTR_R(multi_ring_rctl, FC_UNSOL_DATA, 1,
# identifies what type value to configure the additional ring for.
# Value range is [1,0xff]. Default value is 5 (LLC/SNAP).
*/
-LPFC_ATTR_R(multi_ring_type, FC_LLC_SNAP, 1,
+LPFC_ATTR_R(multi_ring_type, FC_TYPE_IP, 1,
255, "Identifies TYPE for additional ring configuration");
/*
@@ -2947,15 +3171,6 @@ LPFC_ATTR_R(enable_hba_heartbeat, 1, 0, 1, "Enable HBA Heartbeat.");
LPFC_ATTR_R(enable_bg, 0, 0, 1, "Enable BlockGuard Support");
/*
-# lpfc_enable_fip: When set, FIP is required to start discovery. If not
-# set, the driver will add an FCF record manually if the port has no
-# FCF records available and start discovery.
-# Value range is [0,1]. Default value is 1 (enabled)
-*/
-LPFC_ATTR_RW(enable_fip, 0, 0, 1, "Enable FIP Discovery");
-
-
-/*
# lpfc_prot_mask: i
# - Bit mask of host protection capabilities used to register with the
# SCSI mid-layer
@@ -3013,6 +3228,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
&dev_attr_num_discovered_ports,
&dev_attr_menlo_mgmt_mode,
&dev_attr_lpfc_drvr_version,
+ &dev_attr_lpfc_enable_fip,
&dev_attr_lpfc_temp_sensor,
&dev_attr_lpfc_log_verbose,
&dev_attr_lpfc_lun_queue_depth,
@@ -3020,7 +3236,6 @@ struct device_attribute *lpfc_hba_attrs[] = {
&dev_attr_lpfc_peer_port_login,
&dev_attr_lpfc_nodev_tmo,
&dev_attr_lpfc_devloss_tmo,
- &dev_attr_lpfc_enable_fip,
&dev_attr_lpfc_fcp_class,
&dev_attr_lpfc_use_adisc,
&dev_attr_lpfc_ack0,
@@ -3061,6 +3276,8 @@ struct device_attribute *lpfc_hba_attrs[] = {
&dev_attr_lpfc_max_scsicmpl_time,
&dev_attr_lpfc_stat_data_ctrl,
&dev_attr_lpfc_prot_sg_seg_cnt,
+ &dev_attr_lpfc_aer_support,
+ &dev_attr_lpfc_aer_state_cleanup,
NULL,
};
@@ -3073,7 +3290,6 @@ struct device_attribute *lpfc_vport_attrs[] = {
&dev_attr_lpfc_lun_queue_depth,
&dev_attr_lpfc_nodev_tmo,
&dev_attr_lpfc_devloss_tmo,
- &dev_attr_lpfc_enable_fip,
&dev_attr_lpfc_hba_queue_depth,
&dev_attr_lpfc_peer_port_login,
&dev_attr_lpfc_restrict_login,
@@ -3147,7 +3363,7 @@ sysfs_ctlreg_write(struct kobject *kobj, struct bin_attribute *bin_attr,
* sysfs_ctlreg_read - Read method for reading from ctlreg
* @kobj: kernel kobject that contains the kernel class device.
* @bin_attr: kernel attributes passed to us.
- * @buf: if succesful contains the data from the adapter IOREG space.
+ * @buf: if successful contains the data from the adapter IOREG space.
* @off: offset into buffer to beginning of data.
* @count: bytes to transfer.
*
@@ -3815,7 +4031,11 @@ lpfc_get_stats(struct Scsi_Host *shost)
hs->invalid_crc_count -= lso->invalid_crc_count;
hs->error_frames -= lso->error_frames;
- if (phba->fc_topology == TOPOLOGY_LOOP) {
+ if (phba->hba_flag & HBA_FCOE_SUPPORT) {
+ hs->lip_count = -1;
+ hs->nos_count = (phba->link_events >> 1);
+ hs->nos_count -= lso->link_events;
+ } else if (phba->fc_topology == TOPOLOGY_LOOP) {
hs->lip_count = (phba->fc_eventTag >> 1);
hs->lip_count -= lso->link_events;
hs->nos_count = -1;
@@ -3906,7 +4126,10 @@ lpfc_reset_stats(struct Scsi_Host *shost)
lso->invalid_tx_word_count = pmb->un.varRdLnk.invalidXmitWord;
lso->invalid_crc_count = pmb->un.varRdLnk.crcCnt;
lso->error_frames = pmb->un.varRdLnk.crcCnt;
- lso->link_events = (phba->fc_eventTag >> 1);
+ if (phba->hba_flag & HBA_FCOE_SUPPORT)
+ lso->link_events = (phba->link_events >> 1);
+ else
+ lso->link_events = (phba->fc_eventTag >> 1);
psli->stats_start = get_seconds();
@@ -4222,14 +4445,17 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
lpfc_enable_hba_reset_init(phba, lpfc_enable_hba_reset);
lpfc_enable_hba_heartbeat_init(phba, lpfc_enable_hba_heartbeat);
lpfc_enable_bg_init(phba, lpfc_enable_bg);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ phba->cfg_poll = 0;
+ else
phba->cfg_poll = lpfc_poll;
phba->cfg_soft_wwnn = 0L;
phba->cfg_soft_wwpn = 0L;
lpfc_sg_seg_cnt_init(phba, lpfc_sg_seg_cnt);
lpfc_prot_sg_seg_cnt_init(phba, lpfc_prot_sg_seg_cnt);
lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth);
- lpfc_enable_fip_init(phba, lpfc_enable_fip);
lpfc_hba_log_verbose_init(phba, lpfc_log_verbose);
+ lpfc_aer_support_init(phba, lpfc_aer_support);
return;
}
diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c
index da6bf5a..a5d9048 100644
--- a/drivers/scsi/lpfc/lpfc_bsg.c
+++ b/drivers/scsi/lpfc/lpfc_bsg.c
@@ -26,6 +26,7 @@
#include <scsi/scsi_host.h>
#include <scsi/scsi_transport_fc.h>
#include <scsi/scsi_bsg_fc.h>
+#include <scsi/fc/fc_fs.h>
#include "lpfc_hw4.h"
#include "lpfc_hw.h"
@@ -148,8 +149,8 @@ lpfc_bsg_rport_ct(struct fc_bsg_job *job)
cmd->ulpCommand = CMD_GEN_REQUEST64_CR;
cmd->un.genreq64.w5.hcsw.Fctl = (SI | LA);
cmd->un.genreq64.w5.hcsw.Dfctl = 0;
- cmd->un.genreq64.w5.hcsw.Rctl = FC_UNSOL_CTL;
- cmd->un.genreq64.w5.hcsw.Type = FC_COMMON_TRANSPORT_ULP;
+ cmd->un.genreq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL;
+ cmd->un.genreq64.w5.hcsw.Type = FC_TYPE_CT;
cmd->ulpBdeCount = 1;
cmd->ulpLe = 1;
cmd->ulpClass = CLASS3;
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index 0830f37..650494d 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -49,6 +49,8 @@ void lpfc_init_link(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t);
void lpfc_request_features(struct lpfc_hba *, struct lpfcMboxq *);
struct lpfc_vport *lpfc_find_vport_by_did(struct lpfc_hba *, uint32_t);
+void lpfc_cleanup_rcv_buffers(struct lpfc_vport *);
+void lpfc_rcv_seq_check_edtov(struct lpfc_vport *);
void lpfc_cleanup_rpis(struct lpfc_vport *, int);
int lpfc_linkdown(struct lpfc_hba *);
void lpfc_linkdown_port(struct lpfc_vport *);
@@ -144,6 +146,8 @@ void lpfc_hb_timeout_handler(struct lpfc_hba *);
void lpfc_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
struct lpfc_iocbq *);
+void lpfc_sli4_ct_abort_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
+ struct lpfc_iocbq *);
int lpfc_ns_cmd(struct lpfc_vport *, int, uint8_t, uint32_t);
int lpfc_fdmi_cmd(struct lpfc_vport *, struct lpfc_nodelist *, int);
void lpfc_fdmi_tmo(unsigned long);
@@ -188,7 +192,7 @@ int lpfc_mbox_tmo_val(struct lpfc_hba *, int);
void lpfc_init_vfi(struct lpfcMboxq *, struct lpfc_vport *);
void lpfc_reg_vfi(struct lpfcMboxq *, struct lpfc_vport *, dma_addr_t);
void lpfc_init_vpi(struct lpfc_hba *, struct lpfcMboxq *, uint16_t);
-void lpfc_unreg_vfi(struct lpfcMboxq *, uint16_t);
+void lpfc_unreg_vfi(struct lpfcMboxq *, struct lpfc_vport *);
void lpfc_reg_fcfi(struct lpfc_hba *, struct lpfcMboxq *);
void lpfc_unreg_fcfi(struct lpfcMboxq *, uint16_t);
void lpfc_resume_rpi(struct lpfcMboxq *, struct lpfc_nodelist *);
@@ -212,7 +216,10 @@ void lpfc_stop_vport_timers(struct lpfc_vport *);
void lpfc_poll_timeout(unsigned long ptr);
void lpfc_poll_start_timer(struct lpfc_hba *);
void lpfc_poll_eratt(unsigned long);
-void lpfc_sli_poll_fcp_ring(struct lpfc_hba *);
+int
+lpfc_sli_handle_fast_ring_event(struct lpfc_hba *,
+ struct lpfc_sli_ring *, uint32_t);
+
struct lpfc_iocbq * lpfc_sli_get_iocbq(struct lpfc_hba *);
void lpfc_sli_release_iocbq(struct lpfc_hba *, struct lpfc_iocbq *);
uint16_t lpfc_sli_next_iotag(struct lpfc_hba *, struct lpfc_iocbq *);
@@ -235,7 +242,7 @@ void lpfc_sli_mbox_sys_shutdown(struct lpfc_hba *);
int lpfc_sli_check_eratt(struct lpfc_hba *);
void lpfc_sli_handle_slow_ring_event(struct lpfc_hba *,
struct lpfc_sli_ring *, uint32_t);
-int lpfc_sli4_handle_received_buffer(struct lpfc_hba *);
+void lpfc_sli4_handle_received_buffer(struct lpfc_hba *, struct hbq_dmabuf *);
void lpfc_sli_def_mbox_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *);
int lpfc_sli_issue_iocb(struct lpfc_hba *, uint32_t,
struct lpfc_iocbq *, uint32_t);
@@ -361,6 +368,7 @@ void lpfc_stop_port(struct lpfc_hba *);
void lpfc_parse_fcoe_conf(struct lpfc_hba *, uint8_t *, uint32_t);
int lpfc_parse_vpd(struct lpfc_hba *, uint8_t *, int);
void lpfc_start_fdiscs(struct lpfc_hba *phba);
+struct lpfc_vport *lpfc_find_vport_by_vpid(struct lpfc_hba *, uint16_t);
#define ScsiResult(host_code, scsi_code) (((host_code) << 16) | scsi_code)
#define HBA_EVENT_RSCN 5
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index 9a1bd95..0ebcd9b 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -31,6 +31,7 @@
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_transport_fc.h>
+#include <scsi/fc/fc_fs.h>
#include "lpfc_hw4.h"
#include "lpfc_hw.h"
@@ -87,7 +88,6 @@ void
lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
struct lpfc_iocbq *piocbq)
{
-
struct lpfc_dmabuf *mp = NULL;
IOCB_t *icmd = &piocbq->iocb;
int i;
@@ -160,6 +160,39 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
}
}
+/**
+ * lpfc_sli4_ct_abort_unsol_event - Default handle for sli4 unsol abort
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to the driver internal I/O ring.
+ * @piocbq: Pointer to the IOCBQ.
+ *
+ * This function serves as the default handler for the sli4 unsolicited
+ * abort event. It shall be invoked when there is no application interface
+ * registered unsolicited abort handler. This handler does nothing but
+ * just simply releases the dma buffer used by the unsol abort event.
+ **/
+void
+lpfc_sli4_ct_abort_unsol_event(struct lpfc_hba *phba,
+ struct lpfc_sli_ring *pring,
+ struct lpfc_iocbq *piocbq)
+{
+ IOCB_t *icmd = &piocbq->iocb;
+ struct lpfc_dmabuf *bdeBuf;
+ uint32_t size;
+
+ /* Forward abort event to any process registered to receive ct event */
+ lpfc_bsg_ct_unsol_event(phba, pring, piocbq);
+
+ /* If there is no BDE associated with IOCB, there is nothing to do */
+ if (icmd->ulpBdeCount == 0)
+ return;
+ bdeBuf = piocbq->context2;
+ piocbq->context2 = NULL;
+ size = icmd->un.cont64[0].tus.f.bdeSize;
+ lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf, size);
+ lpfc_in_buf_free(phba, bdeBuf);
+}
+
static void
lpfc_free_ct_rsp(struct lpfc_hba *phba, struct lpfc_dmabuf *mlist)
{
@@ -304,8 +337,8 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
/* Fill in rest of iocb */
icmd->un.genreq64.w5.hcsw.Fctl = (SI | LA);
icmd->un.genreq64.w5.hcsw.Dfctl = 0;
- icmd->un.genreq64.w5.hcsw.Rctl = FC_UNSOL_CTL;
- icmd->un.genreq64.w5.hcsw.Type = FC_COMMON_TRANSPORT_ULP;
+ icmd->un.genreq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL;
+ icmd->un.genreq64.w5.hcsw.Type = FC_TYPE_CT;
if (!tmo) {
/* FC spec states we need 3 * ratov for CT requests */
@@ -363,9 +396,14 @@ lpfc_ct_cmd(struct lpfc_vport *vport, struct lpfc_dmabuf *inmp,
outmp = lpfc_alloc_ct_rsp(phba, cmdcode, bpl, rsp_size, &cnt);
if (!outmp)
return -ENOMEM;
-
+ /*
+ * Form the CT IOCB. The total number of BDEs in this IOCB
+ * is the single command plus response count from
+ * lpfc_alloc_ct_rsp.
+ */
+ cnt += 1;
status = lpfc_gen_req(vport, bmp, inmp, outmp, cmpl, ndlp, 0,
- cnt+1, 0, retry);
+ cnt, 0, retry);
if (status) {
lpfc_free_ct_rsp(phba, outmp);
return -ENOMEM;
@@ -501,6 +539,9 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
SLI_CTNS_GFF_ID,
0, Did) == 0)
vport->num_disc_nodes++;
+ else
+ lpfc_setup_disc_node
+ (vport, Did);
}
else {
lpfc_debugfs_disc_trc(vport,
@@ -1209,7 +1250,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
be16_to_cpu(SLI_CTNS_RFF_ID);
CtReq->un.rff.PortId = cpu_to_be32(vport->fc_myDID);
CtReq->un.rff.fbits = FC4_FEATURE_INIT;
- CtReq->un.rff.type_code = FC_FCP_DATA;
+ CtReq->un.rff.type_code = FC_TYPE_FCP;
cmpl = lpfc_cmpl_ct_cmd_rff_id;
break;
}
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c
index 8d0f0de..3915841 100644
--- a/drivers/scsi/lpfc/lpfc_debugfs.c
+++ b/drivers/scsi/lpfc/lpfc_debugfs.c
@@ -926,7 +926,7 @@ lpfc_debugfs_dumpData_open(struct inode *inode, struct file *file)
goto out;
/* Round to page boundry */
- printk(KERN_ERR "BLKGRD %s: _dump_buf_data=0x%p\n",
+ printk(KERN_ERR "9059 BLKGRD: %s: _dump_buf_data=0x%p\n",
__func__, _dump_buf_data);
debug->buffer = _dump_buf_data;
if (!debug->buffer) {
@@ -956,8 +956,8 @@ lpfc_debugfs_dumpDif_open(struct inode *inode, struct file *file)
goto out;
/* Round to page boundry */
- printk(KERN_ERR "BLKGRD %s: _dump_buf_dif=0x%p file=%s\n", __func__,
- _dump_buf_dif, file->f_dentry->d_name.name);
+ printk(KERN_ERR "9060 BLKGRD: %s: _dump_buf_dif=0x%p file=%s\n",
+ __func__, _dump_buf_dif, file->f_dentry->d_name.name);
debug->buffer = _dump_buf_dif;
if (!debug->buffer) {
kfree(debug);
@@ -1377,7 +1377,7 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
debugfs_create_dir(name, phba->hba_debugfs_root);
if (!vport->vport_debugfs_root) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
- "0417 Cant create debugfs");
+ "0417 Cant create debugfs\n");
goto debug_failed;
}
atomic_inc(&phba->debugfs_vport_count);
@@ -1430,7 +1430,7 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
vport, &lpfc_debugfs_op_nodelist);
if (!vport->debug_nodelist) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
- "0409 Cant create debugfs nodelist");
+ "0409 Cant create debugfs nodelist\n");
goto debug_failed;
}
debug_failed:
diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h
index 1142070..2851d75ff 100644
--- a/drivers/scsi/lpfc/lpfc_disc.h
+++ b/drivers/scsi/lpfc/lpfc_disc.h
@@ -19,7 +19,7 @@
*******************************************************************/
#define FC_MAX_HOLD_RSCN 32 /* max number of deferred RSCNs */
-#define FC_MAX_NS_RSP 65536 /* max size NameServer rsp */
+#define FC_MAX_NS_RSP 64512 /* max size NameServer rsp */
#define FC_MAXLOOP 126 /* max devices supported on a fc loop */
#define LPFC_DISC_FLOGI_TMO 10 /* Discovery FLOGI ratov */
@@ -105,8 +105,6 @@ struct lpfc_nodelist {
struct lpfc_vport *vport;
struct lpfc_work_evt els_retry_evt;
struct lpfc_work_evt dev_loss_evt;
- unsigned long last_ramp_up_time; /* jiffy of last ramp up */
- unsigned long last_q_full_time; /* jiffy of last queue full */
struct kref kref;
atomic_t cmd_pending;
uint32_t cmd_qdepth;
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 45337cd..ce52270 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -173,13 +173,26 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
* in FIP mode send FLOGI, FDISC and LOGO as FIP frames.
*/
if ((did == Fabric_DID) &&
- bf_get(lpfc_fip_flag, &phba->sli4_hba.sli4_flags) &&
+ (phba->hba_flag & HBA_FIP_SUPPORT) &&
((elscmd == ELS_CMD_FLOGI) ||
(elscmd == ELS_CMD_FDISC) ||
(elscmd == ELS_CMD_LOGO)))
- elsiocb->iocb_flag |= LPFC_FIP_ELS;
+ switch (elscmd) {
+ case ELS_CMD_FLOGI:
+ elsiocb->iocb_flag |= ((ELS_ID_FLOGI << LPFC_FIP_ELS_ID_SHIFT)
+ & LPFC_FIP_ELS_ID_MASK);
+ break;
+ case ELS_CMD_FDISC:
+ elsiocb->iocb_flag |= ((ELS_ID_FDISC << LPFC_FIP_ELS_ID_SHIFT)
+ & LPFC_FIP_ELS_ID_MASK);
+ break;
+ case ELS_CMD_LOGO:
+ elsiocb->iocb_flag |= ((ELS_ID_LOGO << LPFC_FIP_ELS_ID_SHIFT)
+ & LPFC_FIP_ELS_ID_MASK);
+ break;
+ }
else
- elsiocb->iocb_flag &= ~LPFC_FIP_ELS;
+ elsiocb->iocb_flag &= ~LPFC_FIP_ELS_ID_MASK;
icmd = &elsiocb->iocb;
@@ -591,7 +604,7 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
} else {
ndlp->nlp_type |= NLP_FABRIC;
lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
- if (vport->vfi_state & LPFC_VFI_REGISTERED) {
+ if (vport->vpi_state & LPFC_VPI_REGISTERED) {
lpfc_start_fdiscs(phba);
lpfc_do_scr_ns_plogi(phba, vport);
} else
@@ -802,7 +815,7 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
/* FLOGI completes successfully */
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
- "0101 FLOGI completes sucessfully "
+ "0101 FLOGI completes successfully "
"Data: x%x x%x x%x x%x\n",
irsp->un.ulpWord[4], sp->cmn.e_d_tov,
sp->cmn.w2.r_a_tov, sp->cmn.edtovResolution);
@@ -2452,6 +2465,7 @@ lpfc_els_retry_delay_handler(struct lpfc_nodelist *ndlp)
*/
del_timer_sync(&ndlp->nlp_delayfunc);
retry = ndlp->nlp_retry;
+ ndlp->nlp_retry = 0;
switch (cmd) {
case ELS_CMD_FLOGI:
@@ -2711,12 +2725,16 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
!lpfc_error_lost_link(irsp)) {
/* FLOGI retry policy */
retry = 1;
- maxretry = 48;
- if (cmdiocb->retry >= 32)
+ /* retry forever */
+ maxretry = 0;
+ if (cmdiocb->retry >= 100)
+ delay = 5000;
+ else if (cmdiocb->retry >= 32)
delay = 1000;
}
- if ((++cmdiocb->retry) >= maxretry) {
+ cmdiocb->retry++;
+ if (maxretry && (cmdiocb->retry >= maxretry)) {
phba->fc_stat.elsRetryExceeded++;
retry = 0;
}
@@ -4133,7 +4151,7 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
/* Indicate we are walking fc_rscn_id_list on this vport */
vport->fc_rscn_flush = 1;
spin_unlock_irq(shost->host_lock);
- /* Get the array count after sucessfully have the token */
+ /* Get the array count after successfully have the token */
rscn_cnt = vport->fc_rscn_id_cnt;
/* If we are already processing an RSCN, save the received
* RSCN payload buffer, cmdiocb->context2 to process later.
@@ -4503,6 +4521,29 @@ lpfc_els_rcv_lirr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
}
/**
+ * lpfc_els_rcv_rrq - Process an unsolicited rrq iocb
+ * @vport: pointer to a host virtual N_Port data structure.
+ * @cmdiocb: pointer to lpfc command iocb data structure.
+ * @ndlp: pointer to a node-list data structure.
+ *
+ * This routine processes a Reinstate Recovery Qualifier (RRQ) IOCB
+ * received as an ELS unsolicited event. A request to RRQ shall only
+ * be accepted if the Originator Nx_Port N_Port_ID or the Responder
+ * Nx_Port N_Port_ID of the target Exchange is the same as the
+ * N_Port_ID of the Nx_Port that makes the request. If the RRQ is
+ * not accepted, an LS_RJT with reason code "Unable to perform
+ * command request" and reason code explanation "Invalid Originator
+ * S_ID" shall be returned. For now, we just unconditionally accept
+ * RRQ from the target.
+ **/
+static void
+lpfc_els_rcv_rrq(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_nodelist *ndlp)
+{
+ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
+}
+
+/**
* lpfc_els_rsp_rps_acc - Completion callbk func for MBX_READ_LNK_STAT mbox cmd
* @phba: pointer to lpfc hba data structure.
* @pmb: pointer to the driver internal queue element for mailbox command.
@@ -5396,7 +5437,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
if (lpfc_els_chk_latt(vport))
goto dropit;
- /* Ignore traffic recevied during vport shutdown. */
+ /* Ignore traffic received during vport shutdown. */
if (vport->load_flag & FC_UNLOADING)
goto dropit;
@@ -5618,6 +5659,16 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
if (newnode)
lpfc_nlp_put(ndlp);
break;
+ case ELS_CMD_RRQ:
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV RRQ: did:x%x/ste:x%x flg:x%x",
+ did, vport->port_state, ndlp->nlp_flag);
+
+ phba->fc_stat.elsRcvRRQ++;
+ lpfc_els_rcv_rrq(vport, elsiocb, ndlp);
+ if (newnode)
+ lpfc_nlp_put(ndlp);
+ break;
default:
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
"RCV ELS cmd: cmd:x%x did:x%x/ste:x%x",
@@ -5670,7 +5721,7 @@ dropit:
* NULL - No vport with the matching @vpi found
* Otherwise - Address to the vport with the matching @vpi.
**/
-static struct lpfc_vport *
+struct lpfc_vport *
lpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi)
{
struct lpfc_vport *vport;
@@ -6024,11 +6075,6 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
irsp->ulpStatus, irsp->un.ulpWord[4]);
goto fdisc_failed;
}
- if (vport->fc_vport->vport_state == FC_VPORT_INITIALIZING)
- lpfc_vport_set_state(vport, FC_VPORT_FAILED);
- lpfc_nlp_put(ndlp);
- /* giving up on FDISC. Cancel discovery timer */
- lpfc_can_disctmo(vport);
spin_lock_irq(shost->host_lock);
vport->fc_flag |= FC_FABRIC;
if (vport->phba->fc_topology == TOPOLOGY_LOOP)
@@ -6107,6 +6153,7 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
int did = ndlp->nlp_DID;
int rc;
+ vport->port_state = LPFC_FDISC;
cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm));
elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, did,
ELS_CMD_FDISC);
@@ -6172,7 +6219,6 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
return 1;
}
lpfc_vport_set_state(vport, FC_VPORT_INITIALIZING);
- vport->port_state = LPFC_FDISC;
return 0;
}
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index e6a47e2..3b94244 100644..100755
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -525,8 +525,6 @@ lpfc_work_done(struct lpfc_hba *phba)
spin_unlock_irq(&phba->hbalock);
lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ);
}
- if (phba->hba_flag & HBA_RECEIVE_BUFFER)
- lpfc_sli4_handle_received_buffer(phba);
}
vports = lpfc_create_vport_work_array(phba);
@@ -568,8 +566,9 @@ lpfc_work_done(struct lpfc_hba *phba)
pring = &phba->sli.ring[LPFC_ELS_RING];
status = (ha_copy & (HA_RXMASK << (4*LPFC_ELS_RING)));
status >>= (4*LPFC_ELS_RING);
- if ((status & HA_RXMASK)
- || (pring->flag & LPFC_DEFERRED_RING_EVENT)) {
+ if ((status & HA_RXMASK) ||
+ (pring->flag & LPFC_DEFERRED_RING_EVENT) ||
+ (phba->hba_flag & HBA_SP_QUEUE_EVT)) {
if (pring->flag & LPFC_STOP_IOCB_EVENT) {
pring->flag |= LPFC_DEFERRED_RING_EVENT;
/* Set the lpfc data pending flag */
@@ -688,7 +687,8 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove)
lpfc_unreg_rpi(vport, ndlp);
/* Leave Fabric nodes alone on link down */
- if (!remove && ndlp->nlp_type & NLP_FABRIC)
+ if ((phba->sli_rev < LPFC_SLI_REV4) &&
+ (!remove && ndlp->nlp_type & NLP_FABRIC))
continue;
rc = lpfc_disc_state_machine(vport, ndlp, NULL,
remove
@@ -706,6 +706,9 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove)
void
lpfc_port_link_failure(struct lpfc_vport *vport)
{
+ /* Cleanup any outstanding received buffers */
+ lpfc_cleanup_rcv_buffers(vport);
+
/* Cleanup any outstanding RSCN activity */
lpfc_els_flush_rscn(vport);
@@ -1015,13 +1018,12 @@ lpfc_mbx_cmpl_reg_fcfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
mempool_free(mboxq, phba->mbox_mem_pool);
return;
}
- if (vport->port_state != LPFC_FLOGI) {
- spin_lock_irqsave(&phba->hbalock, flags);
- phba->fcf.fcf_flag |= (FCF_DISCOVERED | FCF_IN_USE);
- phba->hba_flag &= ~FCF_DISC_INPROGRESS;
- spin_unlock_irqrestore(&phba->hbalock, flags);
+ spin_lock_irqsave(&phba->hbalock, flags);
+ phba->fcf.fcf_flag |= (FCF_DISCOVERED | FCF_IN_USE);
+ phba->hba_flag &= ~FCF_DISC_INPROGRESS;
+ spin_unlock_irqrestore(&phba->hbalock, flags);
+ if (vport->port_state != LPFC_FLOGI)
lpfc_initial_flogi(vport);
- }
mempool_free(mboxq, phba->mbox_mem_pool);
return;
@@ -1199,6 +1201,7 @@ lpfc_register_fcf(struct lpfc_hba *phba)
/* If the FCF is not availabe do nothing. */
if (!(phba->fcf.fcf_flag & FCF_AVAILABLE)) {
+ phba->hba_flag &= ~FCF_DISC_INPROGRESS;
spin_unlock_irqrestore(&phba->hbalock, flags);
return;
}
@@ -1216,15 +1219,23 @@ lpfc_register_fcf(struct lpfc_hba *phba)
fcf_mbxq = mempool_alloc(phba->mbox_mem_pool,
GFP_KERNEL);
- if (!fcf_mbxq)
+ if (!fcf_mbxq) {
+ spin_lock_irqsave(&phba->hbalock, flags);
+ phba->hba_flag &= ~FCF_DISC_INPROGRESS;
+ spin_unlock_irqrestore(&phba->hbalock, flags);
return;
+ }
lpfc_reg_fcfi(phba, fcf_mbxq);
fcf_mbxq->vport = phba->pport;
fcf_mbxq->mbox_cmpl = lpfc_mbx_cmpl_reg_fcfi;
rc = lpfc_sli_issue_mbox(phba, fcf_mbxq, MBX_NOWAIT);
- if (rc == MBX_NOT_FINISHED)
+ if (rc == MBX_NOT_FINISHED) {
+ spin_lock_irqsave(&phba->hbalock, flags);
+ phba->hba_flag &= ~FCF_DISC_INPROGRESS;
+ spin_unlock_irqrestore(&phba->hbalock, flags);
mempool_free(fcf_mbxq, phba->mbox_mem_pool);
+ }
return;
}
@@ -1253,13 +1264,27 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba,
uint16_t *vlan_id)
{
struct lpfc_fcf_conn_entry *conn_entry;
+ int i, j, fcf_vlan_id = 0;
+
+ /* Find the lowest VLAN id in the FCF record */
+ for (i = 0; i < 512; i++) {
+ if (new_fcf_record->vlan_bitmap[i]) {
+ fcf_vlan_id = i * 8;
+ j = 0;
+ while (!((new_fcf_record->vlan_bitmap[i] >> j) & 1)) {
+ j++;
+ fcf_vlan_id++;
+ }
+ break;
+ }
+ }
/* If FCF not available return 0 */
if (!bf_get(lpfc_fcf_record_fcf_avail, new_fcf_record) ||
!bf_get(lpfc_fcf_record_fcf_valid, new_fcf_record))
return 0;
- if (!phba->cfg_enable_fip) {
+ if (!(phba->hba_flag & HBA_FIP_SUPPORT)) {
*boot_flag = 0;
*addr_mode = bf_get(lpfc_fcf_record_mac_addr_prov,
new_fcf_record);
@@ -1286,7 +1311,11 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba,
if (*addr_mode & LPFC_FCF_FPMA)
*addr_mode = LPFC_FCF_FPMA;
- *vlan_id = 0xFFFF;
+ /* If FCF record report a vlan id use that vlan id */
+ if (fcf_vlan_id)
+ *vlan_id = fcf_vlan_id;
+ else
+ *vlan_id = 0xFFFF;
return 1;
}
@@ -1384,8 +1413,15 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba,
(*addr_mode & LPFC_FCF_FPMA))
*addr_mode = LPFC_FCF_FPMA;
+ /* If matching connect list has a vlan id, use it */
if (conn_entry->conn_rec.flags & FCFCNCT_VLAN_VALID)
*vlan_id = conn_entry->conn_rec.vlan_tag;
+ /*
+ * If no vlan id is specified in connect list, use the vlan id
+ * in the FCF record
+ */
+ else if (fcf_vlan_id)
+ *vlan_id = fcf_vlan_id;
else
*vlan_id = 0xFFFF;
@@ -1423,6 +1459,15 @@ lpfc_check_pending_fcoe_event(struct lpfc_hba *phba, uint8_t unreg_fcf)
if (phba->link_state >= LPFC_LINK_UP)
lpfc_sli4_read_fcf_record(phba, LPFC_FCOE_FCF_GET_FIRST);
+ else {
+ /*
+ * Do not continue FCF discovery and clear FCF_DISC_INPROGRESS
+ * flag
+ */
+ spin_lock_irq(&phba->hbalock);
+ phba->hba_flag &= ~FCF_DISC_INPROGRESS;
+ spin_unlock_irq(&phba->hbalock);
+ }
if (unreg_fcf) {
spin_lock_irq(&phba->hbalock);
@@ -1659,9 +1704,8 @@ lpfc_init_vpi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
lpfc_initial_fdisc(vport);
else {
lpfc_vport_set_state(vport, FC_VPORT_NO_FABRIC_SUPP);
- lpfc_printf_vlog(vport, KERN_ERR,
- LOG_ELS,
- "2606 No NPIV Fabric support\n");
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "2606 No NPIV Fabric support\n");
}
return;
}
@@ -1756,8 +1800,8 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
goto fail_free_mem;
}
- /* Mark the vport has registered with its VFI */
- vport->vfi_state |= LPFC_VFI_REGISTERED;
+ /* The VPI is implicitly registered when the VFI is registered */
+ vport->vpi_state |= LPFC_VPI_REGISTERED;
if (vport->port_state == LPFC_FABRIC_CFG_LINK) {
lpfc_start_fdiscs(phba);
@@ -1861,7 +1905,10 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
if (phba->fc_topology == TOPOLOGY_LOOP) {
phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED;
- if (phba->cfg_enable_npiv)
+ /* if npiv is enabled and this adapter supports npiv log
+ * a message that npiv is not supported in this topology
+ */
+ if (phba->cfg_enable_npiv && phba->max_vpi)
lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
"1309 Link Up Event npiv not supported in loop "
"topology\n");
@@ -1955,7 +2002,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
* is phase 1 implementation that support FCF index 0 and driver
* defaults.
*/
- if (phba->cfg_enable_fip == 0) {
+ if (!(phba->hba_flag & HBA_FIP_SUPPORT)) {
fcf_record = kzalloc(sizeof(struct fcf_record),
GFP_KERNEL);
if (unlikely(!fcf_record)) {
@@ -2085,6 +2132,7 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
else
phba->sli.sli_flag &= ~LPFC_MENLO_MAINT;
+ phba->link_events++;
if (la->attType == AT_LINK_UP && (!la->mm)) {
phba->fc_stat.LinkUp++;
if (phba->link_flag & LS_LOOPBACK_MODE) {
@@ -2211,13 +2259,14 @@ lpfc_mbx_cmpl_unreg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
mb->mbxStatus);
break;
}
+ vport->vpi_state &= ~LPFC_VPI_REGISTERED;
vport->unreg_vpi_cmpl = VPORT_OK;
mempool_free(pmb, phba->mbox_mem_pool);
/*
* This shost reference might have been taken at the beginning of
* lpfc_vport_delete()
*/
- if (vport->load_flag & FC_UNLOADING)
+ if ((vport->load_flag & FC_UNLOADING) && (vport != phba->pport))
scsi_host_put(shost);
}
@@ -2268,6 +2317,7 @@ lpfc_mbx_cmpl_reg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
goto out;
}
+ vport->vpi_state |= LPFC_VPI_REGISTERED;
vport->num_disc_nodes = 0;
/* go thru NPR list and issue ELS PLOGIs */
if (vport->fc_npr_cnt)
@@ -3077,7 +3127,7 @@ lpfc_no_rpi(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
struct lpfc_sli *psli;
struct lpfc_sli_ring *pring;
struct lpfc_iocbq *iocb, *next_iocb;
- uint32_t rpi, i;
+ uint32_t i;
lpfc_fabric_abort_nport(ndlp);
@@ -3086,7 +3136,6 @@ lpfc_no_rpi(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
* by firmware with a no rpi error.
*/
psli = &phba->sli;
- rpi = ndlp->nlp_rpi;
if (ndlp->nlp_flag & NLP_RPI_VALID) {
/* Now process each ring */
for (i = 0; i < psli->num_rings; i++) {
@@ -4322,6 +4371,14 @@ lpfc_fcf_inuse(struct lpfc_hba *phba)
ret = 1;
spin_unlock_irq(shost->host_lock);
goto out;
+ } else {
+ lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+ "2624 RPI %x DID %x flg %x still "
+ "logged in\n",
+ ndlp->nlp_rpi, ndlp->nlp_DID,
+ ndlp->nlp_flag);
+ if (ndlp->nlp_flag & NLP_RPI_VALID)
+ ret = 1;
}
}
spin_unlock_irq(shost->host_lock);
@@ -4400,7 +4457,7 @@ lpfc_unregister_unused_fcf(struct lpfc_hba *phba)
*/
if (!(phba->hba_flag & HBA_FCOE_SUPPORT) ||
!(phba->fcf.fcf_flag & FCF_REGISTERED) ||
- (phba->cfg_enable_fip == 0)) {
+ (!(phba->hba_flag & HBA_FIP_SUPPORT))) {
spin_unlock_irq(&phba->hbalock);
return;
}
@@ -4409,6 +4466,8 @@ lpfc_unregister_unused_fcf(struct lpfc_hba *phba)
if (lpfc_fcf_inuse(phba))
return;
+ /* At this point, all discovery is aborted */
+ phba->pport->port_state = LPFC_VPORT_UNKNOWN;
/* Unregister VPIs */
vports = lpfc_create_vport_work_array(phba);
@@ -4416,8 +4475,8 @@ lpfc_unregister_unused_fcf(struct lpfc_hba *phba)
(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED))
for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
lpfc_mbx_unreg_vpi(vports[i]);
- vports[i]->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
- vports[i]->vfi_state &= ~LPFC_VFI_REGISTERED;
+ vports[i]->fc_flag |= FC_VPORT_NEEDS_INIT_VPI;
+ vports[i]->vpi_state &= ~LPFC_VPI_REGISTERED;
}
lpfc_destroy_vport_work_array(phba, vports);
@@ -4431,7 +4490,7 @@ lpfc_unregister_unused_fcf(struct lpfc_hba *phba)
return;
}
- lpfc_unreg_vfi(mbox, phba->pport->vfi);
+ lpfc_unreg_vfi(mbox, phba->pport);
mbox->vport = phba->pport;
mbox->mbox_cmpl = lpfc_unregister_vfi_cmpl;
@@ -4512,8 +4571,10 @@ lpfc_read_fcf_conn_tbl(struct lpfc_hba *phba,
/* Free the current connect table */
list_for_each_entry_safe(conn_entry, next_conn_entry,
- &phba->fcf_conn_rec_list, list)
+ &phba->fcf_conn_rec_list, list) {
+ list_del_init(&conn_entry->list);
kfree(conn_entry);
+ }
conn_hdr = (struct lpfc_fcf_conn_hdr *) buff;
record_count = conn_hdr->length * sizeof(uint32_t)/
@@ -4569,14 +4630,6 @@ lpfc_read_fcoe_param(struct lpfc_hba *phba,
(fcoe_param_hdr->length != FCOE_PARAM_LENGTH))
return;
- if (bf_get(lpfc_fip_param_hdr_fipp_mode, fcoe_param_hdr) ==
- FIPP_MODE_ON)
- phba->cfg_enable_fip = 1;
-
- if (bf_get(lpfc_fip_param_hdr_fipp_mode, fcoe_param_hdr) ==
- FIPP_MODE_OFF)
- phba->cfg_enable_fip = 0;
-
if (fcoe_param_hdr->parm_flags & FIPP_VLAN_VALID) {
phba->valid_vlan = 1;
phba->vlan_id = le16_to_cpu(fcoe_param->vlan_tag) &
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index ccb2672..c9faa1d 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -1124,21 +1124,6 @@ typedef struct {
/* Number of 4-byte words in an IOCB. */
#define IOCB_WORD_SZ 8
-/* defines for type field in fc header */
-#define FC_ELS_DATA 0x1
-#define FC_LLC_SNAP 0x5
-#define FC_FCP_DATA 0x8
-#define FC_COMMON_TRANSPORT_ULP 0x20
-
-/* defines for rctl field in fc header */
-#define FC_DEV_DATA 0x0
-#define FC_UNSOL_CTL 0x2
-#define FC_SOL_CTL 0x3
-#define FC_UNSOL_DATA 0x4
-#define FC_FCP_CMND 0x6
-#define FC_ELS_REQ 0x22
-#define FC_ELS_RSP 0x23
-
/* network headers for Dfctl field */
#define FC_NET_HDR 0x20
@@ -1183,6 +1168,8 @@ typedef struct {
#define PCI_DEVICE_ID_ZEPHYR_DCSP 0xfe12
#define PCI_VENDOR_ID_SERVERENGINE 0x19a2
#define PCI_DEVICE_ID_TIGERSHARK 0x0704
+#define PCI_DEVICE_ID_TOMCAT 0x0714
+#define PCI_DEVICE_ID_FALCON 0xf180
#define JEDEC_ID_ADDRESS 0x0080001c
#define FIREFLY_JEDEC_ID 0x1ACC
@@ -1444,6 +1431,7 @@ typedef struct { /* FireFly BIU registers */
#define CMD_ABORT_MXRI64_CN 0x8C
#define CMD_RCV_ELS_REQ64_CX 0x8D
#define CMD_XMIT_ELS_RSP64_CX 0x95
+#define CMD_XMIT_BLS_RSP64_CX 0x97
#define CMD_FCP_IWRITE64_CR 0x98
#define CMD_FCP_IWRITE64_CX 0x99
#define CMD_FCP_IREAD64_CR 0x9A
@@ -2306,8 +2294,7 @@ typedef struct {
uint32_t rsvd1;
uint32_t rsvd2:8;
uint32_t sid:24;
- uint32_t rsvd3;
- uint32_t rsvd4;
+ uint32_t wwn[2];
uint32_t rsvd5;
uint16_t vfi;
uint16_t vpi;
@@ -2315,8 +2302,7 @@ typedef struct {
uint32_t rsvd1;
uint32_t sid:24;
uint32_t rsvd2:8;
- uint32_t rsvd3;
- uint32_t rsvd4;
+ uint32_t wwn[2];
uint32_t rsvd5;
uint16_t vpi;
uint16_t vfi;
@@ -2326,7 +2312,13 @@ typedef struct {
/* Structure for MB Command UNREG_VPI (0x97) */
typedef struct {
uint32_t rsvd1;
- uint32_t rsvd2;
+#ifdef __BIG_ENDIAN_BITFIELD
+ uint16_t rsvd2;
+ uint16_t sli4_vpi;
+#else /* __LITTLE_ENDIAN */
+ uint16_t sli4_vpi;
+ uint16_t rsvd2;
+#endif
uint32_t rsvd3;
uint32_t rsvd4;
uint32_t rsvd5;
@@ -3547,7 +3539,7 @@ typedef struct _IOCB { /* IOCB structure */
ASYNCSTAT_FIELDS asyncstat; /* async_status iocb */
QUE_XRI64_CX_FIELDS quexri64cx; /* que_xri64_cx fields */
struct rcv_seq64 rcvseq64; /* RCV_SEQ64 and RCV_CONT64 */
-
+ struct sli4_bls_acc bls_acc; /* UNSOL ABTS BLS_ACC params */
uint32_t ulpWord[IOCB_WORD_SZ - 2]; /* generic 6 'words' */
} un;
union {
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h
index 3689eee..1585148 100644
--- a/drivers/scsi/lpfc/lpfc_hw4.h
+++ b/drivers/scsi/lpfc/lpfc_hw4.h
@@ -194,6 +194,26 @@ struct lpfc_sli4_flags {
#define lpfc_fip_flag_WORD word0
};
+struct sli4_bls_acc {
+ uint32_t word0_rsvd; /* Word0 must be reserved */
+ uint32_t word1;
+#define lpfc_abts_orig_SHIFT 0
+#define lpfc_abts_orig_MASK 0x00000001
+#define lpfc_abts_orig_WORD word1
+#define LPFC_ABTS_UNSOL_RSP 1
+#define LPFC_ABTS_UNSOL_INT 0
+ uint32_t word2;
+#define lpfc_abts_rxid_SHIFT 0
+#define lpfc_abts_rxid_MASK 0x0000FFFF
+#define lpfc_abts_rxid_WORD word2
+#define lpfc_abts_oxid_SHIFT 16
+#define lpfc_abts_oxid_MASK 0x0000FFFF
+#define lpfc_abts_oxid_WORD word2
+ uint32_t word3;
+ uint32_t word4;
+ uint32_t word5_rsvd; /* Word5 must be reserved */
+};
+
/* event queue entry structure */
struct lpfc_eqe {
uint32_t word0;
@@ -425,7 +445,7 @@ struct lpfc_wqe_generic{
#define lpfc_wqe_gen_status_MASK 0x0000000F
#define lpfc_wqe_gen_status_WORD word7
#define lpfc_wqe_gen_ct_SHIFT 2
-#define lpfc_wqe_gen_ct_MASK 0x00000007
+#define lpfc_wqe_gen_ct_MASK 0x00000003
#define lpfc_wqe_gen_ct_WORD word7
uint32_t abort_tag;
uint32_t word9;
@@ -453,6 +473,13 @@ struct lpfc_wqe_generic{
#define lpfc_wqe_gen_wqec_SHIFT 7
#define lpfc_wqe_gen_wqec_MASK 0x00000001
#define lpfc_wqe_gen_wqec_WORD word11
+#define ELS_ID_FLOGI 3
+#define ELS_ID_FDISC 2
+#define ELS_ID_LOGO 1
+#define ELS_ID_DEFAULT 0
+#define lpfc_wqe_gen_els_id_SHIFT 4
+#define lpfc_wqe_gen_els_id_MASK 0x00000003
+#define lpfc_wqe_gen_els_id_WORD word11
#define lpfc_wqe_gen_cmd_type_SHIFT 0
#define lpfc_wqe_gen_cmd_type_MASK 0x0000000F
#define lpfc_wqe_gen_cmd_type_WORD word11
@@ -487,8 +514,8 @@ struct lpfc_register {
#define LPFC_UERR_STATUS_HI 0x00A4
#define LPFC_UERR_STATUS_LO 0x00A0
-#define LPFC_ONLINE0 0x00B0
-#define LPFC_ONLINE1 0x00B4
+#define LPFC_UE_MASK_HI 0x00AC
+#define LPFC_UE_MASK_LO 0x00A8
#define LPFC_SCRATCHPAD 0x0058
/* BAR0 Registers */
@@ -760,6 +787,7 @@ struct mbox_header {
#define LPFC_MBOX_OPCODE_MQ_DESTROY 0x35
#define LPFC_MBOX_OPCODE_CQ_DESTROY 0x36
#define LPFC_MBOX_OPCODE_EQ_DESTROY 0x37
+#define LPFC_MBOX_OPCODE_QUERY_FW_CFG 0x3A
#define LPFC_MBOX_OPCODE_FUNCTION_RESET 0x3D
/* FCoE Opcodes */
@@ -1273,6 +1301,51 @@ struct lpfc_mbx_del_fcf_tbl_entry {
#define lpfc_mbx_del_fcf_tbl_index_WORD word10
};
+struct lpfc_mbx_query_fw_cfg {
+ struct mbox_header header;
+ uint32_t config_number;
+ uint32_t asic_rev;
+ uint32_t phys_port;
+ uint32_t function_mode;
+/* firmware Function Mode */
+#define lpfc_function_mode_toe_SHIFT 0
+#define lpfc_function_mode_toe_MASK 0x00000001
+#define lpfc_function_mode_toe_WORD function_mode
+#define lpfc_function_mode_nic_SHIFT 1
+#define lpfc_function_mode_nic_MASK 0x00000001
+#define lpfc_function_mode_nic_WORD function_mode
+#define lpfc_function_mode_rdma_SHIFT 2
+#define lpfc_function_mode_rdma_MASK 0x00000001
+#define lpfc_function_mode_rdma_WORD function_mode
+#define lpfc_function_mode_vm_SHIFT 3
+#define lpfc_function_mode_vm_MASK 0x00000001
+#define lpfc_function_mode_vm_WORD function_mode
+#define lpfc_function_mode_iscsi_i_SHIFT 4
+#define lpfc_function_mode_iscsi_i_MASK 0x00000001
+#define lpfc_function_mode_iscsi_i_WORD function_mode
+#define lpfc_function_mode_iscsi_t_SHIFT 5
+#define lpfc_function_mode_iscsi_t_MASK 0x00000001
+#define lpfc_function_mode_iscsi_t_WORD function_mode
+#define lpfc_function_mode_fcoe_i_SHIFT 6
+#define lpfc_function_mode_fcoe_i_MASK 0x00000001
+#define lpfc_function_mode_fcoe_i_WORD function_mode
+#define lpfc_function_mode_fcoe_t_SHIFT 7
+#define lpfc_function_mode_fcoe_t_MASK 0x00000001
+#define lpfc_function_mode_fcoe_t_WORD function_mode
+#define lpfc_function_mode_dal_SHIFT 8
+#define lpfc_function_mode_dal_MASK 0x00000001
+#define lpfc_function_mode_dal_WORD function_mode
+#define lpfc_function_mode_lro_SHIFT 9
+#define lpfc_function_mode_lro_MASK 0x00000001
+#define lpfc_function_mode_lro_WORD function_mode9
+#define lpfc_function_mode_flex10_SHIFT 10
+#define lpfc_function_mode_flex10_MASK 0x00000001
+#define lpfc_function_mode_flex10_WORD function_mode
+#define lpfc_function_mode_ncsi_SHIFT 11
+#define lpfc_function_mode_ncsi_MASK 0x00000001
+#define lpfc_function_mode_ncsi_WORD function_mode
+};
+
/* Status field for embedded SLI_CONFIG mailbox command */
#define STATUS_SUCCESS 0x0
#define STATUS_FAILED 0x1
@@ -1349,8 +1422,7 @@ struct lpfc_mbx_reg_vfi {
#define lpfc_reg_vfi_fcfi_SHIFT 0
#define lpfc_reg_vfi_fcfi_MASK 0x0000FFFF
#define lpfc_reg_vfi_fcfi_WORD word2
- uint32_t word3_rsvd;
- uint32_t word4_rsvd;
+ uint32_t wwn[2];
struct ulp_bde64 bde;
uint32_t word8_rsvd;
uint32_t word9_rsvd;
@@ -1555,6 +1627,11 @@ struct lpfc_mbx_read_rev {
#define lpfc_mbx_rd_rev_fcoe_SHIFT 20
#define lpfc_mbx_rd_rev_fcoe_MASK 0x00000001
#define lpfc_mbx_rd_rev_fcoe_WORD word1
+#define lpfc_mbx_rd_rev_cee_ver_SHIFT 21
+#define lpfc_mbx_rd_rev_cee_ver_MASK 0x00000003
+#define lpfc_mbx_rd_rev_cee_ver_WORD word1
+#define LPFC_PREDCBX_CEE_MODE 0
+#define LPFC_DCBX_CEE_MODE 1
#define lpfc_mbx_rd_rev_vpd_SHIFT 29
#define lpfc_mbx_rd_rev_vpd_MASK 0x00000001
#define lpfc_mbx_rd_rev_vpd_WORD word1
@@ -1804,6 +1881,7 @@ struct lpfc_mqe {
struct lpfc_mbx_read_config rd_config;
struct lpfc_mbx_request_features req_ftrs;
struct lpfc_mbx_post_hdr_tmpl hdr_tmpl;
+ struct lpfc_mbx_query_fw_cfg query_fw_cfg;
struct lpfc_mbx_nop nop;
} un;
};
@@ -1885,7 +1963,7 @@ struct lpfc_acqe_link {
};
struct lpfc_acqe_fcoe {
- uint32_t fcf_index;
+ uint32_t index;
uint32_t word1;
#define lpfc_acqe_fcoe_fcf_count_SHIFT 0
#define lpfc_acqe_fcoe_fcf_count_MASK 0x0000FFFF
@@ -1896,6 +1974,7 @@ struct lpfc_acqe_fcoe {
#define LPFC_FCOE_EVENT_TYPE_NEW_FCF 0x1
#define LPFC_FCOE_EVENT_TYPE_FCF_TABLE_FULL 0x2
#define LPFC_FCOE_EVENT_TYPE_FCF_DEAD 0x3
+#define LPFC_FCOE_EVENT_TYPE_CVL 0x4
uint32_t event_tag;
uint32_t trailer;
};
@@ -1921,12 +2000,13 @@ struct lpfc_bmbx_create {
#define SGL_ALIGN_SZ 64
#define SGL_PAGE_SIZE 4096
/* align SGL addr on a size boundary - adjust address up */
-#define NO_XRI ((uint16_t)-1)
+#define NO_XRI ((uint16_t)-1)
+
struct wqe_common {
uint32_t word6;
-#define wqe_xri_SHIFT 0
-#define wqe_xri_MASK 0x0000FFFF
-#define wqe_xri_WORD word6
+#define wqe_xri_tag_SHIFT 0
+#define wqe_xri_tag_MASK 0x0000FFFF
+#define wqe_xri_tag_WORD word6
#define wqe_ctxt_tag_SHIFT 16
#define wqe_ctxt_tag_MASK 0x0000FFFF
#define wqe_ctxt_tag_WORD word6
@@ -1987,7 +2067,7 @@ struct wqe_common {
#define wqe_wqec_MASK 0x00000001
#define wqe_wqec_WORD word11
#define wqe_cqid_SHIFT 16
-#define wqe_cqid_MASK 0x000003ff
+#define wqe_cqid_MASK 0x0000ffff
#define wqe_cqid_WORD word11
};
@@ -1996,6 +2076,9 @@ struct wqe_did {
#define wqe_els_did_SHIFT 0
#define wqe_els_did_MASK 0x00FFFFFF
#define wqe_els_did_WORD word5
+#define wqe_xmit_bls_pt_SHIFT 28
+#define wqe_xmit_bls_pt_MASK 0x00000003
+#define wqe_xmit_bls_pt_WORD word5
#define wqe_xmit_bls_ar_SHIFT 30
#define wqe_xmit_bls_ar_MASK 0x00000001
#define wqe_xmit_bls_ar_WORD word5
@@ -2044,6 +2127,23 @@ struct xmit_els_rsp64_wqe {
struct xmit_bls_rsp64_wqe {
uint32_t payload0;
+/* Payload0 for BA_ACC */
+#define xmit_bls_rsp64_acc_seq_id_SHIFT 16
+#define xmit_bls_rsp64_acc_seq_id_MASK 0x000000ff
+#define xmit_bls_rsp64_acc_seq_id_WORD payload0
+#define xmit_bls_rsp64_acc_seq_id_vald_SHIFT 24
+#define xmit_bls_rsp64_acc_seq_id_vald_MASK 0x000000ff
+#define xmit_bls_rsp64_acc_seq_id_vald_WORD payload0
+/* Payload0 for BA_RJT */
+#define xmit_bls_rsp64_rjt_vspec_SHIFT 0
+#define xmit_bls_rsp64_rjt_vspec_MASK 0x000000ff
+#define xmit_bls_rsp64_rjt_vspec_WORD payload0
+#define xmit_bls_rsp64_rjt_expc_SHIFT 8
+#define xmit_bls_rsp64_rjt_expc_MASK 0x000000ff
+#define xmit_bls_rsp64_rjt_expc_WORD payload0
+#define xmit_bls_rsp64_rjt_rsnc_SHIFT 16
+#define xmit_bls_rsp64_rjt_rsnc_MASK 0x000000ff
+#define xmit_bls_rsp64_rjt_rsnc_WORD payload0
uint32_t word1;
#define xmit_bls_rsp64_rxid_SHIFT 0
#define xmit_bls_rsp64_rxid_MASK 0x0000ffff
@@ -2052,18 +2152,19 @@ struct xmit_bls_rsp64_wqe {
#define xmit_bls_rsp64_oxid_MASK 0x0000ffff
#define xmit_bls_rsp64_oxid_WORD word1
uint32_t word2;
-#define xmit_bls_rsp64_seqcntlo_SHIFT 0
-#define xmit_bls_rsp64_seqcntlo_MASK 0x0000ffff
-#define xmit_bls_rsp64_seqcntlo_WORD word2
-#define xmit_bls_rsp64_seqcnthi_SHIFT 16
+#define xmit_bls_rsp64_seqcnthi_SHIFT 0
#define xmit_bls_rsp64_seqcnthi_MASK 0x0000ffff
#define xmit_bls_rsp64_seqcnthi_WORD word2
+#define xmit_bls_rsp64_seqcntlo_SHIFT 16
+#define xmit_bls_rsp64_seqcntlo_MASK 0x0000ffff
+#define xmit_bls_rsp64_seqcntlo_WORD word2
uint32_t rsrvd3;
uint32_t rsrvd4;
struct wqe_did wqe_dest;
struct wqe_common wqe_com; /* words 6-11 */
uint32_t rsvd_12_15[4];
};
+
struct wqe_rctl_dfctl {
uint32_t word5;
#define wqe_si_SHIFT 2
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 562d8ce..226920d 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -28,6 +28,7 @@
#include <linux/pci.h>
#include <linux/spinlock.h>
#include <linux/ctype.h>
+#include <linux/aer.h>
#include <scsi/scsi.h>
#include <scsi/scsi_device.h>
@@ -645,7 +646,7 @@ lpfc_hba_down_prep(struct lpfc_hba *phba)
* down the SLI Layer.
*
* Return codes
- * 0 - sucess.
+ * 0 - success.
* Any other value - error.
**/
static int
@@ -700,7 +701,7 @@ lpfc_hba_down_post_s3(struct lpfc_hba *phba)
* down the SLI Layer.
*
* Return codes
- * 0 - sucess.
+ * 0 - success.
* Any other value - error.
**/
static int
@@ -755,7 +756,7 @@ lpfc_hba_down_post_s4(struct lpfc_hba *phba)
* uninitialization after the HBA is reset when bring down the SLI Layer.
*
* Return codes
- * 0 - sucess.
+ * 0 - success.
* Any other value - error.
**/
int
@@ -852,12 +853,19 @@ lpfc_hb_mbox_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq)
void
lpfc_hb_timeout_handler(struct lpfc_hba *phba)
{
+ struct lpfc_vport **vports;
LPFC_MBOXQ_t *pmboxq;
struct lpfc_dmabuf *buf_ptr;
- int retval;
+ int retval, i;
struct lpfc_sli *psli = &phba->sli;
LIST_HEAD(completions);
+ vports = lpfc_create_vport_work_array(phba);
+ if (vports != NULL)
+ for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++)
+ lpfc_rcv_seq_check_edtov(vports[i]);
+ lpfc_destroy_vport_work_array(phba, vports);
+
if ((phba->link_state == LPFC_HBA_ERROR) ||
(phba->pport->load_flag & FC_UNLOADING) ||
(phba->pport->fc_flag & FC_OFFLINE_MODE))
@@ -1254,7 +1262,7 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba)
* routine from the API jump table function pointer from the lpfc_hba struct.
*
* Return codes
- * 0 - sucess.
+ * 0 - success.
* Any other value - error.
**/
void
@@ -1521,10 +1529,10 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp)
int GE = 0;
int oneConnect = 0; /* default is not a oneConnect */
struct {
- char * name;
- int max_speed;
- char * bus;
- } m = {"<Unknown>", 0, ""};
+ char *name;
+ char *bus;
+ char *function;
+ } m = {"<Unknown>", "", ""};
if (mdp && mdp[0] != '\0'
&& descp && descp[0] != '\0')
@@ -1545,132 +1553,155 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp)
switch (dev_id) {
case PCI_DEVICE_ID_FIREFLY:
- m = (typeof(m)){"LP6000", max_speed, "PCI"};
+ m = (typeof(m)){"LP6000", "PCI", "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_SUPERFLY:
if (vp->rev.biuRev >= 1 && vp->rev.biuRev <= 3)
- m = (typeof(m)){"LP7000", max_speed, "PCI"};
+ m = (typeof(m)){"LP7000", "PCI",
+ "Fibre Channel Adapter"};
else
- m = (typeof(m)){"LP7000E", max_speed, "PCI"};
+ m = (typeof(m)){"LP7000E", "PCI",
+ "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_DRAGONFLY:
- m = (typeof(m)){"LP8000", max_speed, "PCI"};
+ m = (typeof(m)){"LP8000", "PCI",
+ "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_CENTAUR:
if (FC_JEDEC_ID(vp->rev.biuRev) == CENTAUR_2G_JEDEC_ID)
- m = (typeof(m)){"LP9002", max_speed, "PCI"};
+ m = (typeof(m)){"LP9002", "PCI",
+ "Fibre Channel Adapter"};
else
- m = (typeof(m)){"LP9000", max_speed, "PCI"};
+ m = (typeof(m)){"LP9000", "PCI",
+ "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_RFLY:
- m = (typeof(m)){"LP952", max_speed, "PCI"};
+ m = (typeof(m)){"LP952", "PCI",
+ "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_PEGASUS:
- m = (typeof(m)){"LP9802", max_speed, "PCI-X"};
+ m = (typeof(m)){"LP9802", "PCI-X",
+ "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_THOR:
- m = (typeof(m)){"LP10000", max_speed, "PCI-X"};
+ m = (typeof(m)){"LP10000", "PCI-X",
+ "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_VIPER:
- m = (typeof(m)){"LPX1000", max_speed, "PCI-X"};
+ m = (typeof(m)){"LPX1000", "PCI-X",
+ "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_PFLY:
- m = (typeof(m)){"LP982", max_speed, "PCI-X"};
+ m = (typeof(m)){"LP982", "PCI-X",
+ "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_TFLY:
- m = (typeof(m)){"LP1050", max_speed, "PCI-X"};
+ m = (typeof(m)){"LP1050", "PCI-X",
+ "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_HELIOS:
- m = (typeof(m)){"LP11000", max_speed, "PCI-X2"};
+ m = (typeof(m)){"LP11000", "PCI-X2",
+ "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_HELIOS_SCSP:
- m = (typeof(m)){"LP11000-SP", max_speed, "PCI-X2"};
+ m = (typeof(m)){"LP11000-SP", "PCI-X2",
+ "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_HELIOS_DCSP:
- m = (typeof(m)){"LP11002-SP", max_speed, "PCI-X2"};
+ m = (typeof(m)){"LP11002-SP", "PCI-X2",
+ "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_NEPTUNE:
- m = (typeof(m)){"LPe1000", max_speed, "PCIe"};
+ m = (typeof(m)){"LPe1000", "PCIe", "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_NEPTUNE_SCSP:
- m = (typeof(m)){"LPe1000-SP", max_speed, "PCIe"};
+ m = (typeof(m)){"LPe1000-SP", "PCIe", "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_NEPTUNE_DCSP:
- m = (typeof(m)){"LPe1002-SP", max_speed, "PCIe"};
+ m = (typeof(m)){"LPe1002-SP", "PCIe", "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_BMID:
- m = (typeof(m)){"LP1150", max_speed, "PCI-X2"};
+ m = (typeof(m)){"LP1150", "PCI-X2", "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_BSMB:
- m = (typeof(m)){"LP111", max_speed, "PCI-X2"};
+ m = (typeof(m)){"LP111", "PCI-X2", "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_ZEPHYR:
- m = (typeof(m)){"LPe11000", max_speed, "PCIe"};
+ m = (typeof(m)){"LPe11000", "PCIe", "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_ZEPHYR_SCSP:
- m = (typeof(m)){"LPe11000", max_speed, "PCIe"};
+ m = (typeof(m)){"LPe11000", "PCIe", "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_ZEPHYR_DCSP:
- m = (typeof(m)){"LP2105", max_speed, "PCIe"};
+ m = (typeof(m)){"LP2105", "PCIe", "FCoE Adapter"};
GE = 1;
break;
case PCI_DEVICE_ID_ZMID:
- m = (typeof(m)){"LPe1150", max_speed, "PCIe"};
+ m = (typeof(m)){"LPe1150", "PCIe", "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_ZSMB:
- m = (typeof(m)){"LPe111", max_speed, "PCIe"};
+ m = (typeof(m)){"LPe111", "PCIe", "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_LP101:
- m = (typeof(m)){"LP101", max_speed, "PCI-X"};
+ m = (typeof(m)){"LP101", "PCI-X", "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_LP10000S:
- m = (typeof(m)){"LP10000-S", max_speed, "PCI"};
+ m = (typeof(m)){"LP10000-S", "PCI", "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_LP11000S:
- m = (typeof(m)){"LP11000-S", max_speed,
- "PCI-X2"};
+ m = (typeof(m)){"LP11000-S", "PCI-X2", "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_LPE11000S:
- m = (typeof(m)){"LPe11000-S", max_speed,
- "PCIe"};
+ m = (typeof(m)){"LPe11000-S", "PCIe", "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_SAT:
- m = (typeof(m)){"LPe12000", max_speed, "PCIe"};
+ m = (typeof(m)){"LPe12000", "PCIe", "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_SAT_MID:
- m = (typeof(m)){"LPe1250", max_speed, "PCIe"};
+ m = (typeof(m)){"LPe1250", "PCIe", "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_SAT_SMB:
- m = (typeof(m)){"LPe121", max_speed, "PCIe"};
+ m = (typeof(m)){"LPe121", "PCIe", "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_SAT_DCSP:
- m = (typeof(m)){"LPe12002-SP", max_speed, "PCIe"};
+ m = (typeof(m)){"LPe12002-SP", "PCIe", "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_SAT_SCSP:
- m = (typeof(m)){"LPe12000-SP", max_speed, "PCIe"};
+ m = (typeof(m)){"LPe12000-SP", "PCIe", "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_SAT_S:
- m = (typeof(m)){"LPe12000-S", max_speed, "PCIe"};
+ m = (typeof(m)){"LPe12000-S", "PCIe", "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_HORNET:
- m = (typeof(m)){"LP21000", max_speed, "PCIe"};
+ m = (typeof(m)){"LP21000", "PCIe", "FCoE Adapter"};
GE = 1;
break;
case PCI_DEVICE_ID_PROTEUS_VF:
- m = (typeof(m)) {"LPev12000", max_speed, "PCIe IOV"};
+ m = (typeof(m)){"LPev12000", "PCIe IOV",
+ "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_PROTEUS_PF:
- m = (typeof(m)) {"LPev12000", max_speed, "PCIe IOV"};
+ m = (typeof(m)){"LPev12000", "PCIe IOV",
+ "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_PROTEUS_S:
- m = (typeof(m)) {"LPemv12002-S", max_speed, "PCIe IOV"};
+ m = (typeof(m)){"LPemv12002-S", "PCIe IOV",
+ "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_TIGERSHARK:
oneConnect = 1;
- m = (typeof(m)) {"OCe10100-F", max_speed, "PCIe"};
+ m = (typeof(m)){"OCe10100", "PCIe", "FCoE"};
+ break;
+ case PCI_DEVICE_ID_TOMCAT:
+ oneConnect = 1;
+ m = (typeof(m)){"OCe11100", "PCIe", "FCoE"};
+ break;
+ case PCI_DEVICE_ID_FALCON:
+ m = (typeof(m)){"LPSe12002-ML1-E", "PCIe",
+ "EmulexSecure Fibre"};
break;
default:
- m = (typeof(m)){ NULL };
+ m = (typeof(m)){"Unknown", "", ""};
break;
}
@@ -1682,17 +1713,14 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp)
if (descp && descp[0] == '\0') {
if (oneConnect)
snprintf(descp, 255,
- "Emulex OneConnect %s, FCoE Initiator, Port %s",
- m.name,
+ "Emulex OneConnect %s, %s Initiator, Port %s",
+ m.name, m.function,
phba->Port);
else
snprintf(descp, 255,
"Emulex %s %d%s %s %s",
- m.name, m.max_speed,
- (GE) ? "GE" : "Gb",
- m.bus,
- (GE) ? "FCoE Adapter" :
- "Fibre Channel Adapter");
+ m.name, max_speed, (GE) ? "GE" : "Gb",
+ m.bus, m.function);
}
}
@@ -2217,7 +2245,7 @@ lpfc_offline_prep(struct lpfc_hba * phba)
if (vports[i]->load_flag & FC_UNLOADING)
continue;
- vports[i]->vfi_state &= ~LPFC_VFI_REGISTERED;
+ vports[i]->vpi_state &= ~LPFC_VPI_REGISTERED;
shost = lpfc_shost_from_vport(vports[i]);
list_for_each_entry_safe(ndlp, next_ndlp,
&vports[i]->fc_nodes,
@@ -2308,6 +2336,7 @@ lpfc_scsi_free(struct lpfc_hba *phba)
spin_lock_irq(&phba->hbalock);
/* Release all the lpfc_scsi_bufs maintained by this host. */
+ spin_lock(&phba->scsi_buf_list_lock);
list_for_each_entry_safe(sb, sb_next, &phba->lpfc_scsi_buf_list, list) {
list_del(&sb->list);
pci_pool_free(phba->lpfc_scsi_dma_buf_pool, sb->data,
@@ -2315,6 +2344,7 @@ lpfc_scsi_free(struct lpfc_hba *phba)
kfree(sb);
phba->total_scsi_bufs--;
}
+ spin_unlock(&phba->scsi_buf_list_lock);
/* Release all the lpfc_iocbq entries maintained by this host. */
list_for_each_entry_safe(io, io_next, &phba->lpfc_iocb_list, list) {
@@ -2322,9 +2352,7 @@ lpfc_scsi_free(struct lpfc_hba *phba)
kfree(io);
phba->total_iocbq_bufs--;
}
-
spin_unlock_irq(&phba->hbalock);
-
return 0;
}
@@ -2408,7 +2436,7 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
vport->els_tmofunc.function = lpfc_els_timeout;
vport->els_tmofunc.data = (unsigned long)vport;
- error = scsi_add_host(shost, dev);
+ error = scsi_add_host_with_dma(shost, dev, &phba->pcidev->dev);
if (error)
goto out_put_shost;
@@ -2699,6 +2727,63 @@ lpfc_sli_remove_dflt_fcf(struct lpfc_hba *phba)
}
/**
+ * lpfc_sli4_fw_cfg_check - Read the firmware config and verify FCoE support
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This function uses the QUERY_FW_CFG mailbox command to determine if the
+ * firmware loaded supports FCoE. A return of zero indicates that the mailbox
+ * was successful and the firmware supports FCoE. Any other return indicates
+ * a error. It is assumed that this function will be called before interrupts
+ * are enabled.
+ **/
+static int
+lpfc_sli4_fw_cfg_check(struct lpfc_hba *phba)
+{
+ int rc = 0;
+ LPFC_MBOXQ_t *mboxq;
+ struct lpfc_mbx_query_fw_cfg *query_fw_cfg;
+ uint32_t length;
+ uint32_t shdr_status, shdr_add_status;
+
+ mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!mboxq) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2621 Failed to allocate mbox for "
+ "query firmware config cmd\n");
+ return -ENOMEM;
+ }
+ query_fw_cfg = &mboxq->u.mqe.un.query_fw_cfg;
+ length = (sizeof(struct lpfc_mbx_query_fw_cfg) -
+ sizeof(struct lpfc_sli4_cfg_mhdr));
+ lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON,
+ LPFC_MBOX_OPCODE_QUERY_FW_CFG,
+ length, LPFC_SLI4_MBX_EMBED);
+ rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
+ /* The IOCTL status is embedded in the mailbox subheader. */
+ shdr_status = bf_get(lpfc_mbox_hdr_status,
+ &query_fw_cfg->header.cfg_shdr.response);
+ shdr_add_status = bf_get(lpfc_mbox_hdr_add_status,
+ &query_fw_cfg->header.cfg_shdr.response);
+ if (shdr_status || shdr_add_status || rc != MBX_SUCCESS) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "2622 Query Firmware Config failed "
+ "mbx status x%x, status x%x add_status x%x\n",
+ rc, shdr_status, shdr_add_status);
+ return -EINVAL;
+ }
+ if (!bf_get(lpfc_function_mode_fcoe_i, query_fw_cfg)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "2623 FCoE Function not supported by firmware. "
+ "Function mode = %08x\n",
+ query_fw_cfg->function_mode);
+ return -EINVAL;
+ }
+ if (rc != MBX_TIMEOUT)
+ mempool_free(mboxq, phba->mbox_mem_pool);
+ return 0;
+}
+
+/**
* lpfc_sli4_parse_latt_fault - Parse sli4 link-attention link fault code
* @phba: pointer to lpfc hba data structure.
* @acqe_link: pointer to the async link completion queue entry.
@@ -2918,13 +3003,17 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
{
uint8_t event_type = bf_get(lpfc_acqe_fcoe_event_type, acqe_fcoe);
int rc;
+ struct lpfc_vport *vport;
+ struct lpfc_nodelist *ndlp;
+ struct Scsi_Host *shost;
+ phba->fc_eventTag = acqe_fcoe->event_tag;
phba->fcoe_eventtag = acqe_fcoe->event_tag;
switch (event_type) {
case LPFC_FCOE_EVENT_TYPE_NEW_FCF:
lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
"2546 New FCF found index 0x%x tag 0x%x\n",
- acqe_fcoe->fcf_index,
+ acqe_fcoe->index,
acqe_fcoe->event_tag);
/*
* If the current FCF is in discovered state, or
@@ -2939,12 +3028,11 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
spin_unlock_irq(&phba->hbalock);
/* Read the FCF table and re-discover SAN. */
- rc = lpfc_sli4_read_fcf_record(phba,
- LPFC_FCOE_FCF_GET_FIRST);
+ rc = lpfc_sli4_read_fcf_record(phba, LPFC_FCOE_FCF_GET_FIRST);
if (rc)
lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "2547 Read FCF record failed 0x%x\n",
- rc);
+ "2547 Read FCF record failed 0x%x\n",
+ rc);
break;
case LPFC_FCOE_EVENT_TYPE_FCF_TABLE_FULL:
@@ -2956,11 +3044,11 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
case LPFC_FCOE_EVENT_TYPE_FCF_DEAD:
lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "2549 FCF disconnected fron network index 0x%x"
- " tag 0x%x\n", acqe_fcoe->fcf_index,
+ "2549 FCF disconnected from network index 0x%x"
+ " tag 0x%x\n", acqe_fcoe->index,
acqe_fcoe->event_tag);
/* If the event is not for currently used fcf do nothing */
- if (phba->fcf.fcf_indx != acqe_fcoe->fcf_index)
+ if (phba->fcf.fcf_indx != acqe_fcoe->index)
break;
/*
* Currently, driver support only one FCF - so treat this as
@@ -2970,7 +3058,28 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
/* Unregister FCF if no devices connected to it */
lpfc_unregister_unused_fcf(phba);
break;
-
+ case LPFC_FCOE_EVENT_TYPE_CVL:
+ lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+ "2718 Clear Virtual Link Received for VPI 0x%x"
+ " tag 0x%x\n", acqe_fcoe->index, acqe_fcoe->event_tag);
+ vport = lpfc_find_vport_by_vpid(phba,
+ acqe_fcoe->index - phba->vpi_base);
+ if (!vport)
+ break;
+ ndlp = lpfc_findnode_did(vport, Fabric_DID);
+ if (!ndlp)
+ break;
+ shost = lpfc_shost_from_vport(vport);
+ lpfc_linkdown_port(vport);
+ if (vport->port_type != LPFC_NPIV_PORT) {
+ mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ);
+ spin_lock_irq(shost->host_lock);
+ ndlp->nlp_flag |= NLP_DELAY_TMO;
+ spin_unlock_irq(shost->host_lock);
+ ndlp->nlp_last_elscmd = ELS_CMD_FLOGI;
+ vport->port_state = LPFC_FLOGI;
+ }
+ break;
default:
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"0288 Unknown FCoE event type 0x%x event tag "
@@ -2990,6 +3099,7 @@ static void
lpfc_sli4_async_dcbx_evt(struct lpfc_hba *phba,
struct lpfc_acqe_dcbx *acqe_dcbx)
{
+ phba->fc_eventTag = acqe_dcbx->event_tag;
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"0290 The SLI4 DCBX asynchronous event is not "
"handled yet\n");
@@ -3124,7 +3234,7 @@ static void lpfc_log_intr_mode(struct lpfc_hba *phba, uint32_t intr_mode)
* PCI devices.
*
* Return codes
- * 0 - sucessful
+ * 0 - successful
* other values - error
**/
static int
@@ -3220,7 +3330,7 @@ lpfc_reset_hba(struct lpfc_hba *phba)
* support the SLI-3 HBA device it attached to.
*
* Return codes
- * 0 - sucessful
+ * 0 - successful
* other values - error
**/
static int
@@ -3321,7 +3431,7 @@ lpfc_sli_driver_resource_unset(struct lpfc_hba *phba)
* support the SLI-4 HBA device it attached to.
*
* Return codes
- * 0 - sucessful
+ * 0 - successful
* other values - error
**/
static int
@@ -3432,7 +3542,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
/* Driver internel slow-path CQ Event pool */
INIT_LIST_HEAD(&phba->sli4_hba.sp_cqe_event_pool);
/* Response IOCB work queue list */
- INIT_LIST_HEAD(&phba->sli4_hba.sp_rspiocb_work_queue);
+ INIT_LIST_HEAD(&phba->sli4_hba.sp_queue_event);
/* Asynchronous event CQ Event work queue list */
INIT_LIST_HEAD(&phba->sli4_hba.sp_asynce_work_queue);
/* Fast-path XRI aborted CQ Event work queue list */
@@ -3461,6 +3571,10 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
if (unlikely(rc))
goto out_free_bsmbx;
+ rc = lpfc_sli4_fw_cfg_check(phba);
+ if (unlikely(rc))
+ goto out_free_bsmbx;
+
/* Set up the hba's configuration parameters. */
rc = lpfc_sli4_read_config(phba);
if (unlikely(rc))
@@ -3594,8 +3708,10 @@ lpfc_sli4_driver_resource_unset(struct lpfc_hba *phba)
/* Free the current connect table */
list_for_each_entry_safe(conn_entry, next_conn_entry,
- &phba->fcf_conn_rec_list, list)
+ &phba->fcf_conn_rec_list, list) {
+ list_del_init(&conn_entry->list);
kfree(conn_entry);
+ }
return;
}
@@ -3642,7 +3758,7 @@ lpfc_init_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp)
* device specific resource setup to support the HBA device it attached to.
*
* Return codes
- * 0 - sucessful
+ * 0 - successful
* other values - error
**/
static int
@@ -3688,7 +3804,7 @@ lpfc_setup_driver_resource_phase1(struct lpfc_hba *phba)
* device specific resource setup to support the HBA device it attached to.
*
* Return codes
- * 0 - sucessful
+ * 0 - successful
* other values - error
**/
static int
@@ -3753,7 +3869,7 @@ lpfc_free_iocb_list(struct lpfc_hba *phba)
* list and set up the IOCB tag array accordingly.
*
* Return codes
- * 0 - sucessful
+ * 0 - successful
* other values - error
**/
static int
@@ -3824,7 +3940,7 @@ lpfc_free_sgl_list(struct lpfc_hba *phba)
rc = lpfc_sli4_remove_all_sgl_pages(phba);
if (rc) {
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "2005 Unable to deregister pages from HBA: %x", rc);
+ "2005 Unable to deregister pages from HBA: %x\n", rc);
}
kfree(phba->sli4_hba.lpfc_els_sgl_array);
}
@@ -3872,7 +3988,7 @@ lpfc_free_active_sgl(struct lpfc_hba *phba)
* list and set up the sgl xritag tag array accordingly.
*
* Return codes
- * 0 - sucessful
+ * 0 - successful
* other values - error
**/
static int
@@ -3986,7 +4102,7 @@ out_free_mem:
* enabled and the driver is reinitializing the device.
*
* Return codes
- * 0 - sucessful
+ * 0 - successful
* ENOMEM - No availble memory
* EIO - The mailbox failed to complete successfully.
**/
@@ -4146,7 +4262,7 @@ lpfc_sli4_remove_rpi_hdrs(struct lpfc_hba *phba)
* PCI device data structure is set.
*
* Return codes
- * pointer to @phba - sucessful
+ * pointer to @phba - successful
* NULL - error
**/
static struct lpfc_hba *
@@ -4202,7 +4318,7 @@ lpfc_hba_free(struct lpfc_hba *phba)
* host with it.
*
* Return codes
- * 0 - sucessful
+ * 0 - successful
* other values - error
**/
static int
@@ -4273,7 +4389,8 @@ lpfc_setup_bg(struct lpfc_hba *phba, struct Scsi_Host *shost)
_dump_buf_data =
(char *) __get_free_pages(GFP_KERNEL, pagecnt);
if (_dump_buf_data) {
- printk(KERN_ERR "BLKGRD allocated %d pages for "
+ lpfc_printf_log(phba, KERN_ERR, LOG_BG,
+ "9043 BLKGRD: allocated %d pages for "
"_dump_buf_data at 0x%p\n",
(1 << pagecnt), _dump_buf_data);
_dump_buf_data_order = pagecnt;
@@ -4284,17 +4401,20 @@ lpfc_setup_bg(struct lpfc_hba *phba, struct Scsi_Host *shost)
--pagecnt;
}
if (!_dump_buf_data_order)
- printk(KERN_ERR "BLKGRD ERROR unable to allocate "
+ lpfc_printf_log(phba, KERN_ERR, LOG_BG,
+ "9044 BLKGRD: ERROR unable to allocate "
"memory for hexdump\n");
} else
- printk(KERN_ERR "BLKGRD already allocated _dump_buf_data=0x%p"
+ lpfc_printf_log(phba, KERN_ERR, LOG_BG,
+ "9045 BLKGRD: already allocated _dump_buf_data=0x%p"
"\n", _dump_buf_data);
if (!_dump_buf_dif) {
while (pagecnt) {
_dump_buf_dif =
(char *) __get_free_pages(GFP_KERNEL, pagecnt);
if (_dump_buf_dif) {
- printk(KERN_ERR "BLKGRD allocated %d pages for "
+ lpfc_printf_log(phba, KERN_ERR, LOG_BG,
+ "9046 BLKGRD: allocated %d pages for "
"_dump_buf_dif at 0x%p\n",
(1 << pagecnt), _dump_buf_dif);
_dump_buf_dif_order = pagecnt;
@@ -4305,10 +4425,12 @@ lpfc_setup_bg(struct lpfc_hba *phba, struct Scsi_Host *shost)
--pagecnt;
}
if (!_dump_buf_dif_order)
- printk(KERN_ERR "BLKGRD ERROR unable to allocate "
+ lpfc_printf_log(phba, KERN_ERR, LOG_BG,
+ "9047 BLKGRD: ERROR unable to allocate "
"memory for hexdump\n");
} else
- printk(KERN_ERR "BLKGRD already allocated _dump_buf_dif=0x%p\n",
+ lpfc_printf_log(phba, KERN_ERR, LOG_BG,
+ "9048 BLKGRD: already allocated _dump_buf_dif=0x%p\n",
_dump_buf_dif);
}
@@ -4365,7 +4487,7 @@ lpfc_post_init_setup(struct lpfc_hba *phba)
* with SLI-3 interface spec.
*
* Return codes
- * 0 - sucessful
+ * 0 - successful
* other values - error
**/
static int
@@ -4512,7 +4634,6 @@ int
lpfc_sli4_post_status_check(struct lpfc_hba *phba)
{
struct lpfc_register sta_reg, uerrlo_reg, uerrhi_reg, scratchpad;
- uint32_t onlnreg0, onlnreg1;
int i, port_error = -ENODEV;
if (!phba->sli4_hba.STAregaddr)
@@ -4556,21 +4677,20 @@ lpfc_sli4_post_status_check(struct lpfc_hba *phba)
bf_get(lpfc_scratchpad_slirev, &scratchpad),
bf_get(lpfc_scratchpad_featurelevel1, &scratchpad),
bf_get(lpfc_scratchpad_featurelevel2, &scratchpad));
-
+ phba->sli4_hba.ue_mask_lo = readl(phba->sli4_hba.UEMASKLOregaddr);
+ phba->sli4_hba.ue_mask_hi = readl(phba->sli4_hba.UEMASKHIregaddr);
/* With uncoverable error, log the error message and return error */
- onlnreg0 = readl(phba->sli4_hba.ONLINE0regaddr);
- onlnreg1 = readl(phba->sli4_hba.ONLINE1regaddr);
- if ((onlnreg0 != LPFC_ONLINE_NERR) || (onlnreg1 != LPFC_ONLINE_NERR)) {
- uerrlo_reg.word0 = readl(phba->sli4_hba.UERRLOregaddr);
- uerrhi_reg.word0 = readl(phba->sli4_hba.UERRHIregaddr);
- if (uerrlo_reg.word0 || uerrhi_reg.word0) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "1422 HBA Unrecoverable error: "
- "uerr_lo_reg=0x%x, uerr_hi_reg=0x%x, "
- "online0_reg=0x%x, online1_reg=0x%x\n",
- uerrlo_reg.word0, uerrhi_reg.word0,
- onlnreg0, onlnreg1);
- }
+ uerrlo_reg.word0 = readl(phba->sli4_hba.UERRLOregaddr);
+ uerrhi_reg.word0 = readl(phba->sli4_hba.UERRHIregaddr);
+ if ((~phba->sli4_hba.ue_mask_lo & uerrlo_reg.word0) ||
+ (~phba->sli4_hba.ue_mask_hi & uerrhi_reg.word0)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "1422 HBA Unrecoverable error: "
+ "uerr_lo_reg=0x%x, uerr_hi_reg=0x%x, "
+ "ue_mask_lo_reg=0x%x, ue_mask_hi_reg=0x%x\n",
+ uerrlo_reg.word0, uerrhi_reg.word0,
+ phba->sli4_hba.ue_mask_lo,
+ phba->sli4_hba.ue_mask_hi);
return -ENODEV;
}
@@ -4591,10 +4711,10 @@ lpfc_sli4_bar0_register_memmap(struct lpfc_hba *phba)
LPFC_UERR_STATUS_LO;
phba->sli4_hba.UERRHIregaddr = phba->sli4_hba.conf_regs_memmap_p +
LPFC_UERR_STATUS_HI;
- phba->sli4_hba.ONLINE0regaddr = phba->sli4_hba.conf_regs_memmap_p +
- LPFC_ONLINE0;
- phba->sli4_hba.ONLINE1regaddr = phba->sli4_hba.conf_regs_memmap_p +
- LPFC_ONLINE1;
+ phba->sli4_hba.UEMASKLOregaddr = phba->sli4_hba.conf_regs_memmap_p +
+ LPFC_UE_MASK_LO;
+ phba->sli4_hba.UEMASKHIregaddr = phba->sli4_hba.conf_regs_memmap_p +
+ LPFC_UE_MASK_HI;
phba->sli4_hba.SCRATCHPADregaddr = phba->sli4_hba.conf_regs_memmap_p +
LPFC_SCRATCHPAD;
}
@@ -4662,7 +4782,7 @@ lpfc_sli4_bar2_register_memmap(struct lpfc_hba *phba, uint32_t vf)
* this routine.
*
* Return codes
- * 0 - sucessful
+ * 0 - successful
* ENOMEM - could not allocated memory.
**/
static int
@@ -4761,7 +4881,7 @@ lpfc_destroy_bootstrap_mbox(struct lpfc_hba *phba)
* allocation for the port.
*
* Return codes
- * 0 - sucessful
+ * 0 - successful
* ENOMEM - No availble memory
* EIO - The mailbox failed to complete successfully.
**/
@@ -4825,7 +4945,8 @@ lpfc_sli4_read_config(struct lpfc_hba *phba)
phba->vpi_base = phba->sli4_hba.max_cfg_param.vpi_base;
phba->vfi_base = phba->sli4_hba.max_cfg_param.vfi_base;
phba->sli4_hba.next_rpi = phba->sli4_hba.max_cfg_param.rpi_base;
- phba->max_vpi = phba->sli4_hba.max_cfg_param.max_vpi;
+ phba->max_vpi = (phba->sli4_hba.max_cfg_param.max_vpi > 0) ?
+ (phba->sli4_hba.max_cfg_param.max_vpi - 1) : 0;
phba->max_vports = phba->max_vpi;
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
"2003 cfg params XRI(B:%d M:%d), "
@@ -4861,7 +4982,7 @@ lpfc_sli4_read_config(struct lpfc_hba *phba)
* HBA consistent with the SLI-4 interface spec.
*
* Return codes
- * 0 - sucessful
+ * 0 - successful
* ENOMEM - No availble memory
* EIO - The mailbox failed to complete successfully.
**/
@@ -4910,7 +5031,7 @@ lpfc_setup_endian_order(struct lpfc_hba *phba)
* we just use some constant number as place holder.
*
* Return codes
- * 0 - sucessful
+ * 0 - successful
* ENOMEM - No availble memory
* EIO - The mailbox failed to complete successfully.
**/
@@ -4979,10 +5100,9 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba)
/* It does not make sense to have more EQs than WQs */
if (cfg_fcp_eq_count > phba->cfg_fcp_wq_count) {
lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
- "2593 The number of FCP EQs (%d) is more "
- "than the number of FCP WQs (%d), take "
- "the number of FCP EQs same as than of "
- "WQs (%d)\n", cfg_fcp_eq_count,
+ "2593 The FCP EQ count(%d) cannot be greater "
+ "than the FCP WQ count(%d), limiting the "
+ "FCP EQ count to %d\n", cfg_fcp_eq_count,
phba->cfg_fcp_wq_count,
phba->cfg_fcp_wq_count);
cfg_fcp_eq_count = phba->cfg_fcp_wq_count;
@@ -5058,15 +5178,6 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba)
}
phba->sli4_hba.els_cq = qdesc;
- /* Create slow-path Unsolicited Receive Complete Queue */
- qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.cq_esize,
- phba->sli4_hba.cq_ecount);
- if (!qdesc) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "0502 Failed allocate slow-path USOL RX CQ\n");
- goto out_free_els_cq;
- }
- phba->sli4_hba.rxq_cq = qdesc;
/* Create fast-path FCP Completion Queue(s), one-to-one with EQs */
phba->sli4_hba.fcp_cq = kzalloc((sizeof(struct lpfc_queue *) *
@@ -5075,7 +5186,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba)
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"2577 Failed allocate memory for fast-path "
"CQ record array\n");
- goto out_free_rxq_cq;
+ goto out_free_els_cq;
}
for (fcp_cqidx = 0; fcp_cqidx < phba->cfg_fcp_eq_count; fcp_cqidx++) {
qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.cq_esize,
@@ -5188,9 +5299,6 @@ out_free_fcp_cq:
phba->sli4_hba.fcp_cq[fcp_cqidx] = NULL;
}
kfree(phba->sli4_hba.fcp_cq);
-out_free_rxq_cq:
- lpfc_sli4_queue_free(phba->sli4_hba.rxq_cq);
- phba->sli4_hba.rxq_cq = NULL;
out_free_els_cq:
lpfc_sli4_queue_free(phba->sli4_hba.els_cq);
phba->sli4_hba.els_cq = NULL;
@@ -5218,7 +5326,7 @@ out_error:
* operation.
*
* Return codes
- * 0 - sucessful
+ * 0 - successful
* ENOMEM - No availble memory
* EIO - The mailbox failed to complete successfully.
**/
@@ -5247,10 +5355,6 @@ lpfc_sli4_queue_destroy(struct lpfc_hba *phba)
lpfc_sli4_queue_free(phba->sli4_hba.dat_rq);
phba->sli4_hba.dat_rq = NULL;
- /* Release unsolicited receive complete queue */
- lpfc_sli4_queue_free(phba->sli4_hba.rxq_cq);
- phba->sli4_hba.rxq_cq = NULL;
-
/* Release ELS complete queue */
lpfc_sli4_queue_free(phba->sli4_hba.els_cq);
phba->sli4_hba.els_cq = NULL;
@@ -5286,7 +5390,7 @@ lpfc_sli4_queue_destroy(struct lpfc_hba *phba)
* operation.
*
* Return codes
- * 0 - sucessful
+ * 0 - successful
* ENOMEM - No availble memory
* EIO - The mailbox failed to complete successfully.
**/
@@ -5383,25 +5487,6 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba)
phba->sli4_hba.els_cq->queue_id,
phba->sli4_hba.sp_eq->queue_id);
- /* Set up slow-path Unsolicited Receive Complete Queue */
- if (!phba->sli4_hba.rxq_cq) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "0532 USOL RX CQ not allocated\n");
- goto out_destroy_els_cq;
- }
- rc = lpfc_cq_create(phba, phba->sli4_hba.rxq_cq, phba->sli4_hba.sp_eq,
- LPFC_RCQ, LPFC_USOL);
- if (rc) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "0533 Failed setup of slow-path USOL RX CQ: "
- "rc = 0x%x\n", rc);
- goto out_destroy_els_cq;
- }
- lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
- "2587 USL CQ setup: cq-id=%d, parent eq-id=%d\n",
- phba->sli4_hba.rxq_cq->queue_id,
- phba->sli4_hba.sp_eq->queue_id);
-
/* Set up fast-path FCP Response Complete Queue */
for (fcp_cqidx = 0; fcp_cqidx < phba->cfg_fcp_eq_count; fcp_cqidx++) {
if (!phba->sli4_hba.fcp_cq[fcp_cqidx]) {
@@ -5507,7 +5592,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba)
goto out_destroy_fcp_wq;
}
rc = lpfc_rq_create(phba, phba->sli4_hba.hdr_rq, phba->sli4_hba.dat_rq,
- phba->sli4_hba.rxq_cq, LPFC_USOL);
+ phba->sli4_hba.els_cq, LPFC_USOL);
if (rc) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"0541 Failed setup of Receive Queue: "
@@ -5519,7 +5604,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba)
"parent cq-id=%d\n",
phba->sli4_hba.hdr_rq->queue_id,
phba->sli4_hba.dat_rq->queue_id,
- phba->sli4_hba.rxq_cq->queue_id);
+ phba->sli4_hba.els_cq->queue_id);
return 0;
out_destroy_fcp_wq:
@@ -5531,8 +5616,6 @@ out_destroy_mbx_wq:
out_destroy_fcp_cq:
for (--fcp_cqidx; fcp_cqidx >= 0; fcp_cqidx--)
lpfc_cq_destroy(phba, phba->sli4_hba.fcp_cq[fcp_cqidx]);
- lpfc_cq_destroy(phba, phba->sli4_hba.rxq_cq);
-out_destroy_els_cq:
lpfc_cq_destroy(phba, phba->sli4_hba.els_cq);
out_destroy_mbx_cq:
lpfc_cq_destroy(phba, phba->sli4_hba.mbx_cq);
@@ -5552,7 +5635,7 @@ out_error:
* operation.
*
* Return codes
- * 0 - sucessful
+ * 0 - successful
* ENOMEM - No availble memory
* EIO - The mailbox failed to complete successfully.
**/
@@ -5574,8 +5657,6 @@ lpfc_sli4_queue_unset(struct lpfc_hba *phba)
lpfc_cq_destroy(phba, phba->sli4_hba.mbx_cq);
/* Unset ELS complete queue */
lpfc_cq_destroy(phba, phba->sli4_hba.els_cq);
- /* Unset unsolicited receive complete queue */
- lpfc_cq_destroy(phba, phba->sli4_hba.rxq_cq);
/* Unset FCP response complete queue */
for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; fcp_qidx++)
lpfc_cq_destroy(phba, phba->sli4_hba.fcp_cq[fcp_qidx]);
@@ -5599,7 +5680,7 @@ lpfc_sli4_queue_unset(struct lpfc_hba *phba)
* Later, this can be used for all the slow-path events.
*
* Return codes
- * 0 - sucessful
+ * 0 - successful
* -ENOMEM - No availble memory
**/
static int
@@ -5760,7 +5841,7 @@ lpfc_sli4_cq_event_release_all(struct lpfc_hba *phba)
* all resources assigned to the PCI function which originates this request.
*
* Return codes
- * 0 - sucessful
+ * 0 - successful
* ENOMEM - No availble memory
* EIO - The mailbox failed to complete successfully.
**/
@@ -5923,7 +6004,7 @@ lpfc_sli4_fcfi_unreg(struct lpfc_hba *phba, uint16_t fcfi)
* with SLI-4 interface spec.
*
* Return codes
- * 0 - sucessful
+ * 0 - successful
* other values - error
**/
static int
@@ -6052,7 +6133,7 @@ lpfc_sli4_pci_mem_unset(struct lpfc_hba *phba)
* will be left with MSI-X enabled and leaks its vectors.
*
* Return codes
- * 0 - sucessful
+ * 0 - successful
* other values - error
**/
static int
@@ -6184,7 +6265,7 @@ lpfc_sli_disable_msix(struct lpfc_hba *phba)
* is done in this function.
*
* Return codes
- * 0 - sucessful
+ * 0 - successful
* other values - error
*/
static int
@@ -6243,7 +6324,7 @@ lpfc_sli_disable_msi(struct lpfc_hba *phba)
* MSI-X -> MSI -> IRQ.
*
* Return codes
- * 0 - sucessful
+ * 0 - successful
* other values - error
**/
static uint32_t
@@ -6333,7 +6414,7 @@ lpfc_sli_disable_intr(struct lpfc_hba *phba)
* enabled and leaks its vectors.
*
* Return codes
- * 0 - sucessful
+ * 0 - successful
* other values - error
**/
static int
@@ -6443,7 +6524,7 @@ lpfc_sli4_disable_msix(struct lpfc_hba *phba)
* which is done in this function.
*
* Return codes
- * 0 - sucessful
+ * 0 - successful
* other values - error
**/
static int
@@ -6508,7 +6589,7 @@ lpfc_sli4_disable_msi(struct lpfc_hba *phba)
* MSI-X -> MSI -> IRQ.
*
* Return codes
- * 0 - sucessful
+ * 0 - successful
* other values - error
**/
static uint32_t
@@ -6722,6 +6803,7 @@ lpfc_pci_probe_one_s3(struct pci_dev *pdev, const struct pci_device_id *pid)
{
struct lpfc_hba *phba;
struct lpfc_vport *vport = NULL;
+ struct Scsi_Host *shost = NULL;
int error;
uint32_t cfg_mode, intr_mode;
@@ -6800,6 +6882,7 @@ lpfc_pci_probe_one_s3(struct pci_dev *pdev, const struct pci_device_id *pid)
goto out_destroy_shost;
}
+ shost = lpfc_shost_from_vport(vport); /* save shost for error cleanup */
/* Now, trying to enable interrupt and bring up the device */
cfg_mode = phba->cfg_use_msi;
while (true) {
@@ -6866,6 +6949,8 @@ out_unset_pci_mem_s3:
lpfc_sli_pci_mem_unset(phba);
out_disable_pci_dev:
lpfc_disable_pci_dev(phba);
+ if (shost)
+ scsi_host_put(shost);
out_free_phba:
lpfc_hba_free(phba);
return error;
@@ -7036,6 +7121,7 @@ lpfc_pci_resume_one_s3(struct pci_dev *pdev)
/* Restore device state from PCI config space */
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
+
if (pdev->is_busmaster)
pci_set_master(pdev);
@@ -7070,6 +7156,75 @@ lpfc_pci_resume_one_s3(struct pci_dev *pdev)
}
/**
+ * lpfc_sli_prep_dev_for_recover - Prepare SLI3 device for pci slot recover
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is called to prepare the SLI3 device for PCI slot recover. It
+ * aborts and stops all the on-going I/Os on the pci device.
+ **/
+static void
+lpfc_sli_prep_dev_for_recover(struct lpfc_hba *phba)
+{
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2723 PCI channel I/O abort preparing for recovery\n");
+ /* Prepare for bringing HBA offline */
+ lpfc_offline_prep(phba);
+ /* Clear sli active flag to prevent sysfs access to HBA */
+ spin_lock_irq(&phba->hbalock);
+ phba->sli.sli_flag &= ~LPFC_SLI_ACTIVE;
+ spin_unlock_irq(&phba->hbalock);
+ /* Stop and flush all I/Os and bring HBA offline */
+ lpfc_offline(phba);
+}
+
+/**
+ * lpfc_sli_prep_dev_for_reset - Prepare SLI3 device for pci slot reset
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is called to prepare the SLI3 device for PCI slot reset. It
+ * disables the device interrupt and pci device, and aborts the internal FCP
+ * pending I/Os.
+ **/
+static void
+lpfc_sli_prep_dev_for_reset(struct lpfc_hba *phba)
+{
+ struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_sli_ring *pring;
+
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2710 PCI channel disable preparing for reset\n");
+ /* Disable interrupt and pci device */
+ lpfc_sli_disable_intr(phba);
+ pci_disable_device(phba->pcidev);
+ /*
+ * There may be I/Os dropped by the firmware.
+ * Error iocb (I/O) on txcmplq and let the SCSI layer
+ * retry it after re-establishing link.
+ */
+ pring = &psli->ring[psli->fcp_ring];
+ lpfc_sli_abort_iocb_ring(phba, pring);
+}
+
+/**
+ * lpfc_sli_prep_dev_for_perm_failure - Prepare SLI3 dev for pci slot disable
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is called to prepare the SLI3 device for PCI slot permanently
+ * disabling. It blocks the SCSI transport layer traffic and flushes the FCP
+ * pending I/Os.
+ **/
+static void
+lpfc_prep_dev_for_perm_failure(struct lpfc_hba *phba)
+{
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2711 PCI channel permanent disable for failure\n");
+ /* Block all SCSI devices' I/Os on the host */
+ lpfc_scsi_dev_block(phba);
+ /* Clean up all driver's outstanding SCSI I/Os */
+ lpfc_sli_flush_fcp_rings(phba);
+}
+
+/**
* lpfc_io_error_detected_s3 - Method for handling SLI-3 device PCI I/O error
* @pdev: pointer to PCI device.
* @state: the current PCI connection state.
@@ -7083,6 +7238,7 @@ lpfc_pci_resume_one_s3(struct pci_dev *pdev)
* as desired.
*
* Return codes
+ * PCI_ERS_RESULT_CAN_RECOVER - can be recovered with reset_link
* PCI_ERS_RESULT_NEED_RESET - need to reset before recovery
* PCI_ERS_RESULT_DISCONNECT - device could not be recovered
**/
@@ -7091,33 +7247,27 @@ lpfc_io_error_detected_s3(struct pci_dev *pdev, pci_channel_state_t state)
{
struct Scsi_Host *shost = pci_get_drvdata(pdev);
struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
- struct lpfc_sli *psli = &phba->sli;
- struct lpfc_sli_ring *pring;
- if (state == pci_channel_io_perm_failure) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "0472 PCI channel I/O permanent failure\n");
- /* Block all SCSI devices' I/Os on the host */
- lpfc_scsi_dev_block(phba);
- /* Clean up all driver's outstanding SCSI I/Os */
- lpfc_sli_flush_fcp_rings(phba);
+ switch (state) {
+ case pci_channel_io_normal:
+ /* Non-fatal error, prepare for recovery */
+ lpfc_sli_prep_dev_for_recover(phba);
+ return PCI_ERS_RESULT_CAN_RECOVER;
+ case pci_channel_io_frozen:
+ /* Fatal error, prepare for slot reset */
+ lpfc_sli_prep_dev_for_reset(phba);
+ return PCI_ERS_RESULT_NEED_RESET;
+ case pci_channel_io_perm_failure:
+ /* Permanent failure, prepare for device down */
+ lpfc_prep_dev_for_perm_failure(phba);
return PCI_ERS_RESULT_DISCONNECT;
+ default:
+ /* Unknown state, prepare and request slot reset */
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "0472 Unknown PCI error state: x%x\n", state);
+ lpfc_sli_prep_dev_for_reset(phba);
+ return PCI_ERS_RESULT_NEED_RESET;
}
-
- pci_disable_device(pdev);
- /*
- * There may be I/Os dropped by the firmware.
- * Error iocb (I/O) on txcmplq and let the SCSI layer
- * retry it after re-establishing link.
- */
- pring = &psli->ring[psli->fcp_ring];
- lpfc_sli_abort_iocb_ring(phba, pring);
-
- /* Disable interrupt */
- lpfc_sli_disable_intr(phba);
-
- /* Request a slot reset. */
- return PCI_ERS_RESULT_NEED_RESET;
}
/**
@@ -7197,7 +7347,12 @@ lpfc_io_resume_s3(struct pci_dev *pdev)
struct Scsi_Host *shost = pci_get_drvdata(pdev);
struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+ /* Bring the device online */
lpfc_online(phba);
+
+ /* Clean up Advanced Error Reporting (AER) if needed */
+ if (phba->hba_flag & HBA_AER_ENABLED)
+ pci_cleanup_aer_uncorrect_error_status(pdev);
}
/**
@@ -7213,15 +7368,15 @@ lpfc_sli4_get_els_iocb_cnt(struct lpfc_hba *phba)
if (phba->sli_rev == LPFC_SLI_REV4) {
if (max_xri <= 100)
- return 4;
+ return 10;
else if (max_xri <= 256)
- return 8;
+ return 25;
else if (max_xri <= 512)
- return 16;
+ return 50;
else if (max_xri <= 1024)
- return 32;
+ return 100;
else
- return 48;
+ return 150;
} else
return 0;
}
@@ -7249,6 +7404,7 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
{
struct lpfc_hba *phba;
struct lpfc_vport *vport = NULL;
+ struct Scsi_Host *shost = NULL;
int error;
uint32_t cfg_mode, intr_mode;
int mcnt;
@@ -7329,6 +7485,7 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
goto out_destroy_shost;
}
+ shost = lpfc_shost_from_vport(vport); /* save shost for error cleanup */
/* Now, trying to enable interrupt and bring up the device */
cfg_mode = phba->cfg_use_msi;
while (true) {
@@ -7397,6 +7554,8 @@ out_unset_pci_mem_s4:
lpfc_sli4_pci_mem_unset(phba);
out_disable_pci_dev:
lpfc_disable_pci_dev(phba);
+ if (shost)
+ scsi_host_put(shost);
out_free_phba:
lpfc_hba_free(phba);
return error;
@@ -7971,6 +8130,10 @@ static struct pci_device_id lpfc_id_table[] = {
PCI_ANY_ID, PCI_ANY_ID, },
{PCI_VENDOR_ID_SERVERENGINE, PCI_DEVICE_ID_TIGERSHARK,
PCI_ANY_ID, PCI_ANY_ID, },
+ {PCI_VENDOR_ID_SERVERENGINE, PCI_DEVICE_ID_TOMCAT,
+ PCI_ANY_ID, PCI_ANY_ID, },
+ {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_FALCON,
+ PCI_ANY_ID, PCI_ANY_ID, },
{ 0 }
};
@@ -8053,15 +8216,15 @@ lpfc_exit(void)
if (lpfc_enable_npiv)
fc_release_transport(lpfc_vport_transport_template);
if (_dump_buf_data) {
- printk(KERN_ERR "BLKGRD freeing %lu pages for _dump_buf_data "
- "at 0x%p\n",
+ printk(KERN_ERR "9062 BLKGRD: freeing %lu pages for "
+ "_dump_buf_data at 0x%p\n",
(1L << _dump_buf_data_order), _dump_buf_data);
free_pages((unsigned long)_dump_buf_data, _dump_buf_data_order);
}
if (_dump_buf_dif) {
- printk(KERN_ERR "BLKGRD freeing %lu pages for _dump_buf_dif "
- "at 0x%p\n",
+ printk(KERN_ERR "9049 BLKGRD: freeing %lu pages for "
+ "_dump_buf_dif at 0x%p\n",
(1L << _dump_buf_dif_order), _dump_buf_dif);
free_pages((unsigned long)_dump_buf_dif, _dump_buf_dif_order);
}
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index 1ab4059..a9afd8b 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -25,8 +25,8 @@
#include <scsi/scsi_device.h>
#include <scsi/scsi_transport_fc.h>
-
#include <scsi/scsi.h>
+#include <scsi/fc/fc_fs.h>
#include "lpfc_hw4.h"
#include "lpfc_hw.h"
@@ -820,6 +820,10 @@ lpfc_reg_vpi(struct lpfc_vport *vport, LPFC_MBOXQ_t *pmb)
mb->un.varRegVpi.vpi = vport->vpi + vport->phba->vpi_base;
mb->un.varRegVpi.sid = vport->fc_myDID;
mb->un.varRegVpi.vfi = vport->vfi + vport->phba->vfi_base;
+ memcpy(mb->un.varRegVpi.wwn, &vport->fc_portname,
+ sizeof(struct lpfc_name));
+ mb->un.varRegVpi.wwn[0] = cpu_to_le32(mb->un.varRegVpi.wwn[0]);
+ mb->un.varRegVpi.wwn[1] = cpu_to_le32(mb->un.varRegVpi.wwn[1]);
mb->mbxCommand = MBX_REG_VPI;
mb->mbxOwner = OWN_HOST;
@@ -849,7 +853,10 @@ lpfc_unreg_vpi(struct lpfc_hba *phba, uint16_t vpi, LPFC_MBOXQ_t *pmb)
MAILBOX_t *mb = &pmb->u.mb;
memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
- mb->un.varUnregVpi.vpi = vpi + phba->vpi_base;
+ if (phba->sli_rev < LPFC_SLI_REV4)
+ mb->un.varUnregVpi.vpi = vpi + phba->vpi_base;
+ else
+ mb->un.varUnregVpi.sli4_vpi = vpi + phba->vpi_base;
mb->mbxCommand = MBX_UNREG_VPI;
mb->mbxOwner = OWN_HOST;
@@ -1132,7 +1139,7 @@ lpfc_config_ring(struct lpfc_hba * phba, int ring, LPFC_MBOXQ_t * pmb)
/* Otherwise we setup specific rctl / type masks for this ring */
for (i = 0; i < pring->num_mask; i++) {
mb->un.varCfgRing.rrRegs[i].rval = pring->prt[i].rctl;
- if (mb->un.varCfgRing.rrRegs[i].rval != FC_ELS_REQ)
+ if (mb->un.varCfgRing.rrRegs[i].rval != FC_RCTL_ELS_REQ)
mb->un.varCfgRing.rrRegs[i].rmask = 0xff;
else
mb->un.varCfgRing.rrRegs[i].rmask = 0xfe;
@@ -1654,9 +1661,12 @@ lpfc_sli4_config(struct lpfc_hba *phba, struct lpfcMboxq *mbox,
/* Allocate record for keeping SGE virtual addresses */
mbox->sge_array = kmalloc(sizeof(struct lpfc_mbx_nembed_sge_virt),
GFP_KERNEL);
- if (!mbox->sge_array)
+ if (!mbox->sge_array) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
+ "2527 Failed to allocate non-embedded SGE "
+ "array.\n");
return 0;
-
+ }
for (pagen = 0, alloc_len = 0; pagen < pcount; pagen++) {
/* The DMA memory is always allocated in the length of a
* page even though the last SGE might not fill up to a
@@ -1753,11 +1763,6 @@ lpfc_request_features(struct lpfc_hba *phba, struct lpfcMboxq *mboxq)
/* Set up host requested features. */
bf_set(lpfc_mbx_rq_ftr_rq_fcpi, &mboxq->u.mqe.un.req_ftrs, 1);
- if (phba->cfg_enable_fip)
- bf_set(lpfc_mbx_rq_ftr_rq_ifip, &mboxq->u.mqe.un.req_ftrs, 0);
- else
- bf_set(lpfc_mbx_rq_ftr_rq_ifip, &mboxq->u.mqe.un.req_ftrs, 1);
-
/* Enable DIF (block guard) only if configured to do so. */
if (phba->cfg_enable_bg)
bf_set(lpfc_mbx_rq_ftr_rq_dif, &mboxq->u.mqe.un.req_ftrs, 1);
@@ -1817,6 +1822,9 @@ lpfc_reg_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport, dma_addr_t phys)
bf_set(lpfc_reg_vfi_vfi, reg_vfi, vport->vfi + vport->phba->vfi_base);
bf_set(lpfc_reg_vfi_fcfi, reg_vfi, vport->phba->fcf.fcfi);
bf_set(lpfc_reg_vfi_vpi, reg_vfi, vport->vpi + vport->phba->vpi_base);
+ memcpy(reg_vfi->wwn, &vport->fc_portname, sizeof(struct lpfc_name));
+ reg_vfi->wwn[0] = cpu_to_le32(reg_vfi->wwn[0]);
+ reg_vfi->wwn[1] = cpu_to_le32(reg_vfi->wwn[1]);
reg_vfi->bde.addrHigh = putPaddrHigh(phys);
reg_vfi->bde.addrLow = putPaddrLow(phys);
reg_vfi->bde.tus.f.bdeSize = sizeof(vport->fc_sparam);
@@ -1850,7 +1858,7 @@ lpfc_init_vpi(struct lpfc_hba *phba, struct lpfcMboxq *mbox, uint16_t vpi)
/**
* lpfc_unreg_vfi - Initialize the UNREG_VFI mailbox command
* @mbox: pointer to lpfc mbox command to initialize.
- * @vfi: VFI to be unregistered.
+ * @vport: vport associated with the VF.
*
* The UNREG_VFI mailbox command causes the SLI Host to put a virtual fabric
* (logical NPort) into the inactive state. The SLI Host must have logged out
@@ -1859,11 +1867,12 @@ lpfc_init_vpi(struct lpfc_hba *phba, struct lpfcMboxq *mbox, uint16_t vpi)
* fabric inactive.
**/
void
-lpfc_unreg_vfi(struct lpfcMboxq *mbox, uint16_t vfi)
+lpfc_unreg_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport)
{
memset(mbox, 0, sizeof(*mbox));
bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_UNREG_VFI);
- bf_set(lpfc_unreg_vfi_vfi, &mbox->u.mqe.un.unreg_vfi, vfi);
+ bf_set(lpfc_unreg_vfi_vfi, &mbox->u.mqe.un.unreg_vfi,
+ vport->vfi + vport->phba->vfi_base);
}
/**
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index 3e74136..2ed6af1 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -1223,6 +1223,12 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_vport *vport,
list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) {
if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) &&
(ndlp == (struct lpfc_nodelist *) mb->context2)) {
+ if (phba->sli_rev == LPFC_SLI_REV4) {
+ spin_unlock_irq(&phba->hbalock);
+ lpfc_sli4_free_rpi(phba,
+ mb->u.mb.un.varRegLogin.rpi);
+ spin_lock_irq(&phba->hbalock);
+ }
mp = (struct lpfc_dmabuf *) (mb->context1);
if (mp) {
__lpfc_mbuf_free(phba, mp->virt, mp->phys);
@@ -1230,6 +1236,7 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_vport *vport,
}
lpfc_nlp_put(ndlp);
list_del(&mb->list);
+ phba->sli.mboxq_cnt--;
mempool_free(mb, phba->mbox_mem_pool);
}
}
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index c88f59f..a246410 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -59,22 +59,26 @@ static char *dif_op_str[] = {
};
static void
lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb);
+static void
+lpfc_release_scsi_buf_s3(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb);
static void
-lpfc_debug_save_data(struct scsi_cmnd *cmnd)
+lpfc_debug_save_data(struct lpfc_hba *phba, struct scsi_cmnd *cmnd)
{
void *src, *dst;
struct scatterlist *sgde = scsi_sglist(cmnd);
if (!_dump_buf_data) {
- printk(KERN_ERR "BLKGRD ERROR %s _dump_buf_data is NULL\n",
+ lpfc_printf_log(phba, KERN_ERR, LOG_BG,
+ "9050 BLKGRD: ERROR %s _dump_buf_data is NULL\n",
__func__);
return;
}
if (!sgde) {
- printk(KERN_ERR "BLKGRD ERROR: data scatterlist is null\n");
+ lpfc_printf_log(phba, KERN_ERR, LOG_BG,
+ "9051 BLKGRD: ERROR: data scatterlist is null\n");
return;
}
@@ -88,19 +92,21 @@ lpfc_debug_save_data(struct scsi_cmnd *cmnd)
}
static void
-lpfc_debug_save_dif(struct scsi_cmnd *cmnd)
+lpfc_debug_save_dif(struct lpfc_hba *phba, struct scsi_cmnd *cmnd)
{
void *src, *dst;
struct scatterlist *sgde = scsi_prot_sglist(cmnd);
if (!_dump_buf_dif) {
- printk(KERN_ERR "BLKGRD ERROR %s _dump_buf_data is NULL\n",
+ lpfc_printf_log(phba, KERN_ERR, LOG_BG,
+ "9052 BLKGRD: ERROR %s _dump_buf_data is NULL\n",
__func__);
return;
}
if (!sgde) {
- printk(KERN_ERR "BLKGRD ERROR: prot scatterlist is null\n");
+ lpfc_printf_log(phba, KERN_ERR, LOG_BG,
+ "9053 BLKGRD: ERROR: prot scatterlist is null\n");
return;
}
@@ -242,6 +248,36 @@ lpfc_send_sdev_queuedepth_change_event(struct lpfc_hba *phba,
}
/**
+ * lpfc_change_queue_depth - Alter scsi device queue depth
+ * @sdev: Pointer the scsi device on which to change the queue depth.
+ * @qdepth: New queue depth to set the sdev to.
+ * @reason: The reason for the queue depth change.
+ *
+ * This function is called by the midlayer and the LLD to alter the queue
+ * depth for a scsi device. This function sets the queue depth to the new
+ * value and sends an event out to log the queue depth change.
+ **/
+int
+lpfc_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
+{
+ struct lpfc_vport *vport = (struct lpfc_vport *) sdev->host->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_rport_data *rdata;
+ unsigned long new_queue_depth, old_queue_depth;
+
+ old_queue_depth = sdev->queue_depth;
+ scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
+ new_queue_depth = sdev->queue_depth;
+ rdata = sdev->hostdata;
+ if (rdata)
+ lpfc_send_sdev_queuedepth_change_event(phba, vport,
+ rdata->pnode, sdev->lun,
+ old_queue_depth,
+ new_queue_depth);
+ return sdev->queue_depth;
+}
+
+/**
* lpfc_rampdown_queue_depth - Post RAMP_DOWN_QUEUE event to worker thread
* @phba: The Hba for which this call is being executed.
*
@@ -305,8 +341,10 @@ lpfc_rampup_queue_depth(struct lpfc_vport *vport,
if (vport->cfg_lun_queue_depth <= queue_depth)
return;
spin_lock_irqsave(&phba->hbalock, flags);
- if (((phba->last_ramp_up_time + QUEUE_RAMP_UP_INTERVAL) > jiffies) ||
- ((phba->last_rsrc_error_time + QUEUE_RAMP_UP_INTERVAL ) > jiffies)) {
+ if (time_before(jiffies,
+ phba->last_ramp_up_time + QUEUE_RAMP_UP_INTERVAL) ||
+ time_before(jiffies,
+ phba->last_rsrc_error_time + QUEUE_RAMP_UP_INTERVAL)) {
spin_unlock_irqrestore(&phba->hbalock, flags);
return;
}
@@ -338,10 +376,9 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba)
struct lpfc_vport **vports;
struct Scsi_Host *shost;
struct scsi_device *sdev;
- unsigned long new_queue_depth, old_queue_depth;
+ unsigned long new_queue_depth;
unsigned long num_rsrc_err, num_cmd_success;
int i;
- struct lpfc_rport_data *rdata;
num_rsrc_err = atomic_read(&phba->num_rsrc_err);
num_cmd_success = atomic_read(&phba->num_cmd_success);
@@ -359,22 +396,8 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba)
else
new_queue_depth = sdev->queue_depth -
new_queue_depth;
- old_queue_depth = sdev->queue_depth;
- if (sdev->ordered_tags)
- scsi_adjust_queue_depth(sdev,
- MSG_ORDERED_TAG,
- new_queue_depth);
- else
- scsi_adjust_queue_depth(sdev,
- MSG_SIMPLE_TAG,
- new_queue_depth);
- rdata = sdev->hostdata;
- if (rdata)
- lpfc_send_sdev_queuedepth_change_event(
- phba, vports[i],
- rdata->pnode,
- sdev->lun, old_queue_depth,
- new_queue_depth);
+ lpfc_change_queue_depth(sdev, new_queue_depth,
+ SCSI_QDEPTH_DEFAULT);
}
}
lpfc_destroy_vport_work_array(phba, vports);
@@ -398,7 +421,6 @@ lpfc_ramp_up_queue_handler(struct lpfc_hba *phba)
struct Scsi_Host *shost;
struct scsi_device *sdev;
int i;
- struct lpfc_rport_data *rdata;
vports = lpfc_create_vport_work_array(phba);
if (vports != NULL)
@@ -408,22 +430,9 @@ lpfc_ramp_up_queue_handler(struct lpfc_hba *phba)
if (vports[i]->cfg_lun_queue_depth <=
sdev->queue_depth)
continue;
- if (sdev->ordered_tags)
- scsi_adjust_queue_depth(sdev,
- MSG_ORDERED_TAG,
- sdev->queue_depth+1);
- else
- scsi_adjust_queue_depth(sdev,
- MSG_SIMPLE_TAG,
- sdev->queue_depth+1);
- rdata = sdev->hostdata;
- if (rdata)
- lpfc_send_sdev_queuedepth_change_event(
- phba, vports[i],
- rdata->pnode,
- sdev->lun,
- sdev->queue_depth - 1,
- sdev->queue_depth);
+ lpfc_change_queue_depth(sdev,
+ sdev->queue_depth+1,
+ SCSI_QDEPTH_RAMP_UP);
}
}
lpfc_destroy_vport_work_array(phba, vports);
@@ -589,7 +598,7 @@ lpfc_new_scsi_buf_s3(struct lpfc_vport *vport, int num_to_alloc)
iocb->ulpClass = CLASS3;
psb->status = IOSTAT_SUCCESS;
/* Put it back into the SCSI buffer list */
- lpfc_release_scsi_buf_s4(phba, psb);
+ lpfc_release_scsi_buf_s3(phba, psb);
}
@@ -1024,7 +1033,8 @@ lpfc_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
lpfc_cmd->seg_cnt = nseg;
if (lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt) {
- printk(KERN_ERR "%s: Too many sg segments from "
+ lpfc_printf_log(phba, KERN_ERR, LOG_BG,
+ "9064 BLKGRD: %s: Too many sg segments from "
"dma_map_sg. Config %d, seg_cnt %d\n",
__func__, phba->cfg_sg_seg_cnt,
lpfc_cmd->seg_cnt);
@@ -1112,7 +1122,7 @@ lpfc_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
* with the cmd
*/
static int
-lpfc_sc_to_sli_prof(struct scsi_cmnd *sc)
+lpfc_sc_to_sli_prof(struct lpfc_hba *phba, struct scsi_cmnd *sc)
{
uint8_t guard_type = scsi_host_get_guard(sc->device->host);
uint8_t ret_prof = LPFC_PROF_INVALID;
@@ -1136,7 +1146,8 @@ lpfc_sc_to_sli_prof(struct scsi_cmnd *sc)
case SCSI_PROT_NORMAL:
default:
- printk(KERN_ERR "Bad op/guard:%d/%d combination\n",
+ lpfc_printf_log(phba, KERN_ERR, LOG_BG,
+ "9063 BLKGRD:Bad op/guard:%d/%d combination\n",
scsi_get_prot_op(sc), guard_type);
break;
@@ -1157,7 +1168,8 @@ lpfc_sc_to_sli_prof(struct scsi_cmnd *sc)
case SCSI_PROT_WRITE_STRIP:
case SCSI_PROT_NORMAL:
default:
- printk(KERN_ERR "Bad op/guard:%d/%d combination\n",
+ lpfc_printf_log(phba, KERN_ERR, LOG_BG,
+ "9075 BLKGRD: Bad op/guard:%d/%d combination\n",
scsi_get_prot_op(sc), guard_type);
break;
}
@@ -1259,7 +1271,7 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc,
uint16_t apptagmask, apptagval;
pde1 = (struct lpfc_pde *) bpl;
- prof = lpfc_sc_to_sli_prof(sc);
+ prof = lpfc_sc_to_sli_prof(phba, sc);
if (prof == LPFC_PROF_INVALID)
goto out;
@@ -1359,7 +1371,7 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
return 0;
}
- prof = lpfc_sc_to_sli_prof(sc);
+ prof = lpfc_sc_to_sli_prof(phba, sc);
if (prof == LPFC_PROF_INVALID)
goto out;
@@ -1408,7 +1420,8 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
subtotal = 0; /* total bytes processed for current prot grp */
while (!pgdone) {
if (!sgde) {
- printk(KERN_ERR "%s Invalid data segment\n",
+ lpfc_printf_log(phba, KERN_ERR, LOG_BG,
+ "9065 BLKGRD:%s Invalid data segment\n",
__func__);
return 0;
}
@@ -1462,7 +1475,8 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
reftag += protgrp_blks;
} else {
/* if we're here, we have a bug */
- printk(KERN_ERR "BLKGRD: bug in %s\n", __func__);
+ lpfc_printf_log(phba, KERN_ERR, LOG_BG,
+ "9054 BLKGRD: bug in %s\n", __func__);
}
} while (!alldone);
@@ -1544,8 +1558,10 @@ lpfc_bg_scsi_prep_dma_buf(struct lpfc_hba *phba,
lpfc_cmd->seg_cnt = datasegcnt;
if (lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt) {
- printk(KERN_ERR "%s: Too many sg segments from "
- "dma_map_sg. Config %d, seg_cnt %d\n",
+ lpfc_printf_log(phba, KERN_ERR, LOG_BG,
+ "9067 BLKGRD: %s: Too many sg segments"
+ " from dma_map_sg. Config %d, seg_cnt"
+ " %d\n",
__func__, phba->cfg_sg_seg_cnt,
lpfc_cmd->seg_cnt);
scsi_dma_unmap(scsi_cmnd);
@@ -1579,8 +1595,9 @@ lpfc_bg_scsi_prep_dma_buf(struct lpfc_hba *phba,
lpfc_cmd->prot_seg_cnt = protsegcnt;
if (lpfc_cmd->prot_seg_cnt
> phba->cfg_prot_sg_seg_cnt) {
- printk(KERN_ERR "%s: Too many prot sg segments "
- "from dma_map_sg. Config %d,"
+ lpfc_printf_log(phba, KERN_ERR, LOG_BG,
+ "9068 BLKGRD: %s: Too many prot sg "
+ "segments from dma_map_sg. Config %d,"
"prot_seg_cnt %d\n", __func__,
phba->cfg_prot_sg_seg_cnt,
lpfc_cmd->prot_seg_cnt);
@@ -1671,23 +1688,26 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd,
uint32_t bgstat = bgf->bgstat;
uint64_t failing_sector = 0;
- printk(KERN_ERR "BG ERROR in cmd 0x%x lba 0x%llx blk cnt 0x%x "
+ lpfc_printf_log(phba, KERN_ERR, LOG_BG, "9069 BLKGRD: BG ERROR in cmd"
+ " 0x%x lba 0x%llx blk cnt 0x%x "
"bgstat=0x%x bghm=0x%x\n",
cmd->cmnd[0], (unsigned long long)scsi_get_lba(cmd),
blk_rq_sectors(cmd->request), bgstat, bghm);
spin_lock(&_dump_buf_lock);
if (!_dump_buf_done) {
- printk(KERN_ERR "Saving Data for %u blocks to debugfs\n",
+ lpfc_printf_log(phba, KERN_ERR, LOG_BG, "9070 BLKGRD: Saving"
+ " Data for %u blocks to debugfs\n",
(cmd->cmnd[7] << 8 | cmd->cmnd[8]));
- lpfc_debug_save_data(cmd);
+ lpfc_debug_save_data(phba, cmd);
/* If we have a prot sgl, save the DIF buffer */
if (lpfc_prot_group_type(phba, cmd) ==
LPFC_PG_TYPE_DIF_BUF) {
- printk(KERN_ERR "Saving DIF for %u blocks to debugfs\n",
- (cmd->cmnd[7] << 8 | cmd->cmnd[8]));
- lpfc_debug_save_dif(cmd);
+ lpfc_printf_log(phba, KERN_ERR, LOG_BG, "9071 BLKGRD: "
+ "Saving DIF for %u blocks to debugfs\n",
+ (cmd->cmnd[7] << 8 | cmd->cmnd[8]));
+ lpfc_debug_save_dif(phba, cmd);
}
_dump_buf_done = 1;
@@ -1696,15 +1716,17 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd,
if (lpfc_bgs_get_invalid_prof(bgstat)) {
cmd->result = ScsiResult(DID_ERROR, 0);
- printk(KERN_ERR "Invalid BlockGuard profile. bgstat:0x%x\n",
- bgstat);
+ lpfc_printf_log(phba, KERN_ERR, LOG_BG, "9072 BLKGRD: Invalid"
+ " BlockGuard profile. bgstat:0x%x\n",
+ bgstat);
ret = (-1);
goto out;
}
if (lpfc_bgs_get_uninit_dif_block(bgstat)) {
cmd->result = ScsiResult(DID_ERROR, 0);
- printk(KERN_ERR "Invalid BlockGuard DIF Block. bgstat:0x%x\n",
+ lpfc_printf_log(phba, KERN_ERR, LOG_BG, "9073 BLKGRD: "
+ "Invalid BlockGuard DIF Block. bgstat:0x%x\n",
bgstat);
ret = (-1);
goto out;
@@ -1718,7 +1740,8 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd,
cmd->result = DRIVER_SENSE << 24
| ScsiResult(DID_ABORT, SAM_STAT_CHECK_CONDITION);
phba->bg_guard_err_cnt++;
- printk(KERN_ERR "BLKGRD: guard_tag error\n");
+ lpfc_printf_log(phba, KERN_ERR, LOG_BG,
+ "9055 BLKGRD: guard_tag error\n");
}
if (lpfc_bgs_get_reftag_err(bgstat)) {
@@ -1730,7 +1753,8 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd,
| ScsiResult(DID_ABORT, SAM_STAT_CHECK_CONDITION);
phba->bg_reftag_err_cnt++;
- printk(KERN_ERR "BLKGRD: ref_tag error\n");
+ lpfc_printf_log(phba, KERN_ERR, LOG_BG,
+ "9056 BLKGRD: ref_tag error\n");
}
if (lpfc_bgs_get_apptag_err(bgstat)) {
@@ -1742,7 +1766,8 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd,
| ScsiResult(DID_ABORT, SAM_STAT_CHECK_CONDITION);
phba->bg_apptag_err_cnt++;
- printk(KERN_ERR "BLKGRD: app_tag error\n");
+ lpfc_printf_log(phba, KERN_ERR, LOG_BG,
+ "9061 BLKGRD: app_tag error\n");
}
if (lpfc_bgs_get_hi_water_mark_present(bgstat)) {
@@ -1763,7 +1788,8 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd,
if (!ret) {
/* No error was reported - problem in FW? */
cmd->result = ScsiResult(DID_ERROR, 0);
- printk(KERN_ERR "BLKGRD: no errors reported!\n");
+ lpfc_printf_log(phba, KERN_ERR, LOG_BG,
+ "9057 BLKGRD: no errors reported!\n");
}
out:
@@ -1822,9 +1848,10 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
lpfc_cmd->seg_cnt = nseg;
if (lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt) {
- printk(KERN_ERR "%s: Too many sg segments from "
- "dma_map_sg. Config %d, seg_cnt %d\n",
- __func__, phba->cfg_sg_seg_cnt,
+ lpfc_printf_log(phba, KERN_ERR, LOG_BG, "9074 BLKGRD:"
+ " %s: Too many sg segments from "
+ "dma_map_sg. Config %d, seg_cnt %d\n",
+ __func__, phba->cfg_sg_seg_cnt,
lpfc_cmd->seg_cnt);
scsi_dma_unmap(scsi_cmnd);
return 1;
@@ -2050,6 +2077,21 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
goto out;
}
+ if (resp_info & RSP_LEN_VALID) {
+ rsplen = be32_to_cpu(fcprsp->rspRspLen);
+ if ((rsplen != 0 && rsplen != 4 && rsplen != 8) ||
+ (fcprsp->rspInfo3 != RSP_NO_FAILURE)) {
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
+ "2719 Invalid response length: "
+ "tgt x%x lun x%x cmnd x%x rsplen x%x\n",
+ cmnd->device->id,
+ cmnd->device->lun, cmnd->cmnd[0],
+ rsplen);
+ host_status = DID_ERROR;
+ goto out;
+ }
+ }
+
if ((resp_info & SNS_LEN_VALID) && fcprsp->rspSnsLen) {
uint32_t snslen = be32_to_cpu(fcprsp->rspSnsLen);
if (snslen > SCSI_SENSE_BUFFERSIZE)
@@ -2074,15 +2116,6 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
be32_to_cpu(fcprsp->rspRspLen),
fcprsp->rspInfo3);
- if (resp_info & RSP_LEN_VALID) {
- rsplen = be32_to_cpu(fcprsp->rspRspLen);
- if ((rsplen != 0 && rsplen != 4 && rsplen != 8) ||
- (fcprsp->rspInfo3 != RSP_NO_FAILURE)) {
- host_status = DID_ERROR;
- goto out;
- }
- }
-
scsi_set_resid(cmnd, 0);
if (resp_info & RESID_UNDER) {
scsi_set_resid(cmnd, be32_to_cpu(fcprsp->rspResId));
@@ -2180,7 +2213,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
struct scsi_cmnd *cmd = lpfc_cmd->pCmd;
int result;
struct scsi_device *tmp_sdev;
- int depth = 0;
+ int depth;
unsigned long flags;
struct lpfc_fast_path_event *fast_path_evt;
struct Scsi_Host *shost = cmd->device->host;
@@ -2264,7 +2297,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
lpfc_printf_vlog(vport, KERN_WARNING,
LOG_BG,
"9031 non-zero BGSTAT "
- "on unprotected cmd");
+ "on unprotected cmd\n");
}
}
@@ -2347,67 +2380,29 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
return;
}
-
if (!result)
lpfc_rampup_queue_depth(vport, queue_depth);
- if (!result && pnode && NLP_CHK_NODE_ACT(pnode) &&
- ((jiffies - pnode->last_ramp_up_time) >
- LPFC_Q_RAMP_UP_INTERVAL * HZ) &&
- ((jiffies - pnode->last_q_full_time) >
- LPFC_Q_RAMP_UP_INTERVAL * HZ) &&
- (vport->cfg_lun_queue_depth > queue_depth)) {
- shost_for_each_device(tmp_sdev, shost) {
- if (vport->cfg_lun_queue_depth > tmp_sdev->queue_depth){
- if (tmp_sdev->id != scsi_id)
- continue;
- if (tmp_sdev->ordered_tags)
- scsi_adjust_queue_depth(tmp_sdev,
- MSG_ORDERED_TAG,
- tmp_sdev->queue_depth+1);
- else
- scsi_adjust_queue_depth(tmp_sdev,
- MSG_SIMPLE_TAG,
- tmp_sdev->queue_depth+1);
-
- pnode->last_ramp_up_time = jiffies;
- }
- }
- lpfc_send_sdev_queuedepth_change_event(phba, vport, pnode,
- 0xFFFFFFFF,
- queue_depth , queue_depth + 1);
- }
-
/*
* Check for queue full. If the lun is reporting queue full, then
* back off the lun queue depth to prevent target overloads.
*/
if (result == SAM_STAT_TASK_SET_FULL && pnode &&
NLP_CHK_NODE_ACT(pnode)) {
- pnode->last_q_full_time = jiffies;
-
shost_for_each_device(tmp_sdev, shost) {
if (tmp_sdev->id != scsi_id)
continue;
depth = scsi_track_queue_full(tmp_sdev,
- tmp_sdev->queue_depth - 1);
- }
- /*
- * The queue depth cannot be lowered any more.
- * Modify the returned error code to store
- * the final depth value set by
- * scsi_track_queue_full.
- */
- if (depth == -1)
- depth = shost->cmd_per_lun;
-
- if (depth) {
+ tmp_sdev->queue_depth-1);
+ if (depth <= 0)
+ continue;
lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
"0711 detected queue full - lun queue "
"depth adjusted to %d.\n", depth);
lpfc_send_sdev_queuedepth_change_event(phba, vport,
- pnode, 0xFFFFFFFF,
- depth+1, depth);
+ pnode,
+ tmp_sdev->lun,
+ depth+1, depth);
}
}
@@ -2745,7 +2740,9 @@ void lpfc_poll_timeout(unsigned long ptr)
struct lpfc_hba *phba = (struct lpfc_hba *) ptr;
if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) {
- lpfc_sli_poll_fcp_ring (phba);
+ lpfc_sli_handle_fast_ring_event(phba,
+ &phba->sli.ring[LPFC_FCP_RING], HA_R0RE_REQ);
+
if (phba->cfg_poll & DISABLE_FCP_RING_INT)
lpfc_poll_rearm_timer(phba);
}
@@ -2771,7 +2768,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
struct lpfc_hba *phba = vport->phba;
struct lpfc_rport_data *rdata = cmnd->device->hostdata;
- struct lpfc_nodelist *ndlp = rdata->pnode;
+ struct lpfc_nodelist *ndlp;
struct lpfc_scsi_buf *lpfc_cmd;
struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device));
int err;
@@ -2781,13 +2778,15 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
cmnd->result = err;
goto out_fail_command;
}
+ ndlp = rdata->pnode;
if (!(phba->sli3_options & LPFC_SLI3_BG_ENABLED) &&
scsi_get_prot_op(cmnd) != SCSI_PROT_NORMAL) {
- printk(KERN_ERR "BLKGRD ERROR: rcvd protected cmd:%02x op:%02x "
- "str=%s without registering for BlockGuard - "
- "Rejecting command\n",
+ lpfc_printf_log(phba, KERN_ERR, LOG_BG,
+ "9058 BLKGRD: ERROR: rcvd protected cmd:%02x"
+ " op:%02x str=%s without registering for"
+ " BlockGuard - Rejecting command\n",
cmnd->cmnd[0], scsi_get_prot_op(cmnd),
dif_op_str[scsi_get_prot_op(cmnd)]);
goto out_fail_command;
@@ -2827,61 +2826,66 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
cmnd->scsi_done = done;
if (scsi_get_prot_op(cmnd) != SCSI_PROT_NORMAL) {
- lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,
+ if (vport->phba->cfg_enable_bg) {
+ lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,
"9033 BLKGRD: rcvd protected cmd:%02x op:%02x "
"str=%s\n",
cmnd->cmnd[0], scsi_get_prot_op(cmnd),
dif_op_str[scsi_get_prot_op(cmnd)]);
- lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,
+ lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,
"9034 BLKGRD: CDB: %02x %02x %02x %02x %02x "
"%02x %02x %02x %02x %02x\n",
cmnd->cmnd[0], cmnd->cmnd[1], cmnd->cmnd[2],
cmnd->cmnd[3], cmnd->cmnd[4], cmnd->cmnd[5],
cmnd->cmnd[6], cmnd->cmnd[7], cmnd->cmnd[8],
cmnd->cmnd[9]);
- if (cmnd->cmnd[0] == READ_10)
- lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,
+ if (cmnd->cmnd[0] == READ_10)
+ lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,
"9035 BLKGRD: READ @ sector %llu, "
"count %u\n",
(unsigned long long)scsi_get_lba(cmnd),
blk_rq_sectors(cmnd->request));
- else if (cmnd->cmnd[0] == WRITE_10)
- lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,
+ else if (cmnd->cmnd[0] == WRITE_10)
+ lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,
"9036 BLKGRD: WRITE @ sector %llu, "
"count %u cmd=%p\n",
(unsigned long long)scsi_get_lba(cmnd),
blk_rq_sectors(cmnd->request),
cmnd);
+ }
err = lpfc_bg_scsi_prep_dma_buf(phba, lpfc_cmd);
} else {
- lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,
- "9038 BLKGRD: rcvd unprotected cmd:%02x op:%02x"
- " str=%s\n",
- cmnd->cmnd[0], scsi_get_prot_op(cmnd),
- dif_op_str[scsi_get_prot_op(cmnd)]);
- lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,
- "9039 BLKGRD: CDB: %02x %02x %02x %02x %02x "
- "%02x %02x %02x %02x %02x\n",
- cmnd->cmnd[0], cmnd->cmnd[1], cmnd->cmnd[2],
- cmnd->cmnd[3], cmnd->cmnd[4], cmnd->cmnd[5],
- cmnd->cmnd[6], cmnd->cmnd[7], cmnd->cmnd[8],
- cmnd->cmnd[9]);
- if (cmnd->cmnd[0] == READ_10)
+ if (vport->phba->cfg_enable_bg) {
lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,
- "9040 dbg: READ @ sector %llu, "
- "count %u\n",
- (unsigned long long)scsi_get_lba(cmnd),
+ "9038 BLKGRD: rcvd unprotected cmd:"
+ "%02x op:%02x str=%s\n",
+ cmnd->cmnd[0], scsi_get_prot_op(cmnd),
+ dif_op_str[scsi_get_prot_op(cmnd)]);
+ lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,
+ "9039 BLKGRD: CDB: %02x %02x %02x "
+ "%02x %02x %02x %02x %02x %02x %02x\n",
+ cmnd->cmnd[0], cmnd->cmnd[1],
+ cmnd->cmnd[2], cmnd->cmnd[3],
+ cmnd->cmnd[4], cmnd->cmnd[5],
+ cmnd->cmnd[6], cmnd->cmnd[7],
+ cmnd->cmnd[8], cmnd->cmnd[9]);
+ if (cmnd->cmnd[0] == READ_10)
+ lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,
+ "9040 dbg: READ @ sector %llu, "
+ "count %u\n",
+ (unsigned long long)scsi_get_lba(cmnd),
blk_rq_sectors(cmnd->request));
- else if (cmnd->cmnd[0] == WRITE_10)
- lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,
+ else if (cmnd->cmnd[0] == WRITE_10)
+ lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,
"9041 dbg: WRITE @ sector %llu, "
"count %u cmd=%p\n",
(unsigned long long)scsi_get_lba(cmnd),
blk_rq_sectors(cmnd->request), cmnd);
- else
- lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,
+ else
+ lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,
"9042 dbg: parser not implemented\n");
+ }
err = lpfc_scsi_prep_dma_buf(phba, lpfc_cmd);
}
@@ -2898,7 +2902,11 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
goto out_host_busy_free_buf;
}
if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) {
- lpfc_sli_poll_fcp_ring(phba);
+ spin_unlock(shost->host_lock);
+ lpfc_sli_handle_fast_ring_event(phba,
+ &phba->sli.ring[LPFC_FCP_RING], HA_R0RE_REQ);
+
+ spin_lock(shost->host_lock);
if (phba->cfg_poll & DISABLE_FCP_RING_INT)
lpfc_poll_rearm_timer(phba);
}
@@ -2917,28 +2925,6 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
}
/**
- * lpfc_block_error_handler - Routine to block error handler
- * @cmnd: Pointer to scsi_cmnd data structure.
- *
- * This routine blocks execution till fc_rport state is not FC_PORSTAT_BLCOEKD.
- **/
-static void
-lpfc_block_error_handler(struct scsi_cmnd *cmnd)
-{
- struct Scsi_Host *shost = cmnd->device->host;
- struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device));
-
- spin_lock_irq(shost->host_lock);
- while (rport->port_state == FC_PORTSTATE_BLOCKED) {
- spin_unlock_irq(shost->host_lock);
- msleep(1000);
- spin_lock_irq(shost->host_lock);
- }
- spin_unlock_irq(shost->host_lock);
- return;
-}
-
-/**
* lpfc_abort_handler - scsi_host_template eh_abort_handler entry point
* @cmnd: Pointer to scsi_cmnd data structure.
*
@@ -2961,7 +2947,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
int ret = SUCCESS;
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq);
- lpfc_block_error_handler(cmnd);
+ fc_block_scsi_eh(cmnd);
lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble;
BUG_ON(!lpfc_cmd);
@@ -3001,6 +2987,10 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
icmd->ulpLe = 1;
icmd->ulpClass = cmd->ulpClass;
+
+ /* ABTS WQE must go to the same WQ as the WQE to be aborted */
+ abtsiocb->fcp_wqidx = iocb->fcp_wqidx;
+
if (lpfc_is_link_up(phba))
icmd->ulpCommand = CMD_ABORT_XRI_CN;
else
@@ -3016,7 +3006,8 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
}
if (phba->cfg_poll & DISABLE_FCP_RING_INT)
- lpfc_sli_poll_fcp_ring (phba);
+ lpfc_sli_handle_fast_ring_event(phba,
+ &phba->sli.ring[LPFC_FCP_RING], HA_R0RE_REQ);
lpfc_cmd->waitq = &waitq;
/* Wait for abort to complete */
@@ -3166,9 +3157,15 @@ static int
lpfc_chk_tgt_mapped(struct lpfc_vport *vport, struct scsi_cmnd *cmnd)
{
struct lpfc_rport_data *rdata = cmnd->device->hostdata;
- struct lpfc_nodelist *pnode = rdata->pnode;
+ struct lpfc_nodelist *pnode;
unsigned long later;
+ if (!rdata) {
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
+ "0797 Tgt Map rport failure: rdata x%p\n", rdata);
+ return FAILED;
+ }
+ pnode = rdata->pnode;
/*
* If target is not in a MAPPED state, delay until
* target is rediscovered or devloss timeout expires.
@@ -3253,13 +3250,19 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd)
struct Scsi_Host *shost = cmnd->device->host;
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
struct lpfc_rport_data *rdata = cmnd->device->hostdata;
- struct lpfc_nodelist *pnode = rdata->pnode;
+ struct lpfc_nodelist *pnode;
unsigned tgt_id = cmnd->device->id;
unsigned int lun_id = cmnd->device->lun;
struct lpfc_scsi_event_header scsi_event;
int status;
- lpfc_block_error_handler(cmnd);
+ if (!rdata) {
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
+ "0798 Device Reset rport failure: rdata x%p\n", rdata);
+ return FAILED;
+ }
+ pnode = rdata->pnode;
+ fc_block_scsi_eh(cmnd);
status = lpfc_chk_tgt_mapped(vport, cmnd);
if (status == FAILED) {
@@ -3312,13 +3315,19 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd)
struct Scsi_Host *shost = cmnd->device->host;
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
struct lpfc_rport_data *rdata = cmnd->device->hostdata;
- struct lpfc_nodelist *pnode = rdata->pnode;
+ struct lpfc_nodelist *pnode;
unsigned tgt_id = cmnd->device->id;
unsigned int lun_id = cmnd->device->lun;
struct lpfc_scsi_event_header scsi_event;
int status;
- lpfc_block_error_handler(cmnd);
+ if (!rdata) {
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
+ "0799 Target Reset rport failure: rdata x%p\n", rdata);
+ return FAILED;
+ }
+ pnode = rdata->pnode;
+ fc_block_scsi_eh(cmnd);
status = lpfc_chk_tgt_mapped(vport, cmnd);
if (status == FAILED) {
@@ -3384,7 +3393,7 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd)
fc_host_post_vendor_event(shost, fc_get_event_number(),
sizeof(scsi_event), (char *)&scsi_event, LPFC_NL_VENDOR_ID);
- lpfc_block_error_handler(cmnd);
+ fc_block_scsi_eh(cmnd);
/*
* Since the driver manages a single bus device, reset all
@@ -3498,6 +3507,8 @@ lpfc_slave_alloc(struct scsi_device *sdev)
"Allocated %d buffers.\n",
num_to_alloc, num_allocated);
}
+ if (num_allocated > 0)
+ phba->total_scsi_bufs += num_allocated;
return 0;
}
@@ -3534,7 +3545,8 @@ lpfc_slave_configure(struct scsi_device *sdev)
rport->dev_loss_tmo = vport->cfg_devloss_tmo;
if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) {
- lpfc_sli_poll_fcp_ring(phba);
+ lpfc_sli_handle_fast_ring_event(phba,
+ &phba->sli.ring[LPFC_FCP_RING], HA_R0RE_REQ);
if (phba->cfg_poll & DISABLE_FCP_RING_INT)
lpfc_poll_rearm_timer(phba);
}
@@ -3576,6 +3588,7 @@ struct scsi_host_template lpfc_template = {
.shost_attrs = lpfc_hba_attrs,
.max_sectors = 0xFFFF,
.vendor_id = LPFC_NL_VENDOR_ID,
+ .change_queue_depth = lpfc_change_queue_depth,
};
struct scsi_host_template lpfc_vport_template = {
@@ -3597,4 +3610,5 @@ struct scsi_host_template lpfc_vport_template = {
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = lpfc_vport_attrs,
.max_sectors = 0xFFFF,
+ .change_queue_depth = lpfc_change_queue_depth,
};
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 43cbe33..7935667 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -30,6 +30,7 @@
#include <scsi/scsi_host.h>
#include <scsi/scsi_transport_fc.h>
#include <scsi/fc/fc_fs.h>
+#include <linux/aer.h>
#include "lpfc_hw4.h"
#include "lpfc_hw.h"
@@ -58,8 +59,11 @@ typedef enum _lpfc_iocb_type {
static int lpfc_sli_issue_mbox_s4(struct lpfc_hba *, LPFC_MBOXQ_t *,
uint32_t);
static int lpfc_sli4_read_rev(struct lpfc_hba *, LPFC_MBOXQ_t *,
- uint8_t *, uint32_t *);
-
+ uint8_t *, uint32_t *);
+static struct lpfc_iocbq *lpfc_sli4_els_wcqe_to_rspiocbq(struct lpfc_hba *,
+ struct lpfc_iocbq *);
+static void lpfc_sli4_send_seq_to_ulp(struct lpfc_vport *,
+ struct hbq_dmabuf *);
static IOCB_t *
lpfc_get_iocb_from_iocbq(struct lpfc_iocbq *iocbq)
{
@@ -259,6 +263,9 @@ lpfc_sli4_eq_release(struct lpfc_queue *q, bool arm)
bf_set(lpfc_eqcq_doorbell_qt, &doorbell, LPFC_QUEUE_TYPE_EVENT);
bf_set(lpfc_eqcq_doorbell_eqid, &doorbell, q->queue_id);
writel(doorbell.word0, q->phba->sli4_hba.EQCQDBregaddr);
+ /* PCI read to flush PCI pipeline on re-arming for INTx mode */
+ if ((q->phba->intr_type == INTx) && (arm == LPFC_QUEUE_REARM))
+ readl(q->phba->sli4_hba.EQCQDBregaddr);
return released;
}
@@ -515,6 +522,8 @@ __lpfc_sli_get_sglq(struct lpfc_hba *phba)
struct lpfc_sglq *sglq = NULL;
uint16_t adj_xri;
list_remove_head(lpfc_sgl_list, sglq, struct lpfc_sglq, list);
+ if (!sglq)
+ return NULL;
adj_xri = sglq->sli4_xritag - phba->sli4_hba.max_cfg_param.xri_base;
phba->sli4_hba.lpfc_sglq_active_list[adj_xri] = sglq;
return sglq;
@@ -572,9 +581,9 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
sglq = __lpfc_clear_active_sglq(phba, iocbq->sli4_xritag);
if (sglq) {
if (iocbq->iocb_flag & LPFC_DRIVER_ABORTED
- || ((iocbq->iocb.ulpStatus == IOSTAT_LOCAL_REJECT)
+ && ((iocbq->iocb.ulpStatus == IOSTAT_LOCAL_REJECT)
&& (iocbq->iocb.un.ulpWord[4]
- == IOERR_SLI_ABORTED))) {
+ == IOERR_ABORT_REQUESTED))) {
spin_lock_irqsave(&phba->sli4_hba.abts_sgl_list_lock,
iflag);
list_add(&sglq->list,
@@ -767,6 +776,7 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd)
case CMD_CLOSE_XRI_CX:
case CMD_XRI_ABORTED_CX:
case CMD_ABORT_MXRI64_CN:
+ case CMD_XMIT_BLS_RSP64_CX:
type = LPFC_ABORT_IOCB;
break;
case CMD_RCV_SEQUENCE_CX:
@@ -1794,7 +1804,7 @@ lpfc_sli_handle_mb_event(struct lpfc_hba *phba)
*/
if (lpfc_sli_chk_mbx_command(pmbox->mbxCommand) ==
MBX_SHUTDOWN) {
- /* Unknow mailbox command compl */
+ /* Unknown mailbox command compl */
lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
"(%d):0323 Unknown Mailbox command "
"x%x (x%x) Cmpl\n",
@@ -2068,8 +2078,8 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
if ((irsp->ulpCommand == CMD_RCV_ELS_REQ64_CX) ||
(irsp->ulpCommand == CMD_RCV_ELS_REQ_CX) ||
(irsp->ulpCommand == CMD_IOCB_RCV_ELS64_CX)) {
- Rctl = FC_ELS_REQ;
- Type = FC_ELS_DATA;
+ Rctl = FC_RCTL_ELS_REQ;
+ Type = FC_TYPE_ELS;
} else {
w5p = (WORD5 *)&(saveq->iocb.un.ulpWord[5]);
Rctl = w5p->hcsw.Rctl;
@@ -2079,8 +2089,8 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
if ((Rctl == 0) && (pring->ringno == LPFC_ELS_RING) &&
(irsp->ulpCommand == CMD_RCV_SEQUENCE64_CX ||
irsp->ulpCommand == CMD_IOCB_RCV_SEQ64_CX)) {
- Rctl = FC_ELS_REQ;
- Type = FC_ELS_DATA;
+ Rctl = FC_RCTL_ELS_REQ;
+ Type = FC_TYPE_ELS;
w5p->hcsw.Rctl = Rctl;
w5p->hcsw.Type = Type;
}
@@ -2324,168 +2334,6 @@ void lpfc_poll_eratt(unsigned long ptr)
return;
}
-/**
- * lpfc_sli_poll_fcp_ring - Handle FCP ring completion in polling mode
- * @phba: Pointer to HBA context object.
- *
- * This function is called from lpfc_queuecommand, lpfc_poll_timeout,
- * lpfc_abort_handler and lpfc_slave_configure when FCP_RING_POLLING
- * is enabled.
- *
- * The caller does not hold any lock.
- * The function processes each response iocb in the response ring until it
- * finds an iocb with LE bit set and chains all the iocbs upto the iocb with
- * LE bit set. The function will call the completion handler of the command iocb
- * if the response iocb indicates a completion for a command iocb or it is
- * an abort completion.
- **/
-void lpfc_sli_poll_fcp_ring(struct lpfc_hba *phba)
-{
- struct lpfc_sli *psli = &phba->sli;
- struct lpfc_sli_ring *pring = &psli->ring[LPFC_FCP_RING];
- IOCB_t *irsp = NULL;
- IOCB_t *entry = NULL;
- struct lpfc_iocbq *cmdiocbq = NULL;
- struct lpfc_iocbq rspiocbq;
- struct lpfc_pgp *pgp = &phba->port_gp[pring->ringno];
- uint32_t status;
- uint32_t portRspPut, portRspMax;
- int type;
- uint32_t rsp_cmpl = 0;
- uint32_t ha_copy;
- unsigned long iflags;
-
- pring->stats.iocb_event++;
-
- /*
- * The next available response entry should never exceed the maximum
- * entries. If it does, treat it as an adapter hardware error.
- */
- portRspMax = pring->numRiocb;
- portRspPut = le32_to_cpu(pgp->rspPutInx);
- if (unlikely(portRspPut >= portRspMax)) {
- lpfc_sli_rsp_pointers_error(phba, pring);
- return;
- }
-
- rmb();
- while (pring->rspidx != portRspPut) {
- entry = lpfc_resp_iocb(phba, pring);
- if (++pring->rspidx >= portRspMax)
- pring->rspidx = 0;
-
- lpfc_sli_pcimem_bcopy((uint32_t *) entry,
- (uint32_t *) &rspiocbq.iocb,
- phba->iocb_rsp_size);
- irsp = &rspiocbq.iocb;
- type = lpfc_sli_iocb_cmd_type(irsp->ulpCommand & CMD_IOCB_MASK);
- pring->stats.iocb_rsp++;
- rsp_cmpl++;
-
- if (unlikely(irsp->ulpStatus)) {
- /* Rsp ring <ringno> error: IOCB */
- lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
- "0326 Rsp Ring %d error: IOCB Data: "
- "x%x x%x x%x x%x x%x x%x x%x x%x\n",
- pring->ringno,
- irsp->un.ulpWord[0],
- irsp->un.ulpWord[1],
- irsp->un.ulpWord[2],
- irsp->un.ulpWord[3],
- irsp->un.ulpWord[4],
- irsp->un.ulpWord[5],
- *(uint32_t *)&irsp->un1,
- *((uint32_t *)&irsp->un1 + 1));
- }
-
- switch (type) {
- case LPFC_ABORT_IOCB:
- case LPFC_SOL_IOCB:
- /*
- * Idle exchange closed via ABTS from port. No iocb
- * resources need to be recovered.
- */
- if (unlikely(irsp->ulpCommand == CMD_XRI_ABORTED_CX)) {
- lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
- "0314 IOCB cmd 0x%x "
- "processed. Skipping "
- "completion",
- irsp->ulpCommand);
- break;
- }
-
- spin_lock_irqsave(&phba->hbalock, iflags);
- cmdiocbq = lpfc_sli_iocbq_lookup(phba, pring,
- &rspiocbq);
- spin_unlock_irqrestore(&phba->hbalock, iflags);
- if ((cmdiocbq) && (cmdiocbq->iocb_cmpl)) {
- (cmdiocbq->iocb_cmpl)(phba, cmdiocbq,
- &rspiocbq);
- }
- break;
- default:
- if (irsp->ulpCommand == CMD_ADAPTER_MSG) {
- char adaptermsg[LPFC_MAX_ADPTMSG];
- memset(adaptermsg, 0, LPFC_MAX_ADPTMSG);
- memcpy(&adaptermsg[0], (uint8_t *) irsp,
- MAX_MSG_DATA);
- dev_warn(&((phba->pcidev)->dev),
- "lpfc%d: %s\n",
- phba->brd_no, adaptermsg);
- } else {
- /* Unknown IOCB command */
- lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "0321 Unknown IOCB command "
- "Data: x%x, x%x x%x x%x x%x\n",
- type, irsp->ulpCommand,
- irsp->ulpStatus,
- irsp->ulpIoTag,
- irsp->ulpContext);
- }
- break;
- }
-
- /*
- * The response IOCB has been processed. Update the ring
- * pointer in SLIM. If the port response put pointer has not
- * been updated, sync the pgp->rspPutInx and fetch the new port
- * response put pointer.
- */
- writel(pring->rspidx, &phba->host_gp[pring->ringno].rspGetInx);
-
- if (pring->rspidx == portRspPut)
- portRspPut = le32_to_cpu(pgp->rspPutInx);
- }
-
- ha_copy = readl(phba->HAregaddr);
- ha_copy >>= (LPFC_FCP_RING * 4);
-
- if ((rsp_cmpl > 0) && (ha_copy & HA_R0RE_REQ)) {
- spin_lock_irqsave(&phba->hbalock, iflags);
- pring->stats.iocb_rsp_full++;
- status = ((CA_R0ATT | CA_R0RE_RSP) << (LPFC_FCP_RING * 4));
- writel(status, phba->CAregaddr);
- readl(phba->CAregaddr);
- spin_unlock_irqrestore(&phba->hbalock, iflags);
- }
- if ((ha_copy & HA_R0CE_RSP) &&
- (pring->flag & LPFC_CALL_RING_AVAILABLE)) {
- spin_lock_irqsave(&phba->hbalock, iflags);
- pring->flag &= ~LPFC_CALL_RING_AVAILABLE;
- pring->stats.iocb_cmd_empty++;
-
- /* Force update of the local copy of cmdGetInx */
- pring->local_getidx = le32_to_cpu(pgp->cmdGetInx);
- lpfc_sli_resume_iocb(phba, pring);
-
- if ((pring->lpfc_sli_cmd_available))
- (pring->lpfc_sli_cmd_available) (phba, pring);
-
- spin_unlock_irqrestore(&phba->hbalock, iflags);
- }
-
- return;
-}
/**
* lpfc_sli_handle_fast_ring_event - Handle ring events on FCP ring
@@ -2502,9 +2350,9 @@ void lpfc_sli_poll_fcp_ring(struct lpfc_hba *phba)
* an abort completion. The function will call lpfc_sli_process_unsol_iocb
* function if this is an unsolicited iocb.
* This routine presumes LPFC_FCP_RING handling and doesn't bother
- * to check it explicitly. This function always returns 1.
- **/
-static int
+ * to check it explicitly.
+ */
+int
lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba,
struct lpfc_sli_ring *pring, uint32_t mask)
{
@@ -2534,6 +2382,11 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba,
spin_unlock_irqrestore(&phba->hbalock, iflag);
return 1;
}
+ if (phba->fcp_ring_in_use) {
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
+ return 1;
+ } else
+ phba->fcp_ring_in_use = 1;
rmb();
while (pring->rspidx != portRspPut) {
@@ -2604,10 +2457,6 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba,
cmdiocbq = lpfc_sli_iocbq_lookup(phba, pring,
&rspiocbq);
if ((cmdiocbq) && (cmdiocbq->iocb_cmpl)) {
- if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) {
- (cmdiocbq->iocb_cmpl)(phba, cmdiocbq,
- &rspiocbq);
- } else {
spin_unlock_irqrestore(&phba->hbalock,
iflag);
(cmdiocbq->iocb_cmpl)(phba, cmdiocbq,
@@ -2615,7 +2464,6 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba,
spin_lock_irqsave(&phba->hbalock,
iflag);
}
- }
break;
case LPFC_UNSOL_IOCB:
spin_unlock_irqrestore(&phba->hbalock, iflag);
@@ -2675,6 +2523,7 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba,
}
+ phba->fcp_ring_in_use = 0;
spin_unlock_irqrestore(&phba->hbalock, iflag);
return rc;
}
@@ -3018,16 +2867,39 @@ lpfc_sli_handle_slow_ring_event_s4(struct lpfc_hba *phba,
struct lpfc_sli_ring *pring, uint32_t mask)
{
struct lpfc_iocbq *irspiocbq;
+ struct hbq_dmabuf *dmabuf;
+ struct lpfc_cq_event *cq_event;
unsigned long iflag;
- while (!list_empty(&phba->sli4_hba.sp_rspiocb_work_queue)) {
+ spin_lock_irqsave(&phba->hbalock, iflag);
+ phba->hba_flag &= ~HBA_SP_QUEUE_EVT;
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
+ while (!list_empty(&phba->sli4_hba.sp_queue_event)) {
/* Get the response iocb from the head of work queue */
spin_lock_irqsave(&phba->hbalock, iflag);
- list_remove_head(&phba->sli4_hba.sp_rspiocb_work_queue,
- irspiocbq, struct lpfc_iocbq, list);
+ list_remove_head(&phba->sli4_hba.sp_queue_event,
+ cq_event, struct lpfc_cq_event, list);
spin_unlock_irqrestore(&phba->hbalock, iflag);
- /* Process the response iocb */
- lpfc_sli_sp_handle_rspiocb(phba, pring, irspiocbq);
+
+ switch (bf_get(lpfc_wcqe_c_code, &cq_event->cqe.wcqe_cmpl)) {
+ case CQE_CODE_COMPL_WQE:
+ irspiocbq = container_of(cq_event, struct lpfc_iocbq,
+ cq_event);
+ /* Translate ELS WCQE to response IOCBQ */
+ irspiocbq = lpfc_sli4_els_wcqe_to_rspiocbq(phba,
+ irspiocbq);
+ if (irspiocbq)
+ lpfc_sli_sp_handle_rspiocb(phba, pring,
+ irspiocbq);
+ break;
+ case CQE_CODE_RECEIVE:
+ dmabuf = container_of(cq_event, struct hbq_dmabuf,
+ cq_event);
+ lpfc_sli4_handle_received_buffer(phba, dmabuf);
+ break;
+ default:
+ break;
+ }
}
}
@@ -3416,6 +3288,7 @@ lpfc_sli_brdreset(struct lpfc_hba *phba)
/* perform board reset */
phba->fc_eventTag = 0;
+ phba->link_events = 0;
phba->pport->fc_myDID = 0;
phba->pport->fc_prevDID = 0;
@@ -3476,6 +3349,7 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba)
/* perform board reset */
phba->fc_eventTag = 0;
+ phba->link_events = 0;
phba->pport->fc_myDID = 0;
phba->pport->fc_prevDID = 0;
@@ -3495,7 +3369,6 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba)
list_del_init(&phba->sli4_hba.dat_rq->list);
list_del_init(&phba->sli4_hba.mbx_cq->list);
list_del_init(&phba->sli4_hba.els_cq->list);
- list_del_init(&phba->sli4_hba.rxq_cq->list);
for (qindx = 0; qindx < phba->cfg_fcp_wq_count; qindx++)
list_del_init(&phba->sli4_hba.fcp_wq[qindx]->list);
for (qindx = 0; qindx < phba->cfg_fcp_eq_count; qindx++)
@@ -3531,9 +3404,13 @@ lpfc_sli_brdrestart_s3(struct lpfc_hba *phba)
struct lpfc_sli *psli;
volatile uint32_t word0;
void __iomem *to_slim;
+ uint32_t hba_aer_enabled;
spin_lock_irq(&phba->hbalock);
+ /* Take PCIe device Advanced Error Reporting (AER) state */
+ hba_aer_enabled = phba->hba_flag & HBA_AER_ENABLED;
+
psli = &phba->sli;
/* Restart HBA */
@@ -3573,6 +3450,10 @@ lpfc_sli_brdrestart_s3(struct lpfc_hba *phba)
/* Give the INITFF and Post time to settle. */
mdelay(100);
+ /* Reset HBA AER if it was enabled, note hba_flag was reset above */
+ if (hba_aer_enabled)
+ pci_disable_pcie_error_reporting(phba->pcidev);
+
lpfc_hba_down_post(phba);
return 0;
@@ -4042,6 +3923,24 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba)
if (rc)
goto lpfc_sli_hba_setup_error;
+ /* Enable PCIe device Advanced Error Reporting (AER) if configured */
+ if (phba->cfg_aer_support == 1 && !(phba->hba_flag & HBA_AER_ENABLED)) {
+ rc = pci_enable_pcie_error_reporting(phba->pcidev);
+ if (!rc) {
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+ "2709 This device supports "
+ "Advanced Error Reporting (AER)\n");
+ spin_lock_irq(&phba->hbalock);
+ phba->hba_flag |= HBA_AER_ENABLED;
+ spin_unlock_irq(&phba->hbalock);
+ } else {
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+ "2708 This device does not support "
+ "Advanced Error Reporting (AER)\n");
+ phba->cfg_aer_support = 0;
+ }
+ }
+
if (phba->sli_rev == 3) {
phba->iocb_cmd_size = SLI3_IOCB_CMD_SIZE;
phba->iocb_rsp_size = SLI3_IOCB_RSP_SIZE;
@@ -4163,7 +4062,7 @@ lpfc_sli4_read_fcoe_params(struct lpfc_hba *phba,
* addition, this routine gets the port vpd data.
*
* Return codes
- * 0 - sucessful
+ * 0 - successful
* ENOMEM - could not allocated memory.
**/
static int
@@ -4243,7 +4142,6 @@ lpfc_sli4_arm_cqeq_intr(struct lpfc_hba *phba)
lpfc_sli4_cq_release(phba->sli4_hba.mbx_cq, LPFC_QUEUE_REARM);
lpfc_sli4_cq_release(phba->sli4_hba.els_cq, LPFC_QUEUE_REARM);
- lpfc_sli4_cq_release(phba->sli4_hba.rxq_cq, LPFC_QUEUE_REARM);
for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_eq_count; fcp_eqidx++)
lpfc_sli4_cq_release(phba->sli4_hba.fcp_cq[fcp_eqidx],
LPFC_QUEUE_REARM);
@@ -4322,6 +4220,13 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
phba->sli_rev = bf_get(lpfc_mbx_rd_rev_sli_lvl, &mqe->un.read_rev);
if (bf_get(lpfc_mbx_rd_rev_fcoe, &mqe->un.read_rev))
phba->hba_flag |= HBA_FCOE_SUPPORT;
+
+ if (bf_get(lpfc_mbx_rd_rev_cee_ver, &mqe->un.read_rev) ==
+ LPFC_DCBX_CEE_MODE)
+ phba->hba_flag |= HBA_FIP_SUPPORT;
+ else
+ phba->hba_flag &= ~HBA_FIP_SUPPORT;
+
if (phba->sli_rev != LPFC_SLI_REV4 ||
!(phba->hba_flag & HBA_FCOE_SUPPORT)) {
lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
@@ -4468,7 +4373,8 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
rc = lpfc_sli4_post_sgl_list(phba);
if (unlikely(rc)) {
lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
- "0582 Error %d during sgl post operation", rc);
+ "0582 Error %d during sgl post operation\n",
+ rc);
rc = -ENODEV;
goto out_free_vpd;
}
@@ -4477,8 +4383,8 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
rc = lpfc_sli4_repost_scsi_sgl_list(phba);
if (unlikely(rc)) {
lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI,
- "0383 Error %d during scsi sgl post opeation",
- rc);
+ "0383 Error %d during scsi sgl post "
+ "operation\n", rc);
/* Some Scsi buffers were moved to the abort scsi list */
/* A pci function reset will repost them */
rc = -ENODEV;
@@ -4494,10 +4400,6 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
rc = -ENODEV;
goto out_free_vpd;
}
- if (phba->cfg_enable_fip)
- bf_set(lpfc_fip_flag, &phba->sli4_hba.sli4_flags, 1);
- else
- bf_set(lpfc_fip_flag, &phba->sli4_hba.sli4_flags, 0);
/* Set up all the queues to the device */
rc = lpfc_sli4_queue_setup(phba);
@@ -5669,7 +5571,7 @@ __lpfc_sli_issue_iocb_s3(struct lpfc_hba *phba, uint32_t ring_number,
case CMD_GEN_REQUEST64_CX:
if (!(phba->sli.sli_flag & LPFC_MENLO_MAINT) ||
(piocb->iocb.un.genreq64.w5.hcsw.Rctl !=
- FC_FCP_CMND) ||
+ FC_RCTL_DD_UNSOL_CMD) ||
(piocb->iocb.un.genreq64.w5.hcsw.Type !=
MENLO_TRANSPORT_TYPE))
@@ -5849,7 +5751,7 @@ static int
lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
union lpfc_wqe *wqe)
{
- uint32_t payload_len = 0;
+ uint32_t xmit_len = 0, total_len = 0;
uint8_t ct = 0;
uint32_t fip;
uint32_t abort_tag;
@@ -5857,12 +5759,15 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
uint8_t cmnd;
uint16_t xritag;
struct ulp_bde64 *bpl = NULL;
+ uint32_t els_id = ELS_ID_DEFAULT;
+ int numBdes, i;
+ struct ulp_bde64 bde;
- fip = bf_get(lpfc_fip_flag, &phba->sli4_hba.sli4_flags);
+ fip = phba->hba_flag & HBA_FIP_SUPPORT;
/* The fcp commands will set command type */
if (iocbq->iocb_flag & LPFC_IO_FCP)
command_type = FCP_COMMAND;
- else if (fip && (iocbq->iocb_flag & LPFC_FIP_ELS))
+ else if (fip && (iocbq->iocb_flag & LPFC_FIP_ELS_ID_MASK))
command_type = ELS_COMMAND_FIP;
else
command_type = ELS_COMMAND_NON_FIP;
@@ -5874,6 +5779,8 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
wqe->words[7] = 0; /* The ct field has moved so reset */
/* words0-2 bpl convert bde */
if (iocbq->iocb.un.genreq64.bdl.bdeFlags == BUFF_TYPE_BLP_64) {
+ numBdes = iocbq->iocb.un.genreq64.bdl.bdeSize /
+ sizeof(struct ulp_bde64);
bpl = (struct ulp_bde64 *)
((struct lpfc_dmabuf *)iocbq->context3)->virt;
if (!bpl)
@@ -5886,9 +5793,14 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
* can assign it to the sgl.
*/
wqe->generic.bde.tus.w = le32_to_cpu(bpl->tus.w);
- payload_len = wqe->generic.bde.tus.f.bdeSize;
+ xmit_len = wqe->generic.bde.tus.f.bdeSize;
+ total_len = 0;
+ for (i = 0; i < numBdes; i++) {
+ bde.tus.w = le32_to_cpu(bpl[i].tus.w);
+ total_len += bde.tus.f.bdeSize;
+ }
} else
- payload_len = iocbq->iocb.un.fcpi64.bdl.bdeSize;
+ xmit_len = iocbq->iocb.un.fcpi64.bdl.bdeSize;
iocbq->iocb.ulpIoTag = iocbq->iotag;
cmnd = iocbq->iocb.ulpCommand;
@@ -5902,7 +5814,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
iocbq->iocb.ulpCommand);
return IOCB_ERROR;
}
- wqe->els_req.payload_len = payload_len;
+ wqe->els_req.payload_len = xmit_len;
/* Els_reguest64 has a TMO */
bf_set(wqe_tmo, &wqe->els_req.wqe_com,
iocbq->iocb.ulpTimeout);
@@ -5923,7 +5835,23 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
bf_set(lpfc_wqe_gen_ct, &wqe->generic, ct);
bf_set(lpfc_wqe_gen_pu, &wqe->generic, 0);
/* CCP CCPE PV PRI in word10 were set in the memcpy */
+
+ if (command_type == ELS_COMMAND_FIP) {
+ els_id = ((iocbq->iocb_flag & LPFC_FIP_ELS_ID_MASK)
+ >> LPFC_FIP_ELS_ID_SHIFT);
+ }
+ bf_set(lpfc_wqe_gen_els_id, &wqe->generic, els_id);
+
break;
+ case CMD_XMIT_SEQUENCE64_CX:
+ bf_set(lpfc_wqe_gen_context, &wqe->generic,
+ iocbq->iocb.un.ulpWord[3]);
+ wqe->generic.word3 = 0;
+ bf_set(wqe_rcvoxid, &wqe->generic, iocbq->iocb.ulpContext);
+ bf_set(wqe_xc, &wqe->generic, 1);
+ /* The entire sequence is transmitted for this IOCB */
+ xmit_len = total_len;
+ cmnd = CMD_XMIT_SEQUENCE64_CR;
case CMD_XMIT_SEQUENCE64_CR:
/* word3 iocb=io_tag32 wqe=payload_offset */
/* payload offset used for multilpe outstanding
@@ -5933,7 +5861,8 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
/* word4 relative_offset memcpy */
/* word5 r_ctl/df_ctl memcpy */
bf_set(lpfc_wqe_gen_pu, &wqe->generic, 0);
- wqe->xmit_sequence.xmit_len = payload_len;
+ wqe->xmit_sequence.xmit_len = xmit_len;
+ command_type = OTHER_COMMAND;
break;
case CMD_XMIT_BCAST64_CN:
/* word3 iocb=iotag32 wqe=payload_len */
@@ -5962,7 +5891,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
case CMD_FCP_IREAD64_CR:
/* FCP_CMD is always the 1st sgl entry */
wqe->fcp_iread.payload_len =
- payload_len + sizeof(struct fcp_rsp);
+ xmit_len + sizeof(struct fcp_rsp);
/* word 4 (xfer length) should have been set on the memcpy */
@@ -5999,7 +5928,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
* sgl[1] = rsp.
*
*/
- wqe->gen_req.command_len = payload_len;
+ wqe->gen_req.command_len = xmit_len;
/* Word4 parameter copied in the memcpy */
/* Word5 [rctl, type, df_ctl, la] copied in memcpy */
/* word6 context tag copied in memcpy */
@@ -6066,6 +5995,38 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
command_type = OTHER_COMMAND;
xritag = 0;
break;
+ case CMD_XMIT_BLS_RSP64_CX:
+ /* As BLS ABTS-ACC WQE is very different from other WQEs,
+ * we re-construct this WQE here based on information in
+ * iocbq from scratch.
+ */
+ memset(wqe, 0, sizeof(union lpfc_wqe));
+ /* OX_ID is invariable to who sent ABTS to CT exchange */
+ bf_set(xmit_bls_rsp64_oxid, &wqe->xmit_bls_rsp,
+ bf_get(lpfc_abts_oxid, &iocbq->iocb.un.bls_acc));
+ if (bf_get(lpfc_abts_orig, &iocbq->iocb.un.bls_acc) ==
+ LPFC_ABTS_UNSOL_INT) {
+ /* ABTS sent by initiator to CT exchange, the
+ * RX_ID field will be filled with the newly
+ * allocated responder XRI.
+ */
+ bf_set(xmit_bls_rsp64_rxid, &wqe->xmit_bls_rsp,
+ iocbq->sli4_xritag);
+ } else {
+ /* ABTS sent by responder to CT exchange, the
+ * RX_ID field will be filled with the responder
+ * RX_ID from ABTS.
+ */
+ bf_set(xmit_bls_rsp64_rxid, &wqe->xmit_bls_rsp,
+ bf_get(lpfc_abts_rxid, &iocbq->iocb.un.bls_acc));
+ }
+ bf_set(xmit_bls_rsp64_seqcnthi, &wqe->xmit_bls_rsp, 0xffff);
+ bf_set(wqe_xmit_bls_pt, &wqe->xmit_bls_rsp.wqe_dest, 0x1);
+ bf_set(wqe_ctxt_tag, &wqe->xmit_bls_rsp.wqe_com,
+ iocbq->iocb.ulpContext);
+ /* Overwrite the pre-set comnd type with OTHER_COMMAND */
+ command_type = OTHER_COMMAND;
+ break;
case CMD_XRI_ABORTED_CX:
case CMD_CREATE_XRI_CR: /* Do we expect to use this? */
/* words0-2 are all 0's no bde */
@@ -6120,11 +6081,10 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
uint16_t xritag;
union lpfc_wqe wqe;
struct lpfc_sli_ring *pring = &phba->sli.ring[ring_number];
- uint32_t fcp_wqidx;
if (piocb->sli4_xritag == NO_XRI) {
if (piocb->iocb.ulpCommand == CMD_ABORT_XRI_CN ||
- piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN)
+ piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN)
sglq = NULL;
else {
sglq = __lpfc_sli_get_sglq(phba);
@@ -6155,8 +6115,17 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
return IOCB_ERROR;
if (piocb->iocb_flag & LPFC_IO_FCP) {
- fcp_wqidx = lpfc_sli4_scmd_to_wqidx_distr(phba);
- if (lpfc_sli4_wq_put(phba->sli4_hba.fcp_wq[fcp_wqidx], &wqe))
+ /*
+ * For FCP command IOCB, get a new WQ index to distribute
+ * WQE across the WQsr. On the other hand, for abort IOCB,
+ * it carries the same WQ index to the original command
+ * IOCB.
+ */
+ if ((piocb->iocb.ulpCommand != CMD_ABORT_XRI_CN) &&
+ (piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN))
+ piocb->fcp_wqidx = lpfc_sli4_scmd_to_wqidx_distr(phba);
+ if (lpfc_sli4_wq_put(phba->sli4_hba.fcp_wq[piocb->fcp_wqidx],
+ &wqe))
return IOCB_ERROR;
} else {
if (lpfc_sli4_wq_put(phba->sli4_hba.els_wq, &wqe))
@@ -6449,31 +6418,37 @@ lpfc_sli_setup(struct lpfc_hba *phba)
pring->iotag_max = 4096;
pring->lpfc_sli_rcv_async_status =
lpfc_sli_async_event_handler;
- pring->num_mask = 4;
+ pring->num_mask = LPFC_MAX_RING_MASK;
pring->prt[0].profile = 0; /* Mask 0 */
- pring->prt[0].rctl = FC_ELS_REQ;
- pring->prt[0].type = FC_ELS_DATA;
+ pring->prt[0].rctl = FC_RCTL_ELS_REQ;
+ pring->prt[0].type = FC_TYPE_ELS;
pring->prt[0].lpfc_sli_rcv_unsol_event =
lpfc_els_unsol_event;
pring->prt[1].profile = 0; /* Mask 1 */
- pring->prt[1].rctl = FC_ELS_RSP;
- pring->prt[1].type = FC_ELS_DATA;
+ pring->prt[1].rctl = FC_RCTL_ELS_REP;
+ pring->prt[1].type = FC_TYPE_ELS;
pring->prt[1].lpfc_sli_rcv_unsol_event =
lpfc_els_unsol_event;
pring->prt[2].profile = 0; /* Mask 2 */
/* NameServer Inquiry */
- pring->prt[2].rctl = FC_UNSOL_CTL;
+ pring->prt[2].rctl = FC_RCTL_DD_UNSOL_CTL;
/* NameServer */
- pring->prt[2].type = FC_COMMON_TRANSPORT_ULP;
+ pring->prt[2].type = FC_TYPE_CT;
pring->prt[2].lpfc_sli_rcv_unsol_event =
lpfc_ct_unsol_event;
pring->prt[3].profile = 0; /* Mask 3 */
/* NameServer response */
- pring->prt[3].rctl = FC_SOL_CTL;
+ pring->prt[3].rctl = FC_RCTL_DD_SOL_CTL;
/* NameServer */
- pring->prt[3].type = FC_COMMON_TRANSPORT_ULP;
+ pring->prt[3].type = FC_TYPE_CT;
pring->prt[3].lpfc_sli_rcv_unsol_event =
lpfc_ct_unsol_event;
+ /* abort unsolicited sequence */
+ pring->prt[4].profile = 0; /* Mask 4 */
+ pring->prt[4].rctl = FC_RCTL_BA_ABTS;
+ pring->prt[4].type = FC_TYPE_BLS;
+ pring->prt[4].lpfc_sli_rcv_unsol_event =
+ lpfc_sli4_ct_abort_unsol_event;
break;
}
totiocbsize += (pring->numCiocb * pring->sizeCiocb) +
@@ -6976,8 +6951,18 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
abort_iotag = cmdiocb->iocb.un.acxri.abortIoTag;
spin_lock_irq(&phba->hbalock);
- if (abort_iotag != 0 && abort_iotag <= phba->sli.last_iotag)
- abort_iocb = phba->sli.iocbq_lookup[abort_iotag];
+ if (phba->sli_rev < LPFC_SLI_REV4) {
+ if (abort_iotag != 0 &&
+ abort_iotag <= phba->sli.last_iotag)
+ abort_iocb =
+ phba->sli.iocbq_lookup[abort_iotag];
+ } else
+ /* For sli4 the abort_tag is the XRI,
+ * so the abort routine puts the iotag of the iocb
+ * being aborted in the context field of the abort
+ * IOCB.
+ */
+ abort_iocb = phba->sli.iocbq_lookup[abort_context];
lpfc_printf_log(phba, KERN_INFO, LOG_ELS | LOG_SLI,
"0327 Cannot abort els iocb %p "
@@ -6991,9 +6976,18 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
* might have completed already. Do not free it again.
*/
if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
- spin_unlock_irq(&phba->hbalock);
- lpfc_sli_release_iocbq(phba, cmdiocb);
- return;
+ if (irsp->un.ulpWord[4] != IOERR_NO_XRI) {
+ spin_unlock_irq(&phba->hbalock);
+ lpfc_sli_release_iocbq(phba, cmdiocb);
+ return;
+ }
+ /* For SLI4 the ulpContext field for abort IOCB
+ * holds the iotag of the IOCB being aborted so
+ * the local abort_context needs to be reset to
+ * match the aborted IOCBs ulpContext.
+ */
+ if (abort_iocb && phba->sli_rev == LPFC_SLI_REV4)
+ abort_context = abort_iocb->iocb.ulpContext;
}
/*
* make sure we have the right iocbq before taking it
@@ -7112,13 +7106,18 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
iabt = &abtsiocbp->iocb;
iabt->un.acxri.abortType = ABORT_TYPE_ABTS;
iabt->un.acxri.abortContextTag = icmd->ulpContext;
- if (phba->sli_rev == LPFC_SLI_REV4)
+ if (phba->sli_rev == LPFC_SLI_REV4) {
iabt->un.acxri.abortIoTag = cmdiocb->sli4_xritag;
+ iabt->un.acxri.abortContextTag = cmdiocb->iotag;
+ }
else
iabt->un.acxri.abortIoTag = icmd->ulpIoTag;
iabt->ulpLe = 1;
iabt->ulpClass = icmd->ulpClass;
+ /* ABTS WQE must go to the same WQ as the WQE to be aborted */
+ abtsiocbp->fcp_wqidx = cmdiocb->fcp_wqidx;
+
if (phba->link_state >= LPFC_LINK_UP)
iabt->ulpCommand = CMD_ABORT_XRI_CN;
else
@@ -7322,6 +7321,9 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring,
abtsiocb->iocb.ulpClass = cmd->ulpClass;
abtsiocb->vport = phba->pport;
+ /* ABTS WQE must go to the same WQ as the WQE to be aborted */
+ abtsiocb->fcp_wqidx = iocbq->fcp_wqidx;
+
if (lpfc_is_link_up(phba))
abtsiocb->iocb.ulpCommand = CMD_ABORT_XRI_CN;
else
@@ -7687,31 +7689,28 @@ static int
lpfc_sli4_eratt_read(struct lpfc_hba *phba)
{
uint32_t uerr_sta_hi, uerr_sta_lo;
- uint32_t onlnreg0, onlnreg1;
/* For now, use the SLI4 device internal unrecoverable error
* registers for error attention. This can be changed later.
*/
- onlnreg0 = readl(phba->sli4_hba.ONLINE0regaddr);
- onlnreg1 = readl(phba->sli4_hba.ONLINE1regaddr);
- if ((onlnreg0 != LPFC_ONLINE_NERR) || (onlnreg1 != LPFC_ONLINE_NERR)) {
- uerr_sta_lo = readl(phba->sli4_hba.UERRLOregaddr);
- uerr_sta_hi = readl(phba->sli4_hba.UERRHIregaddr);
- if (uerr_sta_lo || uerr_sta_hi) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "1423 HBA Unrecoverable error: "
- "uerr_lo_reg=0x%x, uerr_hi_reg=0x%x, "
- "online0_reg=0x%x, online1_reg=0x%x\n",
- uerr_sta_lo, uerr_sta_hi,
- onlnreg0, onlnreg1);
- phba->work_status[0] = uerr_sta_lo;
- phba->work_status[1] = uerr_sta_hi;
- /* Set the driver HA work bitmap */
- phba->work_ha |= HA_ERATT;
- /* Indicate polling handles this ERATT */
- phba->hba_flag |= HBA_ERATT_HANDLED;
- return 1;
- }
+ uerr_sta_lo = readl(phba->sli4_hba.UERRLOregaddr);
+ uerr_sta_hi = readl(phba->sli4_hba.UERRHIregaddr);
+ if ((~phba->sli4_hba.ue_mask_lo & uerr_sta_lo) ||
+ (~phba->sli4_hba.ue_mask_hi & uerr_sta_hi)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "1423 HBA Unrecoverable error: "
+ "uerr_lo_reg=0x%x, uerr_hi_reg=0x%x, "
+ "ue_mask_lo_reg=0x%x, ue_mask_hi_reg=0x%x\n",
+ uerr_sta_lo, uerr_sta_hi,
+ phba->sli4_hba.ue_mask_lo,
+ phba->sli4_hba.ue_mask_hi);
+ phba->work_status[0] = uerr_sta_lo;
+ phba->work_status[1] = uerr_sta_hi;
+ /* Set the driver HA work bitmap */
+ phba->work_ha |= HA_ERATT;
+ /* Indicate polling handles this ERATT */
+ phba->hba_flag |= HBA_ERATT_HANDLED;
+ return 1;
}
return 0;
}
@@ -7834,7 +7833,7 @@ irqreturn_t
lpfc_sli_sp_intr_handler(int irq, void *dev_id)
{
struct lpfc_hba *phba;
- uint32_t ha_copy;
+ uint32_t ha_copy, hc_copy;
uint32_t work_ha_copy;
unsigned long status;
unsigned long iflag;
@@ -7892,8 +7891,13 @@ lpfc_sli_sp_intr_handler(int irq, void *dev_id)
}
/* Clear up only attention source related to slow-path */
+ hc_copy = readl(phba->HCregaddr);
+ writel(hc_copy & ~(HC_MBINT_ENA | HC_R2INT_ENA |
+ HC_LAINT_ENA | HC_ERINT_ENA),
+ phba->HCregaddr);
writel((ha_copy & (HA_MBATT | HA_R2_CLR_MSK)),
phba->HAregaddr);
+ writel(hc_copy, phba->HCregaddr);
readl(phba->HAregaddr); /* flush */
spin_unlock_irqrestore(&phba->hbalock, iflag);
} else
@@ -8049,7 +8053,7 @@ lpfc_sli_sp_intr_handler(int irq, void *dev_id)
KERN_ERR,
LOG_MBOX | LOG_SLI,
"0350 rc should have"
- "been MBX_BUSY");
+ "been MBX_BUSY\n");
if (rc != MBX_NOT_FINISHED)
goto send_current_mbox;
}
@@ -8078,7 +8082,7 @@ send_current_mbox:
if (rc != MBX_SUCCESS)
lpfc_printf_log(phba, KERN_ERR, LOG_MBOX |
LOG_SLI, "0349 rc should be "
- "MBX_SUCCESS");
+ "MBX_SUCCESS\n");
}
spin_lock_irqsave(&phba->hbalock, iflag);
@@ -8203,6 +8207,7 @@ lpfc_sli_intr_handler(int irq, void *dev_id)
struct lpfc_hba *phba;
irqreturn_t sp_irq_rc, fp_irq_rc;
unsigned long status1, status2;
+ uint32_t hc_copy;
/*
* Get the driver's phba structure from the dev_id and
@@ -8240,7 +8245,12 @@ lpfc_sli_intr_handler(int irq, void *dev_id)
}
/* Clear attention sources except link and error attentions */
+ hc_copy = readl(phba->HCregaddr);
+ writel(hc_copy & ~(HC_MBINT_ENA | HC_R0INT_ENA | HC_R1INT_ENA
+ | HC_R2INT_ENA | HC_LAINT_ENA | HC_ERINT_ENA),
+ phba->HCregaddr);
writel((phba->ha_copy & ~(HA_LATT | HA_ERATT)), phba->HAregaddr);
+ writel(hc_copy, phba->HCregaddr);
readl(phba->HAregaddr); /* flush */
spin_unlock(&phba->hbalock);
@@ -8351,8 +8361,6 @@ lpfc_sli4_iocb_param_transfer(struct lpfc_iocbq *pIocbIn,
memcpy((char *)pIocbIn + offset, (char *)pIocbOut + offset,
sizeof(struct lpfc_iocbq) - offset);
- memset(&pIocbIn->sli4_info, 0,
- sizeof(struct lpfc_sli4_rspiocb_info));
/* Map WCQE parameters into irspiocb parameters */
pIocbIn->iocb.ulpStatus = bf_get(lpfc_wcqe_c_status, wcqe);
if (pIocbOut->iocb_flag & LPFC_IO_FCP)
@@ -8364,16 +8372,49 @@ lpfc_sli4_iocb_param_transfer(struct lpfc_iocbq *pIocbIn,
pIocbIn->iocb.un.ulpWord[4] = wcqe->parameter;
else
pIocbIn->iocb.un.ulpWord[4] = wcqe->parameter;
- /* Load in additional WCQE parameters */
- pIocbIn->sli4_info.hw_status = bf_get(lpfc_wcqe_c_hw_status, wcqe);
- pIocbIn->sli4_info.bfield = 0;
- if (bf_get(lpfc_wcqe_c_xb, wcqe))
- pIocbIn->sli4_info.bfield |= LPFC_XB;
- if (bf_get(lpfc_wcqe_c_pv, wcqe)) {
- pIocbIn->sli4_info.bfield |= LPFC_PV;
- pIocbIn->sli4_info.priority =
- bf_get(lpfc_wcqe_c_priority, wcqe);
+}
+
+/**
+ * lpfc_sli4_els_wcqe_to_rspiocbq - Get response iocbq from els wcqe
+ * @phba: Pointer to HBA context object.
+ * @wcqe: Pointer to work-queue completion queue entry.
+ *
+ * This routine handles an ELS work-queue completion event and construct
+ * a pseudo response ELS IODBQ from the SLI4 ELS WCQE for the common
+ * discovery engine to handle.
+ *
+ * Return: Pointer to the receive IOCBQ, NULL otherwise.
+ **/
+static struct lpfc_iocbq *
+lpfc_sli4_els_wcqe_to_rspiocbq(struct lpfc_hba *phba,
+ struct lpfc_iocbq *irspiocbq)
+{
+ struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
+ struct lpfc_iocbq *cmdiocbq;
+ struct lpfc_wcqe_complete *wcqe;
+ unsigned long iflags;
+
+ wcqe = &irspiocbq->cq_event.cqe.wcqe_cmpl;
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ pring->stats.iocb_event++;
+ /* Look up the ELS command IOCB and create pseudo response IOCB */
+ cmdiocbq = lpfc_sli_iocbq_lookup_by_tag(phba, pring,
+ bf_get(lpfc_wcqe_c_request_tag, wcqe));
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+
+ if (unlikely(!cmdiocbq)) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+ "0386 ELS complete with no corresponding "
+ "cmdiocb: iotag (%d)\n",
+ bf_get(lpfc_wcqe_c_request_tag, wcqe));
+ lpfc_sli_release_iocbq(phba, irspiocbq);
+ return NULL;
}
+
+ /* Fake the irspiocbq and copy necessary response information */
+ lpfc_sli4_iocb_param_transfer(irspiocbq, cmdiocbq, wcqe);
+
+ return irspiocbq;
}
/**
@@ -8566,45 +8607,26 @@ static bool
lpfc_sli4_sp_handle_els_wcqe(struct lpfc_hba *phba,
struct lpfc_wcqe_complete *wcqe)
{
- struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
- struct lpfc_iocbq *cmdiocbq;
struct lpfc_iocbq *irspiocbq;
unsigned long iflags;
- bool workposted = false;
-
- spin_lock_irqsave(&phba->hbalock, iflags);
- pring->stats.iocb_event++;
- /* Look up the ELS command IOCB and create pseudo response IOCB */
- cmdiocbq = lpfc_sli_iocbq_lookup_by_tag(phba, pring,
- bf_get(lpfc_wcqe_c_request_tag, wcqe));
- spin_unlock_irqrestore(&phba->hbalock, iflags);
- if (unlikely(!cmdiocbq)) {
- lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
- "0386 ELS complete with no corresponding "
- "cmdiocb: iotag (%d)\n",
- bf_get(lpfc_wcqe_c_request_tag, wcqe));
- return workposted;
- }
-
- /* Fake the irspiocbq and copy necessary response information */
+ /* Get an irspiocbq for later ELS response processing use */
irspiocbq = lpfc_sli_get_iocbq(phba);
if (!irspiocbq) {
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"0387 Failed to allocate an iocbq\n");
- return workposted;
+ return false;
}
- lpfc_sli4_iocb_param_transfer(irspiocbq, cmdiocbq, wcqe);
- /* Add the irspiocb to the response IOCB work list */
+ /* Save off the slow-path queue event for work thread to process */
+ memcpy(&irspiocbq->cq_event.cqe.wcqe_cmpl, wcqe, sizeof(*wcqe));
spin_lock_irqsave(&phba->hbalock, iflags);
- list_add_tail(&irspiocbq->list, &phba->sli4_hba.sp_rspiocb_work_queue);
- /* Indicate ELS ring attention */
- phba->work_ha |= (HA_R0ATT << (4*LPFC_ELS_RING));
+ list_add_tail(&irspiocbq->cq_event.list,
+ &phba->sli4_hba.sp_queue_event);
+ phba->hba_flag |= HBA_SP_QUEUE_EVT;
spin_unlock_irqrestore(&phba->hbalock, iflags);
- workposted = true;
- return workposted;
+ return true;
}
/**
@@ -8690,52 +8712,6 @@ lpfc_sli4_sp_handle_abort_xri_wcqe(struct lpfc_hba *phba,
}
/**
- * lpfc_sli4_sp_handle_wcqe - Process a work-queue completion queue entry
- * @phba: Pointer to HBA context object.
- * @cq: Pointer to the completion queue.
- * @wcqe: Pointer to a completion queue entry.
- *
- * This routine process a slow-path work-queue completion queue entry.
- *
- * Return: true if work posted to worker thread, otherwise false.
- **/
-static bool
-lpfc_sli4_sp_handle_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
- struct lpfc_cqe *cqe)
-{
- struct lpfc_wcqe_complete wcqe;
- bool workposted = false;
-
- /* Copy the work queue CQE and convert endian order if needed */
- lpfc_sli_pcimem_bcopy(cqe, &wcqe, sizeof(struct lpfc_cqe));
-
- /* Check and process for different type of WCQE and dispatch */
- switch (bf_get(lpfc_wcqe_c_code, &wcqe)) {
- case CQE_CODE_COMPL_WQE:
- /* Process the WQ complete event */
- workposted = lpfc_sli4_sp_handle_els_wcqe(phba,
- (struct lpfc_wcqe_complete *)&wcqe);
- break;
- case CQE_CODE_RELEASE_WQE:
- /* Process the WQ release event */
- lpfc_sli4_sp_handle_rel_wcqe(phba,
- (struct lpfc_wcqe_release *)&wcqe);
- break;
- case CQE_CODE_XRI_ABORTED:
- /* Process the WQ XRI abort event */
- workposted = lpfc_sli4_sp_handle_abort_xri_wcqe(phba, cq,
- (struct sli4_wcqe_xri_aborted *)&wcqe);
- break;
- default:
- lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "0388 Not a valid WCQE code: x%x\n",
- bf_get(lpfc_wcqe_c_code, &wcqe));
- break;
- }
- return workposted;
-}
-
-/**
* lpfc_sli4_sp_handle_rcqe - Process a receive-queue completion queue entry
* @phba: Pointer to HBA context object.
* @rcqe: Pointer to receive-queue completion queue entry.
@@ -8745,9 +8721,8 @@ lpfc_sli4_sp_handle_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
* Return: true if work posted to worker thread, otherwise false.
**/
static bool
-lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_cqe *cqe)
+lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_rcqe *rcqe)
{
- struct lpfc_rcqe rcqe;
bool workposted = false;
struct lpfc_queue *hrq = phba->sli4_hba.hdr_rq;
struct lpfc_queue *drq = phba->sli4_hba.dat_rq;
@@ -8755,31 +8730,28 @@ lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_cqe *cqe)
uint32_t status;
unsigned long iflags;
- /* Copy the receive queue CQE and convert endian order if needed */
- lpfc_sli_pcimem_bcopy(cqe, &rcqe, sizeof(struct lpfc_rcqe));
- lpfc_sli4_rq_release(hrq, drq);
- if (bf_get(lpfc_rcqe_code, &rcqe) != CQE_CODE_RECEIVE)
- goto out;
- if (bf_get(lpfc_rcqe_rq_id, &rcqe) != hrq->queue_id)
+ if (bf_get(lpfc_rcqe_rq_id, rcqe) != hrq->queue_id)
goto out;
- status = bf_get(lpfc_rcqe_status, &rcqe);
+ status = bf_get(lpfc_rcqe_status, rcqe);
switch (status) {
case FC_STATUS_RQ_BUF_LEN_EXCEEDED:
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"2537 Receive Frame Truncated!!\n");
case FC_STATUS_RQ_SUCCESS:
+ lpfc_sli4_rq_release(hrq, drq);
spin_lock_irqsave(&phba->hbalock, iflags);
dma_buf = lpfc_sli_hbqbuf_get(&phba->hbqs[0].hbq_buffer_list);
if (!dma_buf) {
spin_unlock_irqrestore(&phba->hbalock, iflags);
goto out;
}
- memcpy(&dma_buf->rcqe, &rcqe, sizeof(rcqe));
+ memcpy(&dma_buf->cq_event.cqe.rcqe_cmpl, rcqe, sizeof(*rcqe));
/* save off the frame for the word thread to process */
- list_add_tail(&dma_buf->dbuf.list, &phba->rb_pend_list);
+ list_add_tail(&dma_buf->cq_event.list,
+ &phba->sli4_hba.sp_queue_event);
/* Frame received */
- phba->hba_flag |= HBA_RECEIVE_BUFFER;
+ phba->hba_flag |= HBA_SP_QUEUE_EVT;
spin_unlock_irqrestore(&phba->hbalock, iflags);
workposted = true;
break;
@@ -8794,7 +8766,58 @@ lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_cqe *cqe)
}
out:
return workposted;
+}
+
+/**
+ * lpfc_sli4_sp_handle_cqe - Process a slow path completion queue entry
+ * @phba: Pointer to HBA context object.
+ * @cq: Pointer to the completion queue.
+ * @wcqe: Pointer to a completion queue entry.
+ *
+ * This routine process a slow-path work-queue or recieve queue completion queue
+ * entry.
+ *
+ * Return: true if work posted to worker thread, otherwise false.
+ **/
+static bool
+lpfc_sli4_sp_handle_cqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
+ struct lpfc_cqe *cqe)
+{
+ struct lpfc_cqe cqevt;
+ bool workposted = false;
+
+ /* Copy the work queue CQE and convert endian order if needed */
+ lpfc_sli_pcimem_bcopy(cqe, &cqevt, sizeof(struct lpfc_cqe));
+ /* Check and process for different type of WCQE and dispatch */
+ switch (bf_get(lpfc_cqe_code, &cqevt)) {
+ case CQE_CODE_COMPL_WQE:
+ /* Process the WQ/RQ complete event */
+ workposted = lpfc_sli4_sp_handle_els_wcqe(phba,
+ (struct lpfc_wcqe_complete *)&cqevt);
+ break;
+ case CQE_CODE_RELEASE_WQE:
+ /* Process the WQ release event */
+ lpfc_sli4_sp_handle_rel_wcqe(phba,
+ (struct lpfc_wcqe_release *)&cqevt);
+ break;
+ case CQE_CODE_XRI_ABORTED:
+ /* Process the WQ XRI abort event */
+ workposted = lpfc_sli4_sp_handle_abort_xri_wcqe(phba, cq,
+ (struct sli4_wcqe_xri_aborted *)&cqevt);
+ break;
+ case CQE_CODE_RECEIVE:
+ /* Process the RQ event */
+ workposted = lpfc_sli4_sp_handle_rcqe(phba,
+ (struct lpfc_rcqe *)&cqevt);
+ break;
+ default:
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "0388 Not a valid WCQE code: x%x\n",
+ bf_get(lpfc_cqe_code, &cqevt));
+ break;
+ }
+ return workposted;
}
/**
@@ -8858,14 +8881,7 @@ lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe)
break;
case LPFC_WCQ:
while ((cqe = lpfc_sli4_cq_get(cq))) {
- workposted |= lpfc_sli4_sp_handle_wcqe(phba, cq, cqe);
- if (!(++ecount % LPFC_GET_QE_REL_INT))
- lpfc_sli4_cq_release(cq, LPFC_QUEUE_NOARM);
- }
- break;
- case LPFC_RCQ:
- while ((cqe = lpfc_sli4_cq_get(cq))) {
- workposted |= lpfc_sli4_sp_handle_rcqe(phba, cqe);
+ workposted |= lpfc_sli4_sp_handle_cqe(phba, cq, cqe);
if (!(++ecount % LPFC_GET_QE_REL_INT))
lpfc_sli4_cq_release(cq, LPFC_QUEUE_NOARM);
}
@@ -10427,8 +10443,7 @@ lpfc_sli4_next_xritag(struct lpfc_hba *phba)
return xritag;
}
spin_unlock_irq(&phba->hbalock);
-
- lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
"2004 Failed to allocate XRI.last XRITAG is %d"
" Max XRI is %d, Used XRI is %d\n",
phba->sli4_hba.next_xri,
@@ -10492,15 +10507,7 @@ lpfc_sli4_post_sgl_list(struct lpfc_hba *phba)
lpfc_sli4_mbox_cmd_free(phba, mbox);
return -ENOMEM;
}
-
/* Get the first SGE entry from the non-embedded DMA memory */
- if (unlikely(!mbox->sge_array)) {
- lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
- "2525 Failed to get the non-embedded SGE "
- "virtual address\n");
- lpfc_sli4_mbox_cmd_free(phba, mbox);
- return -ENOMEM;
- }
viraddr = mbox->sge_array->addr[0];
/* Set up the SGL pages in the non-embedded DMA pages */
@@ -10524,8 +10531,7 @@ lpfc_sli4_post_sgl_list(struct lpfc_hba *phba)
sgl_pg_pairs++;
}
bf_set(lpfc_post_sgl_pages_xri, sgl, xritag_start);
- pg_pairs = (pg_pairs > 0) ? (pg_pairs - 1) : pg_pairs;
- bf_set(lpfc_post_sgl_pages_xricnt, sgl, pg_pairs);
+ bf_set(lpfc_post_sgl_pages_xricnt, sgl, els_xri_cnt);
/* Perform endian conversion if necessary */
sgl->word0 = cpu_to_le32(sgl->word0);
@@ -10607,15 +10613,7 @@ lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *phba, struct list_head *sblist,
lpfc_sli4_mbox_cmd_free(phba, mbox);
return -ENOMEM;
}
-
/* Get the first SGE entry from the non-embedded DMA memory */
- if (unlikely(!mbox->sge_array)) {
- lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
- "2565 Failed to get the non-embedded SGE "
- "virtual address\n");
- lpfc_sli4_mbox_cmd_free(phba, mbox);
- return -ENOMEM;
- }
viraddr = mbox->sge_array->addr[0];
/* Set up the SGL pages in the non-embedded DMA pages */
@@ -10802,6 +10800,105 @@ lpfc_fc_frame_to_vport(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr,
}
/**
+ * lpfc_update_rcv_time_stamp - Update vport's rcv seq time stamp
+ * @vport: The vport to work on.
+ *
+ * This function updates the receive sequence time stamp for this vport. The
+ * receive sequence time stamp indicates the time that the last frame of the
+ * the sequence that has been idle for the longest amount of time was received.
+ * the driver uses this time stamp to indicate if any received sequences have
+ * timed out.
+ **/
+void
+lpfc_update_rcv_time_stamp(struct lpfc_vport *vport)
+{
+ struct lpfc_dmabuf *h_buf;
+ struct hbq_dmabuf *dmabuf = NULL;
+
+ /* get the oldest sequence on the rcv list */
+ h_buf = list_get_first(&vport->rcv_buffer_list,
+ struct lpfc_dmabuf, list);
+ if (!h_buf)
+ return;
+ dmabuf = container_of(h_buf, struct hbq_dmabuf, hbuf);
+ vport->rcv_buffer_time_stamp = dmabuf->time_stamp;
+}
+
+/**
+ * lpfc_cleanup_rcv_buffers - Cleans up all outstanding receive sequences.
+ * @vport: The vport that the received sequences were sent to.
+ *
+ * This function cleans up all outstanding received sequences. This is called
+ * by the driver when a link event or user action invalidates all the received
+ * sequences.
+ **/
+void
+lpfc_cleanup_rcv_buffers(struct lpfc_vport *vport)
+{
+ struct lpfc_dmabuf *h_buf, *hnext;
+ struct lpfc_dmabuf *d_buf, *dnext;
+ struct hbq_dmabuf *dmabuf = NULL;
+
+ /* start with the oldest sequence on the rcv list */
+ list_for_each_entry_safe(h_buf, hnext, &vport->rcv_buffer_list, list) {
+ dmabuf = container_of(h_buf, struct hbq_dmabuf, hbuf);
+ list_del_init(&dmabuf->hbuf.list);
+ list_for_each_entry_safe(d_buf, dnext,
+ &dmabuf->dbuf.list, list) {
+ list_del_init(&d_buf->list);
+ lpfc_in_buf_free(vport->phba, d_buf);
+ }
+ lpfc_in_buf_free(vport->phba, &dmabuf->dbuf);
+ }
+}
+
+/**
+ * lpfc_rcv_seq_check_edtov - Cleans up timed out receive sequences.
+ * @vport: The vport that the received sequences were sent to.
+ *
+ * This function determines whether any received sequences have timed out by
+ * first checking the vport's rcv_buffer_time_stamp. If this time_stamp
+ * indicates that there is at least one timed out sequence this routine will
+ * go through the received sequences one at a time from most inactive to most
+ * active to determine which ones need to be cleaned up. Once it has determined
+ * that a sequence needs to be cleaned up it will simply free up the resources
+ * without sending an abort.
+ **/
+void
+lpfc_rcv_seq_check_edtov(struct lpfc_vport *vport)
+{
+ struct lpfc_dmabuf *h_buf, *hnext;
+ struct lpfc_dmabuf *d_buf, *dnext;
+ struct hbq_dmabuf *dmabuf = NULL;
+ unsigned long timeout;
+ int abort_count = 0;
+
+ timeout = (msecs_to_jiffies(vport->phba->fc_edtov) +
+ vport->rcv_buffer_time_stamp);
+ if (list_empty(&vport->rcv_buffer_list) ||
+ time_before(jiffies, timeout))
+ return;
+ /* start with the oldest sequence on the rcv list */
+ list_for_each_entry_safe(h_buf, hnext, &vport->rcv_buffer_list, list) {
+ dmabuf = container_of(h_buf, struct hbq_dmabuf, hbuf);
+ timeout = (msecs_to_jiffies(vport->phba->fc_edtov) +
+ dmabuf->time_stamp);
+ if (time_before(jiffies, timeout))
+ break;
+ abort_count++;
+ list_del_init(&dmabuf->hbuf.list);
+ list_for_each_entry_safe(d_buf, dnext,
+ &dmabuf->dbuf.list, list) {
+ list_del_init(&d_buf->list);
+ lpfc_in_buf_free(vport->phba, d_buf);
+ }
+ lpfc_in_buf_free(vport->phba, &dmabuf->dbuf);
+ }
+ if (abort_count)
+ lpfc_update_rcv_time_stamp(vport);
+}
+
+/**
* lpfc_fc_frame_add - Adds a frame to the vport's list of received sequences
* @dmabuf: pointer to a dmabuf that describes the hdr and data of the FC frame
*
@@ -10823,6 +10920,8 @@ lpfc_fc_frame_add(struct lpfc_vport *vport, struct hbq_dmabuf *dmabuf)
struct hbq_dmabuf *seq_dmabuf = NULL;
struct hbq_dmabuf *temp_dmabuf = NULL;
+ INIT_LIST_HEAD(&dmabuf->dbuf.list);
+ dmabuf->time_stamp = jiffies;
new_hdr = (struct fc_frame_header *)dmabuf->hbuf.virt;
/* Use the hdr_buf to find the sequence that this frame belongs to */
list_for_each_entry(h_buf, &vport->rcv_buffer_list, list) {
@@ -10841,13 +10940,21 @@ lpfc_fc_frame_add(struct lpfc_vport *vport, struct hbq_dmabuf *dmabuf)
* Queue the buffer on the vport's rcv_buffer_list.
*/
list_add_tail(&dmabuf->hbuf.list, &vport->rcv_buffer_list);
+ lpfc_update_rcv_time_stamp(vport);
return dmabuf;
}
temp_hdr = seq_dmabuf->hbuf.virt;
if (new_hdr->fh_seq_cnt < temp_hdr->fh_seq_cnt) {
- list_add(&seq_dmabuf->dbuf.list, &dmabuf->dbuf.list);
+ list_del_init(&seq_dmabuf->hbuf.list);
+ list_add_tail(&dmabuf->hbuf.list, &vport->rcv_buffer_list);
+ list_add_tail(&dmabuf->dbuf.list, &seq_dmabuf->dbuf.list);
+ lpfc_update_rcv_time_stamp(vport);
return dmabuf;
}
+ /* move this sequence to the tail to indicate a young sequence */
+ list_move_tail(&seq_dmabuf->hbuf.list, &vport->rcv_buffer_list);
+ seq_dmabuf->time_stamp = jiffies;
+ lpfc_update_rcv_time_stamp(vport);
/* find the correct place in the sequence to insert this frame */
list_for_each_entry_reverse(d_buf, &seq_dmabuf->dbuf.list, list) {
temp_dmabuf = container_of(d_buf, struct hbq_dmabuf, dbuf);
@@ -10865,6 +10972,210 @@ lpfc_fc_frame_add(struct lpfc_vport *vport, struct hbq_dmabuf *dmabuf)
}
/**
+ * lpfc_sli4_abort_partial_seq - Abort partially assembled unsol sequence
+ * @vport: pointer to a vitural port
+ * @dmabuf: pointer to a dmabuf that describes the FC sequence
+ *
+ * This function tries to abort from the partially assembed sequence, described
+ * by the information from basic abbort @dmabuf. It checks to see whether such
+ * partially assembled sequence held by the driver. If so, it shall free up all
+ * the frames from the partially assembled sequence.
+ *
+ * Return
+ * true -- if there is matching partially assembled sequence present and all
+ * the frames freed with the sequence;
+ * false -- if there is no matching partially assembled sequence present so
+ * nothing got aborted in the lower layer driver
+ **/
+static bool
+lpfc_sli4_abort_partial_seq(struct lpfc_vport *vport,
+ struct hbq_dmabuf *dmabuf)
+{
+ struct fc_frame_header *new_hdr;
+ struct fc_frame_header *temp_hdr;
+ struct lpfc_dmabuf *d_buf, *n_buf, *h_buf;
+ struct hbq_dmabuf *seq_dmabuf = NULL;
+
+ /* Use the hdr_buf to find the sequence that matches this frame */
+ INIT_LIST_HEAD(&dmabuf->dbuf.list);
+ INIT_LIST_HEAD(&dmabuf->hbuf.list);
+ new_hdr = (struct fc_frame_header *)dmabuf->hbuf.virt;
+ list_for_each_entry(h_buf, &vport->rcv_buffer_list, list) {
+ temp_hdr = (struct fc_frame_header *)h_buf->virt;
+ if ((temp_hdr->fh_seq_id != new_hdr->fh_seq_id) ||
+ (temp_hdr->fh_ox_id != new_hdr->fh_ox_id) ||
+ (memcmp(&temp_hdr->fh_s_id, &new_hdr->fh_s_id, 3)))
+ continue;
+ /* found a pending sequence that matches this frame */
+ seq_dmabuf = container_of(h_buf, struct hbq_dmabuf, hbuf);
+ break;
+ }
+
+ /* Free up all the frames from the partially assembled sequence */
+ if (seq_dmabuf) {
+ list_for_each_entry_safe(d_buf, n_buf,
+ &seq_dmabuf->dbuf.list, list) {
+ list_del_init(&d_buf->list);
+ lpfc_in_buf_free(vport->phba, d_buf);
+ }
+ return true;
+ }
+ return false;
+}
+
+/**
+ * lpfc_sli4_seq_abort_acc_cmpl - Accept seq abort iocb complete handler
+ * @phba: Pointer to HBA context object.
+ * @cmd_iocbq: pointer to the command iocbq structure.
+ * @rsp_iocbq: pointer to the response iocbq structure.
+ *
+ * This function handles the sequence abort accept iocb command complete
+ * event. It properly releases the memory allocated to the sequence abort
+ * accept iocb.
+ **/
+static void
+lpfc_sli4_seq_abort_acc_cmpl(struct lpfc_hba *phba,
+ struct lpfc_iocbq *cmd_iocbq,
+ struct lpfc_iocbq *rsp_iocbq)
+{
+ if (cmd_iocbq)
+ lpfc_sli_release_iocbq(phba, cmd_iocbq);
+}
+
+/**
+ * lpfc_sli4_seq_abort_acc - Accept sequence abort
+ * @phba: Pointer to HBA context object.
+ * @fc_hdr: pointer to a FC frame header.
+ *
+ * This function sends a basic accept to a previous unsol sequence abort
+ * event after aborting the sequence handling.
+ **/
+static void
+lpfc_sli4_seq_abort_acc(struct lpfc_hba *phba,
+ struct fc_frame_header *fc_hdr)
+{
+ struct lpfc_iocbq *ctiocb = NULL;
+ struct lpfc_nodelist *ndlp;
+ uint16_t oxid, rxid;
+ uint32_t sid, fctl;
+ IOCB_t *icmd;
+
+ if (!lpfc_is_link_up(phba))
+ return;
+
+ sid = sli4_sid_from_fc_hdr(fc_hdr);
+ oxid = be16_to_cpu(fc_hdr->fh_ox_id);
+ rxid = be16_to_cpu(fc_hdr->fh_rx_id);
+
+ ndlp = lpfc_findnode_did(phba->pport, sid);
+ if (!ndlp) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_ELS,
+ "1268 Find ndlp returned NULL for oxid:x%x "
+ "SID:x%x\n", oxid, sid);
+ return;
+ }
+
+ /* Allocate buffer for acc iocb */
+ ctiocb = lpfc_sli_get_iocbq(phba);
+ if (!ctiocb)
+ return;
+
+ /* Extract the F_CTL field from FC_HDR */
+ fctl = sli4_fctl_from_fc_hdr(fc_hdr);
+
+ icmd = &ctiocb->iocb;
+ icmd->un.xseq64.bdl.bdeSize = 0;
+ icmd->un.xseq64.bdl.ulpIoTag32 = 0;
+ icmd->un.xseq64.w5.hcsw.Dfctl = 0;
+ icmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_BA_ACC;
+ icmd->un.xseq64.w5.hcsw.Type = FC_TYPE_BLS;
+
+ /* Fill in the rest of iocb fields */
+ icmd->ulpCommand = CMD_XMIT_BLS_RSP64_CX;
+ icmd->ulpBdeCount = 0;
+ icmd->ulpLe = 1;
+ icmd->ulpClass = CLASS3;
+ icmd->ulpContext = ndlp->nlp_rpi;
+
+ ctiocb->iocb_cmpl = NULL;
+ ctiocb->vport = phba->pport;
+ ctiocb->iocb_cmpl = lpfc_sli4_seq_abort_acc_cmpl;
+
+ if (fctl & FC_FC_EX_CTX) {
+ /* ABTS sent by responder to CT exchange, construction
+ * of BA_ACC will use OX_ID from ABTS for the XRI_TAG
+ * field and RX_ID from ABTS for RX_ID field.
+ */
+ bf_set(lpfc_abts_orig, &icmd->un.bls_acc, LPFC_ABTS_UNSOL_RSP);
+ bf_set(lpfc_abts_rxid, &icmd->un.bls_acc, rxid);
+ ctiocb->sli4_xritag = oxid;
+ } else {
+ /* ABTS sent by initiator to CT exchange, construction
+ * of BA_ACC will need to allocate a new XRI as for the
+ * XRI_TAG and RX_ID fields.
+ */
+ bf_set(lpfc_abts_orig, &icmd->un.bls_acc, LPFC_ABTS_UNSOL_INT);
+ bf_set(lpfc_abts_rxid, &icmd->un.bls_acc, NO_XRI);
+ ctiocb->sli4_xritag = NO_XRI;
+ }
+ bf_set(lpfc_abts_oxid, &icmd->un.bls_acc, oxid);
+
+ /* Xmit CT abts accept on exchange <xid> */
+ lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+ "1200 Xmit CT ABTS ACC on exchange x%x Data: x%x\n",
+ CMD_XMIT_BLS_RSP64_CX, phba->link_state);
+ lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, ctiocb, 0);
+}
+
+/**
+ * lpfc_sli4_handle_unsol_abort - Handle sli-4 unsolicited abort event
+ * @vport: Pointer to the vport on which this sequence was received
+ * @dmabuf: pointer to a dmabuf that describes the FC sequence
+ *
+ * This function handles an SLI-4 unsolicited abort event. If the unsolicited
+ * receive sequence is only partially assembed by the driver, it shall abort
+ * the partially assembled frames for the sequence. Otherwise, if the
+ * unsolicited receive sequence has been completely assembled and passed to
+ * the Upper Layer Protocol (UPL), it then mark the per oxid status for the
+ * unsolicited sequence has been aborted. After that, it will issue a basic
+ * accept to accept the abort.
+ **/
+void
+lpfc_sli4_handle_unsol_abort(struct lpfc_vport *vport,
+ struct hbq_dmabuf *dmabuf)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct fc_frame_header fc_hdr;
+ uint32_t fctl;
+ bool abts_par;
+
+ /* Make a copy of fc_hdr before the dmabuf being released */
+ memcpy(&fc_hdr, dmabuf->hbuf.virt, sizeof(struct fc_frame_header));
+ fctl = sli4_fctl_from_fc_hdr(&fc_hdr);
+
+ if (fctl & FC_FC_EX_CTX) {
+ /*
+ * ABTS sent by responder to exchange, just free the buffer
+ */
+ lpfc_in_buf_free(phba, &dmabuf->dbuf);
+ } else {
+ /*
+ * ABTS sent by initiator to exchange, need to do cleanup
+ */
+ /* Try to abort partially assembled seq */
+ abts_par = lpfc_sli4_abort_partial_seq(vport, dmabuf);
+
+ /* Send abort to ULP if partially seq abort failed */
+ if (abts_par == false)
+ lpfc_sli4_send_seq_to_ulp(vport, dmabuf);
+ else
+ lpfc_in_buf_free(phba, &dmabuf->dbuf);
+ }
+ /* Send basic accept (BA_ACC) to the abort requester */
+ lpfc_sli4_seq_abort_acc(phba, &fc_hdr);
+}
+
+/**
* lpfc_seq_complete - Indicates if a sequence is complete
* @dmabuf: pointer to a dmabuf that describes the FC sequence
*
@@ -10935,10 +11246,9 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
fc_hdr = (struct fc_frame_header *)seq_dmabuf->hbuf.virt;
/* remove from receive buffer list */
list_del_init(&seq_dmabuf->hbuf.list);
+ lpfc_update_rcv_time_stamp(vport);
/* get the Remote Port's SID */
- sid = (fc_hdr->fh_s_id[0] << 16 |
- fc_hdr->fh_s_id[1] << 8 |
- fc_hdr->fh_s_id[2]);
+ sid = sli4_sid_from_fc_hdr(fc_hdr);
/* Get an iocbq struct to fill in. */
first_iocbq = lpfc_sli_get_iocbq(vport->phba);
if (first_iocbq) {
@@ -10957,7 +11267,8 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
LPFC_DATA_BUF_SIZE;
first_iocbq->iocb.un.rcvels.remoteID = sid;
first_iocbq->iocb.unsli3.rcvsli3.acc_len +=
- bf_get(lpfc_rcqe_length, &seq_dmabuf->rcqe);
+ bf_get(lpfc_rcqe_length,
+ &seq_dmabuf->cq_event.cqe.rcqe_cmpl);
}
iocbq = first_iocbq;
/*
@@ -10975,7 +11286,8 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
iocbq->iocb.unsli3.rcvsli3.bde2.tus.f.bdeSize =
LPFC_DATA_BUF_SIZE;
first_iocbq->iocb.unsli3.rcvsli3.acc_len +=
- bf_get(lpfc_rcqe_length, &seq_dmabuf->rcqe);
+ bf_get(lpfc_rcqe_length,
+ &seq_dmabuf->cq_event.cqe.rcqe_cmpl);
} else {
iocbq = lpfc_sli_get_iocbq(vport->phba);
if (!iocbq) {
@@ -10994,7 +11306,8 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
iocbq->iocb.un.cont64[0].tus.f.bdeSize =
LPFC_DATA_BUF_SIZE;
first_iocbq->iocb.unsli3.rcvsli3.acc_len +=
- bf_get(lpfc_rcqe_length, &seq_dmabuf->rcqe);
+ bf_get(lpfc_rcqe_length,
+ &seq_dmabuf->cq_event.cqe.rcqe_cmpl);
iocbq->iocb.un.rcvels.remoteID = sid;
list_add_tail(&iocbq->list, &first_iocbq->list);
}
@@ -11002,6 +11315,43 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
return first_iocbq;
}
+static void
+lpfc_sli4_send_seq_to_ulp(struct lpfc_vport *vport,
+ struct hbq_dmabuf *seq_dmabuf)
+{
+ struct fc_frame_header *fc_hdr;
+ struct lpfc_iocbq *iocbq, *curr_iocb, *next_iocb;
+ struct lpfc_hba *phba = vport->phba;
+
+ fc_hdr = (struct fc_frame_header *)seq_dmabuf->hbuf.virt;
+ iocbq = lpfc_prep_seq(vport, seq_dmabuf);
+ if (!iocbq) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "2707 Ring %d handler: Failed to allocate "
+ "iocb Rctl x%x Type x%x received\n",
+ LPFC_ELS_RING,
+ fc_hdr->fh_r_ctl, fc_hdr->fh_type);
+ return;
+ }
+ if (!lpfc_complete_unsol_iocb(phba,
+ &phba->sli.ring[LPFC_ELS_RING],
+ iocbq, fc_hdr->fh_r_ctl,
+ fc_hdr->fh_type))
+ lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+ "2540 Ring %d handler: unexpected Rctl "
+ "x%x Type x%x received\n",
+ LPFC_ELS_RING,
+ fc_hdr->fh_r_ctl, fc_hdr->fh_type);
+
+ /* Free iocb created in lpfc_prep_seq */
+ list_for_each_entry_safe(curr_iocb, next_iocb,
+ &iocbq->list, list) {
+ list_del_init(&curr_iocb->list);
+ lpfc_sli_release_iocbq(phba, curr_iocb);
+ }
+ lpfc_sli_release_iocbq(phba, iocbq);
+}
+
/**
* lpfc_sli4_handle_received_buffer - Handle received buffers from firmware
* @phba: Pointer to HBA context object.
@@ -11014,67 +11364,54 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
* Worker thread calls lpfc_sli4_handle_received_buffer, which will call the
* appropriate receive function when the final frame in a sequence is received.
**/
-int
-lpfc_sli4_handle_received_buffer(struct lpfc_hba *phba)
+void
+lpfc_sli4_handle_received_buffer(struct lpfc_hba *phba,
+ struct hbq_dmabuf *dmabuf)
{
- LIST_HEAD(cmplq);
- struct hbq_dmabuf *dmabuf, *seq_dmabuf;
+ struct hbq_dmabuf *seq_dmabuf;
struct fc_frame_header *fc_hdr;
struct lpfc_vport *vport;
uint32_t fcfi;
- struct lpfc_iocbq *iocbq;
-
- /* Clear hba flag and get all received buffers into the cmplq */
- spin_lock_irq(&phba->hbalock);
- phba->hba_flag &= ~HBA_RECEIVE_BUFFER;
- list_splice_init(&phba->rb_pend_list, &cmplq);
- spin_unlock_irq(&phba->hbalock);
/* Process each received buffer */
- while ((dmabuf = lpfc_sli_hbqbuf_get(&cmplq)) != NULL) {
- fc_hdr = (struct fc_frame_header *)dmabuf->hbuf.virt;
- /* check to see if this a valid type of frame */
- if (lpfc_fc_frame_check(phba, fc_hdr)) {
- lpfc_in_buf_free(phba, &dmabuf->dbuf);
- continue;
- }
- fcfi = bf_get(lpfc_rcqe_fcf_id, &dmabuf->rcqe);
- vport = lpfc_fc_frame_to_vport(phba, fc_hdr, fcfi);
- if (!vport) {
- /* throw out the frame */
- lpfc_in_buf_free(phba, &dmabuf->dbuf);
- continue;
- }
- /* Link this frame */
- seq_dmabuf = lpfc_fc_frame_add(vport, dmabuf);
- if (!seq_dmabuf) {
- /* unable to add frame to vport - throw it out */
- lpfc_in_buf_free(phba, &dmabuf->dbuf);
- continue;
- }
- /* If not last frame in sequence continue processing frames. */
- if (!lpfc_seq_complete(seq_dmabuf)) {
- /*
- * When saving off frames post a new one and mark this
- * frame to be freed when it is finished.
- **/
- lpfc_sli_hbqbuf_fill_hbqs(phba, LPFC_ELS_HBQ, 1);
- dmabuf->tag = -1;
- continue;
- }
- fc_hdr = (struct fc_frame_header *)seq_dmabuf->hbuf.virt;
- iocbq = lpfc_prep_seq(vport, seq_dmabuf);
- if (!lpfc_complete_unsol_iocb(phba,
- &phba->sli.ring[LPFC_ELS_RING],
- iocbq, fc_hdr->fh_r_ctl,
- fc_hdr->fh_type))
- lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
- "2540 Ring %d handler: unexpected Rctl "
- "x%x Type x%x received\n",
- LPFC_ELS_RING,
- fc_hdr->fh_r_ctl, fc_hdr->fh_type);
- };
- return 0;
+ fc_hdr = (struct fc_frame_header *)dmabuf->hbuf.virt;
+ /* check to see if this a valid type of frame */
+ if (lpfc_fc_frame_check(phba, fc_hdr)) {
+ lpfc_in_buf_free(phba, &dmabuf->dbuf);
+ return;
+ }
+ fcfi = bf_get(lpfc_rcqe_fcf_id, &dmabuf->cq_event.cqe.rcqe_cmpl);
+ vport = lpfc_fc_frame_to_vport(phba, fc_hdr, fcfi);
+ if (!vport || !(vport->vpi_state & LPFC_VPI_REGISTERED)) {
+ /* throw out the frame */
+ lpfc_in_buf_free(phba, &dmabuf->dbuf);
+ return;
+ }
+ /* Handle the basic abort sequence (BA_ABTS) event */
+ if (fc_hdr->fh_r_ctl == FC_RCTL_BA_ABTS) {
+ lpfc_sli4_handle_unsol_abort(vport, dmabuf);
+ return;
+ }
+
+ /* Link this frame */
+ seq_dmabuf = lpfc_fc_frame_add(vport, dmabuf);
+ if (!seq_dmabuf) {
+ /* unable to add frame to vport - throw it out */
+ lpfc_in_buf_free(phba, &dmabuf->dbuf);
+ return;
+ }
+ /* If not last frame in sequence continue processing frames. */
+ if (!lpfc_seq_complete(seq_dmabuf)) {
+ /*
+ * When saving off frames post a new one and mark this
+ * frame to be freed when it is finished.
+ **/
+ lpfc_sli_hbqbuf_fill_hbqs(phba, LPFC_ELS_HBQ, 1);
+ dmabuf->tag = -1;
+ return;
+ }
+ /* Send the complete sequence to the upper layer protocol */
+ lpfc_sli4_send_seq_to_ulp(vport, seq_dmabuf);
}
/**
@@ -11091,7 +11428,7 @@ lpfc_sli4_handle_received_buffer(struct lpfc_hba *phba)
* sequential.
*
* Return codes
- * 0 - sucessful
+ * 0 - successful
* EIO - The mailbox failed to complete successfully.
* When this error occurs, the driver is not guaranteed
* to have any rpi regions posted to the device and
@@ -11129,7 +11466,7 @@ lpfc_sli4_post_all_rpi_hdrs(struct lpfc_hba *phba)
* maps up to 64 rpi context regions.
*
* Return codes
- * 0 - sucessful
+ * 0 - successful
* ENOMEM - No available memory
* EIO - The mailbox failed to complete successfully.
**/
@@ -11191,7 +11528,7 @@ lpfc_sli4_post_rpi_hdr(struct lpfc_hba *phba, struct lpfc_rpi_hdr *rpi_page)
* PAGE_SIZE modulo 64 rpi context headers.
*
* Returns
- * A nonzero rpi defined as rpi_base <= rpi < max_rpi if sucessful
+ * A nonzero rpi defined as rpi_base <= rpi < max_rpi if successful
* LPFC_RPI_ALLOC_ERROR if no rpis are available.
**/
int
@@ -11334,6 +11671,7 @@ lpfc_sli4_init_vpi(struct lpfc_hba *phba, uint16_t vpi)
{
LPFC_MBOXQ_t *mboxq;
int rc = 0;
+ int retval = MBX_SUCCESS;
uint32_t mbox_tmo;
if (vpi == 0)
@@ -11344,16 +11682,17 @@ lpfc_sli4_init_vpi(struct lpfc_hba *phba, uint16_t vpi)
lpfc_init_vpi(phba, mboxq, vpi);
mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_INIT_VPI);
rc = lpfc_sli_issue_mbox_wait(phba, mboxq, mbox_tmo);
- if (rc != MBX_TIMEOUT)
- mempool_free(mboxq, phba->mbox_mem_pool);
if (rc != MBX_SUCCESS) {
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"2022 INIT VPI Mailbox failed "
"status %d, mbxStatus x%x\n", rc,
bf_get(lpfc_mqe_status, &mboxq->u.mqe));
- rc = -EIO;
+ retval = -EIO;
}
- return rc;
+ if (rc != MBX_TIMEOUT)
+ mempool_free(mboxq, phba->mbox_mem_pool);
+
+ return retval;
}
/**
@@ -11438,13 +11777,6 @@ lpfc_sli4_add_fcf_record(struct lpfc_hba *phba, struct fcf_record *fcf_record)
*/
lpfc_sli4_mbx_sge_get(mboxq, 0, &sge);
phys_addr = getPaddr(sge.pa_hi, sge.pa_lo);
- if (unlikely(!mboxq->sge_array)) {
- lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
- "2526 Failed to get the non-embedded SGE "
- "virtual address\n");
- lpfc_sli4_mbox_cmd_free(phba, mboxq);
- return -ENOMEM;
- }
virt_addr = mboxq->sge_array->addr[0];
/*
* Configure the FCF record for FCFI 0. This is the driver's
@@ -11542,7 +11874,8 @@ lpfc_sli4_read_fcf_record(struct lpfc_hba *phba, uint16_t fcf_index)
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"2000 Failed to allocate mbox for "
"READ_FCF cmd\n");
- return -ENOMEM;
+ error = -ENOMEM;
+ goto fail_fcfscan;
}
req_len = sizeof(struct fcf_record) +
@@ -11558,8 +11891,8 @@ lpfc_sli4_read_fcf_record(struct lpfc_hba *phba, uint16_t fcf_index)
"0291 Allocated DMA memory size (x%x) is "
"less than the requested DMA memory "
"size (x%x)\n", alloc_len, req_len);
- lpfc_sli4_mbox_cmd_free(phba, mboxq);
- return -ENOMEM;
+ error = -ENOMEM;
+ goto fail_fcfscan;
}
/* Get the first SGE entry from the non-embedded DMA memory. This
@@ -11567,13 +11900,6 @@ lpfc_sli4_read_fcf_record(struct lpfc_hba *phba, uint16_t fcf_index)
*/
lpfc_sli4_mbx_sge_get(mboxq, 0, &sge);
phys_addr = getPaddr(sge.pa_hi, sge.pa_lo);
- if (unlikely(!mboxq->sge_array)) {
- lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
- "2527 Failed to get the non-embedded SGE "
- "virtual address\n");
- lpfc_sli4_mbox_cmd_free(phba, mboxq);
- return -ENOMEM;
- }
virt_addr = mboxq->sge_array->addr[0];
read_fcf = (struct lpfc_mbx_read_fcf_tbl *)virt_addr;
@@ -11586,7 +11912,6 @@ lpfc_sli4_read_fcf_record(struct lpfc_hba *phba, uint16_t fcf_index)
mboxq->mbox_cmpl = lpfc_mbx_cmpl_read_fcf_record;
rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
if (rc == MBX_NOT_FINISHED) {
- lpfc_sli4_mbox_cmd_free(phba, mboxq);
error = -EIO;
} else {
spin_lock_irq(&phba->hbalock);
@@ -11594,6 +11919,15 @@ lpfc_sli4_read_fcf_record(struct lpfc_hba *phba, uint16_t fcf_index)
spin_unlock_irq(&phba->hbalock);
error = 0;
}
+fail_fcfscan:
+ if (error) {
+ if (mboxq)
+ lpfc_sli4_mbox_cmd_free(phba, mboxq);
+ /* FCF scan failed, clear FCF_DISC_INPROGRESS flag */
+ spin_lock_irq(&phba->hbalock);
+ phba->hba_flag &= ~FCF_DISC_INPROGRESS;
+ spin_unlock_irq(&phba->hbalock);
+ }
return error;
}
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
index 3c53316..ba38de3 100644
--- a/drivers/scsi/lpfc/lpfc_sli.h
+++ b/drivers/scsi/lpfc/lpfc_sli.h
@@ -29,14 +29,17 @@ typedef enum _lpfc_ctx_cmd {
LPFC_CTX_HOST
} lpfc_ctx_cmd;
-/* This structure is used to carry the needed response IOCB states */
-struct lpfc_sli4_rspiocb_info {
- uint8_t hw_status;
- uint8_t bfield;
-#define LPFC_XB 0x1
-#define LPFC_PV 0x2
- uint8_t priority;
- uint8_t reserved;
+struct lpfc_cq_event {
+ struct list_head list;
+ union {
+ struct lpfc_mcqe mcqe_cmpl;
+ struct lpfc_acqe_link acqe_link;
+ struct lpfc_acqe_fcoe acqe_fcoe;
+ struct lpfc_acqe_dcbx acqe_dcbx;
+ struct lpfc_rcqe rcqe_cmpl;
+ struct sli4_wcqe_xri_aborted wcqe_axri;
+ struct lpfc_wcqe_complete wcqe_cmpl;
+ } cqe;
};
/* This structure is used to handle IOCB requests / responses */
@@ -46,6 +49,7 @@ struct lpfc_iocbq {
struct list_head clist;
uint16_t iotag; /* pre-assigned IO tag */
uint16_t sli4_xritag; /* pre-assigned XRI, (OXID) tag. */
+ struct lpfc_cq_event cq_event;
IOCB_t iocb; /* IOCB cmd */
uint8_t retry; /* retry counter for IOCB cmd - if needed */
@@ -56,11 +60,13 @@ struct lpfc_iocbq {
#define LPFC_DRIVER_ABORTED 8 /* driver aborted this request */
#define LPFC_IO_FABRIC 0x10 /* Iocb send using fabric scheduler */
#define LPFC_DELAY_MEM_FREE 0x20 /* Defer free'ing of FC data */
-#define LPFC_FIP_ELS 0x40
+#define LPFC_FIP_ELS_ID_MASK 0xc0 /* ELS_ID range 0-3 */
+#define LPFC_FIP_ELS_ID_SHIFT 6
uint8_t abort_count;
uint8_t rsvd2;
uint32_t drvrTimeout; /* driver timeout in seconds */
+ uint32_t fcp_wqidx; /* index to FCP work queue */
struct lpfc_vport *vport;/* virtual port pointer */
void *context1; /* caller context information */
void *context2; /* caller context information */
@@ -76,7 +82,6 @@ struct lpfc_iocbq {
struct lpfc_iocbq *);
void (*iocb_cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
struct lpfc_iocbq *);
- struct lpfc_sli4_rspiocb_info sli4_info;
};
#define SLI_IOCB_RET_IOCB 1 /* Return IOCB if cmd ring full */
@@ -110,7 +115,7 @@ typedef struct lpfcMboxq {
return */
#define MBX_NOWAIT 2 /* issue command then return immediately */
-#define LPFC_MAX_RING_MASK 4 /* max num of rctl/type masks allowed per
+#define LPFC_MAX_RING_MASK 5 /* max num of rctl/type masks allowed per
ring */
#define LPFC_MAX_RING 4 /* max num of SLI rings used by driver */
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h
index b5f4ba1..25d66d0 100644
--- a/drivers/scsi/lpfc/lpfc_sli4.h
+++ b/drivers/scsi/lpfc/lpfc_sli4.h
@@ -58,6 +58,16 @@
#define LPFC_FCOE_FKA_ADV_PER 0
#define LPFC_FCOE_FIP_PRIORITY 0x80
+#define sli4_sid_from_fc_hdr(fc_hdr) \
+ ((fc_hdr)->fh_s_id[0] << 16 | \
+ (fc_hdr)->fh_s_id[1] << 8 | \
+ (fc_hdr)->fh_s_id[2])
+
+#define sli4_fctl_from_fc_hdr(fc_hdr) \
+ ((fc_hdr)->fh_f_ctl[0] << 16 | \
+ (fc_hdr)->fh_f_ctl[1] << 8 | \
+ (fc_hdr)->fh_f_ctl[2])
+
enum lpfc_sli4_queue_type {
LPFC_EQ,
LPFC_GCQ,
@@ -110,18 +120,6 @@ struct lpfc_queue {
union sli4_qe qe[1]; /* array to index entries (must be last) */
};
-struct lpfc_cq_event {
- struct list_head list;
- union {
- struct lpfc_mcqe mcqe_cmpl;
- struct lpfc_acqe_link acqe_link;
- struct lpfc_acqe_fcoe acqe_fcoe;
- struct lpfc_acqe_dcbx acqe_dcbx;
- struct lpfc_rcqe rcqe_cmpl;
- struct sli4_wcqe_xri_aborted wcqe_axri;
- } cqe;
-};
-
struct lpfc_sli4_link {
uint8_t speed;
uint8_t duplex;
@@ -166,7 +164,7 @@ struct lpfc_fip_param_hdr {
#define lpfc_fip_param_hdr_fipp_mode_SHIFT 6
#define lpfc_fip_param_hdr_fipp_mode_MASK 0x3
#define lpfc_fip_param_hdr_fipp_mode_WORD parm_flags
-#define FIPP_MODE_ON 0x2
+#define FIPP_MODE_ON 0x1
#define FIPP_MODE_OFF 0x0
#define FIPP_VLAN_VALID 0x1
};
@@ -295,9 +293,8 @@ struct lpfc_sli4_hba {
/* BAR0 PCI config space register memory map */
void __iomem *UERRLOregaddr; /* Address to UERR_STATUS_LO register */
void __iomem *UERRHIregaddr; /* Address to UERR_STATUS_HI register */
- void __iomem *ONLINE0regaddr; /* Address to components of internal UE */
- void __iomem *ONLINE1regaddr; /* Address to components of internal UE */
-#define LPFC_ONLINE_NERR 0xFFFFFFFF
+ void __iomem *UEMASKLOregaddr; /* Address to UE_MASK_LO register */
+ void __iomem *UEMASKHIregaddr; /* Address to UE_MASK_HI register */
void __iomem *SCRATCHPADregaddr; /* Address to scratchpad register */
/* BAR1 FCoE function CSR register memory map */
void __iomem *STAregaddr; /* Address to HST_STATE register */
@@ -311,6 +308,8 @@ struct lpfc_sli4_hba {
void __iomem *MQDBregaddr; /* Address to MQ_DOORBELL register */
void __iomem *BMBXregaddr; /* Address to BootStrap MBX register */
+ uint32_t ue_mask_lo;
+ uint32_t ue_mask_hi;
struct msix_entry *msix_entries;
uint32_t cfg_eqn;
struct lpfc_fcp_eq_hdl *fcp_eq_hdl; /* FCP per-WQ handle */
@@ -325,7 +324,6 @@ struct lpfc_sli4_hba {
struct lpfc_queue **fcp_cq;/* Fast-path FCP compl queue */
struct lpfc_queue *mbx_cq; /* Slow-path mailbox complete queue */
struct lpfc_queue *els_cq; /* Slow-path ELS response complete queue */
- struct lpfc_queue *rxq_cq; /* Slow-path unsolicited complete queue */
/* Setup information for various queue parameters */
int eq_esize;
@@ -360,7 +358,7 @@ struct lpfc_sli4_hba {
unsigned long *rpi_bmask;
uint16_t rpi_count;
struct lpfc_sli4_flags sli4_flags;
- struct list_head sp_rspiocb_work_queue;
+ struct list_head sp_queue_event;
struct list_head sp_cqe_event_pool;
struct list_head sp_asynce_work_queue;
struct list_head sp_fcp_xri_aborted_work_queue;
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index 9ae20af..c7f3aed 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -18,8 +18,7 @@
* included with this package. *
*******************************************************************/
-#define LPFC_DRIVER_VERSION "8.3.4"
-
+#define LPFC_DRIVER_VERSION "8.3.6"
#define LPFC_DRIVER_NAME "lpfc"
#define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp"
#define LPFC_FP_DRIVER_HANDLER_NAME "lpfc:fp"
diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c
index 606efa7..7d6dd83 100644
--- a/drivers/scsi/lpfc/lpfc_vport.c
+++ b/drivers/scsi/lpfc/lpfc_vport.c
@@ -389,7 +389,7 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
* by the port.
*/
if ((phba->sli_rev == LPFC_SLI_REV4) &&
- (pport->vfi_state & LPFC_VFI_REGISTERED)) {
+ (pport->vpi_state & LPFC_VPI_REGISTERED)) {
rc = lpfc_sli4_init_vpi(phba, vpi);
if (rc) {
lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
@@ -700,6 +700,8 @@ lpfc_vport_delete(struct fc_vport *fc_vport)
}
spin_unlock_irq(&phba->ndlp_lock);
}
+ if (vport->vpi_state != LPFC_VPI_REGISTERED)
+ goto skip_logo;
vport->unreg_vpi_cmpl = VPORT_INVAL;
timeout = msecs_to_jiffies(phba->fc_ratov * 2000);
if (!lpfc_issue_els_npiv_logo(vport, ndlp))
diff --git a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h
index 512c2cc..d310f49 100644
--- a/drivers/scsi/megaraid.h
+++ b/drivers/scsi/megaraid.h
@@ -381,7 +381,7 @@ typedef struct {
u8 battery_status; /*
* BIT 0: battery module missing
* BIT 1: VBAD
- * BIT 2: temprature high
+ * BIT 2: temperature high
* BIT 3: battery pack missing
* BIT 4,5:
* 00 - charge complete
diff --git a/drivers/scsi/megaraid/mbox_defs.h b/drivers/scsi/megaraid/mbox_defs.h
index b25b747..ce2487a 100644
--- a/drivers/scsi/megaraid/mbox_defs.h
+++ b/drivers/scsi/megaraid/mbox_defs.h
@@ -497,7 +497,7 @@ typedef struct {
* @inserted_drive : channel:Id of inserted drive
* @battery_status : bit 0: battery module missing
* bit 1: VBAD
- * bit 2: temprature high
+ * bit 2: temperature high
* bit 3: battery pack missing
* bit 4,5:
* 00 - charge complete
diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c
index 234f0b7..7f97796 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.c
+++ b/drivers/scsi/megaraid/megaraid_mbox.c
@@ -335,12 +335,17 @@ static struct device_attribute *megaraid_sdev_attrs[] = {
* megaraid_change_queue_depth - Change the device's queue depth
* @sdev: scsi device struct
* @qdepth: depth to set
+ * @reason: calling context
*
* Return value:
* actual depth set
*/
-static int megaraid_change_queue_depth(struct scsi_device *sdev, int qdepth)
+static int megaraid_change_queue_depth(struct scsi_device *sdev, int qdepth,
+ int reason)
{
+ if (reason != SCSI_QDEPTH_DEFAULT)
+ return -EOPNOTSUPP;
+
if (qdepth > MBOX_MAX_SCSI_CMDS)
qdepth = MBOX_MAX_SCSI_CMDS;
scsi_adjust_queue_depth(sdev, 0, qdepth);
@@ -2704,7 +2709,7 @@ megaraid_reset_handler(struct scsi_cmnd *scp)
}
else {
con_log(CL_ANN, (KERN_NOTICE
- "megaraid mbox: reset sequence completed sucessfully\n"));
+ "megaraid mbox: reset sequence completed successfully\n"));
}
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
index a39addc..134c63e 100644
--- a/drivers/scsi/megaraid/megaraid_sas.c
+++ b/drivers/scsi/megaraid/megaraid_sas.c
@@ -10,7 +10,7 @@
* 2 of the License, or (at your option) any later version.
*
* FILE : megaraid_sas.c
- * Version : v00.00.04.01-rc1
+ * Version : v00.00.04.12-rc1
*
* Authors:
* (email-id : megaraidlinux@lsi.com)
@@ -40,6 +40,7 @@
#include <linux/compat.h>
#include <linux/blkdev.h>
#include <linux/mutex.h>
+#include <linux/poll.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -75,6 +76,10 @@ static struct pci_device_id megasas_pci_table[] = {
/* gen2*/
{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS0079GEN2)},
/* gen2*/
+ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS0073SKINNY)},
+ /* skinny*/
+ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS0071SKINNY)},
+ /* skinny*/
{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_VERDE_ZCR)},
/* xscale IOP, vega */
{PCI_DEVICE(PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_PERC5)},
@@ -89,8 +94,14 @@ static struct megasas_mgmt_info megasas_mgmt_info;
static struct fasync_struct *megasas_async_queue;
static DEFINE_MUTEX(megasas_async_queue_mutex);
+static int megasas_poll_wait_aen;
+static DECLARE_WAIT_QUEUE_HEAD(megasas_poll_wait);
+static u32 support_poll_for_event;
static u32 megasas_dbg_lvl;
+/* define lock for aen poll */
+spinlock_t poll_aen_lock;
+
static void
megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
u8 alt_status);
@@ -215,7 +226,10 @@ megasas_clear_intr_xscale(struct megasas_register_set __iomem * regs)
* @regs : MFI register set
*/
static inline void
-megasas_fire_cmd_xscale(dma_addr_t frame_phys_addr,u32 frame_count, struct megasas_register_set __iomem *regs)
+megasas_fire_cmd_xscale(struct megasas_instance *instance,
+ dma_addr_t frame_phys_addr,
+ u32 frame_count,
+ struct megasas_register_set __iomem *regs)
{
writel((frame_phys_addr >> 3)|(frame_count),
&(regs)->inbound_queue_port);
@@ -312,7 +326,10 @@ megasas_clear_intr_ppc(struct megasas_register_set __iomem * regs)
* @regs : MFI register set
*/
static inline void
-megasas_fire_cmd_ppc(dma_addr_t frame_phys_addr, u32 frame_count, struct megasas_register_set __iomem *regs)
+megasas_fire_cmd_ppc(struct megasas_instance *instance,
+ dma_addr_t frame_phys_addr,
+ u32 frame_count,
+ struct megasas_register_set __iomem *regs)
{
writel((frame_phys_addr | (frame_count<<1))|1,
&(regs)->inbound_queue_port);
@@ -328,6 +345,104 @@ static struct megasas_instance_template megasas_instance_template_ppc = {
};
/**
+ * megasas_enable_intr_skinny - Enables interrupts
+ * @regs: MFI register set
+ */
+static inline void
+megasas_enable_intr_skinny(struct megasas_register_set __iomem *regs)
+{
+ writel(0xFFFFFFFF, &(regs)->outbound_intr_mask);
+
+ writel(~MFI_SKINNY_ENABLE_INTERRUPT_MASK, &(regs)->outbound_intr_mask);
+
+ /* Dummy readl to force pci flush */
+ readl(&regs->outbound_intr_mask);
+}
+
+/**
+ * megasas_disable_intr_skinny - Disables interrupt
+ * @regs: MFI register set
+ */
+static inline void
+megasas_disable_intr_skinny(struct megasas_register_set __iomem *regs)
+{
+ u32 mask = 0xFFFFFFFF;
+ writel(mask, &regs->outbound_intr_mask);
+ /* Dummy readl to force pci flush */
+ readl(&regs->outbound_intr_mask);
+}
+
+/**
+ * megasas_read_fw_status_reg_skinny - returns the current FW status value
+ * @regs: MFI register set
+ */
+static u32
+megasas_read_fw_status_reg_skinny(struct megasas_register_set __iomem *regs)
+{
+ return readl(&(regs)->outbound_scratch_pad);
+}
+
+/**
+ * megasas_clear_interrupt_skinny - Check & clear interrupt
+ * @regs: MFI register set
+ */
+static int
+megasas_clear_intr_skinny(struct megasas_register_set __iomem *regs)
+{
+ u32 status;
+ /*
+ * Check if it is our interrupt
+ */
+ status = readl(&regs->outbound_intr_status);
+
+ if (!(status & MFI_SKINNY_ENABLE_INTERRUPT_MASK)) {
+ return 1;
+ }
+
+ /*
+ * Clear the interrupt by writing back the same value
+ */
+ writel(status, &regs->outbound_intr_status);
+
+ /*
+ * dummy read to flush PCI
+ */
+ readl(&regs->outbound_intr_status);
+
+ return 0;
+}
+
+/**
+ * megasas_fire_cmd_skinny - Sends command to the FW
+ * @frame_phys_addr : Physical address of cmd
+ * @frame_count : Number of frames for the command
+ * @regs : MFI register set
+ */
+static inline void
+megasas_fire_cmd_skinny(struct megasas_instance *instance,
+ dma_addr_t frame_phys_addr,
+ u32 frame_count,
+ struct megasas_register_set __iomem *regs)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&instance->fire_lock, flags);
+ writel(0, &(regs)->inbound_high_queue_port);
+ writel((frame_phys_addr | (frame_count<<1))|1,
+ &(regs)->inbound_low_queue_port);
+ spin_unlock_irqrestore(&instance->fire_lock, flags);
+}
+
+static struct megasas_instance_template megasas_instance_template_skinny = {
+
+ .fire_cmd = megasas_fire_cmd_skinny,
+ .enable_intr = megasas_enable_intr_skinny,
+ .disable_intr = megasas_disable_intr_skinny,
+ .clear_intr = megasas_clear_intr_skinny,
+ .read_fw_status_reg = megasas_read_fw_status_reg_skinny,
+};
+
+
+/**
* The following functions are defined for gen2 (deviceid : 0x78 0x79)
* controllers
*/
@@ -404,7 +519,9 @@ megasas_clear_intr_gen2(struct megasas_register_set __iomem *regs)
* @regs : MFI register set
*/
static inline void
-megasas_fire_cmd_gen2(dma_addr_t frame_phys_addr, u32 frame_count,
+megasas_fire_cmd_gen2(struct megasas_instance *instance,
+ dma_addr_t frame_phys_addr,
+ u32 frame_count,
struct megasas_register_set __iomem *regs)
{
writel((frame_phys_addr | (frame_count<<1))|1,
@@ -446,7 +563,8 @@ megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
/*
* Issue the frame using inbound queue port
*/
- instance->instancet->fire_cmd(cmd->frame_phys_addr ,0,instance->reg_set);
+ instance->instancet->fire_cmd(instance,
+ cmd->frame_phys_addr, 0, instance->reg_set);
/*
* Wait for cmd_status to change
@@ -477,7 +595,8 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
{
cmd->cmd_status = ENODATA;
- instance->instancet->fire_cmd(cmd->frame_phys_addr ,0,instance->reg_set);
+ instance->instancet->fire_cmd(instance,
+ cmd->frame_phys_addr, 0, instance->reg_set);
wait_event_timeout(instance->int_cmd_wait_q, (cmd->cmd_status != ENODATA),
MEGASAS_INTERNAL_CMD_WAIT_TIME*HZ);
@@ -522,7 +641,8 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
cmd->sync_cmd = 1;
cmd->cmd_status = 0xFF;
- instance->instancet->fire_cmd(cmd->frame_phys_addr ,0,instance->reg_set);
+ instance->instancet->fire_cmd(instance,
+ cmd->frame_phys_addr, 0, instance->reg_set);
/*
* Wait for this cmd to complete
@@ -592,6 +712,35 @@ megasas_make_sgl64(struct megasas_instance *instance, struct scsi_cmnd *scp,
return sge_count;
}
+/**
+ * megasas_make_sgl_skinny - Prepares IEEE SGL
+ * @instance: Adapter soft state
+ * @scp: SCSI command from the mid-layer
+ * @mfi_sgl: SGL to be filled in
+ *
+ * If successful, this function returns the number of SG elements. Otherwise,
+ * it returnes -1.
+ */
+static int
+megasas_make_sgl_skinny(struct megasas_instance *instance,
+ struct scsi_cmnd *scp, union megasas_sgl *mfi_sgl)
+{
+ int i;
+ int sge_count;
+ struct scatterlist *os_sgl;
+
+ sge_count = scsi_dma_map(scp);
+
+ if (sge_count) {
+ scsi_for_each_sg(scp, os_sgl, sge_count, i) {
+ mfi_sgl->sge_skinny[i].length = sg_dma_len(os_sgl);
+ mfi_sgl->sge_skinny[i].phys_addr =
+ sg_dma_address(os_sgl);
+ }
+ }
+ return sge_count;
+}
+
/**
* megasas_get_frame_count - Computes the number of frames
* @frame_type : type of frame- io or pthru frame
@@ -600,7 +749,8 @@ megasas_make_sgl64(struct megasas_instance *instance, struct scsi_cmnd *scp,
* Returns the number of frames required for numnber of sge's (sge_count)
*/
-static u32 megasas_get_frame_count(u8 sge_count, u8 frame_type)
+static u32 megasas_get_frame_count(struct megasas_instance *instance,
+ u8 sge_count, u8 frame_type)
{
int num_cnt;
int sge_bytes;
@@ -610,6 +760,10 @@ static u32 megasas_get_frame_count(u8 sge_count, u8 frame_type)
sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
sizeof(struct megasas_sge32);
+ if (instance->flag_ieee) {
+ sge_sz = sizeof(struct megasas_sge_skinny);
+ }
+
/*
* Main frame can contain 2 SGEs for 64-bit SGLs and
* 3 SGEs for 32-bit SGLs for ldio &
@@ -617,12 +771,16 @@ static u32 megasas_get_frame_count(u8 sge_count, u8 frame_type)
* 2 SGEs for 32-bit SGLs for pthru frame
*/
if (unlikely(frame_type == PTHRU_FRAME)) {
- if (IS_DMA64)
+ if (instance->flag_ieee == 1) {
+ num_cnt = sge_count - 1;
+ } else if (IS_DMA64)
num_cnt = sge_count - 1;
else
num_cnt = sge_count - 2;
} else {
- if (IS_DMA64)
+ if (instance->flag_ieee == 1) {
+ num_cnt = sge_count - 1;
+ } else if (IS_DMA64)
num_cnt = sge_count - 2;
else
num_cnt = sge_count - 3;
@@ -671,6 +829,10 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
else if (scp->sc_data_direction == PCI_DMA_NONE)
flags = MFI_FRAME_DIR_NONE;
+ if (instance->flag_ieee == 1) {
+ flags |= MFI_FRAME_IEEE;
+ }
+
/*
* Prepare the DCDB frame
*/
@@ -687,9 +849,24 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
memcpy(pthru->cdb, scp->cmnd, scp->cmd_len);
/*
+ * If the command is for the tape device, set the
+ * pthru timeout to the os layer timeout value.
+ */
+ if (scp->device->type == TYPE_TAPE) {
+ if ((scp->request->timeout / HZ) > 0xFFFF)
+ pthru->timeout = 0xFFFF;
+ else
+ pthru->timeout = scp->request->timeout / HZ;
+ }
+
+ /*
* Construct SGL
*/
- if (IS_DMA64) {
+ if (instance->flag_ieee == 1) {
+ pthru->flags |= MFI_FRAME_SGL64;
+ pthru->sge_count = megasas_make_sgl_skinny(instance, scp,
+ &pthru->sgl);
+ } else if (IS_DMA64) {
pthru->flags |= MFI_FRAME_SGL64;
pthru->sge_count = megasas_make_sgl64(instance, scp,
&pthru->sgl);
@@ -708,7 +885,7 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
* Compute the total number of frames this command consumes. FW uses
* this number to pull sufficient number of frames from host memory.
*/
- cmd->frame_count = megasas_get_frame_count(pthru->sge_count,
+ cmd->frame_count = megasas_get_frame_count(instance, pthru->sge_count,
PTHRU_FRAME);
return cmd->frame_count;
@@ -739,6 +916,10 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
else if (scp->sc_data_direction == PCI_DMA_FROMDEVICE)
flags = MFI_FRAME_DIR_READ;
+ if (instance->flag_ieee == 1) {
+ flags |= MFI_FRAME_IEEE;
+ }
+
/*
* Prepare the Logical IO frame: 2nd bit is zero for all read cmds
*/
@@ -809,7 +990,11 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
/*
* Construct SGL
*/
- if (IS_DMA64) {
+ if (instance->flag_ieee) {
+ ldio->flags |= MFI_FRAME_SGL64;
+ ldio->sge_count = megasas_make_sgl_skinny(instance, scp,
+ &ldio->sgl);
+ } else if (IS_DMA64) {
ldio->flags |= MFI_FRAME_SGL64;
ldio->sge_count = megasas_make_sgl64(instance, scp, &ldio->sgl);
} else
@@ -826,7 +1011,8 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
* Compute the total number of frames this command consumes. FW uses
* this number to pull sufficient number of frames from host memory.
*/
- cmd->frame_count = megasas_get_frame_count(ldio->sge_count, IO_FRAME);
+ cmd->frame_count = megasas_get_frame_count(instance,
+ ldio->sge_count, IO_FRAME);
return cmd->frame_count;
}
@@ -983,7 +1169,8 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
*/
atomic_inc(&instance->fw_outstanding);
- instance->instancet->fire_cmd(cmd->frame_phys_addr ,cmd->frame_count-1,instance->reg_set);
+ instance->instancet->fire_cmd(instance, cmd->frame_phys_addr,
+ cmd->frame_count-1, instance->reg_set);
/*
* Check if we have pend cmds to be completed
*/
@@ -1000,24 +1187,76 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
return 0;
}
+static struct megasas_instance *megasas_lookup_instance(u16 host_no)
+{
+ int i;
+
+ for (i = 0; i < megasas_mgmt_info.max_index; i++) {
+
+ if ((megasas_mgmt_info.instance[i]) &&
+ (megasas_mgmt_info.instance[i]->host->host_no == host_no))
+ return megasas_mgmt_info.instance[i];
+ }
+
+ return NULL;
+}
+
static int megasas_slave_configure(struct scsi_device *sdev)
{
+ u16 pd_index = 0;
+ struct megasas_instance *instance ;
+
+ instance = megasas_lookup_instance(sdev->host->host_no);
+
/*
- * Don't export physical disk devices to the disk driver.
- *
- * FIXME: Currently we don't export them to the midlayer at all.
- * That will be fixed once LSI engineers have audited the
- * firmware for possible issues.
- */
- if (sdev->channel < MEGASAS_MAX_PD_CHANNELS && sdev->type == TYPE_DISK)
+ * Don't export physical disk devices to the disk driver.
+ *
+ * FIXME: Currently we don't export them to the midlayer at all.
+ * That will be fixed once LSI engineers have audited the
+ * firmware for possible issues.
+ */
+ if (sdev->channel < MEGASAS_MAX_PD_CHANNELS &&
+ sdev->type == TYPE_DISK) {
+ pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
+ sdev->id;
+ if (instance->pd_list[pd_index].driveState ==
+ MR_PD_STATE_SYSTEM) {
+ blk_queue_rq_timeout(sdev->request_queue,
+ MEGASAS_DEFAULT_CMD_TIMEOUT * HZ);
+ return 0;
+ }
return -ENXIO;
+ }
/*
- * The RAID firmware may require extended timeouts.
- */
- if (sdev->channel >= MEGASAS_MAX_PD_CHANNELS)
- blk_queue_rq_timeout(sdev->request_queue,
- MEGASAS_DEFAULT_CMD_TIMEOUT * HZ);
+ * The RAID firmware may require extended timeouts.
+ */
+ blk_queue_rq_timeout(sdev->request_queue,
+ MEGASAS_DEFAULT_CMD_TIMEOUT * HZ);
+ return 0;
+}
+
+static int megasas_slave_alloc(struct scsi_device *sdev)
+{
+ u16 pd_index = 0;
+ struct megasas_instance *instance ;
+ instance = megasas_lookup_instance(sdev->host->host_no);
+ if ((sdev->channel < MEGASAS_MAX_PD_CHANNELS) &&
+ (sdev->type == TYPE_DISK)) {
+ /*
+ * Open the OS scan to the SYSTEM PD
+ */
+ pd_index =
+ (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
+ sdev->id;
+ if ((instance->pd_list[pd_index].driveState ==
+ MR_PD_STATE_SYSTEM) &&
+ (instance->pd_list[pd_index].driveType ==
+ TYPE_DISK)) {
+ return 0;
+ }
+ return -ENXIO;
+ }
return 0;
}
@@ -1072,7 +1311,14 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr)
spin_lock_irqsave(instance->host->host_lock, flags);
instance->flag &= ~MEGASAS_FW_BUSY;
- instance->host->can_queue =
+ if ((instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+ (instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+ instance->host->can_queue =
+ instance->max_fw_cmds - MEGASAS_SKINNY_INT_CMDS;
+ } else
+ instance->host->can_queue =
instance->max_fw_cmds - MEGASAS_INT_CMDS;
spin_unlock_irqrestore(instance->host->host_lock, flags);
@@ -1117,8 +1363,16 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
* Send signal to FW to stop processing any pending cmds.
* The controller will be taken offline by the OS now.
*/
- writel(MFI_STOP_ADP,
+ if ((instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+ (instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+ writel(MFI_STOP_ADP,
+ &instance->reg_set->reserved_0[0]);
+ } else {
+ writel(MFI_STOP_ADP,
&instance->reg_set->inbound_doorbell);
+ }
megasas_dump_pending_frames(instance);
instance->hw_crit_error = 1;
return FAILED;
@@ -1266,6 +1520,8 @@ megasas_bios_param(struct scsi_device *sdev, struct block_device *bdev,
return 0;
}
+static void megasas_aen_polling(struct work_struct *work);
+
/**
* megasas_service_aen - Processes an event notification
* @instance: Adapter soft state
@@ -1281,16 +1537,36 @@ megasas_bios_param(struct scsi_device *sdev, struct block_device *bdev,
static void
megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd)
{
+ unsigned long flags;
/*
* Don't signal app if it is just an aborted previously registered aen
*/
- if (!cmd->abort_aen)
+ if ((!cmd->abort_aen) && (instance->unload == 0)) {
+ spin_lock_irqsave(&poll_aen_lock, flags);
+ megasas_poll_wait_aen = 1;
+ spin_unlock_irqrestore(&poll_aen_lock, flags);
+ wake_up(&megasas_poll_wait);
kill_fasync(&megasas_async_queue, SIGIO, POLL_IN);
+ }
else
cmd->abort_aen = 0;
instance->aen_cmd = NULL;
megasas_return_cmd(instance, cmd);
+
+ if (instance->unload == 0) {
+ struct megasas_aen_event *ev;
+ ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+ if (!ev) {
+ printk(KERN_ERR "megasas_service_aen: out of memory\n");
+ } else {
+ ev->instance = instance;
+ instance->ev = ev;
+ INIT_WORK(&ev->hotplug_work, megasas_aen_polling);
+ schedule_delayed_work(
+ (struct delayed_work *)&ev->hotplug_work, 0);
+ }
+ }
}
/*
@@ -1302,6 +1578,7 @@ static struct scsi_host_template megasas_template = {
.name = "LSI SAS based MegaRAID driver",
.proc_name = "megaraid_sas",
.slave_configure = megasas_slave_configure,
+ .slave_alloc = megasas_slave_alloc,
.queuecommand = megasas_queue_command,
.eh_device_reset_handler = megasas_reset_device,
.eh_bus_reset_handler = megasas_reset_bus_host,
@@ -1370,6 +1647,7 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
{
int exception = 0;
struct megasas_header *hdr = &cmd->frame->hdr;
+ unsigned long flags;
if (cmd->scmd)
cmd->scmd->SCp.ptr = NULL;
@@ -1459,6 +1737,12 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
case MFI_CMD_SMP:
case MFI_CMD_STP:
case MFI_CMD_DCMD:
+ if (cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_GET_INFO ||
+ cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_GET) {
+ spin_lock_irqsave(&poll_aen_lock, flags);
+ megasas_poll_wait_aen = 0;
+ spin_unlock_irqrestore(&poll_aen_lock, flags);
+ }
/*
* See if got an event notification
@@ -1536,6 +1820,7 @@ megasas_transition_to_ready(struct megasas_instance* instance)
u8 max_wait;
u32 fw_state;
u32 cur_state;
+ u32 abs_state, curr_abs_state;
fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK;
@@ -1545,6 +1830,9 @@ megasas_transition_to_ready(struct megasas_instance* instance)
while (fw_state != MFI_STATE_READY) {
+ abs_state =
+ instance->instancet->read_fw_status_reg(instance->reg_set);
+
switch (fw_state) {
case MFI_STATE_FAULT:
@@ -1556,18 +1844,36 @@ megasas_transition_to_ready(struct megasas_instance* instance)
/*
* Set the CLR bit in inbound doorbell
*/
- writel(MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
- &instance->reg_set->inbound_doorbell);
+ if ((instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+ (instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+
+ writel(
+ MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
+ &instance->reg_set->reserved_0[0]);
+ } else {
+ writel(
+ MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
+ &instance->reg_set->inbound_doorbell);
+ }
- max_wait = 2;
+ max_wait = MEGASAS_RESET_WAIT_TIME;
cur_state = MFI_STATE_WAIT_HANDSHAKE;
break;
case MFI_STATE_BOOT_MESSAGE_PENDING:
- writel(MFI_INIT_HOTPLUG,
- &instance->reg_set->inbound_doorbell);
+ if ((instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+ (instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+ writel(MFI_INIT_HOTPLUG,
+ &instance->reg_set->reserved_0[0]);
+ } else
+ writel(MFI_INIT_HOTPLUG,
+ &instance->reg_set->inbound_doorbell);
- max_wait = 10;
+ max_wait = MEGASAS_RESET_WAIT_TIME;
cur_state = MFI_STATE_BOOT_MESSAGE_PENDING;
break;
@@ -1576,9 +1882,17 @@ megasas_transition_to_ready(struct megasas_instance* instance)
* Bring it to READY state; assuming max wait 10 secs
*/
instance->instancet->disable_intr(instance->reg_set);
- writel(MFI_RESET_FLAGS, &instance->reg_set->inbound_doorbell);
+ if ((instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+ (instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+ writel(MFI_RESET_FLAGS,
+ &instance->reg_set->reserved_0[0]);
+ } else
+ writel(MFI_RESET_FLAGS,
+ &instance->reg_set->inbound_doorbell);
- max_wait = 60;
+ max_wait = MEGASAS_RESET_WAIT_TIME;
cur_state = MFI_STATE_OPERATIONAL;
break;
@@ -1586,32 +1900,32 @@ megasas_transition_to_ready(struct megasas_instance* instance)
/*
* This state should not last for more than 2 seconds
*/
- max_wait = 2;
+ max_wait = MEGASAS_RESET_WAIT_TIME;
cur_state = MFI_STATE_UNDEFINED;
break;
case MFI_STATE_BB_INIT:
- max_wait = 2;
+ max_wait = MEGASAS_RESET_WAIT_TIME;
cur_state = MFI_STATE_BB_INIT;
break;
case MFI_STATE_FW_INIT:
- max_wait = 20;
+ max_wait = MEGASAS_RESET_WAIT_TIME;
cur_state = MFI_STATE_FW_INIT;
break;
case MFI_STATE_FW_INIT_2:
- max_wait = 20;
+ max_wait = MEGASAS_RESET_WAIT_TIME;
cur_state = MFI_STATE_FW_INIT_2;
break;
case MFI_STATE_DEVICE_SCAN:
- max_wait = 20;
+ max_wait = MEGASAS_RESET_WAIT_TIME;
cur_state = MFI_STATE_DEVICE_SCAN;
break;
case MFI_STATE_FLUSH_CACHE:
- max_wait = 20;
+ max_wait = MEGASAS_RESET_WAIT_TIME;
cur_state = MFI_STATE_FLUSH_CACHE;
break;
@@ -1627,8 +1941,10 @@ megasas_transition_to_ready(struct megasas_instance* instance)
for (i = 0; i < (max_wait * 1000); i++) {
fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) &
MFI_STATE_MASK ;
+ curr_abs_state =
+ instance->instancet->read_fw_status_reg(instance->reg_set);
- if (fw_state == cur_state) {
+ if (abs_state == curr_abs_state) {
msleep(1);
} else
break;
@@ -1637,7 +1953,7 @@ megasas_transition_to_ready(struct megasas_instance* instance)
/*
* Return error if fw_state hasn't changed after max_wait
*/
- if (fw_state == cur_state) {
+ if (curr_abs_state == abs_state) {
printk(KERN_DEBUG "FW state [%d] hasn't changed "
"in %d secs\n", fw_state, max_wait);
return -ENODEV;
@@ -1715,6 +2031,10 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
sizeof(struct megasas_sge32);
+ if (instance->flag_ieee) {
+ sge_sz = sizeof(struct megasas_sge_skinny);
+ }
+
/*
* Calculated the number of 64byte frames required for SGL
*/
@@ -1777,6 +2097,7 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
}
cmd->frame->io.context = cmd->index;
+ cmd->frame->io.pad_0 = 0;
}
return 0;
@@ -1882,6 +2203,97 @@ static int megasas_alloc_cmds(struct megasas_instance *instance)
return 0;
}
+/*
+ * megasas_get_pd_list_info - Returns FW's pd_list structure
+ * @instance: Adapter soft state
+ * @pd_list: pd_list structure
+ *
+ * Issues an internal command (DCMD) to get the FW's controller PD
+ * list structure. This information is mainly used to find out SYSTEM
+ * supported by the FW.
+ */
+static int
+megasas_get_pd_list(struct megasas_instance *instance)
+{
+ int ret = 0, pd_index = 0;
+ struct megasas_cmd *cmd;
+ struct megasas_dcmd_frame *dcmd;
+ struct MR_PD_LIST *ci;
+ struct MR_PD_ADDRESS *pd_addr;
+ dma_addr_t ci_h = 0;
+
+ cmd = megasas_get_cmd(instance);
+
+ if (!cmd) {
+ printk(KERN_DEBUG "megasas (get_pd_list): Failed to get cmd\n");
+ return -ENOMEM;
+ }
+
+ dcmd = &cmd->frame->dcmd;
+
+ ci = pci_alloc_consistent(instance->pdev,
+ MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST), &ci_h);
+
+ if (!ci) {
+ printk(KERN_DEBUG "Failed to alloc mem for pd_list\n");
+ megasas_return_cmd(instance, cmd);
+ return -ENOMEM;
+ }
+
+ memset(ci, 0, sizeof(*ci));
+ memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
+
+ dcmd->mbox.b[0] = MR_PD_QUERY_TYPE_EXPOSED_TO_HOST;
+ dcmd->mbox.b[1] = 0;
+ dcmd->cmd = MFI_CMD_DCMD;
+ dcmd->cmd_status = 0xFF;
+ dcmd->sge_count = 1;
+ dcmd->flags = MFI_FRAME_DIR_READ;
+ dcmd->timeout = 0;
+ dcmd->data_xfer_len = MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST);
+ dcmd->opcode = MR_DCMD_PD_LIST_QUERY;
+ dcmd->sgl.sge32[0].phys_addr = ci_h;
+ dcmd->sgl.sge32[0].length = MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST);
+
+ if (!megasas_issue_polled(instance, cmd)) {
+ ret = 0;
+ } else {
+ ret = -1;
+ }
+
+ /*
+ * the following function will get the instance PD LIST.
+ */
+
+ pd_addr = ci->addr;
+
+ if ( ret == 0 &&
+ (ci->count <
+ (MEGASAS_MAX_PD_CHANNELS * MEGASAS_MAX_DEV_PER_CHANNEL))) {
+
+ memset(instance->pd_list, 0,
+ MEGASAS_MAX_PD * sizeof(struct megasas_pd_list));
+
+ for (pd_index = 0; pd_index < ci->count; pd_index++) {
+
+ instance->pd_list[pd_addr->deviceId].tid =
+ pd_addr->deviceId;
+ instance->pd_list[pd_addr->deviceId].driveType =
+ pd_addr->scsiDevType;
+ instance->pd_list[pd_addr->deviceId].driveState =
+ MR_PD_STATE_SYSTEM;
+ pd_addr++;
+ }
+ }
+
+ pci_free_consistent(instance->pdev,
+ MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST),
+ ci, ci_h);
+ megasas_return_cmd(instance, cmd);
+
+ return ret;
+}
+
/**
* megasas_get_controller_info - Returns FW's controller structure
* @instance: Adapter soft state
@@ -2081,6 +2493,8 @@ static int megasas_init_mfi(struct megasas_instance *instance)
* Map the message registers
*/
if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1078GEN2) ||
+ (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
+ (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0079GEN2)) {
instance->base_addr = pci_resource_start(instance->pdev, 1);
} else {
@@ -2111,6 +2525,10 @@ static int megasas_init_mfi(struct megasas_instance *instance)
case PCI_DEVICE_ID_LSI_SAS0079GEN2:
instance->instancet = &megasas_instance_template_gen2;
break;
+ case PCI_DEVICE_ID_LSI_SAS0073SKINNY:
+ case PCI_DEVICE_ID_LSI_SAS0071SKINNY:
+ instance->instancet = &megasas_instance_template_skinny;
+ break;
case PCI_DEVICE_ID_LSI_SAS1064R:
case PCI_DEVICE_ID_DELL_PERC5:
default:
@@ -2166,6 +2584,10 @@ static int megasas_init_mfi(struct megasas_instance *instance)
if (megasas_issue_init_mfi(instance))
goto fail_fw_init;
+ memset(instance->pd_list, 0 ,
+ (MEGASAS_MAX_PD * sizeof(struct megasas_pd_list)));
+ megasas_get_pd_list(instance);
+
ctrl_info = kmalloc(sizeof(struct megasas_ctrl_info), GFP_KERNEL);
/*
@@ -2409,6 +2831,11 @@ megasas_register_aen(struct megasas_instance *instance, u32 seq_num,
dcmd->sgl.sge32[0].phys_addr = (u32) instance->evt_detail_h;
dcmd->sgl.sge32[0].length = sizeof(struct megasas_evt_detail);
+ if (instance->aen_cmd != NULL) {
+ megasas_return_cmd(instance, cmd);
+ return 0;
+ }
+
/*
* Store reference to the cmd used to register for AEN. When an
* application wants us to register for AEN, we have to abort this
@@ -2419,7 +2846,8 @@ megasas_register_aen(struct megasas_instance *instance, u32 seq_num,
/*
* Issue the aen registration frame
*/
- instance->instancet->fire_cmd(cmd->frame_phys_addr ,0,instance->reg_set);
+ instance->instancet->fire_cmd(instance,
+ cmd->frame_phys_addr, 0, instance->reg_set);
return 0;
}
@@ -2465,7 +2893,13 @@ static int megasas_io_attach(struct megasas_instance *instance)
*/
host->irq = instance->pdev->irq;
host->unique_id = instance->unique_id;
- host->can_queue = instance->max_fw_cmds - MEGASAS_INT_CMDS;
+ if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+ (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+ host->can_queue =
+ instance->max_fw_cmds - MEGASAS_SKINNY_INT_CMDS;
+ } else
+ host->can_queue =
+ instance->max_fw_cmds - MEGASAS_INT_CMDS;
host->this_id = instance->init_id;
host->sg_tablesize = instance->max_num_sge;
host->max_sectors = instance->max_sectors_per_req;
@@ -2572,6 +3006,9 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
*instance->producer = 0;
*instance->consumer = 0;
+ megasas_poll_wait_aen = 0;
+ instance->flag_ieee = 0;
+ instance->ev = NULL;
instance->evt_detail = pci_alloc_consistent(pdev,
sizeof(struct
@@ -2595,10 +3032,11 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
init_waitqueue_head(&instance->abort_cmd_wait_q);
spin_lock_init(&instance->cmd_pool_lock);
+ spin_lock_init(&instance->fire_lock);
spin_lock_init(&instance->completion_lock);
+ spin_lock_init(&poll_aen_lock);
mutex_init(&instance->aen_mutex);
- sema_init(&instance->ioctl_sem, MEGASAS_INT_CMDS);
/*
* Initialize PCI related and misc parameters
@@ -2608,8 +3046,16 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
instance->unique_id = pdev->bus->number << 8 | pdev->devfn;
instance->init_id = MEGASAS_DEFAULT_INIT_ID;
+ if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+ (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+ instance->flag_ieee = 1;
+ sema_init(&instance->ioctl_sem, MEGASAS_SKINNY_INT_CMDS);
+ } else
+ sema_init(&instance->ioctl_sem, MEGASAS_INT_CMDS);
+
megasas_dbg_lvl = 0;
instance->flag = 0;
+ instance->unload = 1;
instance->last_time = 0;
/*
@@ -2655,6 +3101,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
if (megasas_io_attach(instance))
goto fail_io_attach;
+ instance->unload = 0;
return 0;
fail_start_aen:
@@ -2778,12 +3225,23 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state)
instance = pci_get_drvdata(pdev);
host = instance->host;
+ instance->unload = 1;
if (poll_mode_io)
del_timer_sync(&instance->io_completion_timer);
megasas_flush_cache(instance);
megasas_shutdown_controller(instance, MR_DCMD_HIBERNATE_SHUTDOWN);
+
+ /* cancel the delayed work if this work still in queue */
+ if (instance->ev != NULL) {
+ struct megasas_aen_event *ev = instance->ev;
+ cancel_delayed_work(
+ (struct delayed_work *)&ev->hotplug_work);
+ flush_scheduled_work();
+ instance->ev = NULL;
+ }
+
tasklet_kill(&instance->isr_tasklet);
pci_set_drvdata(instance->pdev, instance);
@@ -2873,6 +3331,8 @@ megasas_resume(struct pci_dev *pdev)
megasas_start_timer(instance, &instance->io_completion_timer,
megasas_io_completion_timer,
MEGASAS_COMPLETION_TIMER_INTERVAL);
+ instance->unload = 0;
+
return 0;
fail_irq:
@@ -2913,6 +3373,7 @@ static void __devexit megasas_detach_one(struct pci_dev *pdev)
struct megasas_instance *instance;
instance = pci_get_drvdata(pdev);
+ instance->unload = 1;
host = instance->host;
if (poll_mode_io)
@@ -2921,6 +3382,16 @@ static void __devexit megasas_detach_one(struct pci_dev *pdev)
scsi_remove_host(instance->host);
megasas_flush_cache(instance);
megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN);
+
+ /* cancel the delayed work if this work still in queue*/
+ if (instance->ev != NULL) {
+ struct megasas_aen_event *ev = instance->ev;
+ cancel_delayed_work(
+ (struct delayed_work *)&ev->hotplug_work);
+ flush_scheduled_work();
+ instance->ev = NULL;
+ }
+
tasklet_kill(&instance->isr_tasklet);
/*
@@ -2969,6 +3440,7 @@ static void __devexit megasas_detach_one(struct pci_dev *pdev)
static void megasas_shutdown(struct pci_dev *pdev)
{
struct megasas_instance *instance = pci_get_drvdata(pdev);
+ instance->unload = 1;
megasas_flush_cache(instance);
megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN);
}
@@ -3016,6 +3488,23 @@ static int megasas_mgmt_fasync(int fd, struct file *filep, int mode)
}
/**
+ * megasas_mgmt_poll - char node "poll" entry point
+ * */
+static unsigned int megasas_mgmt_poll(struct file *file, poll_table *wait)
+{
+ unsigned int mask;
+ unsigned long flags;
+ poll_wait(file, &megasas_poll_wait, wait);
+ spin_lock_irqsave(&poll_aen_lock, flags);
+ if (megasas_poll_wait_aen)
+ mask = (POLLIN | POLLRDNORM);
+ else
+ mask = 0;
+ spin_unlock_irqrestore(&poll_aen_lock, flags);
+ return mask;
+}
+
+/**
* megasas_mgmt_fw_ioctl - Issues management ioctls to FW
* @instance: Adapter soft state
* @argp: User's ioctl packet
@@ -3032,7 +3521,7 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
int error = 0, i;
void *sense = NULL;
dma_addr_t sense_handle;
- u32 *sense_ptr;
+ unsigned long *sense_ptr;
memset(kbuff_arr, 0, sizeof(kbuff_arr));
@@ -3056,6 +3545,7 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
*/
memcpy(cmd->frame, ioc->frame.raw, 2 * MEGAMFI_FRAME_SIZE);
cmd->frame->hdr.context = cmd->index;
+ cmd->frame->hdr.pad_0 = 0;
/*
* The management interface between applications and the fw uses
@@ -3109,7 +3599,7 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
}
sense_ptr =
- (u32 *) ((unsigned long)cmd->frame + ioc->sense_off);
+ (unsigned long *) ((unsigned long)cmd->frame + ioc->sense_off);
*sense_ptr = sense_handle;
}
@@ -3140,8 +3630,8 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
* sense_ptr points to the location that has the user
* sense buffer address
*/
- sense_ptr = (u32 *) ((unsigned long)ioc->frame.raw +
- ioc->sense_off);
+ sense_ptr = (unsigned long *) ((unsigned long)ioc->frame.raw +
+ ioc->sense_off);
if (copy_to_user((void __user *)((unsigned long)(*sense_ptr)),
sense, ioc->sense_len)) {
@@ -3177,20 +3667,6 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
return error;
}
-static struct megasas_instance *megasas_lookup_instance(u16 host_no)
-{
- int i;
-
- for (i = 0; i < megasas_mgmt_info.max_index; i++) {
-
- if ((megasas_mgmt_info.instance[i]) &&
- (megasas_mgmt_info.instance[i]->host->host_no == host_no))
- return megasas_mgmt_info.instance[i];
- }
-
- return NULL;
-}
-
static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
{
struct megasas_iocpacket __user *user_ioc =
@@ -3214,6 +3690,17 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
goto out_kfree_ioc;
}
+ if (instance->hw_crit_error == 1) {
+ printk(KERN_DEBUG "Controller in Crit ERROR\n");
+ error = -ENODEV;
+ goto out_kfree_ioc;
+ }
+
+ if (instance->unload == 1) {
+ error = -ENODEV;
+ goto out_kfree_ioc;
+ }
+
/*
* We will allow only MEGASAS_INT_CMDS number of parallel ioctl cmds
*/
@@ -3249,6 +3736,14 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg)
if (!instance)
return -ENODEV;
+ if (instance->hw_crit_error == 1) {
+ error = -ENODEV;
+ }
+
+ if (instance->unload == 1) {
+ return -ENODEV;
+ }
+
mutex_lock(&instance->aen_mutex);
error = megasas_register_aen(instance, aen.seq_num,
aen.class_locale_word);
@@ -3337,6 +3832,7 @@ static const struct file_operations megasas_mgmt_fops = {
.open = megasas_mgmt_open,
.fasync = megasas_mgmt_fasync,
.unlocked_ioctl = megasas_mgmt_ioctl,
+ .poll = megasas_mgmt_poll,
#ifdef CONFIG_COMPAT
.compat_ioctl = megasas_mgmt_compat_ioctl,
#endif
@@ -3378,6 +3874,15 @@ static DRIVER_ATTR(release_date, S_IRUGO, megasas_sysfs_show_release_date,
NULL);
static ssize_t
+megasas_sysfs_show_support_poll_for_event(struct device_driver *dd, char *buf)
+{
+ return sprintf(buf, "%u\n", support_poll_for_event);
+}
+
+static DRIVER_ATTR(support_poll_for_event, S_IRUGO,
+ megasas_sysfs_show_support_poll_for_event, NULL);
+
+static ssize_t
megasas_sysfs_show_dbg_lvl(struct device_driver *dd, char *buf)
{
return sprintf(buf, "%u\n", megasas_dbg_lvl);
@@ -3451,6 +3956,92 @@ out:
return retval;
}
+static void
+megasas_aen_polling(struct work_struct *work)
+{
+ struct megasas_aen_event *ev =
+ container_of(work, struct megasas_aen_event, hotplug_work);
+ struct megasas_instance *instance = ev->instance;
+ union megasas_evt_class_locale class_locale;
+ struct Scsi_Host *host;
+ struct scsi_device *sdev1;
+ u16 pd_index = 0;
+ int i, j, doscan = 0;
+ u32 seq_num;
+ int error;
+
+ if (!instance) {
+ printk(KERN_ERR "invalid instance!\n");
+ kfree(ev);
+ return;
+ }
+ instance->ev = NULL;
+ host = instance->host;
+ if (instance->evt_detail) {
+
+ switch (instance->evt_detail->code) {
+ case MR_EVT_PD_INSERTED:
+ case MR_EVT_PD_REMOVED:
+ case MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED:
+ doscan = 1;
+ break;
+ default:
+ doscan = 0;
+ break;
+ }
+ } else {
+ printk(KERN_ERR "invalid evt_detail!\n");
+ kfree(ev);
+ return;
+ }
+
+ if (doscan) {
+ printk(KERN_INFO "scanning ...\n");
+ megasas_get_pd_list(instance);
+ for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
+ for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
+ pd_index = i*MEGASAS_MAX_DEV_PER_CHANNEL + j;
+ sdev1 = scsi_device_lookup(host, i, j, 0);
+ if (instance->pd_list[pd_index].driveState ==
+ MR_PD_STATE_SYSTEM) {
+ if (!sdev1) {
+ scsi_add_device(host, i, j, 0);
+ }
+ if (sdev1)
+ scsi_device_put(sdev1);
+ } else {
+ if (sdev1) {
+ scsi_remove_device(sdev1);
+ scsi_device_put(sdev1);
+ }
+ }
+ }
+ }
+ }
+
+ if ( instance->aen_cmd != NULL ) {
+ kfree(ev);
+ return ;
+ }
+
+ seq_num = instance->evt_detail->seq_num + 1;
+
+ /* Register AEN with FW for latest sequence number plus 1 */
+ class_locale.members.reserved = 0;
+ class_locale.members.locale = MR_EVT_LOCALE_ALL;
+ class_locale.members.class = MR_EVT_CLASS_DEBUG;
+ mutex_lock(&instance->aen_mutex);
+ error = megasas_register_aen(instance, seq_num,
+ class_locale.word);
+ mutex_unlock(&instance->aen_mutex);
+
+ if (error)
+ printk(KERN_ERR "register aen failed error %x\n", error);
+
+ kfree(ev);
+}
+
+
static DRIVER_ATTR(poll_mode_io, S_IRUGO|S_IWUGO,
megasas_sysfs_show_poll_mode_io,
megasas_sysfs_set_poll_mode_io);
@@ -3468,6 +4059,8 @@ static int __init megasas_init(void)
printk(KERN_INFO "megasas: %s %s\n", MEGASAS_VERSION,
MEGASAS_EXT_VERSION);
+ support_poll_for_event = 2;
+
memset(&megasas_mgmt_info, 0, sizeof(megasas_mgmt_info));
/*
@@ -3500,6 +4093,12 @@ static int __init megasas_init(void)
&driver_attr_release_date);
if (rval)
goto err_dcf_rel_date;
+
+ rval = driver_create_file(&megasas_pci_driver.driver,
+ &driver_attr_support_poll_for_event);
+ if (rval)
+ goto err_dcf_support_poll_for_event;
+
rval = driver_create_file(&megasas_pci_driver.driver,
&driver_attr_dbg_lvl);
if (rval)
@@ -3516,7 +4115,12 @@ err_dcf_poll_mode_io:
&driver_attr_dbg_lvl);
err_dcf_dbg_lvl:
driver_remove_file(&megasas_pci_driver.driver,
+ &driver_attr_support_poll_for_event);
+
+err_dcf_support_poll_for_event:
+ driver_remove_file(&megasas_pci_driver.driver,
&driver_attr_release_date);
+
err_dcf_rel_date:
driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
err_dcf_attr_ver:
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index 0d03324..72b28e4 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -18,9 +18,9 @@
/*
* MegaRAID SAS Driver meta data
*/
-#define MEGASAS_VERSION "00.00.04.01"
-#define MEGASAS_RELDATE "July 24, 2008"
-#define MEGASAS_EXT_VERSION "Thu July 24 11:41:51 PST 2008"
+#define MEGASAS_VERSION "00.00.04.12-rc1"
+#define MEGASAS_RELDATE "Sep. 17, 2009"
+#define MEGASAS_EXT_VERSION "Thu Sep. 17 11:41:51 PST 2009"
/*
* Device IDs
@@ -30,6 +30,8 @@
#define PCI_DEVICE_ID_LSI_VERDE_ZCR 0x0413
#define PCI_DEVICE_ID_LSI_SAS1078GEN2 0x0078
#define PCI_DEVICE_ID_LSI_SAS0079GEN2 0x0079
+#define PCI_DEVICE_ID_LSI_SAS0073SKINNY 0x0073
+#define PCI_DEVICE_ID_LSI_SAS0071SKINNY 0x0071
/*
* =====================================
@@ -94,6 +96,7 @@
#define MFI_FRAME_DIR_WRITE 0x0008
#define MFI_FRAME_DIR_READ 0x0010
#define MFI_FRAME_DIR_BOTH 0x0018
+#define MFI_FRAME_IEEE 0x0020
/*
* Definition for cmd_status
@@ -131,6 +134,7 @@
#define MR_DCMD_CLUSTER 0x08000000
#define MR_DCMD_CLUSTER_RESET_ALL 0x08010100
#define MR_DCMD_CLUSTER_RESET_LD 0x08010200
+#define MR_DCMD_PD_LIST_QUERY 0x02010100
/*
* MFI command completion codes
@@ -251,9 +255,100 @@ enum MR_EVT_ARGS {
MR_EVT_ARGS_STR,
MR_EVT_ARGS_TIME,
MR_EVT_ARGS_ECC,
+ MR_EVT_ARGS_LD_PROP,
+ MR_EVT_ARGS_PD_SPARE,
+ MR_EVT_ARGS_PD_INDEX,
+ MR_EVT_ARGS_DIAG_PASS,
+ MR_EVT_ARGS_DIAG_FAIL,
+ MR_EVT_ARGS_PD_LBA_LBA,
+ MR_EVT_ARGS_PORT_PHY,
+ MR_EVT_ARGS_PD_MISSING,
+ MR_EVT_ARGS_PD_ADDRESS,
+ MR_EVT_ARGS_BITMAP,
+ MR_EVT_ARGS_CONNECTOR,
+ MR_EVT_ARGS_PD_PD,
+ MR_EVT_ARGS_PD_FRU,
+ MR_EVT_ARGS_PD_PATHINFO,
+ MR_EVT_ARGS_PD_POWER_STATE,
+ MR_EVT_ARGS_GENERIC,
+};
+/*
+ * define constants for device list query options
+ */
+enum MR_PD_QUERY_TYPE {
+ MR_PD_QUERY_TYPE_ALL = 0,
+ MR_PD_QUERY_TYPE_STATE = 1,
+ MR_PD_QUERY_TYPE_POWER_STATE = 2,
+ MR_PD_QUERY_TYPE_MEDIA_TYPE = 3,
+ MR_PD_QUERY_TYPE_SPEED = 4,
+ MR_PD_QUERY_TYPE_EXPOSED_TO_HOST = 5,
};
+#define MR_EVT_CFG_CLEARED 0x0004
+#define MR_EVT_LD_STATE_CHANGE 0x0051
+#define MR_EVT_PD_INSERTED 0x005b
+#define MR_EVT_PD_REMOVED 0x0070
+#define MR_EVT_LD_CREATED 0x008a
+#define MR_EVT_LD_DELETED 0x008b
+#define MR_EVT_FOREIGN_CFG_IMPORTED 0x00db
+#define MR_EVT_LD_OFFLINE 0x00fc
+#define MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED 0x0152
+#define MAX_LOGICAL_DRIVES 64
+
+enum MR_PD_STATE {
+ MR_PD_STATE_UNCONFIGURED_GOOD = 0x00,
+ MR_PD_STATE_UNCONFIGURED_BAD = 0x01,
+ MR_PD_STATE_HOT_SPARE = 0x02,
+ MR_PD_STATE_OFFLINE = 0x10,
+ MR_PD_STATE_FAILED = 0x11,
+ MR_PD_STATE_REBUILD = 0x14,
+ MR_PD_STATE_ONLINE = 0x18,
+ MR_PD_STATE_COPYBACK = 0x20,
+ MR_PD_STATE_SYSTEM = 0x40,
+ };
+
+
+ /*
+ * defines the physical drive address structure
+ */
+struct MR_PD_ADDRESS {
+ u16 deviceId;
+ u16 enclDeviceId;
+
+ union {
+ struct {
+ u8 enclIndex;
+ u8 slotNumber;
+ } mrPdAddress;
+ struct {
+ u8 enclPosition;
+ u8 enclConnectorIndex;
+ } mrEnclAddress;
+ };
+ u8 scsiDevType;
+ union {
+ u8 connectedPortBitmap;
+ u8 connectedPortNumbers;
+ };
+ u64 sasAddr[2];
+} __packed;
+
+/*
+ * defines the physical drive list structure
+ */
+struct MR_PD_LIST {
+ u32 size;
+ u32 count;
+ struct MR_PD_ADDRESS addr[1];
+} __packed;
+
+struct megasas_pd_list {
+ u16 tid;
+ u8 driveType;
+ u8 driveState;
+} __packed;
+
/*
* SAS controller properties
*/
@@ -282,7 +377,7 @@ struct megasas_ctrl_prop {
u8 expose_encl_devices;
u8 reserved[38];
-} __attribute__ ((packed));
+} __packed;
/*
* SAS controller information
@@ -525,7 +620,7 @@ struct megasas_ctrl_info {
u8 pad[0x800 - 0x6a0];
-} __attribute__ ((packed));
+} __packed;
/*
* ===============================
@@ -540,6 +635,8 @@ struct megasas_ctrl_info {
#define MEGASAS_DEFAULT_INIT_ID -1
#define MEGASAS_MAX_LUN 8
#define MEGASAS_MAX_LD 64
+#define MEGASAS_MAX_PD (MEGASAS_MAX_PD_CHANNELS * \
+ MEGASAS_MAX_DEV_PER_CHANNEL)
#define MEGASAS_DBG_LVL 1
@@ -570,6 +667,7 @@ struct megasas_ctrl_info {
* is shown below
*/
#define MEGASAS_INT_CMDS 32
+#define MEGASAS_SKINNY_INT_CMDS 5
/*
* FW can accept both 32 and 64 bit SGLs. We want to allocate 32/64 bit
@@ -584,6 +682,8 @@ struct megasas_ctrl_info {
#define MFI_REPLY_1078_MESSAGE_INTERRUPT 0x80000000
#define MFI_REPLY_GEN2_MESSAGE_INTERRUPT 0x00000001
#define MFI_GEN2_ENABLE_INTERRUPT_MASK (0x00000001 | 0x00000004)
+#define MFI_REPLY_SKINNY_MESSAGE_INTERRUPT 0x40000000
+#define MFI_SKINNY_ENABLE_INTERRUPT_MASK (0x00000001)
/*
* register set for both 1068 and 1078 controllers
@@ -644,10 +744,17 @@ struct megasas_sge64 {
} __attribute__ ((packed));
+struct megasas_sge_skinny {
+ u64 phys_addr;
+ u32 length;
+ u32 flag;
+} __packed;
+
union megasas_sgl {
struct megasas_sge32 sge32[1];
struct megasas_sge64 sge64[1];
+ struct megasas_sge_skinny sge_skinny[1];
} __attribute__ ((packed));
@@ -1061,16 +1168,10 @@ struct megasas_evt_detail {
} __attribute__ ((packed));
- struct megasas_instance_template {
- void (*fire_cmd)(dma_addr_t ,u32 ,struct megasas_register_set __iomem *);
-
- void (*enable_intr)(struct megasas_register_set __iomem *) ;
- void (*disable_intr)(struct megasas_register_set __iomem *);
-
- int (*clear_intr)(struct megasas_register_set __iomem *);
-
- u32 (*read_fw_status_reg)(struct megasas_register_set __iomem *);
- };
+struct megasas_aen_event {
+ struct work_struct hotplug_work;
+ struct megasas_instance *instance;
+};
struct megasas_instance {
@@ -1085,17 +1186,21 @@ struct megasas_instance {
unsigned long base_addr;
struct megasas_register_set __iomem *reg_set;
+ struct megasas_pd_list pd_list[MEGASAS_MAX_PD];
s8 init_id;
u16 max_num_sge;
u16 max_fw_cmds;
u32 max_sectors_per_req;
+ struct megasas_aen_event *ev;
struct megasas_cmd **cmd_list;
struct list_head cmd_pool;
spinlock_t cmd_pool_lock;
/* used to synch producer, consumer ptrs in dpc */
spinlock_t completion_lock;
+ /* used to sync fire the cmd to fw */
+ spinlock_t fire_lock;
struct dma_pool *frame_dma_pool;
struct dma_pool *sense_dma_pool;
@@ -1120,11 +1225,25 @@ struct megasas_instance {
struct tasklet_struct isr_tasklet;
u8 flag;
+ u8 unload;
+ u8 flag_ieee;
unsigned long last_time;
struct timer_list io_completion_timer;
};
+struct megasas_instance_template {
+ void (*fire_cmd)(struct megasas_instance *, dma_addr_t, \
+ u32, struct megasas_register_set __iomem *);
+
+ void (*enable_intr)(struct megasas_register_set __iomem *) ;
+ void (*disable_intr)(struct megasas_register_set __iomem *);
+
+ int (*clear_intr)(struct megasas_register_set __iomem *);
+
+ u32 (*read_fw_status_reg)(struct megasas_register_set __iomem *);
+};
+
#define MEGASAS_IS_LOGICAL(scp) \
(scp->device->channel < MEGASAS_MAX_PD_CHANNELS) ? 0 : 1
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2.h b/drivers/scsi/mpt2sas/mpi/mpi2.h
index f9f6c08..9141681 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2.h
@@ -8,7 +8,7 @@
* scatter/gather formats.
* Creation Date: June 21, 2006
*
- * mpi2.h Version: 02.00.12
+ * mpi2.h Version: 02.00.13
*
* Version History
* ---------------
@@ -52,6 +52,7 @@
* MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR and made those
* bytes reserved.
* Added RAID Accelerator functionality.
+ * 07-30-09 02.00.13 Bumped MPI2_HEADER_VERSION_UNIT.
* --------------------------------------------------------------------------
*/
@@ -77,7 +78,7 @@
#define MPI2_VERSION_02_00 (0x0200)
/* versioning for this MPI header set */
-#define MPI2_HEADER_VERSION_UNIT (0x0C)
+#define MPI2_HEADER_VERSION_UNIT (0x0D)
#define MPI2_HEADER_VERSION_DEV (0x00)
#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00)
#define MPI2_HEADER_VERSION_UNIT_SHIFT (8)
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
index ab47c46..1611c57 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
@@ -6,7 +6,7 @@
* Title: MPI Configuration messages and pages
* Creation Date: November 10, 2006
*
- * mpi2_cnfg.h Version: 02.00.11
+ * mpi2_cnfg.h Version: 02.00.12
*
* Version History
* ---------------
@@ -100,6 +100,13 @@
* Added expander reduced functionality data to SAS
* Expander Page 0.
* Added SAS PHY Page 2 and SAS PHY Page 3.
+ * 07-30-09 02.00.12 Added IO Unit Page 7.
+ * Added new device ids.
+ * Added SAS IO Unit Page 5.
+ * Added partial and slumber power management capable flags
+ * to SAS Device Page 0 Flags field.
+ * Added PhyInfo defines for power condition.
+ * Added Ethernet configuration pages.
* --------------------------------------------------------------------------
*/
@@ -182,6 +189,7 @@ typedef union _MPI2_CONFIG_EXT_PAGE_HEADER_UNION
#define MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG (0x16)
#define MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING (0x17)
#define MPI2_CONFIG_EXTPAGETYPE_SAS_PORT (0x18)
+#define MPI2_CONFIG_EXTPAGETYPE_ETHERNET (0x19)
/*****************************************************************************
@@ -268,6 +276,14 @@ typedef union _MPI2_CONFIG_EXT_PAGE_HEADER_UNION
#define MPI2_DPM_PGAD_START_ENTRY_MASK (0x0000FFFF)
+/* Ethernet PageAddress format */
+#define MPI2_ETHERNET_PGAD_FORM_MASK (0xF0000000)
+#define MPI2_ETHERNET_PGAD_FORM_IF_NUM (0x00000000)
+
+#define MPI2_ETHERNET_PGAD_IF_NUMBER_MASK (0x000000FF)
+
+
+
/****************************************************************************
* Configuration messages
****************************************************************************/
@@ -349,6 +365,15 @@ typedef struct _MPI2_CONFIG_REPLY
#define MPI2_MFGPAGE_DEVID_SAS2116_1 (0x0064)
#define MPI2_MFGPAGE_DEVID_SAS2116_2 (0x0065)
+#define MPI2_MFGPAGE_DEVID_SAS2208_1 (0x0080)
+#define MPI2_MFGPAGE_DEVID_SAS2208_2 (0x0081)
+#define MPI2_MFGPAGE_DEVID_SAS2208_3 (0x0082)
+#define MPI2_MFGPAGE_DEVID_SAS2208_4 (0x0083)
+#define MPI2_MFGPAGE_DEVID_SAS2208_5 (0x0084)
+#define MPI2_MFGPAGE_DEVID_SAS2208_6 (0x0085)
+#define MPI2_MFGPAGE_DEVID_SAS2208_7 (0x0086)
+#define MPI2_MFGPAGE_DEVID_SAS2208_8 (0x0087)
+
/* Manufacturing Page 0 */
@@ -787,6 +812,56 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_6 {
#define MPI2_IOUNITPAGE6_FLAGS_ENABLE_RAID_ACCELERATOR (0x0001)
+/* IO Unit Page 7 */
+
+typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7 {
+ MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
+ U16 Reserved1; /* 0x04 */
+ U8 PCIeWidth; /* 0x06 */
+ U8 PCIeSpeed; /* 0x07 */
+ U32 ProcessorState; /* 0x08 */
+ U32 Reserved2; /* 0x0C */
+ U16 IOCTemperature; /* 0x10 */
+ U8 IOCTemperatureUnits; /* 0x12 */
+ U8 IOCSpeed; /* 0x13 */
+ U32 Reserved3; /* 0x14 */
+} MPI2_CONFIG_PAGE_IO_UNIT_7, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_7,
+ Mpi2IOUnitPage7_t, MPI2_POINTER pMpi2IOUnitPage7_t;
+
+#define MPI2_IOUNITPAGE7_PAGEVERSION (0x00)
+
+/* defines for IO Unit Page 7 PCIeWidth field */
+#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X1 (0x01)
+#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X2 (0x02)
+#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X4 (0x04)
+#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X8 (0x08)
+
+/* defines for IO Unit Page 7 PCIeSpeed field */
+#define MPI2_IOUNITPAGE7_PCIE_SPEED_2_5_GBPS (0x00)
+#define MPI2_IOUNITPAGE7_PCIE_SPEED_5_0_GBPS (0x01)
+#define MPI2_IOUNITPAGE7_PCIE_SPEED_8_0_GBPS (0x02)
+
+/* defines for IO Unit Page 7 ProcessorState field */
+#define MPI2_IOUNITPAGE7_PSTATE_MASK_SECOND (0x0000000F)
+#define MPI2_IOUNITPAGE7_PSTATE_SHIFT_SECOND (0)
+
+#define MPI2_IOUNITPAGE7_PSTATE_NOT_PRESENT (0x00)
+#define MPI2_IOUNITPAGE7_PSTATE_DISABLED (0x01)
+#define MPI2_IOUNITPAGE7_PSTATE_ENABLED (0x02)
+
+/* defines for IO Unit Page 7 IOCTemperatureUnits field */
+#define MPI2_IOUNITPAGE7_IOC_TEMP_NOT_PRESENT (0x00)
+#define MPI2_IOUNITPAGE7_IOC_TEMP_FAHRENHEIT (0x01)
+#define MPI2_IOUNITPAGE7_IOC_TEMP_CELSIUS (0x02)
+
+/* defines for IO Unit Page 7 IOCSpeed field */
+#define MPI2_IOUNITPAGE7_IOC_SPEED_FULL (0x01)
+#define MPI2_IOUNITPAGE7_IOC_SPEED_HALF (0x02)
+#define MPI2_IOUNITPAGE7_IOC_SPEED_QUARTER (0x04)
+#define MPI2_IOUNITPAGE7_IOC_SPEED_EIGHTH (0x08)
+
+
+
/****************************************************************************
* IOC Config Pages
****************************************************************************/
@@ -1470,6 +1545,12 @@ typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_1
/* values for PhyInfo fields */
#define MPI2_SAS_PHYINFO_PHY_VACANT (0x80000000)
+
+#define MPI2_SAS_PHYINFO_PHY_POWER_CONDITION_MASK (0x18000000)
+#define MPI2_SAS_PHYINFO_PHY_POWER_ACTIVE (0x00000000)
+#define MPI2_SAS_PHYINFO_PHY_POWER_PARTIAL (0x08000000)
+#define MPI2_SAS_PHYINFO_PHY_POWER_SLUMBER (0x10000000)
+
#define MPI2_SAS_PHYINFO_CHANGED_REQ_INSIDE_ZPSDS (0x04000000)
#define MPI2_SAS_PHYINFO_INSIDE_ZPSDS_PERSISTENT (0x02000000)
#define MPI2_SAS_PHYINFO_REQ_INSIDE_ZPSDS (0x01000000)
@@ -1682,11 +1763,11 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_1
/* values for SAS IO Unit Page 1 PortFlags */
#define MPI2_SASIOUNIT1_PORT_FLAGS_AUTO_PORT_CONFIG (0x01)
-/* values for SAS IO Unit Page 2 PhyFlags */
+/* values for SAS IO Unit Page 1 PhyFlags */
#define MPI2_SASIOUNIT1_PHYFLAGS_ZONING_ENABLE (0x10)
#define MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE (0x08)
-/* values for SAS IO Unit Page 0 MaxMinLinkRate */
+/* values for SAS IO Unit Page 1 MaxMinLinkRate */
#define MPI2_SASIOUNIT1_MAX_RATE_MASK (0xF0)
#define MPI2_SASIOUNIT1_MAX_RATE_1_5 (0x80)
#define MPI2_SASIOUNIT1_MAX_RATE_3_0 (0x90)
@@ -1745,6 +1826,74 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_4
#define MPI2_SASIOUNIT4_PHY_SPINUP_GROUP_MASK (0x03)
+/* SAS IO Unit Page 5 */
+
+typedef struct _MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS {
+ U8 ControlFlags; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U16 InactivityTimerExponent; /* 0x02 */
+ U8 SATAPartialTimeout; /* 0x04 */
+ U8 Reserved2; /* 0x05 */
+ U8 SATASlumberTimeout; /* 0x06 */
+ U8 Reserved3; /* 0x07 */
+ U8 SASPartialTimeout; /* 0x08 */
+ U8 Reserved4; /* 0x09 */
+ U8 SASSlumberTimeout; /* 0x0A */
+ U8 Reserved5; /* 0x0B */
+} MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS,
+ MPI2_POINTER PTR_MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS,
+ Mpi2SasIOUnit5PhyPmSettings_t, MPI2_POINTER pMpi2SasIOUnit5PhyPmSettings_t;
+
+/* defines for ControlFlags field */
+#define MPI2_SASIOUNIT5_CONTROL_SAS_SLUMBER_ENABLE (0x08)
+#define MPI2_SASIOUNIT5_CONTROL_SAS_PARTIAL_ENABLE (0x04)
+#define MPI2_SASIOUNIT5_CONTROL_SATA_SLUMBER_ENABLE (0x02)
+#define MPI2_SASIOUNIT5_CONTROL_SATA_PARTIAL_ENABLE (0x01)
+
+/* defines for InactivityTimerExponent field */
+#define MPI2_SASIOUNIT5_ITE_MASK_SAS_SLUMBER (0x7000)
+#define MPI2_SASIOUNIT5_ITE_SHIFT_SAS_SLUMBER (12)
+#define MPI2_SASIOUNIT5_ITE_MASK_SAS_PARTIAL (0x0700)
+#define MPI2_SASIOUNIT5_ITE_SHIFT_SAS_PARTIAL (8)
+#define MPI2_SASIOUNIT5_ITE_MASK_SATA_SLUMBER (0x0070)
+#define MPI2_SASIOUNIT5_ITE_SHIFT_SATA_SLUMBER (4)
+#define MPI2_SASIOUNIT5_ITE_MASK_SATA_PARTIAL (0x0007)
+#define MPI2_SASIOUNIT5_ITE_SHIFT_SATA_PARTIAL (0)
+
+#define MPI2_SASIOUNIT5_ITE_TEN_SECONDS (7)
+#define MPI2_SASIOUNIT5_ITE_ONE_SECOND (6)
+#define MPI2_SASIOUNIT5_ITE_HUNDRED_MILLISECONDS (5)
+#define MPI2_SASIOUNIT5_ITE_TEN_MILLISECONDS (4)
+#define MPI2_SASIOUNIT5_ITE_ONE_MILLISECOND (3)
+#define MPI2_SASIOUNIT5_ITE_HUNDRED_MICROSECONDS (2)
+#define MPI2_SASIOUNIT5_ITE_TEN_MICROSECONDS (1)
+#define MPI2_SASIOUNIT5_ITE_ONE_MICROSECOND (0)
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.ExtPageLength or NumPhys at runtime.
+ */
+#ifndef MPI2_SAS_IOUNIT5_PHY_MAX
+#define MPI2_SAS_IOUNIT5_PHY_MAX (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_5 {
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U8 NumPhys; /* 0x08 */
+ U8 Reserved1; /* 0x09 */
+ U16 Reserved2; /* 0x0A */
+ U32 Reserved3; /* 0x0C */
+ MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS SASPhyPowerManagementSettings
+ [MPI2_SAS_IOUNIT5_PHY_MAX]; /* 0x10 */
+} MPI2_CONFIG_PAGE_SASIOUNIT_5,
+ MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_5,
+ Mpi2SasIOUnitPage5_t, MPI2_POINTER pMpi2SasIOUnitPage5_t;
+
+#define MPI2_SASIOUNITPAGE5_PAGEVERSION (0x00)
+
+
+
+
/****************************************************************************
* SAS Expander Config Pages
****************************************************************************/
@@ -1927,6 +2076,8 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_0
/* see mpi2_sas.h for values for SAS Device Page 0 DeviceInfo values */
/* values for SAS Device Page 0 Flags field */
+#define MPI2_SAS_DEVICE0_FLAGS_SLUMBER_PM_CAPABLE (0x1000)
+#define MPI2_SAS_DEVICE0_FLAGS_PARTIAL_PM_CAPABLE (0x0800)
#define MPI2_SAS_DEVICE0_FLAGS_SATA_ASYNCHRONOUS_NOTIFY (0x0400)
#define MPI2_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE (0x0200)
#define MPI2_SAS_DEVICE0_FLAGS_UNSUPPORTED_DEVICE (0x0100)
@@ -2343,5 +2494,122 @@ typedef struct _MPI2_CONFIG_PAGE_DRIVER_MAPPING_0
#define MPI2_DRVMAP0_MAPINFO_MISSING_MASK (0x000F)
+/****************************************************************************
+* Ethernet Config Pages
+****************************************************************************/
+
+/* Ethernet Page 0 */
+
+/* IP address (union of IPv4 and IPv6) */
+typedef union _MPI2_ETHERNET_IP_ADDR {
+ U32 IPv4Addr;
+ U32 IPv6Addr[4];
+} MPI2_ETHERNET_IP_ADDR, MPI2_POINTER PTR_MPI2_ETHERNET_IP_ADDR,
+ Mpi2EthernetIpAddr_t, MPI2_POINTER pMpi2EthernetIpAddr_t;
+
+#define MPI2_ETHERNET_HOST_NAME_LENGTH (32)
+
+typedef struct _MPI2_CONFIG_PAGE_ETHERNET_0 {
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U8 NumInterfaces; /* 0x08 */
+ U8 Reserved0; /* 0x09 */
+ U16 Reserved1; /* 0x0A */
+ U32 Status; /* 0x0C */
+ U8 MediaState; /* 0x10 */
+ U8 Reserved2; /* 0x11 */
+ U16 Reserved3; /* 0x12 */
+ U8 MacAddress[6]; /* 0x14 */
+ U8 Reserved4; /* 0x1A */
+ U8 Reserved5; /* 0x1B */
+ MPI2_ETHERNET_IP_ADDR IpAddress; /* 0x1C */
+ MPI2_ETHERNET_IP_ADDR SubnetMask; /* 0x2C */
+ MPI2_ETHERNET_IP_ADDR GatewayIpAddress; /* 0x3C */
+ MPI2_ETHERNET_IP_ADDR DNS1IpAddress; /* 0x4C */
+ MPI2_ETHERNET_IP_ADDR DNS2IpAddress; /* 0x5C */
+ MPI2_ETHERNET_IP_ADDR DhcpIpAddress; /* 0x6C */
+ U8 HostName
+ [MPI2_ETHERNET_HOST_NAME_LENGTH];/* 0x7C */
+} MPI2_CONFIG_PAGE_ETHERNET_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_ETHERNET_0,
+ Mpi2EthernetPage0_t, MPI2_POINTER pMpi2EthernetPage0_t;
+
+#define MPI2_ETHERNETPAGE0_PAGEVERSION (0x00)
+
+/* values for Ethernet Page 0 Status field */
+#define MPI2_ETHPG0_STATUS_IPV6_CAPABLE (0x80000000)
+#define MPI2_ETHPG0_STATUS_IPV4_CAPABLE (0x40000000)
+#define MPI2_ETHPG0_STATUS_CONSOLE_CONNECTED (0x20000000)
+#define MPI2_ETHPG0_STATUS_DEFAULT_IF (0x00000100)
+#define MPI2_ETHPG0_STATUS_FW_DWNLD_ENABLED (0x00000080)
+#define MPI2_ETHPG0_STATUS_TELNET_ENABLED (0x00000040)
+#define MPI2_ETHPG0_STATUS_SSH2_ENABLED (0x00000020)
+#define MPI2_ETHPG0_STATUS_DHCP_CLIENT_ENABLED (0x00000010)
+#define MPI2_ETHPG0_STATUS_IPV6_ENABLED (0x00000008)
+#define MPI2_ETHPG0_STATUS_IPV4_ENABLED (0x00000004)
+#define MPI2_ETHPG0_STATUS_IPV6_ADDRESSES (0x00000002)
+#define MPI2_ETHPG0_STATUS_ETH_IF_ENABLED (0x00000001)
+
+/* values for Ethernet Page 0 MediaState field */
+#define MPI2_ETHPG0_MS_DUPLEX_MASK (0x80)
+#define MPI2_ETHPG0_MS_HALF_DUPLEX (0x00)
+#define MPI2_ETHPG0_MS_FULL_DUPLEX (0x80)
+
+#define MPI2_ETHPG0_MS_CONNECT_SPEED_MASK (0x07)
+#define MPI2_ETHPG0_MS_NOT_CONNECTED (0x00)
+#define MPI2_ETHPG0_MS_10MBIT (0x01)
+#define MPI2_ETHPG0_MS_100MBIT (0x02)
+#define MPI2_ETHPG0_MS_1GBIT (0x03)
+
+
+/* Ethernet Page 1 */
+
+typedef struct _MPI2_CONFIG_PAGE_ETHERNET_1 {
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U32 Reserved0; /* 0x08 */
+ U32 Flags; /* 0x0C */
+ U8 MediaState; /* 0x10 */
+ U8 Reserved1; /* 0x11 */
+ U16 Reserved2; /* 0x12 */
+ U8 MacAddress[6]; /* 0x14 */
+ U8 Reserved3; /* 0x1A */
+ U8 Reserved4; /* 0x1B */
+ MPI2_ETHERNET_IP_ADDR StaticIpAddress; /* 0x1C */
+ MPI2_ETHERNET_IP_ADDR StaticSubnetMask; /* 0x2C */
+ MPI2_ETHERNET_IP_ADDR StaticGatewayIpAddress; /* 0x3C */
+ MPI2_ETHERNET_IP_ADDR StaticDNS1IpAddress; /* 0x4C */
+ MPI2_ETHERNET_IP_ADDR StaticDNS2IpAddress; /* 0x5C */
+ U32 Reserved5; /* 0x6C */
+ U32 Reserved6; /* 0x70 */
+ U32 Reserved7; /* 0x74 */
+ U32 Reserved8; /* 0x78 */
+ U8 HostName
+ [MPI2_ETHERNET_HOST_NAME_LENGTH];/* 0x7C */
+} MPI2_CONFIG_PAGE_ETHERNET_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_ETHERNET_1,
+ Mpi2EthernetPage1_t, MPI2_POINTER pMpi2EthernetPage1_t;
+
+#define MPI2_ETHERNETPAGE1_PAGEVERSION (0x00)
+
+/* values for Ethernet Page 1 Flags field */
+#define MPI2_ETHPG1_FLAG_SET_DEFAULT_IF (0x00000100)
+#define MPI2_ETHPG1_FLAG_ENABLE_FW_DOWNLOAD (0x00000080)
+#define MPI2_ETHPG1_FLAG_ENABLE_TELNET (0x00000040)
+#define MPI2_ETHPG1_FLAG_ENABLE_SSH2 (0x00000020)
+#define MPI2_ETHPG1_FLAG_ENABLE_DHCP_CLIENT (0x00000010)
+#define MPI2_ETHPG1_FLAG_ENABLE_IPV6 (0x00000008)
+#define MPI2_ETHPG1_FLAG_ENABLE_IPV4 (0x00000004)
+#define MPI2_ETHPG1_FLAG_USE_IPV6_ADDRESSES (0x00000002)
+#define MPI2_ETHPG1_FLAG_ENABLE_ETH_IF (0x00000001)
+
+/* values for Ethernet Page 1 MediaState field */
+#define MPI2_ETHPG1_MS_DUPLEX_MASK (0x80)
+#define MPI2_ETHPG1_MS_HALF_DUPLEX (0x00)
+#define MPI2_ETHPG1_MS_FULL_DUPLEX (0x80)
+
+#define MPI2_ETHPG1_MS_DATA_RATE_MASK (0x07)
+#define MPI2_ETHPG1_MS_DATA_RATE_AUTO (0x00)
+#define MPI2_ETHPG1_MS_DATA_RATE_10MBIT (0x01)
+#define MPI2_ETHPG1_MS_DATA_RATE_100MBIT (0x02)
+#define MPI2_ETHPG1_MS_DATA_RATE_1GBIT (0x03)
+
+
#endif
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
index c294128..ea51ce8 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
@@ -6,7 +6,7 @@
* Title: MPI IOC, Port, Event, FW Download, and FW Upload messages
* Creation Date: October 11, 2006
*
- * mpi2_ioc.h Version: 02.00.11
+ * mpi2_ioc.h Version: 02.00.12
*
* Version History
* ---------------
@@ -84,6 +84,9 @@
* Added two new reason codes for SAS Device Status Change
* Event.
* Added new event: SAS PHY Counter.
+ * 07-30-09 02.00.12 Added GPIO Interrupt event define and structure.
+ * Added MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define.
+ * Added new product id family for 2208.
* --------------------------------------------------------------------------
*/
@@ -274,6 +277,7 @@ typedef struct _MPI2_IOC_FACTS_REPLY
#define MPI2_IOCFACTS_CAPABILITY_MULTICAST (0x00000100)
#define MPI2_IOCFACTS_CAPABILITY_BIDIRECTIONAL_TARGET (0x00000080)
#define MPI2_IOCFACTS_CAPABILITY_EEDP (0x00000040)
+#define MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER (0x00000020)
#define MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER (0x00000010)
#define MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER (0x00000008)
#define MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING (0x00000004)
@@ -448,6 +452,7 @@ typedef struct _MPI2_EVENT_NOTIFICATION_REPLY
#define MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST (0x0020)
#define MPI2_EVENT_LOG_ENTRY_ADDED (0x0021)
#define MPI2_EVENT_SAS_PHY_COUNTER (0x0022)
+#define MPI2_EVENT_GPIO_INTERRUPT (0x0023)
/* Log Entry Added Event data */
@@ -469,6 +474,16 @@ typedef struct _MPI2_EVENT_DATA_LOG_ENTRY_ADDED
MPI2_POINTER PTR_MPI2_EVENT_DATA_LOG_ENTRY_ADDED,
Mpi2EventDataLogEntryAdded_t, MPI2_POINTER pMpi2EventDataLogEntryAdded_t;
+/* GPIO Interrupt Event data */
+
+typedef struct _MPI2_EVENT_DATA_GPIO_INTERRUPT {
+ U8 GPIONum; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U16 Reserved2; /* 0x02 */
+} MPI2_EVENT_DATA_GPIO_INTERRUPT,
+ MPI2_POINTER PTR_MPI2_EVENT_DATA_GPIO_INTERRUPT,
+ Mpi2EventDataGpioInterrupt_t, MPI2_POINTER pMpi2EventDataGpioInterrupt_t;
+
/* Hard Reset Received Event data */
typedef struct _MPI2_EVENT_DATA_HARD_RESET_RECEIVED
@@ -1117,6 +1132,7 @@ typedef struct _MPI2_FW_IMAGE_HEADER
#define MPI2_FW_HEADER_PID_FAMILY_MASK (0x00FF)
/* SAS */
#define MPI2_FW_HEADER_PID_FAMILY_2108_SAS (0x0010)
+#define MPI2_FW_HEADER_PID_FAMILY_2208_SAS (0x0011)
/* use MPI2_IOCFACTS_PROTOCOL_ defines for ProtocolFlags field */
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_raid.h b/drivers/scsi/mpt2sas/mpi/mpi2_raid.h
index 7134816..5160c33 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_raid.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_raid.h
@@ -6,7 +6,7 @@
* Title: MPI Integrated RAID messages and structures
* Creation Date: April 26, 2007
*
- * mpi2_raid.h Version: 02.00.03
+ * mpi2_raid.h Version: 02.00.04
*
* Version History
* ---------------
@@ -20,6 +20,8 @@
* 05-21-08 02.00.03 Added MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS so that
* the PhysDisk array in MPI2_RAID_VOLUME_CREATION_STRUCT
* can be sized by the build environment.
+ * 07-30-09 02.00.04 Added proper define for the Use Default Settings bit of
+ * VolumeCreationFlags and marked the old one as obsolete.
* --------------------------------------------------------------------------
*/
@@ -217,10 +219,14 @@ typedef struct _MPI2_RAID_VOLUME_CREATION_STRUCT
/* use MPI2_RAID_VOL_TYPE_ defines from mpi2_cnfg.h for VolumeType */
/* defines for the VolumeCreationFlags field */
+#define MPI2_RAID_VOL_CREATION_DEFAULT_SETTINGS (0x80000000)
+#define MPI2_RAID_VOL_CREATION_BACKGROUND_INIT (0x00000004)
+#define MPI2_RAID_VOL_CREATION_LOW_LEVEL_INIT (0x00000002)
+#define MPI2_RAID_VOL_CREATION_MIGRATE_DATA (0x00000001)
+/* The following is an obsolete define.
+ * It must be shifted left 24 bits in order to set the proper bit.
+ */
#define MPI2_RAID_VOL_CREATION_USE_DEFAULT_SETTINGS (0x80)
-#define MPI2_RAID_VOL_CREATION_BACKGROUND_INIT (0x04)
-#define MPI2_RAID_VOL_CREATION_LOW_LEVEL_INIT (0x02)
-#define MPI2_RAID_VOL_CREATION_MIGRATE_DATA (0x01)
/* RAID Online Capacity Expansion Structure */
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h
index 007e950..73fcdbf 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h
@@ -6,7 +6,7 @@
* Title: MPI diagnostic tool structures and definitions
* Creation Date: March 26, 2007
*
- * mpi2_tool.h Version: 02.00.03
+ * mpi2_tool.h Version: 02.00.04
*
* Version History
* ---------------
@@ -18,6 +18,10 @@
* structures and defines.
* 02-29-08 02.00.02 Modified various names to make them 32-character unique.
* 05-06-09 02.00.03 Added ISTWI Read Write Tool and Diagnostic CLI Tool.
+ * 07-30-09 02.00.04 Added ExtendedType field to DiagnosticBufferPost request
+ * and reply messages.
+ * Added MPI2_DIAG_BUF_TYPE_EXTENDED.
+ * Incremented MPI2_DIAG_BUF_TYPE_COUNT.
* --------------------------------------------------------------------------
*/
@@ -282,7 +286,7 @@ typedef struct _MPI2_TOOLBOX_DIAGNOSTIC_CLI_REPLY {
typedef struct _MPI2_DIAG_BUFFER_POST_REQUEST
{
- U8 Reserved1; /* 0x00 */
+ U8 ExtendedType; /* 0x00 */
U8 BufferType; /* 0x01 */
U8 ChainOffset; /* 0x02 */
U8 Function; /* 0x03 */
@@ -301,11 +305,15 @@ typedef struct _MPI2_DIAG_BUFFER_POST_REQUEST
} MPI2_DIAG_BUFFER_POST_REQUEST, MPI2_POINTER PTR_MPI2_DIAG_BUFFER_POST_REQUEST,
Mpi2DiagBufferPostRequest_t, MPI2_POINTER pMpi2DiagBufferPostRequest_t;
+/* values for the ExtendedType field */
+#define MPI2_DIAG_EXTENDED_TYPE_UTILIZATION (0x02)
+
/* values for the BufferType field */
#define MPI2_DIAG_BUF_TYPE_TRACE (0x00)
#define MPI2_DIAG_BUF_TYPE_SNAPSHOT (0x01)
+#define MPI2_DIAG_BUF_TYPE_EXTENDED (0x02)
/* count of the number of buffer types */
-#define MPI2_DIAG_BUF_TYPE_COUNT (0x02)
+#define MPI2_DIAG_BUF_TYPE_COUNT (0x03)
/****************************************************************************
@@ -314,7 +322,7 @@ typedef struct _MPI2_DIAG_BUFFER_POST_REQUEST
typedef struct _MPI2_DIAG_BUFFER_POST_REPLY
{
- U8 Reserved1; /* 0x00 */
+ U8 ExtendedType; /* 0x00 */
U8 BufferType; /* 0x01 */
U8 MsgLength; /* 0x02 */
U8 Function; /* 0x03 */
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c
index 670241e..6422e25 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.c
@@ -57,6 +57,7 @@
#include <linux/dma-mapping.h>
#include <linux/sort.h>
#include <linux/io.h>
+#include <linux/time.h>
#include "mpt2sas_base.h"
@@ -77,6 +78,44 @@ static int msix_disable = -1;
module_param(msix_disable, int, 0);
MODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)");
+/* diag_buffer_enable is bitwise
+ * bit 0 set = TRACE
+ * bit 1 set = SNAPSHOT
+ * bit 2 set = EXTENDED
+ *
+ * Either bit can be set, or both
+ */
+static int diag_buffer_enable;
+module_param(diag_buffer_enable, int, 0);
+MODULE_PARM_DESC(diag_buffer_enable, " post diag buffers "
+ "(TRACE=1/SNAPSHOT=2/EXTENDED=4/default=0)");
+
+int mpt2sas_fwfault_debug;
+MODULE_PARM_DESC(mpt2sas_fwfault_debug, " enable detection of firmware fault "
+ "and halt firmware - (default=0)");
+
+/**
+ * _scsih_set_fwfault_debug - global setting of ioc->fwfault_debug.
+ *
+ */
+static int
+_scsih_set_fwfault_debug(const char *val, struct kernel_param *kp)
+{
+ int ret = param_set_int(val, kp);
+ struct MPT2SAS_ADAPTER *ioc;
+
+ if (ret)
+ return ret;
+
+ printk(KERN_INFO "setting logging_level(0x%08x)\n",
+ mpt2sas_fwfault_debug);
+ list_for_each_entry(ioc, &mpt2sas_ioc_list, list)
+ ioc->fwfault_debug = mpt2sas_fwfault_debug;
+ return 0;
+}
+module_param_call(mpt2sas_fwfault_debug, _scsih_set_fwfault_debug,
+ param_get_int, &mpt2sas_fwfault_debug, 0644);
+
/**
* _base_fault_reset_work - workq handling ioc fault conditions
* @work: input argument, used to derive ioc
@@ -121,7 +160,7 @@ _base_fault_reset_work(struct work_struct *work)
/**
* mpt2sas_base_start_watchdog - start the fault_reset_work_q
- * @ioc: pointer to scsi command object
+ * @ioc: per adapter object
* Context: sleep.
*
* Return nothing.
@@ -155,7 +194,7 @@ mpt2sas_base_start_watchdog(struct MPT2SAS_ADAPTER *ioc)
/**
* mpt2sas_base_stop_watchdog - stop the fault_reset_work_q
- * @ioc: pointer to scsi command object
+ * @ioc: per adapter object
* Context: sleep.
*
* Return nothing.
@@ -177,10 +216,55 @@ mpt2sas_base_stop_watchdog(struct MPT2SAS_ADAPTER *ioc)
}
}
+/**
+ * mpt2sas_base_fault_info - verbose translation of firmware FAULT code
+ * @ioc: per adapter object
+ * @fault_code: fault code
+ *
+ * Return nothing.
+ */
+void
+mpt2sas_base_fault_info(struct MPT2SAS_ADAPTER *ioc , u16 fault_code)
+{
+ printk(MPT2SAS_ERR_FMT "fault_state(0x%04x)!\n",
+ ioc->name, fault_code);
+}
+
+/**
+ * mpt2sas_halt_firmware - halt's mpt controller firmware
+ * @ioc: per adapter object
+ *
+ * For debugging timeout related issues. Writing 0xCOFFEE00
+ * to the doorbell register will halt controller firmware. With
+ * the purpose to stop both driver and firmware, the enduser can
+ * obtain a ring buffer from controller UART.
+ */
+void
+mpt2sas_halt_firmware(struct MPT2SAS_ADAPTER *ioc)
+{
+ u32 doorbell;
+
+ if (!ioc->fwfault_debug)
+ return;
+
+ dump_stack();
+
+ doorbell = readl(&ioc->chip->Doorbell);
+ if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT)
+ mpt2sas_base_fault_info(ioc , doorbell);
+ else {
+ writel(0xC0FFEE00, &ioc->chip->Doorbell);
+ printk(MPT2SAS_ERR_FMT "Firmware is halted due to command "
+ "timeout\n", ioc->name);
+ }
+
+ panic("panic in %s\n", __func__);
+}
+
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
/**
* _base_sas_ioc_info - verbose translation of the ioc status
- * @ioc: pointer to scsi command object
+ * @ioc: per adapter object
* @mpi_reply: reply mf payload returned from firmware
* @request_hdr: request mf
*
@@ -394,7 +478,7 @@ _base_sas_ioc_info(struct MPT2SAS_ADAPTER *ioc, MPI2DefaultReply_t *mpi_reply,
/**
* _base_display_event_data - verbose translation of firmware asyn events
- * @ioc: pointer to scsi command object
+ * @ioc: per adapter object
* @mpi_reply: reply mf payload returned from firmware
*
* Return nothing.
@@ -474,7 +558,7 @@ _base_display_event_data(struct MPT2SAS_ADAPTER *ioc,
/**
* _base_sas_log_info - verbose translation of firmware log info
- * @ioc: pointer to scsi command object
+ * @ioc: per adapter object
* @log_info: log info
*
* Return nothing.
@@ -526,22 +610,8 @@ _base_sas_log_info(struct MPT2SAS_ADAPTER *ioc , u32 log_info)
}
/**
- * mpt2sas_base_fault_info - verbose translation of firmware FAULT code
- * @ioc: pointer to scsi command object
- * @fault_code: fault code
- *
- * Return nothing.
- */
-void
-mpt2sas_base_fault_info(struct MPT2SAS_ADAPTER *ioc , u16 fault_code)
-{
- printk(MPT2SAS_ERR_FMT "fault_state(0x%04x)!\n",
- ioc->name, fault_code);
-}
-
-/**
* _base_display_reply_info -
- * @ioc: pointer to scsi command object
+ * @ioc: per adapter object
* @smid: system request message index
* @msix_index: MSIX table index supplied by the OS
* @reply: reply message frame(lower 32bit addr)
@@ -570,7 +640,7 @@ _base_display_reply_info(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
/**
* mpt2sas_base_done - base internal command completion routine
- * @ioc: pointer to scsi command object
+ * @ioc: per adapter object
* @smid: system request message index
* @msix_index: MSIX table index supplied by the OS
* @reply: reply message frame(lower 32bit addr)
@@ -603,7 +673,7 @@ mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
/**
* _base_async_event - main callback handler for firmware asyn events
- * @ioc: pointer to scsi command object
+ * @ioc: per adapter object
* @msix_index: MSIX table index supplied by the OS
* @reply: reply message frame(lower 32bit addr)
*
@@ -684,7 +754,7 @@ _base_get_cb_idx(struct MPT2SAS_ADAPTER *ioc, u16 smid)
/**
* _base_mask_interrupts - disable interrupts
- * @ioc: pointer to scsi command object
+ * @ioc: per adapter object
*
* Disabling ResetIRQ, Reply and Doorbell Interrupts
*
@@ -704,7 +774,7 @@ _base_mask_interrupts(struct MPT2SAS_ADAPTER *ioc)
/**
* _base_unmask_interrupts - enable interrupts
- * @ioc: pointer to scsi command object
+ * @ioc: per adapter object
*
* Enabling only Reply Interrupts
*
@@ -1258,12 +1328,13 @@ mpt2sas_base_get_sense_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid)
* @ioc: per adapter object
* @smid: system request message index
*
- * Returns phys pointer to sense buffer.
+ * Returns phys pointer to the low 32bit address of the sense buffer.
*/
-dma_addr_t
+__le32
mpt2sas_base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid)
{
- return ioc->sense_dma + ((smid - 1) * SCSI_SENSE_BUFFERSIZE);
+ return cpu_to_le32(ioc->sense_dma +
+ ((smid - 1) * SCSI_SENSE_BUFFERSIZE));
}
/**
@@ -1697,6 +1768,12 @@ _base_display_ioc_capabilities(struct MPT2SAS_ADAPTER *ioc)
}
if (ioc->facts.IOCCapabilities &
+ MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER) {
+ printk(KERN_INFO "%sDiag Extended Buffer", i ? "," : "");
+ i++;
+ }
+
+ if (ioc->facts.IOCCapabilities &
MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING) {
printk("%sTask Set Full", i ? "," : "");
i++;
@@ -2871,6 +2948,8 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
Mpi2IOCInitRequest_t mpi_request;
Mpi2IOCInitReply_t mpi_reply;
int r;
+ struct timeval current_time;
+ u16 ioc_status;
dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
__func__));
@@ -2921,6 +3000,13 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
cpu_to_le32(ioc->reply_post_free_dma);
#endif
+ /* This time stamp specifies number of milliseconds
+ * since epoch ~ midnight January 1, 1970.
+ */
+ do_gettimeofday(&current_time);
+ mpi_request.TimeStamp = (current_time.tv_sec * 1000) +
+ (current_time.tv_usec >> 3);
+
if (ioc->logging_level & MPT_DEBUG_INIT) {
u32 *mfp;
int i;
@@ -2943,7 +3029,8 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
return r;
}
- if (mpi_reply.IOCStatus != MPI2_IOCSTATUS_SUCCESS ||
+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS ||
mpi_reply.IOCLogInfo) {
printk(MPT2SAS_ERR_FMT "%s: failed\n", ioc->name, __func__);
r = -EIO;
@@ -3461,11 +3548,11 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
return r;
pci_set_drvdata(ioc->pdev, ioc->shost);
- r = _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET);
+ r = _base_get_ioc_facts(ioc, CAN_SLEEP);
if (r)
goto out_free_resources;
- r = _base_get_ioc_facts(ioc, CAN_SLEEP);
+ r = _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET);
if (r)
goto out_free_resources;
@@ -3531,6 +3618,8 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
goto out_free_resources;
mpt2sas_base_start_watchdog(ioc);
+ if (diag_buffer_enable != 0)
+ mpt2sas_enable_diag_buffer(ioc, diag_buffer_enable);
return 0;
out_free_resources:
@@ -3684,6 +3773,9 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
__func__));
+ if (mpt2sas_fwfault_debug)
+ mpt2sas_halt_firmware(ioc);
+
spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
if (ioc->shost_recovery) {
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h
index 0cf6bc2..bb4f146 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.h
@@ -69,8 +69,8 @@
#define MPT2SAS_DRIVER_NAME "mpt2sas"
#define MPT2SAS_AUTHOR "LSI Corporation <DL-MPTFusionLinux@lsi.com>"
#define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver"
-#define MPT2SAS_DRIVER_VERSION "02.100.03.00"
-#define MPT2SAS_MAJOR_VERSION 02
+#define MPT2SAS_DRIVER_VERSION "03.100.03.00"
+#define MPT2SAS_MAJOR_VERSION 03
#define MPT2SAS_MINOR_VERSION 100
#define MPT2SAS_BUILD_VERSION 03
#define MPT2SAS_RELEASE_VERSION 00
@@ -278,7 +278,7 @@ struct _internal_cmd {
* @sas_address: device sas address
* @device_name: retrieved from the SAS IDENTIFY frame.
* @handle: device handle
- * @parent_handle: handle to parent device
+ * @sas_address_parent: sas address of parent expander or sas host
* @enclosure_handle: enclosure handle
* @enclosure_logical_id: enclosure logical identifier
* @volume_handle: volume handle (valid when hidden raid member)
@@ -296,7 +296,7 @@ struct _sas_device {
u64 sas_address;
u64 device_name;
u16 handle;
- u16 parent_handle;
+ u64 sas_address_parent;
u16 enclosure_handle;
u64 enclosure_logical_id;
u16 volume_handle;
@@ -352,8 +352,6 @@ struct _boot_device {
/**
* struct _sas_port - wide/narrow sas port information
* @port_list: list of ports belonging to expander
- * @handle: device handle for this port
- * @sas_address: sas address of this port
* @num_phys: number of phys belonging to this port
* @remote_identify: attached device identification
* @rphy: sas transport rphy object
@@ -362,8 +360,6 @@ struct _boot_device {
*/
struct _sas_port {
struct list_head port_list;
- u16 handle;
- u64 sas_address;
u8 num_phys;
struct sas_identify remote_identify;
struct sas_rphy *rphy;
@@ -398,7 +394,7 @@ struct _sas_phy {
* @num_phys: number phys belonging to this sas_host/expander
* @sas_address: sas address of this sas_host/expander
* @handle: handle for this sas_host/expander
- * @parent_handle: parent handle
+ * @sas_address_parent: sas address of parent expander or sas host
* @enclosure_handle: handle for this a member of an enclosure
* @device_info: bitwise defining capabilities of this sas_host/expander
* @responding: used in _scsih_expander_device_mark_responding
@@ -411,7 +407,7 @@ struct _sas_node {
u8 num_phys;
u64 sas_address;
u16 handle;
- u16 parent_handle;
+ u64 sas_address_parent;
u16 enclosure_handle;
u64 enclosure_logical_id;
u8 responding;
@@ -470,6 +466,7 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr);
* @chip_phys: physical addrss prior to mapping
* @pio_chip: I/O mapped register space
* @logging_level: see mpt2sas_debug.h
+ * @fwfault_debug: debuging FW timeouts
* @ir_firmware: IR firmware present
* @bars: bitmask of BAR's that must be configured
* @mask_interrupts: ignore interrupt
@@ -495,12 +492,14 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr);
* @msix_table_backup: backup msix table
* @scsi_io_cb_idx: shost generated commands
* @tm_cb_idx: task management commands
+ * @scsih_cb_idx: scsih internal commands
* @transport_cb_idx: transport internal commands
* @ctl_cb_idx: clt internal commands
* @base_cb_idx: base internal commands
* @config_cb_idx: base internal commands
* @base_cmds:
* @transport_cmds:
+ * @scsih_cmds:
* @tm_cmds:
* @ctl_cmds:
* @config_cmds:
@@ -591,6 +590,7 @@ struct MPT2SAS_ADAPTER {
unsigned long chip_phys;
unsigned long pio_chip;
int logging_level;
+ int fwfault_debug;
u8 ir_firmware;
int bars;
u8 mask_interrupts;
@@ -626,6 +626,7 @@ struct MPT2SAS_ADAPTER {
u8 scsi_io_cb_idx;
u8 tm_cb_idx;
u8 transport_cb_idx;
+ u8 scsih_cb_idx;
u8 ctl_cb_idx;
u8 base_cb_idx;
u8 config_cb_idx;
@@ -633,6 +634,7 @@ struct MPT2SAS_ADAPTER {
u8 tm_sas_control_cb_idx;
struct _internal_cmd base_cmds;
struct _internal_cmd transport_cmds;
+ struct _internal_cmd scsih_cmds;
struct _internal_cmd tm_cmds;
struct _internal_cmd ctl_cmds;
struct _internal_cmd config_cmds;
@@ -773,7 +775,7 @@ int mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
void *mpt2sas_base_get_msg_frame(struct MPT2SAS_ADAPTER *ioc, u16 smid);
void *mpt2sas_base_get_sense_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid);
void mpt2sas_base_build_zero_len_sge(struct MPT2SAS_ADAPTER *ioc, void *paddr);
-dma_addr_t mpt2sas_base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc,
+__le32 mpt2sas_base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc,
u16 smid);
/* hi-priority queue */
@@ -807,6 +809,8 @@ int mpt2sas_base_scsi_enclosure_processor(struct MPT2SAS_ADAPTER *ioc,
Mpi2SepReply_t *mpi_reply, Mpi2SepRequest_t *mpi_request);
void mpt2sas_base_validate_event_type(struct MPT2SAS_ADAPTER *ioc, u32 *event_type);
+void mpt2sas_halt_firmware(struct MPT2SAS_ADAPTER *ioc);
+
/* scsih shared API */
u8 mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
u32 reply);
@@ -886,19 +890,22 @@ u8 mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
void mpt2sas_ctl_add_to_event_log(struct MPT2SAS_ADAPTER *ioc,
Mpi2EventNotificationReply_t *mpi_reply);
+void mpt2sas_enable_diag_buffer(struct MPT2SAS_ADAPTER *ioc,
+ u8 bits_to_regsiter);
+
/* transport shared API */
u8 mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
u32 reply);
struct _sas_port *mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc,
- u16 handle, u16 parent_handle);
+ u16 handle, u64 sas_address);
void mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
- u16 parent_handle);
+ u64 sas_address_parent);
int mpt2sas_transport_add_host_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
*mpt2sas_phy, Mpi2SasPhyPage0_t phy_pg0, struct device *parent_dev);
int mpt2sas_transport_add_expander_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
*mpt2sas_phy, Mpi2ExpanderPage1_t expander_pg1, struct device *parent_dev);
-void mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc, u16 handle,
- u16 attached_handle, u8 phy_number, u8 link_rate);
+void mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc,
+ u64 sas_address, u16 handle, u8 phy_number, u8 link_rate);
extern struct sas_function_template mpt2sas_transport_functions;
extern struct scsi_transport_template *mpt2sas_transport_template;
extern int scsi_internal_device_block(struct scsi_device *sdev);
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
index 57d7246..84a124f 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
@@ -740,7 +740,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
Mpi2SCSIIORequest_t *scsiio_request =
(Mpi2SCSIIORequest_t *)mpi_request;
scsiio_request->SenseBufferLowAddress =
- (u32)mpt2sas_base_get_sense_buffer_dma(ioc, smid);
+ mpt2sas_base_get_sense_buffer_dma(ioc, smid);
priv_sense = mpt2sas_base_get_sense_buffer(ioc, smid);
memset(priv_sense, 0, SCSI_SENSE_BUFFERSIZE);
mpt2sas_base_put_smid_scsi_io(ioc, smid,
@@ -848,8 +848,9 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
printk(MPT2SAS_DEBUG_FMT "TASK_MGMT: "
"IOCStatus(0x%04x), IOCLogInfo(0x%08x), "
"TerminationCount(0x%08x)\n", ioc->name,
- tm_reply->IOCStatus, tm_reply->IOCLogInfo,
- tm_reply->TerminationCount);
+ le16_to_cpu(tm_reply->IOCStatus),
+ le32_to_cpu(tm_reply->IOCLogInfo),
+ le32_to_cpu(tm_reply->TerminationCount));
}
#endif
/* copy out xdata to user */
@@ -896,6 +897,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
printk(MPT2SAS_INFO_FMT "issue target reset: handle "
"= (0x%04x)\n", ioc->name,
mpi_request->FunctionDependent1);
+ mpt2sas_halt_firmware(ioc);
mutex_lock(&ioc->tm_cmds.mutex);
mpt2sas_scsih_issue_tm(ioc,
mpi_request->FunctionDependent1, 0,
@@ -1229,7 +1231,7 @@ _ctl_btdh_mapping(void __user *arg)
/**
* _ctl_diag_capability - return diag buffer capability
* @ioc: per adapter object
- * @buffer_type: specifies either TRACE or SNAPSHOT
+ * @buffer_type: specifies either TRACE, SNAPSHOT, or EXTENDED
*
* returns 1 when diag buffer support is enabled in firmware
*/
@@ -1249,24 +1251,25 @@ _ctl_diag_capability(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type)
MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER)
rc = 1;
break;
+ case MPI2_DIAG_BUF_TYPE_EXTENDED:
+ if (ioc->facts.IOCCapabilities &
+ MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER)
+ rc = 1;
}
return rc;
}
/**
- * _ctl_diag_register - application register with driver
- * @arg - user space buffer containing ioctl content
- * @state - NON_BLOCKING or BLOCKING
+ * _ctl_diag_register_2 - wrapper for registering diag buffer support
+ * @ioc: per adapter object
+ * @diag_register: the diag_register struct passed in from user space
*
- * This will allow the driver to setup any required buffers that will be
- * needed by firmware to communicate with the driver.
*/
static long
-_ctl_diag_register(void __user *arg, enum block_state state)
+_ctl_diag_register_2(struct MPT2SAS_ADAPTER *ioc,
+ struct mpt2_diag_register *diag_register)
{
- struct mpt2_diag_register karg;
- struct MPT2SAS_ADAPTER *ioc;
int rc, i;
void *request_data = NULL;
dma_addr_t request_data_dma;
@@ -1279,18 +1282,17 @@ _ctl_diag_register(void __user *arg, enum block_state state)
u16 ioc_status;
u8 issue_reset = 0;
- if (copy_from_user(&karg, arg, sizeof(karg))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
- if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
- return -ENODEV;
-
dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
__func__));
- buffer_type = karg.buffer_type;
+ if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) {
+ printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n",
+ ioc->name, __func__);
+ rc = -EAGAIN;
+ goto out;
+ }
+
+ buffer_type = diag_register->buffer_type;
if (!_ctl_diag_capability(ioc, buffer_type)) {
printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for "
"buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type);
@@ -1305,24 +1307,12 @@ _ctl_diag_register(void __user *arg, enum block_state state)
return -EINVAL;
}
- if (karg.requested_buffer_size % 4) {
+ if (diag_register->requested_buffer_size % 4) {
printk(MPT2SAS_ERR_FMT "%s: the requested_buffer_size "
"is not 4 byte aligned\n", ioc->name, __func__);
return -EINVAL;
}
- if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex))
- return -EAGAIN;
- else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex))
- return -ERESTARTSYS;
-
- if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) {
- printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n",
- ioc->name, __func__);
- rc = -EAGAIN;
- goto out;
- }
-
smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx);
if (!smid) {
printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
@@ -1338,12 +1328,12 @@ _ctl_diag_register(void __user *arg, enum block_state state)
ioc->ctl_cmds.smid = smid;
request_data = ioc->diag_buffer[buffer_type];
- request_data_sz = karg.requested_buffer_size;
- ioc->unique_id[buffer_type] = karg.unique_id;
+ request_data_sz = diag_register->requested_buffer_size;
+ ioc->unique_id[buffer_type] = diag_register->unique_id;
ioc->diag_buffer_status[buffer_type] = 0;
- memcpy(ioc->product_specific[buffer_type], karg.product_specific,
- MPT2_PRODUCT_SPECIFIC_DWORDS);
- ioc->diagnostic_flags[buffer_type] = karg.diagnostic_flags;
+ memcpy(ioc->product_specific[buffer_type],
+ diag_register->product_specific, MPT2_PRODUCT_SPECIFIC_DWORDS);
+ ioc->diagnostic_flags[buffer_type] = diag_register->diagnostic_flags;
if (request_data) {
request_data_dma = ioc->diag_buffer_dma[buffer_type];
@@ -1373,8 +1363,8 @@ _ctl_diag_register(void __user *arg, enum block_state state)
}
mpi_request->Function = MPI2_FUNCTION_DIAG_BUFFER_POST;
- mpi_request->BufferType = karg.buffer_type;
- mpi_request->Flags = cpu_to_le32(karg.diagnostic_flags);
+ mpi_request->BufferType = diag_register->buffer_type;
+ mpi_request->Flags = cpu_to_le32(diag_register->diagnostic_flags);
mpi_request->BufferAddress = cpu_to_le64(request_data_dma);
mpi_request->BufferLength = cpu_to_le32(request_data_sz);
mpi_request->VF_ID = 0; /* TODO */
@@ -1422,7 +1412,7 @@ _ctl_diag_register(void __user *arg, enum block_state state)
} else {
printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) "
"log_info(0x%08x)\n", ioc->name, __func__,
- ioc_status, mpi_reply->IOCLogInfo);
+ ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo));
rc = -EFAULT;
}
@@ -1438,6 +1428,83 @@ _ctl_diag_register(void __user *arg, enum block_state state)
request_data, request_data_dma);
ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;
+ return rc;
+}
+
+/**
+ * mpt2sas_enable_diag_buffer - enabling diag_buffers support driver load time
+ * @ioc: per adapter object
+ * @bits_to_register: bitwise field where trace is bit 0, and snapshot is bit 1
+ *
+ * This is called when command line option diag_buffer_enable is enabled
+ * at driver load time.
+ */
+void
+mpt2sas_enable_diag_buffer(struct MPT2SAS_ADAPTER *ioc, u8 bits_to_register)
+{
+ struct mpt2_diag_register diag_register;
+
+ memset(&diag_register, 0, sizeof(struct mpt2_diag_register));
+
+ if (bits_to_register & 1) {
+ printk(MPT2SAS_INFO_FMT "registering trace buffer support\n",
+ ioc->name);
+ diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_TRACE;
+ /* register for 1MB buffers */
+ diag_register.requested_buffer_size = (1024 * 1024);
+ diag_register.unique_id = 0x7075900;
+ _ctl_diag_register_2(ioc, &diag_register);
+ }
+
+ if (bits_to_register & 2) {
+ printk(MPT2SAS_INFO_FMT "registering snapshot buffer support\n",
+ ioc->name);
+ diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_SNAPSHOT;
+ /* register for 2MB buffers */
+ diag_register.requested_buffer_size = 2 * (1024 * 1024);
+ diag_register.unique_id = 0x7075901;
+ _ctl_diag_register_2(ioc, &diag_register);
+ }
+
+ if (bits_to_register & 4) {
+ printk(MPT2SAS_INFO_FMT "registering extended buffer support\n",
+ ioc->name);
+ diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_EXTENDED;
+ /* register for 2MB buffers */
+ diag_register.requested_buffer_size = 2 * (1024 * 1024);
+ diag_register.unique_id = 0x7075901;
+ _ctl_diag_register_2(ioc, &diag_register);
+ }
+}
+
+/**
+ * _ctl_diag_register - application register with driver
+ * @arg - user space buffer containing ioctl content
+ * @state - NON_BLOCKING or BLOCKING
+ *
+ * This will allow the driver to setup any required buffers that will be
+ * needed by firmware to communicate with the driver.
+ */
+static long
+_ctl_diag_register(void __user *arg, enum block_state state)
+{
+ struct mpt2_diag_register karg;
+ struct MPT2SAS_ADAPTER *ioc;
+ long rc;
+
+ if (copy_from_user(&karg, arg, sizeof(karg))) {
+ printk(KERN_ERR "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
+ return -EFAULT;
+ }
+ if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
+ return -ENODEV;
+
+ if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex))
+ return -EAGAIN;
+ else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex))
+ return -ERESTARTSYS;
+ rc = _ctl_diag_register_2(ioc, &karg);
mutex_unlock(&ioc->ctl_cmds.mutex);
return rc;
}
@@ -1600,7 +1667,7 @@ _ctl_diag_query(void __user *arg)
/**
* _ctl_send_release - Diag Release Message
* @ioc: per adapter object
- * @buffer_type - specifies either TRACE or SNAPSHOT
+ * @buffer_type - specifies either TRACE, SNAPSHOT, or EXTENDED
* @issue_reset - specifies whether host reset is required.
*
*/
@@ -1690,7 +1757,7 @@ _ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, u8 *issue_reset)
} else {
printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) "
"log_info(0x%08x)\n", ioc->name, __func__,
- ioc_status, mpi_reply->IOCLogInfo);
+ ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo));
rc = -EFAULT;
}
@@ -1951,7 +2018,7 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state)
} else {
printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) "
"log_info(0x%08x)\n", ioc->name, __func__,
- ioc_status, mpi_reply->IOCLogInfo);
+ ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo));
rc = -EFAULT;
}
@@ -2474,6 +2541,43 @@ _ctl_logging_level_store(struct device *cdev, struct device_attribute *attr,
static DEVICE_ATTR(logging_level, S_IRUGO | S_IWUSR,
_ctl_logging_level_show, _ctl_logging_level_store);
+/* device attributes */
+/*
+ * _ctl_fwfault_debug_show - show/store fwfault_debug
+ * @cdev - pointer to embedded class device
+ * @buf - the buffer returned
+ *
+ * mpt2sas_fwfault_debug is command line option
+ * A sysfs 'read/write' shost attribute.
+ */
+static ssize_t
+_ctl_fwfault_debug_show(struct device *cdev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", ioc->fwfault_debug);
+}
+static ssize_t
+_ctl_fwfault_debug_store(struct device *cdev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+ int val = 0;
+
+ if (sscanf(buf, "%d", &val) != 1)
+ return -EINVAL;
+
+ ioc->fwfault_debug = val;
+ printk(MPT2SAS_INFO_FMT "fwfault_debug=%d\n", ioc->name,
+ ioc->fwfault_debug);
+ return strlen(buf);
+}
+static DEVICE_ATTR(fwfault_debug, S_IRUGO | S_IWUSR,
+ _ctl_fwfault_debug_show, _ctl_fwfault_debug_store);
+
struct device_attribute *mpt2sas_host_attrs[] = {
&dev_attr_version_fw,
&dev_attr_version_bios,
@@ -2487,13 +2591,12 @@ struct device_attribute *mpt2sas_host_attrs[] = {
&dev_attr_io_delay,
&dev_attr_device_delay,
&dev_attr_logging_level,
+ &dev_attr_fwfault_debug,
&dev_attr_fw_queue_depth,
&dev_attr_host_sas_address,
NULL,
};
-/* device attributes */
-
/**
* _ctl_device_sas_address_show - sas address
* @cdev - pointer to embedded class device
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.h b/drivers/scsi/mpt2sas/mpt2sas_ctl.h
index 211f296..8a5eeb1 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_ctl.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.h
@@ -313,7 +313,7 @@ struct mpt2_ioctl_btdh_mapping {
* struct mpt2_diag_register - application register with driver
* @hdr - generic header
* @reserved -
- * @buffer_type - specifies either TRACE or SNAPSHOT
+ * @buffer_type - specifies either TRACE, SNAPSHOT, or EXTENDED
* @application_flags - misc flags
* @diagnostic_flags - specifies flags affecting command processing
* @product_specific - product specific information
@@ -352,7 +352,7 @@ struct mpt2_diag_unregister {
* struct mpt2_diag_query - query relevant info associated with diag buffers
* @hdr - generic header
* @reserved -
- * @buffer_type - specifies either TRACE or SNAPSHOT
+ * @buffer_type - specifies either TRACE, SNAPSHOT, or EXTENDED
* @application_flags - misc flags
* @diagnostic_flags - specifies flags affecting command processing
* @product_specific - product specific information
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
index 86ab32d..efabea1 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
@@ -76,6 +76,7 @@ static u8 tm_cb_idx = -1;
static u8 ctl_cb_idx = -1;
static u8 base_cb_idx = -1;
static u8 transport_cb_idx = -1;
+static u8 scsih_cb_idx = -1;
static u8 config_cb_idx = -1;
static int mpt_ids;
@@ -196,10 +197,28 @@ static struct pci_device_id scsih_pci_table[] = {
PCI_ANY_ID, PCI_ANY_ID },
{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_3,
PCI_ANY_ID, PCI_ANY_ID },
+ /* Meteor ~ 2116 */
{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_1,
PCI_ANY_ID, PCI_ANY_ID },
{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_2,
PCI_ANY_ID, PCI_ANY_ID },
+ /* Thunderbolt ~ 2208 */
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_1,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_2,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_3,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_4,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_5,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_6,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_7,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_8,
+ PCI_ANY_ID, PCI_ANY_ID },
{0} /* Terminating entry */
};
MODULE_DEVICE_TABLE(pci, scsih_pci_table);
@@ -317,6 +336,47 @@ _scsih_is_boot_device(u64 sas_address, u64 device_name,
}
/**
+ * _scsih_get_sas_address - set the sas_address for given device handle
+ * @handle: device handle
+ * @sas_address: sas address
+ *
+ * Returns 0 success, non-zero when failure
+ */
+static int
+_scsih_get_sas_address(struct MPT2SAS_ADAPTER *ioc, u16 handle,
+ u64 *sas_address)
+{
+ Mpi2SasDevicePage0_t sas_device_pg0;
+ Mpi2ConfigReply_t mpi_reply;
+ u32 ioc_status;
+
+ if (handle <= ioc->sas_hba.num_phys) {
+ *sas_address = ioc->sas_hba.sas_address;
+ return 0;
+ } else
+ *sas_address = 0;
+
+ if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
+ MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
+ printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+ ioc->name, __FILE__, __LINE__, __func__);
+ return -ENXIO;
+ }
+
+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+ MPI2_IOCSTATUS_MASK;
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ printk(MPT2SAS_ERR_FMT "handle(0x%04x), ioc_status(0x%04x)"
+ "\nfailure at %s:%d/%s()!\n", ioc->name, handle, ioc_status,
+ __FILE__, __LINE__, __func__);
+ return -EIO;
+ }
+
+ *sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
+ return 0;
+}
+
+/**
* _scsih_determine_boot_device - determine boot device.
* @ioc: per adapter object
* @device: either sas_device or raid_device object
@@ -510,8 +570,6 @@ _scsih_sas_device_add(struct MPT2SAS_ADAPTER *ioc,
struct _sas_device *sas_device)
{
unsigned long flags;
- u16 handle, parent_handle;
- u64 sas_address;
dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle"
"(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
@@ -521,10 +579,8 @@ _scsih_sas_device_add(struct MPT2SAS_ADAPTER *ioc,
list_add_tail(&sas_device->list, &ioc->sas_device_list);
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- handle = sas_device->handle;
- parent_handle = sas_device->parent_handle;
- sas_address = sas_device->sas_address;
- if (!mpt2sas_transport_port_add(ioc, handle, parent_handle))
+ if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
+ sas_device->sas_address_parent))
_scsih_sas_device_remove(ioc, sas_device);
}
@@ -553,31 +609,6 @@ _scsih_sas_device_init_add(struct MPT2SAS_ADAPTER *ioc,
}
/**
- * mpt2sas_scsih_expander_find_by_handle - expander device search
- * @ioc: per adapter object
- * @handle: expander handle (assigned by firmware)
- * Context: Calling function should acquire ioc->sas_device_lock
- *
- * This searches for expander device based on handle, then returns the
- * sas_node object.
- */
-struct _sas_node *
-mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
-{
- struct _sas_node *sas_expander, *r;
-
- r = NULL;
- list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
- if (sas_expander->handle != handle)
- continue;
- r = sas_expander;
- goto out;
- }
- out:
- return r;
-}
-
-/**
* _scsih_raid_device_find_by_id - raid device search
* @ioc: per adapter object
* @id: sas device target id
@@ -699,6 +730,31 @@ _scsih_raid_device_remove(struct MPT2SAS_ADAPTER *ioc,
}
/**
+ * mpt2sas_scsih_expander_find_by_handle - expander device search
+ * @ioc: per adapter object
+ * @handle: expander handle (assigned by firmware)
+ * Context: Calling function should acquire ioc->sas_device_lock
+ *
+ * This searches for expander device based on handle, then returns the
+ * sas_node object.
+ */
+struct _sas_node *
+mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+{
+ struct _sas_node *sas_expander, *r;
+
+ r = NULL;
+ list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
+ if (sas_expander->handle != handle)
+ continue;
+ r = sas_expander;
+ goto out;
+ }
+ out:
+ return r;
+}
+
+/**
* mpt2sas_scsih_expander_find_by_sas_address - expander device search
* @ioc: per adapter object
* @sas_address: sas address
@@ -1043,17 +1099,46 @@ _scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc,
* _scsih_change_queue_depth - setting device queue depth
* @sdev: scsi device struct
* @qdepth: requested queue depth
+ * @reason: calling context
*
* Returns queue depth.
*/
static int
-_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
+_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
{
struct Scsi_Host *shost = sdev->host;
int max_depth;
int tag_type;
+ struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+ struct MPT2SAS_DEVICE *sas_device_priv_data;
+ struct MPT2SAS_TARGET *sas_target_priv_data;
+ struct _sas_device *sas_device;
+ unsigned long flags;
+
+ if (reason != SCSI_QDEPTH_DEFAULT)
+ return -EOPNOTSUPP;
max_depth = shost->can_queue;
+
+ /* limit max device queue for SATA to 32 */
+ sas_device_priv_data = sdev->hostdata;
+ if (!sas_device_priv_data)
+ goto not_sata;
+ sas_target_priv_data = sas_device_priv_data->sas_target;
+ if (!sas_target_priv_data)
+ goto not_sata;
+ if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))
+ goto not_sata;
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
+ sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
+ sas_device_priv_data->sas_target->sas_address);
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+ if (sas_device && sas_device->device_info &
+ MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
+ max_depth = MPT2SAS_SATA_QUEUE_DEPTH;
+
+ not_sata:
+
if (!sdev->tagged_supported)
max_depth = 1;
if (qdepth > max_depth)
@@ -1488,7 +1573,7 @@ _scsih_slave_configure(struct scsi_device *sdev)
r_level, raid_device->handle,
(unsigned long long)raid_device->wwid,
raid_device->num_pds, ds);
- _scsih_change_queue_depth(sdev, qdepth);
+ _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT);
return 0;
}
@@ -1534,7 +1619,7 @@ _scsih_slave_configure(struct scsi_device *sdev)
_scsih_display_sata_capabilities(ioc, sas_device, sdev);
}
- _scsih_change_queue_depth(sdev, qdepth);
+ _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT);
if (ssp_target)
sas_read_port_mode_page(sdev);
@@ -1874,6 +1959,8 @@ _scsih_abort(struct scsi_cmnd *scmd)
goto out;
}
+ mpt2sas_halt_firmware(ioc);
+
mutex_lock(&ioc->tm_cmds.mutex);
handle = sas_device_priv_data->sas_target->handle;
mpt2sas_scsih_issue_tm(ioc, handle, sas_device_priv_data->lun,
@@ -2297,7 +2384,6 @@ _scsih_block_io_to_children_attached_directly(struct MPT2SAS_ADAPTER *ioc,
u16 handle;
u16 reason_code;
u8 phy_number;
- u8 link_rate;
for (i = 0; i < event_data->NumEntries; i++) {
handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
@@ -2308,11 +2394,6 @@ _scsih_block_io_to_children_attached_directly(struct MPT2SAS_ADAPTER *ioc,
MPI2_EVENT_SAS_TOPO_RC_MASK;
if (reason_code == MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING)
_scsih_block_io_device(ioc, handle);
- if (reason_code == MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED) {
- link_rate = event_data->PHY[i].LinkRate >> 4;
- if (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)
- _scsih_ublock_io_device(ioc, handle);
- }
}
}
@@ -2349,16 +2430,10 @@ _scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle)
spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
- if (!sas_device) {
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- printk(MPT2SAS_ERR_FMT "%s: failed finding sas_device\n",
- ioc->name, __func__);
- return;
- }
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
/* skip is hidden raid component */
- if (sas_device->hidden_raid_component)
+ if (sas_device && sas_device->hidden_raid_component)
return;
smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_cb_idx);
@@ -2371,18 +2446,31 @@ _scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle)
delayed_tr->state = MPT2SAS_REQ_SAS_CNTRL;
list_add_tail(&delayed_tr->list,
&ioc->delayed_tr_list);
- if (sas_device->starget)
+ if (sas_device && sas_device->starget) {
dewtprintk(ioc, starget_printk(KERN_INFO,
sas_device->starget, "DELAYED:tr:handle(0x%04x), "
- "(open)\n", sas_device->handle));
+ "(open)\n", handle));
+ } else {
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
+ "DELAYED:tr:handle(0x%04x), (open)\n",
+ ioc->name, handle));
+ }
return;
}
- if (sas_device->starget && sas_device->starget->hostdata) {
- sas_target_priv_data = sas_device->starget->hostdata;
- sas_target_priv_data->tm_busy = 1;
- dewtprintk(ioc, starget_printk(KERN_INFO, sas_device->starget,
- "tr:handle(0x%04x), (open)\n", sas_device->handle));
+ if (sas_device) {
+ sas_device->state |= MPTSAS_STATE_TR_SEND;
+ sas_device->state |= MPT2SAS_REQ_SAS_CNTRL;
+ if (sas_device->starget && sas_device->starget->hostdata) {
+ sas_target_priv_data = sas_device->starget->hostdata;
+ sas_target_priv_data->tm_busy = 1;
+ dewtprintk(ioc, starget_printk(KERN_INFO,
+ sas_device->starget, "tr:handle(0x%04x), (open)\n",
+ handle));
+ }
+ } else {
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
+ "tr:handle(0x%04x), (open)\n", ioc->name, handle));
}
mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
@@ -2390,8 +2478,6 @@ _scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle)
mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
mpi_request->DevHandle = cpu_to_le16(handle);
mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
- sas_device->state |= MPTSAS_STATE_TR_SEND;
- sas_device->state |= MPT2SAS_REQ_SAS_CNTRL;
mpt2sas_base_put_smid_hi_priority(ioc, smid);
}
@@ -2426,21 +2512,25 @@ _scsih_sas_control_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid,
spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
- if (!sas_device) {
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- printk(MPT2SAS_ERR_FMT "%s: failed finding sas_device\n",
- ioc->name, __func__);
- return 1;
- }
- sas_device->state |= MPTSAS_STATE_CNTRL_COMPLETE;
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- if (sas_device->starget)
- dewtprintk(ioc, starget_printk(KERN_INFO, sas_device->starget,
+ if (sas_device) {
+ sas_device->state |= MPTSAS_STATE_CNTRL_COMPLETE;
+ if (sas_device->starget)
+ dewtprintk(ioc, starget_printk(KERN_INFO,
+ sas_device->starget,
+ "sc_complete:handle(0x%04x), "
+ "ioc_status(0x%04x), loginfo(0x%08x)\n",
+ handle, le16_to_cpu(mpi_reply->IOCStatus),
+ le32_to_cpu(mpi_reply->IOCLogInfo)));
+ } else {
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
"sc_complete:handle(0x%04x), "
"ioc_status(0x%04x), loginfo(0x%08x)\n",
- handle, le16_to_cpu(mpi_reply->IOCStatus),
+ ioc->name, handle, le16_to_cpu(mpi_reply->IOCStatus),
le32_to_cpu(mpi_reply->IOCLogInfo)));
+ }
+
return 1;
}
@@ -2478,28 +2568,33 @@ _scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
handle = le16_to_cpu(mpi_reply->DevHandle);
spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
- if (!sas_device) {
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- printk(MPT2SAS_ERR_FMT "%s: failed finding sas_device\n",
- ioc->name, __func__);
- return 1;
- }
- sas_device->state |= MPTSAS_STATE_TR_COMPLETE;
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- if (sas_device->starget)
- dewtprintk(ioc, starget_printk(KERN_INFO, sas_device->starget,
- "tr_complete:handle(0x%04x), (%s) ioc_status(0x%04x), "
- "loginfo(0x%08x), completed(%d)\n",
- sas_device->handle, (sas_device->state &
- MPT2SAS_REQ_SAS_CNTRL) ? "open" : "active",
- le16_to_cpu(mpi_reply->IOCStatus),
+ if (sas_device) {
+ sas_device->state |= MPTSAS_STATE_TR_COMPLETE;
+ if (sas_device->starget) {
+ dewtprintk(ioc, starget_printk(KERN_INFO,
+ sas_device->starget, "tr_complete:handle(0x%04x), "
+ "(%s) ioc_status(0x%04x), loginfo(0x%08x), "
+ "completed(%d)\n", sas_device->handle,
+ (sas_device->state & MPT2SAS_REQ_SAS_CNTRL) ?
+ "open" : "active",
+ le16_to_cpu(mpi_reply->IOCStatus),
+ le32_to_cpu(mpi_reply->IOCLogInfo),
+ le32_to_cpu(mpi_reply->TerminationCount)));
+ if (sas_device->starget->hostdata) {
+ sas_target_priv_data =
+ sas_device->starget->hostdata;
+ sas_target_priv_data->tm_busy = 0;
+ }
+ }
+ } else {
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
+ "tr_complete:handle(0x%04x), (open) ioc_status(0x%04x), "
+ "loginfo(0x%08x), completed(%d)\n", ioc->name,
+ handle, le16_to_cpu(mpi_reply->IOCStatus),
le32_to_cpu(mpi_reply->IOCLogInfo),
le32_to_cpu(mpi_reply->TerminationCount)));
-
- if (sas_device->starget && sas_device->starget->hostdata) {
- sas_target_priv_data = sas_device->starget->hostdata;
- sas_target_priv_data->tm_busy = 0;
}
if (!list_empty(&ioc->delayed_tr_list)) {
@@ -2514,8 +2609,7 @@ _scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
} else
rc = 1;
-
- if (!(sas_device->state & MPT2SAS_REQ_SAS_CNTRL))
+ if (sas_device && !(sas_device->state & MPT2SAS_REQ_SAS_CNTRL))
return rc;
if (ioc->shost_recovery) {
@@ -2531,12 +2625,14 @@ _scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
return rc;
}
+ if (sas_device)
+ sas_device->state |= MPTSAS_STATE_CNTRL_SEND;
+
mpi_request = mpt2sas_base_get_msg_frame(ioc, smid_sas_ctrl);
memset(mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));
mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE;
mpi_request->DevHandle = mpi_reply->DevHandle;
- sas_device->state |= MPTSAS_STATE_CNTRL_SEND;
mpt2sas_base_put_smid_default(ioc, smid_sas_ctrl);
return rc;
}
@@ -2678,8 +2774,6 @@ _scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request)
else
return;
- mpi_request->EEDPBlockSize = scmd->device->sector_size;
-
switch (prot_type) {
case SCSI_PROT_DIF_TYPE1:
@@ -2687,8 +2781,7 @@ _scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request)
* enable ref/guard checking
* auto increment ref tag
*/
- mpi_request->EEDPFlags = eedp_flags |
- MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
+ eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
mpi_request->CDB.EEDP32.PrimaryReferenceTag =
@@ -2701,11 +2794,11 @@ _scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request)
/*
* enable guard checking
*/
- mpi_request->EEDPFlags = eedp_flags |
- MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
-
+ eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
break;
}
+ mpi_request->EEDPBlockSize = cpu_to_le32(scmd->device->sector_size);
+ mpi_request->EEDPFlags = cpu_to_le16(eedp_flags);
}
/**
@@ -2788,7 +2881,7 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
}
/* see if we are busy with task managment stuff */
- if (sas_target_priv_data->tm_busy)
+ if (sas_device_priv_data->block || sas_target_priv_data->tm_busy)
return SCSI_MLQUEUE_DEVICE_BUSY;
else if (ioc->shost_recovery || ioc->ioc_link_reset_in_progress)
return SCSI_MLQUEUE_HOST_BUSY;
@@ -2842,7 +2935,7 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
mpi_request->MsgFlags = MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR;
mpi_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE;
mpi_request->SenseBufferLowAddress =
- (u32)mpt2sas_base_get_sense_buffer_dma(ioc, smid);
+ mpt2sas_base_get_sense_buffer_dma(ioc, smid);
mpi_request->SGLOffset0 = offsetof(Mpi2SCSIIORequest_t, SGL) / 4;
mpi_request->SGLFlags = cpu_to_le16(MPI2_SCSIIO_SGLFLAGS_TYPE_MPI +
MPI2_SCSIIO_SGLFLAGS_SYSTEM_ADDR);
@@ -2894,7 +2987,7 @@ _scsih_normalize_sense(char *sense_buffer, struct sense_info *data)
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
/**
- * _scsih_scsi_ioc_info - translated non-succesfull SCSI_IO request
+ * _scsih_scsi_ioc_info - translated non-successfull SCSI_IO request
* @ioc: per adapter object
* @scmd: pointer to scsi command object
* @mpi_reply: reply mf payload returned from firmware
@@ -3059,7 +3152,7 @@ _scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) {
response_info = le32_to_cpu(mpi_reply->ResponseInfo);
response_bytes = (u8 *)&response_info;
- _scsih_response_code(ioc, response_bytes[3]);
+ _scsih_response_code(ioc, response_bytes[0]);
}
}
#endif
@@ -3177,7 +3270,7 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
u8 scsi_status;
u32 log_info;
struct MPT2SAS_DEVICE *sas_device_priv_data;
- u32 response_code;
+ u32 response_code = 0;
mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
scmd = _scsih_scsi_lookup_get(ioc, smid);
@@ -3199,16 +3292,16 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
}
/* turning off TLR */
+ scsi_state = mpi_reply->SCSIState;
+ if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID)
+ response_code =
+ le32_to_cpu(mpi_reply->ResponseInfo) & 0xFF;
if (!sas_device_priv_data->tlr_snoop_check) {
sas_device_priv_data->tlr_snoop_check++;
- if (sas_device_priv_data->flags & MPT_DEVICE_TLR_ON) {
- response_code = (le32_to_cpu(mpi_reply->ResponseInfo)
- >> 24);
- if (response_code ==
- MPI2_SCSITASKMGMT_RSP_INVALID_FRAME)
- sas_device_priv_data->flags &=
- ~MPT_DEVICE_TLR_ON;
- }
+ if ((sas_device_priv_data->flags & MPT_DEVICE_TLR_ON) &&
+ response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME)
+ sas_device_priv_data->flags &=
+ ~MPT_DEVICE_TLR_ON;
}
xfer_cnt = le32_to_cpu(mpi_reply->TransferCount);
@@ -3219,7 +3312,6 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
else
log_info = 0;
ioc_status &= MPI2_IOCSTATUS_MASK;
- scsi_state = mpi_reply->SCSIState;
scsi_status = mpi_reply->SCSIStatus;
if (ioc_status == MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
@@ -3255,10 +3347,9 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
if (sas_device_priv_data->block) {
- scmd->result = (DID_BUS_BUSY << 16);
- break;
+ scmd->result = DID_TRANSPORT_DISRUPTED << 16;
+ goto out;
}
-
case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
scmd->result = DID_RESET << 16;
@@ -3304,8 +3395,10 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
case MPI2_IOCSTATUS_SUCCESS:
scmd->result = (DID_OK << 16) | scsi_status;
- if (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED |
- MPI2_SCSI_STATE_NO_SCSI_STATUS))
+ if (response_code ==
+ MPI2_SCSITASKMGMT_RSP_INVALID_FRAME ||
+ (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED |
+ MPI2_SCSI_STATE_NO_SCSI_STATUS)))
scmd->result = DID_SOFT_ERROR << 16;
else if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
scmd->result = DID_RESET << 16;
@@ -3344,7 +3437,6 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
/**
* _scsih_sas_host_refresh - refreshing sas host object contents
* @ioc: per adapter object
- * @update: update link information
* Context: user
*
* During port enable, fw will send topology events for every device. Its
@@ -3354,13 +3446,14 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
* Return nothing.
*/
static void
-_scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc, u8 update)
+_scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc)
{
u16 sz;
u16 ioc_status;
int i;
Mpi2ConfigReply_t mpi_reply;
Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
+ u16 attached_handle;
dtmprintk(ioc, printk(MPT2SAS_INFO_FMT
"updating handles for sas_host(0x%016llx)\n",
@@ -3374,27 +3467,24 @@ _scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc, u8 update)
ioc->name, __FILE__, __LINE__, __func__);
return;
}
- if (!(mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
- sas_iounit_pg0, sz))) {
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
- goto out;
- for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
- ioc->sas_hba.phy[i].handle =
- le16_to_cpu(sas_iounit_pg0->PhyData[i].
- ControllerDevHandle);
- if (update)
- mpt2sas_transport_update_links(
- ioc,
- ioc->sas_hba.phy[i].handle,
- le16_to_cpu(sas_iounit_pg0->PhyData[i].
- AttachedDevHandle), i,
- sas_iounit_pg0->PhyData[i].
- NegotiatedLinkRate >> 4);
- }
- }
+ if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
+ sas_iounit_pg0, sz)) != 0)
+ goto out;
+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
+ goto out;
+ for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
+ if (i == 0)
+ ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0->
+ PhyData[0].ControllerDevHandle);
+ ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle;
+ attached_handle = le16_to_cpu(sas_iounit_pg0->PhyData[i].
+ AttachedDevHandle);
+ mpt2sas_transport_update_links(ioc, ioc->sas_hba.sas_address,
+ attached_handle, i, sas_iounit_pg0->PhyData[i].
+ NegotiatedLinkRate >> 4);
+ }
out:
kfree(sas_iounit_pg0);
}
@@ -3507,19 +3597,21 @@ _scsih_sas_host_add(struct MPT2SAS_ADAPTER *ioc)
ioc->name, __FILE__, __LINE__, __func__);
goto out;
}
- ioc->sas_hba.phy[i].handle =
- le16_to_cpu(sas_iounit_pg0->PhyData[i].ControllerDevHandle);
+
+ if (i == 0)
+ ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0->
+ PhyData[0].ControllerDevHandle);
+ ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle;
ioc->sas_hba.phy[i].phy_id = i;
mpt2sas_transport_add_host_phy(ioc, &ioc->sas_hba.phy[i],
phy_pg0, ioc->sas_hba.parent_dev);
}
if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
- MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, ioc->sas_hba.phy[0].handle))) {
+ MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, ioc->sas_hba.handle))) {
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
goto out;
}
- ioc->sas_hba.handle = le16_to_cpu(sas_device_pg0.DevHandle);
ioc->sas_hba.enclosure_handle =
le16_to_cpu(sas_device_pg0.EnclosureHandle);
ioc->sas_hba.sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
@@ -3562,7 +3654,7 @@ _scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle)
Mpi2SasEnclosurePage0_t enclosure_pg0;
u32 ioc_status;
u16 parent_handle;
- __le64 sas_address;
+ __le64 sas_address, sas_address_parent = 0;
int i;
unsigned long flags;
struct _sas_port *mpt2sas_port = NULL;
@@ -3591,10 +3683,16 @@ _scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle)
/* handle out of order topology events */
parent_handle = le16_to_cpu(expander_pg0.ParentDevHandle);
- if (parent_handle >= ioc->sas_hba.num_phys) {
+ if (_scsih_get_sas_address(ioc, parent_handle, &sas_address_parent)
+ != 0) {
+ printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+ ioc->name, __FILE__, __LINE__, __func__);
+ return -1;
+ }
+ if (sas_address_parent != ioc->sas_hba.sas_address) {
spin_lock_irqsave(&ioc->sas_node_lock, flags);
- sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
- parent_handle);
+ sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
+ sas_address_parent);
spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
if (!sas_expander) {
rc = _scsih_expander_add(ioc, parent_handle);
@@ -3622,14 +3720,12 @@ _scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle)
sas_expander->handle = handle;
sas_expander->num_phys = expander_pg0.NumPhys;
- sas_expander->parent_handle = parent_handle;
- sas_expander->enclosure_handle =
- le16_to_cpu(expander_pg0.EnclosureHandle);
+ sas_expander->sas_address_parent = sas_address_parent;
sas_expander->sas_address = sas_address;
printk(MPT2SAS_INFO_FMT "expander_add: handle(0x%04x),"
" parent(0x%04x), sas_addr(0x%016llx), phys(%d)\n", ioc->name,
- handle, sas_expander->parent_handle, (unsigned long long)
+ handle, parent_handle, (unsigned long long)
sas_expander->sas_address, sas_expander->num_phys);
if (!sas_expander->num_phys)
@@ -3645,7 +3741,7 @@ _scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle)
INIT_LIST_HEAD(&sas_expander->sas_port_list);
mpt2sas_port = mpt2sas_transport_port_add(ioc, handle,
- sas_expander->parent_handle);
+ sas_address_parent);
if (!mpt2sas_port) {
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
@@ -3691,20 +3787,54 @@ _scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle)
if (mpt2sas_port)
mpt2sas_transport_port_remove(ioc, sas_expander->sas_address,
- sas_expander->parent_handle);
+ sas_address_parent);
kfree(sas_expander);
return rc;
}
/**
+ * _scsih_done - scsih callback handler.
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @msix_index: MSIX table index supplied by the OS
+ * @reply: reply message frame(lower 32bit addr)
+ *
+ * Callback handler when sending internal generated message frames.
+ * The callback index passed is `ioc->scsih_cb_idx`
+ *
+ * Return 1 meaning mf should be freed from _base_interrupt
+ * 0 means the mf is freed from this function.
+ */
+static u8
+_scsih_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
+{
+ MPI2DefaultReply_t *mpi_reply;
+
+ mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
+ if (ioc->scsih_cmds.status == MPT2_CMD_NOT_USED)
+ return 1;
+ if (ioc->scsih_cmds.smid != smid)
+ return 1;
+ ioc->scsih_cmds.status |= MPT2_CMD_COMPLETE;
+ if (mpi_reply) {
+ memcpy(ioc->scsih_cmds.reply, mpi_reply,
+ mpi_reply->MsgLength*4);
+ ioc->scsih_cmds.status |= MPT2_CMD_REPLY_VALID;
+ }
+ ioc->scsih_cmds.status &= ~MPT2_CMD_PENDING;
+ complete(&ioc->scsih_cmds.done);
+ return 1;
+}
+
+/**
* _scsih_expander_remove - removing expander object
* @ioc: per adapter object
- * @handle: expander handle
+ * @sas_address: expander sas_address
*
* Return nothing.
*/
static void
-_scsih_expander_remove(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+_scsih_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
{
struct _sas_node *sas_expander;
unsigned long flags;
@@ -3713,7 +3843,8 @@ _scsih_expander_remove(struct MPT2SAS_ADAPTER *ioc, u16 handle)
return;
spin_lock_irqsave(&ioc->sas_node_lock, flags);
- sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc, handle);
+ sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
+ sas_address);
spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
_scsih_expander_node_remove(ioc, sas_expander);
}
@@ -3805,8 +3936,11 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd)
}
sas_device->handle = handle;
- sas_device->parent_handle =
- le16_to_cpu(sas_device_pg0.ParentDevHandle);
+ if (_scsih_get_sas_address(ioc, le16_to_cpu
+ (sas_device_pg0.ParentDevHandle),
+ &sas_device->sas_address_parent) != 0)
+ printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+ ioc->name, __FILE__, __LINE__, __func__);
sas_device->enclosure_handle =
le16_to_cpu(sas_device_pg0.EnclosureHandle);
sas_device->slot =
@@ -3836,43 +3970,39 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd)
/**
* _scsih_remove_device - removing sas device object
* @ioc: per adapter object
- * @handle: sas device handle
+ * @sas_device: the sas_device object
*
* Return nothing.
*/
static void
-_scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+_scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, struct _sas_device
+ *sas_device)
{
struct MPT2SAS_TARGET *sas_target_priv_data;
- struct _sas_device *sas_device;
- unsigned long flags;
Mpi2SasIoUnitControlReply_t mpi_reply;
Mpi2SasIoUnitControlRequest_t mpi_request;
- u16 device_handle;
+ u16 device_handle, handle;
- /* lookup sas_device */
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
- if (!sas_device) {
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+ if (!sas_device)
return;
- }
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: handle"
- "(0x%04x)\n", ioc->name, __func__, handle));
+ handle = sas_device->handle;
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: handle(0x%04x),"
+ " sas_addr(0x%016llx)\n", ioc->name, __func__, handle,
+ (unsigned long long) sas_device->sas_address));
if (sas_device->starget && sas_device->starget->hostdata) {
sas_target_priv_data = sas_device->starget->hostdata;
sas_target_priv_data->deleted = 1;
}
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- if (ioc->remove_host)
+ if (ioc->remove_host || ioc->shost_recovery || !handle)
goto out;
if ((sas_device->state & MPTSAS_STATE_TR_COMPLETE)) {
dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "\tskip "
- "target_reset handle(0x%04x)\n", ioc->name, handle));
+ "target_reset handle(0x%04x)\n", ioc->name,
+ handle));
goto skip_tr;
}
@@ -3925,10 +4055,10 @@ _scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
_scsih_ublock_io_device(ioc, handle);
mpt2sas_transport_port_remove(ioc, sas_device->sas_address,
- sas_device->parent_handle);
+ sas_device->sas_address_parent);
printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr"
- "(0x%016llx)\n", ioc->name, sas_device->handle,
+ "(0x%016llx)\n", ioc->name, handle,
(unsigned long long) sas_device->sas_address);
_scsih_sas_device_remove(ioc, sas_device);
@@ -3952,7 +4082,7 @@ _scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
u16 reason_code;
u8 phy_number;
char *status_str = NULL;
- char link_rate[25];
+ u8 link_rate, prev_link_rate;
switch (event_data->ExpStatus) {
case MPI2_EVENT_SAS_TOPO_ES_ADDED:
@@ -3962,6 +4092,7 @@ _scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
status_str = "remove";
break;
case MPI2_EVENT_SAS_TOPO_ES_RESPONDING:
+ case 0:
status_str = "responding";
break;
case MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING:
@@ -3987,30 +4118,30 @@ _scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
MPI2_EVENT_SAS_TOPO_RC_MASK;
switch (reason_code) {
case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
- snprintf(link_rate, 25, ": add, link(0x%02x)",
- (event_data->PHY[i].LinkRate >> 4));
- status_str = link_rate;
+ status_str = "target add";
break;
case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
- status_str = ": remove";
+ status_str = "target remove";
break;
case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING:
- status_str = ": remove_delay";
+ status_str = "delay target remove";
break;
case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
- snprintf(link_rate, 25, ": link(0x%02x)",
- (event_data->PHY[i].LinkRate >> 4));
- status_str = link_rate;
+ status_str = "link rate change";
break;
case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE:
- status_str = ": responding";
+ status_str = "target responding";
break;
default:
- status_str = ": unknown";
+ status_str = "unknown";
break;
}
- printk(KERN_DEBUG "\tphy(%02d), attached_handle(0x%04x)%s\n",
- phy_number, handle, status_str);
+ link_rate = event_data->PHY[i].LinkRate >> 4;
+ prev_link_rate = event_data->PHY[i].LinkRate & 0xF;
+ printk(KERN_DEBUG "\tphy(%02d), attached_handle(0x%04x): %s:"
+ " link rate: new(0x%02x), old(0x%02x)\n", phy_number,
+ handle, status_str, link_rate, prev_link_rate);
+
}
}
#endif
@@ -4031,8 +4162,10 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
u16 reason_code;
u8 phy_number;
struct _sas_node *sas_expander;
+ struct _sas_device *sas_device;
+ u64 sas_address;
unsigned long flags;
- u8 link_rate_;
+ u8 link_rate, prev_link_rate;
Mpi2EventDataSasTopologyChangeList_t *event_data = fw_event->event_data;
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
@@ -4040,10 +4173,13 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
_scsih_sas_topology_change_event_debug(ioc, event_data);
#endif
+ if (ioc->shost_recovery)
+ return;
+
if (!ioc->sas_hba.num_phys)
_scsih_sas_host_add(ioc);
else
- _scsih_sas_host_refresh(ioc, 0);
+ _scsih_sas_host_refresh(ioc);
if (fw_event->ignore) {
dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ignoring expander "
@@ -4058,6 +4194,17 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
if (_scsih_expander_add(ioc, parent_handle) != 0)
return;
+ spin_lock_irqsave(&ioc->sas_node_lock, flags);
+ sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
+ parent_handle);
+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
+ if (sas_expander)
+ sas_address = sas_expander->sas_address;
+ else if (parent_handle < ioc->sas_hba.num_phys)
+ sas_address = ioc->sas_hba.sas_address;
+ else
+ return;
+
/* handle siblings events */
for (i = 0; i < event_data->NumEntries; i++) {
if (fw_event->ignore) {
@@ -4077,48 +4224,47 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
if (!handle)
continue;
- link_rate_ = event_data->PHY[i].LinkRate >> 4;
+ link_rate = event_data->PHY[i].LinkRate >> 4;
+ prev_link_rate = event_data->PHY[i].LinkRate & 0xF;
switch (reason_code) {
case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
+
+ if (link_rate == prev_link_rate)
+ break;
+
+ mpt2sas_transport_update_links(ioc, sas_address,
+ handle, phy_number, link_rate);
+
+ if (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)
+ _scsih_ublock_io_device(ioc, handle);
+ break;
case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
- if (!parent_handle) {
- if (phy_number < ioc->sas_hba.num_phys)
- mpt2sas_transport_update_links(
- ioc,
- ioc->sas_hba.phy[phy_number].handle,
- handle, phy_number, link_rate_);
- } else {
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- sas_expander =
- mpt2sas_scsih_expander_find_by_handle(ioc,
- parent_handle);
- spin_unlock_irqrestore(&ioc->sas_node_lock,
- flags);
- if (sas_expander) {
- if (phy_number < sas_expander->num_phys)
- mpt2sas_transport_update_links(
- ioc,
- sas_expander->
- phy[phy_number].handle,
- handle, phy_number,
- link_rate_);
- }
- }
- if (reason_code == MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED) {
- if (link_rate_ < MPI2_SAS_NEG_LINK_RATE_1_5)
- break;
- _scsih_add_device(ioc, handle, phy_number, 0);
- }
+
+ mpt2sas_transport_update_links(ioc, sas_address,
+ handle, phy_number, link_rate);
+
+ _scsih_add_device(ioc, handle, phy_number, 0);
break;
case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
- _scsih_remove_device(ioc, handle);
+
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
+ sas_device = _scsih_sas_device_find_by_handle(ioc,
+ handle);
+ if (!sas_device) {
+ spin_unlock_irqrestore(&ioc->sas_device_lock,
+ flags);
+ break;
+ }
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+ _scsih_remove_device(ioc, sas_device);
break;
}
}
/* handle expander removal */
- if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING)
- _scsih_expander_remove(ioc, parent_handle);
+ if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING &&
+ sas_expander)
+ _scsih_expander_remove(ioc, sas_address);
}
@@ -4170,6 +4316,12 @@ _scsih_sas_device_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
case MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION:
reason_str = "internal async notification";
break;
+ case MPI2_EVENT_SAS_DEV_STAT_RC_EXPANDER_REDUCED_FUNCTIONALITY:
+ reason_str = "expander reduced functionality";
+ break;
+ case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_EXPANDER_REDUCED_FUNCTIONALITY:
+ reason_str = "expander reduced functionality complete";
+ break;
default:
reason_str = "unknown reason";
break;
@@ -4197,11 +4349,43 @@ static void
_scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc,
struct fw_event_work *fw_event)
{
+ struct MPT2SAS_TARGET *target_priv_data;
+ struct _sas_device *sas_device;
+ __le64 sas_address;
+ unsigned long flags;
+ Mpi2EventDataSasDeviceStatusChange_t *event_data =
+ fw_event->event_data;
+
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
_scsih_sas_device_status_change_event_debug(ioc,
- fw_event->event_data);
+ event_data);
#endif
+
+ if (!(event_data->ReasonCode ==
+ MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET &&
+ event_data->ReasonCode ==
+ MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET))
+ return;
+
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
+ sas_address = le64_to_cpu(event_data->SASAddress);
+ sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
+ sas_address);
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+
+ if (!sas_device || !sas_device->starget)
+ return;
+
+ target_priv_data = sas_device->starget->hostdata;
+ if (!target_priv_data)
+ return;
+
+ if (event_data->ReasonCode ==
+ MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET)
+ target_priv_data->tm_busy = 1;
+ else
+ target_priv_data->tm_busy = 0;
}
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
@@ -4281,6 +4465,7 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
Mpi2EventDataSasBroadcastPrimitive_t *event_data = fw_event->event_data;
#endif
+ u16 ioc_status;
dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "broadcast primative: "
"phy number(%d), width(%d)\n", ioc->name, event_data->PhyNum,
event_data->PortWidth));
@@ -4314,8 +4499,9 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,
mpt2sas_scsih_issue_tm(ioc, handle, lun,
MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30);
ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
-
- if ((mpi_reply->IOCStatus == MPI2_IOCSTATUS_SUCCESS) &&
+ ioc_status = le16_to_cpu(mpi_reply->IOCStatus)
+ & MPI2_IOCSTATUS_MASK;
+ if ((ioc_status == MPI2_IOCSTATUS_SUCCESS) &&
(mpi_reply->ResponseCode ==
MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
mpi_reply->ResponseCode ==
@@ -4570,7 +4756,7 @@ _scsih_sas_pd_delete(struct MPT2SAS_ADAPTER *ioc,
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
if (!sas_device)
return;
- _scsih_remove_device(ioc, handle);
+ _scsih_remove_device(ioc, sas_device);
}
/**
@@ -4591,6 +4777,8 @@ _scsih_sas_pd_add(struct MPT2SAS_ADAPTER *ioc,
Mpi2ConfigReply_t mpi_reply;
Mpi2SasDevicePage0_t sas_device_pg0;
u32 ioc_status;
+ u64 sas_address;
+ u16 parent_handle;
spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
@@ -4615,9 +4803,10 @@ _scsih_sas_pd_add(struct MPT2SAS_ADAPTER *ioc,
return;
}
- mpt2sas_transport_update_links(ioc,
- le16_to_cpu(sas_device_pg0.ParentDevHandle),
- handle, sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
+ parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
+ if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address))
+ mpt2sas_transport_update_links(ioc, sas_address, handle,
+ sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
_scsih_add_device(ioc, handle, 0, 1);
}
@@ -4857,7 +5046,7 @@ static void
_scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc,
struct fw_event_work *fw_event)
{
- u16 handle;
+ u16 handle, parent_handle;
u32 state;
struct _sas_device *sas_device;
unsigned long flags;
@@ -4865,6 +5054,7 @@ _scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc,
Mpi2SasDevicePage0_t sas_device_pg0;
u32 ioc_status;
Mpi2EventDataIrPhysicalDisk_t *event_data = fw_event->event_data;
+ u64 sas_address;
if (event_data->ReasonCode != MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED)
return;
@@ -4906,9 +5096,10 @@ _scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc,
return;
}
- mpt2sas_transport_update_links(ioc,
- le16_to_cpu(sas_device_pg0.ParentDevHandle),
- handle, sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
+ parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
+ if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address))
+ mpt2sas_transport_update_links(ioc, sas_address, handle,
+ sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
_scsih_add_device(ioc, handle, 0, 1);
@@ -4948,11 +5139,17 @@ _scsih_sas_ir_operation_status_event_debug(struct MPT2SAS_ADAPTER *ioc,
case MPI2_EVENT_IR_RAIDOP_CONSISTENCY_CHECK:
reason_str = "consistency check";
break;
- default:
- reason_str = "unknown reason";
+ case MPI2_EVENT_IR_RAIDOP_BACKGROUND_INIT:
+ reason_str = "background init";
+ break;
+ case MPI2_EVENT_IR_RAIDOP_MAKE_DATA_CONSISTENT:
+ reason_str = "make data consistent";
break;
}
+ if (!reason_str)
+ return;
+
printk(MPT2SAS_INFO_FMT "raid operational status: (%s)"
"\thandle(0x%04x), percent complete(%d)\n",
ioc->name, reason_str,
@@ -5252,18 +5449,23 @@ _scsih_mark_responding_expander(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
{
struct _sas_node *sas_expander;
unsigned long flags;
+ int i;
spin_lock_irqsave(&ioc->sas_node_lock, flags);
list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
- if (sas_expander->sas_address == sas_address) {
- sas_expander->responding = 1;
- if (sas_expander->handle != handle) {
- printk(KERN_INFO "old handle(0x%04x)\n",
- sas_expander->handle);
- sas_expander->handle = handle;
- }
+ if (sas_expander->sas_address != sas_address)
+ continue;
+ sas_expander->responding = 1;
+ if (sas_expander->handle == handle)
goto out;
- }
+ printk(KERN_INFO "\texpander(0x%016llx): handle changed"
+ " from(0x%04x) to (0x%04x)!!!\n",
+ (unsigned long long)sas_expander->sas_address,
+ sas_expander->handle, handle);
+ sas_expander->handle = handle;
+ for (i = 0 ; i < sas_expander->num_phys ; i++)
+ sas_expander->phy[i].handle = handle;
+ goto out;
}
out:
spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
@@ -5340,7 +5542,9 @@ _scsih_remove_unresponding_devices(struct MPT2SAS_ADAPTER *ioc)
(unsigned long long)
sas_device->enclosure_logical_id,
sas_device->slot);
- _scsih_remove_device(ioc, sas_device->handle);
+ /* invalidate the device handle */
+ sas_device->handle = 0;
+ _scsih_remove_device(ioc, sas_device);
}
list_for_each_entry_safe(raid_device, raid_device_next,
@@ -5366,7 +5570,7 @@ _scsih_remove_unresponding_devices(struct MPT2SAS_ADAPTER *ioc)
sas_expander->responding = 0;
continue;
}
- _scsih_expander_remove(ioc, sas_expander->handle);
+ _scsih_expander_remove(ioc, sas_expander->sas_address);
goto retry_expander_search;
}
}
@@ -5406,7 +5610,7 @@ mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
case MPT2_IOC_DONE_RESET:
dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
"MPT2_IOC_DONE_RESET\n", ioc->name, __func__));
- _scsih_sas_host_refresh(ioc, 0);
+ _scsih_sas_host_refresh(ioc);
_scsih_search_responding_sas_devices(ioc);
_scsih_search_responding_raid_devices(ioc);
_scsih_search_responding_expanders(ioc);
@@ -5646,7 +5850,7 @@ _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
if (!sas_device)
continue;
- _scsih_remove_device(ioc, sas_device->handle);
+ _scsih_remove_device(ioc, sas_device);
if (ioc->shost_recovery)
return;
goto retry_device_search;
@@ -5669,7 +5873,8 @@ _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
if (!expander_sibling)
continue;
- _scsih_expander_remove(ioc, expander_sibling->handle);
+ _scsih_expander_remove(ioc,
+ expander_sibling->sas_address);
if (ioc->shost_recovery)
return;
goto retry_expander_search;
@@ -5677,7 +5882,7 @@ _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
}
mpt2sas_transport_port_remove(ioc, sas_expander->sas_address,
- sas_expander->parent_handle);
+ sas_expander->sas_address_parent);
printk(MPT2SAS_INFO_FMT "expander_remove: handle"
"(0x%04x), sas_addr(0x%016llx)\n", ioc->name,
@@ -5690,9 +5895,99 @@ _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
}
/**
+ * _scsih_ir_shutdown - IR shutdown notification
+ * @ioc: per adapter object
+ *
+ * Sending RAID Action to alert the Integrated RAID subsystem of the IOC that
+ * the host system is shutting down.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_ir_shutdown(struct MPT2SAS_ADAPTER *ioc)
+{
+ Mpi2RaidActionRequest_t *mpi_request;
+ Mpi2RaidActionReply_t *mpi_reply;
+ u16 smid;
+
+ /* is IR firmware build loaded ? */
+ if (!ioc->ir_firmware)
+ return;
+
+ /* are there any volumes ? */
+ if (list_empty(&ioc->raid_device_list))
+ return;
+
+ mutex_lock(&ioc->scsih_cmds.mutex);
+
+ if (ioc->scsih_cmds.status != MPT2_CMD_NOT_USED) {
+ printk(MPT2SAS_ERR_FMT "%s: scsih_cmd in use\n",
+ ioc->name, __func__);
+ goto out;
+ }
+ ioc->scsih_cmds.status = MPT2_CMD_PENDING;
+
+ smid = mpt2sas_base_get_smid(ioc, ioc->scsih_cb_idx);
+ if (!smid) {
+ printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
+ ioc->name, __func__);
+ ioc->scsih_cmds.status = MPT2_CMD_NOT_USED;
+ goto out;
+ }
+
+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
+ ioc->scsih_cmds.smid = smid;
+ memset(mpi_request, 0, sizeof(Mpi2RaidActionRequest_t));
+
+ mpi_request->Function = MPI2_FUNCTION_RAID_ACTION;
+ mpi_request->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED;
+
+ printk(MPT2SAS_INFO_FMT "IR shutdown (sending)\n", ioc->name);
+ init_completion(&ioc->scsih_cmds.done);
+ mpt2sas_base_put_smid_default(ioc, smid);
+ wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ);
+
+ if (!(ioc->scsih_cmds.status & MPT2_CMD_COMPLETE)) {
+ printk(MPT2SAS_ERR_FMT "%s: timeout\n",
+ ioc->name, __func__);
+ goto out;
+ }
+
+ if (ioc->scsih_cmds.status & MPT2_CMD_REPLY_VALID) {
+ mpi_reply = ioc->scsih_cmds.reply;
+
+ printk(MPT2SAS_INFO_FMT "IR shutdown (complete): "
+ "ioc_status(0x%04x), loginfo(0x%08x)\n",
+ ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
+ le32_to_cpu(mpi_reply->IOCLogInfo));
+ }
+
+ out:
+ ioc->scsih_cmds.status = MPT2_CMD_NOT_USED;
+ mutex_unlock(&ioc->scsih_cmds.mutex);
+}
+
+/**
+ * _scsih_shutdown - routine call during system shutdown
+ * @pdev: PCI device struct
+ *
+ * Return nothing.
+ */
+static void
+_scsih_shutdown(struct pci_dev *pdev)
+{
+ struct Scsi_Host *shost = pci_get_drvdata(pdev);
+ struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+
+ _scsih_ir_shutdown(ioc);
+ mpt2sas_base_detach(ioc);
+}
+
+/**
* _scsih_remove - detach and remove add host
* @pdev: PCI device struct
*
+ * Routine called when unloading the driver.
* Return nothing.
*/
static void __devexit
@@ -5726,7 +6021,7 @@ _scsih_remove(struct pci_dev *pdev)
mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
mpt2sas_port->remote_identify.sas_address);
if (sas_device) {
- _scsih_remove_device(ioc, sas_device->handle);
+ _scsih_remove_device(ioc, sas_device);
goto retry_again;
}
} else {
@@ -5735,7 +6030,7 @@ _scsih_remove(struct pci_dev *pdev)
mpt2sas_port->remote_identify.sas_address);
if (expander_sibling) {
_scsih_expander_remove(ioc,
- expander_sibling->handle);
+ expander_sibling->sas_address);
goto retry_again;
}
}
@@ -5749,7 +6044,7 @@ _scsih_remove(struct pci_dev *pdev)
}
sas_remove_host(shost);
- mpt2sas_base_detach(ioc);
+ _scsih_shutdown(pdev);
list_del(&ioc->list);
scsi_remove_host(shost);
scsi_host_put(shost);
@@ -5770,7 +6065,8 @@ _scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc)
void *device;
struct _sas_device *sas_device;
struct _raid_device *raid_device;
- u16 handle, parent_handle;
+ u16 handle;
+ u64 sas_address_parent;
u64 sas_address;
unsigned long flags;
int rc;
@@ -5799,17 +6095,17 @@ _scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc)
} else {
sas_device = device;
handle = sas_device->handle;
- parent_handle = sas_device->parent_handle;
+ sas_address_parent = sas_device->sas_address_parent;
sas_address = sas_device->sas_address;
spin_lock_irqsave(&ioc->sas_device_lock, flags);
list_move_tail(&sas_device->list, &ioc->sas_device_list);
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
- sas_device->parent_handle)) {
+ sas_device->sas_address_parent)) {
_scsih_sas_device_remove(ioc, sas_device);
} else if (!sas_device->starget) {
mpt2sas_transport_port_remove(ioc, sas_address,
- parent_handle);
+ sas_address_parent);
_scsih_sas_device_remove(ioc, sas_device);
}
}
@@ -5849,8 +6145,6 @@ _scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc)
{
struct _sas_device *sas_device, *next;
unsigned long flags;
- u16 handle, parent_handle;
- u64 sas_address;
/* SAS Device List */
list_for_each_entry_safe(sas_device, next, &ioc->sas_device_init_list,
@@ -5859,14 +6153,13 @@ _scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc)
list_move_tail(&sas_device->list, &ioc->sas_device_list);
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- handle = sas_device->handle;
- parent_handle = sas_device->parent_handle;
- sas_address = sas_device->sas_address;
- if (!mpt2sas_transport_port_add(ioc, handle, parent_handle)) {
+ if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
+ sas_device->sas_address_parent)) {
_scsih_sas_device_remove(ioc, sas_device);
} else if (!sas_device->starget) {
- mpt2sas_transport_port_remove(ioc, sas_address,
- parent_handle);
+ mpt2sas_transport_port_remove(ioc,
+ sas_device->sas_address,
+ sas_device->sas_address_parent);
_scsih_sas_device_remove(ioc, sas_device);
}
}
@@ -5935,6 +6228,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ioc->ctl_cb_idx = ctl_cb_idx;
ioc->base_cb_idx = base_cb_idx;
ioc->transport_cb_idx = transport_cb_idx;
+ ioc->scsih_cb_idx = scsih_cb_idx;
ioc->config_cb_idx = config_cb_idx;
ioc->tm_tr_cb_idx = tm_tr_cb_idx;
ioc->tm_sas_control_cb_idx = tm_sas_control_cb_idx;
@@ -6072,6 +6366,7 @@ static struct pci_driver scsih_driver = {
.id_table = scsih_pci_table,
.probe = _scsih_probe,
.remove = __devexit_p(_scsih_remove),
+ .shutdown = _scsih_shutdown,
#ifdef CONFIG_PM
.suspend = _scsih_suspend,
.resume = _scsih_resume,
@@ -6113,6 +6408,9 @@ _scsih_init(void)
transport_cb_idx = mpt2sas_base_register_callback_handler(
mpt2sas_transport_done);
+ /* scsih internal commands callback handler */
+ scsih_cb_idx = mpt2sas_base_register_callback_handler(_scsih_done);
+
/* configuration page API internal commands callback handler */
config_cb_idx = mpt2sas_base_register_callback_handler(
mpt2sas_config_done);
@@ -6152,6 +6450,7 @@ _scsih_exit(void)
mpt2sas_base_release_callback_handler(tm_cb_idx);
mpt2sas_base_release_callback_handler(base_cb_idx);
mpt2sas_base_release_callback_handler(transport_cb_idx);
+ mpt2sas_base_release_callback_handler(scsih_cb_idx);
mpt2sas_base_release_callback_handler(config_cb_idx);
mpt2sas_base_release_callback_handler(ctl_cb_idx);
diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c
index eb98188..3a82872 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_transport.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c
@@ -59,24 +59,23 @@
#include "mpt2sas_base.h"
/**
- * _transport_sas_node_find_by_handle - sas node search
+ * _transport_sas_node_find_by_sas_address - sas node search
* @ioc: per adapter object
- * @handle: expander or hba handle (assigned by firmware)
+ * @sas_address: sas address of expander or sas host
* Context: Calling function should acquire ioc->sas_node_lock.
*
* Search for either hba phys or expander device based on handle, then returns
* the sas_node object.
*/
static struct _sas_node *
-_transport_sas_node_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+_transport_sas_node_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
+ u64 sas_address)
{
- int i;
-
- for (i = 0; i < ioc->sas_hba.num_phys; i++)
- if (ioc->sas_hba.phy[i].handle == handle)
- return &ioc->sas_hba;
-
- return mpt2sas_scsih_expander_find_by_handle(ioc, handle);
+ if (ioc->sas_hba.sas_address == sas_address)
+ return &ioc->sas_hba;
+ else
+ return mpt2sas_scsih_expander_find_by_sas_address(ioc,
+ sas_address);
}
/**
@@ -259,8 +258,7 @@ struct rep_manu_reply{
u8 response_length;
u16 expander_change_count;
u8 reserved0[2];
- u8 sas_format:1;
- u8 reserved1:7;
+ u8 sas_format;
u8 reserved2[3];
u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN];
u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN];
@@ -375,7 +373,8 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
mpi_request->VP_ID = 0;
sas_address_le = (u64 *)&mpi_request->SASAddress;
*sas_address_le = cpu_to_le64(sas_address);
- mpi_request->RequestDataLength = sizeof(struct rep_manu_request);
+ mpi_request->RequestDataLength =
+ cpu_to_le16(sizeof(struct rep_manu_request));
psge = &mpi_request->SGL;
/* WRITE sgel first */
@@ -438,8 +437,8 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
SAS_EXPANDER_PRODUCT_ID_LEN);
strncpy(edev->product_rev, manufacture_reply->product_rev,
SAS_EXPANDER_PRODUCT_REV_LEN);
- edev->level = manufacture_reply->sas_format;
- if (manufacture_reply->sas_format) {
+ edev->level = manufacture_reply->sas_format & 1;
+ if (edev->level) {
strncpy(edev->component_vendor_id,
manufacture_reply->component_vendor_id,
SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN);
@@ -469,7 +468,7 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
* mpt2sas_transport_port_add - insert port to the list
* @ioc: per adapter object
* @handle: handle of attached device
- * @parent_handle: parent handle(either hba or expander)
+ * @sas_address: sas address of parent expander or sas host
* Context: This function will acquire ioc->sas_node_lock.
*
* Adding new port object to the sas_node->sas_port_list.
@@ -478,7 +477,7 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
*/
struct _sas_port *
mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle,
- u16 parent_handle)
+ u64 sas_address)
{
struct _sas_phy *mpt2sas_phy, *next;
struct _sas_port *mpt2sas_port;
@@ -488,9 +487,6 @@ mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle,
int i;
struct sas_port *port;
- if (!parent_handle)
- return NULL;
-
mpt2sas_port = kzalloc(sizeof(struct _sas_port),
GFP_KERNEL);
if (!mpt2sas_port) {
@@ -502,17 +498,16 @@ mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle,
INIT_LIST_HEAD(&mpt2sas_port->port_list);
INIT_LIST_HEAD(&mpt2sas_port->phy_list);
spin_lock_irqsave(&ioc->sas_node_lock, flags);
- sas_node = _transport_sas_node_find_by_handle(ioc, parent_handle);
+ sas_node = _transport_sas_node_find_by_sas_address(ioc, sas_address);
spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
if (!sas_node) {
- printk(MPT2SAS_ERR_FMT "%s: Could not find parent(0x%04x)!\n",
- ioc->name, __func__, parent_handle);
+ printk(MPT2SAS_ERR_FMT "%s: Could not find "
+ "parent sas_address(0x%016llx)!\n", ioc->name,
+ __func__, (unsigned long long)sas_address);
goto out_fail;
}
- mpt2sas_port->handle = parent_handle;
- mpt2sas_port->sas_address = sas_node->sas_address;
if ((_transport_set_identify(ioc, handle,
&mpt2sas_port->remote_identify))) {
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
@@ -604,7 +599,7 @@ mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle,
* mpt2sas_transport_port_remove - remove port from the list
* @ioc: per adapter object
* @sas_address: sas address of attached device
- * @parent_handle: handle to the upstream parent(either hba or expander)
+ * @sas_address_parent: sas address of parent expander or sas host
* Context: This function will acquire ioc->sas_node_lock.
*
* Removing object and freeing associated memory from the
@@ -614,7 +609,7 @@ mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle,
*/
void
mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
- u16 parent_handle)
+ u64 sas_address_parent)
{
int i;
unsigned long flags;
@@ -624,7 +619,8 @@ mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
struct _sas_phy *mpt2sas_phy, *next_phy;
spin_lock_irqsave(&ioc->sas_node_lock, flags);
- sas_node = _transport_sas_node_find_by_handle(ioc, parent_handle);
+ sas_node = _transport_sas_node_find_by_sas_address(ioc,
+ sas_address_parent);
spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
if (!sas_node)
return;
@@ -650,8 +646,7 @@ mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
&mpt2sas_port->phy_list, port_siblings) {
if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
dev_printk(KERN_INFO, &mpt2sas_port->port->dev,
- "remove: parent_handle(0x%04x), "
- "sas_addr(0x%016llx), phy(%d)\n", parent_handle,
+ "remove: sas_addr(0x%016llx), phy(%d)\n",
(unsigned long long)
mpt2sas_port->remote_identify.sas_address,
mpt2sas_phy->phy_id);
@@ -799,8 +794,8 @@ mpt2sas_transport_add_expander_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
/**
* mpt2sas_transport_update_links - refreshing phy link changes
* @ioc: per adapter object
- * @handle: handle to sas_host or expander
- * @attached_handle: attached device handle
+ * @sas_address: sas address of parent expander or sas host
+ * @handle: attached device handle
* @phy_numberv: phy number
* @link_rate: new link rate
*
@@ -808,28 +803,25 @@ mpt2sas_transport_add_expander_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
*/
void
mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc,
- u16 handle, u16 attached_handle, u8 phy_number, u8 link_rate)
+ u64 sas_address, u16 handle, u8 phy_number, u8 link_rate)
{
unsigned long flags;
struct _sas_node *sas_node;
struct _sas_phy *mpt2sas_phy;
- if (ioc->shost_recovery) {
- printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
- __func__, ioc->name);
+ if (ioc->shost_recovery)
return;
- }
spin_lock_irqsave(&ioc->sas_node_lock, flags);
- sas_node = _transport_sas_node_find_by_handle(ioc, handle);
+ sas_node = _transport_sas_node_find_by_sas_address(ioc, sas_address);
spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
if (!sas_node)
return;
mpt2sas_phy = &sas_node->phy[phy_number];
- mpt2sas_phy->attached_handle = attached_handle;
- if (attached_handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5))
- _transport_set_identify(ioc, mpt2sas_phy->attached_handle,
+ mpt2sas_phy->attached_handle = handle;
+ if (handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5))
+ _transport_set_identify(ioc, handle,
&mpt2sas_phy->remote_identify);
else
memset(&mpt2sas_phy->remote_identify, 0 , sizeof(struct
@@ -841,13 +833,11 @@ mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc,
if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev,
- "refresh: handle(0x%04x), sas_addr(0x%016llx),\n"
+ "refresh: parent sas_addr(0x%016llx),\n"
"\tlink_rate(0x%02x), phy(%d)\n"
"\tattached_handle(0x%04x), sas_addr(0x%016llx)\n",
- handle, (unsigned long long)
- mpt2sas_phy->identify.sas_address, link_rate,
- phy_number, attached_handle,
- (unsigned long long)
+ (unsigned long long)sas_address,
+ link_rate, phy_number, handle, (unsigned long long)
mpt2sas_phy->remote_identify.sas_address);
}
@@ -1126,7 +1116,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio),
blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL);
if (!dma_addr_out) {
- mpt2sas_base_free_smid(ioc, le16_to_cpu(smid));
+ mpt2sas_base_free_smid(ioc, smid);
goto unmap;
}
@@ -1144,7 +1134,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio),
blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL);
if (!dma_addr_in) {
- mpt2sas_base_free_smid(ioc, le16_to_cpu(smid));
+ mpt2sas_base_free_smid(ioc, smid);
goto unmap;
}
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
index e3c482a..a2d5698 100644
--- a/drivers/scsi/ncr53c8xx.c
+++ b/drivers/scsi/ncr53c8xx.c
@@ -6495,7 +6495,7 @@ static void ncr_int_ma (struct ncb *np)
** we force a SIR_NEGO_PROTO interrupt (it is a hack that avoids
** bloat for such a should_not_happen situation).
** In all other situation, we reset the BUS.
- ** Are these assumptions reasonnable ? (Wait and see ...)
+ ** Are these assumptions reasonable ? (Wait and see ...)
*/
unexpected_phase:
dsp -= 8;
diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c
index 2be7d5b..2c98a6e 100644
--- a/drivers/scsi/nsp32.c
+++ b/drivers/scsi/nsp32.c
@@ -1419,7 +1419,7 @@ static irqreturn_t do_nsp32_isr(int irq, void *dev_id)
nsp32_msg(KERN_ERR, "Received unexpected BMCNTERR IRQ! ");
/*
* TODO: To be implemented improving bus master
- * transfer reliablity when BMCNTERR is occurred in
+ * transfer reliability when BMCNTERR is occurred in
* AutoSCSI phase described in specification.
*/
}
diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c
index 7a117c1..950202a 100644
--- a/drivers/scsi/osd/osd_initiator.c
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -73,7 +73,8 @@ static const char *_osd_ver_desc(struct osd_request *or)
#define ATTR_DEF_RI(id, len) ATTR_DEF(OSD_APAGE_ROOT_INFORMATION, id, len)
-static int _osd_print_system_info(struct osd_dev *od, void *caps)
+static int _osd_get_print_system_info(struct osd_dev *od,
+ void *caps, struct osd_dev_info *odi)
{
struct osd_request *or;
struct osd_attr get_attrs[] = {
@@ -137,8 +138,12 @@ static int _osd_print_system_info(struct osd_dev *od, void *caps)
OSD_INFO("PRODUCT_SERIAL_NUMBER [%s]\n",
(char *)pFirst);
- pFirst = get_attrs[a].val_ptr;
- OSD_INFO("OSD_NAME [%s]\n", (char *)pFirst);
+ odi->osdname_len = get_attrs[a].len;
+ /* Avoid NULL for memcmp optimization 0-length is good enough */
+ odi->osdname = kzalloc(odi->osdname_len + 1, GFP_KERNEL);
+ if (odi->osdname_len)
+ memcpy(odi->osdname, get_attrs[a].val_ptr, odi->osdname_len);
+ OSD_INFO("OSD_NAME [%s]\n", odi->osdname);
a++;
pFirst = get_attrs[a++].val_ptr;
@@ -171,6 +176,14 @@ static int _osd_print_system_info(struct osd_dev *od, void *caps)
sid_dump, sizeof(sid_dump), true);
OSD_INFO("OSD_SYSTEM_ID(%d)\n"
" [%s]\n", len, sid_dump);
+
+ if (unlikely(len > sizeof(odi->systemid))) {
+ OSD_ERR("OSD Target error: OSD_SYSTEM_ID too long(%d). "
+ "device idetification might not work\n", len);
+ len = sizeof(odi->systemid);
+ }
+ odi->systemid_len = len;
+ memcpy(odi->systemid, get_attrs[a].val_ptr, len);
a++;
}
out:
@@ -178,16 +191,17 @@ out:
return ret;
}
-int osd_auto_detect_ver(struct osd_dev *od, void *caps)
+int osd_auto_detect_ver(struct osd_dev *od,
+ void *caps, struct osd_dev_info *odi)
{
int ret;
/* Auto-detect the osd version */
- ret = _osd_print_system_info(od, caps);
+ ret = _osd_get_print_system_info(od, caps, odi);
if (ret) {
osd_dev_set_ver(od, OSD_VER1);
OSD_DEBUG("converting to OSD1\n");
- ret = _osd_print_system_info(od, caps);
+ ret = _osd_get_print_system_info(od, caps, odi);
}
return ret;
@@ -461,7 +475,8 @@ EXPORT_SYMBOL(osd_end_request);
int osd_execute_request(struct osd_request *or)
{
- return blk_execute_rq(or->request->q, NULL, or->request, 0);
+ return or->async_error =
+ blk_execute_rq(or->request->q, NULL, or->request, 0);
}
EXPORT_SYMBOL(osd_execute_request);
@@ -471,8 +486,12 @@ static void osd_request_async_done(struct request *req, int error)
or->async_error = error;
- if (error)
- OSD_DEBUG("osd_request_async_done error recieved %d\n", error);
+ if (unlikely(error)) {
+ OSD_DEBUG("osd_request_async_done error recieved %d "
+ "errors 0x%x\n", error, req->errors);
+ if (!req->errors) /* don't miss out on this one */
+ req->errors = error;
+ }
if (or->async_done)
or->async_done(or, or->async_private);
@@ -1153,6 +1172,7 @@ int osd_req_decode_get_attr_list(struct osd_request *or,
"c=%d r=%d n=%d\n",
cur_bytes, returned_bytes, n);
oa->val_ptr = NULL;
+ cur_bytes = returned_bytes; /* break the caller loop */
break;
}
@@ -1436,6 +1456,15 @@ int osd_finalize_request(struct osd_request *or,
}
EXPORT_SYMBOL(osd_finalize_request);
+static bool _is_osd_security_code(int code)
+{
+ return (code == osd_security_audit_value_frozen) ||
+ (code == osd_security_working_key_frozen) ||
+ (code == osd_nonce_not_unique) ||
+ (code == osd_nonce_timestamp_out_of_range) ||
+ (code == osd_invalid_dataout_buffer_integrity_check_value);
+}
+
#define OSD_SENSE_PRINT1(fmt, a...) \
do { \
if (__cur_sense_need_output) \
@@ -1458,9 +1487,16 @@ int osd_req_decode_sense_full(struct osd_request *or,
#else
bool __cur_sense_need_output = !silent;
#endif
+ int ret;
- if (!or->request->errors)
+ if (likely(!or->request->errors)) {
+ osi->out_resid = 0;
+ osi->in_resid = 0;
return 0;
+ }
+
+ osi = osi ? : &local_osi;
+ memset(osi, 0, sizeof(*osi));
ssdb = or->request->sense;
sense_len = or->request->sense_len;
@@ -1468,17 +1504,15 @@ int osd_req_decode_sense_full(struct osd_request *or,
OSD_ERR("Block-layer returned error(0x%x) but "
"sense_len(%u) || key(%d) is empty\n",
or->request->errors, sense_len, ssdb->sense_key);
- return -EIO;
+ goto analyze;
}
if ((ssdb->response_code != 0x72) && (ssdb->response_code != 0x73)) {
OSD_ERR("Unrecognized scsi sense: rcode=%x length=%d\n",
ssdb->response_code, sense_len);
- return -EIO;
+ goto analyze;
}
- osi = osi ? : &local_osi;
- memset(osi, 0, sizeof(*osi));
osi->key = ssdb->sense_key;
osi->additional_code = be16_to_cpu(ssdb->additional_sense_code);
original_sense_len = ssdb->additional_sense_length + 8;
@@ -1488,9 +1522,10 @@ int osd_req_decode_sense_full(struct osd_request *or,
__cur_sense_need_output = (osi->key > scsi_sk_recovered_error);
#endif
OSD_SENSE_PRINT1("Main Sense information key=0x%x length(%d, %d) "
- "additional_code=0x%x\n",
+ "additional_code=0x%x async_error=%d errors=0x%x\n",
osi->key, original_sense_len, sense_len,
- osi->additional_code);
+ osi->additional_code, or->async_error,
+ or->request->errors);
if (original_sense_len < sense_len)
sense_len = original_sense_len;
@@ -1569,15 +1604,14 @@ int osd_req_decode_sense_full(struct osd_request *or,
{
struct osd_sense_attributes_data_descriptor
*osadd = cur_descriptor;
- int len = min(cur_len, sense_len);
- int i = 0;
+ unsigned len = min(cur_len, sense_len);
struct osd_sense_attr *pattr = osadd->sense_attrs;
- while (len < 0) {
+ while (len >= sizeof(*pattr)) {
u32 attr_page = be32_to_cpu(pattr->attr_page);
u32 attr_id = be32_to_cpu(pattr->attr_id);
- if (i++ == 0) {
+ if (!osi->attr.attr_page) {
osi->attr.attr_page = attr_page;
osi->attr.attr_id = attr_id;
}
@@ -1588,6 +1622,8 @@ int osd_req_decode_sense_full(struct osd_request *or,
bad_attr_list++;
max_attr--;
}
+
+ len -= sizeof(*pattr);
OSD_SENSE_PRINT2(
"osd_sense_attribute_identification"
"attr_page=0x%x attr_id=0x%x\n",
@@ -1621,7 +1657,50 @@ int osd_req_decode_sense_full(struct osd_request *or,
cur_descriptor += cur_len;
}
- return (osi->key > scsi_sk_recovered_error) ? -EIO : 0;
+analyze:
+ if (!osi->key) {
+ /* scsi sense is Empty, the request was never issued to target
+ * linux return code might tell us what happened.
+ */
+ if (or->async_error == -ENOMEM)
+ osi->osd_err_pri = OSD_ERR_PRI_RESOURCE;
+ else
+ osi->osd_err_pri = OSD_ERR_PRI_UNREACHABLE;
+ ret = or->async_error;
+ } else if (osi->key <= scsi_sk_recovered_error) {
+ osi->osd_err_pri = 0;
+ ret = 0;
+ } else if (osi->additional_code == scsi_invalid_field_in_cdb) {
+ if (osi->cdb_field_offset == OSD_CFO_STARTING_BYTE) {
+ osi->osd_err_pri = OSD_ERR_PRI_CLEAR_PAGES;
+ ret = -EFAULT; /* caller should recover from this */
+ } else if (osi->cdb_field_offset == OSD_CFO_OBJECT_ID) {
+ osi->osd_err_pri = OSD_ERR_PRI_NOT_FOUND;
+ ret = -ENOENT;
+ } else if (osi->cdb_field_offset == OSD_CFO_PERMISSIONS) {
+ osi->osd_err_pri = OSD_ERR_PRI_NO_ACCESS;
+ ret = -EACCES;
+ } else {
+ osi->osd_err_pri = OSD_ERR_PRI_BAD_CRED;
+ ret = -EINVAL;
+ }
+ } else if (osi->additional_code == osd_quota_error) {
+ osi->osd_err_pri = OSD_ERR_PRI_NO_SPACE;
+ ret = -ENOSPC;
+ } else if (_is_osd_security_code(osi->additional_code)) {
+ osi->osd_err_pri = OSD_ERR_PRI_BAD_CRED;
+ ret = -EINVAL;
+ } else {
+ osi->osd_err_pri = OSD_ERR_PRI_EIO;
+ ret = -EIO;
+ }
+
+ if (or->out.req)
+ osi->out_resid = or->out.req->resid_len ?: or->out.total_bytes;
+ if (or->in.req)
+ osi->in_resid = or->in.req->resid_len ?: or->in.total_bytes;
+
+ return ret;
}
EXPORT_SYMBOL(osd_req_decode_sense_full);
diff --git a/drivers/scsi/osd/osd_uld.c b/drivers/scsi/osd/osd_uld.c
index 0bdef33..0a90702 100644
--- a/drivers/scsi/osd/osd_uld.c
+++ b/drivers/scsi/osd/osd_uld.c
@@ -71,8 +71,7 @@
#define SCSI_OSD_MAX_MINOR 64
static const char osd_name[] = "osd";
-static const char *osd_version_string = "open-osd 0.1.0";
-const char osd_symlink[] = "scsi_osd";
+static const char *osd_version_string = "open-osd 0.2.0";
MODULE_AUTHOR("Boaz Harrosh <bharrosh@panasas.com>");
MODULE_DESCRIPTION("open-osd Upper-Layer-Driver osd.ko");
@@ -82,15 +81,25 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_OSD);
struct osd_uld_device {
int minor;
- struct kref kref;
+ struct device class_dev;
struct cdev cdev;
struct osd_dev od;
+ struct osd_dev_info odi;
struct gendisk *disk;
- struct device *class_member;
};
-static void __uld_get(struct osd_uld_device *oud);
-static void __uld_put(struct osd_uld_device *oud);
+struct osd_dev_handle {
+ struct osd_dev od;
+ struct file *file;
+ struct osd_uld_device *oud;
+} ;
+
+static DEFINE_IDA(osd_minor_ida);
+
+static struct class osd_uld_class = {
+ .owner = THIS_MODULE,
+ .name = "scsi_osd",
+};
/*
* Char Device operations
@@ -101,7 +110,7 @@ static int osd_uld_open(struct inode *inode, struct file *file)
struct osd_uld_device *oud = container_of(inode->i_cdev,
struct osd_uld_device, cdev);
- __uld_get(oud);
+ get_device(&oud->class_dev);
/* cache osd_uld_device on file handle */
file->private_data = oud;
OSD_DEBUG("osd_uld_open %p\n", oud);
@@ -114,7 +123,7 @@ static int osd_uld_release(struct inode *inode, struct file *file)
OSD_DEBUG("osd_uld_release %p\n", file->private_data);
file->private_data = NULL;
- __uld_put(oud);
+ put_device(&oud->class_dev);
return 0;
}
@@ -177,7 +186,7 @@ static const struct file_operations osd_fops = {
struct osd_dev *osduld_path_lookup(const char *name)
{
struct osd_uld_device *oud;
- struct osd_dev *od;
+ struct osd_dev_handle *odh;
struct file *file;
int error;
@@ -186,8 +195,8 @@ struct osd_dev *osduld_path_lookup(const char *name)
return ERR_PTR(-EINVAL);
}
- od = kzalloc(sizeof(*od), GFP_KERNEL);
- if (!od)
+ odh = kzalloc(sizeof(*odh), GFP_KERNEL);
+ if (unlikely(!odh))
return ERR_PTR(-ENOMEM);
file = filp_open(name, O_RDWR, 0);
@@ -203,33 +212,134 @@ struct osd_dev *osduld_path_lookup(const char *name)
oud = file->private_data;
- *od = oud->od;
- od->file = file;
+ odh->od = oud->od;
+ odh->file = file;
+ odh->oud = oud;
- return od;
+ return &odh->od;
close_file:
fput(file);
free_od:
- kfree(od);
+ kfree(odh);
return ERR_PTR(error);
}
EXPORT_SYMBOL(osduld_path_lookup);
-void osduld_put_device(struct osd_dev *od)
+static inline bool _the_same_or_null(const u8 *a1, unsigned a1_len,
+ const u8 *a2, unsigned a2_len)
{
+ if (!a2_len) /* User string is Empty means don't care */
+ return true;
+
+ if (a1_len != a2_len)
+ return false;
+
+ return 0 == memcmp(a1, a2, a1_len);
+}
+
+struct find_oud_t {
+ const struct osd_dev_info *odi;
+ struct device *dev;
+ struct osd_uld_device *oud;
+} ;
+
+int _mach_odi(struct device *dev, void *find_data)
+{
+ struct osd_uld_device *oud = container_of(dev, struct osd_uld_device,
+ class_dev);
+ struct find_oud_t *fot = find_data;
+ const struct osd_dev_info *odi = fot->odi;
+
+ if (_the_same_or_null(oud->odi.systemid, oud->odi.systemid_len,
+ odi->systemid, odi->systemid_len) &&
+ _the_same_or_null(oud->odi.osdname, oud->odi.osdname_len,
+ odi->osdname, odi->osdname_len)) {
+ OSD_DEBUG("found device sysid_len=%d osdname=%d\n",
+ odi->systemid_len, odi->osdname_len);
+ fot->oud = oud;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+/* osduld_info_lookup - Loop through all devices, return the requested osd_dev.
+ *
+ * if @odi->systemid_len and/or @odi->osdname_len are zero, they act as a don't
+ * care. .e.g if they're both zero /dev/osd0 is returned.
+ */
+struct osd_dev *osduld_info_lookup(const struct osd_dev_info *odi)
+{
+ struct find_oud_t find = {.odi = odi};
+
+ find.dev = class_find_device(&osd_uld_class, NULL, &find, _mach_odi);
+ if (likely(find.dev)) {
+ struct osd_dev_handle *odh = kzalloc(sizeof(*odh), GFP_KERNEL);
+
+ if (unlikely(!odh)) {
+ put_device(find.dev);
+ return ERR_PTR(-ENOMEM);
+ }
+ odh->od = find.oud->od;
+ odh->oud = find.oud;
+
+ return &odh->od;
+ }
+
+ return ERR_PTR(-ENODEV);
+}
+EXPORT_SYMBOL(osduld_info_lookup);
+
+void osduld_put_device(struct osd_dev *od)
+{
if (od && !IS_ERR(od)) {
- struct osd_uld_device *oud = od->file->private_data;
+ struct osd_dev_handle *odh =
+ container_of(od, struct osd_dev_handle, od);
+ struct osd_uld_device *oud = odh->oud;
BUG_ON(od->scsi_device != oud->od.scsi_device);
- fput(od->file);
- kfree(od);
+ /* If scsi has released the device (logout), and exofs has last
+ * reference on oud it will be freed by above osd_uld_release
+ * within fput below. But this will oops in cdev_release which
+ * is called after the fops->release. A get_/put_ pair makes
+ * sure we have a cdev for the duration of fput
+ */
+ if (odh->file) {
+ get_device(&oud->class_dev);
+ fput(odh->file);
+ }
+ put_device(&oud->class_dev);
+ kfree(odh);
}
}
EXPORT_SYMBOL(osduld_put_device);
+const struct osd_dev_info *osduld_device_info(struct osd_dev *od)
+{
+ struct osd_dev_handle *odh =
+ container_of(od, struct osd_dev_handle, od);
+ return &odh->oud->odi;
+}
+EXPORT_SYMBOL(osduld_device_info);
+
+bool osduld_device_same(struct osd_dev *od, const struct osd_dev_info *odi)
+{
+ struct osd_dev_handle *odh =
+ container_of(od, struct osd_dev_handle, od);
+ struct osd_uld_device *oud = odh->oud;
+
+ return (oud->odi.systemid_len == odi->systemid_len) &&
+ _the_same_or_null(oud->odi.systemid, oud->odi.systemid_len,
+ odi->systemid, odi->systemid_len) &&
+ (oud->odi.osdname_len == odi->osdname_len) &&
+ _the_same_or_null(oud->odi.osdname, oud->odi.osdname_len,
+ odi->osdname, odi->osdname_len);
+}
+EXPORT_SYMBOL(osduld_device_same);
+
/*
* Scsi Device operations
*/
@@ -250,14 +360,35 @@ static int __detect_osd(struct osd_uld_device *oud)
OSD_ERR("warning: scsi_test_unit_ready failed\n");
osd_sec_init_nosec_doall_caps(caps, &osd_root_object, false, true);
- if (osd_auto_detect_ver(&oud->od, caps))
+ if (osd_auto_detect_ver(&oud->od, caps, &oud->odi))
return -ENODEV;
return 0;
}
-static struct class *osd_sysfs_class;
-static DEFINE_IDA(osd_minor_ida);
+static void __remove(struct device *dev)
+{
+ struct osd_uld_device *oud = container_of(dev, struct osd_uld_device,
+ class_dev);
+ struct scsi_device *scsi_device = oud->od.scsi_device;
+
+ kfree(oud->odi.osdname);
+
+ if (oud->cdev.owner)
+ cdev_del(&oud->cdev);
+
+ osd_dev_fini(&oud->od);
+ scsi_device_put(scsi_device);
+
+ OSD_INFO("osd_remove %s\n",
+ oud->disk ? oud->disk->disk_name : NULL);
+
+ if (oud->disk)
+ put_disk(oud->disk);
+ ida_remove(&osd_minor_ida, oud->minor);
+
+ kfree(oud);
+}
static int osd_probe(struct device *dev)
{
@@ -289,7 +420,6 @@ static int osd_probe(struct device *dev)
if (NULL == oud)
goto err_retract_minor;
- kref_init(&oud->kref);
dev_set_drvdata(dev, oud);
oud->minor = minor;
@@ -327,18 +457,25 @@ static int osd_probe(struct device *dev)
OSD_ERR("cdev_add failed\n");
goto err_put_disk;
}
- kobject_get(&oud->cdev.kobj); /* 2nd ref see osd_remove() */
-
- /* class_member */
- oud->class_member = device_create(osd_sysfs_class, dev,
- MKDEV(SCSI_OSD_MAJOR, oud->minor), "%s", disk->disk_name);
- if (IS_ERR(oud->class_member)) {
- OSD_ERR("class_device_create failed\n");
- error = PTR_ERR(oud->class_member);
+
+ /* class device member */
+ oud->class_dev.devt = oud->cdev.dev;
+ oud->class_dev.class = &osd_uld_class;
+ oud->class_dev.parent = dev;
+ oud->class_dev.release = __remove;
+ error = dev_set_name(&oud->class_dev, disk->disk_name);
+ if (error) {
+ OSD_ERR("dev_set_name failed => %d\n", error);
+ goto err_put_cdev;
+ }
+
+ error = device_register(&oud->class_dev);
+ if (error) {
+ OSD_ERR("device_register failed => %d\n", error);
goto err_put_cdev;
}
- dev_set_drvdata(oud->class_member, oud);
+ get_device(&oud->class_dev);
OSD_INFO("osd_probe %s\n", disk->disk_name);
return 0;
@@ -367,54 +504,12 @@ static int osd_remove(struct device *dev)
scsi_device);
}
- if (oud->class_member)
- device_destroy(osd_sysfs_class,
- MKDEV(SCSI_OSD_MAJOR, oud->minor));
+ device_unregister(&oud->class_dev);
- /* We have 2 references to the cdev. One is released here
- * and also takes down the /dev/osdX mapping. The second
- * Will be released in __remove() after all users have released
- * the osd_uld_device.
- */
- if (oud->cdev.owner)
- cdev_del(&oud->cdev);
-
- __uld_put(oud);
+ put_device(&oud->class_dev);
return 0;
}
-static void __remove(struct kref *kref)
-{
- struct osd_uld_device *oud = container_of(kref,
- struct osd_uld_device, kref);
- struct scsi_device *scsi_device = oud->od.scsi_device;
-
- /* now let delete the char_dev */
- kobject_put(&oud->cdev.kobj);
-
- osd_dev_fini(&oud->od);
- scsi_device_put(scsi_device);
-
- OSD_INFO("osd_remove %s\n",
- oud->disk ? oud->disk->disk_name : NULL);
-
- if (oud->disk)
- put_disk(oud->disk);
-
- ida_remove(&osd_minor_ida, oud->minor);
- kfree(oud);
-}
-
-static void __uld_get(struct osd_uld_device *oud)
-{
- kref_get(&oud->kref);
-}
-
-static void __uld_put(struct osd_uld_device *oud)
-{
- kref_put(&oud->kref, __remove);
-}
-
/*
* Global driver and scsi registration
*/
@@ -432,11 +527,10 @@ static int __init osd_uld_init(void)
{
int err;
- osd_sysfs_class = class_create(THIS_MODULE, osd_symlink);
- if (IS_ERR(osd_sysfs_class)) {
- OSD_ERR("Unable to register sysfs class => %ld\n",
- PTR_ERR(osd_sysfs_class));
- return PTR_ERR(osd_sysfs_class);
+ err = class_register(&osd_uld_class);
+ if (err) {
+ OSD_ERR("Unable to register sysfs class => %d\n", err);
+ return err;
}
err = register_chrdev_region(MKDEV(SCSI_OSD_MAJOR, 0),
@@ -459,7 +553,7 @@ static int __init osd_uld_init(void)
err_out_chrdev:
unregister_chrdev_region(MKDEV(SCSI_OSD_MAJOR, 0), SCSI_OSD_MAX_MINOR);
err_out:
- class_destroy(osd_sysfs_class);
+ class_unregister(&osd_uld_class);
return err;
}
@@ -467,7 +561,7 @@ static void __exit osd_uld_exit(void)
{
scsi_unregister_driver(&osd_driver.gendrv);
unregister_chrdev_region(MKDEV(SCSI_OSD_MAJOR, 0), SCSI_OSD_MAX_MINOR);
- class_destroy(osd_sysfs_class);
+ class_unregister(&osd_uld_class);
OSD_INFO("UNLOADED %s\n", osd_version_string);
}
diff --git a/drivers/scsi/pm8001/Makefile b/drivers/scsi/pm8001/Makefile
new file mode 100644
index 0000000..52f0429
--- /dev/null
+++ b/drivers/scsi/pm8001/Makefile
@@ -0,0 +1,12 @@
+#
+# Kernel configuration file for the PM8001 SAS/SATA 8x6G based HBA driver
+#
+# Copyright (C) 2008-2009 USI Co., Ltd.
+
+
+obj-$(CONFIG_SCSI_PM8001) += pm8001.o
+pm8001-y += pm8001_init.o \
+ pm8001_sas.o \
+ pm8001_ctl.o \
+ pm8001_hwi.o
+
diff --git a/drivers/scsi/pm8001/pm8001_chips.h b/drivers/scsi/pm8001/pm8001_chips.h
new file mode 100644
index 0000000..4efa4d0
--- /dev/null
+++ b/drivers/scsi/pm8001/pm8001_chips.h
@@ -0,0 +1,89 @@
+/*
+ * PMC-Sierra SPC 8001 SAS/SATA based host adapters driver
+ *
+ * Copyright (c) 2008-2009 USI Co., Ltd.
+ * 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 at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ *
+ */
+
+#ifndef _PM8001_CHIPS_H_
+#define _PM8001_CHIPS_H_
+
+static inline u32 pm8001_read_32(void *virt_addr)
+{
+ return *((u32 *)virt_addr);
+}
+
+static inline void pm8001_write_32(void *addr, u32 offset, u32 val)
+{
+ *((u32 *)(addr + offset)) = val;
+}
+
+static inline u32 pm8001_cr32(struct pm8001_hba_info *pm8001_ha, u32 bar,
+ u32 offset)
+{
+ return readl(pm8001_ha->io_mem[bar].memvirtaddr + offset);
+}
+
+static inline void pm8001_cw32(struct pm8001_hba_info *pm8001_ha, u32 bar,
+ u32 addr, u32 val)
+{
+ writel(val, pm8001_ha->io_mem[bar].memvirtaddr + addr);
+}
+static inline u32 pm8001_mr32(void __iomem *addr, u32 offset)
+{
+ return readl(addr + offset);
+}
+static inline void pm8001_mw32(void __iomem *addr, u32 offset, u32 val)
+{
+ writel(val, addr + offset);
+}
+static inline u32 get_pci_bar_index(u32 pcibar)
+{
+ switch (pcibar) {
+ case 0x18:
+ case 0x1C:
+ return 1;
+ case 0x20:
+ return 2;
+ case 0x24:
+ return 3;
+ default:
+ return 0;
+ }
+}
+
+#endif /* _PM8001_CHIPS_H_ */
+
diff --git a/drivers/scsi/pm8001/pm8001_ctl.c b/drivers/scsi/pm8001/pm8001_ctl.c
new file mode 100644
index 0000000..14b13ac
--- /dev/null
+++ b/drivers/scsi/pm8001/pm8001_ctl.c
@@ -0,0 +1,573 @@
+/*
+ * PMC-Sierra SPC 8001 SAS/SATA based host adapters driver
+ *
+ * Copyright (c) 2008-2009 USI Co., Ltd.
+ * 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 at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ *
+ */
+#include <linux/firmware.h>
+#include "pm8001_sas.h"
+#include "pm8001_ctl.h"
+
+/* scsi host attributes */
+
+/**
+ * pm8001_ctl_mpi_interface_rev_show - MPI interface revision number
+ * @cdev: pointer to embedded class device
+ * @buf: the buffer returned
+ *
+ * A sysfs 'read-only' shost attribute.
+ */
+static ssize_t pm8001_ctl_mpi_interface_rev_show(struct device *cdev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+ struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ pm8001_ha->main_cfg_tbl.interface_rev);
+}
+static
+DEVICE_ATTR(interface_rev, S_IRUGO, pm8001_ctl_mpi_interface_rev_show, NULL);
+
+/**
+ * pm8001_ctl_fw_version_show - firmware version
+ * @cdev: pointer to embedded class device
+ * @buf: the buffer returned
+ *
+ * A sysfs 'read-only' shost attribute.
+ */
+static ssize_t pm8001_ctl_fw_version_show(struct device *cdev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+ struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
+
+ return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
+ (u8)(pm8001_ha->main_cfg_tbl.firmware_rev >> 24),
+ (u8)(pm8001_ha->main_cfg_tbl.firmware_rev >> 16),
+ (u8)(pm8001_ha->main_cfg_tbl.firmware_rev >> 8),
+ (u8)(pm8001_ha->main_cfg_tbl.firmware_rev));
+}
+static DEVICE_ATTR(fw_version, S_IRUGO, pm8001_ctl_fw_version_show, NULL);
+/**
+ * pm8001_ctl_max_out_io_show - max outstanding io supported
+ * @cdev: pointer to embedded class device
+ * @buf: the buffer returned
+ *
+ * A sysfs 'read-only' shost attribute.
+ */
+static ssize_t pm8001_ctl_max_out_io_show(struct device *cdev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+ struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ pm8001_ha->main_cfg_tbl.max_out_io);
+}
+static DEVICE_ATTR(max_out_io, S_IRUGO, pm8001_ctl_max_out_io_show, NULL);
+/**
+ * pm8001_ctl_max_devices_show - max devices support
+ * @cdev: pointer to embedded class device
+ * @buf: the buffer returned
+ *
+ * A sysfs 'read-only' shost attribute.
+ */
+static ssize_t pm8001_ctl_max_devices_show(struct device *cdev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+ struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
+
+ return snprintf(buf, PAGE_SIZE, "%04d\n",
+ (u16)(pm8001_ha->main_cfg_tbl.max_sgl >> 16));
+}
+static DEVICE_ATTR(max_devices, S_IRUGO, pm8001_ctl_max_devices_show, NULL);
+/**
+ * pm8001_ctl_max_sg_list_show - max sg list supported iff not 0.0 for no
+ * hardware limitation
+ * @cdev: pointer to embedded class device
+ * @buf: the buffer returned
+ *
+ * A sysfs 'read-only' shost attribute.
+ */
+static ssize_t pm8001_ctl_max_sg_list_show(struct device *cdev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+ struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
+
+ return snprintf(buf, PAGE_SIZE, "%04d\n",
+ pm8001_ha->main_cfg_tbl.max_sgl & 0x0000FFFF);
+}
+static DEVICE_ATTR(max_sg_list, S_IRUGO, pm8001_ctl_max_sg_list_show, NULL);
+
+#define SAS_1_0 0x1
+#define SAS_1_1 0x2
+#define SAS_2_0 0x4
+
+static ssize_t
+show_sas_spec_support_status(unsigned int mode, char *buf)
+{
+ ssize_t len = 0;
+
+ if (mode & SAS_1_1)
+ len = sprintf(buf, "%s", "SAS1.1");
+ if (mode & SAS_2_0)
+ len += sprintf(buf + len, "%s%s", len ? ", " : "", "SAS2.0");
+ len += sprintf(buf + len, "\n");
+
+ return len;
+}
+
+/**
+ * pm8001_ctl_sas_spec_support_show - sas spec supported
+ * @cdev: pointer to embedded class device
+ * @buf: the buffer returned
+ *
+ * A sysfs 'read-only' shost attribute.
+ */
+static ssize_t pm8001_ctl_sas_spec_support_show(struct device *cdev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned int mode;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+ struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
+ mode = (pm8001_ha->main_cfg_tbl.ctrl_cap_flag & 0xfe000000)>>25;
+ return show_sas_spec_support_status(mode, buf);
+}
+static DEVICE_ATTR(sas_spec_support, S_IRUGO,
+ pm8001_ctl_sas_spec_support_show, NULL);
+
+/**
+ * pm8001_ctl_sas_address_show - sas address
+ * @cdev: pointer to embedded class device
+ * @buf: the buffer returned
+ *
+ * This is the controller sas address
+ *
+ * A sysfs 'read-only' shost attribute.
+ */
+static ssize_t pm8001_ctl_host_sas_address_show(struct device *cdev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+ struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
+ return snprintf(buf, PAGE_SIZE, "0x%016llx\n",
+ be64_to_cpu(*(__be64 *)pm8001_ha->sas_addr));
+}
+static DEVICE_ATTR(host_sas_address, S_IRUGO,
+ pm8001_ctl_host_sas_address_show, NULL);
+
+/**
+ * pm8001_ctl_logging_level_show - logging level
+ * @cdev: pointer to embedded class device
+ * @buf: the buffer returned
+ *
+ * A sysfs 'read/write' shost attribute.
+ */
+static ssize_t pm8001_ctl_logging_level_show(struct device *cdev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+ struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
+
+ return snprintf(buf, PAGE_SIZE, "%08xh\n", pm8001_ha->logging_level);
+}
+static ssize_t pm8001_ctl_logging_level_store(struct device *cdev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+ struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
+ int val = 0;
+
+ if (sscanf(buf, "%x", &val) != 1)
+ return -EINVAL;
+
+ pm8001_ha->logging_level = val;
+ return strlen(buf);
+}
+
+static DEVICE_ATTR(logging_level, S_IRUGO | S_IWUSR,
+ pm8001_ctl_logging_level_show, pm8001_ctl_logging_level_store);
+/**
+ * pm8001_ctl_aap_log_show - aap1 event log
+ * @cdev: pointer to embedded class device
+ * @buf: the buffer returned
+ *
+ * A sysfs 'read-only' shost attribute.
+ */
+static ssize_t pm8001_ctl_aap_log_show(struct device *cdev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+ struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
+ int i;
+#define AAP1_MEMMAP(r, c) \
+ (*(u32 *)((u8*)pm8001_ha->memoryMap.region[AAP1].virt_ptr + (r) * 32 \
+ + (c)))
+
+ char *str = buf;
+ int max = 2;
+ for (i = 0; i < max; i++) {
+ str += sprintf(str, "0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x"
+ "0x%08x 0x%08x\n",
+ AAP1_MEMMAP(i, 0),
+ AAP1_MEMMAP(i, 4),
+ AAP1_MEMMAP(i, 8),
+ AAP1_MEMMAP(i, 12),
+ AAP1_MEMMAP(i, 16),
+ AAP1_MEMMAP(i, 20),
+ AAP1_MEMMAP(i, 24),
+ AAP1_MEMMAP(i, 28));
+ }
+
+ return str - buf;
+}
+static DEVICE_ATTR(aap_log, S_IRUGO, pm8001_ctl_aap_log_show, NULL);
+/**
+ * pm8001_ctl_aap_log_show - IOP event log
+ * @cdev: pointer to embedded class device
+ * @buf: the buffer returned
+ *
+ * A sysfs 'read-only' shost attribute.
+ */
+static ssize_t pm8001_ctl_iop_log_show(struct device *cdev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+ struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
+#define IOP_MEMMAP(r, c) \
+ (*(u32 *)((u8*)pm8001_ha->memoryMap.region[IOP].virt_ptr + (r) * 32 \
+ + (c)))
+ int i;
+ char *str = buf;
+ int max = 2;
+ for (i = 0; i < max; i++) {
+ str += sprintf(str, "0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x"
+ "0x%08x 0x%08x\n",
+ IOP_MEMMAP(i, 0),
+ IOP_MEMMAP(i, 4),
+ IOP_MEMMAP(i, 8),
+ IOP_MEMMAP(i, 12),
+ IOP_MEMMAP(i, 16),
+ IOP_MEMMAP(i, 20),
+ IOP_MEMMAP(i, 24),
+ IOP_MEMMAP(i, 28));
+ }
+
+ return str - buf;
+}
+static DEVICE_ATTR(iop_log, S_IRUGO, pm8001_ctl_iop_log_show, NULL);
+
+#define FLASH_CMD_NONE 0x00
+#define FLASH_CMD_UPDATE 0x01
+#define FLASH_CMD_SET_NVMD 0x02
+
+struct flash_command {
+ u8 command[8];
+ int code;
+};
+
+static struct flash_command flash_command_table[] =
+{
+ {"set_nvmd", FLASH_CMD_SET_NVMD},
+ {"update", FLASH_CMD_UPDATE},
+ {"", FLASH_CMD_NONE} /* Last entry should be NULL. */
+};
+
+struct error_fw {
+ char *reason;
+ int err_code;
+};
+
+static struct error_fw flash_error_table[] =
+{
+ {"Failed to open fw image file", FAIL_OPEN_BIOS_FILE},
+ {"image header mismatch", FLASH_UPDATE_HDR_ERR},
+ {"image offset mismatch", FLASH_UPDATE_OFFSET_ERR},
+ {"image CRC Error", FLASH_UPDATE_CRC_ERR},
+ {"image length Error.", FLASH_UPDATE_LENGTH_ERR},
+ {"Failed to program flash chip", FLASH_UPDATE_HW_ERR},
+ {"Flash chip not supported.", FLASH_UPDATE_DNLD_NOT_SUPPORTED},
+ {"Flash update disabled.", FLASH_UPDATE_DISABLED},
+ {"Flash in progress", FLASH_IN_PROGRESS},
+ {"Image file size Error", FAIL_FILE_SIZE},
+ {"Input parameter error", FAIL_PARAMETERS},
+ {"Out of memory", FAIL_OUT_MEMORY},
+ {"OK", 0} /* Last entry err_code = 0. */
+};
+
+static int pm8001_set_nvmd(struct pm8001_hba_info *pm8001_ha)
+{
+ struct pm8001_ioctl_payload *payload;
+ DECLARE_COMPLETION_ONSTACK(completion);
+ u8 *ioctlbuffer = NULL;
+ u32 length = 0;
+ u32 ret = 0;
+
+ length = 1024 * 5 + sizeof(*payload) - 1;
+ ioctlbuffer = kzalloc(length, GFP_KERNEL);
+ if (!ioctlbuffer)
+ return -ENOMEM;
+ if ((pm8001_ha->fw_image->size <= 0) ||
+ (pm8001_ha->fw_image->size > 4096)) {
+ ret = FAIL_FILE_SIZE;
+ goto out;
+ }
+ payload = (struct pm8001_ioctl_payload *)ioctlbuffer;
+ memcpy((u8 *)payload->func_specific, (u8 *)pm8001_ha->fw_image->data,
+ pm8001_ha->fw_image->size);
+ payload->length = pm8001_ha->fw_image->size;
+ payload->id = 0;
+ pm8001_ha->nvmd_completion = &completion;
+ ret = PM8001_CHIP_DISP->set_nvmd_req(pm8001_ha, payload);
+ wait_for_completion(&completion);
+out:
+ kfree(ioctlbuffer);
+ return ret;
+}
+
+static int pm8001_update_flash(struct pm8001_hba_info *pm8001_ha)
+{
+ struct pm8001_ioctl_payload *payload;
+ DECLARE_COMPLETION_ONSTACK(completion);
+ u8 *ioctlbuffer = NULL;
+ u32 length = 0;
+ struct fw_control_info *fwControl;
+ u32 loopNumber, loopcount = 0;
+ u32 sizeRead = 0;
+ u32 partitionSize, partitionSizeTmp;
+ u32 ret = 0;
+ u32 partitionNumber = 0;
+ struct pm8001_fw_image_header *image_hdr;
+
+ length = 1024 * 16 + sizeof(*payload) - 1;
+ ioctlbuffer = kzalloc(length, GFP_KERNEL);
+ image_hdr = (struct pm8001_fw_image_header *)pm8001_ha->fw_image->data;
+ if (!ioctlbuffer)
+ return -ENOMEM;
+ if (pm8001_ha->fw_image->size < 28) {
+ ret = FAIL_FILE_SIZE;
+ goto out;
+ }
+
+ while (sizeRead < pm8001_ha->fw_image->size) {
+ partitionSizeTmp =
+ *(u32 *)((u8 *)&image_hdr->image_length + sizeRead);
+ partitionSize = be32_to_cpu(partitionSizeTmp);
+ loopcount = (partitionSize + HEADER_LEN)/IOCTL_BUF_SIZE;
+ if (loopcount % IOCTL_BUF_SIZE)
+ loopcount++;
+ if (loopcount == 0)
+ loopcount++;
+ for (loopNumber = 0; loopNumber < loopcount; loopNumber++) {
+ payload = (struct pm8001_ioctl_payload *)ioctlbuffer;
+ payload->length = 1024*16;
+ payload->id = 0;
+ fwControl =
+ (struct fw_control_info *)payload->func_specific;
+ fwControl->len = IOCTL_BUF_SIZE; /* IN */
+ fwControl->size = partitionSize + HEADER_LEN;/* IN */
+ fwControl->retcode = 0;/* OUT */
+ fwControl->offset = loopNumber * IOCTL_BUF_SIZE;/*OUT */
+
+ /* for the last chunk of data in case file size is not even with
+ 4k, load only the rest*/
+ if (((loopcount-loopNumber) == 1) &&
+ ((partitionSize + HEADER_LEN) % IOCTL_BUF_SIZE)) {
+ fwControl->len =
+ (partitionSize + HEADER_LEN) % IOCTL_BUF_SIZE;
+ memcpy((u8 *)fwControl->buffer,
+ (u8 *)pm8001_ha->fw_image->data + sizeRead,
+ (partitionSize + HEADER_LEN) % IOCTL_BUF_SIZE);
+ sizeRead +=
+ (partitionSize + HEADER_LEN) % IOCTL_BUF_SIZE;
+ } else {
+ memcpy((u8 *)fwControl->buffer,
+ (u8 *)pm8001_ha->fw_image->data + sizeRead,
+ IOCTL_BUF_SIZE);
+ sizeRead += IOCTL_BUF_SIZE;
+ }
+
+ pm8001_ha->nvmd_completion = &completion;
+ ret = PM8001_CHIP_DISP->fw_flash_update_req(pm8001_ha, payload);
+ wait_for_completion(&completion);
+ if (ret || (fwControl->retcode > FLASH_UPDATE_IN_PROGRESS)) {
+ ret = fwControl->retcode;
+ kfree(ioctlbuffer);
+ ioctlbuffer = NULL;
+ break;
+ }
+ }
+ if (ret)
+ break;
+ partitionNumber++;
+}
+out:
+ kfree(ioctlbuffer);
+ return ret;
+}
+static ssize_t pm8001_store_update_fw(struct device *cdev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+ struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
+ char *cmd_ptr, *filename_ptr;
+ int res, i;
+ int flash_command = FLASH_CMD_NONE;
+ int err = 0;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ cmd_ptr = kzalloc(count*2, GFP_KERNEL);
+
+ if (!cmd_ptr) {
+ err = FAIL_OUT_MEMORY;
+ goto out;
+ }
+
+ filename_ptr = cmd_ptr + count;
+ res = sscanf(buf, "%s %s", cmd_ptr, filename_ptr);
+ if (res != 2) {
+ err = FAIL_PARAMETERS;
+ goto out1;
+ }
+
+ for (i = 0; flash_command_table[i].code != FLASH_CMD_NONE; i++) {
+ if (!memcmp(flash_command_table[i].command,
+ cmd_ptr, strlen(cmd_ptr))) {
+ flash_command = flash_command_table[i].code;
+ break;
+ }
+ }
+ if (flash_command == FLASH_CMD_NONE) {
+ err = FAIL_PARAMETERS;
+ goto out1;
+ }
+
+ if (pm8001_ha->fw_status == FLASH_IN_PROGRESS) {
+ err = FLASH_IN_PROGRESS;
+ goto out1;
+ }
+ err = request_firmware(&pm8001_ha->fw_image,
+ filename_ptr,
+ pm8001_ha->dev);
+
+ if (err) {
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("Failed to load firmware image file %s,"
+ " error %d\n", filename_ptr, err));
+ err = FAIL_OPEN_BIOS_FILE;
+ goto out1;
+ }
+
+ switch (flash_command) {
+ case FLASH_CMD_UPDATE:
+ pm8001_ha->fw_status = FLASH_IN_PROGRESS;
+ err = pm8001_update_flash(pm8001_ha);
+ break;
+ case FLASH_CMD_SET_NVMD:
+ pm8001_ha->fw_status = FLASH_IN_PROGRESS;
+ err = pm8001_set_nvmd(pm8001_ha);
+ break;
+ default:
+ pm8001_ha->fw_status = FAIL_PARAMETERS;
+ err = FAIL_PARAMETERS;
+ break;
+ }
+ release_firmware(pm8001_ha->fw_image);
+out1:
+ kfree(cmd_ptr);
+out:
+ pm8001_ha->fw_status = err;
+
+ if (!err)
+ return count;
+ else
+ return -err;
+}
+
+static ssize_t pm8001_show_update_fw(struct device *cdev,
+ struct device_attribute *attr, char *buf)
+{
+ int i;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+ struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
+
+ for (i = 0; flash_error_table[i].err_code != 0; i++) {
+ if (flash_error_table[i].err_code == pm8001_ha->fw_status)
+ break;
+ }
+ if (pm8001_ha->fw_status != FLASH_IN_PROGRESS)
+ pm8001_ha->fw_status = FLASH_OK;
+
+ return snprintf(buf, PAGE_SIZE, "status=%x %s\n",
+ flash_error_table[i].err_code,
+ flash_error_table[i].reason);
+}
+
+static DEVICE_ATTR(update_fw, S_IRUGO|S_IWUGO,
+ pm8001_show_update_fw, pm8001_store_update_fw);
+struct device_attribute *pm8001_host_attrs[] = {
+ &dev_attr_interface_rev,
+ &dev_attr_fw_version,
+ &dev_attr_update_fw,
+ &dev_attr_aap_log,
+ &dev_attr_iop_log,
+ &dev_attr_max_out_io,
+ &dev_attr_max_devices,
+ &dev_attr_max_sg_list,
+ &dev_attr_sas_spec_support,
+ &dev_attr_logging_level,
+ &dev_attr_host_sas_address,
+ NULL,
+};
+
diff --git a/drivers/scsi/pm8001/pm8001_ctl.h b/drivers/scsi/pm8001/pm8001_ctl.h
new file mode 100644
index 0000000..22644de
--- /dev/null
+++ b/drivers/scsi/pm8001/pm8001_ctl.h
@@ -0,0 +1,67 @@
+ /*
+ * PMC-Sierra SPC 8001 SAS/SATA based host adapters driver
+ *
+ * Copyright (c) 2008-2009 USI Co., Ltd.
+ * 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 at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ *
+ */
+
+#ifndef PM8001_CTL_H_INCLUDED
+#define PM8001_CTL_H_INCLUDED
+
+#define IOCTL_BUF_SIZE 4096
+#define HEADER_LEN 28
+#define SIZE_OFFSET 16
+
+struct pm8001_ioctl_payload {
+ u32 signature;
+ u16 major_function;
+ u16 minor_function;
+ u16 length;
+ u16 status;
+ u16 offset;
+ u16 id;
+ u8 func_specific[1];
+};
+
+#define FLASH_OK 0x000000
+#define FAIL_OPEN_BIOS_FILE 0x000100
+#define FAIL_FILE_SIZE 0x000a00
+#define FAIL_PARAMETERS 0x000b00
+#define FAIL_OUT_MEMORY 0x000c00
+#define FLASH_IN_PROGRESS 0x001000
+
+#endif /* PM8001_CTL_H_INCLUDED */
+
diff --git a/drivers/scsi/pm8001/pm8001_defs.h b/drivers/scsi/pm8001/pm8001_defs.h
new file mode 100644
index 0000000..944afad
--- /dev/null
+++ b/drivers/scsi/pm8001/pm8001_defs.h
@@ -0,0 +1,112 @@
+/*
+ * PMC-Sierra SPC 8001 SAS/SATA based host adapters driver
+ *
+ * Copyright (c) 2008-2009 USI Co., Ltd.
+ * 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 at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ *
+ */
+
+#ifndef _PM8001_DEFS_H_
+#define _PM8001_DEFS_H_
+
+enum chip_flavors {
+ chip_8001,
+};
+#define USI_MAX_MEMCNT 9
+#define PM8001_MAX_DMA_SG SG_ALL
+enum phy_speed {
+ PHY_SPEED_15 = 0x01,
+ PHY_SPEED_30 = 0x02,
+ PHY_SPEED_60 = 0x04,
+};
+
+enum data_direction {
+ DATA_DIR_NONE = 0x0, /* NO TRANSFER */
+ DATA_DIR_IN = 0x01, /* INBOUND */
+ DATA_DIR_OUT = 0x02, /* OUTBOUND */
+ DATA_DIR_BYRECIPIENT = 0x04, /* UNSPECIFIED */
+};
+
+enum port_type {
+ PORT_TYPE_SAS = (1L << 1),
+ PORT_TYPE_SATA = (1L << 0),
+};
+
+/* driver compile-time configuration */
+#define PM8001_MAX_CCB 512 /* max ccbs supported */
+#define PM8001_MAX_INB_NUM 1
+#define PM8001_MAX_OUTB_NUM 1
+#define PM8001_CAN_QUEUE 128 /* SCSI Queue depth */
+
+/* unchangeable hardware details */
+#define PM8001_MAX_PHYS 8 /* max. possible phys */
+#define PM8001_MAX_PORTS 8 /* max. possible ports */
+#define PM8001_MAX_DEVICES 1024 /* max supported device */
+
+enum memory_region_num {
+ AAP1 = 0x0, /* application acceleration processor */
+ IOP, /* IO processor */
+ CI, /* consumer index */
+ PI, /* producer index */
+ IB, /* inbound queue */
+ OB, /* outbound queue */
+ NVMD, /* NVM device */
+ DEV_MEM, /* memory for devices */
+ CCB_MEM, /* memory for command control block */
+};
+#define PM8001_EVENT_LOG_SIZE (128 * 1024)
+
+/*error code*/
+enum mpi_err {
+ MPI_IO_STATUS_SUCCESS = 0x0,
+ MPI_IO_STATUS_BUSY = 0x01,
+ MPI_IO_STATUS_FAIL = 0x02,
+};
+
+/**
+ * Phy Control constants
+ */
+enum phy_control_type {
+ PHY_LINK_RESET = 0x01,
+ PHY_HARD_RESET = 0x02,
+ PHY_NOTIFY_ENABLE_SPINUP = 0x10,
+};
+
+enum pm8001_hba_info_flags {
+ PM8001F_INIT_TIME = (1U << 0),
+ PM8001F_RUN_TIME = (1U << 1),
+};
+
+#endif
diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c
new file mode 100644
index 0000000..a3de306
--- /dev/null
+++ b/drivers/scsi/pm8001/pm8001_hwi.c
@@ -0,0 +1,4458 @@
+/*
+ * PMC-Sierra SPC 8001 SAS/SATA based host adapters driver
+ *
+ * Copyright (c) 2008-2009 USI Co., Ltd.
+ * 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 at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ *
+ */
+ #include "pm8001_sas.h"
+ #include "pm8001_hwi.h"
+ #include "pm8001_chips.h"
+ #include "pm8001_ctl.h"
+
+/**
+ * read_main_config_table - read the configure table and save it.
+ * @pm8001_ha: our hba card information
+ */
+static void __devinit read_main_config_table(struct pm8001_hba_info *pm8001_ha)
+{
+ void __iomem *address = pm8001_ha->main_cfg_tbl_addr;
+ pm8001_ha->main_cfg_tbl.signature = pm8001_mr32(address, 0x00);
+ pm8001_ha->main_cfg_tbl.interface_rev = pm8001_mr32(address, 0x04);
+ pm8001_ha->main_cfg_tbl.firmware_rev = pm8001_mr32(address, 0x08);
+ pm8001_ha->main_cfg_tbl.max_out_io = pm8001_mr32(address, 0x0C);
+ pm8001_ha->main_cfg_tbl.max_sgl = pm8001_mr32(address, 0x10);
+ pm8001_ha->main_cfg_tbl.ctrl_cap_flag = pm8001_mr32(address, 0x14);
+ pm8001_ha->main_cfg_tbl.gst_offset = pm8001_mr32(address, 0x18);
+ pm8001_ha->main_cfg_tbl.inbound_queue_offset =
+ pm8001_mr32(address, MAIN_IBQ_OFFSET);
+ pm8001_ha->main_cfg_tbl.outbound_queue_offset =
+ pm8001_mr32(address, MAIN_OBQ_OFFSET);
+ pm8001_ha->main_cfg_tbl.hda_mode_flag =
+ pm8001_mr32(address, MAIN_HDA_FLAGS_OFFSET);
+
+ /* read analog Setting offset from the configuration table */
+ pm8001_ha->main_cfg_tbl.anolog_setup_table_offset =
+ pm8001_mr32(address, MAIN_ANALOG_SETUP_OFFSET);
+
+ /* read Error Dump Offset and Length */
+ pm8001_ha->main_cfg_tbl.fatal_err_dump_offset0 =
+ pm8001_mr32(address, MAIN_FATAL_ERROR_RDUMP0_OFFSET);
+ pm8001_ha->main_cfg_tbl.fatal_err_dump_length0 =
+ pm8001_mr32(address, MAIN_FATAL_ERROR_RDUMP0_LENGTH);
+ pm8001_ha->main_cfg_tbl.fatal_err_dump_offset1 =
+ pm8001_mr32(address, MAIN_FATAL_ERROR_RDUMP1_OFFSET);
+ pm8001_ha->main_cfg_tbl.fatal_err_dump_length1 =
+ pm8001_mr32(address, MAIN_FATAL_ERROR_RDUMP1_LENGTH);
+}
+
+/**
+ * read_general_status_table - read the general status table and save it.
+ * @pm8001_ha: our hba card information
+ */
+static void __devinit
+read_general_status_table(struct pm8001_hba_info *pm8001_ha)
+{
+ void __iomem *address = pm8001_ha->general_stat_tbl_addr;
+ pm8001_ha->gs_tbl.gst_len_mpistate = pm8001_mr32(address, 0x00);
+ pm8001_ha->gs_tbl.iq_freeze_state0 = pm8001_mr32(address, 0x04);
+ pm8001_ha->gs_tbl.iq_freeze_state1 = pm8001_mr32(address, 0x08);
+ pm8001_ha->gs_tbl.msgu_tcnt = pm8001_mr32(address, 0x0C);
+ pm8001_ha->gs_tbl.iop_tcnt = pm8001_mr32(address, 0x10);
+ pm8001_ha->gs_tbl.reserved = pm8001_mr32(address, 0x14);
+ pm8001_ha->gs_tbl.phy_state[0] = pm8001_mr32(address, 0x18);
+ pm8001_ha->gs_tbl.phy_state[1] = pm8001_mr32(address, 0x1C);
+ pm8001_ha->gs_tbl.phy_state[2] = pm8001_mr32(address, 0x20);
+ pm8001_ha->gs_tbl.phy_state[3] = pm8001_mr32(address, 0x24);
+ pm8001_ha->gs_tbl.phy_state[4] = pm8001_mr32(address, 0x28);
+ pm8001_ha->gs_tbl.phy_state[5] = pm8001_mr32(address, 0x2C);
+ pm8001_ha->gs_tbl.phy_state[6] = pm8001_mr32(address, 0x30);
+ pm8001_ha->gs_tbl.phy_state[7] = pm8001_mr32(address, 0x34);
+ pm8001_ha->gs_tbl.reserved1 = pm8001_mr32(address, 0x38);
+ pm8001_ha->gs_tbl.reserved2 = pm8001_mr32(address, 0x3C);
+ pm8001_ha->gs_tbl.reserved3 = pm8001_mr32(address, 0x40);
+ pm8001_ha->gs_tbl.recover_err_info[0] = pm8001_mr32(address, 0x44);
+ pm8001_ha->gs_tbl.recover_err_info[1] = pm8001_mr32(address, 0x48);
+ pm8001_ha->gs_tbl.recover_err_info[2] = pm8001_mr32(address, 0x4C);
+ pm8001_ha->gs_tbl.recover_err_info[3] = pm8001_mr32(address, 0x50);
+ pm8001_ha->gs_tbl.recover_err_info[4] = pm8001_mr32(address, 0x54);
+ pm8001_ha->gs_tbl.recover_err_info[5] = pm8001_mr32(address, 0x58);
+ pm8001_ha->gs_tbl.recover_err_info[6] = pm8001_mr32(address, 0x5C);
+ pm8001_ha->gs_tbl.recover_err_info[7] = pm8001_mr32(address, 0x60);
+}
+
+/**
+ * read_inbnd_queue_table - read the inbound queue table and save it.
+ * @pm8001_ha: our hba card information
+ */
+static void __devinit
+read_inbnd_queue_table(struct pm8001_hba_info *pm8001_ha)
+{
+ int inbQ_num = 1;
+ int i;
+ void __iomem *address = pm8001_ha->inbnd_q_tbl_addr;
+ for (i = 0; i < inbQ_num; i++) {
+ u32 offset = i * 0x20;
+ pm8001_ha->inbnd_q_tbl[i].pi_pci_bar =
+ get_pci_bar_index(pm8001_mr32(address, (offset + 0x14)));
+ pm8001_ha->inbnd_q_tbl[i].pi_offset =
+ pm8001_mr32(address, (offset + 0x18));
+ }
+}
+
+/**
+ * read_outbnd_queue_table - read the outbound queue table and save it.
+ * @pm8001_ha: our hba card information
+ */
+static void __devinit
+read_outbnd_queue_table(struct pm8001_hba_info *pm8001_ha)
+{
+ int outbQ_num = 1;
+ int i;
+ void __iomem *address = pm8001_ha->outbnd_q_tbl_addr;
+ for (i = 0; i < outbQ_num; i++) {
+ u32 offset = i * 0x24;
+ pm8001_ha->outbnd_q_tbl[i].ci_pci_bar =
+ get_pci_bar_index(pm8001_mr32(address, (offset + 0x14)));
+ pm8001_ha->outbnd_q_tbl[i].ci_offset =
+ pm8001_mr32(address, (offset + 0x18));
+ }
+}
+
+/**
+ * init_default_table_values - init the default table.
+ * @pm8001_ha: our hba card information
+ */
+static void __devinit
+init_default_table_values(struct pm8001_hba_info *pm8001_ha)
+{
+ int qn = 1;
+ int i;
+ u32 offsetib, offsetob;
+ void __iomem *addressib = pm8001_ha->inbnd_q_tbl_addr;
+ void __iomem *addressob = pm8001_ha->outbnd_q_tbl_addr;
+
+ pm8001_ha->main_cfg_tbl.inbound_q_nppd_hppd = 0;
+ pm8001_ha->main_cfg_tbl.outbound_hw_event_pid0_3 = 0;
+ pm8001_ha->main_cfg_tbl.outbound_hw_event_pid4_7 = 0;
+ pm8001_ha->main_cfg_tbl.outbound_ncq_event_pid0_3 = 0;
+ pm8001_ha->main_cfg_tbl.outbound_ncq_event_pid4_7 = 0;
+ pm8001_ha->main_cfg_tbl.outbound_tgt_ITNexus_event_pid0_3 = 0;
+ pm8001_ha->main_cfg_tbl.outbound_tgt_ITNexus_event_pid4_7 = 0;
+ pm8001_ha->main_cfg_tbl.outbound_tgt_ssp_event_pid0_3 = 0;
+ pm8001_ha->main_cfg_tbl.outbound_tgt_ssp_event_pid4_7 = 0;
+ pm8001_ha->main_cfg_tbl.outbound_tgt_smp_event_pid0_3 = 0;
+ pm8001_ha->main_cfg_tbl.outbound_tgt_smp_event_pid4_7 = 0;
+
+ pm8001_ha->main_cfg_tbl.upper_event_log_addr =
+ pm8001_ha->memoryMap.region[AAP1].phys_addr_hi;
+ pm8001_ha->main_cfg_tbl.lower_event_log_addr =
+ pm8001_ha->memoryMap.region[AAP1].phys_addr_lo;
+ pm8001_ha->main_cfg_tbl.event_log_size = PM8001_EVENT_LOG_SIZE;
+ pm8001_ha->main_cfg_tbl.event_log_option = 0x01;
+ pm8001_ha->main_cfg_tbl.upper_iop_event_log_addr =
+ pm8001_ha->memoryMap.region[IOP].phys_addr_hi;
+ pm8001_ha->main_cfg_tbl.lower_iop_event_log_addr =
+ pm8001_ha->memoryMap.region[IOP].phys_addr_lo;
+ pm8001_ha->main_cfg_tbl.iop_event_log_size = PM8001_EVENT_LOG_SIZE;
+ pm8001_ha->main_cfg_tbl.iop_event_log_option = 0x01;
+ pm8001_ha->main_cfg_tbl.fatal_err_interrupt = 0x01;
+ for (i = 0; i < qn; i++) {
+ pm8001_ha->inbnd_q_tbl[i].element_pri_size_cnt =
+ 0x00000100 | (0x00000040 << 16) | (0x00<<30);
+ pm8001_ha->inbnd_q_tbl[i].upper_base_addr =
+ pm8001_ha->memoryMap.region[IB].phys_addr_hi;
+ pm8001_ha->inbnd_q_tbl[i].lower_base_addr =
+ pm8001_ha->memoryMap.region[IB].phys_addr_lo;
+ pm8001_ha->inbnd_q_tbl[i].base_virt =
+ (u8 *)pm8001_ha->memoryMap.region[IB].virt_ptr;
+ pm8001_ha->inbnd_q_tbl[i].total_length =
+ pm8001_ha->memoryMap.region[IB].total_len;
+ pm8001_ha->inbnd_q_tbl[i].ci_upper_base_addr =
+ pm8001_ha->memoryMap.region[CI].phys_addr_hi;
+ pm8001_ha->inbnd_q_tbl[i].ci_lower_base_addr =
+ pm8001_ha->memoryMap.region[CI].phys_addr_lo;
+ pm8001_ha->inbnd_q_tbl[i].ci_virt =
+ pm8001_ha->memoryMap.region[CI].virt_ptr;
+ offsetib = i * 0x20;
+ pm8001_ha->inbnd_q_tbl[i].pi_pci_bar =
+ get_pci_bar_index(pm8001_mr32(addressib,
+ (offsetib + 0x14)));
+ pm8001_ha->inbnd_q_tbl[i].pi_offset =
+ pm8001_mr32(addressib, (offsetib + 0x18));
+ pm8001_ha->inbnd_q_tbl[i].producer_idx = 0;
+ pm8001_ha->inbnd_q_tbl[i].consumer_index = 0;
+ }
+ for (i = 0; i < qn; i++) {
+ pm8001_ha->outbnd_q_tbl[i].element_size_cnt =
+ 256 | (64 << 16) | (1<<30);
+ pm8001_ha->outbnd_q_tbl[i].upper_base_addr =
+ pm8001_ha->memoryMap.region[OB].phys_addr_hi;
+ pm8001_ha->outbnd_q_tbl[i].lower_base_addr =
+ pm8001_ha->memoryMap.region[OB].phys_addr_lo;
+ pm8001_ha->outbnd_q_tbl[i].base_virt =
+ (u8 *)pm8001_ha->memoryMap.region[OB].virt_ptr;
+ pm8001_ha->outbnd_q_tbl[i].total_length =
+ pm8001_ha->memoryMap.region[OB].total_len;
+ pm8001_ha->outbnd_q_tbl[i].pi_upper_base_addr =
+ pm8001_ha->memoryMap.region[PI].phys_addr_hi;
+ pm8001_ha->outbnd_q_tbl[i].pi_lower_base_addr =
+ pm8001_ha->memoryMap.region[PI].phys_addr_lo;
+ pm8001_ha->outbnd_q_tbl[i].interrup_vec_cnt_delay =
+ 0 | (10 << 16) | (0 << 24);
+ pm8001_ha->outbnd_q_tbl[i].pi_virt =
+ pm8001_ha->memoryMap.region[PI].virt_ptr;
+ offsetob = i * 0x24;
+ pm8001_ha->outbnd_q_tbl[i].ci_pci_bar =
+ get_pci_bar_index(pm8001_mr32(addressob,
+ offsetob + 0x14));
+ pm8001_ha->outbnd_q_tbl[i].ci_offset =
+ pm8001_mr32(addressob, (offsetob + 0x18));
+ pm8001_ha->outbnd_q_tbl[i].consumer_idx = 0;
+ pm8001_ha->outbnd_q_tbl[i].producer_index = 0;
+ }
+}
+
+/**
+ * update_main_config_table - update the main default table to the HBA.
+ * @pm8001_ha: our hba card information
+ */
+static void __devinit
+update_main_config_table(struct pm8001_hba_info *pm8001_ha)
+{
+ void __iomem *address = pm8001_ha->main_cfg_tbl_addr;
+ pm8001_mw32(address, 0x24,
+ pm8001_ha->main_cfg_tbl.inbound_q_nppd_hppd);
+ pm8001_mw32(address, 0x28,
+ pm8001_ha->main_cfg_tbl.outbound_hw_event_pid0_3);
+ pm8001_mw32(address, 0x2C,
+ pm8001_ha->main_cfg_tbl.outbound_hw_event_pid4_7);
+ pm8001_mw32(address, 0x30,
+ pm8001_ha->main_cfg_tbl.outbound_ncq_event_pid0_3);
+ pm8001_mw32(address, 0x34,
+ pm8001_ha->main_cfg_tbl.outbound_ncq_event_pid4_7);
+ pm8001_mw32(address, 0x38,
+ pm8001_ha->main_cfg_tbl.outbound_tgt_ITNexus_event_pid0_3);
+ pm8001_mw32(address, 0x3C,
+ pm8001_ha->main_cfg_tbl.outbound_tgt_ITNexus_event_pid4_7);
+ pm8001_mw32(address, 0x40,
+ pm8001_ha->main_cfg_tbl.outbound_tgt_ssp_event_pid0_3);
+ pm8001_mw32(address, 0x44,
+ pm8001_ha->main_cfg_tbl.outbound_tgt_ssp_event_pid4_7);
+ pm8001_mw32(address, 0x48,
+ pm8001_ha->main_cfg_tbl.outbound_tgt_smp_event_pid0_3);
+ pm8001_mw32(address, 0x4C,
+ pm8001_ha->main_cfg_tbl.outbound_tgt_smp_event_pid4_7);
+ pm8001_mw32(address, 0x50,
+ pm8001_ha->main_cfg_tbl.upper_event_log_addr);
+ pm8001_mw32(address, 0x54,
+ pm8001_ha->main_cfg_tbl.lower_event_log_addr);
+ pm8001_mw32(address, 0x58, pm8001_ha->main_cfg_tbl.event_log_size);
+ pm8001_mw32(address, 0x5C, pm8001_ha->main_cfg_tbl.event_log_option);
+ pm8001_mw32(address, 0x60,
+ pm8001_ha->main_cfg_tbl.upper_iop_event_log_addr);
+ pm8001_mw32(address, 0x64,
+ pm8001_ha->main_cfg_tbl.lower_iop_event_log_addr);
+ pm8001_mw32(address, 0x68, pm8001_ha->main_cfg_tbl.iop_event_log_size);
+ pm8001_mw32(address, 0x6C,
+ pm8001_ha->main_cfg_tbl.iop_event_log_option);
+ pm8001_mw32(address, 0x70,
+ pm8001_ha->main_cfg_tbl.fatal_err_interrupt);
+}
+
+/**
+ * update_inbnd_queue_table - update the inbound queue table to the HBA.
+ * @pm8001_ha: our hba card information
+ */
+static void __devinit
+update_inbnd_queue_table(struct pm8001_hba_info *pm8001_ha, int number)
+{
+ void __iomem *address = pm8001_ha->inbnd_q_tbl_addr;
+ u16 offset = number * 0x20;
+ pm8001_mw32(address, offset + 0x00,
+ pm8001_ha->inbnd_q_tbl[number].element_pri_size_cnt);
+ pm8001_mw32(address, offset + 0x04,
+ pm8001_ha->inbnd_q_tbl[number].upper_base_addr);
+ pm8001_mw32(address, offset + 0x08,
+ pm8001_ha->inbnd_q_tbl[number].lower_base_addr);
+ pm8001_mw32(address, offset + 0x0C,
+ pm8001_ha->inbnd_q_tbl[number].ci_upper_base_addr);
+ pm8001_mw32(address, offset + 0x10,
+ pm8001_ha->inbnd_q_tbl[number].ci_lower_base_addr);
+}
+
+/**
+ * update_outbnd_queue_table - update the outbound queue table to the HBA.
+ * @pm8001_ha: our hba card information
+ */
+static void __devinit
+update_outbnd_queue_table(struct pm8001_hba_info *pm8001_ha, int number)
+{
+ void __iomem *address = pm8001_ha->outbnd_q_tbl_addr;
+ u16 offset = number * 0x24;
+ pm8001_mw32(address, offset + 0x00,
+ pm8001_ha->outbnd_q_tbl[number].element_size_cnt);
+ pm8001_mw32(address, offset + 0x04,
+ pm8001_ha->outbnd_q_tbl[number].upper_base_addr);
+ pm8001_mw32(address, offset + 0x08,
+ pm8001_ha->outbnd_q_tbl[number].lower_base_addr);
+ pm8001_mw32(address, offset + 0x0C,
+ pm8001_ha->outbnd_q_tbl[number].pi_upper_base_addr);
+ pm8001_mw32(address, offset + 0x10,
+ pm8001_ha->outbnd_q_tbl[number].pi_lower_base_addr);
+ pm8001_mw32(address, offset + 0x1C,
+ pm8001_ha->outbnd_q_tbl[number].interrup_vec_cnt_delay);
+}
+
+/**
+ * bar4_shift - function is called to shift BAR base address
+ * @pm8001_ha : our hba card infomation
+ * @shiftValue : shifting value in memory bar.
+ */
+static int bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue)
+{
+ u32 regVal;
+ u32 max_wait_count;
+
+ /* program the inbound AXI translation Lower Address */
+ pm8001_cw32(pm8001_ha, 1, SPC_IBW_AXI_TRANSLATION_LOW, shiftValue);
+
+ /* confirm the setting is written */
+ max_wait_count = 1 * 1000 * 1000; /* 1 sec */
+ do {
+ udelay(1);
+ regVal = pm8001_cr32(pm8001_ha, 1, SPC_IBW_AXI_TRANSLATION_LOW);
+ } while ((regVal != shiftValue) && (--max_wait_count));
+
+ if (!max_wait_count) {
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("TIMEOUT:SPC_IBW_AXI_TRANSLATION_LOW"
+ " = 0x%x\n", regVal));
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * mpi_set_phys_g3_with_ssc
+ * @pm8001_ha: our hba card information
+ * @SSCbit: set SSCbit to 0 to disable all phys ssc; 1 to enable all phys ssc.
+ */
+static void __devinit
+mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha, u32 SSCbit)
+{
+ u32 offset;
+ u32 value;
+ u32 i, j;
+ u32 bit_cnt;
+
+#define SAS2_SETTINGS_LOCAL_PHY_0_3_SHIFT_ADDR 0x00030000
+#define SAS2_SETTINGS_LOCAL_PHY_4_7_SHIFT_ADDR 0x00040000
+#define SAS2_SETTINGS_LOCAL_PHY_0_3_OFFSET 0x1074
+#define SAS2_SETTINGS_LOCAL_PHY_4_7_OFFSET 0x1074
+#define PHY_G3_WITHOUT_SSC_BIT_SHIFT 12
+#define PHY_G3_WITH_SSC_BIT_SHIFT 13
+#define SNW3_PHY_CAPABILITIES_PARITY 31
+
+ /*
+ * Using shifted destination address 0x3_0000:0x1074 + 0x4000*N (N=0:3)
+ * Using shifted destination address 0x4_0000:0x1074 + 0x4000*(N-4) (N=4:7)
+ */
+ if (-1 == bar4_shift(pm8001_ha, SAS2_SETTINGS_LOCAL_PHY_0_3_SHIFT_ADDR))
+ return;
+ /* set SSC bit of PHY 0 - 3 */
+ for (i = 0; i < 4; i++) {
+ offset = SAS2_SETTINGS_LOCAL_PHY_0_3_OFFSET + 0x4000 * i;
+ value = pm8001_cr32(pm8001_ha, 2, offset);
+ if (SSCbit) {
+ value |= 0x00000001 << PHY_G3_WITH_SSC_BIT_SHIFT;
+ value &= ~(0x00000001 << PHY_G3_WITHOUT_SSC_BIT_SHIFT);
+ } else {
+ value |= 0x00000001 << PHY_G3_WITHOUT_SSC_BIT_SHIFT;
+ value &= ~(0x00000001 << PHY_G3_WITH_SSC_BIT_SHIFT);
+ }
+ bit_cnt = 0;
+ for (j = 0; j < 31; j++)
+ if ((value >> j) & 0x00000001)
+ bit_cnt++;
+ if (bit_cnt % 2)
+ value &= ~(0x00000001 << SNW3_PHY_CAPABILITIES_PARITY);
+ else
+ value |= 0x00000001 << SNW3_PHY_CAPABILITIES_PARITY;
+
+ pm8001_cw32(pm8001_ha, 2, offset, value);
+ }
+
+ /* shift membase 3 for SAS2_SETTINGS_LOCAL_PHY 4 - 7 */
+ if (-1 == bar4_shift(pm8001_ha, SAS2_SETTINGS_LOCAL_PHY_4_7_SHIFT_ADDR))
+ return;
+
+ /* set SSC bit of PHY 4 - 7 */
+ for (i = 4; i < 8; i++) {
+ offset = SAS2_SETTINGS_LOCAL_PHY_4_7_OFFSET + 0x4000 * (i-4);
+ value = pm8001_cr32(pm8001_ha, 2, offset);
+ if (SSCbit) {
+ value |= 0x00000001 << PHY_G3_WITH_SSC_BIT_SHIFT;
+ value &= ~(0x00000001 << PHY_G3_WITHOUT_SSC_BIT_SHIFT);
+ } else {
+ value |= 0x00000001 << PHY_G3_WITHOUT_SSC_BIT_SHIFT;
+ value &= ~(0x00000001 << PHY_G3_WITH_SSC_BIT_SHIFT);
+ }
+ bit_cnt = 0;
+ for (j = 0; j < 31; j++)
+ if ((value >> j) & 0x00000001)
+ bit_cnt++;
+ if (bit_cnt % 2)
+ value &= ~(0x00000001 << SNW3_PHY_CAPABILITIES_PARITY);
+ else
+ value |= 0x00000001 << SNW3_PHY_CAPABILITIES_PARITY;
+
+ pm8001_cw32(pm8001_ha, 2, offset, value);
+ }
+
+ /*set the shifted destination address to 0x0 to avoid error operation */
+ bar4_shift(pm8001_ha, 0x0);
+ return;
+}
+
+/**
+ * mpi_set_open_retry_interval_reg
+ * @pm8001_ha: our hba card information
+ * @interval - interval time for each OPEN_REJECT (RETRY). The units are in 1us.
+ */
+static void __devinit
+mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
+ u32 interval)
+{
+ u32 offset;
+ u32 value;
+ u32 i;
+
+#define OPEN_RETRY_INTERVAL_PHY_0_3_SHIFT_ADDR 0x00030000
+#define OPEN_RETRY_INTERVAL_PHY_4_7_SHIFT_ADDR 0x00040000
+#define OPEN_RETRY_INTERVAL_PHY_0_3_OFFSET 0x30B4
+#define OPEN_RETRY_INTERVAL_PHY_4_7_OFFSET 0x30B4
+#define OPEN_RETRY_INTERVAL_REG_MASK 0x0000FFFF
+
+ value = interval & OPEN_RETRY_INTERVAL_REG_MASK;
+ /* shift bar and set the OPEN_REJECT(RETRY) interval time of PHY 0 -3.*/
+ if (-1 == bar4_shift(pm8001_ha,
+ OPEN_RETRY_INTERVAL_PHY_0_3_SHIFT_ADDR))
+ return;
+ for (i = 0; i < 4; i++) {
+ offset = OPEN_RETRY_INTERVAL_PHY_0_3_OFFSET + 0x4000 * i;
+ pm8001_cw32(pm8001_ha, 2, offset, value);
+ }
+
+ if (-1 == bar4_shift(pm8001_ha,
+ OPEN_RETRY_INTERVAL_PHY_4_7_SHIFT_ADDR))
+ return;
+ for (i = 4; i < 8; i++) {
+ offset = OPEN_RETRY_INTERVAL_PHY_4_7_OFFSET + 0x4000 * (i-4);
+ pm8001_cw32(pm8001_ha, 2, offset, value);
+ }
+ /*set the shifted destination address to 0x0 to avoid error operation */
+ bar4_shift(pm8001_ha, 0x0);
+ return;
+}
+
+/**
+ * mpi_init_check - check firmware initialization status.
+ * @pm8001_ha: our hba card information
+ */
+static int mpi_init_check(struct pm8001_hba_info *pm8001_ha)
+{
+ u32 max_wait_count;
+ u32 value;
+ u32 gst_len_mpistate;
+ /* Write bit0=1 to Inbound DoorBell Register to tell the SPC FW the
+ table is updated */
+ pm8001_cw32(pm8001_ha, 0, MSGU_IBDB_SET, SPC_MSGU_CFG_TABLE_UPDATE);
+ /* wait until Inbound DoorBell Clear Register toggled */
+ max_wait_count = 1 * 1000 * 1000;/* 1 sec */
+ do {
+ udelay(1);
+ value = pm8001_cr32(pm8001_ha, 0, MSGU_IBDB_SET);
+ value &= SPC_MSGU_CFG_TABLE_UPDATE;
+ } while ((value != 0) && (--max_wait_count));
+
+ if (!max_wait_count)
+ return -1;
+ /* check the MPI-State for initialization */
+ gst_len_mpistate =
+ pm8001_mr32(pm8001_ha->general_stat_tbl_addr,
+ GST_GSTLEN_MPIS_OFFSET);
+ if (GST_MPI_STATE_INIT != (gst_len_mpistate & GST_MPI_STATE_MASK))
+ return -1;
+ /* check MPI Initialization error */
+ gst_len_mpistate = gst_len_mpistate >> 16;
+ if (0x0000 != gst_len_mpistate)
+ return -1;
+ return 0;
+}
+
+/**
+ * check_fw_ready - The LLDD check if the FW is ready, if not, return error.
+ * @pm8001_ha: our hba card information
+ */
+static int check_fw_ready(struct pm8001_hba_info *pm8001_ha)
+{
+ u32 value, value1;
+ u32 max_wait_count;
+ /* check error state */
+ value = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1);
+ value1 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2);
+ /* check AAP error */
+ if (SCRATCH_PAD1_ERR == (value & SCRATCH_PAD_STATE_MASK)) {
+ /* error state */
+ value = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0);
+ return -1;
+ }
+
+ /* check IOP error */
+ if (SCRATCH_PAD2_ERR == (value1 & SCRATCH_PAD_STATE_MASK)) {
+ /* error state */
+ value1 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3);
+ return -1;
+ }
+
+ /* bit 4-31 of scratch pad1 should be zeros if it is not
+ in error state*/
+ if (value & SCRATCH_PAD1_STATE_MASK) {
+ /* error case */
+ pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0);
+ return -1;
+ }
+
+ /* bit 2, 4-31 of scratch pad2 should be zeros if it is not
+ in error state */
+ if (value1 & SCRATCH_PAD2_STATE_MASK) {
+ /* error case */
+ return -1;
+ }
+
+ max_wait_count = 1 * 1000 * 1000;/* 1 sec timeout */
+
+ /* wait until scratch pad 1 and 2 registers in ready state */
+ do {
+ udelay(1);
+ value = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1)
+ & SCRATCH_PAD1_RDY;
+ value1 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2)
+ & SCRATCH_PAD2_RDY;
+ if ((--max_wait_count) == 0)
+ return -1;
+ } while ((value != SCRATCH_PAD1_RDY) || (value1 != SCRATCH_PAD2_RDY));
+ return 0;
+}
+
+static void init_pci_device_addresses(struct pm8001_hba_info *pm8001_ha)
+{
+ void __iomem *base_addr;
+ u32 value;
+ u32 offset;
+ u32 pcibar;
+ u32 pcilogic;
+
+ value = pm8001_cr32(pm8001_ha, 0, 0x44);
+ offset = value & 0x03FFFFFF;
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("Scratchpad 0 Offset: %x \n", offset));
+ pcilogic = (value & 0xFC000000) >> 26;
+ pcibar = get_pci_bar_index(pcilogic);
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("Scratchpad 0 PCI BAR: %d \n", pcibar));
+ pm8001_ha->main_cfg_tbl_addr = base_addr =
+ pm8001_ha->io_mem[pcibar].memvirtaddr + offset;
+ pm8001_ha->general_stat_tbl_addr =
+ base_addr + pm8001_cr32(pm8001_ha, pcibar, offset + 0x18);
+ pm8001_ha->inbnd_q_tbl_addr =
+ base_addr + pm8001_cr32(pm8001_ha, pcibar, offset + 0x1C);
+ pm8001_ha->outbnd_q_tbl_addr =
+ base_addr + pm8001_cr32(pm8001_ha, pcibar, offset + 0x20);
+}
+
+/**
+ * pm8001_chip_init - the main init function that initialize whole PM8001 chip.
+ * @pm8001_ha: our hba card information
+ */
+static int __devinit pm8001_chip_init(struct pm8001_hba_info *pm8001_ha)
+{
+ /* check the firmware status */
+ if (-1 == check_fw_ready(pm8001_ha)) {
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("Firmware is not ready!\n"));
+ return -EBUSY;
+ }
+
+ /* Initialize pci space address eg: mpi offset */
+ init_pci_device_addresses(pm8001_ha);
+ init_default_table_values(pm8001_ha);
+ read_main_config_table(pm8001_ha);
+ read_general_status_table(pm8001_ha);
+ read_inbnd_queue_table(pm8001_ha);
+ read_outbnd_queue_table(pm8001_ha);
+ /* update main config table ,inbound table and outbound table */
+ update_main_config_table(pm8001_ha);
+ update_inbnd_queue_table(pm8001_ha, 0);
+ update_outbnd_queue_table(pm8001_ha, 0);
+ mpi_set_phys_g3_with_ssc(pm8001_ha, 0);
+ mpi_set_open_retry_interval_reg(pm8001_ha, 7);
+ /* notify firmware update finished and check initialization status */
+ if (0 == mpi_init_check(pm8001_ha)) {
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("MPI initialize successful!\n"));
+ } else
+ return -EBUSY;
+ /*This register is a 16-bit timer with a resolution of 1us. This is the
+ timer used for interrupt delay/coalescing in the PCIe Application Layer.
+ Zero is not a valid value. A value of 1 in the register will cause the
+ interrupts to be normal. A value greater than 1 will cause coalescing
+ delays.*/
+ pm8001_cw32(pm8001_ha, 1, 0x0033c0, 0x1);
+ pm8001_cw32(pm8001_ha, 1, 0x0033c4, 0x0);
+ return 0;
+}
+
+static int mpi_uninit_check(struct pm8001_hba_info *pm8001_ha)
+{
+ u32 max_wait_count;
+ u32 value;
+ u32 gst_len_mpistate;
+ init_pci_device_addresses(pm8001_ha);
+ /* Write bit1=1 to Inbound DoorBell Register to tell the SPC FW the
+ table is stop */
+ pm8001_cw32(pm8001_ha, 0, MSGU_IBDB_SET, SPC_MSGU_CFG_TABLE_RESET);
+
+ /* wait until Inbound DoorBell Clear Register toggled */
+ max_wait_count = 1 * 1000 * 1000;/* 1 sec */
+ do {
+ udelay(1);
+ value = pm8001_cr32(pm8001_ha, 0, MSGU_IBDB_SET);
+ value &= SPC_MSGU_CFG_TABLE_RESET;
+ } while ((value != 0) && (--max_wait_count));
+
+ if (!max_wait_count) {
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("TIMEOUT:IBDB value/=0x%x\n", value));
+ return -1;
+ }
+
+ /* check the MPI-State for termination in progress */
+ /* wait until Inbound DoorBell Clear Register toggled */
+ max_wait_count = 1 * 1000 * 1000; /* 1 sec */
+ do {
+ udelay(1);
+ gst_len_mpistate =
+ pm8001_mr32(pm8001_ha->general_stat_tbl_addr,
+ GST_GSTLEN_MPIS_OFFSET);
+ if (GST_MPI_STATE_UNINIT ==
+ (gst_len_mpistate & GST_MPI_STATE_MASK))
+ break;
+ } while (--max_wait_count);
+ if (!max_wait_count) {
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk(" TIME OUT MPI State = 0x%x\n",
+ gst_len_mpistate & GST_MPI_STATE_MASK));
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * soft_reset_ready_check - Function to check FW is ready for soft reset.
+ * @pm8001_ha: our hba card information
+ */
+static u32 soft_reset_ready_check(struct pm8001_hba_info *pm8001_ha)
+{
+ u32 regVal, regVal1, regVal2;
+ if (mpi_uninit_check(pm8001_ha) != 0) {
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("MPI state is not ready\n"));
+ return -1;
+ }
+ /* read the scratch pad 2 register bit 2 */
+ regVal = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2)
+ & SCRATCH_PAD2_FWRDY_RST;
+ if (regVal == SCRATCH_PAD2_FWRDY_RST) {
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("Firmware is ready for reset .\n"));
+ } else {
+ /* Trigger NMI twice via RB6 */
+ if (-1 == bar4_shift(pm8001_ha, RB6_ACCESS_REG)) {
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("Shift Bar4 to 0x%x failed\n",
+ RB6_ACCESS_REG));
+ return -1;
+ }
+ pm8001_cw32(pm8001_ha, 2, SPC_RB6_OFFSET,
+ RB6_MAGIC_NUMBER_RST);
+ pm8001_cw32(pm8001_ha, 2, SPC_RB6_OFFSET, RB6_MAGIC_NUMBER_RST);
+ /* wait for 100 ms */
+ mdelay(100);
+ regVal = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2) &
+ SCRATCH_PAD2_FWRDY_RST;
+ if (regVal != SCRATCH_PAD2_FWRDY_RST) {
+ regVal1 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1);
+ regVal2 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2);
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("TIMEOUT:MSGU_SCRATCH_PAD1"
+ "=0x%x, MSGU_SCRATCH_PAD2=0x%x\n",
+ regVal1, regVal2));
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("SCRATCH_PAD0 value = 0x%x\n",
+ pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0)));
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
+ pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3)));
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/**
+ * pm8001_chip_soft_rst - soft reset the PM8001 chip, so that the clear all
+ * the FW register status to the originated status.
+ * @pm8001_ha: our hba card information
+ * @signature: signature in host scratch pad0 register.
+ */
+static int
+pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha, u32 signature)
+{
+ u32 regVal, toggleVal;
+ u32 max_wait_count;
+ u32 regVal1, regVal2, regVal3;
+
+ /* step1: Check FW is ready for soft reset */
+ if (soft_reset_ready_check(pm8001_ha) != 0) {
+ PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("FW is not ready\n"));
+ return -1;
+ }
+
+ /* step 2: clear NMI status register on AAP1 and IOP, write the same
+ value to clear */
+ /* map 0x60000 to BAR4(0x20), BAR2(win) */
+ if (-1 == bar4_shift(pm8001_ha, MBIC_AAP1_ADDR_BASE)) {
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("Shift Bar4 to 0x%x failed\n",
+ MBIC_AAP1_ADDR_BASE));
+ return -1;
+ }
+ regVal = pm8001_cr32(pm8001_ha, 2, MBIC_NMI_ENABLE_VPE0_IOP);
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("MBIC - NMI Enable VPE0 (IOP)= 0x%x\n", regVal));
+ pm8001_cw32(pm8001_ha, 2, MBIC_NMI_ENABLE_VPE0_IOP, 0x0);
+ /* map 0x70000 to BAR4(0x20), BAR2(win) */
+ if (-1 == bar4_shift(pm8001_ha, MBIC_IOP_ADDR_BASE)) {
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("Shift Bar4 to 0x%x failed\n",
+ MBIC_IOP_ADDR_BASE));
+ return -1;
+ }
+ regVal = pm8001_cr32(pm8001_ha, 2, MBIC_NMI_ENABLE_VPE0_AAP1);
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("MBIC - NMI Enable VPE0 (AAP1)= 0x%x\n", regVal));
+ pm8001_cw32(pm8001_ha, 2, MBIC_NMI_ENABLE_VPE0_AAP1, 0x0);
+
+ regVal = pm8001_cr32(pm8001_ha, 1, PCIE_EVENT_INTERRUPT_ENABLE);
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("PCIE -Event Interrupt Enable = 0x%x\n", regVal));
+ pm8001_cw32(pm8001_ha, 1, PCIE_EVENT_INTERRUPT_ENABLE, 0x0);
+
+ regVal = pm8001_cr32(pm8001_ha, 1, PCIE_EVENT_INTERRUPT);
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("PCIE - Event Interrupt = 0x%x\n", regVal));
+ pm8001_cw32(pm8001_ha, 1, PCIE_EVENT_INTERRUPT, regVal);
+
+ regVal = pm8001_cr32(pm8001_ha, 1, PCIE_ERROR_INTERRUPT_ENABLE);
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("PCIE -Error Interrupt Enable = 0x%x\n", regVal));
+ pm8001_cw32(pm8001_ha, 1, PCIE_ERROR_INTERRUPT_ENABLE, 0x0);
+
+ regVal = pm8001_cr32(pm8001_ha, 1, PCIE_ERROR_INTERRUPT);
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("PCIE - Error Interrupt = 0x%x\n", regVal));
+ pm8001_cw32(pm8001_ha, 1, PCIE_ERROR_INTERRUPT, regVal);
+
+ /* read the scratch pad 1 register bit 2 */
+ regVal = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1)
+ & SCRATCH_PAD1_RST;
+ toggleVal = regVal ^ SCRATCH_PAD1_RST;
+
+ /* set signature in host scratch pad0 register to tell SPC that the
+ host performs the soft reset */
+ pm8001_cw32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_0, signature);
+
+ /* read required registers for confirmming */
+ /* map 0x0700000 to BAR4(0x20), BAR2(win) */
+ if (-1 == bar4_shift(pm8001_ha, GSM_ADDR_BASE)) {
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("Shift Bar4 to 0x%x failed\n",
+ GSM_ADDR_BASE));
+ return -1;
+ }
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("GSM 0x0(0x00007b88)-GSM Configuration and"
+ " Reset = 0x%x\n",
+ pm8001_cr32(pm8001_ha, 2, GSM_CONFIG_RESET)));
+
+ /* step 3: host read GSM Configuration and Reset register */
+ regVal = pm8001_cr32(pm8001_ha, 2, GSM_CONFIG_RESET);
+ /* Put those bits to low */
+ /* GSM XCBI offset = 0x70 0000
+ 0x00 Bit 13 COM_SLV_SW_RSTB 1
+ 0x00 Bit 12 QSSP_SW_RSTB 1
+ 0x00 Bit 11 RAAE_SW_RSTB 1
+ 0x00 Bit 9 RB_1_SW_RSTB 1
+ 0x00 Bit 8 SM_SW_RSTB 1
+ */
+ regVal &= ~(0x00003b00);
+ /* host write GSM Configuration and Reset register */
+ pm8001_cw32(pm8001_ha, 2, GSM_CONFIG_RESET, regVal);
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("GSM 0x0 (0x00007b88 ==> 0x00004088) - GSM "
+ "Configuration and Reset is set to = 0x%x\n",
+ pm8001_cr32(pm8001_ha, 2, GSM_CONFIG_RESET)));
+
+ /* step 4: */
+ /* disable GSM - Read Address Parity Check */
+ regVal1 = pm8001_cr32(pm8001_ha, 2, GSM_READ_ADDR_PARITY_CHECK);
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("GSM 0x700038 - Read Address Parity Check "
+ "Enable = 0x%x\n", regVal1));
+ pm8001_cw32(pm8001_ha, 2, GSM_READ_ADDR_PARITY_CHECK, 0x0);
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("GSM 0x700038 - Read Address Parity Check Enable"
+ "is set to = 0x%x\n",
+ pm8001_cr32(pm8001_ha, 2, GSM_READ_ADDR_PARITY_CHECK)));
+
+ /* disable GSM - Write Address Parity Check */
+ regVal2 = pm8001_cr32(pm8001_ha, 2, GSM_WRITE_ADDR_PARITY_CHECK);
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("GSM 0x700040 - Write Address Parity Check"
+ " Enable = 0x%x\n", regVal2));
+ pm8001_cw32(pm8001_ha, 2, GSM_WRITE_ADDR_PARITY_CHECK, 0x0);
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("GSM 0x700040 - Write Address Parity Check "
+ "Enable is set to = 0x%x\n",
+ pm8001_cr32(pm8001_ha, 2, GSM_WRITE_ADDR_PARITY_CHECK)));
+
+ /* disable GSM - Write Data Parity Check */
+ regVal3 = pm8001_cr32(pm8001_ha, 2, GSM_WRITE_DATA_PARITY_CHECK);
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("GSM 0x300048 - Write Data Parity Check"
+ " Enable = 0x%x\n", regVal3));
+ pm8001_cw32(pm8001_ha, 2, GSM_WRITE_DATA_PARITY_CHECK, 0x0);
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("GSM 0x300048 - Write Data Parity Check Enable"
+ "is set to = 0x%x\n",
+ pm8001_cr32(pm8001_ha, 2, GSM_WRITE_DATA_PARITY_CHECK)));
+
+ /* step 5: delay 10 usec */
+ udelay(10);
+ /* step 5-b: set GPIO-0 output control to tristate anyway */
+ if (-1 == bar4_shift(pm8001_ha, GPIO_ADDR_BASE)) {
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("Shift Bar4 to 0x%x failed\n",
+ GPIO_ADDR_BASE));
+ return -1;
+ }
+ regVal = pm8001_cr32(pm8001_ha, 2, GPIO_GPIO_0_0UTPUT_CTL_OFFSET);
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("GPIO Output Control Register:"
+ " = 0x%x\n", regVal));
+ /* set GPIO-0 output control to tri-state */
+ regVal &= 0xFFFFFFFC;
+ pm8001_cw32(pm8001_ha, 2, GPIO_GPIO_0_0UTPUT_CTL_OFFSET, regVal);
+
+ /* Step 6: Reset the IOP and AAP1 */
+ /* map 0x00000 to BAR4(0x20), BAR2(win) */
+ if (-1 == bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) {
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("SPC Shift Bar4 to 0x%x failed\n",
+ SPC_TOP_LEVEL_ADDR_BASE));
+ return -1;
+ }
+ regVal = pm8001_cr32(pm8001_ha, 2, SPC_REG_RESET);
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("Top Register before resetting IOP/AAP1"
+ ":= 0x%x\n", regVal));
+ regVal &= ~(SPC_REG_RESET_PCS_IOP_SS | SPC_REG_RESET_PCS_AAP1_SS);
+ pm8001_cw32(pm8001_ha, 2, SPC_REG_RESET, regVal);
+
+ /* step 7: Reset the BDMA/OSSP */
+ regVal = pm8001_cr32(pm8001_ha, 2, SPC_REG_RESET);
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("Top Register before resetting BDMA/OSSP"
+ ": = 0x%x\n", regVal));
+ regVal &= ~(SPC_REG_RESET_BDMA_CORE | SPC_REG_RESET_OSSP);
+ pm8001_cw32(pm8001_ha, 2, SPC_REG_RESET, regVal);
+
+ /* step 8: delay 10 usec */
+ udelay(10);
+
+ /* step 9: bring the BDMA and OSSP out of reset */
+ regVal = pm8001_cr32(pm8001_ha, 2, SPC_REG_RESET);
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("Top Register before bringing up BDMA/OSSP"
+ ":= 0x%x\n", regVal));
+ regVal |= (SPC_REG_RESET_BDMA_CORE | SPC_REG_RESET_OSSP);
+ pm8001_cw32(pm8001_ha, 2, SPC_REG_RESET, regVal);
+
+ /* step 10: delay 10 usec */
+ udelay(10);
+
+ /* step 11: reads and sets the GSM Configuration and Reset Register */
+ /* map 0x0700000 to BAR4(0x20), BAR2(win) */
+ if (-1 == bar4_shift(pm8001_ha, GSM_ADDR_BASE)) {
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("SPC Shift Bar4 to 0x%x failed\n",
+ GSM_ADDR_BASE));
+ return -1;
+ }
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("GSM 0x0 (0x00007b88)-GSM Configuration and "
+ "Reset = 0x%x\n", pm8001_cr32(pm8001_ha, 2, GSM_CONFIG_RESET)));
+ regVal = pm8001_cr32(pm8001_ha, 2, GSM_CONFIG_RESET);
+ /* Put those bits to high */
+ /* GSM XCBI offset = 0x70 0000
+ 0x00 Bit 13 COM_SLV_SW_RSTB 1
+ 0x00 Bit 12 QSSP_SW_RSTB 1
+ 0x00 Bit 11 RAAE_SW_RSTB 1
+ 0x00 Bit 9 RB_1_SW_RSTB 1
+ 0x00 Bit 8 SM_SW_RSTB 1
+ */
+ regVal |= (GSM_CONFIG_RESET_VALUE);
+ pm8001_cw32(pm8001_ha, 2, GSM_CONFIG_RESET, regVal);
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("GSM (0x00004088 ==> 0x00007b88) - GSM"
+ " Configuration and Reset is set to = 0x%x\n",
+ pm8001_cr32(pm8001_ha, 2, GSM_CONFIG_RESET)));
+
+ /* step 12: Restore GSM - Read Address Parity Check */
+ regVal = pm8001_cr32(pm8001_ha, 2, GSM_READ_ADDR_PARITY_CHECK);
+ /* just for debugging */
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("GSM 0x700038 - Read Address Parity Check Enable"
+ " = 0x%x\n", regVal));
+ pm8001_cw32(pm8001_ha, 2, GSM_READ_ADDR_PARITY_CHECK, regVal1);
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("GSM 0x700038 - Read Address Parity"
+ " Check Enable is set to = 0x%x\n",
+ pm8001_cr32(pm8001_ha, 2, GSM_READ_ADDR_PARITY_CHECK)));
+ /* Restore GSM - Write Address Parity Check */
+ regVal = pm8001_cr32(pm8001_ha, 2, GSM_WRITE_ADDR_PARITY_CHECK);
+ pm8001_cw32(pm8001_ha, 2, GSM_WRITE_ADDR_PARITY_CHECK, regVal2);
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("GSM 0x700040 - Write Address Parity Check"
+ " Enable is set to = 0x%x\n",
+ pm8001_cr32(pm8001_ha, 2, GSM_WRITE_ADDR_PARITY_CHECK)));
+ /* Restore GSM - Write Data Parity Check */
+ regVal = pm8001_cr32(pm8001_ha, 2, GSM_WRITE_DATA_PARITY_CHECK);
+ pm8001_cw32(pm8001_ha, 2, GSM_WRITE_DATA_PARITY_CHECK, regVal3);
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("GSM 0x700048 - Write Data Parity Check Enable"
+ "is set to = 0x%x\n",
+ pm8001_cr32(pm8001_ha, 2, GSM_WRITE_DATA_PARITY_CHECK)));
+
+ /* step 13: bring the IOP and AAP1 out of reset */
+ /* map 0x00000 to BAR4(0x20), BAR2(win) */
+ if (-1 == bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) {
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("Shift Bar4 to 0x%x failed\n",
+ SPC_TOP_LEVEL_ADDR_BASE));
+ return -1;
+ }
+ regVal = pm8001_cr32(pm8001_ha, 2, SPC_REG_RESET);
+ regVal |= (SPC_REG_RESET_PCS_IOP_SS | SPC_REG_RESET_PCS_AAP1_SS);
+ pm8001_cw32(pm8001_ha, 2, SPC_REG_RESET, regVal);
+
+ /* step 14: delay 10 usec - Normal Mode */
+ udelay(10);
+ /* check Soft Reset Normal mode or Soft Reset HDA mode */
+ if (signature == SPC_SOFT_RESET_SIGNATURE) {
+ /* step 15 (Normal Mode): wait until scratch pad1 register
+ bit 2 toggled */
+ max_wait_count = 2 * 1000 * 1000;/* 2 sec */
+ do {
+ udelay(1);
+ regVal = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1) &
+ SCRATCH_PAD1_RST;
+ } while ((regVal != toggleVal) && (--max_wait_count));
+
+ if (!max_wait_count) {
+ regVal = pm8001_cr32(pm8001_ha, 0,
+ MSGU_SCRATCH_PAD_1);
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("TIMEOUT : ToggleVal 0x%x,"
+ "MSGU_SCRATCH_PAD1 = 0x%x\n",
+ toggleVal, regVal));
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("SCRATCH_PAD0 value = 0x%x\n",
+ pm8001_cr32(pm8001_ha, 0,
+ MSGU_SCRATCH_PAD_0)));
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("SCRATCH_PAD2 value = 0x%x\n",
+ pm8001_cr32(pm8001_ha, 0,
+ MSGU_SCRATCH_PAD_2)));
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
+ pm8001_cr32(pm8001_ha, 0,
+ MSGU_SCRATCH_PAD_3)));
+ return -1;
+ }
+
+ /* step 16 (Normal) - Clear ODMR and ODCR */
+ pm8001_cw32(pm8001_ha, 0, MSGU_ODCR, ODCR_CLEAR_ALL);
+ pm8001_cw32(pm8001_ha, 0, MSGU_ODMR, ODMR_CLEAR_ALL);
+
+ /* step 17 (Normal Mode): wait for the FW and IOP to get
+ ready - 1 sec timeout */
+ /* Wait for the SPC Configuration Table to be ready */
+ if (check_fw_ready(pm8001_ha) == -1) {
+ regVal = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1);
+ /* return error if MPI Configuration Table not ready */
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("FW not ready SCRATCH_PAD1"
+ " = 0x%x\n", regVal));
+ regVal = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2);
+ /* return error if MPI Configuration Table not ready */
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("FW not ready SCRATCH_PAD2"
+ " = 0x%x\n", regVal));
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("SCRATCH_PAD0 value = 0x%x\n",
+ pm8001_cr32(pm8001_ha, 0,
+ MSGU_SCRATCH_PAD_0)));
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
+ pm8001_cr32(pm8001_ha, 0,
+ MSGU_SCRATCH_PAD_3)));
+ return -1;
+ }
+ }
+
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("SPC soft reset Complete\n"));
+ return 0;
+}
+
+static void pm8001_hw_chip_rst(struct pm8001_hba_info *pm8001_ha)
+{
+ u32 i;
+ u32 regVal;
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("chip reset start\n"));
+
+ /* do SPC chip reset. */
+ regVal = pm8001_cr32(pm8001_ha, 1, SPC_REG_RESET);
+ regVal &= ~(SPC_REG_RESET_DEVICE);
+ pm8001_cw32(pm8001_ha, 1, SPC_REG_RESET, regVal);
+
+ /* delay 10 usec */
+ udelay(10);
+
+ /* bring chip reset out of reset */
+ regVal = pm8001_cr32(pm8001_ha, 1, SPC_REG_RESET);
+ regVal |= SPC_REG_RESET_DEVICE;
+ pm8001_cw32(pm8001_ha, 1, SPC_REG_RESET, regVal);
+
+ /* delay 10 usec */
+ udelay(10);
+
+ /* wait for 20 msec until the firmware gets reloaded */
+ i = 20;
+ do {
+ mdelay(1);
+ } while ((--i) != 0);
+
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("chip reset finished\n"));
+}
+
+/**
+ * pm8001_chip_iounmap - which maped when initilized.
+ * @pm8001_ha: our hba card information
+ */
+static void pm8001_chip_iounmap(struct pm8001_hba_info *pm8001_ha)
+{
+ s8 bar, logical = 0;
+ for (bar = 0; bar < 6; bar++) {
+ /*
+ ** logical BARs for SPC:
+ ** bar 0 and 1 - logical BAR0
+ ** bar 2 and 3 - logical BAR1
+ ** bar4 - logical BAR2
+ ** bar5 - logical BAR3
+ ** Skip the appropriate assignments:
+ */
+ if ((bar == 1) || (bar == 3))
+ continue;
+ if (pm8001_ha->io_mem[logical].memvirtaddr) {
+ iounmap(pm8001_ha->io_mem[logical].memvirtaddr);
+ logical++;
+ }
+ }
+}
+
+/**
+ * pm8001_chip_interrupt_enable - enable PM8001 chip interrupt
+ * @pm8001_ha: our hba card information
+ */
+static void
+pm8001_chip_intx_interrupt_enable(struct pm8001_hba_info *pm8001_ha)
+{
+ pm8001_cw32(pm8001_ha, 0, MSGU_ODMR, ODMR_CLEAR_ALL);
+ pm8001_cw32(pm8001_ha, 0, MSGU_ODCR, ODCR_CLEAR_ALL);
+}
+
+ /**
+ * pm8001_chip_intx_interrupt_disable- disable PM8001 chip interrupt
+ * @pm8001_ha: our hba card information
+ */
+static void
+pm8001_chip_intx_interrupt_disable(struct pm8001_hba_info *pm8001_ha)
+{
+ pm8001_cw32(pm8001_ha, 0, MSGU_ODMR, ODMR_MASK_ALL);
+}
+
+/**
+ * pm8001_chip_msix_interrupt_enable - enable PM8001 chip interrupt
+ * @pm8001_ha: our hba card information
+ */
+static void
+pm8001_chip_msix_interrupt_enable(struct pm8001_hba_info *pm8001_ha,
+ u32 int_vec_idx)
+{
+ u32 msi_index;
+ u32 value;
+ msi_index = int_vec_idx * MSIX_TABLE_ELEMENT_SIZE;
+ msi_index += MSIX_TABLE_BASE;
+ pm8001_cw32(pm8001_ha, 0, msi_index, MSIX_INTERRUPT_ENABLE);
+ value = (1 << int_vec_idx);
+ pm8001_cw32(pm8001_ha, 0, MSGU_ODCR, value);
+
+}
+
+/**
+ * pm8001_chip_msix_interrupt_disable - disable PM8001 chip interrupt
+ * @pm8001_ha: our hba card information
+ */
+static void
+pm8001_chip_msix_interrupt_disable(struct pm8001_hba_info *pm8001_ha,
+ u32 int_vec_idx)
+{
+ u32 msi_index;
+ msi_index = int_vec_idx * MSIX_TABLE_ELEMENT_SIZE;
+ msi_index += MSIX_TABLE_BASE;
+ pm8001_cw32(pm8001_ha, 0, msi_index, MSIX_INTERRUPT_DISABLE);
+
+}
+/**
+ * pm8001_chip_interrupt_enable - enable PM8001 chip interrupt
+ * @pm8001_ha: our hba card information
+ */
+static void
+pm8001_chip_interrupt_enable(struct pm8001_hba_info *pm8001_ha)
+{
+#ifdef PM8001_USE_MSIX
+ pm8001_chip_msix_interrupt_enable(pm8001_ha, 0);
+ return;
+#endif
+ pm8001_chip_intx_interrupt_enable(pm8001_ha);
+
+}
+
+/**
+ * pm8001_chip_intx_interrupt_disable- disable PM8001 chip interrupt
+ * @pm8001_ha: our hba card information
+ */
+static void
+pm8001_chip_interrupt_disable(struct pm8001_hba_info *pm8001_ha)
+{
+#ifdef PM8001_USE_MSIX
+ pm8001_chip_msix_interrupt_disable(pm8001_ha, 0);
+ return;
+#endif
+ pm8001_chip_intx_interrupt_disable(pm8001_ha);
+
+}
+
+/**
+ * mpi_msg_free_get- get the free message buffer for transfer inbound queue.
+ * @circularQ: the inbound queue we want to transfer to HBA.
+ * @messageSize: the message size of this transfer, normally it is 64 bytes
+ * @messagePtr: the pointer to message.
+ */
+static int mpi_msg_free_get(struct inbound_queue_table *circularQ,
+ u16 messageSize, void **messagePtr)
+{
+ u32 offset, consumer_index;
+ struct mpi_msg_hdr *msgHeader;
+ u8 bcCount = 1; /* only support single buffer */
+
+ /* Checks is the requested message size can be allocated in this queue*/
+ if (messageSize > 64) {
+ *messagePtr = NULL;
+ return -1;
+ }
+
+ /* Stores the new consumer index */
+ consumer_index = pm8001_read_32(circularQ->ci_virt);
+ circularQ->consumer_index = cpu_to_le32(consumer_index);
+ if (((circularQ->producer_idx + bcCount) % 256) ==
+ circularQ->consumer_index) {
+ *messagePtr = NULL;
+ return -1;
+ }
+ /* get memory IOMB buffer address */
+ offset = circularQ->producer_idx * 64;
+ /* increment to next bcCount element */
+ circularQ->producer_idx = (circularQ->producer_idx + bcCount) % 256;
+ /* Adds that distance to the base of the region virtual address plus
+ the message header size*/
+ msgHeader = (struct mpi_msg_hdr *)(circularQ->base_virt + offset);
+ *messagePtr = ((void *)msgHeader) + sizeof(struct mpi_msg_hdr);
+ return 0;
+}
+
+/**
+ * mpi_build_cmd- build the message queue for transfer, update the PI to FW
+ * to tell the fw to get this message from IOMB.
+ * @pm8001_ha: our hba card information
+ * @circularQ: the inbound queue we want to transfer to HBA.
+ * @opCode: the operation code represents commands which LLDD and fw recognized.
+ * @payload: the command payload of each operation command.
+ */
+static int mpi_build_cmd(struct pm8001_hba_info *pm8001_ha,
+ struct inbound_queue_table *circularQ,
+ u32 opCode, void *payload)
+{
+ u32 Header = 0, hpriority = 0, bc = 1, category = 0x02;
+ u32 responseQueue = 0;
+ void *pMessage;
+
+ if (mpi_msg_free_get(circularQ, 64, &pMessage) < 0) {
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("No free mpi buffer \n"));
+ return -1;
+ }
+ BUG_ON(!payload);
+ /*Copy to the payload*/
+ memcpy(pMessage, payload, (64 - sizeof(struct mpi_msg_hdr)));
+
+ /*Build the header*/
+ Header = ((1 << 31) | (hpriority << 30) | ((bc & 0x1f) << 24)
+ | ((responseQueue & 0x3F) << 16)
+ | ((category & 0xF) << 12) | (opCode & 0xFFF));
+
+ pm8001_write_32((pMessage - 4), 0, cpu_to_le32(Header));
+ /*Update the PI to the firmware*/
+ pm8001_cw32(pm8001_ha, circularQ->pi_pci_bar,
+ circularQ->pi_offset, circularQ->producer_idx);
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("after PI= %d CI= %d \n", circularQ->producer_idx,
+ circularQ->consumer_index));
+ return 0;
+}
+
+static u32 mpi_msg_free_set(struct pm8001_hba_info *pm8001_ha, void *pMsg,
+ struct outbound_queue_table *circularQ, u8 bc)
+{
+ u32 producer_index;
+ struct mpi_msg_hdr *msgHeader;
+ struct mpi_msg_hdr *pOutBoundMsgHeader;
+
+ msgHeader = (struct mpi_msg_hdr *)(pMsg - sizeof(struct mpi_msg_hdr));
+ pOutBoundMsgHeader = (struct mpi_msg_hdr *)(circularQ->base_virt +
+ circularQ->consumer_idx * 64);
+ if (pOutBoundMsgHeader != msgHeader) {
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("consumer_idx = %d msgHeader = %p\n",
+ circularQ->consumer_idx, msgHeader));
+
+ /* Update the producer index from SPC */
+ producer_index = pm8001_read_32(circularQ->pi_virt);
+ circularQ->producer_index = cpu_to_le32(producer_index);
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("consumer_idx = %d producer_index = %d"
+ "msgHeader = %p\n", circularQ->consumer_idx,
+ circularQ->producer_index, msgHeader));
+ return 0;
+ }
+ /* free the circular queue buffer elements associated with the message*/
+ circularQ->consumer_idx = (circularQ->consumer_idx + bc) % 256;
+ /* update the CI of outbound queue */
+ pm8001_cw32(pm8001_ha, circularQ->ci_pci_bar, circularQ->ci_offset,
+ circularQ->consumer_idx);
+ /* Update the producer index from SPC*/
+ producer_index = pm8001_read_32(circularQ->pi_virt);
+ circularQ->producer_index = cpu_to_le32(producer_index);
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk(" CI=%d PI=%d\n", circularQ->consumer_idx,
+ circularQ->producer_index));
+ return 0;
+}
+
+/**
+ * mpi_msg_consume- get the MPI message from outbound queue message table.
+ * @pm8001_ha: our hba card information
+ * @circularQ: the outbound queue table.
+ * @messagePtr1: the message contents of this outbound message.
+ * @pBC: the message size.
+ */
+static u32 mpi_msg_consume(struct pm8001_hba_info *pm8001_ha,
+ struct outbound_queue_table *circularQ,
+ void **messagePtr1, u8 *pBC)
+{
+ struct mpi_msg_hdr *msgHeader;
+ __le32 msgHeader_tmp;
+ u32 header_tmp;
+ do {
+ /* If there are not-yet-delivered messages ... */
+ if (circularQ->producer_index != circularQ->consumer_idx) {
+ /*Get the pointer to the circular queue buffer element*/
+ msgHeader = (struct mpi_msg_hdr *)
+ (circularQ->base_virt +
+ circularQ->consumer_idx * 64);
+ /* read header */
+ header_tmp = pm8001_read_32(msgHeader);
+ msgHeader_tmp = cpu_to_le32(header_tmp);
+ if (0 != (msgHeader_tmp & 0x80000000)) {
+ if (OPC_OUB_SKIP_ENTRY !=
+ (msgHeader_tmp & 0xfff)) {
+ *messagePtr1 =
+ ((u8 *)msgHeader) +
+ sizeof(struct mpi_msg_hdr);
+ *pBC = (u8)((msgHeader_tmp >> 24) &
+ 0x1f);
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk(": CI=%d PI=%d "
+ "msgHeader=%x\n",
+ circularQ->consumer_idx,
+ circularQ->producer_index,
+ msgHeader_tmp));
+ return MPI_IO_STATUS_SUCCESS;
+ } else {
+ circularQ->consumer_idx =
+ (circularQ->consumer_idx +
+ ((msgHeader_tmp >> 24) & 0x1f))
+ % 256;
+ msgHeader_tmp = 0;
+ pm8001_write_32(msgHeader, 0, 0);
+ /* update the CI of outbound queue */
+ pm8001_cw32(pm8001_ha,
+ circularQ->ci_pci_bar,
+ circularQ->ci_offset,
+ circularQ->consumer_idx);
+ }
+ } else {
+ circularQ->consumer_idx =
+ (circularQ->consumer_idx +
+ ((msgHeader_tmp >> 24) & 0x1f)) % 256;
+ msgHeader_tmp = 0;
+ pm8001_write_32(msgHeader, 0, 0);
+ /* update the CI of outbound queue */
+ pm8001_cw32(pm8001_ha, circularQ->ci_pci_bar,
+ circularQ->ci_offset,
+ circularQ->consumer_idx);
+ return MPI_IO_STATUS_FAIL;
+ }
+ } else {
+ u32 producer_index;
+ void *pi_virt = circularQ->pi_virt;
+ /* Update the producer index from SPC */
+ producer_index = pm8001_read_32(pi_virt);
+ circularQ->producer_index = cpu_to_le32(producer_index);
+ }
+ } while (circularQ->producer_index != circularQ->consumer_idx);
+ /* while we don't have any more not-yet-delivered message */
+ /* report empty */
+ return MPI_IO_STATUS_BUSY;
+}
+
+static void pm8001_work_queue(struct work_struct *work)
+{
+ struct delayed_work *dw = container_of(work, struct delayed_work, work);
+ struct pm8001_wq *wq = container_of(dw, struct pm8001_wq, work_q);
+ struct pm8001_device *pm8001_dev;
+ struct domain_device *dev;
+
+ switch (wq->handler) {
+ case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS:
+ pm8001_dev = wq->data;
+ dev = pm8001_dev->sas_device;
+ pm8001_I_T_nexus_reset(dev);
+ break;
+ case IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY:
+ pm8001_dev = wq->data;
+ dev = pm8001_dev->sas_device;
+ pm8001_I_T_nexus_reset(dev);
+ break;
+ case IO_DS_IN_ERROR:
+ pm8001_dev = wq->data;
+ dev = pm8001_dev->sas_device;
+ pm8001_I_T_nexus_reset(dev);
+ break;
+ case IO_DS_NON_OPERATIONAL:
+ pm8001_dev = wq->data;
+ dev = pm8001_dev->sas_device;
+ pm8001_I_T_nexus_reset(dev);
+ break;
+ }
+ list_del(&wq->entry);
+ kfree(wq);
+}
+
+static int pm8001_handle_event(struct pm8001_hba_info *pm8001_ha, void *data,
+ int handler)
+{
+ struct pm8001_wq *wq;
+ int ret = 0;
+
+ wq = kmalloc(sizeof(struct pm8001_wq), GFP_ATOMIC);
+ if (wq) {
+ wq->pm8001_ha = pm8001_ha;
+ wq->data = data;
+ wq->handler = handler;
+ INIT_DELAYED_WORK(&wq->work_q, pm8001_work_queue);
+ list_add_tail(&wq->entry, &pm8001_ha->wq_list);
+ schedule_delayed_work(&wq->work_q, 0);
+ } else
+ ret = -ENOMEM;
+
+ return ret;
+}
+
+/**
+ * mpi_ssp_completion- process the event that FW response to the SSP request.
+ * @pm8001_ha: our hba card information
+ * @piomb: the message contents of this outbound message.
+ *
+ * When FW has completed a ssp request for example a IO request, after it has
+ * filled the SG data with the data, it will trigger this event represent
+ * that he has finished the job,please check the coresponding buffer.
+ * So we will tell the caller who maybe waiting the result to tell upper layer
+ * that the task has been finished.
+ */
+static void
+mpi_ssp_completion(struct pm8001_hba_info *pm8001_ha , void *piomb)
+{
+ struct sas_task *t;
+ struct pm8001_ccb_info *ccb;
+ unsigned long flags;
+ u32 status;
+ u32 param;
+ u32 tag;
+ struct ssp_completion_resp *psspPayload;
+ struct task_status_struct *ts;
+ struct ssp_response_iu *iu;
+ struct pm8001_device *pm8001_dev;
+ psspPayload = (struct ssp_completion_resp *)(piomb + 4);
+ status = le32_to_cpu(psspPayload->status);
+ tag = le32_to_cpu(psspPayload->tag);
+ ccb = &pm8001_ha->ccb_info[tag];
+ pm8001_dev = ccb->device;
+ param = le32_to_cpu(psspPayload->param);
+
+ t = ccb->task;
+
+ if (status && status != IO_UNDERFLOW)
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("sas IO status 0x%x\n", status));
+ if (unlikely(!t || !t->lldd_task || !t->dev))
+ return;
+ ts = &t->task_status;
+ switch (status) {
+ case IO_SUCCESS:
+ PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_SUCCESS"
+ ",param = %d \n", param));
+ if (param == 0) {
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAM_GOOD;
+ } else {
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_PROTO_RESPONSE;
+ ts->residual = param;
+ iu = &psspPayload->ssp_resp_iu;
+ sas_ssp_task_response(pm8001_ha->dev, t, iu);
+ }
+ if (pm8001_dev)
+ pm8001_dev->running_req--;
+ break;
+ case IO_ABORTED:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_ABORTED IOMB Tag \n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_ABORTED_TASK;
+ break;
+ case IO_UNDERFLOW:
+ /* SSP Completion with error */
+ PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_UNDERFLOW"
+ ",param = %d \n", param));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_DATA_UNDERRUN;
+ ts->residual = param;
+ if (pm8001_dev)
+ pm8001_dev->running_req--;
+ break;
+ case IO_NO_DEVICE:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_NO_DEVICE\n"));
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_PHY_DOWN;
+ break;
+ case IO_XFER_ERROR_BREAK:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_ERROR_BREAK\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ break;
+ case IO_XFER_ERROR_PHY_NOT_READY:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_ERROR_PHY_NOT_READY\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
+ break;
+ case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_EPROTO;
+ break;
+ case IO_OPEN_CNX_ERROR_ZONE_VIOLATION:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_UNKNOWN;
+ break;
+ case IO_OPEN_CNX_ERROR_BREAK:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_BREAK\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
+ break;
+ case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_UNKNOWN;
+ if (!t->uldd_task)
+ pm8001_handle_event(pm8001_ha,
+ pm8001_dev,
+ IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
+ break;
+ case IO_OPEN_CNX_ERROR_BAD_DESTINATION:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_BAD_DESTINATION\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_BAD_DEST;
+ break;
+ case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_CONNECTION_RATE_"
+ "NOT_SUPPORTED\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_CONN_RATE;
+ break;
+ case IO_OPEN_CNX_ERROR_WRONG_DESTINATION:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n"));
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_WRONG_DEST;
+ break;
+ case IO_XFER_ERROR_NAK_RECEIVED:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_ERROR_NAK_RECEIVED\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
+ break;
+ case IO_XFER_ERROR_ACK_NAK_TIMEOUT:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_ERROR_ACK_NAK_TIMEOUT\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_NAK_R_ERR;
+ break;
+ case IO_XFER_ERROR_DMA:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_ERROR_DMA\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ break;
+ case IO_XFER_OPEN_RETRY_TIMEOUT:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_OPEN_RETRY_TIMEOUT\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
+ break;
+ case IO_XFER_ERROR_OFFSET_MISMATCH:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_ERROR_OFFSET_MISMATCH\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ break;
+ case IO_PORT_IN_RESET:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_PORT_IN_RESET\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ break;
+ case IO_DS_NON_OPERATIONAL:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_DS_NON_OPERATIONAL\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ if (!t->uldd_task)
+ pm8001_handle_event(pm8001_ha,
+ pm8001_dev,
+ IO_DS_NON_OPERATIONAL);
+ break;
+ case IO_DS_IN_RECOVERY:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_DS_IN_RECOVERY\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ break;
+ case IO_TM_TAG_NOT_FOUND:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_TM_TAG_NOT_FOUND\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ break;
+ case IO_SSP_EXT_IU_ZERO_LEN_ERROR:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_SSP_EXT_IU_ZERO_LEN_ERROR\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ break;
+ case IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
+ default:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("Unknown status 0x%x\n", status));
+ /* not allowed case. Therefore, return failed status */
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ break;
+ }
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("scsi_status = %x \n ",
+ psspPayload->ssp_resp_iu.status));
+ spin_lock_irqsave(&t->task_state_lock, flags);
+ t->task_state_flags &= ~SAS_TASK_STATE_PENDING;
+ t->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
+ t->task_state_flags |= SAS_TASK_STATE_DONE;
+ if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) {
+ spin_unlock_irqrestore(&t->task_state_lock, flags);
+ PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("task 0x%p done with"
+ " io_status 0x%x resp 0x%x "
+ "stat 0x%x but aborted by upper layer!\n",
+ t, status, ts->resp, ts->stat));
+ pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
+ } else {
+ spin_unlock_irqrestore(&t->task_state_lock, flags);
+ pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
+ mb();/* in order to force CPU ordering */
+ t->task_done(t);
+ }
+}
+
+/*See the comments for mpi_ssp_completion */
+static void mpi_ssp_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
+{
+ struct sas_task *t;
+ unsigned long flags;
+ struct task_status_struct *ts;
+ struct pm8001_ccb_info *ccb;
+ struct pm8001_device *pm8001_dev;
+ struct ssp_event_resp *psspPayload =
+ (struct ssp_event_resp *)(piomb + 4);
+ u32 event = le32_to_cpu(psspPayload->event);
+ u32 tag = le32_to_cpu(psspPayload->tag);
+ u32 port_id = le32_to_cpu(psspPayload->port_id);
+ u32 dev_id = le32_to_cpu(psspPayload->device_id);
+
+ ccb = &pm8001_ha->ccb_info[tag];
+ t = ccb->task;
+ pm8001_dev = ccb->device;
+ if (event)
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("sas IO status 0x%x\n", event));
+ if (unlikely(!t || !t->lldd_task || !t->dev))
+ return;
+ ts = &t->task_status;
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("port_id = %x,device_id = %x\n",
+ port_id, dev_id));
+ switch (event) {
+ case IO_OVERFLOW:
+ PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_UNDERFLOW\n");)
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_DATA_OVERRUN;
+ ts->residual = 0;
+ if (pm8001_dev)
+ pm8001_dev->running_req--;
+ break;
+ case IO_XFER_ERROR_BREAK:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_ERROR_BREAK\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_INTERRUPTED;
+ break;
+ case IO_XFER_ERROR_PHY_NOT_READY:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_ERROR_PHY_NOT_READY\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
+ break;
+ case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_PROTOCOL_NOT"
+ "_SUPPORTED\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_EPROTO;
+ break;
+ case IO_OPEN_CNX_ERROR_ZONE_VIOLATION:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_UNKNOWN;
+ break;
+ case IO_OPEN_CNX_ERROR_BREAK:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_BREAK\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
+ break;
+ case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_UNKNOWN;
+ if (!t->uldd_task)
+ pm8001_handle_event(pm8001_ha,
+ pm8001_dev,
+ IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
+ break;
+ case IO_OPEN_CNX_ERROR_BAD_DESTINATION:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_BAD_DESTINATION\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_BAD_DEST;
+ break;
+ case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_CONNECTION_RATE_"
+ "NOT_SUPPORTED\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_CONN_RATE;
+ break;
+ case IO_OPEN_CNX_ERROR_WRONG_DESTINATION:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_WRONG_DEST;
+ break;
+ case IO_XFER_ERROR_NAK_RECEIVED:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_ERROR_NAK_RECEIVED\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
+ break;
+ case IO_XFER_ERROR_ACK_NAK_TIMEOUT:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_ERROR_ACK_NAK_TIMEOUT\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_NAK_R_ERR;
+ break;
+ case IO_XFER_OPEN_RETRY_TIMEOUT:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_OPEN_RETRY_TIMEOUT\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
+ break;
+ case IO_XFER_ERROR_UNEXPECTED_PHASE:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_ERROR_UNEXPECTED_PHASE\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_DATA_OVERRUN;
+ break;
+ case IO_XFER_ERROR_XFER_RDY_OVERRUN:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_ERROR_XFER_RDY_OVERRUN\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_DATA_OVERRUN;
+ break;
+ case IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_DATA_OVERRUN;
+ break;
+ case IO_XFER_ERROR_CMD_ISSUE_ACK_NAK_TIMEOUT:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_ERROR_CMD_ISSUE_ACK_NAK_TIMEOUT\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_DATA_OVERRUN;
+ break;
+ case IO_XFER_ERROR_OFFSET_MISMATCH:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_ERROR_OFFSET_MISMATCH\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_DATA_OVERRUN;
+ break;
+ case IO_XFER_ERROR_XFER_ZERO_DATA_LEN:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_ERROR_XFER_ZERO_DATA_LEN\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_DATA_OVERRUN;
+ break;
+ case IO_XFER_CMD_FRAME_ISSUED:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk(" IO_XFER_CMD_FRAME_ISSUED\n"));
+ return;
+ default:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("Unknown status 0x%x\n", event));
+ /* not allowed case. Therefore, return failed status */
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_DATA_OVERRUN;
+ break;
+ }
+ spin_lock_irqsave(&t->task_state_lock, flags);
+ t->task_state_flags &= ~SAS_TASK_STATE_PENDING;
+ t->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
+ t->task_state_flags |= SAS_TASK_STATE_DONE;
+ if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) {
+ spin_unlock_irqrestore(&t->task_state_lock, flags);
+ PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("task 0x%p done with"
+ " event 0x%x resp 0x%x "
+ "stat 0x%x but aborted by upper layer!\n",
+ t, event, ts->resp, ts->stat));
+ pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
+ } else {
+ spin_unlock_irqrestore(&t->task_state_lock, flags);
+ pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
+ mb();/* in order to force CPU ordering */
+ t->task_done(t);
+ }
+}
+
+/*See the comments for mpi_ssp_completion */
+static void
+mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
+{
+ struct sas_task *t;
+ struct pm8001_ccb_info *ccb;
+ unsigned long flags;
+ u32 param;
+ u32 status;
+ u32 tag;
+ struct sata_completion_resp *psataPayload;
+ struct task_status_struct *ts;
+ struct ata_task_resp *resp ;
+ u32 *sata_resp;
+ struct pm8001_device *pm8001_dev;
+
+ psataPayload = (struct sata_completion_resp *)(piomb + 4);
+ status = le32_to_cpu(psataPayload->status);
+ tag = le32_to_cpu(psataPayload->tag);
+
+ ccb = &pm8001_ha->ccb_info[tag];
+ param = le32_to_cpu(psataPayload->param);
+ t = ccb->task;
+ ts = &t->task_status;
+ pm8001_dev = ccb->device;
+ if (status)
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("sata IO status 0x%x\n", status));
+ if (unlikely(!t || !t->lldd_task || !t->dev))
+ return;
+
+ switch (status) {
+ case IO_SUCCESS:
+ PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_SUCCESS\n"));
+ if (param == 0) {
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAM_GOOD;
+ } else {
+ u8 len;
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_PROTO_RESPONSE;
+ ts->residual = param;
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("SAS_PROTO_RESPONSE len = %d\n",
+ param));
+ sata_resp = &psataPayload->sata_resp[0];
+ resp = (struct ata_task_resp *)ts->buf;
+ if (t->ata_task.dma_xfer == 0 &&
+ t->data_dir == PCI_DMA_FROMDEVICE) {
+ len = sizeof(struct pio_setup_fis);
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("PIO read len = %d\n", len));
+ } else if (t->ata_task.use_ncq) {
+ len = sizeof(struct set_dev_bits_fis);
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("FPDMA len = %d\n", len));
+ } else {
+ len = sizeof(struct dev_to_host_fis);
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("other len = %d\n", len));
+ }
+ if (SAS_STATUS_BUF_SIZE >= sizeof(*resp)) {
+ resp->frame_len = len;
+ memcpy(&resp->ending_fis[0], sata_resp, len);
+ ts->buf_valid_size = sizeof(*resp);
+ } else
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("response to large \n"));
+ }
+ if (pm8001_dev)
+ pm8001_dev->running_req--;
+ break;
+ case IO_ABORTED:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_ABORTED IOMB Tag \n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_ABORTED_TASK;
+ if (pm8001_dev)
+ pm8001_dev->running_req--;
+ break;
+ /* following cases are to do cases */
+ case IO_UNDERFLOW:
+ /* SATA Completion with error */
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_UNDERFLOW param = %d\n", param));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_DATA_UNDERRUN;
+ ts->residual = param;
+ if (pm8001_dev)
+ pm8001_dev->running_req--;
+ break;
+ case IO_NO_DEVICE:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_NO_DEVICE\n"));
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_PHY_DOWN;
+ break;
+ case IO_XFER_ERROR_BREAK:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_ERROR_BREAK\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_INTERRUPTED;
+ break;
+ case IO_XFER_ERROR_PHY_NOT_READY:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_ERROR_PHY_NOT_READY\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
+ break;
+ case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_PROTOCOL_NOT"
+ "_SUPPORTED\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_EPROTO;
+ break;
+ case IO_OPEN_CNX_ERROR_ZONE_VIOLATION:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_UNKNOWN;
+ break;
+ case IO_OPEN_CNX_ERROR_BREAK:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_BREAK\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_RSVD_CONT0;
+ break;
+ case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_DEV_NO_RESPONSE;
+ if (!t->uldd_task) {
+ pm8001_handle_event(pm8001_ha,
+ pm8001_dev,
+ IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_QUEUE_FULL;
+ pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
+ mb();/*in order to force CPU ordering*/
+ t->task_done(t);
+ return;
+ }
+ break;
+ case IO_OPEN_CNX_ERROR_BAD_DESTINATION:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_BAD_DESTINATION\n"));
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_BAD_DEST;
+ if (!t->uldd_task) {
+ pm8001_handle_event(pm8001_ha,
+ pm8001_dev,
+ IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_QUEUE_FULL;
+ pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
+ mb();/*ditto*/
+ t->task_done(t);
+ return;
+ }
+ break;
+ case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_CONNECTION_RATE_"
+ "NOT_SUPPORTED\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_CONN_RATE;
+ break;
+ case IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_STP_RESOURCES"
+ "_BUSY\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_DEV_NO_RESPONSE;
+ if (!t->uldd_task) {
+ pm8001_handle_event(pm8001_ha,
+ pm8001_dev,
+ IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY);
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_QUEUE_FULL;
+ pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
+ mb();/* ditto*/
+ t->task_done(t);
+ return;
+ }
+ break;
+ case IO_OPEN_CNX_ERROR_WRONG_DESTINATION:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_WRONG_DEST;
+ break;
+ case IO_XFER_ERROR_NAK_RECEIVED:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_ERROR_NAK_RECEIVED\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_NAK_R_ERR;
+ break;
+ case IO_XFER_ERROR_ACK_NAK_TIMEOUT:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_ERROR_ACK_NAK_TIMEOUT\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_NAK_R_ERR;
+ break;
+ case IO_XFER_ERROR_DMA:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_ERROR_DMA\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_ABORTED_TASK;
+ break;
+ case IO_XFER_ERROR_SATA_LINK_TIMEOUT:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_ERROR_SATA_LINK_TIMEOUT\n"));
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_DEV_NO_RESPONSE;
+ break;
+ case IO_XFER_ERROR_REJECTED_NCQ_MODE:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_ERROR_REJECTED_NCQ_MODE\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_DATA_UNDERRUN;
+ break;
+ case IO_XFER_OPEN_RETRY_TIMEOUT:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_OPEN_RETRY_TIMEOUT\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_TO;
+ break;
+ case IO_PORT_IN_RESET:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_PORT_IN_RESET\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_DEV_NO_RESPONSE;
+ break;
+ case IO_DS_NON_OPERATIONAL:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_DS_NON_OPERATIONAL\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_DEV_NO_RESPONSE;
+ if (!t->uldd_task) {
+ pm8001_handle_event(pm8001_ha, pm8001_dev,
+ IO_DS_NON_OPERATIONAL);
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_QUEUE_FULL;
+ pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
+ mb();/*ditto*/
+ t->task_done(t);
+ return;
+ }
+ break;
+ case IO_DS_IN_RECOVERY:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk(" IO_DS_IN_RECOVERY\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_DEV_NO_RESPONSE;
+ break;
+ case IO_DS_IN_ERROR:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_DS_IN_ERROR\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_DEV_NO_RESPONSE;
+ if (!t->uldd_task) {
+ pm8001_handle_event(pm8001_ha, pm8001_dev,
+ IO_DS_IN_ERROR);
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_QUEUE_FULL;
+ pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
+ mb();/*ditto*/
+ t->task_done(t);
+ return;
+ }
+ break;
+ case IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
+ default:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("Unknown status 0x%x\n", status));
+ /* not allowed case. Therefore, return failed status */
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_DEV_NO_RESPONSE;
+ break;
+ }
+ spin_lock_irqsave(&t->task_state_lock, flags);
+ t->task_state_flags &= ~SAS_TASK_STATE_PENDING;
+ t->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
+ t->task_state_flags |= SAS_TASK_STATE_DONE;
+ if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) {
+ spin_unlock_irqrestore(&t->task_state_lock, flags);
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("task 0x%p done with io_status 0x%x"
+ " resp 0x%x stat 0x%x but aborted by upper layer!\n",
+ t, status, ts->resp, ts->stat));
+ pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
+ } else {
+ spin_unlock_irqrestore(&t->task_state_lock, flags);
+ pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
+ mb();/* ditto */
+ t->task_done(t);
+ }
+}
+
+/*See the comments for mpi_ssp_completion */
+static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
+{
+ struct sas_task *t;
+ unsigned long flags;
+ struct task_status_struct *ts;
+ struct pm8001_ccb_info *ccb;
+ struct pm8001_device *pm8001_dev;
+ struct sata_event_resp *psataPayload =
+ (struct sata_event_resp *)(piomb + 4);
+ u32 event = le32_to_cpu(psataPayload->event);
+ u32 tag = le32_to_cpu(psataPayload->tag);
+ u32 port_id = le32_to_cpu(psataPayload->port_id);
+ u32 dev_id = le32_to_cpu(psataPayload->device_id);
+
+ ccb = &pm8001_ha->ccb_info[tag];
+ t = ccb->task;
+ pm8001_dev = ccb->device;
+ if (event)
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("sata IO status 0x%x\n", event));
+ if (unlikely(!t || !t->lldd_task || !t->dev))
+ return;
+ ts = &t->task_status;
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("port_id = %x,device_id = %x\n",
+ port_id, dev_id));
+ switch (event) {
+ case IO_OVERFLOW:
+ PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_UNDERFLOW\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_DATA_OVERRUN;
+ ts->residual = 0;
+ if (pm8001_dev)
+ pm8001_dev->running_req--;
+ break;
+ case IO_XFER_ERROR_BREAK:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_ERROR_BREAK\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_INTERRUPTED;
+ break;
+ case IO_XFER_ERROR_PHY_NOT_READY:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_ERROR_PHY_NOT_READY\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
+ break;
+ case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_PROTOCOL_NOT"
+ "_SUPPORTED\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_EPROTO;
+ break;
+ case IO_OPEN_CNX_ERROR_ZONE_VIOLATION:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_UNKNOWN;
+ break;
+ case IO_OPEN_CNX_ERROR_BREAK:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_BREAK\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_RSVD_CONT0;
+ break;
+ case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n"));
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_DEV_NO_RESPONSE;
+ if (!t->uldd_task) {
+ pm8001_handle_event(pm8001_ha,
+ pm8001_dev,
+ IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_QUEUE_FULL;
+ pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
+ mb();/*ditto*/
+ t->task_done(t);
+ return;
+ }
+ break;
+ case IO_OPEN_CNX_ERROR_BAD_DESTINATION:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_BAD_DESTINATION\n"));
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_BAD_DEST;
+ break;
+ case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_CONNECTION_RATE_"
+ "NOT_SUPPORTED\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_CONN_RATE;
+ break;
+ case IO_OPEN_CNX_ERROR_WRONG_DESTINATION:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_WRONG_DEST;
+ break;
+ case IO_XFER_ERROR_NAK_RECEIVED:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_ERROR_NAK_RECEIVED\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_NAK_R_ERR;
+ break;
+ case IO_XFER_ERROR_PEER_ABORTED:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_ERROR_PEER_ABORTED\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_NAK_R_ERR;
+ break;
+ case IO_XFER_ERROR_REJECTED_NCQ_MODE:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_ERROR_REJECTED_NCQ_MODE\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_DATA_UNDERRUN;
+ break;
+ case IO_XFER_OPEN_RETRY_TIMEOUT:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_OPEN_RETRY_TIMEOUT\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_TO;
+ break;
+ case IO_XFER_ERROR_UNEXPECTED_PHASE:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_ERROR_UNEXPECTED_PHASE\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_TO;
+ break;
+ case IO_XFER_ERROR_XFER_RDY_OVERRUN:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_ERROR_XFER_RDY_OVERRUN\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_TO;
+ break;
+ case IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_TO;
+ break;
+ case IO_XFER_ERROR_OFFSET_MISMATCH:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_ERROR_OFFSET_MISMATCH\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_TO;
+ break;
+ case IO_XFER_ERROR_XFER_ZERO_DATA_LEN:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_ERROR_XFER_ZERO_DATA_LEN\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_TO;
+ break;
+ case IO_XFER_CMD_FRAME_ISSUED:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_CMD_FRAME_ISSUED\n"));
+ break;
+ case IO_XFER_PIO_SETUP_ERROR:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_PIO_SETUP_ERROR\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_TO;
+ break;
+ default:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("Unknown status 0x%x\n", event));
+ /* not allowed case. Therefore, return failed status */
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_TO;
+ break;
+ }
+ spin_lock_irqsave(&t->task_state_lock, flags);
+ t->task_state_flags &= ~SAS_TASK_STATE_PENDING;
+ t->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
+ t->task_state_flags |= SAS_TASK_STATE_DONE;
+ if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) {
+ spin_unlock_irqrestore(&t->task_state_lock, flags);
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("task 0x%p done with io_status 0x%x"
+ " resp 0x%x stat 0x%x but aborted by upper layer!\n",
+ t, event, ts->resp, ts->stat));
+ pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
+ } else {
+ spin_unlock_irqrestore(&t->task_state_lock, flags);
+ pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
+ mb();/* in order to force CPU ordering */
+ t->task_done(t);
+ }
+}
+
+/*See the comments for mpi_ssp_completion */
+static void
+mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
+{
+ u32 param;
+ struct sas_task *t;
+ struct pm8001_ccb_info *ccb;
+ unsigned long flags;
+ u32 status;
+ u32 tag;
+ struct smp_completion_resp *psmpPayload;
+ struct task_status_struct *ts;
+ struct pm8001_device *pm8001_dev;
+
+ psmpPayload = (struct smp_completion_resp *)(piomb + 4);
+ status = le32_to_cpu(psmpPayload->status);
+ tag = le32_to_cpu(psmpPayload->tag);
+
+ ccb = &pm8001_ha->ccb_info[tag];
+ param = le32_to_cpu(psmpPayload->param);
+ t = ccb->task;
+ ts = &t->task_status;
+ pm8001_dev = ccb->device;
+ if (status)
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("smp IO status 0x%x\n", status));
+ if (unlikely(!t || !t->lldd_task || !t->dev))
+ return;
+
+ switch (status) {
+ case IO_SUCCESS:
+ PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_SUCCESS\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAM_GOOD;
+ if (pm8001_dev)
+ pm8001_dev->running_req--;
+ break;
+ case IO_ABORTED:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_ABORTED IOMB\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_ABORTED_TASK;
+ if (pm8001_dev)
+ pm8001_dev->running_req--;
+ break;
+ case IO_OVERFLOW:
+ PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_UNDERFLOW\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_DATA_OVERRUN;
+ ts->residual = 0;
+ if (pm8001_dev)
+ pm8001_dev->running_req--;
+ break;
+ case IO_NO_DEVICE:
+ PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_NO_DEVICE\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_PHY_DOWN;
+ break;
+ case IO_ERROR_HW_TIMEOUT:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_ERROR_HW_TIMEOUT\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAM_BUSY;
+ break;
+ case IO_XFER_ERROR_BREAK:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_ERROR_BREAK\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAM_BUSY;
+ break;
+ case IO_XFER_ERROR_PHY_NOT_READY:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_ERROR_PHY_NOT_READY\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAM_BUSY;
+ break;
+ case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_UNKNOWN;
+ break;
+ case IO_OPEN_CNX_ERROR_ZONE_VIOLATION:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_UNKNOWN;
+ break;
+ case IO_OPEN_CNX_ERROR_BREAK:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_BREAK\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_RSVD_CONT0;
+ break;
+ case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_UNKNOWN;
+ pm8001_handle_event(pm8001_ha,
+ pm8001_dev,
+ IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
+ break;
+ case IO_OPEN_CNX_ERROR_BAD_DESTINATION:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_BAD_DESTINATION\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_BAD_DEST;
+ break;
+ case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_CONNECTION_RATE_"
+ "NOT_SUPPORTED\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_CONN_RATE;
+ break;
+ case IO_OPEN_CNX_ERROR_WRONG_DESTINATION:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_WRONG_DEST;
+ break;
+ case IO_XFER_ERROR_RX_FRAME:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_ERROR_RX_FRAME\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_DEV_NO_RESPONSE;
+ break;
+ case IO_XFER_OPEN_RETRY_TIMEOUT:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFER_OPEN_RETRY_TIMEOUT\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
+ break;
+ case IO_ERROR_INTERNAL_SMP_RESOURCE:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_ERROR_INTERNAL_SMP_RESOURCE\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_QUEUE_FULL;
+ break;
+ case IO_PORT_IN_RESET:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_PORT_IN_RESET\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
+ break;
+ case IO_DS_NON_OPERATIONAL:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_DS_NON_OPERATIONAL\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_DEV_NO_RESPONSE;
+ break;
+ case IO_DS_IN_RECOVERY:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_DS_IN_RECOVERY\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
+ break;
+ case IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
+ break;
+ default:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("Unknown status 0x%x\n", status));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_DEV_NO_RESPONSE;
+ /* not allowed case. Therefore, return failed status */
+ break;
+ }
+ spin_lock_irqsave(&t->task_state_lock, flags);
+ t->task_state_flags &= ~SAS_TASK_STATE_PENDING;
+ t->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
+ t->task_state_flags |= SAS_TASK_STATE_DONE;
+ if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) {
+ spin_unlock_irqrestore(&t->task_state_lock, flags);
+ PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("task 0x%p done with"
+ " io_status 0x%x resp 0x%x "
+ "stat 0x%x but aborted by upper layer!\n",
+ t, status, ts->resp, ts->stat));
+ pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
+ } else {
+ spin_unlock_irqrestore(&t->task_state_lock, flags);
+ pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
+ mb();/* in order to force CPU ordering */
+ t->task_done(t);
+ }
+}
+
+static void
+mpi_set_dev_state_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
+{
+ struct set_dev_state_resp *pPayload =
+ (struct set_dev_state_resp *)(piomb + 4);
+ u32 tag = le32_to_cpu(pPayload->tag);
+ struct pm8001_ccb_info *ccb = &pm8001_ha->ccb_info[tag];
+ struct pm8001_device *pm8001_dev = ccb->device;
+ u32 status = le32_to_cpu(pPayload->status);
+ u32 device_id = le32_to_cpu(pPayload->device_id);
+ u8 pds = le32_to_cpu(pPayload->pds_nds) | PDS_BITS;
+ u8 nds = le32_to_cpu(pPayload->pds_nds) | NDS_BITS;
+ PM8001_MSG_DBG(pm8001_ha, pm8001_printk("Set device id = 0x%x state "
+ "from 0x%x to 0x%x status = 0x%x!\n",
+ device_id, pds, nds, status));
+ complete(pm8001_dev->setds_completion);
+ ccb->task = NULL;
+ ccb->ccb_tag = 0xFFFFFFFF;
+ pm8001_ccb_free(pm8001_ha, tag);
+}
+
+static void
+mpi_set_nvmd_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
+{
+ struct get_nvm_data_resp *pPayload =
+ (struct get_nvm_data_resp *)(piomb + 4);
+ u32 tag = le32_to_cpu(pPayload->tag);
+ struct pm8001_ccb_info *ccb = &pm8001_ha->ccb_info[tag];
+ u32 dlen_status = le32_to_cpu(pPayload->dlen_status);
+ complete(pm8001_ha->nvmd_completion);
+ PM8001_MSG_DBG(pm8001_ha, pm8001_printk("Set nvm data complete!\n"));
+ if ((dlen_status & NVMD_STAT) != 0) {
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("Set nvm data error!\n"));
+ return;
+ }
+ ccb->task = NULL;
+ ccb->ccb_tag = 0xFFFFFFFF;
+ pm8001_ccb_free(pm8001_ha, tag);
+}
+
+static void
+mpi_get_nvmd_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
+{
+ struct fw_control_ex *fw_control_context;
+ struct get_nvm_data_resp *pPayload =
+ (struct get_nvm_data_resp *)(piomb + 4);
+ u32 tag = le32_to_cpu(pPayload->tag);
+ struct pm8001_ccb_info *ccb = &pm8001_ha->ccb_info[tag];
+ u32 dlen_status = le32_to_cpu(pPayload->dlen_status);
+ u32 ir_tds_bn_dps_das_nvm =
+ le32_to_cpu(pPayload->ir_tda_bn_dps_das_nvm);
+ void *virt_addr = pm8001_ha->memoryMap.region[NVMD].virt_ptr;
+ fw_control_context = ccb->fw_control_context;
+
+ PM8001_MSG_DBG(pm8001_ha, pm8001_printk("Get nvm data complete!\n"));
+ if ((dlen_status & NVMD_STAT) != 0) {
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("Get nvm data error!\n"));
+ complete(pm8001_ha->nvmd_completion);
+ return;
+ }
+
+ if (ir_tds_bn_dps_das_nvm & IPMode) {
+ /* indirect mode - IR bit set */
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("Get NVMD success, IR=1\n"));
+ if ((ir_tds_bn_dps_das_nvm & NVMD_TYPE) == TWI_DEVICE) {
+ if (ir_tds_bn_dps_das_nvm == 0x80a80200) {
+ memcpy(pm8001_ha->sas_addr,
+ ((u8 *)virt_addr + 4),
+ SAS_ADDR_SIZE);
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("Get SAS address"
+ " from VPD successfully!\n"));
+ }
+ } else if (((ir_tds_bn_dps_das_nvm & NVMD_TYPE) == C_SEEPROM)
+ || ((ir_tds_bn_dps_das_nvm & NVMD_TYPE) == VPD_FLASH) ||
+ ((ir_tds_bn_dps_das_nvm & NVMD_TYPE) == EXPAN_ROM)) {
+ ;
+ } else if (((ir_tds_bn_dps_das_nvm & NVMD_TYPE) == AAP1_RDUMP)
+ || ((ir_tds_bn_dps_das_nvm & NVMD_TYPE) == IOP_RDUMP)) {
+ ;
+ } else {
+ /* Should not be happened*/
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("(IR=1)Wrong Device type 0x%x\n",
+ ir_tds_bn_dps_das_nvm));
+ }
+ } else /* direct mode */{
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("Get NVMD success, IR=0, dataLen=%d\n",
+ (dlen_status & NVMD_LEN) >> 24));
+ }
+ memcpy(fw_control_context->usrAddr,
+ pm8001_ha->memoryMap.region[NVMD].virt_ptr,
+ fw_control_context->len);
+ complete(pm8001_ha->nvmd_completion);
+ ccb->task = NULL;
+ ccb->ccb_tag = 0xFFFFFFFF;
+ pm8001_ccb_free(pm8001_ha, tag);
+}
+
+static int mpi_local_phy_ctl(struct pm8001_hba_info *pm8001_ha, void *piomb)
+{
+ struct local_phy_ctl_resp *pPayload =
+ (struct local_phy_ctl_resp *)(piomb + 4);
+ u32 status = le32_to_cpu(pPayload->status);
+ u32 phy_id = le32_to_cpu(pPayload->phyop_phyid) & ID_BITS;
+ u32 phy_op = le32_to_cpu(pPayload->phyop_phyid) & OP_BITS;
+ if (status != 0) {
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("%x phy execute %x phy op failed! \n",
+ phy_id, phy_op));
+ } else
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("%x phy execute %x phy op success! \n",
+ phy_id, phy_op));
+ return 0;
+}
+
+/**
+ * pm8001_bytes_dmaed - one of the interface function communication with libsas
+ * @pm8001_ha: our hba card information
+ * @i: which phy that received the event.
+ *
+ * when HBA driver received the identify done event or initiate FIS received
+ * event(for SATA), it will invoke this function to notify the sas layer that
+ * the sas toplogy has formed, please discover the the whole sas domain,
+ * while receive a broadcast(change) primitive just tell the sas
+ * layer to discover the changed domain rather than the whole domain.
+ */
+static void pm8001_bytes_dmaed(struct pm8001_hba_info *pm8001_ha, int i)
+{
+ struct pm8001_phy *phy = &pm8001_ha->phy[i];
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+ struct sas_ha_struct *sas_ha;
+ if (!phy->phy_attached)
+ return;
+
+ sas_ha = pm8001_ha->sas;
+ if (sas_phy->phy) {
+ struct sas_phy *sphy = sas_phy->phy;
+ sphy->negotiated_linkrate = sas_phy->linkrate;
+ sphy->minimum_linkrate = phy->minimum_linkrate;
+ sphy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
+ sphy->maximum_linkrate = phy->maximum_linkrate;
+ sphy->maximum_linkrate_hw = phy->maximum_linkrate;
+ }
+
+ if (phy->phy_type & PORT_TYPE_SAS) {
+ struct sas_identify_frame *id;
+ id = (struct sas_identify_frame *)phy->frame_rcvd;
+ id->dev_type = phy->identify.device_type;
+ id->initiator_bits = SAS_PROTOCOL_ALL;
+ id->target_bits = phy->identify.target_port_protocols;
+ } else if (phy->phy_type & PORT_TYPE_SATA) {
+ /*Nothing*/
+ }
+ PM8001_MSG_DBG(pm8001_ha, pm8001_printk("phy %d byte dmaded.\n", i));
+
+ sas_phy->frame_rcvd_size = phy->frame_rcvd_size;
+ pm8001_ha->sas->notify_port_event(sas_phy, PORTE_BYTES_DMAED);
+}
+
+/* Get the link rate speed */
+static void get_lrate_mode(struct pm8001_phy *phy, u8 link_rate)
+{
+ struct sas_phy *sas_phy = phy->sas_phy.phy;
+
+ switch (link_rate) {
+ case PHY_SPEED_60:
+ phy->sas_phy.linkrate = SAS_LINK_RATE_6_0_GBPS;
+ phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_6_0_GBPS;
+ break;
+ case PHY_SPEED_30:
+ phy->sas_phy.linkrate = SAS_LINK_RATE_3_0_GBPS;
+ phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
+ break;
+ case PHY_SPEED_15:
+ phy->sas_phy.linkrate = SAS_LINK_RATE_1_5_GBPS;
+ phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
+ break;
+ }
+ sas_phy->negotiated_linkrate = phy->sas_phy.linkrate;
+ sas_phy->maximum_linkrate_hw = SAS_LINK_RATE_6_0_GBPS;
+ sas_phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
+ sas_phy->maximum_linkrate = SAS_LINK_RATE_6_0_GBPS;
+ sas_phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
+}
+
+/**
+ * asd_get_attached_sas_addr -- extract/generate attached SAS address
+ * @phy: pointer to asd_phy
+ * @sas_addr: pointer to buffer where the SAS address is to be written
+ *
+ * This function extracts the SAS address from an IDENTIFY frame
+ * received. If OOB is SATA, then a SAS address is generated from the
+ * HA tables.
+ *
+ * LOCKING: the frame_rcvd_lock needs to be held since this parses the frame
+ * buffer.
+ */
+static void pm8001_get_attached_sas_addr(struct pm8001_phy *phy,
+ u8 *sas_addr)
+{
+ if (phy->sas_phy.frame_rcvd[0] == 0x34
+ && phy->sas_phy.oob_mode == SATA_OOB_MODE) {
+ struct pm8001_hba_info *pm8001_ha = phy->sas_phy.ha->lldd_ha;
+ /* FIS device-to-host */
+ u64 addr = be64_to_cpu(*(__be64 *)pm8001_ha->sas_addr);
+ addr += phy->sas_phy.id;
+ *(__be64 *)sas_addr = cpu_to_be64(addr);
+ } else {
+ struct sas_identify_frame *idframe =
+ (void *) phy->sas_phy.frame_rcvd;
+ memcpy(sas_addr, idframe->sas_addr, SAS_ADDR_SIZE);
+ }
+}
+
+/**
+ * pm8001_hw_event_ack_req- For PM8001,some events need to acknowage to FW.
+ * @pm8001_ha: our hba card information
+ * @Qnum: the outbound queue message number.
+ * @SEA: source of event to ack
+ * @port_id: port id.
+ * @phyId: phy id.
+ * @param0: parameter 0.
+ * @param1: parameter 1.
+ */
+static void pm8001_hw_event_ack_req(struct pm8001_hba_info *pm8001_ha,
+ u32 Qnum, u32 SEA, u32 port_id, u32 phyId, u32 param0, u32 param1)
+{
+ struct hw_event_ack_req payload;
+ u32 opc = OPC_INB_SAS_HW_EVENT_ACK;
+
+ struct inbound_queue_table *circularQ;
+
+ memset((u8 *)&payload, 0, sizeof(payload));
+ circularQ = &pm8001_ha->inbnd_q_tbl[Qnum];
+ payload.tag = 1;
+ payload.sea_phyid_portid = cpu_to_le32(((SEA & 0xFFFF) << 8) |
+ ((phyId & 0x0F) << 4) | (port_id & 0x0F));
+ payload.param0 = cpu_to_le32(param0);
+ payload.param1 = cpu_to_le32(param1);
+ mpi_build_cmd(pm8001_ha, circularQ, opc, &payload);
+}
+
+static int pm8001_chip_phy_ctl_req(struct pm8001_hba_info *pm8001_ha,
+ u32 phyId, u32 phy_op);
+
+/**
+ * hw_event_sas_phy_up -FW tells me a SAS phy up event.
+ * @pm8001_ha: our hba card information
+ * @piomb: IO message buffer
+ */
+static void
+hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb)
+{
+ struct hw_event_resp *pPayload =
+ (struct hw_event_resp *)(piomb + 4);
+ u32 lr_evt_status_phyid_portid =
+ le32_to_cpu(pPayload->lr_evt_status_phyid_portid);
+ u8 link_rate =
+ (u8)((lr_evt_status_phyid_portid & 0xF0000000) >> 28);
+ u8 phy_id =
+ (u8)((lr_evt_status_phyid_portid & 0x000000F0) >> 4);
+ struct sas_ha_struct *sas_ha = pm8001_ha->sas;
+ struct pm8001_phy *phy = &pm8001_ha->phy[phy_id];
+ unsigned long flags;
+ u8 deviceType = pPayload->sas_identify.dev_type;
+
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("HW_EVENT_SAS_PHY_UP \n"));
+
+ switch (deviceType) {
+ case SAS_PHY_UNUSED:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("device type no device.\n"));
+ break;
+ case SAS_END_DEVICE:
+ PM8001_MSG_DBG(pm8001_ha, pm8001_printk("end device.\n"));
+ pm8001_chip_phy_ctl_req(pm8001_ha, phy_id,
+ PHY_NOTIFY_ENABLE_SPINUP);
+ get_lrate_mode(phy, link_rate);
+ break;
+ case SAS_EDGE_EXPANDER_DEVICE:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("expander device.\n"));
+ get_lrate_mode(phy, link_rate);
+ break;
+ case SAS_FANOUT_EXPANDER_DEVICE:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("fanout expander device.\n"));
+ get_lrate_mode(phy, link_rate);
+ break;
+ default:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("unkown device type(%x)\n", deviceType));
+ break;
+ }
+ phy->phy_type |= PORT_TYPE_SAS;
+ phy->identify.device_type = deviceType;
+ phy->phy_attached = 1;
+ if (phy->identify.device_type == SAS_END_DEV)
+ phy->identify.target_port_protocols = SAS_PROTOCOL_SSP;
+ else if (phy->identify.device_type != NO_DEVICE)
+ phy->identify.target_port_protocols = SAS_PROTOCOL_SMP;
+ phy->sas_phy.oob_mode = SAS_OOB_MODE;
+ sas_ha->notify_phy_event(&phy->sas_phy, PHYE_OOB_DONE);
+ spin_lock_irqsave(&phy->sas_phy.frame_rcvd_lock, flags);
+ memcpy(phy->frame_rcvd, &pPayload->sas_identify,
+ sizeof(struct sas_identify_frame)-4);
+ phy->frame_rcvd_size = sizeof(struct sas_identify_frame) - 4;
+ pm8001_get_attached_sas_addr(phy, phy->sas_phy.attached_sas_addr);
+ spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags);
+ if (pm8001_ha->flags == PM8001F_RUN_TIME)
+ mdelay(200);/*delay a moment to wait disk to spinup*/
+ pm8001_bytes_dmaed(pm8001_ha, phy_id);
+}
+
+/**
+ * hw_event_sata_phy_up -FW tells me a SATA phy up event.
+ * @pm8001_ha: our hba card information
+ * @piomb: IO message buffer
+ */
+static void
+hw_event_sata_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb)
+{
+ struct hw_event_resp *pPayload =
+ (struct hw_event_resp *)(piomb + 4);
+ u32 lr_evt_status_phyid_portid =
+ le32_to_cpu(pPayload->lr_evt_status_phyid_portid);
+ u8 link_rate =
+ (u8)((lr_evt_status_phyid_portid & 0xF0000000) >> 28);
+ u8 phy_id =
+ (u8)((lr_evt_status_phyid_portid & 0x000000F0) >> 4);
+ struct sas_ha_struct *sas_ha = pm8001_ha->sas;
+ struct pm8001_phy *phy = &pm8001_ha->phy[phy_id];
+ unsigned long flags;
+ get_lrate_mode(phy, link_rate);
+ phy->phy_type |= PORT_TYPE_SATA;
+ phy->phy_attached = 1;
+ phy->sas_phy.oob_mode = SATA_OOB_MODE;
+ sas_ha->notify_phy_event(&phy->sas_phy, PHYE_OOB_DONE);
+ spin_lock_irqsave(&phy->sas_phy.frame_rcvd_lock, flags);
+ memcpy(phy->frame_rcvd, ((u8 *)&pPayload->sata_fis - 4),
+ sizeof(struct dev_to_host_fis));
+ phy->frame_rcvd_size = sizeof(struct dev_to_host_fis);
+ phy->identify.target_port_protocols = SAS_PROTOCOL_SATA;
+ phy->identify.device_type = SATA_DEV;
+ pm8001_get_attached_sas_addr(phy, phy->sas_phy.attached_sas_addr);
+ spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags);
+ pm8001_bytes_dmaed(pm8001_ha, phy_id);
+}
+
+/**
+ * hw_event_phy_down -we should notify the libsas the phy is down.
+ * @pm8001_ha: our hba card information
+ * @piomb: IO message buffer
+ */
+static void
+hw_event_phy_down(struct pm8001_hba_info *pm8001_ha, void *piomb)
+{
+ struct hw_event_resp *pPayload =
+ (struct hw_event_resp *)(piomb + 4);
+ u32 lr_evt_status_phyid_portid =
+ le32_to_cpu(pPayload->lr_evt_status_phyid_portid);
+ u8 port_id = (u8)(lr_evt_status_phyid_portid & 0x0000000F);
+ u8 phy_id =
+ (u8)((lr_evt_status_phyid_portid & 0x000000F0) >> 4);
+ u32 npip_portstate = le32_to_cpu(pPayload->npip_portstate);
+ u8 portstate = (u8)(npip_portstate & 0x0000000F);
+
+ switch (portstate) {
+ case PORT_VALID:
+ break;
+ case PORT_INVALID:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk(" PortInvalid portID %d \n", port_id));
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk(" Last phy Down and port invalid\n"));
+ pm8001_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PHY_DOWN,
+ port_id, phy_id, 0, 0);
+ break;
+ case PORT_IN_RESET:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk(" PortInReset portID %d \n", port_id));
+ break;
+ case PORT_NOT_ESTABLISHED:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk(" phy Down and PORT_NOT_ESTABLISHED\n"));
+ break;
+ case PORT_LOSTCOMM:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk(" phy Down and PORT_LOSTCOMM\n"));
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk(" Last phy Down and port invalid\n"));
+ pm8001_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PHY_DOWN,
+ port_id, phy_id, 0, 0);
+ break;
+ default:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk(" phy Down and(default) = %x\n",
+ portstate));
+ break;
+
+ }
+}
+
+/**
+ * mpi_reg_resp -process register device ID response.
+ * @pm8001_ha: our hba card information
+ * @piomb: IO message buffer
+ *
+ * when sas layer find a device it will notify LLDD, then the driver register
+ * the domain device to FW, this event is the return device ID which the FW
+ * has assigned, from now,inter-communication with FW is no longer using the
+ * SAS address, use device ID which FW assigned.
+ */
+static int mpi_reg_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
+{
+ u32 status;
+ u32 device_id;
+ u32 htag;
+ struct pm8001_ccb_info *ccb;
+ struct pm8001_device *pm8001_dev;
+ struct dev_reg_resp *registerRespPayload =
+ (struct dev_reg_resp *)(piomb + 4);
+
+ htag = le32_to_cpu(registerRespPayload->tag);
+ ccb = &pm8001_ha->ccb_info[registerRespPayload->tag];
+ pm8001_dev = ccb->device;
+ status = le32_to_cpu(registerRespPayload->status);
+ device_id = le32_to_cpu(registerRespPayload->device_id);
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk(" register device is status = %d\n", status));
+ switch (status) {
+ case DEVREG_SUCCESS:
+ PM8001_MSG_DBG(pm8001_ha, pm8001_printk("DEVREG_SUCCESS\n"));
+ pm8001_dev->device_id = device_id;
+ break;
+ case DEVREG_FAILURE_OUT_OF_RESOURCE:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("DEVREG_FAILURE_OUT_OF_RESOURCE\n"));
+ break;
+ case DEVREG_FAILURE_DEVICE_ALREADY_REGISTERED:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("DEVREG_FAILURE_DEVICE_ALREADY_REGISTERED\n"));
+ break;
+ case DEVREG_FAILURE_INVALID_PHY_ID:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("DEVREG_FAILURE_INVALID_PHY_ID\n"));
+ break;
+ case DEVREG_FAILURE_PHY_ID_ALREADY_REGISTERED:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("DEVREG_FAILURE_PHY_ID_ALREADY_REGISTERED\n"));
+ break;
+ case DEVREG_FAILURE_PORT_ID_OUT_OF_RANGE:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("DEVREG_FAILURE_PORT_ID_OUT_OF_RANGE\n"));
+ break;
+ case DEVREG_FAILURE_PORT_NOT_VALID_STATE:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("DEVREG_FAILURE_PORT_NOT_VALID_STATE\n"));
+ break;
+ case DEVREG_FAILURE_DEVICE_TYPE_NOT_VALID:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("DEVREG_FAILURE_DEVICE_TYPE_NOT_VALID\n"));
+ break;
+ default:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("DEVREG_FAILURE_DEVICE_TYPE_NOT_UNSORPORTED\n"));
+ break;
+ }
+ complete(pm8001_dev->dcompletion);
+ ccb->task = NULL;
+ ccb->ccb_tag = 0xFFFFFFFF;
+ pm8001_ccb_free(pm8001_ha, htag);
+ return 0;
+}
+
+static int mpi_dereg_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
+{
+ u32 status;
+ u32 device_id;
+ struct dev_reg_resp *registerRespPayload =
+ (struct dev_reg_resp *)(piomb + 4);
+
+ status = le32_to_cpu(registerRespPayload->status);
+ device_id = le32_to_cpu(registerRespPayload->device_id);
+ if (status != 0)
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk(" deregister device failed ,status = %x"
+ ", device_id = %x\n", status, device_id));
+ return 0;
+}
+
+static int
+mpi_fw_flash_update_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
+{
+ u32 status;
+ struct fw_control_ex fw_control_context;
+ struct fw_flash_Update_resp *ppayload =
+ (struct fw_flash_Update_resp *)(piomb + 4);
+ u32 tag = le32_to_cpu(ppayload->tag);
+ struct pm8001_ccb_info *ccb = &pm8001_ha->ccb_info[tag];
+ status = le32_to_cpu(ppayload->status);
+ memcpy(&fw_control_context,
+ ccb->fw_control_context,
+ sizeof(fw_control_context));
+ switch (status) {
+ case FLASH_UPDATE_COMPLETE_PENDING_REBOOT:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk(": FLASH_UPDATE_COMPLETE_PENDING_REBOOT\n"));
+ break;
+ case FLASH_UPDATE_IN_PROGRESS:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk(": FLASH_UPDATE_IN_PROGRESS\n"));
+ break;
+ case FLASH_UPDATE_HDR_ERR:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk(": FLASH_UPDATE_HDR_ERR\n"));
+ break;
+ case FLASH_UPDATE_OFFSET_ERR:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk(": FLASH_UPDATE_OFFSET_ERR\n"));
+ break;
+ case FLASH_UPDATE_CRC_ERR:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk(": FLASH_UPDATE_CRC_ERR\n"));
+ break;
+ case FLASH_UPDATE_LENGTH_ERR:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk(": FLASH_UPDATE_LENGTH_ERR\n"));
+ break;
+ case FLASH_UPDATE_HW_ERR:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk(": FLASH_UPDATE_HW_ERR\n"));
+ break;
+ case FLASH_UPDATE_DNLD_NOT_SUPPORTED:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk(": FLASH_UPDATE_DNLD_NOT_SUPPORTED\n"));
+ break;
+ case FLASH_UPDATE_DISABLED:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk(": FLASH_UPDATE_DISABLED\n"));
+ break;
+ default:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("No matched status = %d\n", status));
+ break;
+ }
+ ccb->fw_control_context->fw_control->retcode = status;
+ pci_free_consistent(pm8001_ha->pdev,
+ fw_control_context.len,
+ fw_control_context.virtAddr,
+ fw_control_context.phys_addr);
+ complete(pm8001_ha->nvmd_completion);
+ ccb->task = NULL;
+ ccb->ccb_tag = 0xFFFFFFFF;
+ pm8001_ccb_free(pm8001_ha, tag);
+ return 0;
+}
+
+static int
+mpi_general_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
+{
+ u32 status;
+ int i;
+ struct general_event_resp *pPayload =
+ (struct general_event_resp *)(piomb + 4);
+ status = le32_to_cpu(pPayload->status);
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk(" status = 0x%x\n", status));
+ for (i = 0; i < GENERAL_EVENT_PAYLOAD; i++)
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("inb_IOMB_payload[0x%x] 0x%x, \n", i,
+ pPayload->inb_IOMB_payload[i]));
+ return 0;
+}
+
+static int
+mpi_task_abort_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
+{
+ struct sas_task *t;
+ struct pm8001_ccb_info *ccb;
+ unsigned long flags;
+ u32 status ;
+ u32 tag, scp;
+ struct task_status_struct *ts;
+
+ struct task_abort_resp *pPayload =
+ (struct task_abort_resp *)(piomb + 4);
+ ccb = &pm8001_ha->ccb_info[pPayload->tag];
+ t = ccb->task;
+
+
+ status = le32_to_cpu(pPayload->status);
+ tag = le32_to_cpu(pPayload->tag);
+ scp = le32_to_cpu(pPayload->scp);
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk(" status = 0x%x\n", status));
+ if (t == NULL)
+ return -1;
+ ts = &t->task_status;
+ if (status != 0)
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("task abort failed status 0x%x ,"
+ "tag = 0x%x, scp= 0x%x\n", status, tag, scp));
+ switch (status) {
+ case IO_SUCCESS:
+ PM8001_EH_DBG(pm8001_ha, pm8001_printk("IO_SUCCESS\n"));
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAM_GOOD;
+ break;
+ case IO_NOT_VALID:
+ PM8001_EH_DBG(pm8001_ha, pm8001_printk("IO_NOT_VALID\n"));
+ ts->resp = TMF_RESP_FUNC_FAILED;
+ break;
+ }
+ spin_lock_irqsave(&t->task_state_lock, flags);
+ t->task_state_flags &= ~SAS_TASK_STATE_PENDING;
+ t->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
+ t->task_state_flags |= SAS_TASK_STATE_DONE;
+ spin_unlock_irqrestore(&t->task_state_lock, flags);
+ pm8001_ccb_task_free(pm8001_ha, t, ccb, pPayload->tag);
+ mb();
+ t->task_done(t);
+ return 0;
+}
+
+/**
+ * mpi_hw_event -The hw event has come.
+ * @pm8001_ha: our hba card information
+ * @piomb: IO message buffer
+ */
+static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void* piomb)
+{
+ unsigned long flags;
+ struct hw_event_resp *pPayload =
+ (struct hw_event_resp *)(piomb + 4);
+ u32 lr_evt_status_phyid_portid =
+ le32_to_cpu(pPayload->lr_evt_status_phyid_portid);
+ u8 port_id = (u8)(lr_evt_status_phyid_portid & 0x0000000F);
+ u8 phy_id =
+ (u8)((lr_evt_status_phyid_portid & 0x000000F0) >> 4);
+ u16 eventType =
+ (u16)((lr_evt_status_phyid_portid & 0x00FFFF00) >> 8);
+ u8 status =
+ (u8)((lr_evt_status_phyid_portid & 0x0F000000) >> 24);
+ struct sas_ha_struct *sas_ha = pm8001_ha->sas;
+ struct pm8001_phy *phy = &pm8001_ha->phy[phy_id];
+ struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id];
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("outbound queue HW event & event type : "));
+ switch (eventType) {
+ case HW_EVENT_PHY_START_STATUS:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("HW_EVENT_PHY_START_STATUS"
+ " status = %x\n", status));
+ if (status == 0) {
+ phy->phy_state = 1;
+ if (pm8001_ha->flags == PM8001F_RUN_TIME)
+ complete(phy->enable_completion);
+ }
+ break;
+ case HW_EVENT_SAS_PHY_UP:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("HW_EVENT_PHY_START_STATUS \n"));
+ hw_event_sas_phy_up(pm8001_ha, piomb);
+ break;
+ case HW_EVENT_SATA_PHY_UP:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("HW_EVENT_SATA_PHY_UP \n"));
+ hw_event_sata_phy_up(pm8001_ha, piomb);
+ break;
+ case HW_EVENT_PHY_STOP_STATUS:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("HW_EVENT_PHY_STOP_STATUS "
+ "status = %x\n", status));
+ if (status == 0)
+ phy->phy_state = 0;
+ break;
+ case HW_EVENT_SATA_SPINUP_HOLD:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("HW_EVENT_SATA_SPINUP_HOLD \n"));
+ sas_ha->notify_phy_event(&phy->sas_phy, PHYE_SPINUP_HOLD);
+ break;
+ case HW_EVENT_PHY_DOWN:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("HW_EVENT_PHY_DOWN \n"));
+ sas_ha->notify_phy_event(&phy->sas_phy, PHYE_LOSS_OF_SIGNAL);
+ phy->phy_attached = 0;
+ phy->phy_state = 0;
+ hw_event_phy_down(pm8001_ha, piomb);
+ break;
+ case HW_EVENT_PORT_INVALID:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("HW_EVENT_PORT_INVALID\n"));
+ sas_phy_disconnected(sas_phy);
+ phy->phy_attached = 0;
+ sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR);
+ break;
+ /* the broadcast change primitive received, tell the LIBSAS this event
+ to revalidate the sas domain*/
+ case HW_EVENT_BROADCAST_CHANGE:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("HW_EVENT_BROADCAST_CHANGE\n"));
+ pm8001_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_BROADCAST_CHANGE,
+ port_id, phy_id, 1, 0);
+ spin_lock_irqsave(&sas_phy->sas_prim_lock, flags);
+ sas_phy->sas_prim = HW_EVENT_BROADCAST_CHANGE;
+ spin_unlock_irqrestore(&sas_phy->sas_prim_lock, flags);
+ sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD);
+ break;
+ case HW_EVENT_PHY_ERROR:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("HW_EVENT_PHY_ERROR\n"));
+ sas_phy_disconnected(&phy->sas_phy);
+ phy->phy_attached = 0;
+ sas_ha->notify_phy_event(&phy->sas_phy, PHYE_OOB_ERROR);
+ break;
+ case HW_EVENT_BROADCAST_EXP:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("HW_EVENT_BROADCAST_EXP\n"));
+ spin_lock_irqsave(&sas_phy->sas_prim_lock, flags);
+ sas_phy->sas_prim = HW_EVENT_BROADCAST_EXP;
+ spin_unlock_irqrestore(&sas_phy->sas_prim_lock, flags);
+ sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD);
+ break;
+ case HW_EVENT_LINK_ERR_INVALID_DWORD:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("HW_EVENT_LINK_ERR_INVALID_DWORD\n"));
+ pm8001_hw_event_ack_req(pm8001_ha, 0,
+ HW_EVENT_LINK_ERR_INVALID_DWORD, port_id, phy_id, 0, 0);
+ sas_phy_disconnected(sas_phy);
+ phy->phy_attached = 0;
+ sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR);
+ break;
+ case HW_EVENT_LINK_ERR_DISPARITY_ERROR:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("HW_EVENT_LINK_ERR_DISPARITY_ERROR\n"));
+ pm8001_hw_event_ack_req(pm8001_ha, 0,
+ HW_EVENT_LINK_ERR_DISPARITY_ERROR,
+ port_id, phy_id, 0, 0);
+ sas_phy_disconnected(sas_phy);
+ phy->phy_attached = 0;
+ sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR);
+ break;
+ case HW_EVENT_LINK_ERR_CODE_VIOLATION:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("HW_EVENT_LINK_ERR_CODE_VIOLATION\n"));
+ pm8001_hw_event_ack_req(pm8001_ha, 0,
+ HW_EVENT_LINK_ERR_CODE_VIOLATION,
+ port_id, phy_id, 0, 0);
+ sas_phy_disconnected(sas_phy);
+ phy->phy_attached = 0;
+ sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR);
+ break;
+ case HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH\n"));
+ pm8001_hw_event_ack_req(pm8001_ha, 0,
+ HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH,
+ port_id, phy_id, 0, 0);
+ sas_phy_disconnected(sas_phy);
+ phy->phy_attached = 0;
+ sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR);
+ break;
+ case HW_EVENT_MALFUNCTION:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("HW_EVENT_MALFUNCTION\n"));
+ break;
+ case HW_EVENT_BROADCAST_SES:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("HW_EVENT_BROADCAST_SES\n"));
+ spin_lock_irqsave(&sas_phy->sas_prim_lock, flags);
+ sas_phy->sas_prim = HW_EVENT_BROADCAST_SES;
+ spin_unlock_irqrestore(&sas_phy->sas_prim_lock, flags);
+ sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD);
+ break;
+ case HW_EVENT_INBOUND_CRC_ERROR:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("HW_EVENT_INBOUND_CRC_ERROR\n"));
+ pm8001_hw_event_ack_req(pm8001_ha, 0,
+ HW_EVENT_INBOUND_CRC_ERROR,
+ port_id, phy_id, 0, 0);
+ break;
+ case HW_EVENT_HARD_RESET_RECEIVED:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("HW_EVENT_HARD_RESET_RECEIVED\n"));
+ sas_ha->notify_port_event(sas_phy, PORTE_HARD_RESET);
+ break;
+ case HW_EVENT_ID_FRAME_TIMEOUT:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("HW_EVENT_ID_FRAME_TIMEOUT\n"));
+ sas_phy_disconnected(sas_phy);
+ phy->phy_attached = 0;
+ sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR);
+ break;
+ case HW_EVENT_LINK_ERR_PHY_RESET_FAILED:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("HW_EVENT_LINK_ERR_PHY_RESET_FAILED \n"));
+ pm8001_hw_event_ack_req(pm8001_ha, 0,
+ HW_EVENT_LINK_ERR_PHY_RESET_FAILED,
+ port_id, phy_id, 0, 0);
+ sas_phy_disconnected(sas_phy);
+ phy->phy_attached = 0;
+ sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR);
+ break;
+ case HW_EVENT_PORT_RESET_TIMER_TMO:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("HW_EVENT_PORT_RESET_TIMER_TMO \n"));
+ sas_phy_disconnected(sas_phy);
+ phy->phy_attached = 0;
+ sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR);
+ break;
+ case HW_EVENT_PORT_RECOVERY_TIMER_TMO:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("HW_EVENT_PORT_RECOVERY_TIMER_TMO \n"));
+ sas_phy_disconnected(sas_phy);
+ phy->phy_attached = 0;
+ sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR);
+ break;
+ case HW_EVENT_PORT_RECOVER:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("HW_EVENT_PORT_RECOVER \n"));
+ break;
+ case HW_EVENT_PORT_RESET_COMPLETE:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("HW_EVENT_PORT_RESET_COMPLETE \n"));
+ break;
+ case EVENT_BROADCAST_ASYNCH_EVENT:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("EVENT_BROADCAST_ASYNCH_EVENT\n"));
+ break;
+ default:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("Unknown event type = %x\n", eventType));
+ break;
+ }
+ return 0;
+}
+
+/**
+ * process_one_iomb - process one outbound Queue memory block
+ * @pm8001_ha: our hba card information
+ * @piomb: IO message buffer
+ */
+static void process_one_iomb(struct pm8001_hba_info *pm8001_ha, void *piomb)
+{
+ u32 pHeader = (u32)*(u32 *)piomb;
+ u8 opc = (u8)((le32_to_cpu(pHeader)) & 0xFFF);
+
+ PM8001_MSG_DBG(pm8001_ha, pm8001_printk("process_one_iomb:"));
+
+ switch (opc) {
+ case OPC_OUB_ECHO:
+ PM8001_MSG_DBG(pm8001_ha, pm8001_printk("OPC_OUB_ECHO \n"));
+ break;
+ case OPC_OUB_HW_EVENT:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("OPC_OUB_HW_EVENT \n"));
+ mpi_hw_event(pm8001_ha, piomb);
+ break;
+ case OPC_OUB_SSP_COMP:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("OPC_OUB_SSP_COMP \n"));
+ mpi_ssp_completion(pm8001_ha, piomb);
+ break;
+ case OPC_OUB_SMP_COMP:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("OPC_OUB_SMP_COMP \n"));
+ mpi_smp_completion(pm8001_ha, piomb);
+ break;
+ case OPC_OUB_LOCAL_PHY_CNTRL:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("OPC_OUB_LOCAL_PHY_CNTRL\n"));
+ mpi_local_phy_ctl(pm8001_ha, piomb);
+ break;
+ case OPC_OUB_DEV_REGIST:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("OPC_OUB_DEV_REGIST \n"));
+ mpi_reg_resp(pm8001_ha, piomb);
+ break;
+ case OPC_OUB_DEREG_DEV:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("unresgister the deviece \n"));
+ mpi_dereg_resp(pm8001_ha, piomb);
+ break;
+ case OPC_OUB_GET_DEV_HANDLE:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("OPC_OUB_GET_DEV_HANDLE \n"));
+ break;
+ case OPC_OUB_SATA_COMP:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("OPC_OUB_SATA_COMP \n"));
+ mpi_sata_completion(pm8001_ha, piomb);
+ break;
+ case OPC_OUB_SATA_EVENT:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("OPC_OUB_SATA_EVENT \n"));
+ mpi_sata_event(pm8001_ha, piomb);
+ break;
+ case OPC_OUB_SSP_EVENT:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("OPC_OUB_SSP_EVENT\n"));
+ mpi_ssp_event(pm8001_ha, piomb);
+ break;
+ case OPC_OUB_DEV_HANDLE_ARRIV:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("OPC_OUB_DEV_HANDLE_ARRIV\n"));
+ /*This is for target*/
+ break;
+ case OPC_OUB_SSP_RECV_EVENT:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("OPC_OUB_SSP_RECV_EVENT\n"));
+ /*This is for target*/
+ break;
+ case OPC_OUB_DEV_INFO:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("OPC_OUB_DEV_INFO\n"));
+ break;
+ case OPC_OUB_FW_FLASH_UPDATE:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("OPC_OUB_FW_FLASH_UPDATE\n"));
+ mpi_fw_flash_update_resp(pm8001_ha, piomb);
+ break;
+ case OPC_OUB_GPIO_RESPONSE:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("OPC_OUB_GPIO_RESPONSE\n"));
+ break;
+ case OPC_OUB_GPIO_EVENT:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("OPC_OUB_GPIO_EVENT\n"));
+ break;
+ case OPC_OUB_GENERAL_EVENT:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("OPC_OUB_GENERAL_EVENT\n"));
+ mpi_general_event(pm8001_ha, piomb);
+ break;
+ case OPC_OUB_SSP_ABORT_RSP:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("OPC_OUB_SSP_ABORT_RSP\n"));
+ mpi_task_abort_resp(pm8001_ha, piomb);
+ break;
+ case OPC_OUB_SATA_ABORT_RSP:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("OPC_OUB_SATA_ABORT_RSP\n"));
+ mpi_task_abort_resp(pm8001_ha, piomb);
+ break;
+ case OPC_OUB_SAS_DIAG_MODE_START_END:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("OPC_OUB_SAS_DIAG_MODE_START_END\n"));
+ break;
+ case OPC_OUB_SAS_DIAG_EXECUTE:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("OPC_OUB_SAS_DIAG_EXECUTE\n"));
+ break;
+ case OPC_OUB_GET_TIME_STAMP:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("OPC_OUB_GET_TIME_STAMP\n"));
+ break;
+ case OPC_OUB_SAS_HW_EVENT_ACK:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("OPC_OUB_SAS_HW_EVENT_ACK\n"));
+ break;
+ case OPC_OUB_PORT_CONTROL:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("OPC_OUB_PORT_CONTROL\n"));
+ break;
+ case OPC_OUB_SMP_ABORT_RSP:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("OPC_OUB_SMP_ABORT_RSP\n"));
+ mpi_task_abort_resp(pm8001_ha, piomb);
+ break;
+ case OPC_OUB_GET_NVMD_DATA:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("OPC_OUB_GET_NVMD_DATA\n"));
+ mpi_get_nvmd_resp(pm8001_ha, piomb);
+ break;
+ case OPC_OUB_SET_NVMD_DATA:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("OPC_OUB_SET_NVMD_DATA\n"));
+ mpi_set_nvmd_resp(pm8001_ha, piomb);
+ break;
+ case OPC_OUB_DEVICE_HANDLE_REMOVAL:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("OPC_OUB_DEVICE_HANDLE_REMOVAL\n"));
+ break;
+ case OPC_OUB_SET_DEVICE_STATE:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("OPC_OUB_SET_DEVICE_STATE\n"));
+ mpi_set_dev_state_resp(pm8001_ha, piomb);
+ break;
+ case OPC_OUB_GET_DEVICE_STATE:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("OPC_OUB_GET_DEVICE_STATE\n"));
+ break;
+ case OPC_OUB_SET_DEV_INFO:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("OPC_OUB_SET_DEV_INFO\n"));
+ break;
+ case OPC_OUB_SAS_RE_INITIALIZE:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("OPC_OUB_SAS_RE_INITIALIZE\n"));
+ break;
+ default:
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("Unknown outbound Queue IOMB OPC = %x\n",
+ opc));
+ break;
+ }
+}
+
+static int process_oq(struct pm8001_hba_info *pm8001_ha)
+{
+ struct outbound_queue_table *circularQ;
+ void *pMsg1 = NULL;
+ u8 bc = 0;
+ u32 ret = MPI_IO_STATUS_FAIL;
+
+ circularQ = &pm8001_ha->outbnd_q_tbl[0];
+ do {
+ ret = mpi_msg_consume(pm8001_ha, circularQ, &pMsg1, &bc);
+ if (MPI_IO_STATUS_SUCCESS == ret) {
+ /* process the outbound message */
+ process_one_iomb(pm8001_ha, (void *)(pMsg1 - 4));
+ /* free the message from the outbound circular buffer */
+ mpi_msg_free_set(pm8001_ha, pMsg1, circularQ, bc);
+ }
+ if (MPI_IO_STATUS_BUSY == ret) {
+ u32 producer_idx;
+ /* Update the producer index from SPC */
+ producer_idx = pm8001_read_32(circularQ->pi_virt);
+ circularQ->producer_index = cpu_to_le32(producer_idx);
+ if (circularQ->producer_index ==
+ circularQ->consumer_idx)
+ /* OQ is empty */
+ break;
+ }
+ } while (1);
+ return ret;
+}
+
+/* PCI_DMA_... to our direction translation. */
+static const u8 data_dir_flags[] = {
+ [PCI_DMA_BIDIRECTIONAL] = DATA_DIR_BYRECIPIENT,/* UNSPECIFIED */
+ [PCI_DMA_TODEVICE] = DATA_DIR_OUT,/* OUTBOUND */
+ [PCI_DMA_FROMDEVICE] = DATA_DIR_IN,/* INBOUND */
+ [PCI_DMA_NONE] = DATA_DIR_NONE,/* NO TRANSFER */
+};
+static void
+pm8001_chip_make_sg(struct scatterlist *scatter, int nr, void *prd)
+{
+ int i;
+ struct scatterlist *sg;
+ struct pm8001_prd *buf_prd = prd;
+
+ for_each_sg(scatter, sg, nr, i) {
+ buf_prd->addr = cpu_to_le64(sg_dma_address(sg));
+ buf_prd->im_len.len = cpu_to_le32(sg_dma_len(sg));
+ buf_prd->im_len.e = 0;
+ buf_prd++;
+ }
+}
+
+static void build_smp_cmd(u32 deviceID, u32 hTag, struct smp_req *psmp_cmd)
+{
+ psmp_cmd->tag = cpu_to_le32(hTag);
+ psmp_cmd->device_id = cpu_to_le32(deviceID);
+ psmp_cmd->len_ip_ir = cpu_to_le32(1|(1 << 1));
+}
+
+/**
+ * pm8001_chip_smp_req - send a SMP task to FW
+ * @pm8001_ha: our hba card information.
+ * @ccb: the ccb information this request used.
+ */
+static int pm8001_chip_smp_req(struct pm8001_hba_info *pm8001_ha,
+ struct pm8001_ccb_info *ccb)
+{
+ int elem, rc;
+ struct sas_task *task = ccb->task;
+ struct domain_device *dev = task->dev;
+ struct pm8001_device *pm8001_dev = dev->lldd_dev;
+ struct scatterlist *sg_req, *sg_resp;
+ u32 req_len, resp_len;
+ struct smp_req smp_cmd;
+ u32 opc;
+ struct inbound_queue_table *circularQ;
+
+ memset(&smp_cmd, 0, sizeof(smp_cmd));
+ /*
+ * DMA-map SMP request, response buffers
+ */
+ sg_req = &task->smp_task.smp_req;
+ elem = dma_map_sg(pm8001_ha->dev, sg_req, 1, PCI_DMA_TODEVICE);
+ if (!elem)
+ return -ENOMEM;
+ req_len = sg_dma_len(sg_req);
+
+ sg_resp = &task->smp_task.smp_resp;
+ elem = dma_map_sg(pm8001_ha->dev, sg_resp, 1, PCI_DMA_FROMDEVICE);
+ if (!elem) {
+ rc = -ENOMEM;
+ goto err_out;
+ }
+ resp_len = sg_dma_len(sg_resp);
+ /* must be in dwords */
+ if ((req_len & 0x3) || (resp_len & 0x3)) {
+ rc = -EINVAL;
+ goto err_out_2;
+ }
+
+ opc = OPC_INB_SMP_REQUEST;
+ circularQ = &pm8001_ha->inbnd_q_tbl[0];
+ smp_cmd.tag = cpu_to_le32(ccb->ccb_tag);
+ smp_cmd.long_smp_req.long_req_addr =
+ cpu_to_le64((u64)sg_dma_address(&task->smp_task.smp_req));
+ smp_cmd.long_smp_req.long_req_size =
+ cpu_to_le32((u32)sg_dma_len(&task->smp_task.smp_req)-4);
+ smp_cmd.long_smp_req.long_resp_addr =
+ cpu_to_le64((u64)sg_dma_address(&task->smp_task.smp_resp));
+ smp_cmd.long_smp_req.long_resp_size =
+ cpu_to_le32((u32)sg_dma_len(&task->smp_task.smp_resp)-4);
+ build_smp_cmd(pm8001_dev->device_id, smp_cmd.tag, &smp_cmd);
+ mpi_build_cmd(pm8001_ha, circularQ, opc, (u32 *)&smp_cmd);
+ return 0;
+
+err_out_2:
+ dma_unmap_sg(pm8001_ha->dev, &ccb->task->smp_task.smp_resp, 1,
+ PCI_DMA_FROMDEVICE);
+err_out:
+ dma_unmap_sg(pm8001_ha->dev, &ccb->task->smp_task.smp_req, 1,
+ PCI_DMA_TODEVICE);
+ return rc;
+}
+
+/**
+ * pm8001_chip_ssp_io_req - send a SSP task to FW
+ * @pm8001_ha: our hba card information.
+ * @ccb: the ccb information this request used.
+ */
+static int pm8001_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha,
+ struct pm8001_ccb_info *ccb)
+{
+ struct sas_task *task = ccb->task;
+ struct domain_device *dev = task->dev;
+ struct pm8001_device *pm8001_dev = dev->lldd_dev;
+ struct ssp_ini_io_start_req ssp_cmd;
+ u32 tag = ccb->ccb_tag;
+ int ret;
+ __le64 phys_addr;
+ struct inbound_queue_table *circularQ;
+ u32 opc = OPC_INB_SSPINIIOSTART;
+ memset(&ssp_cmd, 0, sizeof(ssp_cmd));
+ memcpy(ssp_cmd.ssp_iu.lun, task->ssp_task.LUN, 8);
+ ssp_cmd.dir_m_tlr = data_dir_flags[task->data_dir] << 8 | 0x0;/*0 for
+ SAS 1.1 compatible TLR*/
+ ssp_cmd.data_len = cpu_to_le32(task->total_xfer_len);
+ ssp_cmd.device_id = cpu_to_le32(pm8001_dev->device_id);
+ ssp_cmd.tag = cpu_to_le32(tag);
+ if (task->ssp_task.enable_first_burst)
+ ssp_cmd.ssp_iu.efb_prio_attr |= 0x80;
+ ssp_cmd.ssp_iu.efb_prio_attr |= (task->ssp_task.task_prio << 3);
+ ssp_cmd.ssp_iu.efb_prio_attr |= (task->ssp_task.task_attr & 7);
+ memcpy(ssp_cmd.ssp_iu.cdb, task->ssp_task.cdb, 16);
+ circularQ = &pm8001_ha->inbnd_q_tbl[0];
+
+ /* fill in PRD (scatter/gather) table, if any */
+ if (task->num_scatter > 1) {
+ pm8001_chip_make_sg(task->scatter, ccb->n_elem, ccb->buf_prd);
+ phys_addr = cpu_to_le64(ccb->ccb_dma_handle +
+ offsetof(struct pm8001_ccb_info, buf_prd[0]));
+ ssp_cmd.addr_low = lower_32_bits(phys_addr);
+ ssp_cmd.addr_high = upper_32_bits(phys_addr);
+ ssp_cmd.esgl = cpu_to_le32(1<<31);
+ } else if (task->num_scatter == 1) {
+ __le64 dma_addr = cpu_to_le64(sg_dma_address(task->scatter));
+ ssp_cmd.addr_low = lower_32_bits(dma_addr);
+ ssp_cmd.addr_high = upper_32_bits(dma_addr);
+ ssp_cmd.len = cpu_to_le32(task->total_xfer_len);
+ ssp_cmd.esgl = 0;
+ } else if (task->num_scatter == 0) {
+ ssp_cmd.addr_low = 0;
+ ssp_cmd.addr_high = 0;
+ ssp_cmd.len = cpu_to_le32(task->total_xfer_len);
+ ssp_cmd.esgl = 0;
+ }
+ ret = mpi_build_cmd(pm8001_ha, circularQ, opc, &ssp_cmd);
+ return ret;
+}
+
+static int pm8001_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
+ struct pm8001_ccb_info *ccb)
+{
+ struct sas_task *task = ccb->task;
+ struct domain_device *dev = task->dev;
+ struct pm8001_device *pm8001_ha_dev = dev->lldd_dev;
+ u32 tag = ccb->ccb_tag;
+ int ret;
+ struct sata_start_req sata_cmd;
+ u32 hdr_tag, ncg_tag = 0;
+ __le64 phys_addr;
+ u32 ATAP = 0x0;
+ u32 dir;
+ struct inbound_queue_table *circularQ;
+ u32 opc = OPC_INB_SATA_HOST_OPSTART;
+ memset(&sata_cmd, 0, sizeof(sata_cmd));
+ circularQ = &pm8001_ha->inbnd_q_tbl[0];
+ if (task->data_dir == PCI_DMA_NONE) {
+ ATAP = 0x04; /* no data*/
+ PM8001_IO_DBG(pm8001_ha, pm8001_printk("no data \n"));
+ } else if (likely(!task->ata_task.device_control_reg_update)) {
+ if (task->ata_task.dma_xfer) {
+ ATAP = 0x06; /* DMA */
+ PM8001_IO_DBG(pm8001_ha, pm8001_printk("DMA \n"));
+ } else {
+ ATAP = 0x05; /* PIO*/
+ PM8001_IO_DBG(pm8001_ha, pm8001_printk("PIO \n"));
+ }
+ if (task->ata_task.use_ncq &&
+ dev->sata_dev.command_set != ATAPI_COMMAND_SET) {
+ ATAP = 0x07; /* FPDMA */
+ PM8001_IO_DBG(pm8001_ha, pm8001_printk("FPDMA \n"));
+ }
+ }
+ if (task->ata_task.use_ncq && pm8001_get_ncq_tag(task, &hdr_tag))
+ ncg_tag = cpu_to_le32(hdr_tag);
+ dir = data_dir_flags[task->data_dir] << 8;
+ sata_cmd.tag = cpu_to_le32(tag);
+ sata_cmd.device_id = cpu_to_le32(pm8001_ha_dev->device_id);
+ sata_cmd.data_len = cpu_to_le32(task->total_xfer_len);
+ sata_cmd.ncqtag_atap_dir_m =
+ cpu_to_le32(((ncg_tag & 0xff)<<16)|((ATAP & 0x3f) << 10) | dir);
+ sata_cmd.sata_fis = task->ata_task.fis;
+ if (likely(!task->ata_task.device_control_reg_update))
+ sata_cmd.sata_fis.flags |= 0x80;/* C=1: update ATA cmd reg */
+ sata_cmd.sata_fis.flags &= 0xF0;/* PM_PORT field shall be 0 */
+ /* fill in PRD (scatter/gather) table, if any */
+ if (task->num_scatter > 1) {
+ pm8001_chip_make_sg(task->scatter, ccb->n_elem, ccb->buf_prd);
+ phys_addr = cpu_to_le64(ccb->ccb_dma_handle +
+ offsetof(struct pm8001_ccb_info, buf_prd[0]));
+ sata_cmd.addr_low = lower_32_bits(phys_addr);
+ sata_cmd.addr_high = upper_32_bits(phys_addr);
+ sata_cmd.esgl = cpu_to_le32(1 << 31);
+ } else if (task->num_scatter == 1) {
+ __le64 dma_addr = cpu_to_le64(sg_dma_address(task->scatter));
+ sata_cmd.addr_low = lower_32_bits(dma_addr);
+ sata_cmd.addr_high = upper_32_bits(dma_addr);
+ sata_cmd.len = cpu_to_le32(task->total_xfer_len);
+ sata_cmd.esgl = 0;
+ } else if (task->num_scatter == 0) {
+ sata_cmd.addr_low = 0;
+ sata_cmd.addr_high = 0;
+ sata_cmd.len = cpu_to_le32(task->total_xfer_len);
+ sata_cmd.esgl = 0;
+ }
+ ret = mpi_build_cmd(pm8001_ha, circularQ, opc, &sata_cmd);
+ return ret;
+}
+
+/**
+ * pm8001_chip_phy_start_req - start phy via PHY_START COMMAND
+ * @pm8001_ha: our hba card information.
+ * @num: the inbound queue number
+ * @phy_id: the phy id which we wanted to start up.
+ */
+static int
+pm8001_chip_phy_start_req(struct pm8001_hba_info *pm8001_ha, u8 phy_id)
+{
+ struct phy_start_req payload;
+ struct inbound_queue_table *circularQ;
+ int ret;
+ u32 tag = 0x01;
+ u32 opcode = OPC_INB_PHYSTART;
+ circularQ = &pm8001_ha->inbnd_q_tbl[0];
+ memset(&payload, 0, sizeof(payload));
+ payload.tag = cpu_to_le32(tag);
+ /*
+ ** [0:7] PHY Identifier
+ ** [8:11] link rate 1.5G, 3G, 6G
+ ** [12:13] link mode 01b SAS mode; 10b SATA mode; 11b both
+ ** [14] 0b disable spin up hold; 1b enable spin up hold
+ */
+ payload.ase_sh_lm_slr_phyid = cpu_to_le32(SPINHOLD_DISABLE |
+ LINKMODE_AUTO | LINKRATE_15 |
+ LINKRATE_30 | LINKRATE_60 | phy_id);
+ payload.sas_identify.dev_type = SAS_END_DEV;
+ payload.sas_identify.initiator_bits = SAS_PROTOCOL_ALL;
+ memcpy(payload.sas_identify.sas_addr,
+ pm8001_ha->sas_addr, SAS_ADDR_SIZE);
+ payload.sas_identify.phy_id = phy_id;
+ ret = mpi_build_cmd(pm8001_ha, circularQ, opcode, &payload);
+ return ret;
+}
+
+/**
+ * pm8001_chip_phy_stop_req - start phy via PHY_STOP COMMAND
+ * @pm8001_ha: our hba card information.
+ * @num: the inbound queue number
+ * @phy_id: the phy id which we wanted to start up.
+ */
+static int pm8001_chip_phy_stop_req(struct pm8001_hba_info *pm8001_ha,
+ u8 phy_id)
+{
+ struct phy_stop_req payload;
+ struct inbound_queue_table *circularQ;
+ int ret;
+ u32 tag = 0x01;
+ u32 opcode = OPC_INB_PHYSTOP;
+ circularQ = &pm8001_ha->inbnd_q_tbl[0];
+ memset(&payload, 0, sizeof(payload));
+ payload.tag = cpu_to_le32(tag);
+ payload.phy_id = cpu_to_le32(phy_id);
+ ret = mpi_build_cmd(pm8001_ha, circularQ, opcode, &payload);
+ return ret;
+}
+
+/**
+ * see comments on mpi_reg_resp.
+ */
+static int pm8001_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha,
+ struct pm8001_device *pm8001_dev, u32 flag)
+{
+ struct reg_dev_req payload;
+ u32 opc;
+ u32 stp_sspsmp_sata = 0x4;
+ struct inbound_queue_table *circularQ;
+ u32 linkrate, phy_id;
+ int rc, tag = 0xdeadbeef;
+ struct pm8001_ccb_info *ccb;
+ u8 retryFlag = 0x1;
+ u16 firstBurstSize = 0;
+ u16 ITNT = 2000;
+ struct domain_device *dev = pm8001_dev->sas_device;
+ struct domain_device *parent_dev = dev->parent;
+ circularQ = &pm8001_ha->inbnd_q_tbl[0];
+
+ memset(&payload, 0, sizeof(payload));
+ rc = pm8001_tag_alloc(pm8001_ha, &tag);
+ if (rc)
+ return rc;
+ ccb = &pm8001_ha->ccb_info[tag];
+ ccb->device = pm8001_dev;
+ ccb->ccb_tag = tag;
+ payload.tag = cpu_to_le32(tag);
+ if (flag == 1)
+ stp_sspsmp_sata = 0x02; /*direct attached sata */
+ else {
+ if (pm8001_dev->dev_type == SATA_DEV)
+ stp_sspsmp_sata = 0x00; /* stp*/
+ else if (pm8001_dev->dev_type == SAS_END_DEV ||
+ pm8001_dev->dev_type == EDGE_DEV ||
+ pm8001_dev->dev_type == FANOUT_DEV)
+ stp_sspsmp_sata = 0x01; /*ssp or smp*/
+ }
+ if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type))
+ phy_id = parent_dev->ex_dev.ex_phy->phy_id;
+ else
+ phy_id = pm8001_dev->attached_phy;
+ opc = OPC_INB_REG_DEV;
+ linkrate = (pm8001_dev->sas_device->linkrate < dev->port->linkrate) ?
+ pm8001_dev->sas_device->linkrate : dev->port->linkrate;
+ payload.phyid_portid =
+ cpu_to_le32(((pm8001_dev->sas_device->port->id) & 0x0F) |
+ ((phy_id & 0x0F) << 4));
+ payload.dtype_dlr_retry = cpu_to_le32((retryFlag & 0x01) |
+ ((linkrate & 0x0F) * 0x1000000) |
+ ((stp_sspsmp_sata & 0x03) * 0x10000000));
+ payload.firstburstsize_ITNexustimeout =
+ cpu_to_le32(ITNT | (firstBurstSize * 0x10000));
+ memcpy(&payload.sas_addr_hi, pm8001_dev->sas_device->sas_addr,
+ SAS_ADDR_SIZE);
+ rc = mpi_build_cmd(pm8001_ha, circularQ, opc, &payload);
+ return rc;
+}
+
+/**
+ * see comments on mpi_reg_resp.
+ */
+static int pm8001_chip_dereg_dev_req(struct pm8001_hba_info *pm8001_ha,
+ u32 device_id)
+{
+ struct dereg_dev_req payload;
+ u32 opc = OPC_INB_DEREG_DEV_HANDLE;
+ int ret;
+ struct inbound_queue_table *circularQ;
+
+ circularQ = &pm8001_ha->inbnd_q_tbl[0];
+ memset(&payload, 0, sizeof(payload));
+ payload.tag = 1;
+ payload.device_id = cpu_to_le32(device_id);
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("unregister device device_id = %d\n", device_id));
+ ret = mpi_build_cmd(pm8001_ha, circularQ, opc, &payload);
+ return ret;
+}
+
+/**
+ * pm8001_chip_phy_ctl_req - support the local phy operation
+ * @pm8001_ha: our hba card information.
+ * @num: the inbound queue number
+ * @phy_id: the phy id which we wanted to operate
+ * @phy_op:
+ */
+static int pm8001_chip_phy_ctl_req(struct pm8001_hba_info *pm8001_ha,
+ u32 phyId, u32 phy_op)
+{
+ struct local_phy_ctl_req payload;
+ struct inbound_queue_table *circularQ;
+ int ret;
+ u32 opc = OPC_INB_LOCAL_PHY_CONTROL;
+ memset((u8 *)&payload, 0, sizeof(payload));
+ circularQ = &pm8001_ha->inbnd_q_tbl[0];
+ payload.tag = 1;
+ payload.phyop_phyid =
+ cpu_to_le32(((phy_op & 0xff) << 8) | (phyId & 0x0F));
+ ret = mpi_build_cmd(pm8001_ha, circularQ, opc, &payload);
+ return ret;
+}
+
+static u32 pm8001_chip_is_our_interupt(struct pm8001_hba_info *pm8001_ha)
+{
+ u32 value;
+#ifdef PM8001_USE_MSIX
+ return 1;
+#endif
+ value = pm8001_cr32(pm8001_ha, 0, MSGU_ODR);
+ if (value)
+ return 1;
+ return 0;
+
+}
+
+/**
+ * pm8001_chip_isr - PM8001 isr handler.
+ * @pm8001_ha: our hba card information.
+ * @irq: irq number.
+ * @stat: stat.
+ */
+static irqreturn_t
+pm8001_chip_isr(struct pm8001_hba_info *pm8001_ha)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&pm8001_ha->lock, flags);
+ pm8001_chip_interrupt_disable(pm8001_ha);
+ process_oq(pm8001_ha);
+ pm8001_chip_interrupt_enable(pm8001_ha);
+ spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+ return IRQ_HANDLED;
+}
+
+static int send_task_abort(struct pm8001_hba_info *pm8001_ha, u32 opc,
+ u32 dev_id, u8 flag, u32 task_tag, u32 cmd_tag)
+{
+ struct task_abort_req task_abort;
+ struct inbound_queue_table *circularQ;
+ int ret;
+ circularQ = &pm8001_ha->inbnd_q_tbl[0];
+ memset(&task_abort, 0, sizeof(task_abort));
+ if (ABORT_SINGLE == (flag & ABORT_MASK)) {
+ task_abort.abort_all = 0;
+ task_abort.device_id = cpu_to_le32(dev_id);
+ task_abort.tag_to_abort = cpu_to_le32(task_tag);
+ task_abort.tag = cpu_to_le32(cmd_tag);
+ } else if (ABORT_ALL == (flag & ABORT_MASK)) {
+ task_abort.abort_all = cpu_to_le32(1);
+ task_abort.device_id = cpu_to_le32(dev_id);
+ task_abort.tag = cpu_to_le32(cmd_tag);
+ }
+ ret = mpi_build_cmd(pm8001_ha, circularQ, opc, &task_abort);
+ return ret;
+}
+
+/**
+ * pm8001_chip_abort_task - SAS abort task when error or exception happened.
+ * @task: the task we wanted to aborted.
+ * @flag: the abort flag.
+ */
+static int pm8001_chip_abort_task(struct pm8001_hba_info *pm8001_ha,
+ struct pm8001_device *pm8001_dev, u8 flag, u32 task_tag, u32 cmd_tag)
+{
+ u32 opc, device_id;
+ int rc = TMF_RESP_FUNC_FAILED;
+ PM8001_EH_DBG(pm8001_ha, pm8001_printk("cmd_tag = %x, abort task tag"
+ " = %x", cmd_tag, task_tag));
+ if (pm8001_dev->dev_type == SAS_END_DEV)
+ opc = OPC_INB_SSP_ABORT;
+ else if (pm8001_dev->dev_type == SATA_DEV)
+ opc = OPC_INB_SATA_ABORT;
+ else
+ opc = OPC_INB_SMP_ABORT;/* SMP */
+ device_id = pm8001_dev->device_id;
+ rc = send_task_abort(pm8001_ha, opc, device_id, flag,
+ task_tag, cmd_tag);
+ if (rc != TMF_RESP_FUNC_COMPLETE)
+ PM8001_EH_DBG(pm8001_ha, pm8001_printk("rc= %d\n", rc));
+ return rc;
+}
+
+/**
+ * pm8001_chip_ssp_tm_req - built the task managment command.
+ * @pm8001_ha: our hba card information.
+ * @ccb: the ccb information.
+ * @tmf: task management function.
+ */
+static int pm8001_chip_ssp_tm_req(struct pm8001_hba_info *pm8001_ha,
+ struct pm8001_ccb_info *ccb, struct pm8001_tmf_task *tmf)
+{
+ struct sas_task *task = ccb->task;
+ struct domain_device *dev = task->dev;
+ struct pm8001_device *pm8001_dev = dev->lldd_dev;
+ u32 opc = OPC_INB_SSPINITMSTART;
+ struct inbound_queue_table *circularQ;
+ struct ssp_ini_tm_start_req sspTMCmd;
+ int ret;
+
+ memset(&sspTMCmd, 0, sizeof(sspTMCmd));
+ sspTMCmd.device_id = cpu_to_le32(pm8001_dev->device_id);
+ sspTMCmd.relate_tag = cpu_to_le32(tmf->tag_of_task_to_be_managed);
+ sspTMCmd.tmf = cpu_to_le32(tmf->tmf);
+ memcpy(sspTMCmd.lun, task->ssp_task.LUN, 8);
+ sspTMCmd.tag = cpu_to_le32(ccb->ccb_tag);
+ circularQ = &pm8001_ha->inbnd_q_tbl[0];
+ ret = mpi_build_cmd(pm8001_ha, circularQ, opc, &sspTMCmd);
+ return ret;
+}
+
+static int pm8001_chip_get_nvmd_req(struct pm8001_hba_info *pm8001_ha,
+ void *payload)
+{
+ u32 opc = OPC_INB_GET_NVMD_DATA;
+ u32 nvmd_type;
+ int rc;
+ u32 tag;
+ struct pm8001_ccb_info *ccb;
+ struct inbound_queue_table *circularQ;
+ struct get_nvm_data_req nvmd_req;
+ struct fw_control_ex *fw_control_context;
+ struct pm8001_ioctl_payload *ioctl_payload = payload;
+
+ nvmd_type = ioctl_payload->minor_function;
+ fw_control_context = kzalloc(sizeof(struct fw_control_ex), GFP_KERNEL);
+ fw_control_context->usrAddr = (u8 *)&ioctl_payload->func_specific[0];
+ fw_control_context->len = ioctl_payload->length;
+ circularQ = &pm8001_ha->inbnd_q_tbl[0];
+ memset(&nvmd_req, 0, sizeof(nvmd_req));
+ rc = pm8001_tag_alloc(pm8001_ha, &tag);
+ if (rc)
+ return rc;
+ ccb = &pm8001_ha->ccb_info[tag];
+ ccb->ccb_tag = tag;
+ ccb->fw_control_context = fw_control_context;
+ nvmd_req.tag = cpu_to_le32(tag);
+
+ switch (nvmd_type) {
+ case TWI_DEVICE: {
+ u32 twi_addr, twi_page_size;
+ twi_addr = 0xa8;
+ twi_page_size = 2;
+
+ nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | twi_addr << 16 |
+ twi_page_size << 8 | TWI_DEVICE);
+ nvmd_req.resp_len = cpu_to_le32(ioctl_payload->length);
+ nvmd_req.resp_addr_hi =
+ cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi);
+ nvmd_req.resp_addr_lo =
+ cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_lo);
+ break;
+ }
+ case C_SEEPROM: {
+ nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | C_SEEPROM);
+ nvmd_req.resp_len = cpu_to_le32(ioctl_payload->length);
+ nvmd_req.resp_addr_hi =
+ cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi);
+ nvmd_req.resp_addr_lo =
+ cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_lo);
+ break;
+ }
+ case VPD_FLASH: {
+ nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | VPD_FLASH);
+ nvmd_req.resp_len = cpu_to_le32(ioctl_payload->length);
+ nvmd_req.resp_addr_hi =
+ cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi);
+ nvmd_req.resp_addr_lo =
+ cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_lo);
+ break;
+ }
+ case EXPAN_ROM: {
+ nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | EXPAN_ROM);
+ nvmd_req.resp_len = cpu_to_le32(ioctl_payload->length);
+ nvmd_req.resp_addr_hi =
+ cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi);
+ nvmd_req.resp_addr_lo =
+ cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_lo);
+ break;
+ }
+ default:
+ break;
+ }
+ rc = mpi_build_cmd(pm8001_ha, circularQ, opc, &nvmd_req);
+ return rc;
+}
+
+static int pm8001_chip_set_nvmd_req(struct pm8001_hba_info *pm8001_ha,
+ void *payload)
+{
+ u32 opc = OPC_INB_SET_NVMD_DATA;
+ u32 nvmd_type;
+ int rc;
+ u32 tag;
+ struct pm8001_ccb_info *ccb;
+ struct inbound_queue_table *circularQ;
+ struct set_nvm_data_req nvmd_req;
+ struct fw_control_ex *fw_control_context;
+ struct pm8001_ioctl_payload *ioctl_payload = payload;
+
+ nvmd_type = ioctl_payload->minor_function;
+ fw_control_context = kzalloc(sizeof(struct fw_control_ex), GFP_KERNEL);
+ circularQ = &pm8001_ha->inbnd_q_tbl[0];
+ memcpy(pm8001_ha->memoryMap.region[NVMD].virt_ptr,
+ ioctl_payload->func_specific,
+ ioctl_payload->length);
+ memset(&nvmd_req, 0, sizeof(nvmd_req));
+ rc = pm8001_tag_alloc(pm8001_ha, &tag);
+ if (rc)
+ return rc;
+ ccb = &pm8001_ha->ccb_info[tag];
+ ccb->fw_control_context = fw_control_context;
+ ccb->ccb_tag = tag;
+ nvmd_req.tag = cpu_to_le32(tag);
+ switch (nvmd_type) {
+ case TWI_DEVICE: {
+ u32 twi_addr, twi_page_size;
+ twi_addr = 0xa8;
+ twi_page_size = 2;
+ nvmd_req.reserved[0] = cpu_to_le32(0xFEDCBA98);
+ nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | twi_addr << 16 |
+ twi_page_size << 8 | TWI_DEVICE);
+ nvmd_req.resp_len = cpu_to_le32(ioctl_payload->length);
+ nvmd_req.resp_addr_hi =
+ cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi);
+ nvmd_req.resp_addr_lo =
+ cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_lo);
+ break;
+ }
+ case C_SEEPROM:
+ nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | C_SEEPROM);
+ nvmd_req.resp_len = cpu_to_le32(ioctl_payload->length);
+ nvmd_req.reserved[0] = cpu_to_le32(0xFEDCBA98);
+ nvmd_req.resp_addr_hi =
+ cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi);
+ nvmd_req.resp_addr_lo =
+ cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_lo);
+ break;
+ case VPD_FLASH:
+ nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | VPD_FLASH);
+ nvmd_req.resp_len = cpu_to_le32(ioctl_payload->length);
+ nvmd_req.reserved[0] = cpu_to_le32(0xFEDCBA98);
+ nvmd_req.resp_addr_hi =
+ cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi);
+ nvmd_req.resp_addr_lo =
+ cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_lo);
+ break;
+ case EXPAN_ROM:
+ nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | EXPAN_ROM);
+ nvmd_req.resp_len = cpu_to_le32(ioctl_payload->length);
+ nvmd_req.reserved[0] = cpu_to_le32(0xFEDCBA98);
+ nvmd_req.resp_addr_hi =
+ cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi);
+ nvmd_req.resp_addr_lo =
+ cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_lo);
+ break;
+ default:
+ break;
+ }
+ rc = mpi_build_cmd(pm8001_ha, circularQ, opc, &nvmd_req);
+ return rc;
+}
+
+/**
+ * pm8001_chip_fw_flash_update_build - support the firmware update operation
+ * @pm8001_ha: our hba card information.
+ * @fw_flash_updata_info: firmware flash update param
+ */
+static int
+pm8001_chip_fw_flash_update_build(struct pm8001_hba_info *pm8001_ha,
+ void *fw_flash_updata_info, u32 tag)
+{
+ struct fw_flash_Update_req payload;
+ struct fw_flash_updata_info *info;
+ struct inbound_queue_table *circularQ;
+ int ret;
+ u32 opc = OPC_INB_FW_FLASH_UPDATE;
+
+ memset(&payload, 0, sizeof(struct fw_flash_Update_req));
+ circularQ = &pm8001_ha->inbnd_q_tbl[0];
+ info = fw_flash_updata_info;
+ payload.tag = cpu_to_le32(tag);
+ payload.cur_image_len = cpu_to_le32(info->cur_image_len);
+ payload.cur_image_offset = cpu_to_le32(info->cur_image_offset);
+ payload.total_image_len = cpu_to_le32(info->total_image_len);
+ payload.len = info->sgl.im_len.len ;
+ payload.sgl_addr_lo = lower_32_bits(info->sgl.addr);
+ payload.sgl_addr_hi = upper_32_bits(info->sgl.addr);
+ ret = mpi_build_cmd(pm8001_ha, circularQ, opc, &payload);
+ return ret;
+}
+
+static int
+pm8001_chip_fw_flash_update_req(struct pm8001_hba_info *pm8001_ha,
+ void *payload)
+{
+ struct fw_flash_updata_info flash_update_info;
+ struct fw_control_info *fw_control;
+ struct fw_control_ex *fw_control_context;
+ int rc;
+ u32 tag;
+ struct pm8001_ccb_info *ccb;
+ void *buffer = NULL;
+ dma_addr_t phys_addr;
+ u32 phys_addr_hi;
+ u32 phys_addr_lo;
+ struct pm8001_ioctl_payload *ioctl_payload = payload;
+
+ fw_control_context = kzalloc(sizeof(struct fw_control_ex), GFP_KERNEL);
+ fw_control = (struct fw_control_info *)&ioctl_payload->func_specific[0];
+ if (fw_control->len != 0) {
+ if (pm8001_mem_alloc(pm8001_ha->pdev,
+ (void **)&buffer,
+ &phys_addr,
+ &phys_addr_hi,
+ &phys_addr_lo,
+ fw_control->len, 0) != 0) {
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("Mem alloc failure\n"));
+ return -ENOMEM;
+ }
+ }
+ memset(buffer, 0, fw_control->len);
+ memcpy(buffer, fw_control->buffer, fw_control->len);
+ flash_update_info.sgl.addr = cpu_to_le64(phys_addr);
+ flash_update_info.sgl.im_len.len = cpu_to_le32(fw_control->len);
+ flash_update_info.sgl.im_len.e = 0;
+ flash_update_info.cur_image_offset = fw_control->offset;
+ flash_update_info.cur_image_len = fw_control->len;
+ flash_update_info.total_image_len = fw_control->size;
+ fw_control_context->fw_control = fw_control;
+ fw_control_context->virtAddr = buffer;
+ fw_control_context->len = fw_control->len;
+ rc = pm8001_tag_alloc(pm8001_ha, &tag);
+ if (rc)
+ return rc;
+ ccb = &pm8001_ha->ccb_info[tag];
+ ccb->fw_control_context = fw_control_context;
+ ccb->ccb_tag = tag;
+ rc = pm8001_chip_fw_flash_update_build(pm8001_ha, &flash_update_info,
+ tag);
+ return rc;
+}
+
+static int
+pm8001_chip_set_dev_state_req(struct pm8001_hba_info *pm8001_ha,
+ struct pm8001_device *pm8001_dev, u32 state)
+{
+ struct set_dev_state_req payload;
+ struct inbound_queue_table *circularQ;
+ struct pm8001_ccb_info *ccb;
+ int rc;
+ u32 tag;
+ u32 opc = OPC_INB_SET_DEVICE_STATE;
+ memset(&payload, 0, sizeof(payload));
+ rc = pm8001_tag_alloc(pm8001_ha, &tag);
+ if (rc)
+ return -1;
+ ccb = &pm8001_ha->ccb_info[tag];
+ ccb->ccb_tag = tag;
+ ccb->device = pm8001_dev;
+ circularQ = &pm8001_ha->inbnd_q_tbl[0];
+ payload.tag = cpu_to_le32(tag);
+ payload.device_id = cpu_to_le32(pm8001_dev->device_id);
+ payload.nds = cpu_to_le32(state);
+ rc = mpi_build_cmd(pm8001_ha, circularQ, opc, &payload);
+ return rc;
+
+}
+
+static int
+pm8001_chip_sas_re_initialization(struct pm8001_hba_info *pm8001_ha)
+{
+ struct sas_re_initialization_req payload;
+ struct inbound_queue_table *circularQ;
+ struct pm8001_ccb_info *ccb;
+ int rc;
+ u32 tag;
+ u32 opc = OPC_INB_SAS_RE_INITIALIZE;
+ memset(&payload, 0, sizeof(payload));
+ rc = pm8001_tag_alloc(pm8001_ha, &tag);
+ if (rc)
+ return -1;
+ ccb = &pm8001_ha->ccb_info[tag];
+ ccb->ccb_tag = tag;
+ circularQ = &pm8001_ha->inbnd_q_tbl[0];
+ payload.tag = cpu_to_le32(tag);
+ payload.SSAHOLT = cpu_to_le32(0xd << 25);
+ payload.sata_hol_tmo = cpu_to_le32(80);
+ payload.open_reject_cmdretries_data_retries = cpu_to_le32(0xff00ff);
+ rc = mpi_build_cmd(pm8001_ha, circularQ, opc, &payload);
+ return rc;
+
+}
+
+const struct pm8001_dispatch pm8001_8001_dispatch = {
+ .name = "pmc8001",
+ .chip_init = pm8001_chip_init,
+ .chip_soft_rst = pm8001_chip_soft_rst,
+ .chip_rst = pm8001_hw_chip_rst,
+ .chip_iounmap = pm8001_chip_iounmap,
+ .isr = pm8001_chip_isr,
+ .is_our_interupt = pm8001_chip_is_our_interupt,
+ .isr_process_oq = process_oq,
+ .interrupt_enable = pm8001_chip_interrupt_enable,
+ .interrupt_disable = pm8001_chip_interrupt_disable,
+ .make_prd = pm8001_chip_make_sg,
+ .smp_req = pm8001_chip_smp_req,
+ .ssp_io_req = pm8001_chip_ssp_io_req,
+ .sata_req = pm8001_chip_sata_req,
+ .phy_start_req = pm8001_chip_phy_start_req,
+ .phy_stop_req = pm8001_chip_phy_stop_req,
+ .reg_dev_req = pm8001_chip_reg_dev_req,
+ .dereg_dev_req = pm8001_chip_dereg_dev_req,
+ .phy_ctl_req = pm8001_chip_phy_ctl_req,
+ .task_abort = pm8001_chip_abort_task,
+ .ssp_tm_req = pm8001_chip_ssp_tm_req,
+ .get_nvmd_req = pm8001_chip_get_nvmd_req,
+ .set_nvmd_req = pm8001_chip_set_nvmd_req,
+ .fw_flash_update_req = pm8001_chip_fw_flash_update_req,
+ .set_dev_state_req = pm8001_chip_set_dev_state_req,
+ .sas_re_init_req = pm8001_chip_sas_re_initialization,
+};
+
diff --git a/drivers/scsi/pm8001/pm8001_hwi.h b/drivers/scsi/pm8001/pm8001_hwi.h
new file mode 100644
index 0000000..96e4daa
--- /dev/null
+++ b/drivers/scsi/pm8001/pm8001_hwi.h
@@ -0,0 +1,1030 @@
+/*
+ * PMC-Sierra SPC 8001 SAS/SATA based host adapters driver
+ *
+ * Copyright (c) 2008-2009 USI Co., Ltd.
+ * 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 at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ *
+ */
+#ifndef _PMC8001_REG_H_
+#define _PMC8001_REG_H_
+
+#include <linux/types.h>
+#include <scsi/libsas.h>
+
+
+/* for Request Opcode of IOMB */
+#define OPC_INB_ECHO 1 /* 0x000 */
+#define OPC_INB_PHYSTART 4 /* 0x004 */
+#define OPC_INB_PHYSTOP 5 /* 0x005 */
+#define OPC_INB_SSPINIIOSTART 6 /* 0x006 */
+#define OPC_INB_SSPINITMSTART 7 /* 0x007 */
+#define OPC_INB_SSPINIEXTIOSTART 8 /* 0x008 */
+#define OPC_INB_DEV_HANDLE_ACCEPT 9 /* 0x009 */
+#define OPC_INB_SSPTGTIOSTART 10 /* 0x00A */
+#define OPC_INB_SSPTGTRSPSTART 11 /* 0x00B */
+#define OPC_INB_SSPINIEDCIOSTART 12 /* 0x00C */
+#define OPC_INB_SSPINIEXTEDCIOSTART 13 /* 0x00D */
+#define OPC_INB_SSPTGTEDCIOSTART 14 /* 0x00E */
+#define OPC_INB_SSP_ABORT 15 /* 0x00F */
+#define OPC_INB_DEREG_DEV_HANDLE 16 /* 0x010 */
+#define OPC_INB_GET_DEV_HANDLE 17 /* 0x011 */
+#define OPC_INB_SMP_REQUEST 18 /* 0x012 */
+/* SMP_RESPONSE is removed */
+#define OPC_INB_SMP_RESPONSE 19 /* 0x013 */
+#define OPC_INB_SMP_ABORT 20 /* 0x014 */
+#define OPC_INB_REG_DEV 22 /* 0x016 */
+#define OPC_INB_SATA_HOST_OPSTART 23 /* 0x017 */
+#define OPC_INB_SATA_ABORT 24 /* 0x018 */
+#define OPC_INB_LOCAL_PHY_CONTROL 25 /* 0x019 */
+#define OPC_INB_GET_DEV_INFO 26 /* 0x01A */
+#define OPC_INB_FW_FLASH_UPDATE 32 /* 0x020 */
+#define OPC_INB_GPIO 34 /* 0x022 */
+#define OPC_INB_SAS_DIAG_MODE_START_END 35 /* 0x023 */
+#define OPC_INB_SAS_DIAG_EXECUTE 36 /* 0x024 */
+#define OPC_INB_SAS_HW_EVENT_ACK 37 /* 0x025 */
+#define OPC_INB_GET_TIME_STAMP 38 /* 0x026 */
+#define OPC_INB_PORT_CONTROL 39 /* 0x027 */
+#define OPC_INB_GET_NVMD_DATA 40 /* 0x028 */
+#define OPC_INB_SET_NVMD_DATA 41 /* 0x029 */
+#define OPC_INB_SET_DEVICE_STATE 42 /* 0x02A */
+#define OPC_INB_GET_DEVICE_STATE 43 /* 0x02B */
+#define OPC_INB_SET_DEV_INFO 44 /* 0x02C */
+#define OPC_INB_SAS_RE_INITIALIZE 45 /* 0x02D */
+
+/* for Response Opcode of IOMB */
+#define OPC_OUB_ECHO 1 /* 0x001 */
+#define OPC_OUB_HW_EVENT 4 /* 0x004 */
+#define OPC_OUB_SSP_COMP 5 /* 0x005 */
+#define OPC_OUB_SMP_COMP 6 /* 0x006 */
+#define OPC_OUB_LOCAL_PHY_CNTRL 7 /* 0x007 */
+#define OPC_OUB_DEV_REGIST 10 /* 0x00A */
+#define OPC_OUB_DEREG_DEV 11 /* 0x00B */
+#define OPC_OUB_GET_DEV_HANDLE 12 /* 0x00C */
+#define OPC_OUB_SATA_COMP 13 /* 0x00D */
+#define OPC_OUB_SATA_EVENT 14 /* 0x00E */
+#define OPC_OUB_SSP_EVENT 15 /* 0x00F */
+#define OPC_OUB_DEV_HANDLE_ARRIV 16 /* 0x010 */
+/* SMP_RECEIVED Notification is removed */
+#define OPC_OUB_SMP_RECV_EVENT 17 /* 0x011 */
+#define OPC_OUB_SSP_RECV_EVENT 18 /* 0x012 */
+#define OPC_OUB_DEV_INFO 19 /* 0x013 */
+#define OPC_OUB_FW_FLASH_UPDATE 20 /* 0x014 */
+#define OPC_OUB_GPIO_RESPONSE 22 /* 0x016 */
+#define OPC_OUB_GPIO_EVENT 23 /* 0x017 */
+#define OPC_OUB_GENERAL_EVENT 24 /* 0x018 */
+#define OPC_OUB_SSP_ABORT_RSP 26 /* 0x01A */
+#define OPC_OUB_SATA_ABORT_RSP 27 /* 0x01B */
+#define OPC_OUB_SAS_DIAG_MODE_START_END 28 /* 0x01C */
+#define OPC_OUB_SAS_DIAG_EXECUTE 29 /* 0x01D */
+#define OPC_OUB_GET_TIME_STAMP 30 /* 0x01E */
+#define OPC_OUB_SAS_HW_EVENT_ACK 31 /* 0x01F */
+#define OPC_OUB_PORT_CONTROL 32 /* 0x020 */
+#define OPC_OUB_SKIP_ENTRY 33 /* 0x021 */
+#define OPC_OUB_SMP_ABORT_RSP 34 /* 0x022 */
+#define OPC_OUB_GET_NVMD_DATA 35 /* 0x023 */
+#define OPC_OUB_SET_NVMD_DATA 36 /* 0x024 */
+#define OPC_OUB_DEVICE_HANDLE_REMOVAL 37 /* 0x025 */
+#define OPC_OUB_SET_DEVICE_STATE 38 /* 0x026 */
+#define OPC_OUB_GET_DEVICE_STATE 39 /* 0x027 */
+#define OPC_OUB_SET_DEV_INFO 40 /* 0x028 */
+#define OPC_OUB_SAS_RE_INITIALIZE 41 /* 0x029 */
+
+/* for phy start*/
+#define SPINHOLD_DISABLE (0x00 << 14)
+#define SPINHOLD_ENABLE (0x01 << 14)
+#define LINKMODE_SAS (0x01 << 12)
+#define LINKMODE_DSATA (0x02 << 12)
+#define LINKMODE_AUTO (0x03 << 12)
+#define LINKRATE_15 (0x01 << 8)
+#define LINKRATE_30 (0x02 << 8)
+#define LINKRATE_60 (0x04 << 8)
+
+struct mpi_msg_hdr{
+ __le32 header; /* Bits [11:0] - Message operation code */
+ /* Bits [15:12] - Message Category */
+ /* Bits [21:16] - Outboundqueue ID for the
+ operation completion message */
+ /* Bits [23:22] - Reserved */
+ /* Bits [28:24] - Buffer Count, indicates how
+ many buffer are allocated for the massage */
+ /* Bits [30:29] - Reserved */
+ /* Bits [31] - Message Valid bit */
+} __attribute__((packed, aligned(4)));
+
+
+/*
+ * brief the data structure of PHY Start Command
+ * use to describe enable the phy (64 bytes)
+ */
+struct phy_start_req {
+ __le32 tag;
+ __le32 ase_sh_lm_slr_phyid;
+ struct sas_identify_frame sas_identify;
+ u32 reserved[5];
+} __attribute__((packed, aligned(4)));
+
+
+/*
+ * brief the data structure of PHY Start Command
+ * use to disable the phy (64 bytes)
+ */
+struct phy_stop_req {
+ __le32 tag;
+ __le32 phy_id;
+ u32 reserved[13];
+} __attribute__((packed, aligned(4)));
+
+
+/* set device bits fis - device to host */
+struct set_dev_bits_fis {
+ u8 fis_type; /* 0xA1*/
+ u8 n_i_pmport;
+ /* b7 : n Bit. Notification bit. If set device needs attention. */
+ /* b6 : i Bit. Interrupt Bit */
+ /* b5-b4: reserved2 */
+ /* b3-b0: PM Port */
+ u8 status;
+ u8 error;
+ u32 _r_a;
+} __attribute__ ((packed));
+/* PIO setup FIS - device to host */
+struct pio_setup_fis {
+ u8 fis_type; /* 0x5f */
+ u8 i_d_pmPort;
+ /* b7 : reserved */
+ /* b6 : i bit. Interrupt bit */
+ /* b5 : d bit. data transfer direction. set to 1 for device to host
+ xfer */
+ /* b4 : reserved */
+ /* b3-b0: PM Port */
+ u8 status;
+ u8 error;
+ u8 lbal;
+ u8 lbam;
+ u8 lbah;
+ u8 device;
+ u8 lbal_exp;
+ u8 lbam_exp;
+ u8 lbah_exp;
+ u8 _r_a;
+ u8 sector_count;
+ u8 sector_count_exp;
+ u8 _r_b;
+ u8 e_status;
+ u8 _r_c[2];
+ u8 transfer_count;
+} __attribute__ ((packed));
+
+/*
+ * brief the data structure of SATA Completion Response
+ * use to discribe the sata task response (64 bytes)
+ */
+struct sata_completion_resp {
+ __le32 tag;
+ __le32 status;
+ __le32 param;
+ u32 sata_resp[12];
+} __attribute__((packed, aligned(4)));
+
+
+/*
+ * brief the data structure of SAS HW Event Notification
+ * use to alert the host about the hardware event(64 bytes)
+ */
+struct hw_event_resp {
+ __le32 lr_evt_status_phyid_portid;
+ __le32 evt_param;
+ __le32 npip_portstate;
+ struct sas_identify_frame sas_identify;
+ struct dev_to_host_fis sata_fis;
+} __attribute__((packed, aligned(4)));
+
+
+/*
+ * brief the data structure of REGISTER DEVICE Command
+ * use to describe MPI REGISTER DEVICE Command (64 bytes)
+ */
+
+struct reg_dev_req {
+ __le32 tag;
+ __le32 phyid_portid;
+ __le32 dtype_dlr_retry;
+ __le32 firstburstsize_ITNexustimeout;
+ u32 sas_addr_hi;
+ u32 sas_addr_low;
+ __le32 upper_device_id;
+ u32 reserved[8];
+} __attribute__((packed, aligned(4)));
+
+
+/*
+ * brief the data structure of DEREGISTER DEVICE Command
+ * use to request spc to remove all internal resources associated
+ * with the device id (64 bytes)
+ */
+
+struct dereg_dev_req {
+ __le32 tag;
+ __le32 device_id;
+ u32 reserved[13];
+} __attribute__((packed, aligned(4)));
+
+
+/*
+ * brief the data structure of DEVICE_REGISTRATION Response
+ * use to notify the completion of the device registration (64 bytes)
+ */
+
+struct dev_reg_resp {
+ __le32 tag;
+ __le32 status;
+ __le32 device_id;
+ u32 reserved[12];
+} __attribute__((packed, aligned(4)));
+
+
+/*
+ * brief the data structure of Local PHY Control Command
+ * use to issue PHY CONTROL to local phy (64 bytes)
+ */
+struct local_phy_ctl_req {
+ __le32 tag;
+ __le32 phyop_phyid;
+ u32 reserved1[13];
+} __attribute__((packed, aligned(4)));
+
+
+/**
+ * brief the data structure of Local Phy Control Response
+ * use to describe MPI Local Phy Control Response (64 bytes)
+ */
+struct local_phy_ctl_resp {
+ __le32 tag;
+ __le32 phyop_phyid;
+ __le32 status;
+ u32 reserved[12];
+} __attribute__((packed, aligned(4)));
+
+
+#define OP_BITS 0x0000FF00
+#define ID_BITS 0x0000000F
+
+/*
+ * brief the data structure of PORT Control Command
+ * use to control port properties (64 bytes)
+ */
+
+struct port_ctl_req {
+ __le32 tag;
+ __le32 portop_portid;
+ __le32 param0;
+ __le32 param1;
+ u32 reserved1[11];
+} __attribute__((packed, aligned(4)));
+
+
+/*
+ * brief the data structure of HW Event Ack Command
+ * use to acknowledge receive HW event (64 bytes)
+ */
+
+struct hw_event_ack_req {
+ __le32 tag;
+ __le32 sea_phyid_portid;
+ __le32 param0;
+ __le32 param1;
+ u32 reserved1[11];
+} __attribute__((packed, aligned(4)));
+
+
+/*
+ * brief the data structure of SSP Completion Response
+ * use to indicate a SSP Completion (n bytes)
+ */
+struct ssp_completion_resp {
+ __le32 tag;
+ __le32 status;
+ __le32 param;
+ __le32 ssptag_rescv_rescpad;
+ struct ssp_response_iu ssp_resp_iu;
+ __le32 residual_count;
+} __attribute__((packed, aligned(4)));
+
+
+#define SSP_RESCV_BIT 0x00010000
+
+/*
+ * brief the data structure of SATA EVNET esponse
+ * use to indicate a SATA Completion (64 bytes)
+ */
+
+struct sata_event_resp {
+ __le32 tag;
+ __le32 event;
+ __le32 port_id;
+ __le32 device_id;
+ u32 reserved[11];
+} __attribute__((packed, aligned(4)));
+
+/*
+ * brief the data structure of SSP EVNET esponse
+ * use to indicate a SSP Completion (64 bytes)
+ */
+
+struct ssp_event_resp {
+ __le32 tag;
+ __le32 event;
+ __le32 port_id;
+ __le32 device_id;
+ u32 reserved[11];
+} __attribute__((packed, aligned(4)));
+
+/**
+ * brief the data structure of General Event Notification Response
+ * use to describe MPI General Event Notification Response (64 bytes)
+ */
+struct general_event_resp {
+ __le32 status;
+ __le32 inb_IOMB_payload[14];
+} __attribute__((packed, aligned(4)));
+
+
+#define GENERAL_EVENT_PAYLOAD 14
+#define OPCODE_BITS 0x00000fff
+
+/*
+ * brief the data structure of SMP Request Command
+ * use to describe MPI SMP REQUEST Command (64 bytes)
+ */
+struct smp_req {
+ __le32 tag;
+ __le32 device_id;
+ __le32 len_ip_ir;
+ /* Bits [0] - Indirect response */
+ /* Bits [1] - Indirect Payload */
+ /* Bits [15:2] - Reserved */
+ /* Bits [23:16] - direct payload Len */
+ /* Bits [31:24] - Reserved */
+ u8 smp_req16[16];
+ union {
+ u8 smp_req[32];
+ struct {
+ __le64 long_req_addr;/* sg dma address, LE */
+ __le32 long_req_size;/* LE */
+ u32 _r_a;
+ __le64 long_resp_addr;/* sg dma address, LE */
+ __le32 long_resp_size;/* LE */
+ u32 _r_b;
+ } long_smp_req;/* sequencer extension */
+ };
+} __attribute__((packed, aligned(4)));
+/*
+ * brief the data structure of SMP Completion Response
+ * use to describe MPI SMP Completion Response (64 bytes)
+ */
+struct smp_completion_resp {
+ __le32 tag;
+ __le32 status;
+ __le32 param;
+ __le32 _r_a[12];
+} __attribute__((packed, aligned(4)));
+
+/*
+ *brief the data structure of SSP SMP SATA Abort Command
+ * use to describe MPI SSP SMP & SATA Abort Command (64 bytes)
+ */
+struct task_abort_req {
+ __le32 tag;
+ __le32 device_id;
+ __le32 tag_to_abort;
+ __le32 abort_all;
+ u32 reserved[11];
+} __attribute__((packed, aligned(4)));
+
+/* These flags used for SSP SMP & SATA Abort */
+#define ABORT_MASK 0x3
+#define ABORT_SINGLE 0x0
+#define ABORT_ALL 0x1
+
+/**
+ * brief the data structure of SSP SATA SMP Abort Response
+ * use to describe SSP SMP & SATA Abort Response ( 64 bytes)
+ */
+struct task_abort_resp {
+ __le32 tag;
+ __le32 status;
+ __le32 scp;
+ u32 reserved[12];
+} __attribute__((packed, aligned(4)));
+
+
+/**
+ * brief the data structure of SAS Diagnostic Start/End Command
+ * use to describe MPI SAS Diagnostic Start/End Command (64 bytes)
+ */
+struct sas_diag_start_end_req {
+ __le32 tag;
+ __le32 operation_phyid;
+ u32 reserved[13];
+} __attribute__((packed, aligned(4)));
+
+
+/**
+ * brief the data structure of SAS Diagnostic Execute Command
+ * use to describe MPI SAS Diagnostic Execute Command (64 bytes)
+ */
+struct sas_diag_execute_req{
+ __le32 tag;
+ __le32 cmdtype_cmddesc_phyid;
+ __le32 pat1_pat2;
+ __le32 threshold;
+ __le32 codepat_errmsk;
+ __le32 pmon;
+ __le32 pERF1CTL;
+ u32 reserved[8];
+} __attribute__((packed, aligned(4)));
+
+
+#define SAS_DIAG_PARAM_BYTES 24
+
+/*
+ * brief the data structure of Set Device State Command
+ * use to describe MPI Set Device State Command (64 bytes)
+ */
+struct set_dev_state_req {
+ __le32 tag;
+ __le32 device_id;
+ __le32 nds;
+ u32 reserved[12];
+} __attribute__((packed, aligned(4)));
+
+/*
+ * brief the data structure of sas_re_initialization
+ */
+struct sas_re_initialization_req {
+
+ __le32 tag;
+ __le32 SSAHOLT;/* bit29-set max port;
+ ** bit28-set open reject cmd retries.
+ ** bit27-set open reject data retries.
+ ** bit26-set open reject option, remap:1 or not:0.
+ ** bit25-set sata head of line time out.
+ */
+ __le32 reserved_maxPorts;
+ __le32 open_reject_cmdretries_data_retries;/* cmd retries: 31-bit16;
+ * data retries: bit15-bit0.
+ */
+ __le32 sata_hol_tmo;
+ u32 reserved1[10];
+} __attribute__((packed, aligned(4)));
+
+/*
+ * brief the data structure of SATA Start Command
+ * use to describe MPI SATA IO Start Command (64 bytes)
+ */
+
+struct sata_start_req {
+ __le32 tag;
+ __le32 device_id;
+ __le32 data_len;
+ __le32 ncqtag_atap_dir_m;
+ struct host_to_dev_fis sata_fis;
+ u32 reserved1;
+ u32 reserved2;
+ u32 addr_low;
+ u32 addr_high;
+ __le32 len;
+ __le32 esgl;
+} __attribute__((packed, aligned(4)));
+
+/**
+ * brief the data structure of SSP INI TM Start Command
+ * use to describe MPI SSP INI TM Start Command (64 bytes)
+ */
+struct ssp_ini_tm_start_req {
+ __le32 tag;
+ __le32 device_id;
+ __le32 relate_tag;
+ __le32 tmf;
+ u8 lun[8];
+ __le32 ds_ads_m;
+ u32 reserved[8];
+} __attribute__((packed, aligned(4)));
+
+
+struct ssp_info_unit {
+ u8 lun[8];/* SCSI Logical Unit Number */
+ u8 reserved1;/* reserved */
+ u8 efb_prio_attr;
+ /* B7 : enabledFirstBurst */
+ /* B6-3 : taskPriority */
+ /* B2-0 : taskAttribute */
+ u8 reserved2; /* reserved */
+ u8 additional_cdb_len;
+ /* B7-2 : additional_cdb_len */
+ /* B1-0 : reserved */
+ u8 cdb[16];/* The SCSI CDB up to 16 bytes length */
+} __attribute__((packed, aligned(4)));
+
+
+/**
+ * brief the data structure of SSP INI IO Start Command
+ * use to describe MPI SSP INI IO Start Command (64 bytes)
+ */
+struct ssp_ini_io_start_req {
+ __le32 tag;
+ __le32 device_id;
+ __le32 data_len;
+ __le32 dir_m_tlr;
+ struct ssp_info_unit ssp_iu;
+ __le32 addr_low;
+ __le32 addr_high;
+ __le32 len;
+ __le32 esgl;
+} __attribute__((packed, aligned(4)));
+
+
+/**
+ * brief the data structure of Firmware download
+ * use to describe MPI FW DOWNLOAD Command (64 bytes)
+ */
+struct fw_flash_Update_req {
+ __le32 tag;
+ __le32 cur_image_offset;
+ __le32 cur_image_len;
+ __le32 total_image_len;
+ u32 reserved0[7];
+ __le32 sgl_addr_lo;
+ __le32 sgl_addr_hi;
+ __le32 len;
+ __le32 ext_reserved;
+} __attribute__((packed, aligned(4)));
+
+
+#define FWFLASH_IOMB_RESERVED_LEN 0x07
+/**
+ * brief the data structure of FW_FLASH_UPDATE Response
+ * use to describe MPI FW_FLASH_UPDATE Response (64 bytes)
+ *
+ */
+struct fw_flash_Update_resp {
+ dma_addr_t tag;
+ __le32 status;
+ u32 reserved[13];
+} __attribute__((packed, aligned(4)));
+
+
+/**
+ * brief the data structure of Get NVM Data Command
+ * use to get data from NVM in HBA(64 bytes)
+ */
+struct get_nvm_data_req {
+ __le32 tag;
+ __le32 len_ir_vpdd;
+ __le32 vpd_offset;
+ u32 reserved[8];
+ __le32 resp_addr_lo;
+ __le32 resp_addr_hi;
+ __le32 resp_len;
+ u32 reserved1;
+} __attribute__((packed, aligned(4)));
+
+
+struct set_nvm_data_req {
+ __le32 tag;
+ __le32 len_ir_vpdd;
+ __le32 vpd_offset;
+ u32 reserved[8];
+ __le32 resp_addr_lo;
+ __le32 resp_addr_hi;
+ __le32 resp_len;
+ u32 reserved1;
+} __attribute__((packed, aligned(4)));
+
+
+#define TWI_DEVICE 0x0
+#define C_SEEPROM 0x1
+#define VPD_FLASH 0x4
+#define AAP1_RDUMP 0x5
+#define IOP_RDUMP 0x6
+#define EXPAN_ROM 0x7
+
+#define IPMode 0x80000000
+#define NVMD_TYPE 0x0000000F
+#define NVMD_STAT 0x0000FFFF
+#define NVMD_LEN 0xFF000000
+/**
+ * brief the data structure of Get NVMD Data Response
+ * use to describe MPI Get NVMD Data Response (64 bytes)
+ */
+struct get_nvm_data_resp {
+ __le32 tag;
+ __le32 ir_tda_bn_dps_das_nvm;
+ __le32 dlen_status;
+ __le32 nvm_data[12];
+} __attribute__((packed, aligned(4)));
+
+
+/**
+ * brief the data structure of SAS Diagnostic Start/End Response
+ * use to describe MPI SAS Diagnostic Start/End Response (64 bytes)
+ *
+ */
+struct sas_diag_start_end_resp {
+ __le32 tag;
+ __le32 status;
+ u32 reserved[13];
+} __attribute__((packed, aligned(4)));
+
+
+/**
+ * brief the data structure of SAS Diagnostic Execute Response
+ * use to describe MPI SAS Diagnostic Execute Response (64 bytes)
+ *
+ */
+struct sas_diag_execute_resp {
+ __le32 tag;
+ __le32 cmdtype_cmddesc_phyid;
+ __le32 Status;
+ __le32 ReportData;
+ u32 reserved[11];
+} __attribute__((packed, aligned(4)));
+
+
+/**
+ * brief the data structure of Set Device State Response
+ * use to describe MPI Set Device State Response (64 bytes)
+ *
+ */
+struct set_dev_state_resp {
+ __le32 tag;
+ __le32 status;
+ __le32 device_id;
+ __le32 pds_nds;
+ u32 reserved[11];
+} __attribute__((packed, aligned(4)));
+
+
+#define NDS_BITS 0x0F
+#define PDS_BITS 0xF0
+
+/*
+ * HW Events type
+ */
+
+#define HW_EVENT_RESET_START 0x01
+#define HW_EVENT_CHIP_RESET_COMPLETE 0x02
+#define HW_EVENT_PHY_STOP_STATUS 0x03
+#define HW_EVENT_SAS_PHY_UP 0x04
+#define HW_EVENT_SATA_PHY_UP 0x05
+#define HW_EVENT_SATA_SPINUP_HOLD 0x06
+#define HW_EVENT_PHY_DOWN 0x07
+#define HW_EVENT_PORT_INVALID 0x08
+#define HW_EVENT_BROADCAST_CHANGE 0x09
+#define HW_EVENT_PHY_ERROR 0x0A
+#define HW_EVENT_BROADCAST_SES 0x0B
+#define HW_EVENT_INBOUND_CRC_ERROR 0x0C
+#define HW_EVENT_HARD_RESET_RECEIVED 0x0D
+#define HW_EVENT_MALFUNCTION 0x0E
+#define HW_EVENT_ID_FRAME_TIMEOUT 0x0F
+#define HW_EVENT_BROADCAST_EXP 0x10
+#define HW_EVENT_PHY_START_STATUS 0x11
+#define HW_EVENT_LINK_ERR_INVALID_DWORD 0x12
+#define HW_EVENT_LINK_ERR_DISPARITY_ERROR 0x13
+#define HW_EVENT_LINK_ERR_CODE_VIOLATION 0x14
+#define HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH 0x15
+#define HW_EVENT_LINK_ERR_PHY_RESET_FAILED 0x16
+#define HW_EVENT_PORT_RECOVERY_TIMER_TMO 0x17
+#define HW_EVENT_PORT_RECOVER 0x18
+#define HW_EVENT_PORT_RESET_TIMER_TMO 0x19
+#define HW_EVENT_PORT_RESET_COMPLETE 0x20
+#define EVENT_BROADCAST_ASYNCH_EVENT 0x21
+
+/* port state */
+#define PORT_NOT_ESTABLISHED 0x00
+#define PORT_VALID 0x01
+#define PORT_LOSTCOMM 0x02
+#define PORT_IN_RESET 0x04
+#define PORT_INVALID 0x08
+
+/*
+ * SSP/SMP/SATA IO Completion Status values
+ */
+
+#define IO_SUCCESS 0x00
+#define IO_ABORTED 0x01
+#define IO_OVERFLOW 0x02
+#define IO_UNDERFLOW 0x03
+#define IO_FAILED 0x04
+#define IO_ABORT_RESET 0x05
+#define IO_NOT_VALID 0x06
+#define IO_NO_DEVICE 0x07
+#define IO_ILLEGAL_PARAMETER 0x08
+#define IO_LINK_FAILURE 0x09
+#define IO_PROG_ERROR 0x0A
+#define IO_EDC_IN_ERROR 0x0B
+#define IO_EDC_OUT_ERROR 0x0C
+#define IO_ERROR_HW_TIMEOUT 0x0D
+#define IO_XFER_ERROR_BREAK 0x0E
+#define IO_XFER_ERROR_PHY_NOT_READY 0x0F
+#define IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED 0x10
+#define IO_OPEN_CNX_ERROR_ZONE_VIOLATION 0x11
+#define IO_OPEN_CNX_ERROR_BREAK 0x12
+#define IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS 0x13
+#define IO_OPEN_CNX_ERROR_BAD_DESTINATION 0x14
+#define IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED 0x15
+#define IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY 0x16
+#define IO_OPEN_CNX_ERROR_WRONG_DESTINATION 0x17
+#define IO_OPEN_CNX_ERROR_UNKNOWN_ERROR 0x18
+#define IO_XFER_ERROR_NAK_RECEIVED 0x19
+#define IO_XFER_ERROR_ACK_NAK_TIMEOUT 0x1A
+#define IO_XFER_ERROR_PEER_ABORTED 0x1B
+#define IO_XFER_ERROR_RX_FRAME 0x1C
+#define IO_XFER_ERROR_DMA 0x1D
+#define IO_XFER_ERROR_CREDIT_TIMEOUT 0x1E
+#define IO_XFER_ERROR_SATA_LINK_TIMEOUT 0x1F
+#define IO_XFER_ERROR_SATA 0x20
+#define IO_XFER_ERROR_ABORTED_DUE_TO_SRST 0x22
+#define IO_XFER_ERROR_REJECTED_NCQ_MODE 0x21
+#define IO_XFER_ERROR_ABORTED_NCQ_MODE 0x23
+#define IO_XFER_OPEN_RETRY_TIMEOUT 0x24
+#define IO_XFER_SMP_RESP_CONNECTION_ERROR 0x25
+#define IO_XFER_ERROR_UNEXPECTED_PHASE 0x26
+#define IO_XFER_ERROR_XFER_RDY_OVERRUN 0x27
+#define IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED 0x28
+
+#define IO_XFER_ERROR_CMD_ISSUE_ACK_NAK_TIMEOUT 0x30
+#define IO_XFER_ERROR_CMD_ISSUE_BREAK_BEFORE_ACK_NAK 0x31
+#define IO_XFER_ERROR_CMD_ISSUE_PHY_DOWN_BEFORE_ACK_NAK 0x32
+
+#define IO_XFER_ERROR_OFFSET_MISMATCH 0x34
+#define IO_XFER_ERROR_XFER_ZERO_DATA_LEN 0x35
+#define IO_XFER_CMD_FRAME_ISSUED 0x36
+#define IO_ERROR_INTERNAL_SMP_RESOURCE 0x37
+#define IO_PORT_IN_RESET 0x38
+#define IO_DS_NON_OPERATIONAL 0x39
+#define IO_DS_IN_RECOVERY 0x3A
+#define IO_TM_TAG_NOT_FOUND 0x3B
+#define IO_XFER_PIO_SETUP_ERROR 0x3C
+#define IO_SSP_EXT_IU_ZERO_LEN_ERROR 0x3D
+#define IO_DS_IN_ERROR 0x3E
+#define IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY 0x3F
+#define IO_ABORT_IN_PROGRESS 0x40
+#define IO_ABORT_DELAYED 0x41
+#define IO_INVALID_LENGTH 0x42
+
+/* WARNING: This error code must always be the last number.
+ * If you add error code, modify this code also
+ * It is used as an index
+ */
+#define IO_ERROR_UNKNOWN_GENERIC 0x43
+
+/* MSGU CONFIGURATION TABLE*/
+
+#define SPC_MSGU_CFG_TABLE_UPDATE 0x01/* Inbound doorbell bit0 */
+#define SPC_MSGU_CFG_TABLE_RESET 0x02/* Inbound doorbell bit1 */
+#define SPC_MSGU_CFG_TABLE_FREEZE 0x04/* Inbound doorbell bit2 */
+#define SPC_MSGU_CFG_TABLE_UNFREEZE 0x08/* Inbound doorbell bit4 */
+#define MSGU_IBDB_SET 0x04
+#define MSGU_HOST_INT_STATUS 0x08
+#define MSGU_HOST_INT_MASK 0x0C
+#define MSGU_IOPIB_INT_STATUS 0x18
+#define MSGU_IOPIB_INT_MASK 0x1C
+#define MSGU_IBDB_CLEAR 0x20/* RevB - Host not use */
+#define MSGU_MSGU_CONTROL 0x24
+#define MSGU_ODR 0x3C/* RevB */
+#define MSGU_ODCR 0x40/* RevB */
+#define MSGU_SCRATCH_PAD_0 0x44
+#define MSGU_SCRATCH_PAD_1 0x48
+#define MSGU_SCRATCH_PAD_2 0x4C
+#define MSGU_SCRATCH_PAD_3 0x50
+#define MSGU_HOST_SCRATCH_PAD_0 0x54
+#define MSGU_HOST_SCRATCH_PAD_1 0x58
+#define MSGU_HOST_SCRATCH_PAD_2 0x5C
+#define MSGU_HOST_SCRATCH_PAD_3 0x60
+#define MSGU_HOST_SCRATCH_PAD_4 0x64
+#define MSGU_HOST_SCRATCH_PAD_5 0x68
+#define MSGU_HOST_SCRATCH_PAD_6 0x6C
+#define MSGU_HOST_SCRATCH_PAD_7 0x70
+#define MSGU_ODMR 0x74/* RevB */
+
+/* bit definition for ODMR register */
+#define ODMR_MASK_ALL 0xFFFFFFFF/* mask all
+ interrupt vector */
+#define ODMR_CLEAR_ALL 0/* clear all
+ interrupt vector */
+/* bit definition for ODCR register */
+#define ODCR_CLEAR_ALL 0xFFFFFFFF /* mask all
+ interrupt vector*/
+/* MSIX Interupts */
+#define MSIX_TABLE_OFFSET 0x2000
+#define MSIX_TABLE_ELEMENT_SIZE 0x10
+#define MSIX_INTERRUPT_CONTROL_OFFSET 0xC
+#define MSIX_TABLE_BASE (MSIX_TABLE_OFFSET + MSIX_INTERRUPT_CONTROL_OFFSET)
+#define MSIX_INTERRUPT_DISABLE 0x1
+#define MSIX_INTERRUPT_ENABLE 0x0
+
+
+/* state definition for Scratch Pad1 register */
+#define SCRATCH_PAD1_POR 0x00 /* power on reset state */
+#define SCRATCH_PAD1_SFR 0x01 /* soft reset state */
+#define SCRATCH_PAD1_ERR 0x02 /* error state */
+#define SCRATCH_PAD1_RDY 0x03 /* ready state */
+#define SCRATCH_PAD1_RST 0x04 /* soft reset toggle flag */
+#define SCRATCH_PAD1_AAP1RDY_RST 0x08 /* AAP1 ready for soft reset */
+#define SCRATCH_PAD1_STATE_MASK 0xFFFFFFF0 /* ScratchPad1
+ Mask, bit1-0 State, bit2 Soft Reset, bit3 FW RDY for Soft Reset */
+#define SCRATCH_PAD1_RESERVED 0x000003F8 /* Scratch Pad1
+ Reserved bit 3 to 9 */
+
+ /* state definition for Scratch Pad2 register */
+#define SCRATCH_PAD2_POR 0x00 /* power on state */
+#define SCRATCH_PAD2_SFR 0x01 /* soft reset state */
+#define SCRATCH_PAD2_ERR 0x02 /* error state */
+#define SCRATCH_PAD2_RDY 0x03 /* ready state */
+#define SCRATCH_PAD2_FWRDY_RST 0x04 /* FW ready for soft reset flag*/
+#define SCRATCH_PAD2_IOPRDY_RST 0x08 /* IOP ready for soft reset */
+#define SCRATCH_PAD2_STATE_MASK 0xFFFFFFF4 /* ScratchPad 2
+ Mask, bit1-0 State */
+#define SCRATCH_PAD2_RESERVED 0x000003FC /* Scratch Pad1
+ Reserved bit 2 to 9 */
+
+#define SCRATCH_PAD_ERROR_MASK 0xFFFFFC00 /* Error mask bits */
+#define SCRATCH_PAD_STATE_MASK 0x00000003 /* State Mask bits */
+
+/* main configuration offset - byte offset */
+#define MAIN_SIGNATURE_OFFSET 0x00/* DWORD 0x00 */
+#define MAIN_INTERFACE_REVISION 0x04/* DWORD 0x01 */
+#define MAIN_FW_REVISION 0x08/* DWORD 0x02 */
+#define MAIN_MAX_OUTSTANDING_IO_OFFSET 0x0C/* DWORD 0x03 */
+#define MAIN_MAX_SGL_OFFSET 0x10/* DWORD 0x04 */
+#define MAIN_CNTRL_CAP_OFFSET 0x14/* DWORD 0x05 */
+#define MAIN_GST_OFFSET 0x18/* DWORD 0x06 */
+#define MAIN_IBQ_OFFSET 0x1C/* DWORD 0x07 */
+#define MAIN_OBQ_OFFSET 0x20/* DWORD 0x08 */
+#define MAIN_IQNPPD_HPPD_OFFSET 0x24/* DWORD 0x09 */
+#define MAIN_OB_HW_EVENT_PID03_OFFSET 0x28/* DWORD 0x0A */
+#define MAIN_OB_HW_EVENT_PID47_OFFSET 0x2C/* DWORD 0x0B */
+#define MAIN_OB_NCQ_EVENT_PID03_OFFSET 0x30/* DWORD 0x0C */
+#define MAIN_OB_NCQ_EVENT_PID47_OFFSET 0x34/* DWORD 0x0D */
+#define MAIN_TITNX_EVENT_PID03_OFFSET 0x38/* DWORD 0x0E */
+#define MAIN_TITNX_EVENT_PID47_OFFSET 0x3C/* DWORD 0x0F */
+#define MAIN_OB_SSP_EVENT_PID03_OFFSET 0x40/* DWORD 0x10 */
+#define MAIN_OB_SSP_EVENT_PID47_OFFSET 0x44/* DWORD 0x11 */
+#define MAIN_OB_SMP_EVENT_PID03_OFFSET 0x48/* DWORD 0x12 */
+#define MAIN_OB_SMP_EVENT_PID47_OFFSET 0x4C/* DWORD 0x13 */
+#define MAIN_EVENT_LOG_ADDR_HI 0x50/* DWORD 0x14 */
+#define MAIN_EVENT_LOG_ADDR_LO 0x54/* DWORD 0x15 */
+#define MAIN_EVENT_LOG_BUFF_SIZE 0x58/* DWORD 0x16 */
+#define MAIN_EVENT_LOG_OPTION 0x5C/* DWORD 0x17 */
+#define MAIN_IOP_EVENT_LOG_ADDR_HI 0x60/* DWORD 0x18 */
+#define MAIN_IOP_EVENT_LOG_ADDR_LO 0x64/* DWORD 0x19 */
+#define MAIN_IOP_EVENT_LOG_BUFF_SIZE 0x68/* DWORD 0x1A */
+#define MAIN_IOP_EVENT_LOG_OPTION 0x6C/* DWORD 0x1B */
+#define MAIN_FATAL_ERROR_INTERRUPT 0x70/* DWORD 0x1C */
+#define MAIN_FATAL_ERROR_RDUMP0_OFFSET 0x74/* DWORD 0x1D */
+#define MAIN_FATAL_ERROR_RDUMP0_LENGTH 0x78/* DWORD 0x1E */
+#define MAIN_FATAL_ERROR_RDUMP1_OFFSET 0x7C/* DWORD 0x1F */
+#define MAIN_FATAL_ERROR_RDUMP1_LENGTH 0x80/* DWORD 0x20 */
+#define MAIN_HDA_FLAGS_OFFSET 0x84/* DWORD 0x21 */
+#define MAIN_ANALOG_SETUP_OFFSET 0x88/* DWORD 0x22 */
+
+/* Gereral Status Table offset - byte offset */
+#define GST_GSTLEN_MPIS_OFFSET 0x00
+#define GST_IQ_FREEZE_STATE0_OFFSET 0x04
+#define GST_IQ_FREEZE_STATE1_OFFSET 0x08
+#define GST_MSGUTCNT_OFFSET 0x0C
+#define GST_IOPTCNT_OFFSET 0x10
+#define GST_PHYSTATE_OFFSET 0x18
+#define GST_PHYSTATE0_OFFSET 0x18
+#define GST_PHYSTATE1_OFFSET 0x1C
+#define GST_PHYSTATE2_OFFSET 0x20
+#define GST_PHYSTATE3_OFFSET 0x24
+#define GST_PHYSTATE4_OFFSET 0x28
+#define GST_PHYSTATE5_OFFSET 0x2C
+#define GST_PHYSTATE6_OFFSET 0x30
+#define GST_PHYSTATE7_OFFSET 0x34
+#define GST_RERRINFO_OFFSET 0x44
+
+/* General Status Table - MPI state */
+#define GST_MPI_STATE_UNINIT 0x00
+#define GST_MPI_STATE_INIT 0x01
+#define GST_MPI_STATE_TERMINATION 0x02
+#define GST_MPI_STATE_ERROR 0x03
+#define GST_MPI_STATE_MASK 0x07
+
+#define MBIC_NMI_ENABLE_VPE0_IOP 0x000418
+#define MBIC_NMI_ENABLE_VPE0_AAP1 0x000418
+/* PCIE registers - BAR2(0x18), BAR1(win) 0x010000 */
+#define PCIE_EVENT_INTERRUPT_ENABLE 0x003040
+#define PCIE_EVENT_INTERRUPT 0x003044
+#define PCIE_ERROR_INTERRUPT_ENABLE 0x003048
+#define PCIE_ERROR_INTERRUPT 0x00304C
+/* signature defintion for host scratch pad0 register */
+#define SPC_SOFT_RESET_SIGNATURE 0x252acbcd
+/* Signature for Soft Reset */
+
+/* SPC Reset register - BAR4(0x20), BAR2(win) (need dynamic mapping) */
+#define SPC_REG_RESET 0x000000/* reset register */
+
+/* bit difination for SPC_RESET register */
+#define SPC_REG_RESET_OSSP 0x00000001
+#define SPC_REG_RESET_RAAE 0x00000002
+#define SPC_REG_RESET_PCS_SPBC 0x00000004
+#define SPC_REG_RESET_PCS_IOP_SS 0x00000008
+#define SPC_REG_RESET_PCS_AAP1_SS 0x00000010
+#define SPC_REG_RESET_PCS_AAP2_SS 0x00000020
+#define SPC_REG_RESET_PCS_LM 0x00000040
+#define SPC_REG_RESET_PCS 0x00000080
+#define SPC_REG_RESET_GSM 0x00000100
+#define SPC_REG_RESET_DDR2 0x00010000
+#define SPC_REG_RESET_BDMA_CORE 0x00020000
+#define SPC_REG_RESET_BDMA_SXCBI 0x00040000
+#define SPC_REG_RESET_PCIE_AL_SXCBI 0x00080000
+#define SPC_REG_RESET_PCIE_PWR 0x00100000
+#define SPC_REG_RESET_PCIE_SFT 0x00200000
+#define SPC_REG_RESET_PCS_SXCBI 0x00400000
+#define SPC_REG_RESET_LMS_SXCBI 0x00800000
+#define SPC_REG_RESET_PMIC_SXCBI 0x01000000
+#define SPC_REG_RESET_PMIC_CORE 0x02000000
+#define SPC_REG_RESET_PCIE_PC_SXCBI 0x04000000
+#define SPC_REG_RESET_DEVICE 0x80000000
+
+/* registers for BAR Shifting - BAR2(0x18), BAR1(win) */
+#define SPC_IBW_AXI_TRANSLATION_LOW 0x003258
+
+#define MBIC_AAP1_ADDR_BASE 0x060000
+#define MBIC_IOP_ADDR_BASE 0x070000
+#define GSM_ADDR_BASE 0x0700000
+/* Dynamic map through Bar4 - 0x00700000 */
+#define GSM_CONFIG_RESET 0x00000000
+#define RAM_ECC_DB_ERR 0x00000018
+#define GSM_READ_ADDR_PARITY_INDIC 0x00000058
+#define GSM_WRITE_ADDR_PARITY_INDIC 0x00000060
+#define GSM_WRITE_DATA_PARITY_INDIC 0x00000068
+#define GSM_READ_ADDR_PARITY_CHECK 0x00000038
+#define GSM_WRITE_ADDR_PARITY_CHECK 0x00000040
+#define GSM_WRITE_DATA_PARITY_CHECK 0x00000048
+
+#define RB6_ACCESS_REG 0x6A0000
+#define HDAC_EXEC_CMD 0x0002
+#define HDA_C_PA 0xcb
+#define HDA_SEQ_ID_BITS 0x00ff0000
+#define HDA_GSM_OFFSET_BITS 0x00FFFFFF
+#define MBIC_AAP1_ADDR_BASE 0x060000
+#define MBIC_IOP_ADDR_BASE 0x070000
+#define GSM_ADDR_BASE 0x0700000
+#define SPC_TOP_LEVEL_ADDR_BASE 0x000000
+#define GSM_CONFIG_RESET_VALUE 0x00003b00
+#define GPIO_ADDR_BASE 0x00090000
+#define GPIO_GPIO_0_0UTPUT_CTL_OFFSET 0x0000010c
+
+/* RB6 offset */
+#define SPC_RB6_OFFSET 0x80C0
+/* Magic number of soft reset for RB6 */
+#define RB6_MAGIC_NUMBER_RST 0x1234
+
+/* Device Register status */
+#define DEVREG_SUCCESS 0x00
+#define DEVREG_FAILURE_OUT_OF_RESOURCE 0x01
+#define DEVREG_FAILURE_DEVICE_ALREADY_REGISTERED 0x02
+#define DEVREG_FAILURE_INVALID_PHY_ID 0x03
+#define DEVREG_FAILURE_PHY_ID_ALREADY_REGISTERED 0x04
+#define DEVREG_FAILURE_PORT_ID_OUT_OF_RANGE 0x05
+#define DEVREG_FAILURE_PORT_NOT_VALID_STATE 0x06
+#define DEVREG_FAILURE_DEVICE_TYPE_NOT_VALID 0x07
+
+#endif
+
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
new file mode 100644
index 0000000..42ebe72
--- /dev/null
+++ b/drivers/scsi/pm8001/pm8001_init.c
@@ -0,0 +1,891 @@
+/*
+ * PMC-Sierra SPC 8001 SAS/SATA based host adapters driver
+ *
+ * Copyright (c) 2008-2009 USI Co., Ltd.
+ * 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 at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ *
+ */
+
+#include "pm8001_sas.h"
+#include "pm8001_chips.h"
+
+static struct scsi_transport_template *pm8001_stt;
+
+static const struct pm8001_chip_info pm8001_chips[] = {
+ [chip_8001] = { 8, &pm8001_8001_dispatch,},
+};
+static int pm8001_id;
+
+LIST_HEAD(hba_list);
+
+/**
+ * The main structure which LLDD must register for scsi core.
+ */
+static struct scsi_host_template pm8001_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .queuecommand = sas_queuecommand,
+ .target_alloc = sas_target_alloc,
+ .slave_configure = pm8001_slave_configure,
+ .slave_destroy = sas_slave_destroy,
+ .scan_finished = pm8001_scan_finished,
+ .scan_start = pm8001_scan_start,
+ .change_queue_depth = sas_change_queue_depth,
+ .change_queue_type = sas_change_queue_type,
+ .bios_param = sas_bios_param,
+ .can_queue = 1,
+ .cmd_per_lun = 1,
+ .this_id = -1,
+ .sg_tablesize = SG_ALL,
+ .max_sectors = SCSI_DEFAULT_MAX_SECTORS,
+ .use_clustering = ENABLE_CLUSTERING,
+ .eh_device_reset_handler = sas_eh_device_reset_handler,
+ .eh_bus_reset_handler = sas_eh_bus_reset_handler,
+ .slave_alloc = pm8001_slave_alloc,
+ .target_destroy = sas_target_destroy,
+ .ioctl = sas_ioctl,
+ .shost_attrs = pm8001_host_attrs,
+};
+
+/**
+ * Sas layer call this function to execute specific task.
+ */
+static struct sas_domain_function_template pm8001_transport_ops = {
+ .lldd_dev_found = pm8001_dev_found,
+ .lldd_dev_gone = pm8001_dev_gone,
+
+ .lldd_execute_task = pm8001_queue_command,
+ .lldd_control_phy = pm8001_phy_control,
+
+ .lldd_abort_task = pm8001_abort_task,
+ .lldd_abort_task_set = pm8001_abort_task_set,
+ .lldd_clear_aca = pm8001_clear_aca,
+ .lldd_clear_task_set = pm8001_clear_task_set,
+ .lldd_I_T_nexus_reset = pm8001_I_T_nexus_reset,
+ .lldd_lu_reset = pm8001_lu_reset,
+ .lldd_query_task = pm8001_query_task,
+};
+
+/**
+ *pm8001_phy_init - initiate our adapter phys
+ *@pm8001_ha: our hba structure.
+ *@phy_id: phy id.
+ */
+static void __devinit pm8001_phy_init(struct pm8001_hba_info *pm8001_ha,
+ int phy_id)
+{
+ struct pm8001_phy *phy = &pm8001_ha->phy[phy_id];
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+ phy->phy_state = 0;
+ phy->pm8001_ha = pm8001_ha;
+ sas_phy->enabled = (phy_id < pm8001_ha->chip->n_phy) ? 1 : 0;
+ sas_phy->class = SAS;
+ sas_phy->iproto = SAS_PROTOCOL_ALL;
+ sas_phy->tproto = 0;
+ sas_phy->type = PHY_TYPE_PHYSICAL;
+ sas_phy->role = PHY_ROLE_INITIATOR;
+ sas_phy->oob_mode = OOB_NOT_CONNECTED;
+ sas_phy->linkrate = SAS_LINK_RATE_UNKNOWN;
+ sas_phy->id = phy_id;
+ sas_phy->sas_addr = &pm8001_ha->sas_addr[0];
+ sas_phy->frame_rcvd = &phy->frame_rcvd[0];
+ sas_phy->ha = (struct sas_ha_struct *)pm8001_ha->shost->hostdata;
+ sas_phy->lldd_phy = phy;
+}
+
+/**
+ *pm8001_free - free hba
+ *@pm8001_ha: our hba structure.
+ *
+ */
+static void pm8001_free(struct pm8001_hba_info *pm8001_ha)
+{
+ int i;
+ struct pm8001_wq *wq;
+
+ if (!pm8001_ha)
+ return;
+
+ for (i = 0; i < USI_MAX_MEMCNT; i++) {
+ if (pm8001_ha->memoryMap.region[i].virt_ptr != NULL) {
+ pci_free_consistent(pm8001_ha->pdev,
+ pm8001_ha->memoryMap.region[i].element_size,
+ pm8001_ha->memoryMap.region[i].virt_ptr,
+ pm8001_ha->memoryMap.region[i].phys_addr);
+ }
+ }
+ PM8001_CHIP_DISP->chip_iounmap(pm8001_ha);
+ if (pm8001_ha->shost)
+ scsi_host_put(pm8001_ha->shost);
+ list_for_each_entry(wq, &pm8001_ha->wq_list, entry)
+ cancel_delayed_work(&wq->work_q);
+ kfree(pm8001_ha->tags);
+ kfree(pm8001_ha);
+}
+
+#ifdef PM8001_USE_TASKLET
+static void pm8001_tasklet(unsigned long opaque)
+{
+ struct pm8001_hba_info *pm8001_ha;
+ pm8001_ha = (struct pm8001_hba_info *)opaque;;
+ if (unlikely(!pm8001_ha))
+ BUG_ON(1);
+ PM8001_CHIP_DISP->isr(pm8001_ha);
+}
+#endif
+
+
+ /**
+ * pm8001_interrupt - when HBA originate a interrupt,we should invoke this
+ * dispatcher to handle each case.
+ * @irq: irq number.
+ * @opaque: the passed general host adapter struct
+ */
+static irqreturn_t pm8001_interrupt(int irq, void *opaque)
+{
+ struct pm8001_hba_info *pm8001_ha;
+ irqreturn_t ret = IRQ_HANDLED;
+ struct sas_ha_struct *sha = opaque;
+ pm8001_ha = sha->lldd_ha;
+ if (unlikely(!pm8001_ha))
+ return IRQ_NONE;
+ if (!PM8001_CHIP_DISP->is_our_interupt(pm8001_ha))
+ return IRQ_NONE;
+#ifdef PM8001_USE_TASKLET
+ tasklet_schedule(&pm8001_ha->tasklet);
+#else
+ ret = PM8001_CHIP_DISP->isr(pm8001_ha);
+#endif
+ return ret;
+}
+
+/**
+ * pm8001_alloc - initiate our hba structure and 6 DMAs area.
+ * @pm8001_ha:our hba structure.
+ *
+ */
+static int __devinit pm8001_alloc(struct pm8001_hba_info *pm8001_ha)
+{
+ int i;
+ spin_lock_init(&pm8001_ha->lock);
+ for (i = 0; i < pm8001_ha->chip->n_phy; i++)
+ pm8001_phy_init(pm8001_ha, i);
+
+ pm8001_ha->tags = kzalloc(PM8001_MAX_CCB, GFP_KERNEL);
+ if (!pm8001_ha->tags)
+ goto err_out;
+ /* MPI Memory region 1 for AAP Event Log for fw */
+ pm8001_ha->memoryMap.region[AAP1].num_elements = 1;
+ pm8001_ha->memoryMap.region[AAP1].element_size = PM8001_EVENT_LOG_SIZE;
+ pm8001_ha->memoryMap.region[AAP1].total_len = PM8001_EVENT_LOG_SIZE;
+ pm8001_ha->memoryMap.region[AAP1].alignment = 32;
+
+ /* MPI Memory region 2 for IOP Event Log for fw */
+ pm8001_ha->memoryMap.region[IOP].num_elements = 1;
+ pm8001_ha->memoryMap.region[IOP].element_size = PM8001_EVENT_LOG_SIZE;
+ pm8001_ha->memoryMap.region[IOP].total_len = PM8001_EVENT_LOG_SIZE;
+ pm8001_ha->memoryMap.region[IOP].alignment = 32;
+
+ /* MPI Memory region 3 for consumer Index of inbound queues */
+ pm8001_ha->memoryMap.region[CI].num_elements = 1;
+ pm8001_ha->memoryMap.region[CI].element_size = 4;
+ pm8001_ha->memoryMap.region[CI].total_len = 4;
+ pm8001_ha->memoryMap.region[CI].alignment = 4;
+
+ /* MPI Memory region 4 for producer Index of outbound queues */
+ pm8001_ha->memoryMap.region[PI].num_elements = 1;
+ pm8001_ha->memoryMap.region[PI].element_size = 4;
+ pm8001_ha->memoryMap.region[PI].total_len = 4;
+ pm8001_ha->memoryMap.region[PI].alignment = 4;
+
+ /* MPI Memory region 5 inbound queues */
+ pm8001_ha->memoryMap.region[IB].num_elements = 256;
+ pm8001_ha->memoryMap.region[IB].element_size = 64;
+ pm8001_ha->memoryMap.region[IB].total_len = 256 * 64;
+ pm8001_ha->memoryMap.region[IB].alignment = 64;
+
+ /* MPI Memory region 6 inbound queues */
+ pm8001_ha->memoryMap.region[OB].num_elements = 256;
+ pm8001_ha->memoryMap.region[OB].element_size = 64;
+ pm8001_ha->memoryMap.region[OB].total_len = 256 * 64;
+ pm8001_ha->memoryMap.region[OB].alignment = 64;
+
+ /* Memory region write DMA*/
+ pm8001_ha->memoryMap.region[NVMD].num_elements = 1;
+ pm8001_ha->memoryMap.region[NVMD].element_size = 4096;
+ pm8001_ha->memoryMap.region[NVMD].total_len = 4096;
+ /* Memory region for devices*/
+ pm8001_ha->memoryMap.region[DEV_MEM].num_elements = 1;
+ pm8001_ha->memoryMap.region[DEV_MEM].element_size = PM8001_MAX_DEVICES *
+ sizeof(struct pm8001_device);
+ pm8001_ha->memoryMap.region[DEV_MEM].total_len = PM8001_MAX_DEVICES *
+ sizeof(struct pm8001_device);
+
+ /* Memory region for ccb_info*/
+ pm8001_ha->memoryMap.region[CCB_MEM].num_elements = 1;
+ pm8001_ha->memoryMap.region[CCB_MEM].element_size = PM8001_MAX_CCB *
+ sizeof(struct pm8001_ccb_info);
+ pm8001_ha->memoryMap.region[CCB_MEM].total_len = PM8001_MAX_CCB *
+ sizeof(struct pm8001_ccb_info);
+
+ for (i = 0; i < USI_MAX_MEMCNT; i++) {
+ if (pm8001_mem_alloc(pm8001_ha->pdev,
+ &pm8001_ha->memoryMap.region[i].virt_ptr,
+ &pm8001_ha->memoryMap.region[i].phys_addr,
+ &pm8001_ha->memoryMap.region[i].phys_addr_hi,
+ &pm8001_ha->memoryMap.region[i].phys_addr_lo,
+ pm8001_ha->memoryMap.region[i].total_len,
+ pm8001_ha->memoryMap.region[i].alignment) != 0) {
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("Mem%d alloc failed\n",
+ i));
+ goto err_out;
+ }
+ }
+
+ pm8001_ha->devices = pm8001_ha->memoryMap.region[DEV_MEM].virt_ptr;
+ for (i = 0; i < PM8001_MAX_DEVICES; i++) {
+ pm8001_ha->devices[i].dev_type = NO_DEVICE;
+ pm8001_ha->devices[i].id = i;
+ pm8001_ha->devices[i].device_id = PM8001_MAX_DEVICES;
+ pm8001_ha->devices[i].running_req = 0;
+ }
+ pm8001_ha->ccb_info = pm8001_ha->memoryMap.region[CCB_MEM].virt_ptr;
+ for (i = 0; i < PM8001_MAX_CCB; i++) {
+ pm8001_ha->ccb_info[i].ccb_dma_handle =
+ pm8001_ha->memoryMap.region[CCB_MEM].phys_addr +
+ i * sizeof(struct pm8001_ccb_info);
+ pm8001_ha->ccb_info[i].task = NULL;
+ pm8001_ha->ccb_info[i].ccb_tag = 0xffffffff;
+ pm8001_ha->ccb_info[i].device = NULL;
+ ++pm8001_ha->tags_num;
+ }
+ pm8001_ha->flags = PM8001F_INIT_TIME;
+ /* Initialize tags */
+ pm8001_tag_init(pm8001_ha);
+ return 0;
+err_out:
+ return 1;
+}
+
+/**
+ * pm8001_ioremap - remap the pci high physical address to kernal virtual
+ * address so that we can access them.
+ * @pm8001_ha:our hba structure.
+ */
+static int pm8001_ioremap(struct pm8001_hba_info *pm8001_ha)
+{
+ u32 bar;
+ u32 logicalBar = 0;
+ struct pci_dev *pdev;
+
+ pdev = pm8001_ha->pdev;
+ /* map pci mem (PMC pci base 0-3)*/
+ for (bar = 0; bar < 6; bar++) {
+ /*
+ ** logical BARs for SPC:
+ ** bar 0 and 1 - logical BAR0
+ ** bar 2 and 3 - logical BAR1
+ ** bar4 - logical BAR2
+ ** bar5 - logical BAR3
+ ** Skip the appropriate assignments:
+ */
+ if ((bar == 1) || (bar == 3))
+ continue;
+ if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) {
+ pm8001_ha->io_mem[logicalBar].membase =
+ pci_resource_start(pdev, bar);
+ pm8001_ha->io_mem[logicalBar].membase &=
+ (u32)PCI_BASE_ADDRESS_MEM_MASK;
+ pm8001_ha->io_mem[logicalBar].memsize =
+ pci_resource_len(pdev, bar);
+ pm8001_ha->io_mem[logicalBar].memvirtaddr =
+ ioremap(pm8001_ha->io_mem[logicalBar].membase,
+ pm8001_ha->io_mem[logicalBar].memsize);
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("PCI: bar %d, logicalBar %d "
+ "virt_addr=%lx,len=%d\n", bar, logicalBar,
+ (unsigned long)
+ pm8001_ha->io_mem[logicalBar].memvirtaddr,
+ pm8001_ha->io_mem[logicalBar].memsize));
+ } else {
+ pm8001_ha->io_mem[logicalBar].membase = 0;
+ pm8001_ha->io_mem[logicalBar].memsize = 0;
+ pm8001_ha->io_mem[logicalBar].memvirtaddr = 0;
+ }
+ logicalBar++;
+ }
+ return 0;
+}
+
+/**
+ * pm8001_pci_alloc - initialize our ha card structure
+ * @pdev: pci device.
+ * @ent: ent
+ * @shost: scsi host struct which has been initialized before.
+ */
+static struct pm8001_hba_info *__devinit
+pm8001_pci_alloc(struct pci_dev *pdev, u32 chip_id, struct Scsi_Host *shost)
+{
+ struct pm8001_hba_info *pm8001_ha;
+ struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+
+
+ pm8001_ha = sha->lldd_ha;
+ if (!pm8001_ha)
+ return NULL;
+
+ pm8001_ha->pdev = pdev;
+ pm8001_ha->dev = &pdev->dev;
+ pm8001_ha->chip_id = chip_id;
+ pm8001_ha->chip = &pm8001_chips[pm8001_ha->chip_id];
+ pm8001_ha->irq = pdev->irq;
+ pm8001_ha->sas = sha;
+ pm8001_ha->shost = shost;
+ pm8001_ha->id = pm8001_id++;
+ INIT_LIST_HEAD(&pm8001_ha->wq_list);
+ pm8001_ha->logging_level = 0x01;
+ sprintf(pm8001_ha->name, "%s%d", DRV_NAME, pm8001_ha->id);
+#ifdef PM8001_USE_TASKLET
+ tasklet_init(&pm8001_ha->tasklet, pm8001_tasklet,
+ (unsigned long)pm8001_ha);
+#endif
+ pm8001_ioremap(pm8001_ha);
+ if (!pm8001_alloc(pm8001_ha))
+ return pm8001_ha;
+ pm8001_free(pm8001_ha);
+ return NULL;
+}
+
+/**
+ * pci_go_44 - pm8001 specified, its DMA is 44 bit rather than 64 bit
+ * @pdev: pci device.
+ */
+static int pci_go_44(struct pci_dev *pdev)
+{
+ int rc;
+
+ if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(44))) {
+ rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(44));
+ if (rc) {
+ rc = pci_set_consistent_dma_mask(pdev,
+ DMA_BIT_MASK(32));
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "44-bit DMA enable failed\n");
+ return rc;
+ }
+ }
+ } else {
+ rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "32-bit DMA enable failed\n");
+ return rc;
+ }
+ rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "32-bit consistent DMA enable failed\n");
+ return rc;
+ }
+ }
+ return rc;
+}
+
+/**
+ * pm8001_prep_sas_ha_init - allocate memory in general hba struct && init them.
+ * @shost: scsi host which has been allocated outside.
+ * @chip_info: our ha struct.
+ */
+static int __devinit pm8001_prep_sas_ha_init(struct Scsi_Host * shost,
+ const struct pm8001_chip_info *chip_info)
+{
+ int phy_nr, port_nr;
+ struct asd_sas_phy **arr_phy;
+ struct asd_sas_port **arr_port;
+ struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+
+ phy_nr = chip_info->n_phy;
+ port_nr = phy_nr;
+ memset(sha, 0x00, sizeof(*sha));
+ arr_phy = kcalloc(phy_nr, sizeof(void *), GFP_KERNEL);
+ if (!arr_phy)
+ goto exit;
+ arr_port = kcalloc(port_nr, sizeof(void *), GFP_KERNEL);
+ if (!arr_port)
+ goto exit_free2;
+
+ sha->sas_phy = arr_phy;
+ sha->sas_port = arr_port;
+ sha->lldd_ha = kzalloc(sizeof(struct pm8001_hba_info), GFP_KERNEL);
+ if (!sha->lldd_ha)
+ goto exit_free1;
+
+ shost->transportt = pm8001_stt;
+ shost->max_id = PM8001_MAX_DEVICES;
+ shost->max_lun = 8;
+ shost->max_channel = 0;
+ shost->unique_id = pm8001_id;
+ shost->max_cmd_len = 16;
+ shost->can_queue = PM8001_CAN_QUEUE;
+ shost->cmd_per_lun = 32;
+ return 0;
+exit_free1:
+ kfree(arr_port);
+exit_free2:
+ kfree(arr_phy);
+exit:
+ return -1;
+}
+
+/**
+ * pm8001_post_sas_ha_init - initialize general hba struct defined in libsas
+ * @shost: scsi host which has been allocated outside
+ * @chip_info: our ha struct.
+ */
+static void __devinit pm8001_post_sas_ha_init(struct Scsi_Host *shost,
+ const struct pm8001_chip_info *chip_info)
+{
+ int i = 0;
+ struct pm8001_hba_info *pm8001_ha;
+ struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+
+ pm8001_ha = sha->lldd_ha;
+ for (i = 0; i < chip_info->n_phy; i++) {
+ sha->sas_phy[i] = &pm8001_ha->phy[i].sas_phy;
+ sha->sas_port[i] = &pm8001_ha->port[i].sas_port;
+ }
+ sha->sas_ha_name = DRV_NAME;
+ sha->dev = pm8001_ha->dev;
+
+ sha->lldd_module = THIS_MODULE;
+ sha->sas_addr = &pm8001_ha->sas_addr[0];
+ sha->num_phys = chip_info->n_phy;
+ sha->lldd_max_execute_num = 1;
+ sha->lldd_queue_size = PM8001_CAN_QUEUE;
+ sha->core.shost = shost;
+}
+
+/**
+ * pm8001_init_sas_add - initialize sas address
+ * @chip_info: our ha struct.
+ *
+ * Currently we just set the fixed SAS address to our HBA,for manufacture,
+ * it should read from the EEPROM
+ */
+static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha)
+{
+ u8 i;
+#ifdef PM8001_READ_VPD
+ DECLARE_COMPLETION_ONSTACK(completion);
+ pm8001_ha->nvmd_completion = &completion;
+ PM8001_CHIP_DISP->get_nvmd_req(pm8001_ha, 0, 0);
+ wait_for_completion(&completion);
+ for (i = 0; i < pm8001_ha->chip->n_phy; i++) {
+ memcpy(&pm8001_ha->phy[i].dev_sas_addr, pm8001_ha->sas_addr,
+ SAS_ADDR_SIZE);
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("phy %d sas_addr = %x \n", i,
+ (u64)pm8001_ha->phy[i].dev_sas_addr));
+ }
+#else
+ for (i = 0; i < pm8001_ha->chip->n_phy; i++) {
+ pm8001_ha->phy[i].dev_sas_addr = 0x500e004010000004ULL;
+ pm8001_ha->phy[i].dev_sas_addr =
+ cpu_to_be64((u64)
+ (*(u64 *)&pm8001_ha->phy[i].dev_sas_addr));
+ }
+ memcpy(pm8001_ha->sas_addr, &pm8001_ha->phy[0].dev_sas_addr,
+ SAS_ADDR_SIZE);
+#endif
+}
+
+#ifdef PM8001_USE_MSIX
+/**
+ * pm8001_setup_msix - enable MSI-X interrupt
+ * @chip_info: our ha struct.
+ * @irq_handler: irq_handler
+ */
+static u32 pm8001_setup_msix(struct pm8001_hba_info *pm8001_ha,
+ irq_handler_t irq_handler)
+{
+ u32 i = 0, j = 0;
+ u32 number_of_intr = 1;
+ int flag = 0;
+ u32 max_entry;
+ int rc;
+ max_entry = sizeof(pm8001_ha->msix_entries) /
+ sizeof(pm8001_ha->msix_entries[0]);
+ flag |= IRQF_DISABLED;
+ for (i = 0; i < max_entry ; i++)
+ pm8001_ha->msix_entries[i].entry = i;
+ rc = pci_enable_msix(pm8001_ha->pdev, pm8001_ha->msix_entries,
+ number_of_intr);
+ pm8001_ha->number_of_intr = number_of_intr;
+ if (!rc) {
+ for (i = 0; i < number_of_intr; i++) {
+ if (request_irq(pm8001_ha->msix_entries[i].vector,
+ irq_handler, flag, DRV_NAME,
+ SHOST_TO_SAS_HA(pm8001_ha->shost))) {
+ for (j = 0; j < i; j++)
+ free_irq(
+ pm8001_ha->msix_entries[j].vector,
+ SHOST_TO_SAS_HA(pm8001_ha->shost));
+ pci_disable_msix(pm8001_ha->pdev);
+ break;
+ }
+ }
+ }
+ return rc;
+}
+#endif
+
+/**
+ * pm8001_request_irq - register interrupt
+ * @chip_info: our ha struct.
+ */
+static u32 pm8001_request_irq(struct pm8001_hba_info *pm8001_ha)
+{
+ struct pci_dev *pdev;
+ irq_handler_t irq_handler = pm8001_interrupt;
+ int rc;
+
+ pdev = pm8001_ha->pdev;
+
+#ifdef PM8001_USE_MSIX
+ if (pci_find_capability(pdev, PCI_CAP_ID_MSIX))
+ return pm8001_setup_msix(pm8001_ha, irq_handler);
+ else
+ goto intx;
+#endif
+
+intx:
+ /* intialize the INT-X interrupt */
+ rc = request_irq(pdev->irq, irq_handler, IRQF_SHARED, DRV_NAME,
+ SHOST_TO_SAS_HA(pm8001_ha->shost));
+ return rc;
+}
+
+/**
+ * pm8001_pci_probe - probe supported device
+ * @pdev: pci device which kernel has been prepared for.
+ * @ent: pci device id
+ *
+ * This function is the main initialization function, when register a new
+ * pci driver it is invoked, all struct an hardware initilization should be done
+ * here, also, register interrupt
+ */
+static int __devinit pm8001_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ unsigned int rc;
+ u32 pci_reg;
+ struct pm8001_hba_info *pm8001_ha;
+ struct Scsi_Host *shost = NULL;
+ const struct pm8001_chip_info *chip;
+
+ dev_printk(KERN_INFO, &pdev->dev,
+ "pm8001: driver version %s\n", DRV_VERSION);
+ rc = pci_enable_device(pdev);
+ if (rc)
+ goto err_out_enable;
+ pci_set_master(pdev);
+ /*
+ * Enable pci slot busmaster by setting pci command register.
+ * This is required by FW for Cyclone card.
+ */
+
+ pci_read_config_dword(pdev, PCI_COMMAND, &pci_reg);
+ pci_reg |= 0x157;
+ pci_write_config_dword(pdev, PCI_COMMAND, pci_reg);
+ rc = pci_request_regions(pdev, DRV_NAME);
+ if (rc)
+ goto err_out_disable;
+ rc = pci_go_44(pdev);
+ if (rc)
+ goto err_out_regions;
+
+ shost = scsi_host_alloc(&pm8001_sht, sizeof(void *));
+ if (!shost) {
+ rc = -ENOMEM;
+ goto err_out_regions;
+ }
+ chip = &pm8001_chips[ent->driver_data];
+ SHOST_TO_SAS_HA(shost) =
+ kcalloc(1, sizeof(struct sas_ha_struct), GFP_KERNEL);
+ if (!SHOST_TO_SAS_HA(shost)) {
+ rc = -ENOMEM;
+ goto err_out_free_host;
+ }
+
+ rc = pm8001_prep_sas_ha_init(shost, chip);
+ if (rc) {
+ rc = -ENOMEM;
+ goto err_out_free;
+ }
+ pci_set_drvdata(pdev, SHOST_TO_SAS_HA(shost));
+ pm8001_ha = pm8001_pci_alloc(pdev, chip_8001, shost);
+ if (!pm8001_ha) {
+ rc = -ENOMEM;
+ goto err_out_free;
+ }
+ list_add_tail(&pm8001_ha->list, &hba_list);
+ PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha, 0x252acbcd);
+ rc = PM8001_CHIP_DISP->chip_init(pm8001_ha);
+ if (rc)
+ goto err_out_ha_free;
+
+ rc = scsi_add_host(shost, &pdev->dev);
+ if (rc)
+ goto err_out_ha_free;
+ rc = pm8001_request_irq(pm8001_ha);
+ if (rc)
+ goto err_out_shost;
+
+ PM8001_CHIP_DISP->interrupt_enable(pm8001_ha);
+ pm8001_init_sas_add(pm8001_ha);
+ pm8001_post_sas_ha_init(shost, chip);
+ rc = sas_register_ha(SHOST_TO_SAS_HA(shost));
+ if (rc)
+ goto err_out_shost;
+ scsi_scan_host(pm8001_ha->shost);
+ return 0;
+
+err_out_shost:
+ scsi_remove_host(pm8001_ha->shost);
+err_out_ha_free:
+ pm8001_free(pm8001_ha);
+err_out_free:
+ kfree(SHOST_TO_SAS_HA(shost));
+err_out_free_host:
+ kfree(shost);
+err_out_regions:
+ pci_release_regions(pdev);
+err_out_disable:
+ pci_disable_device(pdev);
+err_out_enable:
+ return rc;
+}
+
+static void __devexit pm8001_pci_remove(struct pci_dev *pdev)
+{
+ struct sas_ha_struct *sha = pci_get_drvdata(pdev);
+ struct pm8001_hba_info *pm8001_ha;
+ int i;
+ pm8001_ha = sha->lldd_ha;
+ pci_set_drvdata(pdev, NULL);
+ sas_unregister_ha(sha);
+ sas_remove_host(pm8001_ha->shost);
+ list_del(&pm8001_ha->list);
+ scsi_remove_host(pm8001_ha->shost);
+ PM8001_CHIP_DISP->interrupt_disable(pm8001_ha);
+ PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha, 0x252acbcd);
+
+#ifdef PM8001_USE_MSIX
+ for (i = 0; i < pm8001_ha->number_of_intr; i++)
+ synchronize_irq(pm8001_ha->msix_entries[i].vector);
+ for (i = 0; i < pm8001_ha->number_of_intr; i++)
+ free_irq(pm8001_ha->msix_entries[i].vector, sha);
+ pci_disable_msix(pdev);
+#else
+ free_irq(pm8001_ha->irq, sha);
+#endif
+#ifdef PM8001_USE_TASKLET
+ tasklet_kill(&pm8001_ha->tasklet);
+#endif
+ pm8001_free(pm8001_ha);
+ kfree(sha->sas_phy);
+ kfree(sha->sas_port);
+ kfree(sha);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+}
+
+/**
+ * pm8001_pci_suspend - power management suspend main entry point
+ * @pdev: PCI device struct
+ * @state: PM state change to (usually PCI_D3)
+ *
+ * Returns 0 success, anything else error.
+ */
+static int pm8001_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct sas_ha_struct *sha = pci_get_drvdata(pdev);
+ struct pm8001_hba_info *pm8001_ha;
+ int i , pos;
+ u32 device_state;
+ pm8001_ha = sha->lldd_ha;
+ flush_scheduled_work();
+ scsi_block_requests(pm8001_ha->shost);
+ pos = pci_find_capability(pdev, PCI_CAP_ID_PM);
+ if (pos == 0) {
+ printk(KERN_ERR " PCI PM not supported\n");
+ return -ENODEV;
+ }
+ PM8001_CHIP_DISP->interrupt_disable(pm8001_ha);
+ PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha, 0x252acbcd);
+#ifdef PM8001_USE_MSIX
+ for (i = 0; i < pm8001_ha->number_of_intr; i++)
+ synchronize_irq(pm8001_ha->msix_entries[i].vector);
+ for (i = 0; i < pm8001_ha->number_of_intr; i++)
+ free_irq(pm8001_ha->msix_entries[i].vector, sha);
+ pci_disable_msix(pdev);
+#else
+ free_irq(pm8001_ha->irq, sha);
+#endif
+#ifdef PM8001_USE_TASKLET
+ tasklet_kill(&pm8001_ha->tasklet);
+#endif
+ device_state = pci_choose_state(pdev, state);
+ pm8001_printk("pdev=0x%p, slot=%s, entering "
+ "operating state [D%d]\n", pdev,
+ pm8001_ha->name, device_state);
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, device_state);
+ return 0;
+}
+
+/**
+ * pm8001_pci_resume - power management resume main entry point
+ * @pdev: PCI device struct
+ *
+ * Returns 0 success, anything else error.
+ */
+static int pm8001_pci_resume(struct pci_dev *pdev)
+{
+ struct sas_ha_struct *sha = pci_get_drvdata(pdev);
+ struct pm8001_hba_info *pm8001_ha;
+ int rc;
+ u32 device_state;
+ pm8001_ha = sha->lldd_ha;
+ device_state = pdev->current_state;
+
+ pm8001_printk("pdev=0x%p, slot=%s, resuming from previous "
+ "operating state [D%d]\n", pdev, pm8001_ha->name, device_state);
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_enable_wake(pdev, PCI_D0, 0);
+ pci_restore_state(pdev);
+ rc = pci_enable_device(pdev);
+ if (rc) {
+ pm8001_printk("slot=%s Enable device failed during resume\n",
+ pm8001_ha->name);
+ goto err_out_enable;
+ }
+
+ pci_set_master(pdev);
+ rc = pci_go_44(pdev);
+ if (rc)
+ goto err_out_disable;
+
+ PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha, 0x252acbcd);
+ rc = PM8001_CHIP_DISP->chip_init(pm8001_ha);
+ if (rc)
+ goto err_out_disable;
+ PM8001_CHIP_DISP->interrupt_disable(pm8001_ha);
+ rc = pm8001_request_irq(pm8001_ha);
+ if (rc)
+ goto err_out_disable;
+ #ifdef PM8001_USE_TASKLET
+ tasklet_init(&pm8001_ha->tasklet, pm8001_tasklet,
+ (unsigned long)pm8001_ha);
+ #endif
+ PM8001_CHIP_DISP->interrupt_enable(pm8001_ha);
+ scsi_unblock_requests(pm8001_ha->shost);
+ return 0;
+
+err_out_disable:
+ scsi_remove_host(pm8001_ha->shost);
+ pci_disable_device(pdev);
+err_out_enable:
+ return rc;
+}
+
+static struct pci_device_id __devinitdata pm8001_pci_table[] = {
+ {
+ PCI_VDEVICE(PMC_Sierra, 0x8001), chip_8001
+ },
+ {
+ PCI_DEVICE(0x117c, 0x0042),
+ .driver_data = chip_8001
+ },
+ {} /* terminate list */
+};
+
+static struct pci_driver pm8001_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = pm8001_pci_table,
+ .probe = pm8001_pci_probe,
+ .remove = __devexit_p(pm8001_pci_remove),
+ .suspend = pm8001_pci_suspend,
+ .resume = pm8001_pci_resume,
+};
+
+/**
+ * pm8001_init - initialize scsi transport template
+ */
+static int __init pm8001_init(void)
+{
+ int rc;
+ pm8001_id = 0;
+ pm8001_stt = sas_domain_attach_transport(&pm8001_transport_ops);
+ if (!pm8001_stt)
+ return -ENOMEM;
+ rc = pci_register_driver(&pm8001_pci_driver);
+ if (rc)
+ goto err_out;
+ return 0;
+err_out:
+ sas_release_transport(pm8001_stt);
+ return rc;
+}
+
+static void __exit pm8001_exit(void)
+{
+ pci_unregister_driver(&pm8001_pci_driver);
+ sas_release_transport(pm8001_stt);
+}
+
+module_init(pm8001_init);
+module_exit(pm8001_exit);
+
+MODULE_AUTHOR("Jack Wang <jack_wang@usish.com>");
+MODULE_DESCRIPTION("PMC-Sierra PM8001 SAS/SATA controller driver");
+MODULE_VERSION(DRV_VERSION);
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, pm8001_pci_table);
+
diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c
new file mode 100644
index 0000000..1f767a0
--- /dev/null
+++ b/drivers/scsi/pm8001/pm8001_sas.c
@@ -0,0 +1,1103 @@
+/*
+ * PMC-Sierra SPC 8001 SAS/SATA based host adapters driver
+ *
+ * Copyright (c) 2008-2009 USI Co., Ltd.
+ * 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 at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ *
+ */
+
+#include "pm8001_sas.h"
+
+/**
+ * pm8001_find_tag - from sas task to find out tag that belongs to this task
+ * @task: the task sent to the LLDD
+ * @tag: the found tag associated with the task
+ */
+static int pm8001_find_tag(struct sas_task *task, u32 *tag)
+{
+ if (task->lldd_task) {
+ struct pm8001_ccb_info *ccb;
+ ccb = task->lldd_task;
+ *tag = ccb->ccb_tag;
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * pm8001_tag_clear - clear the tags bitmap
+ * @pm8001_ha: our hba struct
+ * @tag: the found tag associated with the task
+ */
+static void pm8001_tag_clear(struct pm8001_hba_info *pm8001_ha, u32 tag)
+{
+ void *bitmap = pm8001_ha->tags;
+ clear_bit(tag, bitmap);
+}
+
+static void pm8001_tag_free(struct pm8001_hba_info *pm8001_ha, u32 tag)
+{
+ pm8001_tag_clear(pm8001_ha, tag);
+}
+
+static void pm8001_tag_set(struct pm8001_hba_info *pm8001_ha, u32 tag)
+{
+ void *bitmap = pm8001_ha->tags;
+ set_bit(tag, bitmap);
+}
+
+/**
+ * pm8001_tag_alloc - allocate a empty tag for task used.
+ * @pm8001_ha: our hba struct
+ * @tag_out: the found empty tag .
+ */
+inline int pm8001_tag_alloc(struct pm8001_hba_info *pm8001_ha, u32 *tag_out)
+{
+ unsigned int index, tag;
+ void *bitmap = pm8001_ha->tags;
+
+ index = find_first_zero_bit(bitmap, pm8001_ha->tags_num);
+ tag = index;
+ if (tag >= pm8001_ha->tags_num)
+ return -SAS_QUEUE_FULL;
+ pm8001_tag_set(pm8001_ha, tag);
+ *tag_out = tag;
+ return 0;
+}
+
+void pm8001_tag_init(struct pm8001_hba_info *pm8001_ha)
+{
+ int i;
+ for (i = 0; i < pm8001_ha->tags_num; ++i)
+ pm8001_tag_clear(pm8001_ha, i);
+}
+
+ /**
+ * pm8001_mem_alloc - allocate memory for pm8001.
+ * @pdev: pci device.
+ * @virt_addr: the allocated virtual address
+ * @pphys_addr_hi: the physical address high byte address.
+ * @pphys_addr_lo: the physical address low byte address.
+ * @mem_size: memory size.
+ */
+int pm8001_mem_alloc(struct pci_dev *pdev, void **virt_addr,
+ dma_addr_t *pphys_addr, u32 *pphys_addr_hi,
+ u32 *pphys_addr_lo, u32 mem_size, u32 align)
+{
+ caddr_t mem_virt_alloc;
+ dma_addr_t mem_dma_handle;
+ u64 phys_align;
+ u64 align_offset = 0;
+ if (align)
+ align_offset = (dma_addr_t)align - 1;
+ mem_virt_alloc =
+ pci_alloc_consistent(pdev, mem_size + align, &mem_dma_handle);
+ if (!mem_virt_alloc) {
+ pm8001_printk("memory allocation error\n");
+ return -1;
+ }
+ memset((void *)mem_virt_alloc, 0, mem_size+align);
+ *pphys_addr = mem_dma_handle;
+ phys_align = (*pphys_addr + align_offset) & ~align_offset;
+ *virt_addr = (void *)mem_virt_alloc + phys_align - *pphys_addr;
+ *pphys_addr_hi = upper_32_bits(phys_align);
+ *pphys_addr_lo = lower_32_bits(phys_align);
+ return 0;
+}
+/**
+ * pm8001_find_ha_by_dev - from domain device which come from sas layer to
+ * find out our hba struct.
+ * @dev: the domain device which from sas layer.
+ */
+static
+struct pm8001_hba_info *pm8001_find_ha_by_dev(struct domain_device *dev)
+{
+ struct sas_ha_struct *sha = dev->port->ha;
+ struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
+ return pm8001_ha;
+}
+
+/**
+ * pm8001_phy_control - this function should be registered to
+ * sas_domain_function_template to provide libsas used, note: this is just
+ * control the HBA phy rather than other expander phy if you want control
+ * other phy, you should use SMP command.
+ * @sas_phy: which phy in HBA phys.
+ * @func: the operation.
+ * @funcdata: always NULL.
+ */
+int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
+ void *funcdata)
+{
+ int rc = 0, phy_id = sas_phy->id;
+ struct pm8001_hba_info *pm8001_ha = NULL;
+ struct sas_phy_linkrates *rates;
+ DECLARE_COMPLETION_ONSTACK(completion);
+ pm8001_ha = sas_phy->ha->lldd_ha;
+ pm8001_ha->phy[phy_id].enable_completion = &completion;
+ switch (func) {
+ case PHY_FUNC_SET_LINK_RATE:
+ rates = funcdata;
+ if (rates->minimum_linkrate) {
+ pm8001_ha->phy[phy_id].minimum_linkrate =
+ rates->minimum_linkrate;
+ }
+ if (rates->maximum_linkrate) {
+ pm8001_ha->phy[phy_id].maximum_linkrate =
+ rates->maximum_linkrate;
+ }
+ if (pm8001_ha->phy[phy_id].phy_state == 0) {
+ PM8001_CHIP_DISP->phy_start_req(pm8001_ha, phy_id);
+ wait_for_completion(&completion);
+ }
+ PM8001_CHIP_DISP->phy_ctl_req(pm8001_ha, phy_id,
+ PHY_LINK_RESET);
+ break;
+ case PHY_FUNC_HARD_RESET:
+ if (pm8001_ha->phy[phy_id].phy_state == 0) {
+ PM8001_CHIP_DISP->phy_start_req(pm8001_ha, phy_id);
+ wait_for_completion(&completion);
+ }
+ PM8001_CHIP_DISP->phy_ctl_req(pm8001_ha, phy_id,
+ PHY_HARD_RESET);
+ break;
+ case PHY_FUNC_LINK_RESET:
+ if (pm8001_ha->phy[phy_id].phy_state == 0) {
+ PM8001_CHIP_DISP->phy_start_req(pm8001_ha, phy_id);
+ wait_for_completion(&completion);
+ }
+ PM8001_CHIP_DISP->phy_ctl_req(pm8001_ha, phy_id,
+ PHY_LINK_RESET);
+ break;
+ case PHY_FUNC_RELEASE_SPINUP_HOLD:
+ PM8001_CHIP_DISP->phy_ctl_req(pm8001_ha, phy_id,
+ PHY_LINK_RESET);
+ break;
+ case PHY_FUNC_DISABLE:
+ PM8001_CHIP_DISP->phy_stop_req(pm8001_ha, phy_id);
+ break;
+ default:
+ rc = -EOPNOTSUPP;
+ }
+ msleep(300);
+ return rc;
+}
+
+int pm8001_slave_alloc(struct scsi_device *scsi_dev)
+{
+ struct domain_device *dev = sdev_to_domain_dev(scsi_dev);
+ if (dev_is_sata(dev)) {
+ /* We don't need to rescan targets
+ * if REPORT_LUNS request is failed
+ */
+ if (scsi_dev->lun > 0)
+ return -ENXIO;
+ scsi_dev->tagged_supported = 1;
+ }
+ return sas_slave_alloc(scsi_dev);
+}
+
+/**
+ * pm8001_scan_start - we should enable all HBA phys by sending the phy_start
+ * command to HBA.
+ * @shost: the scsi host data.
+ */
+void pm8001_scan_start(struct Scsi_Host *shost)
+{
+ int i;
+ struct pm8001_hba_info *pm8001_ha;
+ struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+ pm8001_ha = sha->lldd_ha;
+ PM8001_CHIP_DISP->sas_re_init_req(pm8001_ha);
+ for (i = 0; i < pm8001_ha->chip->n_phy; ++i)
+ PM8001_CHIP_DISP->phy_start_req(pm8001_ha, i);
+}
+
+int pm8001_scan_finished(struct Scsi_Host *shost, unsigned long time)
+{
+ /* give the phy enabling interrupt event time to come in (1s
+ * is empirically about all it takes) */
+ if (time < HZ)
+ return 0;
+ /* Wait for discovery to finish */
+ scsi_flush_work(shost);
+ return 1;
+}
+
+/**
+ * pm8001_task_prep_smp - the dispatcher function, prepare data for smp task
+ * @pm8001_ha: our hba card information
+ * @ccb: the ccb which attached to smp task
+ */
+static int pm8001_task_prep_smp(struct pm8001_hba_info *pm8001_ha,
+ struct pm8001_ccb_info *ccb)
+{
+ return PM8001_CHIP_DISP->smp_req(pm8001_ha, ccb);
+}
+
+u32 pm8001_get_ncq_tag(struct sas_task *task, u32 *tag)
+{
+ struct ata_queued_cmd *qc = task->uldd_task;
+ if (qc) {
+ if (qc->tf.command == ATA_CMD_FPDMA_WRITE ||
+ qc->tf.command == ATA_CMD_FPDMA_READ) {
+ *tag = qc->tag;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/**
+ * pm8001_task_prep_ata - the dispatcher function, prepare data for sata task
+ * @pm8001_ha: our hba card information
+ * @ccb: the ccb which attached to sata task
+ */
+static int pm8001_task_prep_ata(struct pm8001_hba_info *pm8001_ha,
+ struct pm8001_ccb_info *ccb)
+{
+ return PM8001_CHIP_DISP->sata_req(pm8001_ha, ccb);
+}
+
+/**
+ * pm8001_task_prep_ssp_tm - the dispatcher function, prepare task management data
+ * @pm8001_ha: our hba card information
+ * @ccb: the ccb which attached to TM
+ * @tmf: the task management IU
+ */
+static int pm8001_task_prep_ssp_tm(struct pm8001_hba_info *pm8001_ha,
+ struct pm8001_ccb_info *ccb, struct pm8001_tmf_task *tmf)
+{
+ return PM8001_CHIP_DISP->ssp_tm_req(pm8001_ha, ccb, tmf);
+}
+
+/**
+ * pm8001_task_prep_ssp - the dispatcher function,prepare ssp data for ssp task
+ * @pm8001_ha: our hba card information
+ * @ccb: the ccb which attached to ssp task
+ */
+static int pm8001_task_prep_ssp(struct pm8001_hba_info *pm8001_ha,
+ struct pm8001_ccb_info *ccb)
+{
+ return PM8001_CHIP_DISP->ssp_io_req(pm8001_ha, ccb);
+}
+int pm8001_slave_configure(struct scsi_device *sdev)
+{
+ struct domain_device *dev = sdev_to_domain_dev(sdev);
+ int ret = sas_slave_configure(sdev);
+ if (ret)
+ return ret;
+ if (dev_is_sata(dev)) {
+ #ifdef PM8001_DISABLE_NCQ
+ struct ata_port *ap = dev->sata_dev.ap;
+ struct ata_device *adev = ap->link.device;
+ adev->flags |= ATA_DFLAG_NCQ_OFF;
+ scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, 1);
+ #endif
+ }
+ return 0;
+}
+/**
+ * pm8001_task_exec - queue the task(ssp, smp && ata) to the hardware.
+ * @task: the task to be execute.
+ * @num: if can_queue great than 1, the task can be queued up. for SMP task,
+ * we always execute one one time.
+ * @gfp_flags: gfp_flags.
+ * @is_tmf: if it is task management task.
+ * @tmf: the task management IU
+ */
+#define DEV_IS_GONE(pm8001_dev) \
+ ((!pm8001_dev || (pm8001_dev->dev_type == NO_DEVICE)))
+static int pm8001_task_exec(struct sas_task *task, const int num,
+ gfp_t gfp_flags, int is_tmf, struct pm8001_tmf_task *tmf)
+{
+ struct domain_device *dev = task->dev;
+ struct pm8001_hba_info *pm8001_ha;
+ struct pm8001_device *pm8001_dev;
+ struct sas_task *t = task;
+ struct pm8001_ccb_info *ccb;
+ u32 tag = 0xdeadbeef, rc, n_elem = 0;
+ u32 n = num;
+ unsigned long flags = 0;
+
+ if (!dev->port) {
+ struct task_status_struct *tsm = &t->task_status;
+ tsm->resp = SAS_TASK_UNDELIVERED;
+ tsm->stat = SAS_PHY_DOWN;
+ if (dev->dev_type != SATA_DEV)
+ t->task_done(t);
+ return 0;
+ }
+ pm8001_ha = pm8001_find_ha_by_dev(task->dev);
+ PM8001_IO_DBG(pm8001_ha, pm8001_printk("pm8001_task_exec device \n "));
+ spin_lock_irqsave(&pm8001_ha->lock, flags);
+ do {
+ dev = t->dev;
+ pm8001_dev = dev->lldd_dev;
+ if (DEV_IS_GONE(pm8001_dev)) {
+ if (pm8001_dev) {
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("device %d not ready.\n",
+ pm8001_dev->device_id));
+ } else {
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("device %016llx not "
+ "ready.\n", SAS_ADDR(dev->sas_addr)));
+ }
+ rc = SAS_PHY_DOWN;
+ goto out_done;
+ }
+ rc = pm8001_tag_alloc(pm8001_ha, &tag);
+ if (rc)
+ goto err_out;
+ ccb = &pm8001_ha->ccb_info[tag];
+
+ if (!sas_protocol_ata(t->task_proto)) {
+ if (t->num_scatter) {
+ n_elem = dma_map_sg(pm8001_ha->dev,
+ t->scatter,
+ t->num_scatter,
+ t->data_dir);
+ if (!n_elem) {
+ rc = -ENOMEM;
+ goto err_out_tag;
+ }
+ }
+ } else {
+ n_elem = t->num_scatter;
+ }
+
+ t->lldd_task = ccb;
+ ccb->n_elem = n_elem;
+ ccb->ccb_tag = tag;
+ ccb->task = t;
+ switch (t->task_proto) {
+ case SAS_PROTOCOL_SMP:
+ rc = pm8001_task_prep_smp(pm8001_ha, ccb);
+ break;
+ case SAS_PROTOCOL_SSP:
+ if (is_tmf)
+ rc = pm8001_task_prep_ssp_tm(pm8001_ha,
+ ccb, tmf);
+ else
+ rc = pm8001_task_prep_ssp(pm8001_ha, ccb);
+ break;
+ case SAS_PROTOCOL_SATA:
+ case SAS_PROTOCOL_STP:
+ case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
+ rc = pm8001_task_prep_ata(pm8001_ha, ccb);
+ break;
+ default:
+ dev_printk(KERN_ERR, pm8001_ha->dev,
+ "unknown sas_task proto: 0x%x\n",
+ t->task_proto);
+ rc = -EINVAL;
+ break;
+ }
+
+ if (rc) {
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("rc is %x\n", rc));
+ goto err_out_tag;
+ }
+ /* TODO: select normal or high priority */
+ spin_lock(&t->task_state_lock);
+ t->task_state_flags |= SAS_TASK_AT_INITIATOR;
+ spin_unlock(&t->task_state_lock);
+ pm8001_dev->running_req++;
+ if (n > 1)
+ t = list_entry(t->list.next, struct sas_task, list);
+ } while (--n);
+ rc = 0;
+ goto out_done;
+
+err_out_tag:
+ pm8001_tag_free(pm8001_ha, tag);
+err_out:
+ dev_printk(KERN_ERR, pm8001_ha->dev, "pm8001 exec failed[%d]!\n", rc);
+ if (!sas_protocol_ata(t->task_proto))
+ if (n_elem)
+ dma_unmap_sg(pm8001_ha->dev, t->scatter, n_elem,
+ t->data_dir);
+out_done:
+ spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+ return rc;
+}
+
+/**
+ * pm8001_queue_command - register for upper layer used, all IO commands sent
+ * to HBA are from this interface.
+ * @task: the task to be execute.
+ * @num: if can_queue great than 1, the task can be queued up. for SMP task,
+ * we always execute one one time
+ * @gfp_flags: gfp_flags
+ */
+int pm8001_queue_command(struct sas_task *task, const int num,
+ gfp_t gfp_flags)
+{
+ return pm8001_task_exec(task, num, gfp_flags, 0, NULL);
+}
+
+void pm8001_ccb_free(struct pm8001_hba_info *pm8001_ha, u32 ccb_idx)
+{
+ pm8001_tag_clear(pm8001_ha, ccb_idx);
+}
+
+/**
+ * pm8001_ccb_task_free - free the sg for ssp and smp command, free the ccb.
+ * @pm8001_ha: our hba card information
+ * @ccb: the ccb which attached to ssp task
+ * @task: the task to be free.
+ * @ccb_idx: ccb index.
+ */
+void pm8001_ccb_task_free(struct pm8001_hba_info *pm8001_ha,
+ struct sas_task *task, struct pm8001_ccb_info *ccb, u32 ccb_idx)
+{
+ if (!ccb->task)
+ return;
+ if (!sas_protocol_ata(task->task_proto))
+ if (ccb->n_elem)
+ dma_unmap_sg(pm8001_ha->dev, task->scatter,
+ task->num_scatter, task->data_dir);
+
+ switch (task->task_proto) {
+ case SAS_PROTOCOL_SMP:
+ dma_unmap_sg(pm8001_ha->dev, &task->smp_task.smp_resp, 1,
+ PCI_DMA_FROMDEVICE);
+ dma_unmap_sg(pm8001_ha->dev, &task->smp_task.smp_req, 1,
+ PCI_DMA_TODEVICE);
+ break;
+
+ case SAS_PROTOCOL_SATA:
+ case SAS_PROTOCOL_STP:
+ case SAS_PROTOCOL_SSP:
+ default:
+ /* do nothing */
+ break;
+ }
+ task->lldd_task = NULL;
+ ccb->task = NULL;
+ ccb->ccb_tag = 0xFFFFFFFF;
+ pm8001_ccb_free(pm8001_ha, ccb_idx);
+}
+
+ /**
+ * pm8001_alloc_dev - find a empty pm8001_device
+ * @pm8001_ha: our hba card information
+ */
+struct pm8001_device *pm8001_alloc_dev(struct pm8001_hba_info *pm8001_ha)
+{
+ u32 dev;
+ for (dev = 0; dev < PM8001_MAX_DEVICES; dev++) {
+ if (pm8001_ha->devices[dev].dev_type == NO_DEVICE) {
+ pm8001_ha->devices[dev].id = dev;
+ return &pm8001_ha->devices[dev];
+ }
+ }
+ if (dev == PM8001_MAX_DEVICES) {
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("max support %d devices, ignore ..\n",
+ PM8001_MAX_DEVICES));
+ }
+ return NULL;
+}
+
+static void pm8001_free_dev(struct pm8001_device *pm8001_dev)
+{
+ u32 id = pm8001_dev->id;
+ memset(pm8001_dev, 0, sizeof(*pm8001_dev));
+ pm8001_dev->id = id;
+ pm8001_dev->dev_type = NO_DEVICE;
+ pm8001_dev->device_id = PM8001_MAX_DEVICES;
+ pm8001_dev->sas_device = NULL;
+}
+
+/**
+ * pm8001_dev_found_notify - libsas notify a device is found.
+ * @dev: the device structure which sas layer used.
+ *
+ * when libsas find a sas domain device, it should tell the LLDD that
+ * device is found, and then LLDD register this device to HBA firmware
+ * by the command "OPC_INB_REG_DEV", after that the HBA will assign a
+ * device ID(according to device's sas address) and returned it to LLDD. From
+ * now on, we communicate with HBA FW with the device ID which HBA assigned
+ * rather than sas address. it is the neccessary step for our HBA but it is
+ * the optional for other HBA driver.
+ */
+static int pm8001_dev_found_notify(struct domain_device *dev)
+{
+ unsigned long flags = 0;
+ int res = 0;
+ struct pm8001_hba_info *pm8001_ha = NULL;
+ struct domain_device *parent_dev = dev->parent;
+ struct pm8001_device *pm8001_device;
+ DECLARE_COMPLETION_ONSTACK(completion);
+ u32 flag = 0;
+ pm8001_ha = pm8001_find_ha_by_dev(dev);
+ spin_lock_irqsave(&pm8001_ha->lock, flags);
+
+ pm8001_device = pm8001_alloc_dev(pm8001_ha);
+ pm8001_device->sas_device = dev;
+ if (!pm8001_device) {
+ res = -1;
+ goto found_out;
+ }
+ dev->lldd_dev = pm8001_device;
+ pm8001_device->dev_type = dev->dev_type;
+ pm8001_device->dcompletion = &completion;
+ if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) {
+ int phy_id;
+ struct ex_phy *phy;
+ for (phy_id = 0; phy_id < parent_dev->ex_dev.num_phys;
+ phy_id++) {
+ phy = &parent_dev->ex_dev.ex_phy[phy_id];
+ if (SAS_ADDR(phy->attached_sas_addr)
+ == SAS_ADDR(dev->sas_addr)) {
+ pm8001_device->attached_phy = phy_id;
+ break;
+ }
+ }
+ if (phy_id == parent_dev->ex_dev.num_phys) {
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("Error: no attached dev:%016llx"
+ " at ex:%016llx.\n", SAS_ADDR(dev->sas_addr),
+ SAS_ADDR(parent_dev->sas_addr)));
+ res = -1;
+ }
+ } else {
+ if (dev->dev_type == SATA_DEV) {
+ pm8001_device->attached_phy =
+ dev->rphy->identify.phy_identifier;
+ flag = 1; /* directly sata*/
+ }
+ } /*register this device to HBA*/
+ PM8001_DISC_DBG(pm8001_ha, pm8001_printk("Found device \n"));
+ PM8001_CHIP_DISP->reg_dev_req(pm8001_ha, pm8001_device, flag);
+ spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+ wait_for_completion(&completion);
+ if (dev->dev_type == SAS_END_DEV)
+ msleep(50);
+ pm8001_ha->flags = PM8001F_RUN_TIME ;
+ return 0;
+found_out:
+ spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+ return res;
+}
+
+int pm8001_dev_found(struct domain_device *dev)
+{
+ return pm8001_dev_found_notify(dev);
+}
+
+/**
+ * pm8001_alloc_task - allocate a task structure for TMF
+ */
+static struct sas_task *pm8001_alloc_task(void)
+{
+ struct sas_task *task = kzalloc(sizeof(*task), GFP_KERNEL);
+ if (task) {
+ INIT_LIST_HEAD(&task->list);
+ spin_lock_init(&task->task_state_lock);
+ task->task_state_flags = SAS_TASK_STATE_PENDING;
+ init_timer(&task->timer);
+ init_completion(&task->completion);
+ }
+ return task;
+}
+
+static void pm8001_free_task(struct sas_task *task)
+{
+ if (task) {
+ BUG_ON(!list_empty(&task->list));
+ kfree(task);
+ }
+}
+
+static void pm8001_task_done(struct sas_task *task)
+{
+ if (!del_timer(&task->timer))
+ return;
+ complete(&task->completion);
+}
+
+static void pm8001_tmf_timedout(unsigned long data)
+{
+ struct sas_task *task = (struct sas_task *)data;
+
+ task->task_state_flags |= SAS_TASK_STATE_ABORTED;
+ complete(&task->completion);
+}
+
+#define PM8001_TASK_TIMEOUT 20
+/**
+ * pm8001_exec_internal_tmf_task - execute some task management commands.
+ * @dev: the wanted device.
+ * @tmf: which task management wanted to be take.
+ * @para_len: para_len.
+ * @parameter: ssp task parameter.
+ *
+ * when errors or exception happened, we may want to do something, for example
+ * abort the issued task which result in this execption, it is done by calling
+ * this function, note it is also with the task execute interface.
+ */
+static int pm8001_exec_internal_tmf_task(struct domain_device *dev,
+ void *parameter, u32 para_len, struct pm8001_tmf_task *tmf)
+{
+ int res, retry;
+ struct sas_task *task = NULL;
+ struct pm8001_hba_info *pm8001_ha = pm8001_find_ha_by_dev(dev);
+
+ for (retry = 0; retry < 3; retry++) {
+ task = pm8001_alloc_task();
+ if (!task)
+ return -ENOMEM;
+
+ task->dev = dev;
+ task->task_proto = dev->tproto;
+ memcpy(&task->ssp_task, parameter, para_len);
+ task->task_done = pm8001_task_done;
+ task->timer.data = (unsigned long)task;
+ task->timer.function = pm8001_tmf_timedout;
+ task->timer.expires = jiffies + PM8001_TASK_TIMEOUT*HZ;
+ add_timer(&task->timer);
+
+ res = pm8001_task_exec(task, 1, GFP_KERNEL, 1, tmf);
+
+ if (res) {
+ del_timer(&task->timer);
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("Executing internal task "
+ "failed\n"));
+ goto ex_err;
+ }
+ wait_for_completion(&task->completion);
+ res = -TMF_RESP_FUNC_FAILED;
+ /* Even TMF timed out, return direct. */
+ if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
+ if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("TMF task[%x]timeout.\n",
+ tmf->tmf));
+ goto ex_err;
+ }
+ }
+
+ if (task->task_status.resp == SAS_TASK_COMPLETE &&
+ task->task_status.stat == SAM_GOOD) {
+ res = TMF_RESP_FUNC_COMPLETE;
+ break;
+ }
+
+ if (task->task_status.resp == SAS_TASK_COMPLETE &&
+ task->task_status.stat == SAS_DATA_UNDERRUN) {
+ /* no error, but return the number of bytes of
+ * underrun */
+ res = task->task_status.residual;
+ break;
+ }
+
+ if (task->task_status.resp == SAS_TASK_COMPLETE &&
+ task->task_status.stat == SAS_DATA_OVERRUN) {
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("Blocked task error.\n"));
+ res = -EMSGSIZE;
+ break;
+ } else {
+ PM8001_EH_DBG(pm8001_ha,
+ pm8001_printk(" Task to dev %016llx response:"
+ "0x%x status 0x%x\n",
+ SAS_ADDR(dev->sas_addr),
+ task->task_status.resp,
+ task->task_status.stat));
+ pm8001_free_task(task);
+ task = NULL;
+ }
+ }
+ex_err:
+ BUG_ON(retry == 3 && task != NULL);
+ if (task != NULL)
+ pm8001_free_task(task);
+ return res;
+}
+
+static int
+pm8001_exec_internal_task_abort(struct pm8001_hba_info *pm8001_ha,
+ struct pm8001_device *pm8001_dev, struct domain_device *dev, u32 flag,
+ u32 task_tag)
+{
+ int res, retry;
+ u32 ccb_tag;
+ struct pm8001_ccb_info *ccb;
+ struct sas_task *task = NULL;
+
+ for (retry = 0; retry < 3; retry++) {
+ task = pm8001_alloc_task();
+ if (!task)
+ return -ENOMEM;
+
+ task->dev = dev;
+ task->task_proto = dev->tproto;
+ task->task_done = pm8001_task_done;
+ task->timer.data = (unsigned long)task;
+ task->timer.function = pm8001_tmf_timedout;
+ task->timer.expires = jiffies + PM8001_TASK_TIMEOUT*HZ;
+ add_timer(&task->timer);
+
+ res = pm8001_tag_alloc(pm8001_ha, &ccb_tag);
+ if (res)
+ return res;
+ ccb = &pm8001_ha->ccb_info[ccb_tag];
+ ccb->device = pm8001_dev;
+ ccb->ccb_tag = ccb_tag;
+ ccb->task = task;
+
+ res = PM8001_CHIP_DISP->task_abort(pm8001_ha,
+ pm8001_dev, flag, task_tag, ccb_tag);
+
+ if (res) {
+ del_timer(&task->timer);
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("Executing internal task "
+ "failed\n"));
+ goto ex_err;
+ }
+ wait_for_completion(&task->completion);
+ res = TMF_RESP_FUNC_FAILED;
+ /* Even TMF timed out, return direct. */
+ if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
+ if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("TMF task timeout.\n"));
+ goto ex_err;
+ }
+ }
+
+ if (task->task_status.resp == SAS_TASK_COMPLETE &&
+ task->task_status.stat == SAM_GOOD) {
+ res = TMF_RESP_FUNC_COMPLETE;
+ break;
+
+ } else {
+ PM8001_EH_DBG(pm8001_ha,
+ pm8001_printk(" Task to dev %016llx response: "
+ "0x%x status 0x%x\n",
+ SAS_ADDR(dev->sas_addr),
+ task->task_status.resp,
+ task->task_status.stat));
+ pm8001_free_task(task);
+ task = NULL;
+ }
+ }
+ex_err:
+ BUG_ON(retry == 3 && task != NULL);
+ if (task != NULL)
+ pm8001_free_task(task);
+ return res;
+}
+
+/**
+ * pm8001_dev_gone_notify - see the comments for "pm8001_dev_found_notify"
+ * @dev: the device structure which sas layer used.
+ */
+static void pm8001_dev_gone_notify(struct domain_device *dev)
+{
+ unsigned long flags = 0;
+ u32 tag;
+ struct pm8001_hba_info *pm8001_ha;
+ struct pm8001_device *pm8001_dev = dev->lldd_dev;
+ u32 device_id = pm8001_dev->device_id;
+ pm8001_ha = pm8001_find_ha_by_dev(dev);
+ spin_lock_irqsave(&pm8001_ha->lock, flags);
+ pm8001_tag_alloc(pm8001_ha, &tag);
+ if (pm8001_dev) {
+ PM8001_DISC_DBG(pm8001_ha,
+ pm8001_printk("found dev[%d:%x] is gone.\n",
+ pm8001_dev->device_id, pm8001_dev->dev_type));
+ if (pm8001_dev->running_req) {
+ spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+ pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev ,
+ dev, 1, 0);
+ spin_lock_irqsave(&pm8001_ha->lock, flags);
+ }
+ PM8001_CHIP_DISP->dereg_dev_req(pm8001_ha, device_id);
+ pm8001_free_dev(pm8001_dev);
+ } else {
+ PM8001_DISC_DBG(pm8001_ha,
+ pm8001_printk("Found dev has gone.\n"));
+ }
+ dev->lldd_dev = NULL;
+ spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+}
+
+void pm8001_dev_gone(struct domain_device *dev)
+{
+ pm8001_dev_gone_notify(dev);
+}
+
+static int pm8001_issue_ssp_tmf(struct domain_device *dev,
+ u8 *lun, struct pm8001_tmf_task *tmf)
+{
+ struct sas_ssp_task ssp_task;
+ if (!(dev->tproto & SAS_PROTOCOL_SSP))
+ return TMF_RESP_FUNC_ESUPP;
+
+ strncpy((u8 *)&ssp_task.LUN, lun, 8);
+ return pm8001_exec_internal_tmf_task(dev, &ssp_task, sizeof(ssp_task),
+ tmf);
+}
+
+/**
+ * Standard mandates link reset for ATA (type 0) and hard reset for
+ * SSP (type 1) , only for RECOVERY
+ */
+int pm8001_I_T_nexus_reset(struct domain_device *dev)
+{
+ int rc = TMF_RESP_FUNC_FAILED;
+ struct pm8001_device *pm8001_dev;
+ struct pm8001_hba_info *pm8001_ha;
+ struct sas_phy *phy;
+ if (!dev || !dev->lldd_dev)
+ return -1;
+
+ pm8001_dev = dev->lldd_dev;
+ pm8001_ha = pm8001_find_ha_by_dev(dev);
+ phy = sas_find_local_phy(dev);
+
+ if (dev_is_sata(dev)) {
+ DECLARE_COMPLETION_ONSTACK(completion_setstate);
+ rc = sas_phy_reset(phy, 1);
+ msleep(2000);
+ rc = pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev ,
+ dev, 1, 0);
+ pm8001_dev->setds_completion = &completion_setstate;
+ rc = PM8001_CHIP_DISP->set_dev_state_req(pm8001_ha,
+ pm8001_dev, 0x01);
+ wait_for_completion(&completion_setstate);
+ } else{
+ rc = sas_phy_reset(phy, 1);
+ msleep(2000);
+ }
+ PM8001_EH_DBG(pm8001_ha, pm8001_printk(" for device[%x]:rc=%d\n",
+ pm8001_dev->device_id, rc));
+ return rc;
+}
+
+/* mandatory SAM-3, the task reset the specified LUN*/
+int pm8001_lu_reset(struct domain_device *dev, u8 *lun)
+{
+ int rc = TMF_RESP_FUNC_FAILED;
+ struct pm8001_tmf_task tmf_task;
+ struct pm8001_device *pm8001_dev = dev->lldd_dev;
+ struct pm8001_hba_info *pm8001_ha = pm8001_find_ha_by_dev(dev);
+ if (dev_is_sata(dev)) {
+ struct sas_phy *phy = sas_find_local_phy(dev);
+ rc = pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev ,
+ dev, 1, 0);
+ rc = sas_phy_reset(phy, 1);
+ rc = PM8001_CHIP_DISP->set_dev_state_req(pm8001_ha,
+ pm8001_dev, 0x01);
+ msleep(2000);
+ } else {
+ tmf_task.tmf = TMF_LU_RESET;
+ rc = pm8001_issue_ssp_tmf(dev, lun, &tmf_task);
+ }
+ /* If failed, fall-through I_T_Nexus reset */
+ PM8001_EH_DBG(pm8001_ha, pm8001_printk("for device[%x]:rc=%d\n",
+ pm8001_dev->device_id, rc));
+ return rc;
+}
+
+/* optional SAM-3 */
+int pm8001_query_task(struct sas_task *task)
+{
+ u32 tag = 0xdeadbeef;
+ int i = 0;
+ struct scsi_lun lun;
+ struct pm8001_tmf_task tmf_task;
+ int rc = TMF_RESP_FUNC_FAILED;
+ if (unlikely(!task || !task->lldd_task || !task->dev))
+ return rc;
+
+ if (task->task_proto & SAS_PROTOCOL_SSP) {
+ struct scsi_cmnd *cmnd = task->uldd_task;
+ struct domain_device *dev = task->dev;
+ struct pm8001_hba_info *pm8001_ha =
+ pm8001_find_ha_by_dev(dev);
+
+ int_to_scsilun(cmnd->device->lun, &lun);
+ rc = pm8001_find_tag(task, &tag);
+ if (rc == 0) {
+ rc = TMF_RESP_FUNC_FAILED;
+ return rc;
+ }
+ PM8001_EH_DBG(pm8001_ha, pm8001_printk("Query:["));
+ for (i = 0; i < 16; i++)
+ printk(KERN_INFO "%02x ", cmnd->cmnd[i]);
+ printk(KERN_INFO "]\n");
+ tmf_task.tmf = TMF_QUERY_TASK;
+ tmf_task.tag_of_task_to_be_managed = tag;
+
+ rc = pm8001_issue_ssp_tmf(dev, lun.scsi_lun, &tmf_task);
+ switch (rc) {
+ /* The task is still in Lun, release it then */
+ case TMF_RESP_FUNC_SUCC:
+ PM8001_EH_DBG(pm8001_ha,
+ pm8001_printk("The task is still in Lun \n"));
+ /* The task is not in Lun or failed, reset the phy */
+ case TMF_RESP_FUNC_FAILED:
+ case TMF_RESP_FUNC_COMPLETE:
+ PM8001_EH_DBG(pm8001_ha,
+ pm8001_printk("The task is not in Lun or failed,"
+ " reset the phy \n"));
+ break;
+ }
+ }
+ pm8001_printk(":rc= %d\n", rc);
+ return rc;
+}
+
+/* mandatory SAM-3, still need free task/ccb info, abord the specified task */
+int pm8001_abort_task(struct sas_task *task)
+{
+ unsigned long flags;
+ u32 tag = 0xdeadbeef;
+ u32 device_id;
+ struct domain_device *dev ;
+ struct pm8001_hba_info *pm8001_ha = NULL;
+ struct pm8001_ccb_info *ccb;
+ struct scsi_lun lun;
+ struct pm8001_device *pm8001_dev;
+ struct pm8001_tmf_task tmf_task;
+ int rc = TMF_RESP_FUNC_FAILED;
+ if (unlikely(!task || !task->lldd_task || !task->dev))
+ return rc;
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ if (task->task_state_flags & SAS_TASK_STATE_DONE) {
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+ rc = TMF_RESP_FUNC_COMPLETE;
+ goto out;
+ }
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+ if (task->task_proto & SAS_PROTOCOL_SSP) {
+ struct scsi_cmnd *cmnd = task->uldd_task;
+ dev = task->dev;
+ ccb = task->lldd_task;
+ pm8001_dev = dev->lldd_dev;
+ pm8001_ha = pm8001_find_ha_by_dev(dev);
+ int_to_scsilun(cmnd->device->lun, &lun);
+ rc = pm8001_find_tag(task, &tag);
+ if (rc == 0) {
+ printk(KERN_INFO "No such tag in %s\n", __func__);
+ rc = TMF_RESP_FUNC_FAILED;
+ return rc;
+ }
+ device_id = pm8001_dev->device_id;
+ PM8001_EH_DBG(pm8001_ha,
+ pm8001_printk("abort io to deviceid= %d\n", device_id));
+ tmf_task.tmf = TMF_ABORT_TASK;
+ tmf_task.tag_of_task_to_be_managed = tag;
+ rc = pm8001_issue_ssp_tmf(dev, lun.scsi_lun, &tmf_task);
+ pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev,
+ pm8001_dev->sas_device, 0, tag);
+ } else if (task->task_proto & SAS_PROTOCOL_SATA ||
+ task->task_proto & SAS_PROTOCOL_STP) {
+ dev = task->dev;
+ pm8001_dev = dev->lldd_dev;
+ pm8001_ha = pm8001_find_ha_by_dev(dev);
+ rc = pm8001_find_tag(task, &tag);
+ if (rc == 0) {
+ printk(KERN_INFO "No such tag in %s\n", __func__);
+ rc = TMF_RESP_FUNC_FAILED;
+ return rc;
+ }
+ rc = pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev,
+ pm8001_dev->sas_device, 0, tag);
+ } else if (task->task_proto & SAS_PROTOCOL_SMP) {
+ /* SMP */
+ dev = task->dev;
+ pm8001_dev = dev->lldd_dev;
+ pm8001_ha = pm8001_find_ha_by_dev(dev);
+ rc = pm8001_find_tag(task, &tag);
+ if (rc == 0) {
+ printk(KERN_INFO "No such tag in %s\n", __func__);
+ rc = TMF_RESP_FUNC_FAILED;
+ return rc;
+ }
+ rc = pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev,
+ pm8001_dev->sas_device, 0, tag);
+
+ }
+out:
+ if (rc != TMF_RESP_FUNC_COMPLETE)
+ pm8001_printk("rc= %d\n", rc);
+ return rc;
+}
+
+int pm8001_abort_task_set(struct domain_device *dev, u8 *lun)
+{
+ int rc = TMF_RESP_FUNC_FAILED;
+ struct pm8001_tmf_task tmf_task;
+
+ tmf_task.tmf = TMF_ABORT_TASK_SET;
+ rc = pm8001_issue_ssp_tmf(dev, lun, &tmf_task);
+ return rc;
+}
+
+int pm8001_clear_aca(struct domain_device *dev, u8 *lun)
+{
+ int rc = TMF_RESP_FUNC_FAILED;
+ struct pm8001_tmf_task tmf_task;
+
+ tmf_task.tmf = TMF_CLEAR_ACA;
+ rc = pm8001_issue_ssp_tmf(dev, lun, &tmf_task);
+
+ return rc;
+}
+
+int pm8001_clear_task_set(struct domain_device *dev, u8 *lun)
+{
+ int rc = TMF_RESP_FUNC_FAILED;
+ struct pm8001_tmf_task tmf_task;
+ struct pm8001_device *pm8001_dev = dev->lldd_dev;
+ struct pm8001_hba_info *pm8001_ha = pm8001_find_ha_by_dev(dev);
+
+ PM8001_EH_DBG(pm8001_ha,
+ pm8001_printk("I_T_L_Q clear task set[%x]\n",
+ pm8001_dev->device_id));
+ tmf_task.tmf = TMF_CLEAR_TASK_SET;
+ rc = pm8001_issue_ssp_tmf(dev, lun, &tmf_task);
+ return rc;
+}
+
diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h
new file mode 100644
index 0000000..30f2ede
--- /dev/null
+++ b/drivers/scsi/pm8001/pm8001_sas.h
@@ -0,0 +1,481 @@
+/*
+ * PMC-Sierra SPC 8001 SAS/SATA based host adapters driver
+ *
+ * Copyright (c) 2008-2009 USI Co., Ltd.
+ * 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 at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ *
+ */
+
+#ifndef _PM8001_SAS_H_
+#define _PM8001_SAS_H_
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/ctype.h>
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/smp_lock.h>
+#include <scsi/libsas.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/sas_ata.h>
+#include <asm/atomic.h>
+#include "pm8001_defs.h"
+
+#define DRV_NAME "pm8001"
+#define DRV_VERSION "0.1.36"
+#define PM8001_FAIL_LOGGING 0x01 /* libsas EH function logging */
+#define PM8001_INIT_LOGGING 0x02 /* driver init logging */
+#define PM8001_DISC_LOGGING 0x04 /* discovery layer logging */
+#define PM8001_IO_LOGGING 0x08 /* I/O path logging */
+#define PM8001_EH_LOGGING 0x10 /* Error message logging */
+#define PM8001_IOCTL_LOGGING 0x20 /* IOCTL message logging */
+#define PM8001_MSG_LOGGING 0x40 /* misc message logging */
+#define pm8001_printk(format, arg...) printk(KERN_INFO "%s %d:" format,\
+ __func__, __LINE__, ## arg)
+#define PM8001_CHECK_LOGGING(HBA, LEVEL, CMD) \
+do { \
+ if (unlikely(HBA->logging_level & LEVEL)) \
+ do { \
+ CMD; \
+ } while (0); \
+} while (0);
+
+#define PM8001_EH_DBG(HBA, CMD) \
+ PM8001_CHECK_LOGGING(HBA, PM8001_EH_LOGGING, CMD)
+
+#define PM8001_INIT_DBG(HBA, CMD) \
+ PM8001_CHECK_LOGGING(HBA, PM8001_INIT_LOGGING, CMD)
+
+#define PM8001_DISC_DBG(HBA, CMD) \
+ PM8001_CHECK_LOGGING(HBA, PM8001_DISC_LOGGING, CMD)
+
+#define PM8001_IO_DBG(HBA, CMD) \
+ PM8001_CHECK_LOGGING(HBA, PM8001_IO_LOGGING, CMD)
+
+#define PM8001_FAIL_DBG(HBA, CMD) \
+ PM8001_CHECK_LOGGING(HBA, PM8001_FAIL_LOGGING, CMD)
+
+#define PM8001_IOCTL_DBG(HBA, CMD) \
+ PM8001_CHECK_LOGGING(HBA, PM8001_IOCTL_LOGGING, CMD)
+
+#define PM8001_MSG_DBG(HBA, CMD) \
+ PM8001_CHECK_LOGGING(HBA, PM8001_MSG_LOGGING, CMD)
+
+
+#define PM8001_USE_TASKLET
+#define PM8001_USE_MSIX
+
+
+#define DEV_IS_EXPANDER(type) ((type == EDGE_DEV) || (type == FANOUT_DEV))
+
+#define PM8001_NAME_LENGTH 32/* generic length of strings */
+extern struct list_head hba_list;
+extern const struct pm8001_dispatch pm8001_8001_dispatch;
+
+struct pm8001_hba_info;
+struct pm8001_ccb_info;
+struct pm8001_device;
+struct pm8001_tmf_task;
+struct pm8001_dispatch {
+ char *name;
+ int (*chip_init)(struct pm8001_hba_info *pm8001_ha);
+ int (*chip_soft_rst)(struct pm8001_hba_info *pm8001_ha, u32 signature);
+ void (*chip_rst)(struct pm8001_hba_info *pm8001_ha);
+ int (*chip_ioremap)(struct pm8001_hba_info *pm8001_ha);
+ void (*chip_iounmap)(struct pm8001_hba_info *pm8001_ha);
+ irqreturn_t (*isr)(struct pm8001_hba_info *pm8001_ha);
+ u32 (*is_our_interupt)(struct pm8001_hba_info *pm8001_ha);
+ int (*isr_process_oq)(struct pm8001_hba_info *pm8001_ha);
+ void (*interrupt_enable)(struct pm8001_hba_info *pm8001_ha);
+ void (*interrupt_disable)(struct pm8001_hba_info *pm8001_ha);
+ void (*make_prd)(struct scatterlist *scatter, int nr, void *prd);
+ int (*smp_req)(struct pm8001_hba_info *pm8001_ha,
+ struct pm8001_ccb_info *ccb);
+ int (*ssp_io_req)(struct pm8001_hba_info *pm8001_ha,
+ struct pm8001_ccb_info *ccb);
+ int (*sata_req)(struct pm8001_hba_info *pm8001_ha,
+ struct pm8001_ccb_info *ccb);
+ int (*phy_start_req)(struct pm8001_hba_info *pm8001_ha, u8 phy_id);
+ int (*phy_stop_req)(struct pm8001_hba_info *pm8001_ha, u8 phy_id);
+ int (*reg_dev_req)(struct pm8001_hba_info *pm8001_ha,
+ struct pm8001_device *pm8001_dev, u32 flag);
+ int (*dereg_dev_req)(struct pm8001_hba_info *pm8001_ha, u32 device_id);
+ int (*phy_ctl_req)(struct pm8001_hba_info *pm8001_ha,
+ u32 phy_id, u32 phy_op);
+ int (*task_abort)(struct pm8001_hba_info *pm8001_ha,
+ struct pm8001_device *pm8001_dev, u8 flag, u32 task_tag,
+ u32 cmd_tag);
+ int (*ssp_tm_req)(struct pm8001_hba_info *pm8001_ha,
+ struct pm8001_ccb_info *ccb, struct pm8001_tmf_task *tmf);
+ int (*get_nvmd_req)(struct pm8001_hba_info *pm8001_ha, void *payload);
+ int (*set_nvmd_req)(struct pm8001_hba_info *pm8001_ha, void *payload);
+ int (*fw_flash_update_req)(struct pm8001_hba_info *pm8001_ha,
+ void *payload);
+ int (*set_dev_state_req)(struct pm8001_hba_info *pm8001_ha,
+ struct pm8001_device *pm8001_dev, u32 state);
+ int (*sas_diag_start_end_req)(struct pm8001_hba_info *pm8001_ha,
+ u32 state);
+ int (*sas_diag_execute_req)(struct pm8001_hba_info *pm8001_ha,
+ u32 state);
+ int (*sas_re_init_req)(struct pm8001_hba_info *pm8001_ha);
+};
+
+struct pm8001_chip_info {
+ u32 n_phy;
+ const struct pm8001_dispatch *dispatch;
+};
+#define PM8001_CHIP_DISP (pm8001_ha->chip->dispatch)
+
+struct pm8001_port {
+ struct asd_sas_port sas_port;
+};
+
+struct pm8001_phy {
+ struct pm8001_hba_info *pm8001_ha;
+ struct pm8001_port *port;
+ struct asd_sas_phy sas_phy;
+ struct sas_identify identify;
+ struct scsi_device *sdev;
+ u64 dev_sas_addr;
+ u32 phy_type;
+ struct completion *enable_completion;
+ u32 frame_rcvd_size;
+ u8 frame_rcvd[32];
+ u8 phy_attached;
+ u8 phy_state;
+ enum sas_linkrate minimum_linkrate;
+ enum sas_linkrate maximum_linkrate;
+};
+
+struct pm8001_device {
+ enum sas_dev_type dev_type;
+ struct domain_device *sas_device;
+ u32 attached_phy;
+ u32 id;
+ struct completion *dcompletion;
+ struct completion *setds_completion;
+ u32 device_id;
+ u32 running_req;
+};
+
+struct pm8001_prd_imt {
+ __le32 len;
+ __le32 e;
+};
+
+struct pm8001_prd {
+ __le64 addr; /* 64-bit buffer address */
+ struct pm8001_prd_imt im_len; /* 64-bit length */
+} __attribute__ ((packed));
+/*
+ * CCB(Command Control Block)
+ */
+struct pm8001_ccb_info {
+ struct list_head entry;
+ struct sas_task *task;
+ u32 n_elem;
+ u32 ccb_tag;
+ dma_addr_t ccb_dma_handle;
+ struct pm8001_device *device;
+ struct pm8001_prd buf_prd[PM8001_MAX_DMA_SG];
+ struct fw_control_ex *fw_control_context;
+};
+
+struct mpi_mem {
+ void *virt_ptr;
+ dma_addr_t phys_addr;
+ u32 phys_addr_hi;
+ u32 phys_addr_lo;
+ u32 total_len;
+ u32 num_elements;
+ u32 element_size;
+ u32 alignment;
+};
+
+struct mpi_mem_req {
+ /* The number of element in the mpiMemory array */
+ u32 count;
+ /* The array of structures that define memroy regions*/
+ struct mpi_mem region[USI_MAX_MEMCNT];
+};
+
+struct main_cfg_table {
+ u32 signature;
+ u32 interface_rev;
+ u32 firmware_rev;
+ u32 max_out_io;
+ u32 max_sgl;
+ u32 ctrl_cap_flag;
+ u32 gst_offset;
+ u32 inbound_queue_offset;
+ u32 outbound_queue_offset;
+ u32 inbound_q_nppd_hppd;
+ u32 outbound_hw_event_pid0_3;
+ u32 outbound_hw_event_pid4_7;
+ u32 outbound_ncq_event_pid0_3;
+ u32 outbound_ncq_event_pid4_7;
+ u32 outbound_tgt_ITNexus_event_pid0_3;
+ u32 outbound_tgt_ITNexus_event_pid4_7;
+ u32 outbound_tgt_ssp_event_pid0_3;
+ u32 outbound_tgt_ssp_event_pid4_7;
+ u32 outbound_tgt_smp_event_pid0_3;
+ u32 outbound_tgt_smp_event_pid4_7;
+ u32 upper_event_log_addr;
+ u32 lower_event_log_addr;
+ u32 event_log_size;
+ u32 event_log_option;
+ u32 upper_iop_event_log_addr;
+ u32 lower_iop_event_log_addr;
+ u32 iop_event_log_size;
+ u32 iop_event_log_option;
+ u32 fatal_err_interrupt;
+ u32 fatal_err_dump_offset0;
+ u32 fatal_err_dump_length0;
+ u32 fatal_err_dump_offset1;
+ u32 fatal_err_dump_length1;
+ u32 hda_mode_flag;
+ u32 anolog_setup_table_offset;
+};
+struct general_status_table {
+ u32 gst_len_mpistate;
+ u32 iq_freeze_state0;
+ u32 iq_freeze_state1;
+ u32 msgu_tcnt;
+ u32 iop_tcnt;
+ u32 reserved;
+ u32 phy_state[8];
+ u32 reserved1;
+ u32 reserved2;
+ u32 reserved3;
+ u32 recover_err_info[8];
+};
+struct inbound_queue_table {
+ u32 element_pri_size_cnt;
+ u32 upper_base_addr;
+ u32 lower_base_addr;
+ u32 ci_upper_base_addr;
+ u32 ci_lower_base_addr;
+ u32 pi_pci_bar;
+ u32 pi_offset;
+ u32 total_length;
+ void *base_virt;
+ void *ci_virt;
+ u32 reserved;
+ __le32 consumer_index;
+ u32 producer_idx;
+};
+struct outbound_queue_table {
+ u32 element_size_cnt;
+ u32 upper_base_addr;
+ u32 lower_base_addr;
+ void *base_virt;
+ u32 pi_upper_base_addr;
+ u32 pi_lower_base_addr;
+ u32 ci_pci_bar;
+ u32 ci_offset;
+ u32 total_length;
+ void *pi_virt;
+ u32 interrup_vec_cnt_delay;
+ u32 dinterrup_to_pci_offset;
+ __le32 producer_index;
+ u32 consumer_idx;
+};
+struct pm8001_hba_memspace {
+ void __iomem *memvirtaddr;
+ u64 membase;
+ u32 memsize;
+};
+struct pm8001_hba_info {
+ char name[PM8001_NAME_LENGTH];
+ struct list_head list;
+ unsigned long flags;
+ spinlock_t lock;/* host-wide lock */
+ struct pci_dev *pdev;/* our device */
+ struct device *dev;
+ struct pm8001_hba_memspace io_mem[6];
+ struct mpi_mem_req memoryMap;
+ void __iomem *msg_unit_tbl_addr;/*Message Unit Table Addr*/
+ void __iomem *main_cfg_tbl_addr;/*Main Config Table Addr*/
+ void __iomem *general_stat_tbl_addr;/*General Status Table Addr*/
+ void __iomem *inbnd_q_tbl_addr;/*Inbound Queue Config Table Addr*/
+ void __iomem *outbnd_q_tbl_addr;/*Outbound Queue Config Table Addr*/
+ struct main_cfg_table main_cfg_tbl;
+ struct general_status_table gs_tbl;
+ struct inbound_queue_table inbnd_q_tbl[PM8001_MAX_INB_NUM];
+ struct outbound_queue_table outbnd_q_tbl[PM8001_MAX_OUTB_NUM];
+ u8 sas_addr[SAS_ADDR_SIZE];
+ struct sas_ha_struct *sas;/* SCSI/SAS glue */
+ struct Scsi_Host *shost;
+ u32 chip_id;
+ const struct pm8001_chip_info *chip;
+ struct completion *nvmd_completion;
+ int tags_num;
+ unsigned long *tags;
+ struct pm8001_phy phy[PM8001_MAX_PHYS];
+ struct pm8001_port port[PM8001_MAX_PHYS];
+ u32 id;
+ u32 irq;
+ struct pm8001_device *devices;
+ struct pm8001_ccb_info *ccb_info;
+#ifdef PM8001_USE_MSIX
+ struct msix_entry msix_entries[16];/*for msi-x interrupt*/
+ int number_of_intr;/*will be used in remove()*/
+#endif
+#ifdef PM8001_USE_TASKLET
+ struct tasklet_struct tasklet;
+#endif
+ struct list_head wq_list;
+ u32 logging_level;
+ u32 fw_status;
+ const struct firmware *fw_image;
+};
+
+struct pm8001_wq {
+ struct delayed_work work_q;
+ struct pm8001_hba_info *pm8001_ha;
+ void *data;
+ int handler;
+ struct list_head entry;
+};
+
+struct pm8001_fw_image_header {
+ u8 vender_id[8];
+ u8 product_id;
+ u8 hardware_rev;
+ u8 dest_partition;
+ u8 reserved;
+ u8 fw_rev[4];
+ __be32 image_length;
+ __be32 image_crc;
+ __be32 startup_entry;
+} __attribute__((packed, aligned(4)));
+
+/* define task management IU */
+struct pm8001_tmf_task {
+ u8 tmf;
+ u32 tag_of_task_to_be_managed;
+};
+/**
+ * FW Flash Update status values
+ */
+#define FLASH_UPDATE_COMPLETE_PENDING_REBOOT 0x00
+#define FLASH_UPDATE_IN_PROGRESS 0x01
+#define FLASH_UPDATE_HDR_ERR 0x02
+#define FLASH_UPDATE_OFFSET_ERR 0x03
+#define FLASH_UPDATE_CRC_ERR 0x04
+#define FLASH_UPDATE_LENGTH_ERR 0x05
+#define FLASH_UPDATE_HW_ERR 0x06
+#define FLASH_UPDATE_DNLD_NOT_SUPPORTED 0x10
+#define FLASH_UPDATE_DISABLED 0x11
+
+/**
+ * brief param structure for firmware flash update.
+ */
+struct fw_flash_updata_info {
+ u32 cur_image_offset;
+ u32 cur_image_len;
+ u32 total_image_len;
+ struct pm8001_prd sgl;
+};
+
+struct fw_control_info {
+ u32 retcode;/*ret code (status)*/
+ u32 phase;/*ret code phase*/
+ u32 phaseCmplt;/*percent complete for the current
+ update phase */
+ u32 version;/*Hex encoded firmware version number*/
+ u32 offset;/*Used for downloading firmware */
+ u32 len; /*len of buffer*/
+ u32 size;/* Used in OS VPD and Trace get size
+ operations.*/
+ u32 reserved;/* padding required for 64 bit
+ alignment */
+ u8 buffer[1];/* Start of buffer */
+};
+struct fw_control_ex {
+ struct fw_control_info *fw_control;
+ void *buffer;/* keep buffer pointer to be
+ freed when the responce comes*/
+ void *virtAddr;/* keep virtual address of the data */
+ void *usrAddr;/* keep virtual address of the
+ user data */
+ dma_addr_t phys_addr;
+ u32 len; /* len of buffer */
+ void *payload; /* pointer to IOCTL Payload */
+ u8 inProgress;/*if 1 - the IOCTL request is in
+ progress */
+ void *param1;
+ void *param2;
+ void *param3;
+};
+
+/******************** function prototype *********************/
+int pm8001_tag_alloc(struct pm8001_hba_info *pm8001_ha, u32 *tag_out);
+void pm8001_tag_init(struct pm8001_hba_info *pm8001_ha);
+u32 pm8001_get_ncq_tag(struct sas_task *task, u32 *tag);
+void pm8001_ccb_free(struct pm8001_hba_info *pm8001_ha, u32 ccb_idx);
+void pm8001_ccb_task_free(struct pm8001_hba_info *pm8001_ha,
+ struct sas_task *task, struct pm8001_ccb_info *ccb, u32 ccb_idx);
+int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
+ void *funcdata);
+int pm8001_slave_alloc(struct scsi_device *scsi_dev);
+int pm8001_slave_configure(struct scsi_device *sdev);
+void pm8001_scan_start(struct Scsi_Host *shost);
+int pm8001_scan_finished(struct Scsi_Host *shost, unsigned long time);
+int pm8001_queue_command(struct sas_task *task, const int num,
+ gfp_t gfp_flags);
+int pm8001_abort_task(struct sas_task *task);
+int pm8001_abort_task_set(struct domain_device *dev, u8 *lun);
+int pm8001_clear_aca(struct domain_device *dev, u8 *lun);
+int pm8001_clear_task_set(struct domain_device *dev, u8 *lun);
+int pm8001_dev_found(struct domain_device *dev);
+void pm8001_dev_gone(struct domain_device *dev);
+int pm8001_lu_reset(struct domain_device *dev, u8 *lun);
+int pm8001_I_T_nexus_reset(struct domain_device *dev);
+int pm8001_query_task(struct sas_task *task);
+int pm8001_mem_alloc(struct pci_dev *pdev, void **virt_addr,
+ dma_addr_t *pphys_addr, u32 *pphys_addr_hi, u32 *pphys_addr_lo,
+ u32 mem_size, u32 align);
+
+
+/* ctl shared API */
+extern struct device_attribute *pm8001_host_attrs[];
+
+#endif
+
diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c
index 0a97bc9..34c6b89 100644
--- a/drivers/scsi/pmcraid.c
+++ b/drivers/scsi/pmcraid.c
@@ -278,12 +278,17 @@ static void pmcraid_slave_destroy(struct scsi_device *scsi_dev)
* pmcraid_change_queue_depth - Change the device's queue depth
* @scsi_dev: scsi device struct
* @depth: depth to set
+ * @reason: calling context
*
* Return value
* actual depth set
*/
-static int pmcraid_change_queue_depth(struct scsi_device *scsi_dev, int depth)
+static int pmcraid_change_queue_depth(struct scsi_device *scsi_dev, int depth,
+ int reason)
{
+ if (reason != SCSI_QDEPTH_DEFAULT)
+ return -EOPNOTSUPP;
+
if (depth > PMCRAID_MAX_CMD_PER_LUN)
depth = PMCRAID_MAX_CMD_PER_LUN;
@@ -3342,7 +3347,7 @@ static int pmcraid_chr_fasync(int fd, struct file *filep, int mode)
* @direction : data transfer direction
*
* Return value
- * 0 on sucess, non-zero error code on failure
+ * 0 on success, non-zero error code on failure
*/
static int pmcraid_build_passthrough_ioadls(
struct pmcraid_cmd *cmd,
@@ -3401,7 +3406,7 @@ static int pmcraid_build_passthrough_ioadls(
* @direction: data transfer direction
*
* Return value
- * 0 on sucess, non-zero error code on failure
+ * 0 on success, non-zero error code on failure
*/
static void pmcraid_release_passthrough_ioadls(
struct pmcraid_cmd *cmd,
@@ -3429,7 +3434,7 @@ static void pmcraid_release_passthrough_ioadls(
* @arg: pointer to pmcraid_passthrough_buffer user buffer
*
* Return value
- * 0 on sucess, non-zero error code on failure
+ * 0 on success, non-zero error code on failure
*/
static long pmcraid_ioctl_passthrough(
struct pmcraid_instance *pinstance,
diff --git a/drivers/scsi/pmcraid.h b/drivers/scsi/pmcraid.h
index 3441b3f..2752b56 100644
--- a/drivers/scsi/pmcraid.h
+++ b/drivers/scsi/pmcraid.h
@@ -771,11 +771,11 @@ static struct pmcraid_ioasc_error pmcraid_ioasc_error_table[] = {
{0x01180600, IOASC_LOG_LEVEL_MUST,
"Recovered Error, soft media error, sector reassignment suggested"},
{0x015D0000, IOASC_LOG_LEVEL_MUST,
- "Recovered Error, failure prediction thresold exceeded"},
+ "Recovered Error, failure prediction threshold exceeded"},
{0x015D9200, IOASC_LOG_LEVEL_MUST,
- "Recovered Error, soft Cache Card Battery error thresold"},
+ "Recovered Error, soft Cache Card Battery error threshold"},
{0x015D9200, IOASC_LOG_LEVEL_MUST,
- "Recovered Error, soft Cache Card Battery error thresold"},
+ "Recovered Error, soft Cache Card Battery error threshold"},
{0x02048000, IOASC_LOG_LEVEL_MUST,
"Not Ready, IOA Reset Required"},
{0x02408500, IOASC_LOG_LEVEL_MUST,
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index fbcb82a..21e2bc4 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -1654,7 +1654,8 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
fc_vport_set_state(fc_vport, FC_VPORT_LINKDOWN);
}
- if (scsi_add_host(vha->host, &fc_vport->dev)) {
+ if (scsi_add_host_with_dma(vha->host, &fc_vport->dev,
+ &ha->pdev->dev)) {
DEBUG15(printk("scsi(%ld): scsi_add_host failure for VP[%d].\n",
vha->host_no, vha->vp_idx));
goto vport_create_failed_2;
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index cca8e4a..cb2eca4 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -377,6 +377,24 @@ qla25xx_copy_mq(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain)
return ptr + sizeof(struct qla2xxx_mq_chain);
}
+static void
+qla2xxx_dump_post_process(scsi_qla_host_t *vha, int rval)
+{
+ struct qla_hw_data *ha = vha->hw;
+
+ if (rval != QLA_SUCCESS) {
+ qla_printk(KERN_WARNING, ha,
+ "Failed to dump firmware (%x)!!!\n", rval);
+ ha->fw_dumped = 0;
+ } else {
+ qla_printk(KERN_INFO, ha,
+ "Firmware dump saved to temp buffer (%ld/%p).\n",
+ vha->host_no, ha->fw_dump);
+ ha->fw_dumped = 1;
+ qla2x00_post_uevent_work(vha, QLA_UEVENT_CODE_FW_DUMP);
+ }
+}
+
/**
* qla2300_fw_dump() - Dumps binary data from the 2300 firmware.
* @ha: HA context
@@ -530,17 +548,7 @@ qla2300_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
if (rval == QLA_SUCCESS)
qla2xxx_copy_queues(ha, nxt);
- if (rval != QLA_SUCCESS) {
- qla_printk(KERN_WARNING, ha,
- "Failed to dump firmware (%x)!!!\n", rval);
- ha->fw_dumped = 0;
-
- } else {
- qla_printk(KERN_INFO, ha,
- "Firmware dump saved to temp buffer (%ld/%p).\n",
- base_vha->host_no, ha->fw_dump);
- ha->fw_dumped = 1;
- }
+ qla2xxx_dump_post_process(base_vha, rval);
qla2300_fw_dump_failed:
if (!hardware_locked)
@@ -737,17 +745,7 @@ qla2100_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
if (rval == QLA_SUCCESS)
qla2xxx_copy_queues(ha, &fw->risc_ram[cnt]);
- if (rval != QLA_SUCCESS) {
- qla_printk(KERN_WARNING, ha,
- "Failed to dump firmware (%x)!!!\n", rval);
- ha->fw_dumped = 0;
-
- } else {
- qla_printk(KERN_INFO, ha,
- "Firmware dump saved to temp buffer (%ld/%p).\n",
- base_vha->host_no, ha->fw_dump);
- ha->fw_dumped = 1;
- }
+ qla2xxx_dump_post_process(base_vha, rval);
qla2100_fw_dump_failed:
if (!hardware_locked)
@@ -984,17 +982,7 @@ qla24xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
qla24xx_copy_eft(ha, nxt);
qla24xx_fw_dump_failed_0:
- if (rval != QLA_SUCCESS) {
- qla_printk(KERN_WARNING, ha,
- "Failed to dump firmware (%x)!!!\n", rval);
- ha->fw_dumped = 0;
-
- } else {
- qla_printk(KERN_INFO, ha,
- "Firmware dump saved to temp buffer (%ld/%p).\n",
- base_vha->host_no, ha->fw_dump);
- ha->fw_dumped = 1;
- }
+ qla2xxx_dump_post_process(base_vha, rval);
qla24xx_fw_dump_failed:
if (!hardware_locked)
@@ -1305,17 +1293,7 @@ qla25xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
}
qla25xx_fw_dump_failed_0:
- if (rval != QLA_SUCCESS) {
- qla_printk(KERN_WARNING, ha,
- "Failed to dump firmware (%x)!!!\n", rval);
- ha->fw_dumped = 0;
-
- } else {
- qla_printk(KERN_INFO, ha,
- "Firmware dump saved to temp buffer (%ld/%p).\n",
- base_vha->host_no, ha->fw_dump);
- ha->fw_dumped = 1;
- }
+ qla2xxx_dump_post_process(base_vha, rval);
qla25xx_fw_dump_failed:
if (!hardware_locked)
@@ -1628,17 +1606,7 @@ qla81xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
}
qla81xx_fw_dump_failed_0:
- if (rval != QLA_SUCCESS) {
- qla_printk(KERN_WARNING, ha,
- "Failed to dump firmware (%x)!!!\n", rval);
- ha->fw_dumped = 0;
-
- } else {
- qla_printk(KERN_INFO, ha,
- "Firmware dump saved to temp buffer (%ld/%p).\n",
- base_vha->host_no, ha->fw_dump);
- ha->fw_dumped = 1;
- }
+ qla2xxx_dump_post_process(base_vha, rval);
qla81xx_fw_dump_failed:
if (!hardware_locked)
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 2150618..6b9bf23 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -2123,6 +2123,7 @@ enum qla_work_type {
QLA_EVT_ASYNC_LOGIN_DONE,
QLA_EVT_ASYNC_LOGOUT,
QLA_EVT_ASYNC_LOGOUT_DONE,
+ QLA_EVT_UEVENT,
};
@@ -2146,6 +2147,10 @@ struct qla_work_evt {
#define QLA_LOGIO_LOGIN_RETRIED BIT_0
u16 data[2];
} logio;
+ struct {
+ u32 code;
+#define QLA_UEVENT_CODE_FW_DUMP 0
+ } uevent;
} u;
};
@@ -2435,11 +2440,11 @@ struct qla_hw_data {
dma_addr_t edc_data_dma;
uint16_t edc_data_len;
-#define XGMAC_DATA_SIZE PAGE_SIZE
+#define XGMAC_DATA_SIZE 4096
void *xgmac_data;
dma_addr_t xgmac_data_dma;
-#define DCBX_TLV_DATA_SIZE PAGE_SIZE
+#define DCBX_TLV_DATA_SIZE 4096
void *dcbx_tlv;
dma_addr_t dcbx_tlv_dma;
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index f3d1d1a..e218513 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -92,6 +92,7 @@ extern int qla2x00_post_async_logout_work(struct scsi_qla_host *, fc_port_t *,
uint16_t *);
extern int qla2x00_post_async_logout_done_work(struct scsi_qla_host *,
fc_port_t *, uint16_t *);
+extern int qla2x00_post_uevent_work(struct scsi_qla_host *, u32);
extern int qla81xx_restart_mpi_firmware(scsi_qla_host_t *);
@@ -246,7 +247,7 @@ 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 *, 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);
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 9e3eaac..b74924b 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -277,7 +277,6 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
vha->marker_needed = 0;
ha->isp_abort_cnt = 0;
ha->beacon_blink_led = 0;
- set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags);
set_bit(0, ha->req_qid_map);
set_bit(0, ha->rsp_qid_map);
@@ -1203,7 +1202,7 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
}
qla2x00_get_resource_cnts(vha, NULL,
&ha->fw_xcb_count, NULL, NULL,
- &ha->max_npiv_vports);
+ &ha->max_npiv_vports, NULL);
if (!fw_major_version && ql2xallocfwdump)
qla2x00_alloc_fw_dump(vha);
@@ -3573,6 +3572,15 @@ qla2x00_abort_isp(scsi_qla_host_t *vha)
ha->isp_abort_cnt = 0;
clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
+ if (IS_QLA81XX(ha))
+ qla2x00_get_fw_version(vha,
+ &ha->fw_major_version,
+ &ha->fw_minor_version,
+ &ha->fw_subminor_version,
+ &ha->fw_attributes, &ha->fw_memory_size,
+ ha->mpi_version, &ha->mpi_capabilities,
+ ha->phy_version);
+
if (ha->fce) {
ha->flags.fce_enabled = 1;
memset(ha->fce, 0,
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index b20a716..8049873 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -313,10 +313,11 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
static char *link_speeds[] = { "1", "2", "?", "4", "8", "10" };
char *link_speed;
uint16_t handle_cnt;
- uint16_t cnt;
+ uint16_t cnt, mbx;
uint32_t handles[5];
struct qla_hw_data *ha = vha->hw;
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
+ struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24;
uint32_t rscn_entry, host_pid;
uint8_t rscn_queue_index;
unsigned long flags;
@@ -395,9 +396,10 @@ skip_rio:
break;
case MBA_SYSTEM_ERR: /* System Error */
+ mbx = IS_QLA81XX(ha) ? RD_REG_WORD(&reg24->mailbox7) : 0;
qla_printk(KERN_INFO, ha,
- "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh.\n",
- mb[1], mb[2], mb[3]);
+ "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh "
+ "mbx7=%xh.\n", mb[1], mb[2], mb[3], mbx);
ha->isp_ops->fw_dump(vha, 1);
@@ -419,9 +421,10 @@ skip_rio:
break;
case MBA_REQ_TRANSFER_ERR: /* Request Transfer Error */
- DEBUG2(printk("scsi(%ld): ISP Request Transfer Error.\n",
- vha->host_no));
- qla_printk(KERN_WARNING, ha, "ISP Request Transfer Error.\n");
+ DEBUG2(printk("scsi(%ld): ISP Request Transfer Error (%x).\n",
+ vha->host_no, mb[1]));
+ qla_printk(KERN_WARNING, ha,
+ "ISP Request Transfer Error (%x).\n", mb[1]);
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
break;
@@ -485,10 +488,13 @@ skip_rio:
break;
case MBA_LOOP_DOWN: /* Loop Down Event */
+ mbx = IS_QLA81XX(ha) ? RD_REG_WORD(&reg24->mailbox4) : 0;
DEBUG2(printk("scsi(%ld): Asynchronous LOOP DOWN "
- "(%x %x %x).\n", vha->host_no, mb[1], mb[2], mb[3]));
- qla_printk(KERN_INFO, ha, "LOOP DOWN detected (%x %x %x).\n",
- mb[1], mb[2], mb[3]);
+ "(%x %x %x %x).\n", vha->host_no, mb[1], mb[2], mb[3],
+ mbx));
+ qla_printk(KERN_INFO, ha,
+ "LOOP DOWN detected (%x %x %x %x).\n", mb[1], mb[2], mb[3],
+ mbx);
if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
atomic_set(&vha->loop_state, LOOP_DOWN);
@@ -1347,16 +1353,22 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
sense_len = rsp_info_len = resid_len = fw_resid_len = 0;
if (IS_FWI2_CAPABLE(ha)) {
- sense_len = le32_to_cpu(sts24->sense_len);
- rsp_info_len = le32_to_cpu(sts24->rsp_data_len);
- resid_len = le32_to_cpu(sts24->rsp_residual_count);
- fw_resid_len = le32_to_cpu(sts24->residual_len);
+ if (scsi_status & SS_SENSE_LEN_VALID)
+ sense_len = le32_to_cpu(sts24->sense_len);
+ if (scsi_status & SS_RESPONSE_INFO_LEN_VALID)
+ rsp_info_len = le32_to_cpu(sts24->rsp_data_len);
+ if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER))
+ resid_len = le32_to_cpu(sts24->rsp_residual_count);
+ if (comp_status == CS_DATA_UNDERRUN)
+ fw_resid_len = le32_to_cpu(sts24->residual_len);
rsp_info = sts24->data;
sense_data = sts24->data;
host_to_fcp_swap(sts24->data, sizeof(sts24->data));
} else {
- sense_len = le16_to_cpu(sts->req_sense_length);
- rsp_info_len = le16_to_cpu(sts->rsp_info_len);
+ if (scsi_status & SS_SENSE_LEN_VALID)
+ sense_len = le16_to_cpu(sts->req_sense_length);
+ if (scsi_status & SS_RESPONSE_INFO_LEN_VALID)
+ rsp_info_len = le16_to_cpu(sts->rsp_info_len);
resid_len = le32_to_cpu(sts->residual_length);
rsp_info = sts->rsp_info;
sense_data = sts->req_sense_data;
@@ -1443,38 +1455,62 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
break;
case CS_DATA_UNDERRUN:
- resid = resid_len;
+ DEBUG2(printk(KERN_INFO
+ "scsi(%ld:%d:%d) UNDERRUN status detected 0x%x-0x%x. "
+ "resid=0x%x fw_resid=0x%x cdb=0x%x os_underflow=0x%x\n",
+ vha->host_no, cp->device->id, cp->device->lun, comp_status,
+ scsi_status, resid_len, fw_resid_len, cp->cmnd[0],
+ cp->underflow));
+
/* Use F/W calculated residual length. */
- if (IS_FWI2_CAPABLE(ha)) {
- if (!(scsi_status & SS_RESIDUAL_UNDER)) {
- lscsi_status = 0;
- } else if (resid != fw_resid_len) {
- scsi_status &= ~SS_RESIDUAL_UNDER;
- lscsi_status = 0;
+ resid = IS_FWI2_CAPABLE(ha) ? fw_resid_len : resid_len;
+ scsi_set_resid(cp, resid);
+ if (scsi_status & SS_RESIDUAL_UNDER) {
+ if (IS_FWI2_CAPABLE(ha) && fw_resid_len != resid_len) {
+ DEBUG2(printk(
+ "scsi(%ld:%d:%d:%d) Dropped frame(s) "
+ "detected (%x of %x bytes)...residual "
+ "length mismatch...retrying command.\n",
+ vha->host_no, cp->device->channel,
+ cp->device->id, cp->device->lun, resid,
+ scsi_bufflen(cp)));
+
+ cp->result = DID_ERROR << 16 | lscsi_status;
+ break;
}
- resid = fw_resid_len;
- }
- if (scsi_status & SS_RESIDUAL_UNDER) {
- scsi_set_resid(cp, resid);
- } else {
- DEBUG2(printk(KERN_INFO
- "scsi(%ld:%d:%d) UNDERRUN status detected "
- "0x%x-0x%x. resid=0x%x fw_resid=0x%x cdb=0x%x "
- "os_underflow=0x%x\n", vha->host_no,
- cp->device->id, cp->device->lun, comp_status,
- scsi_status, resid_len, resid, cp->cmnd[0],
- cp->underflow));
+ if (!lscsi_status &&
+ ((unsigned)(scsi_bufflen(cp) - resid) <
+ cp->underflow)) {
+ qla_printk(KERN_INFO, ha,
+ "scsi(%ld:%d:%d:%d): Mid-layer underflow "
+ "detected (%x of %x bytes)...returning "
+ "error status.\n", vha->host_no,
+ cp->device->channel, cp->device->id,
+ cp->device->lun, resid, scsi_bufflen(cp));
+
+ cp->result = DID_ERROR << 16;
+ break;
+ }
+ } else if (!lscsi_status) {
+ DEBUG2(printk(
+ "scsi(%ld:%d:%d:%d) Dropped frame(s) detected "
+ "(%x of %x bytes)...firmware reported underrun..."
+ "retrying command.\n", vha->host_no,
+ cp->device->channel, cp->device->id,
+ cp->device->lun, resid, scsi_bufflen(cp)));
+ cp->result = DID_ERROR << 16;
+ break;
}
+ cp->result = DID_OK << 16 | lscsi_status;
+
/*
* Check to see if SCSI Status is non zero. If so report SCSI
* Status.
*/
if (lscsi_status != 0) {
- cp->result = DID_OK << 16 | lscsi_status;
-
if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
DEBUG2(printk(KERN_INFO
"scsi(%ld): QUEUE FULL status detected "
@@ -1501,42 +1537,6 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
break;
qla2x00_handle_sense(sp, sense_data, sense_len, rsp);
- } else {
- /*
- * If RISC reports underrun and target does not report
- * it then we must have a lost frame, so tell upper
- * layer to retry it by reporting an error.
- */
- if (!(scsi_status & SS_RESIDUAL_UNDER)) {
- DEBUG2(printk("scsi(%ld:%d:%d:%d) Dropped "
- "frame(s) detected (%x of %x bytes)..."
- "retrying command.\n",
- vha->host_no, cp->device->channel,
- cp->device->id, cp->device->lun, resid,
- scsi_bufflen(cp)));
-
- scsi_set_resid(cp, resid);
- cp->result = DID_ERROR << 16;
- break;
- }
-
- /* Handle mid-layer underflow */
- if ((unsigned)(scsi_bufflen(cp) - resid) <
- cp->underflow) {
- qla_printk(KERN_INFO, ha,
- "scsi(%ld:%d:%d:%d): Mid-layer underflow "
- "detected (%x of %x bytes)...returning "
- "error status.\n", vha->host_no,
- cp->device->channel, cp->device->id,
- cp->device->lun, resid,
- scsi_bufflen(cp));
-
- cp->result = DID_ERROR << 16;
- break;
- }
-
- /* Everybody online, looking good... */
- cp->result = DID_OK << 16;
}
break;
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index b6202fe..05d595d 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -2006,7 +2006,7 @@ qla2x00_get_id_list(scsi_qla_host_t *vha, void *id_list, dma_addr_t id_list_dma,
int
qla2x00_get_resource_cnts(scsi_qla_host_t *vha, uint16_t *cur_xchg_cnt,
uint16_t *orig_xchg_cnt, uint16_t *cur_iocb_cnt,
- uint16_t *orig_iocb_cnt, uint16_t *max_npiv_vports)
+ uint16_t *orig_iocb_cnt, uint16_t *max_npiv_vports, uint16_t *max_fcfs)
{
int rval;
mbx_cmd_t mc;
@@ -2017,6 +2017,8 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *vha, uint16_t *cur_xchg_cnt,
mcp->mb[0] = MBC_GET_RESOURCE_COUNTS;
mcp->out_mb = MBX_0;
mcp->in_mb = MBX_11|MBX_10|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+ if (IS_QLA81XX(vha->hw))
+ mcp->in_mb |= MBX_12;
mcp->tov = MBX_TOV_SECONDS;
mcp->flags = 0;
rval = qla2x00_mailbox_command(vha, mcp);
@@ -2027,9 +2029,10 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *vha, uint16_t *cur_xchg_cnt,
vha->host_no, mcp->mb[0]));
} else {
DEBUG11(printk("%s(%ld): done. mb1=%x mb2=%x mb3=%x mb6=%x "
- "mb7=%x mb10=%x mb11=%x.\n", __func__, vha->host_no,
- mcp->mb[1], mcp->mb[2], mcp->mb[3], mcp->mb[6], mcp->mb[7],
- mcp->mb[10], mcp->mb[11]));
+ "mb7=%x mb10=%x mb11=%x mb12=%x.\n", __func__,
+ vha->host_no, mcp->mb[1], mcp->mb[2], mcp->mb[3],
+ mcp->mb[6], mcp->mb[7], mcp->mb[10], mcp->mb[11],
+ mcp->mb[12]));
if (cur_xchg_cnt)
*cur_xchg_cnt = mcp->mb[3];
@@ -2041,6 +2044,8 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *vha, uint16_t *cur_xchg_cnt,
*orig_iocb_cnt = mcp->mb[10];
if (vha->hw->flags.npiv_supported && max_npiv_vports)
*max_npiv_vports = mcp->mb[11];
+ if (IS_QLA81XX(vha->hw) && max_fcfs)
+ *max_fcfs = mcp->mb[12];
}
return (rval);
@@ -2313,6 +2318,7 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport,
{
int rval, rval2;
struct tsk_mgmt_cmd *tsk;
+ struct sts_entry_24xx *sts;
dma_addr_t tsk_dma;
scsi_qla_host_t *vha;
struct qla_hw_data *ha;
@@ -2352,20 +2358,37 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport,
sizeof(tsk->p.tsk.lun));
}
+ sts = &tsk->p.sts;
rval = qla2x00_issue_iocb(vha, tsk, tsk_dma, 0);
if (rval != QLA_SUCCESS) {
DEBUG2_3_11(printk("%s(%ld): failed to issue %s Reset IOCB "
"(%x).\n", __func__, vha->host_no, name, rval));
- } else if (tsk->p.sts.entry_status != 0) {
+ } else if (sts->entry_status != 0) {
DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
"-- error status (%x).\n", __func__, vha->host_no,
- tsk->p.sts.entry_status));
+ sts->entry_status));
rval = QLA_FUNCTION_FAILED;
- } else if (tsk->p.sts.comp_status !=
+ } else if (sts->comp_status !=
__constant_cpu_to_le16(CS_COMPLETE)) {
DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
"-- completion status (%x).\n", __func__,
- vha->host_no, le16_to_cpu(tsk->p.sts.comp_status)));
+ vha->host_no, le16_to_cpu(sts->comp_status)));
+ rval = QLA_FUNCTION_FAILED;
+ } else if (!(le16_to_cpu(sts->scsi_status) &
+ SS_RESPONSE_INFO_LEN_VALID)) {
+ DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
+ "-- no response info (%x).\n", __func__, vha->host_no,
+ le16_to_cpu(sts->scsi_status)));
+ rval = QLA_FUNCTION_FAILED;
+ } else if (le32_to_cpu(sts->rsp_data_len) < 4) {
+ DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
+ "-- not enough response info (%d).\n", __func__,
+ vha->host_no, le32_to_cpu(sts->rsp_data_len)));
+ rval = QLA_FUNCTION_FAILED;
+ } else if (sts->data[3]) {
+ DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
+ "-- response (%x).\n", __func__,
+ vha->host_no, sts->data[3]));
rval = QLA_FUNCTION_FAILED;
}
@@ -2759,8 +2782,10 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
vp_idx, MSB(stat),
rptid_entry->port_id[2], rptid_entry->port_id[1],
rptid_entry->port_id[0]));
- if (vp_idx == 0)
- return;
+
+ vp = vha;
+ if (vp_idx == 0 && (MSB(stat) != 1))
+ goto reg_needed;
if (MSB(stat) == 1) {
DEBUG2(printk("scsi(%ld): Could not acquire ID for "
@@ -2783,8 +2808,11 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
* response queue. Handle it in dpc context.
*/
set_bit(VP_IDX_ACQUIRED, &vp->vp_flags);
- set_bit(VP_DPC_NEEDED, &vha->dpc_flags);
+reg_needed:
+ set_bit(REGISTER_FC4_NEEDED, &vp->dpc_flags);
+ set_bit(REGISTER_FDMI_NEEDED, &vp->dpc_flags);
+ set_bit(VP_DPC_NEEDED, &vha->dpc_flags);
qla2xxx_wake_dpc(vha);
}
}
diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
index e07b361..a47d343 100644
--- a/drivers/scsi/qla2xxx/qla_mid.c
+++ b/drivers/scsi/qla2xxx/qla_mid.c
@@ -382,8 +382,6 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
vha->mgmt_svr_loop_id = 10 + vha->vp_idx;
vha->dpc_flags = 0L;
- set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags);
- set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags);
/*
* To fix the issue of processing a parent's RSCN for the vport before
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index b79fca7..4166935 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -11,6 +11,7 @@
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/mutex.h>
+#include <linux/kobject.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsicam.h>
@@ -137,7 +138,7 @@ static int qla2xxx_eh_target_reset(struct scsi_cmnd *);
static int qla2xxx_eh_bus_reset(struct scsi_cmnd *);
static int qla2xxx_eh_host_reset(struct scsi_cmnd *);
-static int qla2x00_change_queue_depth(struct scsi_device *, int);
+static int qla2x00_change_queue_depth(struct scsi_device *, int, int);
static int qla2x00_change_queue_type(struct scsi_device *, int);
struct scsi_host_template qla2xxx_driver_template = {
@@ -727,23 +728,6 @@ qla2x00_abort_fcport_cmds(fc_port_t *fcport)
spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
-static void
-qla2x00_block_error_handler(struct scsi_cmnd *cmnd)
-{
- struct Scsi_Host *shost = cmnd->device->host;
- struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device));
- unsigned long flags;
-
- spin_lock_irqsave(shost->host_lock, flags);
- while (rport->port_state == FC_PORTSTATE_BLOCKED) {
- spin_unlock_irqrestore(shost->host_lock, flags);
- msleep(1000);
- spin_lock_irqsave(shost->host_lock, flags);
- }
- spin_unlock_irqrestore(shost->host_lock, flags);
- return;
-}
-
/**************************************************************************
* qla2xxx_eh_abort
*
@@ -773,7 +757,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
struct req_que *req = vha->req;
srb_t *spt;
- qla2x00_block_error_handler(cmd);
+ fc_block_scsi_eh(cmd);
if (!CMD_SP(cmd))
return SUCCESS;
@@ -904,7 +888,7 @@ __qla2xxx_eh_generic_reset(char *name, enum nexus_wait_type type,
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
int err;
- qla2x00_block_error_handler(cmd);
+ fc_block_scsi_eh(cmd);
if (!fcport)
return FAILED;
@@ -984,7 +968,7 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
unsigned long serial;
srb_t *sp = (srb_t *) CMD_SP(cmd);
- qla2x00_block_error_handler(cmd);
+ fc_block_scsi_eh(cmd);
id = cmd->device->id;
lun = cmd->device->lun;
@@ -1047,7 +1031,7 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
srb_t *sp = (srb_t *) CMD_SP(cmd);
scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
- qla2x00_block_error_handler(cmd);
+ fc_block_scsi_eh(cmd);
id = cmd->device->id;
lun = cmd->device->lun;
@@ -1234,8 +1218,11 @@ qla2xxx_slave_destroy(struct scsi_device *sdev)
}
static int
-qla2x00_change_queue_depth(struct scsi_device *sdev, int qdepth)
+qla2x00_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
{
+ if (reason != SCSI_QDEPTH_DEFAULT)
+ return -EOPNOTSUPP;
+
scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
return sdev->queue_depth;
}
@@ -2653,6 +2640,37 @@ qla2x00_post_async_work(login_done, QLA_EVT_ASYNC_LOGIN_DONE);
qla2x00_post_async_work(logout, QLA_EVT_ASYNC_LOGOUT);
qla2x00_post_async_work(logout_done, QLA_EVT_ASYNC_LOGOUT_DONE);
+int
+qla2x00_post_uevent_work(struct scsi_qla_host *vha, u32 code)
+{
+ struct qla_work_evt *e;
+
+ e = qla2x00_alloc_work(vha, QLA_EVT_UEVENT);
+ if (!e)
+ return QLA_FUNCTION_FAILED;
+
+ e->u.uevent.code = code;
+ return qla2x00_post_work(vha, e);
+}
+
+static void
+qla2x00_uevent_emit(struct scsi_qla_host *vha, u32 code)
+{
+ char event_string[40];
+ char *envp[] = { event_string, NULL };
+
+ switch (code) {
+ case QLA_UEVENT_CODE_FW_DUMP:
+ snprintf(event_string, sizeof(event_string), "FW_DUMP=%ld",
+ vha->host_no);
+ break;
+ default:
+ /* do nothing */
+ break;
+ }
+ kobject_uevent_env(&vha->hw->pdev->dev.kobj, KOBJ_CHANGE, envp);
+}
+
void
qla2x00_do_work(struct scsi_qla_host *vha)
{
@@ -2690,6 +2708,9 @@ qla2x00_do_work(struct scsi_qla_host *vha)
qla2x00_async_logout_done(vha, e->u.logio.fcport,
e->u.logio.data);
break;
+ case QLA_EVT_UEVENT:
+ qla2x00_uevent_emit(vha, e->u.uevent.code);
+ break;
}
if (e->flags & QLA_EVT_FLAG_FREE)
kfree(e);
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index ac107a2..807e0db 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,7 +7,7 @@
/*
* Driver version
*/
-#define QLA2XXX_VERSION "8.03.01-k6"
+#define QLA2XXX_VERSION "8.03.01-k7"
#define QLA_DRIVER_MAJOR_VER 8
#define QLA_DRIVER_MINOR_VER 3
diff --git a/drivers/scsi/qlogicpti.h b/drivers/scsi/qlogicpti.h
index 9c053bb..e3c74d1 100644
--- a/drivers/scsi/qlogicpti.h
+++ b/drivers/scsi/qlogicpti.h
@@ -43,7 +43,7 @@
* determined for each queue request anew.
*/
#define QLOGICPTI_REQ_QUEUE_LEN 255 /* must be power of two - 1 */
-#define QLOGICPTI_MAX_SG(ql) (4 + ((ql) > 0) ? 7*((ql) - 1) : 0)
+#define QLOGICPTI_MAX_SG(ql) (4 + (((ql) > 0) ? 7*((ql) - 1) : 0))
/* mailbox command complete status codes */
#define MBOX_COMMAND_COMPLETE 0x4000
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index dd098ca..a60da55 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -940,10 +940,16 @@ EXPORT_SYMBOL(scsi_adjust_queue_depth);
*/
int scsi_track_queue_full(struct scsi_device *sdev, int depth)
{
- if ((jiffies >> 4) == sdev->last_queue_full_time)
+
+ /*
+ * Don't let QUEUE_FULLs on the same
+ * jiffies count, they could all be from
+ * same event.
+ */
+ if ((jiffies >> 4) == (sdev->last_queue_full_time >> 4))
return 0;
- sdev->last_queue_full_time = (jiffies >> 4);
+ sdev->last_queue_full_time = jiffies;
if (sdev->last_queue_full_depth != depth) {
sdev->last_queue_full_count = 1;
sdev->last_queue_full_depth = depth;
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index c4103be..0b575c8 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -44,6 +44,8 @@
#include <net/checksum.h>
+#include <asm/unaligned.h>
+
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
@@ -105,6 +107,10 @@ static const char * scsi_debug_version_date = "20070104";
#define DEF_ATO 1
#define DEF_PHYSBLK_EXP 0
#define DEF_LOWEST_ALIGNED 0
+#define DEF_UNMAP_MAX_BLOCKS 0
+#define DEF_UNMAP_MAX_DESC 0
+#define DEF_UNMAP_GRANULARITY 0
+#define DEF_UNMAP_ALIGNMENT 0
/* bit mask values for scsi_debug_opts */
#define SCSI_DEBUG_OPT_NOISE 1
@@ -162,6 +168,10 @@ static int scsi_debug_guard = DEF_GUARD;
static int scsi_debug_ato = DEF_ATO;
static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP;
static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED;
+static int scsi_debug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
+static int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
+static int scsi_debug_unmap_granularity = DEF_UNMAP_GRANULARITY;
+static int scsi_debug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
static int scsi_debug_cmnd_count = 0;
@@ -223,7 +233,9 @@ static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
static unsigned char * fake_storep; /* ramdisk storage */
static unsigned char *dif_storep; /* protection info */
+static void *map_storep; /* provisioning map */
+static unsigned long map_size;
static int num_aborts = 0;
static int num_dev_resets = 0;
static int num_bus_resets = 0;
@@ -317,6 +329,7 @@ static void get_data_transfer_info(unsigned char *cmd,
(u32)cmd[28] << 24;
break;
+ case WRITE_SAME_16:
case WRITE_16:
case READ_16:
*lba = (u64)cmd[9] | (u64)cmd[8] << 8 |
@@ -335,6 +348,7 @@ static void get_data_transfer_info(unsigned char *cmd,
*num = (u32)cmd[9] | (u32)cmd[8] << 8 | (u32)cmd[7] << 16 |
(u32)cmd[6] << 24;
break;
+ case WRITE_SAME:
case WRITE_10:
case READ_10:
case XDWRITEREAD_10:
@@ -671,10 +685,12 @@ static int inquiry_evpd_89(unsigned char * arr)
}
+/* Block limits VPD page (SBC-3) */
static unsigned char vpdb0_data[] = {
- /* from 4th byte */ 0,0,0,4,
- 0,0,0x4,0,
- 0,0,0,64,
+ /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
+ 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,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
};
static int inquiry_evpd_b0(unsigned char * arr)
@@ -691,14 +707,40 @@ static int inquiry_evpd_b0(unsigned char * arr)
arr[6] = (sdebug_store_sectors >> 8) & 0xff;
arr[7] = sdebug_store_sectors & 0xff;
}
+
+ if (scsi_debug_unmap_max_desc) {
+ unsigned int blocks;
+
+ if (scsi_debug_unmap_max_blocks)
+ blocks = scsi_debug_unmap_max_blocks;
+ else
+ blocks = 0xffffffff;
+
+ put_unaligned_be32(blocks, &arr[16]);
+ put_unaligned_be32(scsi_debug_unmap_max_desc, &arr[20]);
+ }
+
+ if (scsi_debug_unmap_alignment) {
+ put_unaligned_be32(scsi_debug_unmap_alignment, &arr[28]);
+ arr[28] |= 0x80; /* UGAVALID */
+ }
+
+ if (scsi_debug_unmap_granularity) {
+ put_unaligned_be32(scsi_debug_unmap_granularity, &arr[24]);
+ return 0x3c; /* Mandatory page length for thin provisioning */
+ }
+
return sizeof(vpdb0_data);
}
+/* Block device characteristics VPD page (SBC-3) */
static int inquiry_evpd_b1(unsigned char *arr)
{
memset(arr, 0, 0x3c);
arr[0] = 0;
- arr[1] = 1;
+ arr[1] = 1; /* non rotating medium (e.g. solid state) */
+ arr[2] = 0;
+ arr[3] = 5; /* less than 1.8" */
return 0x3c;
}
@@ -974,6 +1016,10 @@ static int resp_readcap16(struct scsi_cmnd * scp,
arr[11] = scsi_debug_sector_size & 0xff;
arr[13] = scsi_debug_physblk_exp & 0xf;
arr[14] = (scsi_debug_lowest_aligned >> 8) & 0x3f;
+
+ if (scsi_debug_unmap_granularity)
+ arr[14] |= 0x80; /* TPE */
+
arr[15] = scsi_debug_lowest_aligned & 0xff;
if (scsi_debug_dif) {
@@ -1887,6 +1933,70 @@ out:
return ret;
}
+static unsigned int map_state(sector_t lba, unsigned int *num)
+{
+ unsigned int granularity, alignment, mapped;
+ sector_t block, next, end;
+
+ granularity = scsi_debug_unmap_granularity;
+ alignment = granularity - scsi_debug_unmap_alignment;
+ block = lba + alignment;
+ do_div(block, granularity);
+
+ mapped = test_bit(block, map_storep);
+
+ if (mapped)
+ next = find_next_zero_bit(map_storep, map_size, block);
+ else
+ next = find_next_bit(map_storep, map_size, block);
+
+ end = next * granularity - scsi_debug_unmap_alignment;
+ *num = end - lba;
+
+ return mapped;
+}
+
+static void map_region(sector_t lba, unsigned int len)
+{
+ unsigned int granularity, alignment;
+ sector_t end = lba + len;
+
+ granularity = scsi_debug_unmap_granularity;
+ alignment = granularity - scsi_debug_unmap_alignment;
+
+ while (lba < end) {
+ sector_t block, rem;
+
+ block = lba + alignment;
+ rem = do_div(block, granularity);
+
+ set_bit(block, map_storep);
+
+ lba += granularity - rem;
+ }
+}
+
+static void unmap_region(sector_t lba, unsigned int len)
+{
+ unsigned int granularity, alignment;
+ sector_t end = lba + len;
+
+ granularity = scsi_debug_unmap_granularity;
+ alignment = granularity - scsi_debug_unmap_alignment;
+
+ while (lba < end) {
+ sector_t block, rem;
+
+ block = lba + alignment;
+ rem = do_div(block, granularity);
+
+ if (rem == 0 && lba + granularity <= end)
+ clear_bit(block, map_storep);
+
+ lba += granularity - rem;
+ }
+}
+
static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
unsigned int num, struct sdebug_dev_info *devip,
u32 ei_lba)
@@ -1910,6 +2020,8 @@ static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
write_lock_irqsave(&atomic_rw, iflags);
ret = do_device_access(SCpnt, devip, lba, num, 1);
+ if (scsi_debug_unmap_granularity)
+ map_region(lba, num);
write_unlock_irqrestore(&atomic_rw, iflags);
if (-1 == ret)
return (DID_ERROR << 16);
@@ -1917,9 +2029,143 @@ static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
(SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
" IO sent=%d bytes\n", num * scsi_debug_sector_size, ret);
+
+ return 0;
+}
+
+static int resp_write_same(struct scsi_cmnd *scmd, unsigned long long lba,
+ unsigned int num, struct sdebug_dev_info *devip,
+ u32 ei_lba, unsigned int unmap)
+{
+ unsigned long iflags;
+ unsigned long long i;
+ int ret;
+
+ ret = check_device_access_params(devip, lba, num);
+ if (ret)
+ return ret;
+
+ write_lock_irqsave(&atomic_rw, iflags);
+
+ if (unmap && scsi_debug_unmap_granularity) {
+ unmap_region(lba, num);
+ goto out;
+ }
+
+ /* Else fetch one logical block */
+ ret = fetch_to_dev_buffer(scmd,
+ fake_storep + (lba * scsi_debug_sector_size),
+ scsi_debug_sector_size);
+
+ if (-1 == ret) {
+ write_unlock_irqrestore(&atomic_rw, iflags);
+ return (DID_ERROR << 16);
+ } else if ((ret < (num * scsi_debug_sector_size)) &&
+ (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
+ printk(KERN_INFO "scsi_debug: write same: cdb indicated=%u, "
+ " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret);
+
+ /* Copy first sector to remaining blocks */
+ for (i = 1 ; i < num ; i++)
+ memcpy(fake_storep + ((lba + i) * scsi_debug_sector_size),
+ fake_storep + (lba * scsi_debug_sector_size),
+ scsi_debug_sector_size);
+
+ if (scsi_debug_unmap_granularity)
+ map_region(lba, num);
+out:
+ write_unlock_irqrestore(&atomic_rw, iflags);
+
return 0;
}
+struct unmap_block_desc {
+ __be64 lba;
+ __be32 blocks;
+ __be32 __reserved;
+};
+
+static int resp_unmap(struct scsi_cmnd * scmd, struct sdebug_dev_info * devip)
+{
+ unsigned char *buf;
+ struct unmap_block_desc *desc;
+ unsigned int i, payload_len, descriptors;
+ int ret;
+
+ ret = check_readiness(scmd, 1, devip);
+ if (ret)
+ return ret;
+
+ payload_len = get_unaligned_be16(&scmd->cmnd[7]);
+ BUG_ON(scsi_bufflen(scmd) != payload_len);
+
+ descriptors = (payload_len - 8) / 16;
+
+ buf = kmalloc(scsi_bufflen(scmd), GFP_ATOMIC);
+ if (!buf)
+ return check_condition_result;
+
+ scsi_sg_copy_to_buffer(scmd, buf, scsi_bufflen(scmd));
+
+ BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
+ BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
+
+ desc = (void *)&buf[8];
+
+ for (i = 0 ; i < descriptors ; i++) {
+ unsigned long long lba = get_unaligned_be64(&desc[i].lba);
+ unsigned int num = get_unaligned_be32(&desc[i].blocks);
+
+ ret = check_device_access_params(devip, lba, num);
+ if (ret)
+ goto out;
+
+ unmap_region(lba, num);
+ }
+
+ ret = 0;
+
+out:
+ kfree(buf);
+
+ return ret;
+}
+
+#define SDEBUG_GET_LBA_STATUS_LEN 32
+
+static int resp_get_lba_status(struct scsi_cmnd * scmd,
+ struct sdebug_dev_info * devip)
+{
+ unsigned long long lba;
+ unsigned int alloc_len, mapped, num;
+ unsigned char arr[SDEBUG_GET_LBA_STATUS_LEN];
+ int ret;
+
+ ret = check_readiness(scmd, 1, devip);
+ if (ret)
+ return ret;
+
+ lba = get_unaligned_be64(&scmd->cmnd[2]);
+ alloc_len = get_unaligned_be32(&scmd->cmnd[10]);
+
+ if (alloc_len < 24)
+ return 0;
+
+ ret = check_device_access_params(devip, lba, 1);
+ if (ret)
+ return ret;
+
+ mapped = map_state(lba, &num);
+
+ memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
+ put_unaligned_be32(16, &arr[0]); /* Parameter Data Length */
+ put_unaligned_be64(lba, &arr[8]); /* LBA */
+ put_unaligned_be32(num, &arr[16]); /* Number of blocks */
+ arr[20] = !mapped; /* mapped = 0, unmapped = 1 */
+
+ return fill_from_dev_buffer(scmd, arr, SDEBUG_GET_LBA_STATUS_LEN);
+}
+
#define SDEBUG_RLUN_ARR_SZ 256
static int resp_report_luns(struct scsi_cmnd * scp,
@@ -2430,6 +2676,10 @@ module_param_named(guard, scsi_debug_guard, int, S_IRUGO);
module_param_named(ato, scsi_debug_ato, int, S_IRUGO);
module_param_named(physblk_exp, scsi_debug_physblk_exp, int, S_IRUGO);
module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO);
+module_param_named(unmap_max_blocks, scsi_debug_unmap_max_blocks, int, S_IRUGO);
+module_param_named(unmap_max_desc, scsi_debug_unmap_max_desc, int, S_IRUGO);
+module_param_named(unmap_granularity, scsi_debug_unmap_granularity, int, S_IRUGO);
+module_param_named(unmap_alignment, scsi_debug_unmap_alignment, int, S_IRUGO);
MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
MODULE_DESCRIPTION("SCSI debug adapter driver");
@@ -2458,6 +2708,10 @@ MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
+MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0)");
+MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=0)");
+MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=0)");
+MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
static char sdebug_info[256];
@@ -2816,6 +3070,23 @@ static ssize_t sdebug_ato_show(struct device_driver *ddp, char *buf)
}
DRIVER_ATTR(ato, S_IRUGO, sdebug_ato_show, NULL);
+static ssize_t sdebug_map_show(struct device_driver *ddp, char *buf)
+{
+ ssize_t count;
+
+ if (scsi_debug_unmap_granularity == 0)
+ return scnprintf(buf, PAGE_SIZE, "0-%u\n",
+ sdebug_store_sectors);
+
+ count = bitmap_scnlistprintf(buf, PAGE_SIZE, map_storep, map_size);
+
+ buf[count++] = '\n';
+ buf[count++] = 0;
+
+ return count;
+}
+DRIVER_ATTR(map, S_IRUGO, sdebug_map_show, NULL);
+
/* Note: The following function creates attribute files in the
/sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
@@ -2847,11 +3118,13 @@ static int do_create_driverfs_files(void)
ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dif);
ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_guard);
ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ato);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_map);
return ret;
}
static void do_remove_driverfs_files(void)
{
+ driver_remove_file(&sdebug_driverfs_driver, &driver_attr_map);
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ato);
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_guard);
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dif);
@@ -2989,6 +3262,36 @@ static int __init scsi_debug_init(void)
memset(dif_storep, 0xff, dif_size);
}
+ if (scsi_debug_unmap_granularity) {
+ unsigned int map_bytes;
+
+ if (scsi_debug_unmap_granularity < scsi_debug_unmap_alignment) {
+ printk(KERN_ERR
+ "%s: ERR: unmap_granularity < unmap_alignment\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ map_size = (sdebug_store_sectors / scsi_debug_unmap_granularity);
+ map_bytes = map_size >> 3;
+ map_storep = vmalloc(map_bytes);
+
+ printk(KERN_INFO "scsi_debug_init: %lu provisioning blocks\n",
+ map_size);
+
+ if (map_storep == NULL) {
+ printk(KERN_ERR "scsi_debug_init: out of mem. (MAP)\n");
+ ret = -ENOMEM;
+ goto free_vm;
+ }
+
+ memset(map_storep, 0x0, map_bytes);
+
+ /* Map first 1KB for partition table */
+ if (scsi_debug_num_parts)
+ map_region(0, 2);
+ }
+
ret = device_register(&pseudo_primary);
if (ret < 0) {
printk(KERN_WARNING "scsi_debug: device_register error: %d\n",
@@ -3041,6 +3344,8 @@ bus_unreg:
dev_unreg:
device_unregister(&pseudo_primary);
free_vm:
+ if (map_storep)
+ vfree(map_storep);
if (dif_storep)
vfree(dif_storep);
vfree(fake_storep);
@@ -3167,6 +3472,7 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
int inj_dif = 0;
int inj_dix = 0;
int delay_override = 0;
+ int unmap = 0;
scsi_set_resid(SCpnt, 0);
if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
@@ -3272,13 +3578,21 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
errsts = resp_readcap(SCpnt, devip);
break;
case SERVICE_ACTION_IN:
- if (SAI_READ_CAPACITY_16 != cmd[1]) {
+ if (cmd[1] == SAI_READ_CAPACITY_16)
+ errsts = resp_readcap16(SCpnt, devip);
+ else if (cmd[1] == SAI_GET_LBA_STATUS) {
+
+ if (scsi_debug_unmap_max_desc == 0) {
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ INVALID_COMMAND_OPCODE, 0);
+ errsts = check_condition_result;
+ } else
+ errsts = resp_get_lba_status(SCpnt, devip);
+ } else {
mk_sense_buffer(devip, ILLEGAL_REQUEST,
INVALID_OPCODE, 0);
errsts = check_condition_result;
- break;
}
- errsts = resp_readcap16(SCpnt, devip);
break;
case MAINTENANCE_IN:
if (MI_REPORT_TARGET_PGS != cmd[1]) {
@@ -3378,6 +3692,29 @@ write:
errsts = illegal_condition_result;
}
break;
+ case WRITE_SAME_16:
+ if (cmd[1] & 0x8)
+ unmap = 1;
+ /* fall through */
+ case WRITE_SAME:
+ errsts = check_readiness(SCpnt, 0, devip);
+ if (errsts)
+ break;
+ get_data_transfer_info(cmd, &lba, &num, &ei_lba);
+ errsts = resp_write_same(SCpnt, lba, num, devip, ei_lba, unmap);
+ break;
+ case UNMAP:
+ errsts = check_readiness(SCpnt, 0, devip);
+ if (errsts)
+ break;
+
+ if (scsi_debug_unmap_max_desc == 0) {
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ INVALID_COMMAND_OPCODE, 0);
+ errsts = check_condition_result;
+ } else
+ errsts = resp_unmap(SCpnt, devip);
+ break;
case MODE_SENSE:
case MODE_SENSE_10:
errsts = resp_mode_sense(SCpnt, target, devip);
diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c
index 93c2622..37af178 100644
--- a/drivers/scsi/scsi_devinfo.c
+++ b/drivers/scsi/scsi_devinfo.c
@@ -168,11 +168,10 @@ static struct {
{"Generic", "USB SD Reader", "1.00", BLIST_FORCELUN | BLIST_INQUIRY_36},
{"Generic", "USB Storage-SMC", "0180", BLIST_FORCELUN | BLIST_INQUIRY_36},
{"Generic", "USB Storage-SMC", "0207", BLIST_FORCELUN | BLIST_INQUIRY_36},
- {"HITACHI", "DF400", "*", BLIST_SPARSELUN},
- {"HITACHI", "DF500", "*", BLIST_SPARSELUN},
- {"HITACHI", "DF600", "*", BLIST_SPARSELUN},
- {"HITACHI", "DISK-SUBSYSTEM", "*", BLIST_ATTACH_PQ3 | BLIST_SPARSELUN | BLIST_LARGELUN},
- {"HITACHI", "OPEN-E", "*", BLIST_ATTACH_PQ3 | BLIST_SPARSELUN | BLIST_LARGELUN},
+ {"HITACHI", "DF400", "*", BLIST_REPORTLUN2},
+ {"HITACHI", "DF500", "*", BLIST_REPORTLUN2},
+ {"HITACHI", "DISK-SUBSYSTEM", "*", BLIST_REPORTLUN2},
+ {"HITACHI", "OPEN-", "*", BLIST_REPORTLUN2},
{"HITACHI", "OP-C-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
{"HITACHI", "3380-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
{"HITACHI", "3390-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
@@ -454,7 +453,7 @@ int scsi_get_device_flags(struct scsi_device *sdev,
/**
- * get_device_flags_keyed - get device specific flags from the dynamic device list.
+ * scsi_get_device_flags_keyed - get device specific flags from the dynamic device list
* @sdev: &scsi_device to get flags for
* @vendor: vendor name
* @model: model name
@@ -685,7 +684,7 @@ MODULE_PARM_DESC(default_dev_flags,
"scsi default device flag integer value");
/**
- * scsi_dev_info_list_delete - called from scsi.c:exit_scsi to remove the scsi_dev_info_list.
+ * scsi_exit_devinfo - remove /proc/scsi/device_info & the scsi_dev_info_list
**/
void scsi_exit_devinfo(void)
{
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 1b0060b..08ed506 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -331,6 +331,64 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
}
}
+static void scsi_handle_queue_ramp_up(struct scsi_device *sdev)
+{
+ struct scsi_host_template *sht = sdev->host->hostt;
+ struct scsi_device *tmp_sdev;
+
+ if (!sht->change_queue_depth ||
+ sdev->queue_depth >= sdev->max_queue_depth)
+ return;
+
+ if (time_before(jiffies,
+ sdev->last_queue_ramp_up + sdev->queue_ramp_up_period))
+ return;
+
+ if (time_before(jiffies,
+ sdev->last_queue_full_time + sdev->queue_ramp_up_period))
+ return;
+
+ /*
+ * Walk all devices of a target and do
+ * ramp up on them.
+ */
+ shost_for_each_device(tmp_sdev, sdev->host) {
+ if (tmp_sdev->channel != sdev->channel ||
+ tmp_sdev->id != sdev->id ||
+ tmp_sdev->queue_depth == sdev->max_queue_depth)
+ continue;
+ /*
+ * call back into LLD to increase queue_depth by one
+ * with ramp up reason code.
+ */
+ sht->change_queue_depth(tmp_sdev, tmp_sdev->queue_depth + 1,
+ SCSI_QDEPTH_RAMP_UP);
+ sdev->last_queue_ramp_up = jiffies;
+ }
+}
+
+static void scsi_handle_queue_full(struct scsi_device *sdev)
+{
+ struct scsi_host_template *sht = sdev->host->hostt;
+ struct scsi_device *tmp_sdev;
+
+ if (!sht->change_queue_depth)
+ return;
+
+ shost_for_each_device(tmp_sdev, sdev->host) {
+ if (tmp_sdev->channel != sdev->channel ||
+ tmp_sdev->id != sdev->id)
+ continue;
+ /*
+ * We do not know the number of commands that were at
+ * the device when we got the queue full so we start
+ * from the highest possible value and work our way down.
+ */
+ sht->change_queue_depth(tmp_sdev, tmp_sdev->queue_depth - 1,
+ SCSI_QDEPTH_QFULL);
+ }
+}
+
/**
* scsi_eh_completed_normally - Disposition a eh cmd on return from LLD.
* @scmd: SCSI cmd to examine.
@@ -371,6 +429,7 @@ static int scsi_eh_completed_normally(struct scsi_cmnd *scmd)
*/
switch (status_byte(scmd->result)) {
case GOOD:
+ scsi_handle_queue_ramp_up(scmd->device);
case COMMAND_TERMINATED:
return SUCCESS;
case CHECK_CONDITION:
@@ -387,8 +446,10 @@ static int scsi_eh_completed_normally(struct scsi_cmnd *scmd)
* let issuer deal with this, it could be just fine
*/
return SUCCESS;
- case BUSY:
case QUEUE_FULL:
+ scsi_handle_queue_full(scmd->device);
+ /* fall through */
+ case BUSY:
default:
return FAILED;
}
@@ -1387,6 +1448,7 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd)
*/
switch (status_byte(scmd->result)) {
case QUEUE_FULL:
+ scsi_handle_queue_full(scmd->device);
/*
* the case of trying to send too many commands to a
* tagged queueing device.
@@ -1400,6 +1462,7 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd)
*/
return ADD_TO_MLQUEUE;
case GOOD:
+ scsi_handle_queue_ramp_up(scmd->device);
case COMMAND_TERMINATED:
return SUCCESS;
case TASK_ABORTED:
diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c
index b98f763..d9564fb 100644
--- a/drivers/scsi/scsi_ioctl.c
+++ b/drivers/scsi/scsi_ioctl.c
@@ -308,6 +308,9 @@ int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd,
case SG_SCSI_RESET_DEVICE:
val = SCSI_TRY_RESET_DEVICE;
break;
+ case SG_SCSI_RESET_TARGET:
+ val = SCSI_TRY_RESET_TARGET;
+ break;
case SG_SCSI_RESET_BUS:
val = SCSI_TRY_RESET_BUS;
break;
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 5987da8..e495d38 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -898,7 +898,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
scsi_print_sense("", cmd);
scsi_print_command(cmd);
}
- if (blk_end_request_err(req, -EIO))
+ if (blk_end_request_err(req, error))
scsi_requeue_command(q, cmd);
else
scsi_next_command(cmd);
@@ -1359,9 +1359,9 @@ static int scsi_lld_busy(struct request_queue *q)
static void scsi_kill_request(struct request *req, struct request_queue *q)
{
struct scsi_cmnd *cmd = req->special;
- struct scsi_device *sdev = cmd->device;
- struct scsi_target *starget = scsi_target(sdev);
- struct Scsi_Host *shost = sdev->host;
+ struct scsi_device *sdev;
+ struct scsi_target *starget;
+ struct Scsi_Host *shost;
blk_start_request(req);
@@ -1371,6 +1371,9 @@ static void scsi_kill_request(struct request *req, struct request_queue *q)
BUG();
}
+ sdev = cmd->device;
+ starget = scsi_target(sdev);
+ shost = sdev->host;
scsi_init_cmd_errh(cmd);
cmd->result = DID_NO_CONNECT << 16;
atomic_inc(&cmd->device->iorequest_cnt);
diff --git a/drivers/scsi/scsi_lib_dma.c b/drivers/scsi/scsi_lib_dma.c
index ac6855c..dcd1285 100644
--- a/drivers/scsi/scsi_lib_dma.c
+++ b/drivers/scsi/scsi_lib_dma.c
@@ -23,7 +23,7 @@ int scsi_dma_map(struct scsi_cmnd *cmd)
int nseg = 0;
if (scsi_sg_count(cmd)) {
- struct device *dev = cmd->device->host->shost_gendev.parent;
+ struct device *dev = cmd->device->host->dma_dev;
nseg = dma_map_sg(dev, scsi_sglist(cmd), scsi_sg_count(cmd),
cmd->sc_data_direction);
@@ -41,7 +41,7 @@ EXPORT_SYMBOL(scsi_dma_map);
void scsi_dma_unmap(struct scsi_cmnd *cmd)
{
if (scsi_sg_count(cmd)) {
- struct device *dev = cmd->device->host->shost_gendev.parent;
+ struct device *dev = cmd->device->host->dma_dev;
dma_unmap_sg(dev, scsi_sglist(cmd), scsi_sg_count(cmd),
cmd->sc_data_direction);
diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c
index 723fdec..0fd6ae6 100644
--- a/drivers/scsi/scsi_netlink.c
+++ b/drivers/scsi/scsi_netlink.c
@@ -613,7 +613,7 @@ EXPORT_SYMBOL_GPL(scsi_nl_send_transport_msg);
* @data_buf: pointer to vendor unique data buffer
*
* Returns:
- * 0 on succesful return
+ * 0 on successful return
* otherwise, failing error code
*
* Notes:
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 47291bc..012f73a 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -251,6 +251,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
sdev->model = scsi_null_device_strs;
sdev->rev = scsi_null_device_strs;
sdev->host = shost;
+ sdev->queue_ramp_up_period = SCSI_DEFAULT_RAMP_UP_PERIOD;
sdev->id = starget->id;
sdev->lun = lun;
sdev->channel = starget->channel;
@@ -941,6 +942,8 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
}
}
+ sdev->max_queue_depth = sdev->queue_depth;
+
/*
* Ok, the device is now all set up, we can
* register it and tell the rest of the kernel
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 392d8db..5a06505 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -766,10 +766,13 @@ sdev_store_queue_depth_rw(struct device *dev, struct device_attribute *attr,
if (depth < 1)
return -EINVAL;
- retval = sht->change_queue_depth(sdev, depth);
+ retval = sht->change_queue_depth(sdev, depth,
+ SCSI_QDEPTH_DEFAULT);
if (retval < 0)
return retval;
+ sdev->max_queue_depth = sdev->queue_depth;
+
return count;
}
@@ -778,6 +781,37 @@ static struct device_attribute sdev_attr_queue_depth_rw =
sdev_store_queue_depth_rw);
static ssize_t
+sdev_show_queue_ramp_up_period(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct scsi_device *sdev;
+ sdev = to_scsi_device(dev);
+ return snprintf(buf, 20, "%u\n",
+ jiffies_to_msecs(sdev->queue_ramp_up_period));
+}
+
+static ssize_t
+sdev_store_queue_ramp_up_period(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ unsigned long period;
+
+ if (strict_strtoul(buf, 10, &period))
+ return -EINVAL;
+
+ sdev->queue_ramp_up_period = msecs_to_jiffies(period);
+ return period;
+}
+
+static struct device_attribute sdev_attr_queue_ramp_up_period =
+ __ATTR(queue_ramp_up_period, S_IRUGO | S_IWUSR,
+ sdev_show_queue_ramp_up_period,
+ sdev_store_queue_ramp_up_period);
+
+static ssize_t
sdev_store_queue_type_rw(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
@@ -867,8 +901,12 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
sdev->is_visible = 1;
/* 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);
+ if (sdev->host->hostt->change_queue_depth) {
+ error = device_create_file(&sdev->sdev_gendev,
+ &sdev_attr_queue_depth_rw);
+ error = device_create_file(&sdev->sdev_gendev,
+ &sdev_attr_queue_ramp_up_period);
+ }
else
error = device_create_file(&sdev->sdev_gendev, &dev_attr_queue_depth);
if (error)
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index c6f70da..6531c91 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -27,6 +27,7 @@
*/
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/delay.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_transport.h>
@@ -2384,6 +2385,7 @@ fc_rport_final_delete(struct work_struct *work)
struct Scsi_Host *shost = rport_to_shost(rport);
struct fc_internal *i = to_fc_internal(shost->transportt);
unsigned long flags;
+ int do_callback = 0;
/*
* if a scan is pending, flush the SCSI Host work_q so that
@@ -2422,8 +2424,15 @@ fc_rport_final_delete(struct work_struct *work)
* Avoid this call if we already called it when we preserved the
* rport for the binding.
*/
+ spin_lock_irqsave(shost->host_lock, flags);
if (!(rport->flags & FC_RPORT_DEVLOSS_CALLBK_DONE) &&
- (i->f->dev_loss_tmo_callbk))
+ (i->f->dev_loss_tmo_callbk)) {
+ rport->flags |= FC_RPORT_DEVLOSS_CALLBK_DONE;
+ do_callback = 1;
+ }
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
+ if (do_callback)
i->f->dev_loss_tmo_callbk(rport);
fc_bsg_remove(rport->rqst_q);
@@ -2970,6 +2979,7 @@ fc_timeout_deleted_rport(struct work_struct *work)
struct fc_internal *i = to_fc_internal(shost->transportt);
struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
unsigned long flags;
+ int do_callback = 0;
spin_lock_irqsave(shost->host_lock, flags);
@@ -3035,7 +3045,6 @@ fc_timeout_deleted_rport(struct work_struct *work)
rport->roles = FC_PORT_ROLE_UNKNOWN;
rport->port_state = FC_PORTSTATE_NOTPRESENT;
rport->flags &= ~FC_RPORT_FAST_FAIL_TIMEDOUT;
- rport->flags |= FC_RPORT_DEVLOSS_CALLBK_DONE;
/*
* Pre-emptively kill I/O rather than waiting for the work queue
@@ -3045,32 +3054,40 @@ fc_timeout_deleted_rport(struct work_struct *work)
spin_unlock_irqrestore(shost->host_lock, flags);
fc_terminate_rport_io(rport);
- BUG_ON(rport->port_state != FC_PORTSTATE_NOTPRESENT);
+ spin_lock_irqsave(shost->host_lock, flags);
+
+ if (rport->port_state == FC_PORTSTATE_NOTPRESENT) { /* still missing */
- /* remove the identifiers that aren't used in the consisting binding */
- switch (fc_host->tgtid_bind_type) {
- case FC_TGTID_BIND_BY_WWPN:
- rport->node_name = -1;
- rport->port_id = -1;
- break;
- case FC_TGTID_BIND_BY_WWNN:
- rport->port_name = -1;
- rport->port_id = -1;
- break;
- case FC_TGTID_BIND_BY_ID:
- rport->node_name = -1;
- rport->port_name = -1;
- break;
- case FC_TGTID_BIND_NONE: /* to keep compiler happy */
- break;
+ /* remove the identifiers that aren't used in the consisting binding */
+ switch (fc_host->tgtid_bind_type) {
+ case FC_TGTID_BIND_BY_WWPN:
+ rport->node_name = -1;
+ rport->port_id = -1;
+ break;
+ case FC_TGTID_BIND_BY_WWNN:
+ rport->port_name = -1;
+ rport->port_id = -1;
+ break;
+ case FC_TGTID_BIND_BY_ID:
+ rport->node_name = -1;
+ rport->port_name = -1;
+ break;
+ case FC_TGTID_BIND_NONE: /* to keep compiler happy */
+ break;
+ }
+
+ /*
+ * As this only occurs if the remote port (scsi target)
+ * went away and didn't come back - we'll remove
+ * all attached scsi devices.
+ */
+ rport->flags |= FC_RPORT_DEVLOSS_CALLBK_DONE;
+ fc_queue_work(shost, &rport->stgt_delete_work);
+
+ do_callback = 1;
}
- /*
- * As this only occurs if the remote port (scsi target)
- * went away and didn't come back - we'll remove
- * all attached scsi devices.
- */
- fc_queue_work(shost, &rport->stgt_delete_work);
+ spin_unlock_irqrestore(shost->host_lock, flags);
/*
* Notify the driver that the rport is now dead. The LLDD will
@@ -3078,7 +3095,7 @@ fc_timeout_deleted_rport(struct work_struct *work)
*
* Note: we set the CALLBK_DONE flag above to correspond
*/
- if (i->f->dev_loss_tmo_callbk)
+ if (do_callback && i->f->dev_loss_tmo_callbk)
i->f->dev_loss_tmo_callbk(rport);
}
@@ -3128,6 +3145,31 @@ fc_scsi_scan_rport(struct work_struct *work)
spin_unlock_irqrestore(shost->host_lock, flags);
}
+/**
+ * fc_block_scsi_eh - Block SCSI eh thread for blocked fc_rport
+ * @cmnd: SCSI command that scsi_eh is trying to recover
+ *
+ * This routine can be called from a FC LLD scsi_eh callback. It
+ * blocks the scsi_eh thread until the fc_rport leaves the
+ * FC_PORTSTATE_BLOCKED. This is necessary to avoid the scsi_eh
+ * failing recovery actions for blocked rports which would lead to
+ * offlined SCSI devices.
+ */
+void fc_block_scsi_eh(struct scsi_cmnd *cmnd)
+{
+ struct Scsi_Host *shost = cmnd->device->host;
+ struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device));
+ unsigned long flags;
+
+ spin_lock_irqsave(shost->host_lock, flags);
+ while (rport->port_state == FC_PORTSTATE_BLOCKED) {
+ spin_unlock_irqrestore(shost->host_lock, flags);
+ msleep(1000);
+ spin_lock_irqsave(shost->host_lock, flags);
+ }
+ spin_unlock_irqrestore(shost->host_lock, flags);
+}
+EXPORT_SYMBOL(fc_block_scsi_eh);
/**
* fc_vport_setup - allocates and creates a FC virtual port.
@@ -3769,8 +3811,9 @@ fc_bsg_request_handler(struct request_queue *q, struct Scsi_Host *shost,
return;
while (!blk_queue_plugged(q)) {
- if (rport && (rport->port_state == FC_PORTSTATE_BLOCKED))
- break;
+ if (rport && (rport->port_state == FC_PORTSTATE_BLOCKED) &&
+ !(rport->flags & FC_RPORT_FAST_FAIL_TIMEDOUT))
+ break;
req = blk_fetch_request(q);
if (!req)
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index ad897df..ea3892e 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -30,7 +30,7 @@
#include <scsi/scsi_transport_iscsi.h>
#include <scsi/iscsi_if.h>
-#define ISCSI_SESSION_ATTRS 21
+#define ISCSI_SESSION_ATTRS 22
#define ISCSI_CONN_ATTRS 13
#define ISCSI_HOST_ATTRS 4
@@ -627,8 +627,10 @@ static void __iscsi_block_session(struct work_struct *work)
spin_unlock_irqrestore(&session->lock, flags);
scsi_target_block(&session->dev);
ISCSI_DBG_TRANS_SESSION(session, "Completed SCSI target blocking\n");
- queue_delayed_work(iscsi_eh_timer_workq, &session->recovery_work,
- session->recovery_tmo * HZ);
+ if (session->recovery_tmo >= 0)
+ queue_delayed_work(iscsi_eh_timer_workq,
+ &session->recovery_work,
+ session->recovery_tmo * HZ);
}
void iscsi_block_session(struct iscsi_cls_session *session)
@@ -1348,8 +1350,7 @@ iscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev)
switch (ev->u.set_param.param) {
case ISCSI_PARAM_SESS_RECOVERY_TMO:
sscanf(data, "%d", &value);
- if (value != 0)
- session->recovery_tmo = value;
+ session->recovery_tmo = value;
break;
default:
err = transport->set_param(conn, ev->u.set_param.param,
@@ -1759,6 +1760,7 @@ iscsi_session_attr(password_in, ISCSI_PARAM_PASSWORD_IN, 1);
iscsi_session_attr(fast_abort, ISCSI_PARAM_FAST_ABORT, 0);
iscsi_session_attr(abort_tmo, ISCSI_PARAM_ABORT_TMO, 0);
iscsi_session_attr(lu_reset_tmo, ISCSI_PARAM_LU_RESET_TMO, 0);
+iscsi_session_attr(tgt_reset_tmo, ISCSI_PARAM_TGT_RESET_TMO, 0);
iscsi_session_attr(ifacename, ISCSI_PARAM_IFACE_NAME, 0);
iscsi_session_attr(initiatorname, ISCSI_PARAM_INITIATOR_NAME, 0)
@@ -2000,6 +2002,7 @@ iscsi_register_transport(struct iscsi_transport *tt)
SETUP_SESSION_RD_ATTR(fast_abort, ISCSI_FAST_ABORT);
SETUP_SESSION_RD_ATTR(abort_tmo, ISCSI_ABORT_TMO);
SETUP_SESSION_RD_ATTR(lu_reset_tmo,ISCSI_LU_RESET_TMO);
+ SETUP_SESSION_RD_ATTR(tgt_reset_tmo,ISCSI_TGT_RESET_TMO);
SETUP_SESSION_RD_ATTR(ifacename, ISCSI_IFACE_NAME);
SETUP_SESSION_RD_ATTR(initiatorname, ISCSI_INITIATOR_NAME);
SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo);
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index fd47cb1..f27e52d 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -666,7 +666,7 @@ EXPORT_SYMBOL(sas_phy_add);
*
* Note:
* This function must only be called on a PHY that has not
- * sucessfully been added using sas_phy_add().
+ * successfully been added using sas_phy_add().
*/
void sas_phy_free(struct sas_phy *phy)
{
@@ -896,7 +896,7 @@ EXPORT_SYMBOL(sas_port_add);
*
* Note:
* This function must only be called on a PORT that has not
- * sucessfully been added using sas_port_add().
+ * successfully been added using sas_port_add().
*/
void sas_port_free(struct sas_port *port)
{
@@ -1476,7 +1476,7 @@ EXPORT_SYMBOL(sas_rphy_add);
*
* Note:
* This function must only be called on a remote
- * PHY that has not sucessfully been added using
+ * PHY that has not successfully been added using
* sas_rphy_add() (or has been sas_rphy_remove()'d)
*/
void sas_rphy_free(struct sas_rphy *rphy)
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 12d58a7..ad59abb 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -2280,7 +2280,8 @@ static int st_set_options(struct scsi_tape *STp, long options)
} else if (code == MT_ST_SET_CLN) {
value = (options & ~MT_ST_OPTIONS) & 0xff;
if (value != 0 &&
- value < EXTENDED_SENSE_START && value >= SCSI_SENSE_BUFFERSIZE)
+ (value < EXTENDED_SENSE_START ||
+ value >= SCSI_SENSE_BUFFERSIZE))
return (-EINVAL);
STp->cln_mode = value;
STp->cln_sense_mask = (options >> 8) & 0xff;
diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c
index 09fa886..3058bb1 100644
--- a/drivers/scsi/stex.c
+++ b/drivers/scsi/stex.c
@@ -36,11 +36,11 @@
#include <scsi/scsi_eh.h>
#define DRV_NAME "stex"
-#define ST_DRIVER_VERSION "4.6.0000.3"
+#define ST_DRIVER_VERSION "4.6.0000.4"
#define ST_VER_MAJOR 4
#define ST_VER_MINOR 6
#define ST_OEM 0
-#define ST_BUILD_VER 3
+#define ST_BUILD_VER 4
enum {
/* MU register offset */
@@ -64,24 +64,24 @@ enum {
YH2I_REQ_HI = 0xc4,
/* MU register value */
- MU_INBOUND_DOORBELL_HANDSHAKE = 1,
- MU_INBOUND_DOORBELL_REQHEADCHANGED = 2,
- MU_INBOUND_DOORBELL_STATUSTAILCHANGED = 4,
- MU_INBOUND_DOORBELL_HMUSTOPPED = 8,
- MU_INBOUND_DOORBELL_RESET = 16,
-
- MU_OUTBOUND_DOORBELL_HANDSHAKE = 1,
- MU_OUTBOUND_DOORBELL_REQUESTTAILCHANGED = 2,
- MU_OUTBOUND_DOORBELL_STATUSHEADCHANGED = 4,
- MU_OUTBOUND_DOORBELL_BUSCHANGE = 8,
- MU_OUTBOUND_DOORBELL_HASEVENT = 16,
+ MU_INBOUND_DOORBELL_HANDSHAKE = (1 << 0),
+ MU_INBOUND_DOORBELL_REQHEADCHANGED = (1 << 1),
+ MU_INBOUND_DOORBELL_STATUSTAILCHANGED = (1 << 2),
+ MU_INBOUND_DOORBELL_HMUSTOPPED = (1 << 3),
+ MU_INBOUND_DOORBELL_RESET = (1 << 4),
+
+ MU_OUTBOUND_DOORBELL_HANDSHAKE = (1 << 0),
+ MU_OUTBOUND_DOORBELL_REQUESTTAILCHANGED = (1 << 1),
+ MU_OUTBOUND_DOORBELL_STATUSHEADCHANGED = (1 << 2),
+ MU_OUTBOUND_DOORBELL_BUSCHANGE = (1 << 3),
+ MU_OUTBOUND_DOORBELL_HASEVENT = (1 << 4),
+ MU_OUTBOUND_DOORBELL_REQUEST_RESET = (1 << 27),
/* MU status code */
MU_STATE_STARTING = 1,
- MU_STATE_FMU_READY_FOR_HANDSHAKE = 2,
- MU_STATE_SEND_HANDSHAKE_FRAME = 3,
- MU_STATE_STARTED = 4,
- MU_STATE_RESETTING = 5,
+ MU_STATE_STARTED = 2,
+ MU_STATE_RESETTING = 3,
+ MU_STATE_FAILED = 4,
MU_MAX_DELAY = 120,
MU_HANDSHAKE_SIGNATURE = 0x55aaaa55,
@@ -111,6 +111,8 @@ enum {
SS_H2I_INT_RESET = 0x100,
+ SS_I2H_REQUEST_RESET = 0x2000,
+
SS_MU_OPERATIONAL = 0x80000000,
STEX_CDB_LENGTH = 16,
@@ -160,6 +162,7 @@ enum {
INQUIRY_EVPD = 0x01,
ST_ADDITIONAL_MEM = 0x200000,
+ ST_ADDITIONAL_MEM_MIN = 0x80000,
};
struct st_sgitem {
@@ -311,6 +314,10 @@ struct st_hba {
struct st_ccb *wait_ccb;
__le32 *scratch;
+ char work_q_name[20];
+ struct workqueue_struct *work_q;
+ struct work_struct reset_work;
+ wait_queue_head_t reset_waitq;
unsigned int mu_status;
unsigned int cardtype;
int msi_enabled;
@@ -577,6 +584,9 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
lun = cmd->device->lun;
hba = (struct st_hba *) &host->hostdata[0];
+ if (unlikely(hba->mu_status == MU_STATE_RESETTING))
+ return SCSI_MLQUEUE_HOST_BUSY;
+
switch (cmd->cmnd[0]) {
case MODE_SENSE_10:
{
@@ -841,7 +851,6 @@ static irqreturn_t stex_intr(int irq, void *__hba)
void __iomem *base = hba->mmio_base;
u32 data;
unsigned long flags;
- int handled = 0;
spin_lock_irqsave(hba->host->host_lock, flags);
@@ -852,12 +861,16 @@ static irqreturn_t stex_intr(int irq, void *__hba)
writel(data, base + ODBL);
readl(base + ODBL); /* flush */
stex_mu_intr(hba, data);
- handled = 1;
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ if (unlikely(data & MU_OUTBOUND_DOORBELL_REQUEST_RESET &&
+ hba->cardtype == st_shasta))
+ queue_work(hba->work_q, &hba->reset_work);
+ return IRQ_HANDLED;
}
spin_unlock_irqrestore(hba->host->host_lock, flags);
- return IRQ_RETVAL(handled);
+ return IRQ_NONE;
}
static void stex_ss_mu_intr(struct st_hba *hba)
@@ -939,7 +952,6 @@ static irqreturn_t stex_ss_intr(int irq, void *__hba)
void __iomem *base = hba->mmio_base;
u32 data;
unsigned long flags;
- int handled = 0;
spin_lock_irqsave(hba->host->host_lock, flags);
@@ -948,12 +960,15 @@ static irqreturn_t stex_ss_intr(int irq, void *__hba)
/* clear the interrupt */
writel(data, base + YI2H_INT_C);
stex_ss_mu_intr(hba);
- handled = 1;
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ if (unlikely(data & SS_I2H_REQUEST_RESET))
+ queue_work(hba->work_q, &hba->reset_work);
+ return IRQ_HANDLED;
}
spin_unlock_irqrestore(hba->host->host_lock, flags);
- return IRQ_RETVAL(handled);
+ return IRQ_NONE;
}
static int stex_common_handshake(struct st_hba *hba)
@@ -1001,7 +1016,7 @@ static int stex_common_handshake(struct st_hba *hba)
h->partner_type = HMU_PARTNER_TYPE;
if (hba->extra_offset) {
h->extra_offset = cpu_to_le32(hba->extra_offset);
- h->extra_size = cpu_to_le32(ST_ADDITIONAL_MEM);
+ h->extra_size = cpu_to_le32(hba->dma_size - hba->extra_offset);
} else
h->extra_offset = h->extra_size = 0;
@@ -1046,7 +1061,7 @@ static int stex_ss_handshake(struct st_hba *hba)
struct st_msg_header *msg_h;
struct handshake_frame *h;
__le32 *scratch;
- u32 data;
+ u32 data, scratch_size;
unsigned long before;
int ret = 0;
@@ -1074,13 +1089,16 @@ static int stex_ss_handshake(struct st_hba *hba)
stex_gettime(&h->hosttime);
h->partner_type = HMU_PARTNER_TYPE;
h->extra_offset = h->extra_size = 0;
- h->scratch_size = cpu_to_le32((hba->sts_count+1)*sizeof(u32));
+ scratch_size = (hba->sts_count+1)*sizeof(u32);
+ h->scratch_size = cpu_to_le32(scratch_size);
data = readl(base + YINT_EN);
data &= ~4;
writel(data, base + YINT_EN);
writel((hba->dma_handle >> 16) >> 16, base + YH2I_REQ_HI);
+ readl(base + YH2I_REQ_HI);
writel(hba->dma_handle, base + YH2I_REQ);
+ readl(base + YH2I_REQ); /* flush */
scratch = hba->scratch;
before = jiffies;
@@ -1096,7 +1114,7 @@ static int stex_ss_handshake(struct st_hba *hba)
msleep(1);
}
- *scratch = 0;
+ memset(scratch, 0, scratch_size);
msg_h->flag = 0;
return ret;
}
@@ -1105,19 +1123,24 @@ static int stex_handshake(struct st_hba *hba)
{
int err;
unsigned long flags;
+ unsigned int mu_status;
err = (hba->cardtype == st_yel) ?
stex_ss_handshake(hba) : stex_common_handshake(hba);
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ mu_status = hba->mu_status;
if (err == 0) {
- spin_lock_irqsave(hba->host->host_lock, flags);
hba->req_head = 0;
hba->req_tail = 0;
hba->status_head = 0;
hba->status_tail = 0;
hba->out_req_cnt = 0;
hba->mu_status = MU_STATE_STARTED;
- spin_unlock_irqrestore(hba->host->host_lock, flags);
- }
+ } else
+ hba->mu_status = MU_STATE_FAILED;
+ if (mu_status == MU_STATE_RESETTING)
+ wake_up_all(&hba->reset_waitq);
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
return err;
}
@@ -1137,17 +1160,11 @@ static int stex_abort(struct scsi_cmnd *cmd)
base = hba->mmio_base;
spin_lock_irqsave(host->host_lock, flags);
- if (tag < host->can_queue && hba->ccb[tag].cmd == cmd)
+ if (tag < host->can_queue &&
+ hba->ccb[tag].req && hba->ccb[tag].cmd == cmd)
hba->wait_ccb = &hba->ccb[tag];
- else {
- for (tag = 0; tag < host->can_queue; tag++)
- if (hba->ccb[tag].cmd == cmd) {
- hba->wait_ccb = &hba->ccb[tag];
- break;
- }
- if (tag >= host->can_queue)
- goto out;
- }
+ else
+ goto out;
if (hba->cardtype == st_yel) {
data = readl(base + YI2H_INT);
@@ -1221,6 +1238,37 @@ static void stex_hard_reset(struct st_hba *hba)
hba->pdev->saved_config_space[i]);
}
+static int stex_yos_reset(struct st_hba *hba)
+{
+ void __iomem *base;
+ unsigned long flags, before;
+ int ret = 0;
+
+ base = hba->mmio_base;
+ writel(MU_INBOUND_DOORBELL_RESET, base + IDBL);
+ readl(base + IDBL); /* flush */
+ before = jiffies;
+ while (hba->out_req_cnt > 0) {
+ if (time_after(jiffies, before + ST_INTERNAL_TIMEOUT * HZ)) {
+ printk(KERN_WARNING DRV_NAME
+ "(%s): reset timeout\n", pci_name(hba->pdev));
+ ret = -1;
+ break;
+ }
+ msleep(1);
+ }
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ if (ret == -1)
+ hba->mu_status = MU_STATE_FAILED;
+ else
+ hba->mu_status = MU_STATE_STARTED;
+ wake_up_all(&hba->reset_waitq);
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+ return ret;
+}
+
static void stex_ss_reset(struct st_hba *hba)
{
writel(SS_H2I_INT_RESET, hba->mmio_base + YH2I_INT);
@@ -1228,66 +1276,86 @@ static void stex_ss_reset(struct st_hba *hba)
ssleep(5);
}
-static int stex_reset(struct scsi_cmnd *cmd)
+static int stex_do_reset(struct st_hba *hba)
{
- struct st_hba *hba;
- void __iomem *base;
- unsigned long flags, before;
+ struct st_ccb *ccb;
+ unsigned long flags;
+ unsigned int mu_status = MU_STATE_RESETTING;
+ u16 tag;
- hba = (struct st_hba *) &cmd->device->host->hostdata[0];
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ if (hba->mu_status == MU_STATE_STARTING) {
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ printk(KERN_INFO DRV_NAME "(%s): request reset during init\n",
+ pci_name(hba->pdev));
+ return 0;
+ }
+ while (hba->mu_status == MU_STATE_RESETTING) {
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ wait_event_timeout(hba->reset_waitq,
+ hba->mu_status != MU_STATE_RESETTING,
+ MU_MAX_DELAY * HZ);
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ mu_status = hba->mu_status;
+ }
- printk(KERN_INFO DRV_NAME
- "(%s): resetting host\n", pci_name(hba->pdev));
- scsi_print_command(cmd);
+ if (mu_status != MU_STATE_RESETTING) {
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ return (mu_status == MU_STATE_STARTED) ? 0 : -1;
+ }
hba->mu_status = MU_STATE_RESETTING;
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+ if (hba->cardtype == st_yosemite)
+ return stex_yos_reset(hba);
if (hba->cardtype == st_shasta)
stex_hard_reset(hba);
else if (hba->cardtype == st_yel)
stex_ss_reset(hba);
- if (hba->cardtype != st_yosemite) {
- if (stex_handshake(hba)) {
- printk(KERN_WARNING DRV_NAME
- "(%s): resetting: handshake failed\n",
- pci_name(hba->pdev));
- return FAILED;
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ for (tag = 0; tag < hba->host->can_queue; tag++) {
+ ccb = &hba->ccb[tag];
+ if (ccb->req == NULL)
+ continue;
+ ccb->req = NULL;
+ if (ccb->cmd) {
+ scsi_dma_unmap(ccb->cmd);
+ ccb->cmd->result = DID_RESET << 16;
+ ccb->cmd->scsi_done(ccb->cmd);
+ ccb->cmd = NULL;
}
- return SUCCESS;
}
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
- /* st_yosemite */
- writel(MU_INBOUND_DOORBELL_RESET, hba->mmio_base + IDBL);
- readl(hba->mmio_base + IDBL); /* flush */
- before = jiffies;
- while (hba->out_req_cnt > 0) {
- if (time_after(jiffies, before + ST_INTERNAL_TIMEOUT * HZ)) {
- printk(KERN_WARNING DRV_NAME
- "(%s): reset timeout\n", pci_name(hba->pdev));
- return FAILED;
- }
- msleep(1);
- }
+ if (stex_handshake(hba) == 0)
+ return 0;
- base = hba->mmio_base;
- writel(0, base + IMR0);
- readl(base + IMR0);
- writel(0, base + OMR0);
- readl(base + OMR0);
- writel(0, base + IMR1);
- readl(base + IMR1);
- writel(0, base + OMR1);
- readl(base + OMR1); /* flush */
- spin_lock_irqsave(hba->host->host_lock, flags);
- hba->req_head = 0;
- hba->req_tail = 0;
- hba->status_head = 0;
- hba->status_tail = 0;
- hba->out_req_cnt = 0;
- hba->mu_status = MU_STATE_STARTED;
- spin_unlock_irqrestore(hba->host->host_lock, flags);
- return SUCCESS;
+ printk(KERN_WARNING DRV_NAME "(%s): resetting: handshake failed\n",
+ pci_name(hba->pdev));
+ return -1;
+}
+
+static int stex_reset(struct scsi_cmnd *cmd)
+{
+ struct st_hba *hba;
+
+ hba = (struct st_hba *) &cmd->device->host->hostdata[0];
+
+ printk(KERN_INFO DRV_NAME
+ "(%s): resetting host\n", pci_name(hba->pdev));
+ scsi_print_command(cmd);
+
+ return stex_do_reset(hba) ? FAILED : SUCCESS;
+}
+
+static void stex_reset_work(struct work_struct *work)
+{
+ struct st_hba *hba = container_of(work, struct st_hba, reset_work);
+
+ stex_do_reset(hba);
}
static int stex_biosparam(struct scsi_device *sdev,
@@ -1420,8 +1488,8 @@ static int stex_set_dma_mask(struct pci_dev * pdev)
{
int ret;
- if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
- && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)))
+ if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
+ && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)))
return 0;
ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (!ret)
@@ -1528,10 +1596,24 @@ stex_probe(struct pci_dev *pdev, const struct pci_device_id *id)
hba->dma_mem = dma_alloc_coherent(&pdev->dev,
hba->dma_size, &hba->dma_handle, GFP_KERNEL);
if (!hba->dma_mem) {
- err = -ENOMEM;
- printk(KERN_ERR DRV_NAME "(%s): dma mem alloc failed\n",
- pci_name(pdev));
- goto out_iounmap;
+ /* Retry minimum coherent mapping for st_seq and st_vsc */
+ if (hba->cardtype == st_seq ||
+ (hba->cardtype == st_vsc && (pdev->subsystem_device & 1))) {
+ printk(KERN_WARNING DRV_NAME
+ "(%s): allocating min buffer for controller\n",
+ pci_name(pdev));
+ hba->dma_size = hba->extra_offset
+ + ST_ADDITIONAL_MEM_MIN;
+ hba->dma_mem = dma_alloc_coherent(&pdev->dev,
+ hba->dma_size, &hba->dma_handle, GFP_KERNEL);
+ }
+
+ if (!hba->dma_mem) {
+ err = -ENOMEM;
+ printk(KERN_ERR DRV_NAME "(%s): dma mem alloc failed\n",
+ pci_name(pdev));
+ goto out_iounmap;
+ }
}
hba->ccb = kcalloc(ci->rq_count, sizeof(struct st_ccb), GFP_KERNEL);
@@ -1568,12 +1650,24 @@ stex_probe(struct pci_dev *pdev, const struct pci_device_id *id)
hba->host = host;
hba->pdev = pdev;
+ init_waitqueue_head(&hba->reset_waitq);
+
+ snprintf(hba->work_q_name, sizeof(hba->work_q_name),
+ "stex_wq_%d", host->host_no);
+ hba->work_q = create_singlethread_workqueue(hba->work_q_name);
+ if (!hba->work_q) {
+ printk(KERN_ERR DRV_NAME "(%s): create workqueue failed\n",
+ pci_name(pdev));
+ err = -ENOMEM;
+ goto out_ccb_free;
+ }
+ INIT_WORK(&hba->reset_work, stex_reset_work);
err = stex_request_irq(hba);
if (err) {
printk(KERN_ERR DRV_NAME "(%s): request irq failed\n",
pci_name(pdev));
- goto out_ccb_free;
+ goto out_free_wq;
}
err = stex_handshake(hba);
@@ -1602,6 +1696,8 @@ stex_probe(struct pci_dev *pdev, const struct pci_device_id *id)
out_free_irq:
stex_free_irq(hba);
+out_free_wq:
+ destroy_workqueue(hba->work_q);
out_ccb_free:
kfree(hba->ccb);
out_pci_free:
@@ -1669,6 +1765,8 @@ static void stex_hba_free(struct st_hba *hba)
{
stex_free_irq(hba);
+ destroy_workqueue(hba->work_q);
+
iounmap(hba->mmio_base);
pci_release_regions(hba->pdev);
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
index 45374d6..2b38f6a 100644
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
@@ -1864,7 +1864,7 @@ static pci_ers_result_t sym2_io_slot_dump(struct pci_dev *pdev)
*
* This routine is similar to sym_set_workarounds(), except
* that, at this point, we already know that the device was
- * succesfully intialized at least once before, and so most
+ * successfully intialized at least once before, and so most
* of the steps taken there are un-needed here.
*/
static void sym2_reset_workarounds(struct pci_dev *pdev)
diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c
index 297deb8..a7bc8b7 100644
--- a/drivers/scsi/sym53c8xx_2/sym_hipd.c
+++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c
@@ -2692,7 +2692,7 @@ static void sym_int_ma (struct sym_hcb *np)
* we force a SIR_NEGO_PROTO interrupt (it is a hack that avoids
* bloat for such a should_not_happen situation).
* In all other situation, we reset the BUS.
- * Are these assumptions reasonnable ? (Wait and see ...)
+ * Are these assumptions reasonable ? (Wait and see ...)
*/
unexpected_phase:
dsp -= 8;
diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.h b/drivers/scsi/sym53c8xx_2/sym_hipd.h
index 053e63c..5a80cba 100644
--- a/drivers/scsi/sym53c8xx_2/sym_hipd.h
+++ b/drivers/scsi/sym53c8xx_2/sym_hipd.h
@@ -54,7 +54,7 @@
*
* SYM_OPT_LIMIT_COMMAND_REORDERING
* When this option is set, the driver tries to limit tagged
- * command reordering to some reasonnable value.
+ * command reordering to some reasonable value.
* (set for Linux)
*/
#if 0
diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c
new file mode 100644
index 0000000..d2604c8
--- /dev/null
+++ b/drivers/scsi/vmw_pvscsi.c
@@ -0,0 +1,1407 @@
+/*
+ * Linux driver for VMware's para-virtualized SCSI HBA.
+ *
+ * Copyright (C) 2008-2009, VMware, 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 the
+ * Free Software Foundation; version 2 of the License and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Maintained by: Alok N Kataria <akataria@vmware.com>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/pci.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+
+#include "vmw_pvscsi.h"
+
+#define PVSCSI_LINUX_DRIVER_DESC "VMware PVSCSI driver"
+
+MODULE_DESCRIPTION(PVSCSI_LINUX_DRIVER_DESC);
+MODULE_AUTHOR("VMware, Inc.");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(PVSCSI_DRIVER_VERSION_STRING);
+
+#define PVSCSI_DEFAULT_NUM_PAGES_PER_RING 8
+#define PVSCSI_DEFAULT_NUM_PAGES_MSG_RING 1
+#define PVSCSI_DEFAULT_QUEUE_DEPTH 64
+#define SGL_SIZE PAGE_SIZE
+
+struct pvscsi_sg_list {
+ struct PVSCSISGElement sge[PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT];
+};
+
+struct pvscsi_ctx {
+ /*
+ * The index of the context in cmd_map serves as the context ID for a
+ * 1-to-1 mapping completions back to requests.
+ */
+ struct scsi_cmnd *cmd;
+ struct pvscsi_sg_list *sgl;
+ struct list_head list;
+ dma_addr_t dataPA;
+ dma_addr_t sensePA;
+ dma_addr_t sglPA;
+};
+
+struct pvscsi_adapter {
+ char *mmioBase;
+ unsigned int irq;
+ u8 rev;
+ bool use_msi;
+ bool use_msix;
+ bool use_msg;
+
+ spinlock_t hw_lock;
+
+ struct workqueue_struct *workqueue;
+ struct work_struct work;
+
+ struct PVSCSIRingReqDesc *req_ring;
+ unsigned req_pages;
+ unsigned req_depth;
+ dma_addr_t reqRingPA;
+
+ struct PVSCSIRingCmpDesc *cmp_ring;
+ unsigned cmp_pages;
+ dma_addr_t cmpRingPA;
+
+ struct PVSCSIRingMsgDesc *msg_ring;
+ unsigned msg_pages;
+ dma_addr_t msgRingPA;
+
+ struct PVSCSIRingsState *rings_state;
+ dma_addr_t ringStatePA;
+
+ struct pci_dev *dev;
+ struct Scsi_Host *host;
+
+ struct list_head cmd_pool;
+ struct pvscsi_ctx *cmd_map;
+};
+
+
+/* Command line parameters */
+static int pvscsi_ring_pages = PVSCSI_DEFAULT_NUM_PAGES_PER_RING;
+static int pvscsi_msg_ring_pages = PVSCSI_DEFAULT_NUM_PAGES_MSG_RING;
+static int pvscsi_cmd_per_lun = PVSCSI_DEFAULT_QUEUE_DEPTH;
+static bool pvscsi_disable_msi;
+static bool pvscsi_disable_msix;
+static bool pvscsi_use_msg = true;
+
+#define PVSCSI_RW (S_IRUSR | S_IWUSR)
+
+module_param_named(ring_pages, pvscsi_ring_pages, int, PVSCSI_RW);
+MODULE_PARM_DESC(ring_pages, "Number of pages per req/cmp ring - (default="
+ __stringify(PVSCSI_DEFAULT_NUM_PAGES_PER_RING) ")");
+
+module_param_named(msg_ring_pages, pvscsi_msg_ring_pages, int, PVSCSI_RW);
+MODULE_PARM_DESC(msg_ring_pages, "Number of pages for the msg ring - (default="
+ __stringify(PVSCSI_DEFAULT_NUM_PAGES_MSG_RING) ")");
+
+module_param_named(cmd_per_lun, pvscsi_cmd_per_lun, int, PVSCSI_RW);
+MODULE_PARM_DESC(cmd_per_lun, "Maximum commands per lun - (default="
+ __stringify(PVSCSI_MAX_REQ_QUEUE_DEPTH) ")");
+
+module_param_named(disable_msi, pvscsi_disable_msi, bool, PVSCSI_RW);
+MODULE_PARM_DESC(disable_msi, "Disable MSI use in driver - (default=0)");
+
+module_param_named(disable_msix, pvscsi_disable_msix, bool, PVSCSI_RW);
+MODULE_PARM_DESC(disable_msix, "Disable MSI-X use in driver - (default=0)");
+
+module_param_named(use_msg, pvscsi_use_msg, bool, PVSCSI_RW);
+MODULE_PARM_DESC(use_msg, "Use msg ring when available - (default=1)");
+
+static const struct pci_device_id pvscsi_pci_tbl[] = {
+ { PCI_VDEVICE(VMWARE, PCI_DEVICE_ID_VMWARE_PVSCSI) },
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, pvscsi_pci_tbl);
+
+static struct device *
+pvscsi_dev(const struct pvscsi_adapter *adapter)
+{
+ return &(adapter->dev->dev);
+}
+
+static struct pvscsi_ctx *
+pvscsi_find_context(const struct pvscsi_adapter *adapter, struct scsi_cmnd *cmd)
+{
+ struct pvscsi_ctx *ctx, *end;
+
+ end = &adapter->cmd_map[adapter->req_depth];
+ for (ctx = adapter->cmd_map; ctx < end; ctx++)
+ if (ctx->cmd == cmd)
+ return ctx;
+
+ return NULL;
+}
+
+static struct pvscsi_ctx *
+pvscsi_acquire_context(struct pvscsi_adapter *adapter, struct scsi_cmnd *cmd)
+{
+ struct pvscsi_ctx *ctx;
+
+ if (list_empty(&adapter->cmd_pool))
+ return NULL;
+
+ ctx = list_first_entry(&adapter->cmd_pool, struct pvscsi_ctx, list);
+ ctx->cmd = cmd;
+ list_del(&ctx->list);
+
+ return ctx;
+}
+
+static void pvscsi_release_context(struct pvscsi_adapter *adapter,
+ struct pvscsi_ctx *ctx)
+{
+ ctx->cmd = NULL;
+ list_add(&ctx->list, &adapter->cmd_pool);
+}
+
+/*
+ * Map a pvscsi_ctx struct to a context ID field value; we map to a simple
+ * non-zero integer. ctx always points to an entry in cmd_map array, hence
+ * the return value is always >=1.
+ */
+static u64 pvscsi_map_context(const struct pvscsi_adapter *adapter,
+ const struct pvscsi_ctx *ctx)
+{
+ return ctx - adapter->cmd_map + 1;
+}
+
+static struct pvscsi_ctx *
+pvscsi_get_context(const struct pvscsi_adapter *adapter, u64 context)
+{
+ return &adapter->cmd_map[context - 1];
+}
+
+static void pvscsi_reg_write(const struct pvscsi_adapter *adapter,
+ u32 offset, u32 val)
+{
+ writel(val, adapter->mmioBase + offset);
+}
+
+static u32 pvscsi_reg_read(const struct pvscsi_adapter *adapter, u32 offset)
+{
+ return readl(adapter->mmioBase + offset);
+}
+
+static u32 pvscsi_read_intr_status(const struct pvscsi_adapter *adapter)
+{
+ return pvscsi_reg_read(adapter, PVSCSI_REG_OFFSET_INTR_STATUS);
+}
+
+static void pvscsi_write_intr_status(const struct pvscsi_adapter *adapter,
+ u32 val)
+{
+ pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_INTR_STATUS, val);
+}
+
+static void pvscsi_unmask_intr(const struct pvscsi_adapter *adapter)
+{
+ u32 intr_bits;
+
+ intr_bits = PVSCSI_INTR_CMPL_MASK;
+ if (adapter->use_msg)
+ intr_bits |= PVSCSI_INTR_MSG_MASK;
+
+ pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_INTR_MASK, intr_bits);
+}
+
+static void pvscsi_mask_intr(const struct pvscsi_adapter *adapter)
+{
+ pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_INTR_MASK, 0);
+}
+
+static void pvscsi_write_cmd_desc(const struct pvscsi_adapter *adapter,
+ u32 cmd, const void *desc, size_t len)
+{
+ const u32 *ptr = desc;
+ size_t i;
+
+ len /= sizeof(*ptr);
+ pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_COMMAND, cmd);
+ for (i = 0; i < len; i++)
+ pvscsi_reg_write(adapter,
+ PVSCSI_REG_OFFSET_COMMAND_DATA, ptr[i]);
+}
+
+static void pvscsi_abort_cmd(const struct pvscsi_adapter *adapter,
+ const struct pvscsi_ctx *ctx)
+{
+ struct PVSCSICmdDescAbortCmd cmd = { 0 };
+
+ cmd.target = ctx->cmd->device->id;
+ cmd.context = pvscsi_map_context(adapter, ctx);
+
+ pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_ABORT_CMD, &cmd, sizeof(cmd));
+}
+
+static void pvscsi_kick_rw_io(const struct pvscsi_adapter *adapter)
+{
+ pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_KICK_RW_IO, 0);
+}
+
+static void pvscsi_process_request_ring(const struct pvscsi_adapter *adapter)
+{
+ pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_KICK_NON_RW_IO, 0);
+}
+
+static int scsi_is_rw(unsigned char op)
+{
+ return op == READ_6 || op == WRITE_6 ||
+ op == READ_10 || op == WRITE_10 ||
+ op == READ_12 || op == WRITE_12 ||
+ op == READ_16 || op == WRITE_16;
+}
+
+static void pvscsi_kick_io(const struct pvscsi_adapter *adapter,
+ unsigned char op)
+{
+ if (scsi_is_rw(op))
+ pvscsi_kick_rw_io(adapter);
+ else
+ pvscsi_process_request_ring(adapter);
+}
+
+static void ll_adapter_reset(const struct pvscsi_adapter *adapter)
+{
+ dev_dbg(pvscsi_dev(adapter), "Adapter Reset on %p\n", adapter);
+
+ pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_ADAPTER_RESET, NULL, 0);
+}
+
+static void ll_bus_reset(const struct pvscsi_adapter *adapter)
+{
+ dev_dbg(pvscsi_dev(adapter), "Reseting bus on %p\n", adapter);
+
+ pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_RESET_BUS, NULL, 0);
+}
+
+static void ll_device_reset(const struct pvscsi_adapter *adapter, u32 target)
+{
+ struct PVSCSICmdDescResetDevice cmd = { 0 };
+
+ dev_dbg(pvscsi_dev(adapter), "Reseting device: target=%u\n", target);
+
+ cmd.target = target;
+
+ pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_RESET_DEVICE,
+ &cmd, sizeof(cmd));
+}
+
+static void pvscsi_create_sg(struct pvscsi_ctx *ctx,
+ struct scatterlist *sg, unsigned count)
+{
+ unsigned i;
+ struct PVSCSISGElement *sge;
+
+ BUG_ON(count > PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT);
+
+ sge = &ctx->sgl->sge[0];
+ for (i = 0; i < count; i++, sg++) {
+ sge[i].addr = sg_dma_address(sg);
+ sge[i].length = sg_dma_len(sg);
+ sge[i].flags = 0;
+ }
+}
+
+/*
+ * Map all data buffers for a command into PCI space and
+ * setup the scatter/gather list if needed.
+ */
+static void pvscsi_map_buffers(struct pvscsi_adapter *adapter,
+ struct pvscsi_ctx *ctx, struct scsi_cmnd *cmd,
+ struct PVSCSIRingReqDesc *e)
+{
+ unsigned count;
+ unsigned bufflen = scsi_bufflen(cmd);
+ struct scatterlist *sg;
+
+ e->dataLen = bufflen;
+ e->dataAddr = 0;
+ if (bufflen == 0)
+ return;
+
+ sg = scsi_sglist(cmd);
+ count = scsi_sg_count(cmd);
+ if (count != 0) {
+ int segs = scsi_dma_map(cmd);
+ if (segs > 1) {
+ pvscsi_create_sg(ctx, sg, segs);
+
+ e->flags |= PVSCSI_FLAG_CMD_WITH_SG_LIST;
+ ctx->sglPA = pci_map_single(adapter->dev, ctx->sgl,
+ SGL_SIZE, PCI_DMA_TODEVICE);
+ e->dataAddr = ctx->sglPA;
+ } else
+ e->dataAddr = sg_dma_address(sg);
+ } else {
+ /*
+ * In case there is no S/G list, scsi_sglist points
+ * directly to the buffer.
+ */
+ ctx->dataPA = pci_map_single(adapter->dev, sg, bufflen,
+ cmd->sc_data_direction);
+ e->dataAddr = ctx->dataPA;
+ }
+}
+
+static void pvscsi_unmap_buffers(const struct pvscsi_adapter *adapter,
+ struct pvscsi_ctx *ctx)
+{
+ struct scsi_cmnd *cmd;
+ unsigned bufflen;
+
+ cmd = ctx->cmd;
+ bufflen = scsi_bufflen(cmd);
+
+ if (bufflen != 0) {
+ unsigned count = scsi_sg_count(cmd);
+
+ if (count != 0) {
+ scsi_dma_unmap(cmd);
+ if (ctx->sglPA) {
+ pci_unmap_single(adapter->dev, ctx->sglPA,
+ SGL_SIZE, PCI_DMA_TODEVICE);
+ ctx->sglPA = 0;
+ }
+ } else
+ pci_unmap_single(adapter->dev, ctx->dataPA, bufflen,
+ cmd->sc_data_direction);
+ }
+ if (cmd->sense_buffer)
+ pci_unmap_single(adapter->dev, ctx->sensePA,
+ SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE);
+}
+
+static int __devinit pvscsi_allocate_rings(struct pvscsi_adapter *adapter)
+{
+ adapter->rings_state = pci_alloc_consistent(adapter->dev, PAGE_SIZE,
+ &adapter->ringStatePA);
+ if (!adapter->rings_state)
+ return -ENOMEM;
+
+ adapter->req_pages = min(PVSCSI_MAX_NUM_PAGES_REQ_RING,
+ pvscsi_ring_pages);
+ adapter->req_depth = adapter->req_pages
+ * PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE;
+ adapter->req_ring = pci_alloc_consistent(adapter->dev,
+ adapter->req_pages * PAGE_SIZE,
+ &adapter->reqRingPA);
+ if (!adapter->req_ring)
+ return -ENOMEM;
+
+ adapter->cmp_pages = min(PVSCSI_MAX_NUM_PAGES_CMP_RING,
+ pvscsi_ring_pages);
+ adapter->cmp_ring = pci_alloc_consistent(adapter->dev,
+ adapter->cmp_pages * PAGE_SIZE,
+ &adapter->cmpRingPA);
+ if (!adapter->cmp_ring)
+ return -ENOMEM;
+
+ BUG_ON(!IS_ALIGNED(adapter->ringStatePA, PAGE_SIZE));
+ BUG_ON(!IS_ALIGNED(adapter->reqRingPA, PAGE_SIZE));
+ BUG_ON(!IS_ALIGNED(adapter->cmpRingPA, PAGE_SIZE));
+
+ if (!adapter->use_msg)
+ return 0;
+
+ adapter->msg_pages = min(PVSCSI_MAX_NUM_PAGES_MSG_RING,
+ pvscsi_msg_ring_pages);
+ adapter->msg_ring = pci_alloc_consistent(adapter->dev,
+ adapter->msg_pages * PAGE_SIZE,
+ &adapter->msgRingPA);
+ if (!adapter->msg_ring)
+ return -ENOMEM;
+ BUG_ON(!IS_ALIGNED(adapter->msgRingPA, PAGE_SIZE));
+
+ return 0;
+}
+
+static void pvscsi_setup_all_rings(const struct pvscsi_adapter *adapter)
+{
+ struct PVSCSICmdDescSetupRings cmd = { 0 };
+ dma_addr_t base;
+ unsigned i;
+
+ cmd.ringsStatePPN = adapter->ringStatePA >> PAGE_SHIFT;
+ cmd.reqRingNumPages = adapter->req_pages;
+ cmd.cmpRingNumPages = adapter->cmp_pages;
+
+ base = adapter->reqRingPA;
+ for (i = 0; i < adapter->req_pages; i++) {
+ cmd.reqRingPPNs[i] = base >> PAGE_SHIFT;
+ base += PAGE_SIZE;
+ }
+
+ base = adapter->cmpRingPA;
+ for (i = 0; i < adapter->cmp_pages; i++) {
+ cmd.cmpRingPPNs[i] = base >> PAGE_SHIFT;
+ base += PAGE_SIZE;
+ }
+
+ memset(adapter->rings_state, 0, PAGE_SIZE);
+ memset(adapter->req_ring, 0, adapter->req_pages * PAGE_SIZE);
+ memset(adapter->cmp_ring, 0, adapter->cmp_pages * PAGE_SIZE);
+
+ pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_SETUP_RINGS,
+ &cmd, sizeof(cmd));
+
+ if (adapter->use_msg) {
+ struct PVSCSICmdDescSetupMsgRing cmd_msg = { 0 };
+
+ cmd_msg.numPages = adapter->msg_pages;
+
+ base = adapter->msgRingPA;
+ for (i = 0; i < adapter->msg_pages; i++) {
+ cmd_msg.ringPPNs[i] = base >> PAGE_SHIFT;
+ base += PAGE_SIZE;
+ }
+ memset(adapter->msg_ring, 0, adapter->msg_pages * PAGE_SIZE);
+
+ pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_SETUP_MSG_RING,
+ &cmd_msg, sizeof(cmd_msg));
+ }
+}
+
+/*
+ * Pull a completion descriptor off and pass the completion back
+ * to the SCSI mid layer.
+ */
+static void pvscsi_complete_request(struct pvscsi_adapter *adapter,
+ const struct PVSCSIRingCmpDesc *e)
+{
+ struct pvscsi_ctx *ctx;
+ struct scsi_cmnd *cmd;
+ u32 btstat = e->hostStatus;
+ u32 sdstat = e->scsiStatus;
+
+ ctx = pvscsi_get_context(adapter, e->context);
+ cmd = ctx->cmd;
+ pvscsi_unmap_buffers(adapter, ctx);
+ pvscsi_release_context(adapter, ctx);
+ cmd->result = 0;
+
+ if (sdstat != SAM_STAT_GOOD &&
+ (btstat == BTSTAT_SUCCESS ||
+ btstat == BTSTAT_LINKED_COMMAND_COMPLETED ||
+ btstat == BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG)) {
+ cmd->result = (DID_OK << 16) | sdstat;
+ if (sdstat == SAM_STAT_CHECK_CONDITION && cmd->sense_buffer)
+ cmd->result |= (DRIVER_SENSE << 24);
+ } else
+ switch (btstat) {
+ case BTSTAT_SUCCESS:
+ case BTSTAT_LINKED_COMMAND_COMPLETED:
+ case BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG:
+ /* If everything went fine, let's move on.. */
+ cmd->result = (DID_OK << 16);
+ break;
+
+ case BTSTAT_DATARUN:
+ case BTSTAT_DATA_UNDERRUN:
+ /* Report residual data in underruns */
+ scsi_set_resid(cmd, scsi_bufflen(cmd) - e->dataLen);
+ cmd->result = (DID_ERROR << 16);
+ break;
+
+ case BTSTAT_SELTIMEO:
+ /* Our emulation returns this for non-connected devs */
+ cmd->result = (DID_BAD_TARGET << 16);
+ break;
+
+ case BTSTAT_LUNMISMATCH:
+ case BTSTAT_TAGREJECT:
+ case BTSTAT_BADMSG:
+ cmd->result = (DRIVER_INVALID << 24);
+ /* fall through */
+
+ case BTSTAT_HAHARDWARE:
+ case BTSTAT_INVPHASE:
+ case BTSTAT_HATIMEOUT:
+ case BTSTAT_NORESPONSE:
+ case BTSTAT_DISCONNECT:
+ case BTSTAT_HASOFTWARE:
+ case BTSTAT_BUSFREE:
+ case BTSTAT_SENSFAILED:
+ cmd->result |= (DID_ERROR << 16);
+ break;
+
+ case BTSTAT_SENTRST:
+ case BTSTAT_RECVRST:
+ case BTSTAT_BUSRESET:
+ cmd->result = (DID_RESET << 16);
+ break;
+
+ case BTSTAT_ABORTQUEUE:
+ cmd->result = (DID_ABORT << 16);
+ break;
+
+ case BTSTAT_SCSIPARITY:
+ cmd->result = (DID_PARITY << 16);
+ break;
+
+ default:
+ cmd->result = (DID_ERROR << 16);
+ scmd_printk(KERN_DEBUG, cmd,
+ "Unknown completion status: 0x%x\n",
+ btstat);
+ }
+
+ dev_dbg(&cmd->device->sdev_gendev,
+ "cmd=%p %x ctx=%p result=0x%x status=0x%x,%x\n",
+ cmd, cmd->cmnd[0], ctx, cmd->result, btstat, sdstat);
+
+ cmd->scsi_done(cmd);
+}
+
+/*
+ * barrier usage : Since the PVSCSI device is emulated, there could be cases
+ * where we may want to serialize some accesses between the driver and the
+ * emulation layer. We use compiler barriers instead of the more expensive
+ * memory barriers because PVSCSI is only supported on X86 which has strong
+ * memory access ordering.
+ */
+static void pvscsi_process_completion_ring(struct pvscsi_adapter *adapter)
+{
+ struct PVSCSIRingsState *s = adapter->rings_state;
+ struct PVSCSIRingCmpDesc *ring = adapter->cmp_ring;
+ u32 cmp_entries = s->cmpNumEntriesLog2;
+
+ while (s->cmpConsIdx != s->cmpProdIdx) {
+ struct PVSCSIRingCmpDesc *e = ring + (s->cmpConsIdx &
+ MASK(cmp_entries));
+ /*
+ * This barrier() ensures that *e is not dereferenced while
+ * the device emulation still writes data into the slot.
+ * Since the device emulation advances s->cmpProdIdx only after
+ * updating the slot we want to check it first.
+ */
+ barrier();
+ pvscsi_complete_request(adapter, e);
+ /*
+ * This barrier() ensures that compiler doesn't reorder write
+ * to s->cmpConsIdx before the read of (*e) inside
+ * pvscsi_complete_request. Otherwise, device emulation may
+ * overwrite *e before we had a chance to read it.
+ */
+ barrier();
+ s->cmpConsIdx++;
+ }
+}
+
+/*
+ * Translate a Linux SCSI request into a request ring entry.
+ */
+static int pvscsi_queue_ring(struct pvscsi_adapter *adapter,
+ struct pvscsi_ctx *ctx, struct scsi_cmnd *cmd)
+{
+ struct PVSCSIRingsState *s;
+ struct PVSCSIRingReqDesc *e;
+ struct scsi_device *sdev;
+ u32 req_entries;
+
+ s = adapter->rings_state;
+ sdev = cmd->device;
+ req_entries = s->reqNumEntriesLog2;
+
+ /*
+ * If this condition holds, we might have room on the request ring, but
+ * we might not have room on the completion ring for the response.
+ * However, we have already ruled out this possibility - we would not
+ * have successfully allocated a context if it were true, since we only
+ * have one context per request entry. Check for it anyway, since it
+ * would be a serious bug.
+ */
+ if (s->reqProdIdx - s->cmpConsIdx >= 1 << req_entries) {
+ scmd_printk(KERN_ERR, cmd, "vmw_pvscsi: "
+ "ring full: reqProdIdx=%d cmpConsIdx=%d\n",
+ s->reqProdIdx, s->cmpConsIdx);
+ return -1;
+ }
+
+ e = adapter->req_ring + (s->reqProdIdx & MASK(req_entries));
+
+ e->bus = sdev->channel;
+ e->target = sdev->id;
+ memset(e->lun, 0, sizeof(e->lun));
+ e->lun[1] = sdev->lun;
+
+ if (cmd->sense_buffer) {
+ ctx->sensePA = pci_map_single(adapter->dev, cmd->sense_buffer,
+ SCSI_SENSE_BUFFERSIZE,
+ PCI_DMA_FROMDEVICE);
+ e->senseAddr = ctx->sensePA;
+ e->senseLen = SCSI_SENSE_BUFFERSIZE;
+ } else {
+ e->senseLen = 0;
+ e->senseAddr = 0;
+ }
+ e->cdbLen = cmd->cmd_len;
+ e->vcpuHint = smp_processor_id();
+ memcpy(e->cdb, cmd->cmnd, e->cdbLen);
+
+ e->tag = SIMPLE_QUEUE_TAG;
+ if (sdev->tagged_supported &&
+ (cmd->tag == HEAD_OF_QUEUE_TAG ||
+ cmd->tag == ORDERED_QUEUE_TAG))
+ e->tag = cmd->tag;
+
+ if (cmd->sc_data_direction == DMA_FROM_DEVICE)
+ e->flags = PVSCSI_FLAG_CMD_DIR_TOHOST;
+ else if (cmd->sc_data_direction == DMA_TO_DEVICE)
+ e->flags = PVSCSI_FLAG_CMD_DIR_TODEVICE;
+ else if (cmd->sc_data_direction == DMA_NONE)
+ e->flags = PVSCSI_FLAG_CMD_DIR_NONE;
+ else
+ e->flags = 0;
+
+ pvscsi_map_buffers(adapter, ctx, cmd, e);
+
+ e->context = pvscsi_map_context(adapter, ctx);
+
+ barrier();
+
+ s->reqProdIdx++;
+
+ return 0;
+}
+
+static int pvscsi_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+{
+ struct Scsi_Host *host = cmd->device->host;
+ struct pvscsi_adapter *adapter = shost_priv(host);
+ struct pvscsi_ctx *ctx;
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->hw_lock, flags);
+
+ ctx = pvscsi_acquire_context(adapter, cmd);
+ if (!ctx || pvscsi_queue_ring(adapter, ctx, cmd) != 0) {
+ if (ctx)
+ pvscsi_release_context(adapter, ctx);
+ spin_unlock_irqrestore(&adapter->hw_lock, flags);
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+
+ cmd->scsi_done = done;
+
+ dev_dbg(&cmd->device->sdev_gendev,
+ "queued cmd %p, ctx %p, op=%x\n", cmd, ctx, cmd->cmnd[0]);
+
+ spin_unlock_irqrestore(&adapter->hw_lock, flags);
+
+ pvscsi_kick_io(adapter, cmd->cmnd[0]);
+
+ return 0;
+}
+
+static int pvscsi_abort(struct scsi_cmnd *cmd)
+{
+ struct pvscsi_adapter *adapter = shost_priv(cmd->device->host);
+ struct pvscsi_ctx *ctx;
+ unsigned long flags;
+
+ scmd_printk(KERN_DEBUG, cmd, "task abort on host %u, %p\n",
+ adapter->host->host_no, cmd);
+
+ spin_lock_irqsave(&adapter->hw_lock, flags);
+
+ /*
+ * Poll the completion ring first - we might be trying to abort
+ * a command that is waiting to be dispatched in the completion ring.
+ */
+ pvscsi_process_completion_ring(adapter);
+
+ /*
+ * If there is no context for the command, it either already succeeded
+ * or else was never properly issued. Not our problem.
+ */
+ ctx = pvscsi_find_context(adapter, cmd);
+ if (!ctx) {
+ scmd_printk(KERN_DEBUG, cmd, "Failed to abort cmd %p\n", cmd);
+ goto out;
+ }
+
+ pvscsi_abort_cmd(adapter, ctx);
+
+ pvscsi_process_completion_ring(adapter);
+
+out:
+ spin_unlock_irqrestore(&adapter->hw_lock, flags);
+ return SUCCESS;
+}
+
+/*
+ * Abort all outstanding requests. This is only safe to use if the completion
+ * ring will never be walked again or the device has been reset, because it
+ * destroys the 1-1 mapping between context field passed to emulation and our
+ * request structure.
+ */
+static void pvscsi_reset_all(struct pvscsi_adapter *adapter)
+{
+ unsigned i;
+
+ for (i = 0; i < adapter->req_depth; i++) {
+ struct pvscsi_ctx *ctx = &adapter->cmd_map[i];
+ struct scsi_cmnd *cmd = ctx->cmd;
+ if (cmd) {
+ scmd_printk(KERN_ERR, cmd,
+ "Forced reset on cmd %p\n", cmd);
+ pvscsi_unmap_buffers(adapter, ctx);
+ pvscsi_release_context(adapter, ctx);
+ cmd->result = (DID_RESET << 16);
+ cmd->scsi_done(cmd);
+ }
+ }
+}
+
+static int pvscsi_host_reset(struct scsi_cmnd *cmd)
+{
+ struct Scsi_Host *host = cmd->device->host;
+ struct pvscsi_adapter *adapter = shost_priv(host);
+ unsigned long flags;
+ bool use_msg;
+
+ scmd_printk(KERN_INFO, cmd, "SCSI Host reset\n");
+
+ spin_lock_irqsave(&adapter->hw_lock, flags);
+
+ use_msg = adapter->use_msg;
+
+ if (use_msg) {
+ adapter->use_msg = 0;
+ spin_unlock_irqrestore(&adapter->hw_lock, flags);
+
+ /*
+ * Now that we know that the ISR won't add more work on the
+ * workqueue we can safely flush any outstanding work.
+ */
+ flush_workqueue(adapter->workqueue);
+ spin_lock_irqsave(&adapter->hw_lock, flags);
+ }
+
+ /*
+ * We're going to tear down the entire ring structure and set it back
+ * up, so stalling new requests until all completions are flushed and
+ * the rings are back in place.
+ */
+
+ pvscsi_process_request_ring(adapter);
+
+ ll_adapter_reset(adapter);
+
+ /*
+ * Now process any completions. Note we do this AFTER adapter reset,
+ * which is strange, but stops races where completions get posted
+ * between processing the ring and issuing the reset. The backend will
+ * not touch the ring memory after reset, so the immediately pre-reset
+ * completion ring state is still valid.
+ */
+ pvscsi_process_completion_ring(adapter);
+
+ pvscsi_reset_all(adapter);
+ adapter->use_msg = use_msg;
+ pvscsi_setup_all_rings(adapter);
+ pvscsi_unmask_intr(adapter);
+
+ spin_unlock_irqrestore(&adapter->hw_lock, flags);
+
+ return SUCCESS;
+}
+
+static int pvscsi_bus_reset(struct scsi_cmnd *cmd)
+{
+ struct Scsi_Host *host = cmd->device->host;
+ struct pvscsi_adapter *adapter = shost_priv(host);
+ unsigned long flags;
+
+ scmd_printk(KERN_INFO, cmd, "SCSI Bus reset\n");
+
+ /*
+ * We don't want to queue new requests for this bus after
+ * flushing all pending requests to emulation, since new
+ * requests could then sneak in during this bus reset phase,
+ * so take the lock now.
+ */
+ spin_lock_irqsave(&adapter->hw_lock, flags);
+
+ pvscsi_process_request_ring(adapter);
+ ll_bus_reset(adapter);
+ pvscsi_process_completion_ring(adapter);
+
+ spin_unlock_irqrestore(&adapter->hw_lock, flags);
+
+ return SUCCESS;
+}
+
+static int pvscsi_device_reset(struct scsi_cmnd *cmd)
+{
+ struct Scsi_Host *host = cmd->device->host;
+ struct pvscsi_adapter *adapter = shost_priv(host);
+ unsigned long flags;
+
+ scmd_printk(KERN_INFO, cmd, "SCSI device reset on scsi%u:%u\n",
+ host->host_no, cmd->device->id);
+
+ /*
+ * We don't want to queue new requests for this device after flushing
+ * all pending requests to emulation, since new requests could then
+ * sneak in during this device reset phase, so take the lock now.
+ */
+ spin_lock_irqsave(&adapter->hw_lock, flags);
+
+ pvscsi_process_request_ring(adapter);
+ ll_device_reset(adapter, cmd->device->id);
+ pvscsi_process_completion_ring(adapter);
+
+ spin_unlock_irqrestore(&adapter->hw_lock, flags);
+
+ return SUCCESS;
+}
+
+static struct scsi_host_template pvscsi_template;
+
+static const char *pvscsi_info(struct Scsi_Host *host)
+{
+ struct pvscsi_adapter *adapter = shost_priv(host);
+ static char buf[256];
+
+ sprintf(buf, "VMware PVSCSI storage adapter rev %d, req/cmp/msg rings: "
+ "%u/%u/%u pages, cmd_per_lun=%u", adapter->rev,
+ adapter->req_pages, adapter->cmp_pages, adapter->msg_pages,
+ pvscsi_template.cmd_per_lun);
+
+ return buf;
+}
+
+static struct scsi_host_template pvscsi_template = {
+ .module = THIS_MODULE,
+ .name = "VMware PVSCSI Host Adapter",
+ .proc_name = "vmw_pvscsi",
+ .info = pvscsi_info,
+ .queuecommand = pvscsi_queue,
+ .this_id = -1,
+ .sg_tablesize = PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT,
+ .dma_boundary = UINT_MAX,
+ .max_sectors = 0xffff,
+ .use_clustering = ENABLE_CLUSTERING,
+ .eh_abort_handler = pvscsi_abort,
+ .eh_device_reset_handler = pvscsi_device_reset,
+ .eh_bus_reset_handler = pvscsi_bus_reset,
+ .eh_host_reset_handler = pvscsi_host_reset,
+};
+
+static void pvscsi_process_msg(const struct pvscsi_adapter *adapter,
+ const struct PVSCSIRingMsgDesc *e)
+{
+ struct PVSCSIRingsState *s = adapter->rings_state;
+ struct Scsi_Host *host = adapter->host;
+ struct scsi_device *sdev;
+
+ printk(KERN_INFO "vmw_pvscsi: msg type: 0x%x - MSG RING: %u/%u (%u) \n",
+ e->type, s->msgProdIdx, s->msgConsIdx, s->msgNumEntriesLog2);
+
+ BUILD_BUG_ON(PVSCSI_MSG_LAST != 2);
+
+ if (e->type == PVSCSI_MSG_DEV_ADDED) {
+ struct PVSCSIMsgDescDevStatusChanged *desc;
+ desc = (struct PVSCSIMsgDescDevStatusChanged *)e;
+
+ printk(KERN_INFO
+ "vmw_pvscsi: msg: device added at scsi%u:%u:%u\n",
+ desc->bus, desc->target, desc->lun[1]);
+
+ if (!scsi_host_get(host))
+ return;
+
+ sdev = scsi_device_lookup(host, desc->bus, desc->target,
+ desc->lun[1]);
+ if (sdev) {
+ printk(KERN_INFO "vmw_pvscsi: device already exists\n");
+ scsi_device_put(sdev);
+ } else
+ scsi_add_device(adapter->host, desc->bus,
+ desc->target, desc->lun[1]);
+
+ scsi_host_put(host);
+ } else if (e->type == PVSCSI_MSG_DEV_REMOVED) {
+ struct PVSCSIMsgDescDevStatusChanged *desc;
+ desc = (struct PVSCSIMsgDescDevStatusChanged *)e;
+
+ printk(KERN_INFO
+ "vmw_pvscsi: msg: device removed at scsi%u:%u:%u\n",
+ desc->bus, desc->target, desc->lun[1]);
+
+ if (!scsi_host_get(host))
+ return;
+
+ sdev = scsi_device_lookup(host, desc->bus, desc->target,
+ desc->lun[1]);
+ if (sdev) {
+ scsi_remove_device(sdev);
+ scsi_device_put(sdev);
+ } else
+ printk(KERN_INFO
+ "vmw_pvscsi: failed to lookup scsi%u:%u:%u\n",
+ desc->bus, desc->target, desc->lun[1]);
+
+ scsi_host_put(host);
+ }
+}
+
+static int pvscsi_msg_pending(const struct pvscsi_adapter *adapter)
+{
+ struct PVSCSIRingsState *s = adapter->rings_state;
+
+ return s->msgProdIdx != s->msgConsIdx;
+}
+
+static void pvscsi_process_msg_ring(const struct pvscsi_adapter *adapter)
+{
+ struct PVSCSIRingsState *s = adapter->rings_state;
+ struct PVSCSIRingMsgDesc *ring = adapter->msg_ring;
+ u32 msg_entries = s->msgNumEntriesLog2;
+
+ while (pvscsi_msg_pending(adapter)) {
+ struct PVSCSIRingMsgDesc *e = ring + (s->msgConsIdx &
+ MASK(msg_entries));
+
+ barrier();
+ pvscsi_process_msg(adapter, e);
+ barrier();
+ s->msgConsIdx++;
+ }
+}
+
+static void pvscsi_msg_workqueue_handler(struct work_struct *data)
+{
+ struct pvscsi_adapter *adapter;
+
+ adapter = container_of(data, struct pvscsi_adapter, work);
+
+ pvscsi_process_msg_ring(adapter);
+}
+
+static int pvscsi_setup_msg_workqueue(struct pvscsi_adapter *adapter)
+{
+ char name[32];
+
+ if (!pvscsi_use_msg)
+ return 0;
+
+ pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_COMMAND,
+ PVSCSI_CMD_SETUP_MSG_RING);
+
+ if (pvscsi_reg_read(adapter, PVSCSI_REG_OFFSET_COMMAND_STATUS) == -1)
+ return 0;
+
+ snprintf(name, sizeof(name),
+ "vmw_pvscsi_wq_%u", adapter->host->host_no);
+
+ adapter->workqueue = create_singlethread_workqueue(name);
+ if (!adapter->workqueue) {
+ printk(KERN_ERR "vmw_pvscsi: failed to create work queue\n");
+ return 0;
+ }
+ INIT_WORK(&adapter->work, pvscsi_msg_workqueue_handler);
+
+ return 1;
+}
+
+static irqreturn_t pvscsi_isr(int irq, void *devp)
+{
+ struct pvscsi_adapter *adapter = devp;
+ int handled;
+
+ if (adapter->use_msi || adapter->use_msix)
+ handled = true;
+ else {
+ u32 val = pvscsi_read_intr_status(adapter);
+ handled = (val & PVSCSI_INTR_ALL_SUPPORTED) != 0;
+ if (handled)
+ pvscsi_write_intr_status(devp, val);
+ }
+
+ if (handled) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->hw_lock, flags);
+
+ pvscsi_process_completion_ring(adapter);
+ if (adapter->use_msg && pvscsi_msg_pending(adapter))
+ queue_work(adapter->workqueue, &adapter->work);
+
+ spin_unlock_irqrestore(&adapter->hw_lock, flags);
+ }
+
+ return IRQ_RETVAL(handled);
+}
+
+static void pvscsi_free_sgls(const struct pvscsi_adapter *adapter)
+{
+ struct pvscsi_ctx *ctx = adapter->cmd_map;
+ unsigned i;
+
+ for (i = 0; i < adapter->req_depth; ++i, ++ctx)
+ free_pages((unsigned long)ctx->sgl, get_order(SGL_SIZE));
+}
+
+static int pvscsi_setup_msix(const struct pvscsi_adapter *adapter, int *irq)
+{
+ struct msix_entry entry = { 0, PVSCSI_VECTOR_COMPLETION };
+ int ret;
+
+ ret = pci_enable_msix(adapter->dev, &entry, 1);
+ if (ret)
+ return ret;
+
+ *irq = entry.vector;
+
+ return 0;
+}
+
+static void pvscsi_shutdown_intr(struct pvscsi_adapter *adapter)
+{
+ if (adapter->irq) {
+ free_irq(adapter->irq, adapter);
+ adapter->irq = 0;
+ }
+ if (adapter->use_msi) {
+ pci_disable_msi(adapter->dev);
+ adapter->use_msi = 0;
+ } else if (adapter->use_msix) {
+ pci_disable_msix(adapter->dev);
+ adapter->use_msix = 0;
+ }
+}
+
+static void pvscsi_release_resources(struct pvscsi_adapter *adapter)
+{
+ pvscsi_shutdown_intr(adapter);
+
+ if (adapter->workqueue)
+ destroy_workqueue(adapter->workqueue);
+
+ if (adapter->mmioBase)
+ pci_iounmap(adapter->dev, adapter->mmioBase);
+
+ pci_release_regions(adapter->dev);
+
+ if (adapter->cmd_map) {
+ pvscsi_free_sgls(adapter);
+ kfree(adapter->cmd_map);
+ }
+
+ if (adapter->rings_state)
+ pci_free_consistent(adapter->dev, PAGE_SIZE,
+ adapter->rings_state, adapter->ringStatePA);
+
+ if (adapter->req_ring)
+ pci_free_consistent(adapter->dev,
+ adapter->req_pages * PAGE_SIZE,
+ adapter->req_ring, adapter->reqRingPA);
+
+ if (adapter->cmp_ring)
+ pci_free_consistent(adapter->dev,
+ adapter->cmp_pages * PAGE_SIZE,
+ adapter->cmp_ring, adapter->cmpRingPA);
+
+ if (adapter->msg_ring)
+ pci_free_consistent(adapter->dev,
+ adapter->msg_pages * PAGE_SIZE,
+ adapter->msg_ring, adapter->msgRingPA);
+}
+
+/*
+ * Allocate scatter gather lists.
+ *
+ * These are statically allocated. Trying to be clever was not worth it.
+ *
+ * Dynamic allocation can fail, and we can't go deeep into the memory
+ * allocator, since we're a SCSI driver, and trying too hard to allocate
+ * memory might generate disk I/O. We also don't want to fail disk I/O
+ * in that case because we can't get an allocation - the I/O could be
+ * trying to swap out data to free memory. Since that is pathological,
+ * just use a statically allocated scatter list.
+ *
+ */
+static int __devinit pvscsi_allocate_sg(struct pvscsi_adapter *adapter)
+{
+ struct pvscsi_ctx *ctx;
+ int i;
+
+ ctx = adapter->cmd_map;
+ BUILD_BUG_ON(sizeof(struct pvscsi_sg_list) > SGL_SIZE);
+
+ for (i = 0; i < adapter->req_depth; ++i, ++ctx) {
+ ctx->sgl = (void *)__get_free_pages(GFP_KERNEL,
+ get_order(SGL_SIZE));
+ ctx->sglPA = 0;
+ BUG_ON(!IS_ALIGNED(((unsigned long)ctx->sgl), PAGE_SIZE));
+ if (!ctx->sgl) {
+ for (; i >= 0; --i, --ctx) {
+ free_pages((unsigned long)ctx->sgl,
+ get_order(SGL_SIZE));
+ ctx->sgl = NULL;
+ }
+ return -ENOMEM;
+ }
+ }
+
+ return 0;
+}
+
+static int __devinit pvscsi_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct pvscsi_adapter *adapter;
+ struct Scsi_Host *host;
+ unsigned int i;
+ unsigned long flags = 0;
+ int error;
+
+ error = -ENODEV;
+
+ if (pci_enable_device(pdev))
+ return error;
+
+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) == 0 &&
+ pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) == 0) {
+ printk(KERN_INFO "vmw_pvscsi: using 64bit dma\n");
+ } else if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) == 0 &&
+ pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)) == 0) {
+ printk(KERN_INFO "vmw_pvscsi: using 32bit dma\n");
+ } else {
+ printk(KERN_ERR "vmw_pvscsi: failed to set DMA mask\n");
+ goto out_disable_device;
+ }
+
+ pvscsi_template.can_queue =
+ min(PVSCSI_MAX_NUM_PAGES_REQ_RING, pvscsi_ring_pages) *
+ PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE;
+ pvscsi_template.cmd_per_lun =
+ min(pvscsi_template.can_queue, pvscsi_cmd_per_lun);
+ host = scsi_host_alloc(&pvscsi_template, sizeof(struct pvscsi_adapter));
+ if (!host) {
+ printk(KERN_ERR "vmw_pvscsi: failed to allocate host\n");
+ goto out_disable_device;
+ }
+
+ adapter = shost_priv(host);
+ memset(adapter, 0, sizeof(*adapter));
+ adapter->dev = pdev;
+ adapter->host = host;
+
+ spin_lock_init(&adapter->hw_lock);
+
+ host->max_channel = 0;
+ host->max_id = 16;
+ host->max_lun = 1;
+ host->max_cmd_len = 16;
+
+ adapter->rev = pdev->revision;
+
+ if (pci_request_regions(pdev, "vmw_pvscsi")) {
+ printk(KERN_ERR "vmw_pvscsi: pci memory selection failed\n");
+ goto out_free_host;
+ }
+
+ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+ if ((pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO))
+ continue;
+
+ if (pci_resource_len(pdev, i) < PVSCSI_MEM_SPACE_SIZE)
+ continue;
+
+ break;
+ }
+
+ if (i == DEVICE_COUNT_RESOURCE) {
+ printk(KERN_ERR
+ "vmw_pvscsi: adapter has no suitable MMIO region\n");
+ goto out_release_resources;
+ }
+
+ adapter->mmioBase = pci_iomap(pdev, i, PVSCSI_MEM_SPACE_SIZE);
+
+ if (!adapter->mmioBase) {
+ printk(KERN_ERR
+ "vmw_pvscsi: can't iomap for BAR %d memsize %lu\n",
+ i, PVSCSI_MEM_SPACE_SIZE);
+ goto out_release_resources;
+ }
+
+ pci_set_master(pdev);
+ pci_set_drvdata(pdev, host);
+
+ ll_adapter_reset(adapter);
+
+ adapter->use_msg = pvscsi_setup_msg_workqueue(adapter);
+
+ error = pvscsi_allocate_rings(adapter);
+ if (error) {
+ printk(KERN_ERR "vmw_pvscsi: unable to allocate ring memory\n");
+ goto out_release_resources;
+ }
+
+ /*
+ * From this point on we should reset the adapter if anything goes
+ * wrong.
+ */
+ pvscsi_setup_all_rings(adapter);
+
+ adapter->cmd_map = kcalloc(adapter->req_depth,
+ sizeof(struct pvscsi_ctx), GFP_KERNEL);
+ if (!adapter->cmd_map) {
+ printk(KERN_ERR "vmw_pvscsi: failed to allocate memory.\n");
+ error = -ENOMEM;
+ goto out_reset_adapter;
+ }
+
+ INIT_LIST_HEAD(&adapter->cmd_pool);
+ for (i = 0; i < adapter->req_depth; i++) {
+ struct pvscsi_ctx *ctx = adapter->cmd_map + i;
+ list_add(&ctx->list, &adapter->cmd_pool);
+ }
+
+ error = pvscsi_allocate_sg(adapter);
+ if (error) {
+ printk(KERN_ERR "vmw_pvscsi: unable to allocate s/g table\n");
+ goto out_reset_adapter;
+ }
+
+ if (!pvscsi_disable_msix &&
+ pvscsi_setup_msix(adapter, &adapter->irq) == 0) {
+ printk(KERN_INFO "vmw_pvscsi: using MSI-X\n");
+ adapter->use_msix = 1;
+ } else if (!pvscsi_disable_msi && pci_enable_msi(pdev) == 0) {
+ printk(KERN_INFO "vmw_pvscsi: using MSI\n");
+ adapter->use_msi = 1;
+ adapter->irq = pdev->irq;
+ } else {
+ printk(KERN_INFO "vmw_pvscsi: using INTx\n");
+ adapter->irq = pdev->irq;
+ flags = IRQF_SHARED;
+ }
+
+ error = request_irq(adapter->irq, pvscsi_isr, flags,
+ "vmw_pvscsi", adapter);
+ if (error) {
+ printk(KERN_ERR
+ "vmw_pvscsi: unable to request IRQ: %d\n", error);
+ adapter->irq = 0;
+ goto out_reset_adapter;
+ }
+
+ error = scsi_add_host(host, &pdev->dev);
+ if (error) {
+ printk(KERN_ERR
+ "vmw_pvscsi: scsi_add_host failed: %d\n", error);
+ goto out_reset_adapter;
+ }
+
+ dev_info(&pdev->dev, "VMware PVSCSI rev %d host #%u\n",
+ adapter->rev, host->host_no);
+
+ pvscsi_unmask_intr(adapter);
+
+ scsi_scan_host(host);
+
+ return 0;
+
+out_reset_adapter:
+ ll_adapter_reset(adapter);
+out_release_resources:
+ pvscsi_release_resources(adapter);
+out_free_host:
+ scsi_host_put(host);
+out_disable_device:
+ pci_set_drvdata(pdev, NULL);
+ pci_disable_device(pdev);
+
+ return error;
+}
+
+static void __pvscsi_shutdown(struct pvscsi_adapter *adapter)
+{
+ pvscsi_mask_intr(adapter);
+
+ if (adapter->workqueue)
+ flush_workqueue(adapter->workqueue);
+
+ pvscsi_shutdown_intr(adapter);
+
+ pvscsi_process_request_ring(adapter);
+ pvscsi_process_completion_ring(adapter);
+ ll_adapter_reset(adapter);
+}
+
+static void pvscsi_shutdown(struct pci_dev *dev)
+{
+ struct Scsi_Host *host = pci_get_drvdata(dev);
+ struct pvscsi_adapter *adapter = shost_priv(host);
+
+ __pvscsi_shutdown(adapter);
+}
+
+static void pvscsi_remove(struct pci_dev *pdev)
+{
+ struct Scsi_Host *host = pci_get_drvdata(pdev);
+ struct pvscsi_adapter *adapter = shost_priv(host);
+
+ scsi_remove_host(host);
+
+ __pvscsi_shutdown(adapter);
+ pvscsi_release_resources(adapter);
+
+ scsi_host_put(host);
+
+ pci_set_drvdata(pdev, NULL);
+ pci_disable_device(pdev);
+}
+
+static struct pci_driver pvscsi_pci_driver = {
+ .name = "vmw_pvscsi",
+ .id_table = pvscsi_pci_tbl,
+ .probe = pvscsi_probe,
+ .remove = __devexit_p(pvscsi_remove),
+ .shutdown = pvscsi_shutdown,
+};
+
+static int __init pvscsi_init(void)
+{
+ pr_info("%s - version %s\n",
+ PVSCSI_LINUX_DRIVER_DESC, PVSCSI_DRIVER_VERSION_STRING);
+ return pci_register_driver(&pvscsi_pci_driver);
+}
+
+static void __exit pvscsi_exit(void)
+{
+ pci_unregister_driver(&pvscsi_pci_driver);
+}
+
+module_init(pvscsi_init);
+module_exit(pvscsi_exit);
diff --git a/drivers/scsi/vmw_pvscsi.h b/drivers/scsi/vmw_pvscsi.h
new file mode 100644
index 0000000..62e36e7
--- /dev/null
+++ b/drivers/scsi/vmw_pvscsi.h
@@ -0,0 +1,397 @@
+/*
+ * VMware PVSCSI header file
+ *
+ * Copyright (C) 2008-2009, VMware, 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 the
+ * Free Software Foundation; version 2 of the License and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Maintained by: Alok N Kataria <akataria@vmware.com>
+ *
+ */
+
+#ifndef _VMW_PVSCSI_H_
+#define _VMW_PVSCSI_H_
+
+#include <linux/types.h>
+
+#define PVSCSI_DRIVER_VERSION_STRING "1.0.1.0-k"
+
+#define PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT 128
+
+#define MASK(n) ((1 << (n)) - 1) /* make an n-bit mask */
+
+#define PCI_VENDOR_ID_VMWARE 0x15AD
+#define PCI_DEVICE_ID_VMWARE_PVSCSI 0x07C0
+
+/*
+ * host adapter status/error codes
+ */
+enum HostBusAdapterStatus {
+ BTSTAT_SUCCESS = 0x00, /* CCB complete normally with no errors */
+ BTSTAT_LINKED_COMMAND_COMPLETED = 0x0a,
+ BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG = 0x0b,
+ BTSTAT_DATA_UNDERRUN = 0x0c,
+ BTSTAT_SELTIMEO = 0x11, /* SCSI selection timeout */
+ BTSTAT_DATARUN = 0x12, /* data overrun/underrun */
+ BTSTAT_BUSFREE = 0x13, /* unexpected bus free */
+ BTSTAT_INVPHASE = 0x14, /* invalid bus phase or sequence requested by target */
+ BTSTAT_LUNMISMATCH = 0x17, /* linked CCB has different LUN from first CCB */
+ BTSTAT_SENSFAILED = 0x1b, /* auto request sense failed */
+ BTSTAT_TAGREJECT = 0x1c, /* SCSI II tagged queueing message rejected by target */
+ BTSTAT_BADMSG = 0x1d, /* unsupported message received by the host adapter */
+ BTSTAT_HAHARDWARE = 0x20, /* host adapter hardware failed */
+ BTSTAT_NORESPONSE = 0x21, /* target did not respond to SCSI ATN, sent a SCSI RST */
+ BTSTAT_SENTRST = 0x22, /* host adapter asserted a SCSI RST */
+ BTSTAT_RECVRST = 0x23, /* other SCSI devices asserted a SCSI RST */
+ BTSTAT_DISCONNECT = 0x24, /* target device reconnected improperly (w/o tag) */
+ BTSTAT_BUSRESET = 0x25, /* host adapter issued BUS device reset */
+ BTSTAT_ABORTQUEUE = 0x26, /* abort queue generated */
+ BTSTAT_HASOFTWARE = 0x27, /* host adapter software error */
+ BTSTAT_HATIMEOUT = 0x30, /* host adapter hardware timeout error */
+ BTSTAT_SCSIPARITY = 0x34, /* SCSI parity error detected */
+};
+
+/*
+ * Register offsets.
+ *
+ * These registers are accessible both via i/o space and mm i/o.
+ */
+
+enum PVSCSIRegOffset {
+ PVSCSI_REG_OFFSET_COMMAND = 0x0,
+ PVSCSI_REG_OFFSET_COMMAND_DATA = 0x4,
+ PVSCSI_REG_OFFSET_COMMAND_STATUS = 0x8,
+ PVSCSI_REG_OFFSET_LAST_STS_0 = 0x100,
+ PVSCSI_REG_OFFSET_LAST_STS_1 = 0x104,
+ PVSCSI_REG_OFFSET_LAST_STS_2 = 0x108,
+ PVSCSI_REG_OFFSET_LAST_STS_3 = 0x10c,
+ PVSCSI_REG_OFFSET_INTR_STATUS = 0x100c,
+ PVSCSI_REG_OFFSET_INTR_MASK = 0x2010,
+ PVSCSI_REG_OFFSET_KICK_NON_RW_IO = 0x3014,
+ PVSCSI_REG_OFFSET_DEBUG = 0x3018,
+ PVSCSI_REG_OFFSET_KICK_RW_IO = 0x4018,
+};
+
+/*
+ * Virtual h/w commands.
+ */
+
+enum PVSCSICommands {
+ PVSCSI_CMD_FIRST = 0, /* has to be first */
+
+ PVSCSI_CMD_ADAPTER_RESET = 1,
+ PVSCSI_CMD_ISSUE_SCSI = 2,
+ PVSCSI_CMD_SETUP_RINGS = 3,
+ PVSCSI_CMD_RESET_BUS = 4,
+ PVSCSI_CMD_RESET_DEVICE = 5,
+ PVSCSI_CMD_ABORT_CMD = 6,
+ PVSCSI_CMD_CONFIG = 7,
+ PVSCSI_CMD_SETUP_MSG_RING = 8,
+ PVSCSI_CMD_DEVICE_UNPLUG = 9,
+
+ PVSCSI_CMD_LAST = 10 /* has to be last */
+};
+
+/*
+ * Command descriptor for PVSCSI_CMD_RESET_DEVICE --
+ */
+
+struct PVSCSICmdDescResetDevice {
+ u32 target;
+ u8 lun[8];
+} __packed;
+
+/*
+ * Command descriptor for PVSCSI_CMD_ABORT_CMD --
+ *
+ * - currently does not support specifying the LUN.
+ * - _pad should be 0.
+ */
+
+struct PVSCSICmdDescAbortCmd {
+ u64 context;
+ u32 target;
+ u32 _pad;
+} __packed;
+
+/*
+ * Command descriptor for PVSCSI_CMD_SETUP_RINGS --
+ *
+ * Notes:
+ * - reqRingNumPages and cmpRingNumPages need to be power of two.
+ * - reqRingNumPages and cmpRingNumPages need to be different from 0,
+ * - reqRingNumPages and cmpRingNumPages need to be inferior to
+ * PVSCSI_SETUP_RINGS_MAX_NUM_PAGES.
+ */
+
+#define PVSCSI_SETUP_RINGS_MAX_NUM_PAGES 32
+struct PVSCSICmdDescSetupRings {
+ u32 reqRingNumPages;
+ u32 cmpRingNumPages;
+ u64 ringsStatePPN;
+ u64 reqRingPPNs[PVSCSI_SETUP_RINGS_MAX_NUM_PAGES];
+ u64 cmpRingPPNs[PVSCSI_SETUP_RINGS_MAX_NUM_PAGES];
+} __packed;
+
+/*
+ * Command descriptor for PVSCSI_CMD_SETUP_MSG_RING --
+ *
+ * Notes:
+ * - this command was not supported in the initial revision of the h/w
+ * interface. Before using it, you need to check that it is supported by
+ * writing PVSCSI_CMD_SETUP_MSG_RING to the 'command' register, then
+ * immediately after read the 'command status' register:
+ * * a value of -1 means that the cmd is NOT supported,
+ * * a value != -1 means that the cmd IS supported.
+ * If it's supported the 'command status' register should return:
+ * sizeof(PVSCSICmdDescSetupMsgRing) / sizeof(u32).
+ * - this command should be issued _after_ the usual SETUP_RINGS so that the
+ * RingsState page is already setup. If not, the command is a nop.
+ * - numPages needs to be a power of two,
+ * - numPages needs to be different from 0,
+ * - _pad should be zero.
+ */
+
+#define PVSCSI_SETUP_MSG_RING_MAX_NUM_PAGES 16
+
+struct PVSCSICmdDescSetupMsgRing {
+ u32 numPages;
+ u32 _pad;
+ u64 ringPPNs[PVSCSI_SETUP_MSG_RING_MAX_NUM_PAGES];
+} __packed;
+
+enum PVSCSIMsgType {
+ PVSCSI_MSG_DEV_ADDED = 0,
+ PVSCSI_MSG_DEV_REMOVED = 1,
+ PVSCSI_MSG_LAST = 2,
+};
+
+/*
+ * Msg descriptor.
+ *
+ * sizeof(struct PVSCSIRingMsgDesc) == 128.
+ *
+ * - type is of type enum PVSCSIMsgType.
+ * - the content of args depend on the type of event being delivered.
+ */
+
+struct PVSCSIRingMsgDesc {
+ u32 type;
+ u32 args[31];
+} __packed;
+
+struct PVSCSIMsgDescDevStatusChanged {
+ u32 type; /* PVSCSI_MSG_DEV _ADDED / _REMOVED */
+ u32 bus;
+ u32 target;
+ u8 lun[8];
+ u32 pad[27];
+} __packed;
+
+/*
+ * Rings state.
+ *
+ * - the fields:
+ * . msgProdIdx,
+ * . msgConsIdx,
+ * . msgNumEntriesLog2,
+ * .. are only used once the SETUP_MSG_RING cmd has been issued.
+ * - '_pad' helps to ensure that the msg related fields are on their own
+ * cache-line.
+ */
+
+struct PVSCSIRingsState {
+ u32 reqProdIdx;
+ u32 reqConsIdx;
+ u32 reqNumEntriesLog2;
+
+ u32 cmpProdIdx;
+ u32 cmpConsIdx;
+ u32 cmpNumEntriesLog2;
+
+ u8 _pad[104];
+
+ u32 msgProdIdx;
+ u32 msgConsIdx;
+ u32 msgNumEntriesLog2;
+} __packed;
+
+/*
+ * Request descriptor.
+ *
+ * sizeof(RingReqDesc) = 128
+ *
+ * - context: is a unique identifier of a command. It could normally be any
+ * 64bit value, however we currently store it in the serialNumber variable
+ * of struct SCSI_Command, so we have the following restrictions due to the
+ * way this field is handled in the vmkernel storage stack:
+ * * this value can't be 0,
+ * * the upper 32bit need to be 0 since serialNumber is as a u32.
+ * Currently tracked as PR 292060.
+ * - dataLen: contains the total number of bytes that need to be transferred.
+ * - dataAddr:
+ * * if PVSCSI_FLAG_CMD_WITH_SG_LIST is set: dataAddr is the PA of the first
+ * s/g table segment, each s/g segment is entirely contained on a single
+ * page of physical memory,
+ * * if PVSCSI_FLAG_CMD_WITH_SG_LIST is NOT set, then dataAddr is the PA of
+ * the buffer used for the DMA transfer,
+ * - flags:
+ * * PVSCSI_FLAG_CMD_WITH_SG_LIST: see dataAddr above,
+ * * PVSCSI_FLAG_CMD_DIR_NONE: no DMA involved,
+ * * PVSCSI_FLAG_CMD_DIR_TOHOST: transfer from device to main memory,
+ * * PVSCSI_FLAG_CMD_DIR_TODEVICE: transfer from main memory to device,
+ * * PVSCSI_FLAG_CMD_OUT_OF_BAND_CDB: reserved to handle CDBs larger than
+ * 16bytes. To be specified.
+ * - vcpuHint: vcpuId of the processor that will be most likely waiting for the
+ * completion of the i/o. For guest OSes that use lowest priority message
+ * delivery mode (such as windows), we use this "hint" to deliver the
+ * completion action to the proper vcpu. For now, we can use the vcpuId of
+ * the processor that initiated the i/o as a likely candidate for the vcpu
+ * that will be waiting for the completion..
+ * - bus should be 0: we currently only support bus 0 for now.
+ * - unused should be zero'd.
+ */
+
+#define PVSCSI_FLAG_CMD_WITH_SG_LIST (1 << 0)
+#define PVSCSI_FLAG_CMD_OUT_OF_BAND_CDB (1 << 1)
+#define PVSCSI_FLAG_CMD_DIR_NONE (1 << 2)
+#define PVSCSI_FLAG_CMD_DIR_TOHOST (1 << 3)
+#define PVSCSI_FLAG_CMD_DIR_TODEVICE (1 << 4)
+
+struct PVSCSIRingReqDesc {
+ u64 context;
+ u64 dataAddr;
+ u64 dataLen;
+ u64 senseAddr;
+ u32 senseLen;
+ u32 flags;
+ u8 cdb[16];
+ u8 cdbLen;
+ u8 lun[8];
+ u8 tag;
+ u8 bus;
+ u8 target;
+ u8 vcpuHint;
+ u8 unused[59];
+} __packed;
+
+/*
+ * Scatter-gather list management.
+ *
+ * As described above, when PVSCSI_FLAG_CMD_WITH_SG_LIST is set in the
+ * RingReqDesc.flags, then RingReqDesc.dataAddr is the PA of the first s/g
+ * table segment.
+ *
+ * - each segment of the s/g table contain a succession of struct
+ * PVSCSISGElement.
+ * - each segment is entirely contained on a single physical page of memory.
+ * - a "chain" s/g element has the flag PVSCSI_SGE_FLAG_CHAIN_ELEMENT set in
+ * PVSCSISGElement.flags and in this case:
+ * * addr is the PA of the next s/g segment,
+ * * length is undefined, assumed to be 0.
+ */
+
+struct PVSCSISGElement {
+ u64 addr;
+ u32 length;
+ u32 flags;
+} __packed;
+
+/*
+ * Completion descriptor.
+ *
+ * sizeof(RingCmpDesc) = 32
+ *
+ * - context: identifier of the command. The same thing that was specified
+ * under "context" as part of struct RingReqDesc at initiation time,
+ * - dataLen: number of bytes transferred for the actual i/o operation,
+ * - senseLen: number of bytes written into the sense buffer,
+ * - hostStatus: adapter status,
+ * - scsiStatus: device status,
+ * - _pad should be zero.
+ */
+
+struct PVSCSIRingCmpDesc {
+ u64 context;
+ u64 dataLen;
+ u32 senseLen;
+ u16 hostStatus;
+ u16 scsiStatus;
+ u32 _pad[2];
+} __packed;
+
+/*
+ * Interrupt status / IRQ bits.
+ */
+
+#define PVSCSI_INTR_CMPL_0 (1 << 0)
+#define PVSCSI_INTR_CMPL_1 (1 << 1)
+#define PVSCSI_INTR_CMPL_MASK MASK(2)
+
+#define PVSCSI_INTR_MSG_0 (1 << 2)
+#define PVSCSI_INTR_MSG_1 (1 << 3)
+#define PVSCSI_INTR_MSG_MASK (MASK(2) << 2)
+
+#define PVSCSI_INTR_ALL_SUPPORTED MASK(4)
+
+/*
+ * Number of MSI-X vectors supported.
+ */
+#define PVSCSI_MAX_INTRS 24
+
+/*
+ * Enumeration of supported MSI-X vectors
+ */
+#define PVSCSI_VECTOR_COMPLETION 0
+
+/*
+ * Misc constants for the rings.
+ */
+
+#define PVSCSI_MAX_NUM_PAGES_REQ_RING PVSCSI_SETUP_RINGS_MAX_NUM_PAGES
+#define PVSCSI_MAX_NUM_PAGES_CMP_RING PVSCSI_SETUP_RINGS_MAX_NUM_PAGES
+#define PVSCSI_MAX_NUM_PAGES_MSG_RING PVSCSI_SETUP_MSG_RING_MAX_NUM_PAGES
+
+#define PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE \
+ (PAGE_SIZE / sizeof(struct PVSCSIRingReqDesc))
+
+#define PVSCSI_MAX_REQ_QUEUE_DEPTH \
+ (PVSCSI_MAX_NUM_PAGES_REQ_RING * PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE)
+
+#define PVSCSI_MEM_SPACE_COMMAND_NUM_PAGES 1
+#define PVSCSI_MEM_SPACE_INTR_STATUS_NUM_PAGES 1
+#define PVSCSI_MEM_SPACE_MISC_NUM_PAGES 2
+#define PVSCSI_MEM_SPACE_KICK_IO_NUM_PAGES 2
+#define PVSCSI_MEM_SPACE_MSIX_NUM_PAGES 2
+
+enum PVSCSIMemSpace {
+ PVSCSI_MEM_SPACE_COMMAND_PAGE = 0,
+ PVSCSI_MEM_SPACE_INTR_STATUS_PAGE = 1,
+ PVSCSI_MEM_SPACE_MISC_PAGE = 2,
+ PVSCSI_MEM_SPACE_KICK_IO_PAGE = 4,
+ PVSCSI_MEM_SPACE_MSIX_TABLE_PAGE = 6,
+ PVSCSI_MEM_SPACE_MSIX_PBA_PAGE = 7,
+};
+
+#define PVSCSI_MEM_SPACE_NUM_PAGES \
+ (PVSCSI_MEM_SPACE_COMMAND_NUM_PAGES + \
+ PVSCSI_MEM_SPACE_INTR_STATUS_NUM_PAGES + \
+ PVSCSI_MEM_SPACE_MISC_NUM_PAGES + \
+ PVSCSI_MEM_SPACE_KICK_IO_NUM_PAGES + \
+ PVSCSI_MEM_SPACE_MSIX_NUM_PAGES)
+
+#define PVSCSI_MEM_SPACE_SIZE (PVSCSI_MEM_SPACE_NUM_PAGES * PAGE_SIZE)
+
+#endif /* _VMW_PVSCSI_H_ */
diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c
index 093610b..2f6e9d8 100644
--- a/drivers/scsi/wd7000.c
+++ b/drivers/scsi/wd7000.c
@@ -161,7 +161,7 @@
*
* 2003/02/12 - Christoph Hellwig <hch@infradead.org>
*
- * Cleaned up host template defintion
+ * Cleaned up host template definition
* Removed now obsolete wd7000.h
*/
diff --git a/drivers/serial/8250_pnp.c b/drivers/serial/8250_pnp.c
index d71dfe3..36ede02 100644
--- a/drivers/serial/8250_pnp.c
+++ b/drivers/serial/8250_pnp.c
@@ -361,9 +361,9 @@ static const struct pnp_device_id pnp_dev_table[] = {
{ "LTS0001", 0 },
/* Rockwell's (PORALiNK) 33600 INT PNP */
{ "WCI0003", 0 },
- /* Unkown PnP modems */
+ /* Unknown PnP modems */
{ "PNPCXXX", UNKNOWN_DEV },
- /* More unkown PnP modems */
+ /* More unknown PnP modems */
{ "PNPDXXX", UNKNOWN_DEV },
{ "", 0 }
};
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 50943ff..9ff47db0 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -996,7 +996,7 @@ config SERIAL_IP22_ZILOG_CONSOLE
config SERIAL_SH_SCI
tristate "SuperH SCI(F) serial port support"
- depends on SUPERH || H8300
+ depends on HAVE_CLK && (SUPERH || H8300)
select SERIAL_CORE
config SERIAL_SH_SCI_NR_UARTS
diff --git a/drivers/serial/mcf.c b/drivers/serial/mcf.c
index b443824..7bb5fee 100644
--- a/drivers/serial/mcf.c
+++ b/drivers/serial/mcf.c
@@ -602,7 +602,7 @@ static int __devinit mcf_probe(struct platform_device *pdev)
/****************************************************************************/
-static int mcf_remove(struct platform_device *pdev)
+static int __devexit mcf_remove(struct platform_device *pdev)
{
struct uart_port *port;
int i;
diff --git a/drivers/serial/pmac_zilog.h b/drivers/serial/pmac_zilog.h
index 570b0d9..f6e77f1 100644
--- a/drivers/serial/pmac_zilog.h
+++ b/drivers/serial/pmac_zilog.h
@@ -73,7 +73,7 @@ static inline struct uart_pmac_port *pmz_get_port_A(struct uart_pmac_port *uap)
}
/*
- * Register acessors. Note that we don't need to enforce a recovery
+ * Register accessors. Note that we don't need to enforce a recovery
* delay on PCI PowerMac hardware, it's dealt in HW by the MacIO chip,
* though if we try to use this driver on older machines, we might have
* to add it back
diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c
index 6498bd1..ff38dbd 100644
--- a/drivers/serial/sh-sci.c
+++ b/drivers/serial/sh-sci.c
@@ -50,7 +50,6 @@
#include <linux/list.h>
#ifdef CONFIG_SUPERH
-#include <asm/clock.h>
#include <asm/sh_bios.h>
#endif
@@ -79,22 +78,18 @@ struct sci_port {
struct timer_list break_timer;
int break_flag;
-#ifdef CONFIG_HAVE_CLK
/* Interface clock */
struct clk *iclk;
/* Data clock */
struct clk *dclk;
-#endif
+
struct list_head node;
};
struct sh_sci_priv {
spinlock_t lock;
struct list_head ports;
-
-#ifdef CONFIG_HAVE_CLK
struct notifier_block clk_nb;
-#endif
};
/* Function prototypes */
@@ -156,32 +151,6 @@ static void sci_poll_put_char(struct uart_port *port, unsigned char c)
}
#endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE */
-#if defined(__H8300S__)
-enum { sci_disable, sci_enable };
-
-static void h8300_sci_config(struct uart_port *port, unsigned int ctrl)
-{
- volatile unsigned char *mstpcrl = (volatile unsigned char *)MSTPCRL;
- int ch = (port->mapbase - SMR0) >> 3;
- unsigned char mask = 1 << (ch+1);
-
- if (ctrl == sci_disable)
- *mstpcrl |= mask;
- else
- *mstpcrl &= ~mask;
-}
-
-static void h8300_sci_enable(struct uart_port *port)
-{
- h8300_sci_config(port, sci_enable);
-}
-
-static void h8300_sci_disable(struct uart_port *port)
-{
- h8300_sci_config(port, sci_disable);
-}
-#endif
-
#if defined(__H8300H__) || defined(__H8300S__)
static void sci_init_pins(struct uart_port *port, unsigned int cflag)
{
@@ -733,7 +702,6 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
return ret;
}
-#ifdef CONFIG_HAVE_CLK
/*
* Here we define a transistion notifier so that we can update all of our
* ports' baud rate when the peripheral clock changes.
@@ -751,7 +719,6 @@ static int sci_notifier(struct notifier_block *self,
spin_lock_irqsave(&priv->lock, flags);
list_for_each_entry(sci_port, &priv->ports, node)
sci_port->port.uartclk = clk_get_rate(sci_port->dclk);
-
spin_unlock_irqrestore(&priv->lock, flags);
}
@@ -778,7 +745,6 @@ static void sci_clk_disable(struct uart_port *port)
clk_disable(sci_port->dclk);
}
-#endif
static int sci_request_irq(struct sci_port *port)
{
@@ -833,8 +799,8 @@ static void sci_free_irq(struct sci_port *port)
static unsigned int sci_tx_empty(struct uart_port *port)
{
- /* Can't detect */
- return TIOCSER_TEMT;
+ unsigned short status = sci_in(port, SCxSR);
+ return status & SCxSR_TEND(port) ? TIOCSER_TEMT : 0;
}
static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl)
@@ -1077,21 +1043,10 @@ static void __devinit sci_init_single(struct platform_device *dev,
sci_port->port.iotype = UPIO_MEM;
sci_port->port.line = index;
sci_port->port.fifosize = 1;
-
-#if defined(__H8300H__) || defined(__H8300S__)
-#ifdef __H8300S__
- sci_port->enable = h8300_sci_enable;
- sci_port->disable = h8300_sci_disable;
-#endif
- sci_port->port.uartclk = CONFIG_CPU_CLOCK;
-#elif defined(CONFIG_HAVE_CLK)
sci_port->iclk = p->clk ? clk_get(&dev->dev, p->clk) : NULL;
sci_port->dclk = clk_get(&dev->dev, "peripheral_clk");
sci_port->enable = sci_clk_enable;
sci_port->disable = sci_clk_disable;
-#else
-#error "Need a valid uartclk"
-#endif
sci_port->break_timer.data = (unsigned long)sci_port;
sci_port->break_timer.function = sci_break_timer;
@@ -1106,7 +1061,6 @@ static void __devinit sci_init_single(struct platform_device *dev,
sci_port->type = sci_port->port.type = p->type;
memcpy(&sci_port->irqs, &p->irqs, sizeof(p->irqs));
-
}
#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
@@ -1239,14 +1193,11 @@ static int sci_remove(struct platform_device *dev)
struct sci_port *p;
unsigned long flags;
-#ifdef CONFIG_HAVE_CLK
cpufreq_unregister_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER);
-#endif
spin_lock_irqsave(&priv->lock, flags);
list_for_each_entry(p, &priv->ports, node)
uart_remove_one_port(&sci_uart_driver, &p->port);
-
spin_unlock_irqrestore(&priv->lock, flags);
kfree(priv);
@@ -1307,10 +1258,8 @@ static int __devinit sci_probe(struct platform_device *dev)
spin_lock_init(&priv->lock);
platform_set_drvdata(dev, priv);
-#ifdef CONFIG_HAVE_CLK
priv->clk_nb.notifier_call = sci_notifier;
cpufreq_register_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER);
-#endif
if (dev->id != -1) {
ret = sci_probe_single(dev, dev->id, p, &sci_ports[dev->id]);
@@ -1370,7 +1319,7 @@ static struct dev_pm_ops sci_dev_pm_ops = {
static struct platform_driver sci_driver = {
.probe = sci_probe,
- .remove = __devexit_p(sci_remove),
+ .remove = sci_remove,
.driver = {
.name = "sh-sci",
.owner = THIS_MODULE,
diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h
index 3e2fcf9..a32094ee 100644
--- a/drivers/serial/sh-sci.h
+++ b/drivers/serial/sh-sci.h
@@ -1,5 +1,5 @@
#include <linux/serial_core.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/gpio.h>
#if defined(CONFIG_H83007) || defined(CONFIG_H83068)
diff --git a/drivers/serial/ucc_uart.c b/drivers/serial/ucc_uart.c
index 0c08f28..46de564 100644
--- a/drivers/serial/ucc_uart.c
+++ b/drivers/serial/ucc_uart.c
@@ -313,7 +313,7 @@ static void qe_uart_stop_tx(struct uart_port *port)
* This function will attempt to stuff of all the characters from the
* kernel's transmit buffer into TX BDs.
*
- * A return value of non-zero indicates that it sucessfully stuffed all
+ * A return value of non-zero indicates that it successfully stuffed all
* characters from the kernel buffer.
*
* A return value of zero indicates that there are still characters in the
diff --git a/drivers/sh/Makefile b/drivers/sh/Makefile
index 6a025ce..4956bf1 100644
--- a/drivers/sh/Makefile
+++ b/drivers/sh/Makefile
@@ -3,4 +3,5 @@
#
obj-$(CONFIG_SUPERHYWAY) += superhyway/
obj-$(CONFIG_MAPLE) += maple/
+obj-$(CONFIG_GENERIC_GPIO) += pfc.o
obj-y += intc.o
diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c
index 559b5fe..a7e5c2e 100644
--- a/drivers/sh/intc.c
+++ b/drivers/sh/intc.c
@@ -2,6 +2,7 @@
* Shared interrupt handling code for IPR and INTC2 types of IRQs.
*
* Copyright (C) 2007, 2008 Magnus Damm
+ * Copyright (C) 2009 Paul Mundt
*
* Based on intc2.c and ipr.c
*
@@ -24,6 +25,7 @@
#include <linux/sysdev.h>
#include <linux/list.h>
#include <linux/topology.h>
+#include <linux/bitmap.h>
#define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \
((shift) | ((width) << 5) | ((fn) << 9) | ((mode) << 13) | \
@@ -59,6 +61,20 @@ struct intc_desc_int {
static LIST_HEAD(intc_list);
+/*
+ * The intc_irq_map provides a global map of bound IRQ vectors for a
+ * given platform. Allocation of IRQs are either static through the CPU
+ * vector map, or dynamic in the case of board mux vectors or MSI.
+ *
+ * As this is a central point for all IRQ controllers on the system,
+ * each of the available sources are mapped out here. This combined with
+ * sparseirq makes it quite trivial to keep the vector map tightly packed
+ * when dynamically creating IRQs, as well as tying in to otherwise
+ * unused irq_desc positions in the sparse array.
+ */
+static DECLARE_BITMAP(intc_irq_map, NR_IRQS);
+static DEFINE_SPINLOCK(vector_lock);
+
#ifdef CONFIG_SMP
#define IS_SMP(x) x.smp
#define INTC_REG(d, x, c) (d->reg[(x)] + ((d->smp[(x)] & 0xff) * c))
@@ -70,9 +86,7 @@ static LIST_HEAD(intc_list);
#endif
static unsigned int intc_prio_level[NR_IRQS]; /* for now */
-#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A)
static unsigned long ack_handle[NR_IRQS];
-#endif
static inline struct intc_desc_int *get_intc_desc(unsigned int irq)
{
@@ -250,7 +264,6 @@ static int intc_set_wake(unsigned int irq, unsigned int on)
return 0; /* allow wakeup, but setup hardware in intc_suspend() */
}
-#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A)
static void intc_mask_ack(unsigned int irq)
{
struct intc_desc_int *d = get_intc_desc(irq);
@@ -282,7 +295,6 @@ static void intc_mask_ack(unsigned int irq)
}
}
}
-#endif
static struct intc_handle_int *intc_find_irq(struct intc_handle_int *hp,
unsigned int nr_hp,
@@ -501,7 +513,6 @@ static unsigned int __init intc_prio_data(struct intc_desc *desc,
return 0;
}
-#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A)
static unsigned int __init intc_ack_data(struct intc_desc *desc,
struct intc_desc_int *d,
intc_enum enum_id)
@@ -533,7 +544,6 @@ static unsigned int __init intc_ack_data(struct intc_desc *desc,
return 0;
}
-#endif
static unsigned int __init intc_sense_data(struct intc_desc *desc,
struct intc_desc_int *d,
@@ -572,6 +582,11 @@ static void __init intc_register_irq(struct intc_desc *desc,
struct intc_handle_int *hp;
unsigned int data[2], primary;
+ /*
+ * Register the IRQ position with the global IRQ map
+ */
+ set_bit(irq, intc_irq_map);
+
/* Prefer single interrupt source bitmap over other combinations:
* 1. bitmap, single interrupt source
* 2. priority, single interrupt source
@@ -641,10 +656,8 @@ static void __init intc_register_irq(struct intc_desc *desc,
/* irq should be disabled by default */
d->chip.mask(irq);
-#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A)
if (desc->ack_regs)
ack_handle[irq] = intc_ack_data(desc, d, enum_id);
-#endif
}
static unsigned int __init save_reg(struct intc_desc_int *d,
@@ -681,10 +694,8 @@ void __init register_intc_controller(struct intc_desc *desc)
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;
-
-#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A)
d->nr_reg += desc->ack_regs ? desc->nr_ack_regs : 0;
-#endif
+
d->reg = kzalloc(d->nr_reg * sizeof(*d->reg), GFP_NOWAIT);
#ifdef CONFIG_SMP
d->smp = kzalloc(d->nr_reg * sizeof(*d->smp), GFP_NOWAIT);
@@ -727,14 +738,12 @@ void __init register_intc_controller(struct intc_desc *desc)
d->chip.set_type = intc_set_sense;
d->chip.set_wake = intc_set_wake;
-#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A)
if (desc->ack_regs) {
for (i = 0; i < desc->nr_ack_regs; i++)
k += save_reg(d, k, desc->ack_regs[i].set_reg, 0);
d->chip.mask_ack = intc_mask_ack;
}
-#endif
BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */
@@ -856,5 +865,91 @@ static int __init register_intc_sysdevs(void)
return error;
}
-
device_initcall(register_intc_sysdevs);
+
+/*
+ * Dynamic IRQ allocation and deallocation
+ */
+static unsigned int create_irq_on_node(unsigned int irq_want, int node)
+{
+ unsigned int irq = 0, new;
+ unsigned long flags;
+ struct irq_desc *desc;
+
+ spin_lock_irqsave(&vector_lock, flags);
+
+ /*
+ * First try the wanted IRQ, then scan.
+ */
+ if (test_and_set_bit(irq_want, intc_irq_map)) {
+ new = find_first_zero_bit(intc_irq_map, nr_irqs);
+ if (unlikely(new == nr_irqs))
+ goto out_unlock;
+
+ desc = irq_to_desc_alloc_node(new, node);
+ if (unlikely(!desc)) {
+ pr_info("can't get irq_desc for %d\n", new);
+ goto out_unlock;
+ }
+
+ desc = move_irq_desc(desc, node);
+ __set_bit(new, intc_irq_map);
+ irq = new;
+ }
+
+out_unlock:
+ spin_unlock_irqrestore(&vector_lock, flags);
+
+ if (irq > 0)
+ dynamic_irq_init(irq);
+
+ return irq;
+}
+
+int create_irq(void)
+{
+ int nid = cpu_to_node(smp_processor_id());
+ int irq;
+
+ irq = create_irq_on_node(NR_IRQS_LEGACY, nid);
+ if (irq == 0)
+ irq = -1;
+
+ return irq;
+}
+
+void destroy_irq(unsigned int irq)
+{
+ unsigned long flags;
+
+ dynamic_irq_cleanup(irq);
+
+ spin_lock_irqsave(&vector_lock, flags);
+ __clear_bit(irq, intc_irq_map);
+ spin_unlock_irqrestore(&vector_lock, flags);
+}
+
+int reserve_irq_vector(unsigned int irq)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&vector_lock, flags);
+ if (test_and_set_bit(irq, intc_irq_map))
+ ret = -EBUSY;
+ spin_unlock_irqrestore(&vector_lock, flags);
+
+ return ret;
+}
+
+void reserve_irq_legacy(void)
+{
+ unsigned long flags;
+ int i, j;
+
+ spin_lock_irqsave(&vector_lock, flags);
+ j = find_first_bit(intc_irq_map, nr_irqs);
+ for (i = 0; i < j; i++)
+ __set_bit(i, intc_irq_map);
+ spin_unlock_irqrestore(&vector_lock, flags);
+}
diff --git a/drivers/sh/maple/maple.c b/drivers/sh/maple/maple.c
index 93c20e1..4e8f57d 100644
--- a/drivers/sh/maple/maple.c
+++ b/drivers/sh/maple/maple.c
@@ -106,7 +106,7 @@ static void maple_dma_reset(void)
* max delay is 11
*/
ctrl_outl(MAPLE_2MBPS | MAPLE_TIMEOUT(0xFFFF), MAPLE_SPEED);
- ctrl_outl(PHYSADDR(maple_sendbuf), MAPLE_DMAADDR);
+ ctrl_outl(virt_to_phys(maple_sendbuf), MAPLE_DMAADDR);
ctrl_outl(1, MAPLE_ENABLE);
}
@@ -258,7 +258,7 @@ static void maple_build_block(struct mapleq *mq)
maple_lastptr = maple_sendptr;
*maple_sendptr++ = (port << 16) | len | 0x80000000;
- *maple_sendptr++ = PHYSADDR(mq->recvbuf->buf);
+ *maple_sendptr++ = virt_to_phys(mq->recvbuf->buf);
*maple_sendptr++ =
mq->command | (to << 8) | (from << 16) | (len << 24);
while (len-- > 0)
diff --git a/arch/sh/kernel/gpio.c b/drivers/sh/pfc.c
index d22e5af..841ed50 100644
--- a/arch/sh/kernel/gpio.c
+++ b/drivers/sh/pfc.c
@@ -7,7 +7,6 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
-
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/list.h>
@@ -35,11 +34,11 @@ static unsigned long gpio_read_raw_reg(unsigned long reg,
{
switch (reg_width) {
case 8:
- return ctrl_inb(reg);
+ return __raw_readb(reg);
case 16:
- return ctrl_inw(reg);
+ return __raw_readw(reg);
case 32:
- return ctrl_inl(reg);
+ return __raw_readl(reg);
}
BUG();
@@ -52,13 +51,13 @@ static void gpio_write_raw_reg(unsigned long reg,
{
switch (reg_width) {
case 8:
- ctrl_outb(data, reg);
+ __raw_writeb(data, reg);
return;
case 16:
- ctrl_outw(data, reg);
+ __raw_writew(data, reg);
return;
case 32:
- ctrl_outl(data, reg);
+ __raw_writel(data, reg);
return;
}
@@ -72,11 +71,9 @@ static void gpio_write_bit(struct pinmux_data_reg *dr,
pos = dr->reg_width - (in_pos + 1);
-#ifdef DEBUG
- pr_info("write_bit addr = %lx, value = %ld, pos = %ld, "
- "r_width = %ld\n",
- dr->reg, !!value, pos, dr->reg_width);
-#endif
+ pr_debug("write_bit addr = %lx, value = %ld, pos = %ld, "
+ "r_width = %ld\n",
+ dr->reg, !!value, pos, dr->reg_width);
if (value)
set_bit(pos, &dr->reg_shadow);
@@ -95,11 +92,9 @@ static int gpio_read_reg(unsigned long reg, unsigned long reg_width,
mask = (1 << field_width) - 1;
pos = reg_width - ((in_pos + 1) * field_width);
-#ifdef DEBUG
- pr_info("read_reg: addr = %lx, pos = %ld, "
- "r_width = %ld, f_width = %ld\n",
- reg, pos, reg_width, field_width);
-#endif
+ pr_debug("read_reg: addr = %lx, pos = %ld, "
+ "r_width = %ld, f_width = %ld\n",
+ reg, pos, reg_width, field_width);
data = gpio_read_raw_reg(reg, reg_width);
return (data >> pos) & mask;
@@ -114,24 +109,22 @@ static void gpio_write_reg(unsigned long reg, unsigned long reg_width,
mask = (1 << field_width) - 1;
pos = reg_width - ((in_pos + 1) * field_width);
-#ifdef DEBUG
- pr_info("write_reg addr = %lx, value = %ld, pos = %ld, "
- "r_width = %ld, f_width = %ld\n",
- reg, value, pos, reg_width, field_width);
-#endif
+ pr_debug("write_reg addr = %lx, value = %ld, pos = %ld, "
+ "r_width = %ld, f_width = %ld\n",
+ reg, value, pos, reg_width, field_width);
mask = ~(mask << pos);
value = value << pos;
switch (reg_width) {
case 8:
- ctrl_outb((ctrl_inb(reg) & mask) | value, reg);
+ __raw_writeb((__raw_readb(reg) & mask) | value, reg);
break;
case 16:
- ctrl_outw((ctrl_inw(reg) & mask) | value, reg);
+ __raw_writew((__raw_readw(reg) & mask) | value, reg);
break;
case 32:
- ctrl_outl((ctrl_inl(reg) & mask) | value, reg);
+ __raw_writel((__raw_readl(reg) & mask) | value, reg);
break;
}
}
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index 5d23983..20d7322 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -30,7 +30,6 @@
#include <linux/errno.h>
#include <linux/mutex.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/spi/spi.h>
#include <linux/spi/spidev.h>
@@ -42,7 +41,7 @@
* This supports acccess to SPI devices using normal userspace I/O calls.
* Note that while traditional UNIX/POSIX I/O semantics are half duplex,
* and often mask message boundaries, full SPI support requires full duplex
- * transfers. There are several kinds of of internal message boundaries to
+ * transfers. There are several kinds of internal message boundaries to
* handle chipselect management and other protocol options.
*
* SPI has a character major number assigned. We allocate minor numbers
@@ -477,7 +476,6 @@ static int spidev_open(struct inode *inode, struct file *filp)
struct spidev_data *spidev;
int status = -ENXIO;
- lock_kernel();
mutex_lock(&device_list_lock);
list_for_each_entry(spidev, &device_list, device_entry) {
@@ -503,7 +501,6 @@ static int spidev_open(struct inode *inode, struct file *filp)
pr_debug("spidev: nothing for minor %d\n", iminor(inode));
mutex_unlock(&device_list_lock);
- unlock_kernel();
return status;
}
diff --git a/drivers/staging/otus/80211core/pub_zfi.h b/drivers/staging/otus/80211core/pub_zfi.h
index a35bd5d..60b7d1c 100644
--- a/drivers/staging/otus/80211core/pub_zfi.h
+++ b/drivers/staging/otus/80211core/pub_zfi.h
@@ -20,7 +20,7 @@
#include "../oal_dt.h"
/***** Section 1 : Tunable Parameters *****/
-/* The defintions in this section are tunabel parameters */
+/* The definitions in this section are tunabel parameters */
/* Maximum number of BSS that could be scaned */
#define ZM_MAX_BSS 128
diff --git a/drivers/staging/otus/zdcompat.h b/drivers/staging/otus/zdcompat.h
index 84ac433..cdcaef5 100644
--- a/drivers/staging/otus/zdcompat.h
+++ b/drivers/staging/otus/zdcompat.h
@@ -17,7 +17,7 @@
/* Module Name : zdcompat.h */
/* */
/* Abstract */
-/* This module contains function defintion for compatibility. */
+/* This module contains function definition for compatibility. */
/* */
/* NOTES */
/* Platform dependent. */
diff --git a/drivers/staging/rtl8187se/r8180.h b/drivers/staging/rtl8187se/r8180.h
index 8216d7e..35ed60b 100644
--- a/drivers/staging/rtl8187se/r8180.h
+++ b/drivers/staging/rtl8187se/r8180.h
@@ -521,7 +521,7 @@ typedef struct r8180_priv
//u32 NumTxOkInPeriod; //YJ,del,080828
u8 TxPollingTimes;
- bool bApBufOurFrame;// TRUE if AP buffer our unicast data , we will keep eAwake untill receive data or timeout.
+ bool bApBufOurFrame;// TRUE if AP buffer our unicast data , we will keep eAwake until receive data or timeout.
u8 WaitBufDataBcnCount;
u8 WaitBufDataTimeOut;
diff --git a/drivers/staging/rtl8192su/r8192S_phyreg.h b/drivers/staging/rtl8192su/r8192S_phyreg.h
index 96c7cfa..acf644f 100644
--- a/drivers/staging/rtl8192su/r8192S_phyreg.h
+++ b/drivers/staging/rtl8192su/r8192S_phyreg.h
@@ -38,7 +38,7 @@
// 2. 0x800/0x900/0xA00/0xC00/0xD00/0xE00
// 3. RF register 0x00-2E
// 4. Bit Mask for BB/RF register
-// 5. Other defintion for BB/RF R/W
+// 5. Other definition for BB/RF R/W
//
diff --git a/drivers/staging/wavelan/wavelan_cs.c b/drivers/staging/wavelan/wavelan_cs.c
index 33918fd..10c702b 100644
--- a/drivers/staging/wavelan/wavelan_cs.c
+++ b/drivers/staging/wavelan/wavelan_cs.c
@@ -3987,7 +3987,7 @@ wavelan_interrupt(int irq,
#endif
/* Prevent reentrancy. We need to do that because we may have
- * multiple interrupt handler running concurently.
+ * multiple interrupt handler running concurrently.
* It is safe because interrupts are disabled before aquiring
* the spinlock. */
spin_lock(&lp->spinlock);
diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c
index 40de151..e89304c 100644
--- a/drivers/telephony/ixj.c
+++ b/drivers/telephony/ixj.c
@@ -4190,7 +4190,7 @@ static void ixj_aec_start(IXJ *j, int level)
ixj_WriteDSPCommand(0x1224, j);
ixj_WriteDSPCommand(0xE014, j);
- ixj_WriteDSPCommand(0x0003, j); /* Lock threashold at 3dB */
+ ixj_WriteDSPCommand(0x0003, j); /* Lock threshold at 3dB */
ixj_WriteDSPCommand(0xE338, j); /* Set Echo Suppresser Attenuation to 0dB */
@@ -4235,7 +4235,7 @@ static void ixj_aec_start(IXJ *j, int level)
ixj_WriteDSPCommand(0x1224, j);
ixj_WriteDSPCommand(0xE014, j);
- ixj_WriteDSPCommand(0x0003, j); /* Lock threashold at 3dB */
+ ixj_WriteDSPCommand(0x0003, j); /* Lock threshold at 3dB */
ixj_WriteDSPCommand(0xE338, j); /* Set Echo Suppresser Attenuation to 0dB */
diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c
index d171b56..bba4d3e 100644
--- a/drivers/usb/atm/ueagle-atm.c
+++ b/drivers/usb/atm/ueagle-atm.c
@@ -1958,7 +1958,7 @@ static void uea_dispatch_cmv_e1(struct uea_softc *sc, struct intr_pkt *intr)
goto bad1;
/* FIXME : ADI930 reply wrong preambule (func = 2, sub = 2) to
- * the first MEMACESS cmv. Ignore it...
+ * the first MEMACCESS cmv. Ignore it...
*/
if (cmv->bFunction != dsc->function) {
if (UEA_CHIP_VERSION(sc) == ADI930
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 2473cf0..b4bd241 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -1,5 +1,5 @@
/**
- * drivers/usb/class/usbtmc.c - USB Test & Measurment class driver
+ * drivers/usb/class/usbtmc.c - USB Test & Measurement class driver
*
* Copyright (C) 2007 Stefan Kopp, Gechingen, Germany
* Copyright (C) 2008 Novell, Inc.
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index da718e8..e80f1af 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -1890,7 +1890,7 @@ static void cancel_async_set_config(struct usb_device *udev)
* routine gets around the normal restrictions by using a work thread to
* submit the change-config request.
*
- * Returns 0 if the request was succesfully queued, error code otherwise.
+ * Returns 0 if the request was successfully queued, error code otherwise.
* The caller has no way to know whether the queued request will eventually
* succeed.
*/
diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c
index 7953948..4e36578 100644
--- a/drivers/usb/gadget/f_acm.c
+++ b/drivers/usb/gadget/f_acm.c
@@ -432,7 +432,7 @@ static void acm_disable(struct usb_function *f)
* @length: size of data
* Context: irqs blocked, acm->lock held, acm_notify_req non-null
*
- * Returns zero on sucess or a negative errno.
+ * Returns zero on success or a negative errno.
*
* See section 6.3.5 of the CDC 1.1 specification for information
* about the only notification we issue: SerialState change.
diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c
index 1937d8c..adda120 100644
--- a/drivers/usb/gadget/pxa27x_udc.c
+++ b/drivers/usb/gadget/pxa27x_udc.c
@@ -1524,7 +1524,7 @@ static int pxa_udc_get_frame(struct usb_gadget *_gadget)
* pxa_udc_wakeup - Force udc device out of suspend
* @_gadget: usb gadget
*
- * Returns 0 if succesfull, error code otherwise
+ * Returns 0 if successfull, error code otherwise
*/
static int pxa_udc_wakeup(struct usb_gadget *_gadget)
{
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index f5f5601..d8f4aaa 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -210,7 +210,7 @@ static int handshake_on_error_set_halt(struct ehci_hcd *ehci, void __iomem *ptr,
if (error) {
ehci_halt(ehci);
ehci_to_hcd(ehci)->state = HC_STATE_HALT;
- ehci_err(ehci, "force halt; handhake %p %08x %08x -> %d\n",
+ ehci_err(ehci, "force halt; handshake %p %08x %08x -> %d\n",
ptr, mask, done, error);
}
diff --git a/drivers/usb/host/fhci-sched.c b/drivers/usb/host/fhci-sched.c
index 62a226b..00a2985 100644
--- a/drivers/usb/host/fhci-sched.c
+++ b/drivers/usb/host/fhci-sched.c
@@ -627,7 +627,7 @@ irqreturn_t fhci_irq(struct usb_hcd *hcd)
/*
- * Process normal completions(error or sucess) and clean the schedule.
+ * Process normal completions(error or success) and clean the schedule.
*
* This is the main path for handing urbs back to drivers. The only other patth
* is process_del_list(),which unlinks URBs by scanning EDs,instead of scanning
diff --git a/drivers/usb/wusbcore/crypto.c b/drivers/usb/wusbcore/crypto.c
index 9ec7fd5..9579cf4 100644
--- a/drivers/usb/wusbcore/crypto.c
+++ b/drivers/usb/wusbcore/crypto.c
@@ -111,7 +111,7 @@ struct aes_ccm_b1 {
*
* CCM uses Ax blocks to generate a keystream with which the MIC and
* the message's payload are encoded. A0 always encrypts/decrypts the
- * MIC. Ax (x>0) are used for the sucesive payload blocks.
+ * MIC. Ax (x>0) are used for the successive payload blocks.
*
* The x is the counter, and is increased for each block.
*/
diff --git a/drivers/usb/wusbcore/wa-xfer.c b/drivers/usb/wusbcore/wa-xfer.c
index 613a5fc..489b478 100644
--- a/drivers/usb/wusbcore/wa-xfer.c
+++ b/drivers/usb/wusbcore/wa-xfer.c
@@ -558,7 +558,7 @@ static void wa_seg_dto_cb(struct urb *urb)
/*
* Callback for the segment request
*
- * If succesful transition state (unless already transitioned or
+ * If successful transition state (unless already transitioned or
* outbound transfer); otherwise, take a note of the error, mark this
* segment done and try completion.
*
@@ -1364,7 +1364,7 @@ segment_aborted:
/*
* Callback for the IN data phase
*
- * If succesful transition state; otherwise, take a note of the
+ * If successful transition state; otherwise, take a note of the
* error, mark this segment done and try completion.
*
* Note we don't access until we are sure that the transfer hasn't
diff --git a/drivers/uwb/i1480/dfu/usb.c b/drivers/uwb/i1480/dfu/usb.c
index c7080d4..0bb665a 100644
--- a/drivers/uwb/i1480/dfu/usb.c
+++ b/drivers/uwb/i1480/dfu/usb.c
@@ -229,7 +229,7 @@ void i1480_usb_neep_cb(struct urb *urb)
* will verify it.
*
* Set i1480->evt_result with the result of getting the event or its
- * size (if succesful).
+ * size (if successful).
*
* Delivers the data directly to i1480->evt_buf
*/
diff --git a/drivers/uwb/neh.c b/drivers/uwb/neh.c
index 0af8916..78510a1 100644
--- a/drivers/uwb/neh.c
+++ b/drivers/uwb/neh.c
@@ -150,7 +150,7 @@ void uwb_rc_neh_put(struct uwb_rc_neh *neh)
* 0xff is invalid, so they must not be used. Initialization
* fills up those two in the bitmap so they are not allocated.
*
- * We spread the allocation around to reduce the posiblity of two
+ * We spread the allocation around to reduce the possibility of two
* consecutive opened @neh's getting the same context ID assigned (to
* avoid surprises with late events that timed out long time ago). So
* first we search from where @rc->ctx_roll is, if not found, we
diff --git a/drivers/uwb/wlp/txrx.c b/drivers/uwb/wlp/txrx.c
index 86a853b..7350ed6 100644
--- a/drivers/uwb/wlp/txrx.c
+++ b/drivers/uwb/wlp/txrx.c
@@ -282,7 +282,7 @@ EXPORT_SYMBOL_GPL(wlp_receive_frame);
* and transmission will be done by the calling function.
* @dst: On return this will contain the device address to which the
* frame is destined.
- * @returns: 0 on success no tx : WLP header sucessfully applied to skb buffer,
+ * @returns: 0 on success no tx : WLP header successfully applied to skb buffer,
* calling function can proceed with tx
* 1 on success with tx : WLP will take over transmission of this
* frame
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index d5e8010..3d886c6 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -964,7 +964,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
if (sinfo->atmel_lcdfb_power_control)
sinfo->atmel_lcdfb_power_control(1);
- dev_info(dev, "fb%d: Atmel LCDC at 0x%08lx (mapped at %p), irq %lu\n",
+ dev_info(dev, "fb%d: Atmel LCDC at 0x%08lx (mapped at %p), irq %d\n",
info->node, info->fix.mmio_start, sinfo->mmio, sinfo->irq_base);
return 0;
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index 913b4a4..1ddeb4c 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -3276,7 +3276,7 @@ static void __devinit aty_init_lcd(struct atyfb_par *par, u32 bios_base)
txtformat = "24 bit interface";
break;
default:
- txtformat = "unkown format";
+ txtformat = "unknown format";
}
} else {
switch (format & 7) {
@@ -3299,7 +3299,7 @@ static void __devinit aty_init_lcd(struct atyfb_par *par, u32 bios_base)
txtformat = "262144 colours (FDPI-2 mode)";
break;
default:
- txtformat = "unkown format";
+ txtformat = "unknown format";
}
}
PRINTKI("%s%s %s monitor detected: %s\n",
diff --git a/drivers/video/backlight/atmel-pwm-bl.c b/drivers/video/backlight/atmel-pwm-bl.c
index 505c082..2cf7ba5 100644
--- a/drivers/video/backlight/atmel-pwm-bl.c
+++ b/drivers/video/backlight/atmel-pwm-bl.c
@@ -158,7 +158,7 @@ static int atmel_pwm_bl_probe(struct platform_device *pdev)
goto err_free_pwm;
}
- /* Turn display off by defatult. */
+ /* Turn display off by default. */
retval = gpio_direction_output(pwmbl->gpio_on,
0 ^ pdata->on_active_low);
if (retval)
diff --git a/drivers/video/backlight/tosa_lcd.c b/drivers/video/backlight/tosa_lcd.c
index 50ec17d..fa32b94 100644
--- a/drivers/video/backlight/tosa_lcd.c
+++ b/drivers/video/backlight/tosa_lcd.c
@@ -177,7 +177,7 @@ static int __devinit tosa_lcd_probe(struct spi_device *spi)
if (!data)
return -ENOMEM;
- data->is_vga = true; /* defaut to VGA mode */
+ data->is_vga = true; /* default to VGA mode */
/*
* bits_per_word cannot be configured in platform data
diff --git a/drivers/video/console/sticore.c b/drivers/video/console/sticore.c
index 857b366..6468a29 100644
--- a/drivers/video/console/sticore.c
+++ b/drivers/video/console/sticore.c
@@ -436,7 +436,7 @@ sti_init_glob_cfg(struct sti_struct *sti,
(offs < PCI_BASE_ADDRESS_0 ||
offs > PCI_BASE_ADDRESS_5)) {
printk (KERN_WARNING
- "STI pci region maping for region %d (%02x) can't be mapped\n",
+ "STI pci region mapping for region %d (%02x) can't be mapped\n",
i,sti->rm_entry[i]);
continue;
}
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
index da55cca..cc4bbbe 100644
--- a/drivers/video/console/vgacon.c
+++ b/drivers/video/console/vgacon.c
@@ -585,6 +585,11 @@ static void vgacon_init(struct vc_data *c, int init)
vgacon_uni_pagedir[1]++;
if (!vgacon_uni_pagedir[0] && p)
con_set_default_unimap(c);
+
+ /* Only set the default if the user didn't deliberately override it */
+ if (global_cursor_default == -1)
+ global_cursor_default =
+ !(screen_info.flags & VIDEO_FLAGS_NOCURSOR);
}
static void vgacon_deinit(struct vc_data *c)
diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c
index c27ab1e..e59c083 100644
--- a/drivers/video/fb_defio.c
+++ b/drivers/video/fb_defio.c
@@ -71,7 +71,7 @@ int fb_deferred_io_fsync(struct file *file, struct dentry *dentry, int datasync)
{
struct fb_info *info = file->private_data;
- /* Skip if deferred io is complied-in but disabled on this fbdev */
+ /* Skip if deferred io is compiled-in but disabled on this fbdev */
if (!info->fbdefio)
return 0;
diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c
index f67db42..695fa01 100644
--- a/drivers/video/gbefb.c
+++ b/drivers/video/gbefb.c
@@ -701,7 +701,7 @@ static int gbefb_set_par(struct fb_info *info)
blocks of 512x128, 256x128 or 128x128 pixels, respectively for 8bit,
16bit and 32 bit modes (64 kB). They cover the screen with partial
tiles on the right and/or bottom of the screen if needed.
- For exemple in 640x480 8 bit mode the mapping is:
+ For example in 640x480 8 bit mode the mapping is:
<-------- 640 ----->
<---- 512 ----><128|384 offscreen>
diff --git a/drivers/video/omap/lcd_ams_delta.c b/drivers/video/omap/lcd_ams_delta.c
index 3d52772..b3973eb 100644
--- a/drivers/video/omap/lcd_ams_delta.c
+++ b/drivers/video/omap/lcd_ams_delta.c
@@ -123,12 +123,12 @@ struct platform_driver ams_delta_panel_driver = {
},
};
-static int ams_delta_panel_drv_init(void)
+static int __init ams_delta_panel_drv_init(void)
{
return platform_driver_register(&ams_delta_panel_driver);
}
-static void ams_delta_panel_drv_cleanup(void)
+static void __exit ams_delta_panel_drv_cleanup(void)
{
platform_driver_unregister(&ams_delta_panel_driver);
}
diff --git a/drivers/video/omap/lcd_mipid.c b/drivers/video/omap/lcd_mipid.c
index 2162eb0..8f3e2b4 100644
--- a/drivers/video/omap/lcd_mipid.c
+++ b/drivers/video/omap/lcd_mipid.c
@@ -607,7 +607,7 @@ static struct spi_driver mipid_spi_driver = {
.remove = __devexit_p(mipid_spi_remove),
};
-static int mipid_drv_init(void)
+static int __init mipid_drv_init(void)
{
spi_register_driver(&mipid_spi_driver);
@@ -615,7 +615,7 @@ static int mipid_drv_init(void)
}
module_init(mipid_drv_init);
-static void mipid_drv_cleanup(void)
+static void __exit mipid_drv_cleanup(void)
{
spi_unregister_driver(&mipid_spi_driver);
}
diff --git a/drivers/video/sgivwfb.c b/drivers/video/sgivwfb.c
index bba5371..f860122 100644
--- a/drivers/video/sgivwfb.c
+++ b/drivers/video/sgivwfb.c
@@ -260,13 +260,13 @@ static int sgivwfb_check_var(struct fb_var_screeninfo *var,
var->grayscale = 0; /* No grayscale for now */
/* determine valid resolution and timing */
- for (min_mode = 0; min_mode < DBE_VT_SIZE; min_mode++) {
+ for (min_mode = 0; min_mode < ARRAY_SIZE(dbeVTimings); min_mode++) {
if (dbeVTimings[min_mode].width >= var->xres &&
dbeVTimings[min_mode].height >= var->yres)
break;
}
- if (min_mode == DBE_VT_SIZE)
+ if (min_mode == ARRAY_SIZE(dbeVTimings))
return -EINVAL; /* Resolution to high */
/* XXX FIXME - should try to pick best refresh rate */
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index 3ad5157..b4b5de9 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -281,18 +281,34 @@ static void sh_mobile_lcdc_deferred_io(struct fb_info *info,
struct list_head *pagelist)
{
struct sh_mobile_lcdc_chan *ch = info->par;
- unsigned int nr_pages;
/* enable clocks before accessing hardware */
sh_mobile_lcdc_clk_on(ch->lcdc);
- nr_pages = sh_mobile_lcdc_sginit(info, pagelist);
- dma_map_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE);
-
- /* trigger panel update */
- lcdc_write_chan(ch, LDSM2R, 1);
-
- dma_unmap_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE);
+ /*
+ * It's possible to get here without anything on the pagelist via
+ * sh_mobile_lcdc_deferred_io_touch() or via a userspace fsync()
+ * invocation. In the former case, the acceleration routines are
+ * stepped in to when using the framebuffer console causing the
+ * workqueue to be scheduled without any dirty pages on the list.
+ *
+ * Despite this, a panel update is still needed given that the
+ * acceleration routines have their own methods for writing in
+ * that still need to be updated.
+ *
+ * The fsync() and empty pagelist case could be optimized for,
+ * but we don't bother, as any application exhibiting such
+ * behaviour is fundamentally broken anyways.
+ */
+ if (!list_empty(pagelist)) {
+ unsigned int nr_pages = sh_mobile_lcdc_sginit(info, pagelist);
+
+ /* trigger panel update */
+ dma_map_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE);
+ lcdc_write_chan(ch, LDSM2R, 1);
+ dma_unmap_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE);
+ } else
+ lcdc_write_chan(ch, LDSM2R, 1);
}
static void sh_mobile_lcdc_deferred_io_touch(struct fb_info *info)
diff --git a/drivers/video/stifb.c b/drivers/video/stifb.c
index 6120f0c..876648e 100644
--- a/drivers/video/stifb.c
+++ b/drivers/video/stifb.c
@@ -756,9 +756,9 @@ hyperResetPlanes(struct stifb_info *fb, int enable)
if (fb->info.var.bits_per_pixel == 32)
controlPlaneReg = 0x04000F00;
else
- controlPlaneReg = 0x00000F00; /* 0x00000800 should be enought, but lets clear all 4 bits */
+ controlPlaneReg = 0x00000F00; /* 0x00000800 should be enough, but lets clear all 4 bits */
else
- controlPlaneReg = 0x00000F00; /* 0x00000100 should be enought, but lets clear all 4 bits */
+ controlPlaneReg = 0x00000F00; /* 0x00000100 should be enough, but lets clear all 4 bits */
switch (enable) {
case ENABLE:
diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c
index ff43c88..9805483 100644
--- a/drivers/video/tdfxfb.c
+++ b/drivers/video/tdfxfb.c
@@ -52,7 +52,7 @@
*
* 0.1.3 (released 1999-11-02) added Attila's panning support, code
* reorg, hwcursor address page size alignment
- * (for mmaping both frame buffer and regs),
+ * (for mmapping both frame buffer and regs),
* and my changes to get rid of hardcoded
* VGA i/o register locations (uses PCI
* configuration info now)
diff --git a/drivers/video/via/dvi.c b/drivers/video/via/dvi.c
index c5c32b6..67b3693 100644
--- a/drivers/video/via/dvi.c
+++ b/drivers/video/via/dvi.c
@@ -467,7 +467,7 @@ static int dvi_get_panel_size_from_DDCv1(void)
default:
viaparinfo->tmds_setting_info->dvi_panel_size =
VIA_RES_1024X768;
- DEBUG_MSG(KERN_INFO "Unknow panel size max resolution = %d !\
+ DEBUG_MSG(KERN_INFO "Unknown panel size max resolution = %d !\
set default panel size.\n", max_h);
break;
}
@@ -534,7 +534,7 @@ static int dvi_get_panel_size_from_DDCv2(void)
default:
viaparinfo->tmds_setting_info->dvi_panel_size =
VIA_RES_1024X768;
- DEBUG_MSG(KERN_INFO "Unknow panel size max resolution = %d!\
+ DEBUG_MSG(KERN_INFO "Unknown panel size max resolution = %d!\
set default panel size.\n", HSize);
break;
}
diff --git a/drivers/video/vt8623fb.c b/drivers/video/vt8623fb.c
index 3df17dc..65ccd21 100644
--- a/drivers/video/vt8623fb.c
+++ b/drivers/video/vt8623fb.c
@@ -446,7 +446,7 @@ static int vt8623fb_set_par(struct fb_info *info)
svga_wseq_mask(0x1E, 0xF0, 0xF0); // DI/DVP bus
svga_wseq_mask(0x2A, 0x0F, 0x0F); // DI/DVP bus
- svga_wseq_mask(0x16, 0x08, 0xBF); // FIFO read treshold
+ svga_wseq_mask(0x16, 0x08, 0xBF); // FIFO read threshold
vga_wseq(NULL, 0x17, 0x1F); // FIFO depth
vga_wseq(NULL, 0x18, 0x4E);
svga_wseq_mask(0x1A, 0x08, 0x08); // enable MMIO ?
diff --git a/drivers/watchdog/coh901327_wdt.c b/drivers/watchdog/coh901327_wdt.c
index 381026c..923cc68 100644
--- a/drivers/watchdog/coh901327_wdt.c
+++ b/drivers/watchdog/coh901327_wdt.c
@@ -508,7 +508,7 @@ void coh901327_watchdog_reset(void)
* deactivating the watchdog before it is shut down by it.
*
* NOTE: on future versions of the watchdog, this restriction is
- * gone: the watchdog will be reloaded with a defaul value (1 min)
+ * gone: the watchdog will be reloaded with a default value (1 min)
* instead of last value, and you can conveniently set the watchdog
* timeout to 10ms (value = 1) without any problems.
*/
diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c
index 6a51edd..e44fbb3 100644
--- a/drivers/watchdog/iTCO_wdt.c
+++ b/drivers/watchdog/iTCO_wdt.c
@@ -1,5 +1,5 @@
/*
- * intel TCO Watchdog Driver (Used in i82801 and i63xxESB chipsets)
+ * intel TCO Watchdog Driver
*
* (c) Copyright 2006-2009 Wim Van Sebroeck <wim@iguana.be>.
*
@@ -14,47 +14,22 @@
*
* The TCO watchdog is implemented in the following I/O controller hubs:
* (See the intel documentation on http://developer.intel.com.)
- * 82801AA (ICH) : document number 290655-003, 290677-014,
- * 82801AB (ICHO) : document number 290655-003, 290677-014,
- * 82801BA (ICH2) : document number 290687-002, 298242-027,
- * 82801BAM (ICH2-M) : document number 290687-002, 298242-027,
- * 82801CA (ICH3-S) : document number 290733-003, 290739-013,
- * 82801CAM (ICH3-M) : document number 290716-001, 290718-007,
- * 82801DB (ICH4) : document number 290744-001, 290745-025,
- * 82801DBM (ICH4-M) : document number 252337-001, 252663-008,
- * 82801E (C-ICH) : document number 273599-001, 273645-002,
- * 82801EB (ICH5) : document number 252516-001, 252517-028,
- * 82801ER (ICH5R) : document number 252516-001, 252517-028,
- * 6300ESB (6300ESB) : document number 300641-004, 300884-013,
- * 82801FB (ICH6) : document number 301473-002, 301474-026,
- * 82801FR (ICH6R) : document number 301473-002, 301474-026,
- * 82801FBM (ICH6-M) : document number 301473-002, 301474-026,
- * 82801FW (ICH6W) : document number 301473-001, 301474-026,
- * 82801FRW (ICH6RW) : document number 301473-001, 301474-026,
- * 631xESB (631xESB) : document number 313082-001, 313075-006,
- * 632xESB (632xESB) : document number 313082-001, 313075-006,
- * 82801GB (ICH7) : document number 307013-003, 307014-024,
- * 82801GR (ICH7R) : document number 307013-003, 307014-024,
- * 82801GDH (ICH7DH) : document number 307013-003, 307014-024,
- * 82801GBM (ICH7-M) : document number 307013-003, 307014-024,
- * 82801GHM (ICH7-M DH) : document number 307013-003, 307014-024,
- * 82801GU (ICH7-U) : document number 307013-003, 307014-024,
- * 82801HB (ICH8) : document number 313056-003, 313057-017,
- * 82801HR (ICH8R) : document number 313056-003, 313057-017,
- * 82801HBM (ICH8M) : document number 313056-003, 313057-017,
- * 82801HH (ICH8DH) : document number 313056-003, 313057-017,
- * 82801HO (ICH8DO) : document number 313056-003, 313057-017,
- * 82801HEM (ICH8M-E) : document number 313056-003, 313057-017,
- * 82801IB (ICH9) : document number 316972-004, 316973-012,
- * 82801IR (ICH9R) : document number 316972-004, 316973-012,
- * 82801IH (ICH9DH) : document number 316972-004, 316973-012,
- * 82801IO (ICH9DO) : document number 316972-004, 316973-012,
- * 82801IBM (ICH9M) : document number 316972-004, 316973-012,
- * 82801IEM (ICH9M-E) : document number 316972-004, 316973-012,
- * 82801JIB (ICH10) : document number 319973-002, 319974-002,
- * 82801JIR (ICH10R) : document number 319973-002, 319974-002,
- * 82801JD (ICH10D) : document number 319973-002, 319974-002,
- * 82801JDO (ICH10DO) : document number 319973-002, 319974-002
+ * document number 290655-003, 290677-014: 82801AA (ICH), 82801AB (ICHO)
+ * document number 290687-002, 298242-027: 82801BA (ICH2)
+ * document number 290733-003, 290739-013: 82801CA (ICH3-S)
+ * document number 290716-001, 290718-007: 82801CAM (ICH3-M)
+ * document number 290744-001, 290745-025: 82801DB (ICH4)
+ * document number 252337-001, 252663-008: 82801DBM (ICH4-M)
+ * document number 273599-001, 273645-002: 82801E (C-ICH)
+ * document number 252516-001, 252517-028: 82801EB (ICH5), 82801ER (ICH5R)
+ * document number 300641-004, 300884-013: 6300ESB
+ * document number 301473-002, 301474-026: 82801F (ICH6)
+ * document number 313082-001, 313075-006: 631xESB, 632xESB
+ * document number 307013-003, 307014-024: 82801G (ICH7)
+ * document number 313056-003, 313057-017: 82801H (ICH8)
+ * document number 316972-004, 316973-012: 82801I (ICH9)
+ * document number 319973-002, 319974-002: 82801J (ICH10)
+ * document number 322169-001, 322170-001: 5 Series, 3400 Series (PCH)
*/
/*
@@ -122,6 +97,9 @@ enum iTCO_chipsets {
TCO_ICH10R, /* ICH10R */
TCO_ICH10D, /* ICH10D */
TCO_ICH10DO, /* ICH10DO */
+ TCO_PCH, /* PCH Desktop Full Featured */
+ TCO_PCHM, /* PCH Mobile Full Featured */
+ TCO_PCHMSFF, /* PCH Mobile SFF Full Featured */
};
static struct {
@@ -162,6 +140,9 @@ static struct {
{"ICH10R", 2},
{"ICH10D", 2},
{"ICH10DO", 2},
+ {"PCH Desktop Full Featured", 2},
+ {"PCH Mobile Full Featured", 2},
+ {"PCH Mobile SFF Full Featured", 2},
{NULL, 0}
};
@@ -230,6 +211,9 @@ static struct pci_device_id iTCO_wdt_pci_tbl[] = {
{ ITCO_PCI_DEVICE(0x3a16, TCO_ICH10R)},
{ ITCO_PCI_DEVICE(0x3a1a, TCO_ICH10D)},
{ ITCO_PCI_DEVICE(0x3a14, TCO_ICH10DO)},
+ { ITCO_PCI_DEVICE(0x3b00, TCO_PCH)},
+ { ITCO_PCI_DEVICE(0x3b01, TCO_PCHM)},
+ { ITCO_PCI_DEVICE(0x3b0d, TCO_PCHMSFF)},
{ 0, }, /* End of list */
};
MODULE_DEVICE_TABLE(pci, iTCO_wdt_pci_tbl);
diff --git a/drivers/watchdog/machzwd.c b/drivers/watchdog/machzwd.c
index b6b3f59..47d7197 100644
--- a/drivers/watchdog/machzwd.c
+++ b/drivers/watchdog/machzwd.c
@@ -21,7 +21,7 @@
* wd#1 - 2 seconds;
* wd#2 - 7.2 ms;
* After the expiration of wd#1, it can generate a NMI, SCI, SMI, or
- * a system RESET and it starts wd#2 that unconditionaly will RESET
+ * a system RESET and it starts wd#2 that unconditionally will RESET
* the system when the counter reaches zero.
*
* 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c
index b57ac6b..85b93e1 100644
--- a/drivers/watchdog/s3c2410_wdt.c
+++ b/drivers/watchdog/s3c2410_wdt.c
@@ -36,6 +36,7 @@
#include <linux/clk.h>
#include <linux/uaccess.h>
#include <linux/io.h>
+#include <linux/cpufreq.h>
#include <mach/map.h>
@@ -142,9 +143,14 @@ static void s3c2410wdt_start(void)
spin_unlock(&wdt_lock);
}
+static inline int s3c2410wdt_is_running(void)
+{
+ return readl(wdt_base + S3C2410_WTCON) & S3C2410_WTCON_ENABLE;
+}
+
static int s3c2410wdt_set_heartbeat(int timeout)
{
- unsigned int freq = clk_get_rate(wdt_clock);
+ unsigned long freq = clk_get_rate(wdt_clock);
unsigned int count;
unsigned int divisor = 1;
unsigned long wtcon;
@@ -155,7 +161,7 @@ static int s3c2410wdt_set_heartbeat(int timeout)
freq /= 128;
count = timeout * freq;
- DBG("%s: count=%d, timeout=%d, freq=%d\n",
+ DBG("%s: count=%d, timeout=%d, freq=%lu\n",
__func__, count, timeout, freq);
/* if the count is bigger than the watchdog register,
@@ -324,6 +330,73 @@ static irqreturn_t s3c2410wdt_irq(int irqno, void *param)
s3c2410wdt_keepalive();
return IRQ_HANDLED;
}
+
+
+#ifdef CONFIG_CPU_FREQ
+
+static int s3c2410wdt_cpufreq_transition(struct notifier_block *nb,
+ unsigned long val, void *data)
+{
+ int ret;
+
+ if (!s3c2410wdt_is_running())
+ goto done;
+
+ if (val == CPUFREQ_PRECHANGE) {
+ /* To ensure that over the change we don't cause the
+ * watchdog to trigger, we perform an keep-alive if
+ * the watchdog is running.
+ */
+
+ s3c2410wdt_keepalive();
+ } else if (val == CPUFREQ_POSTCHANGE) {
+ s3c2410wdt_stop();
+
+ ret = s3c2410wdt_set_heartbeat(tmr_margin);
+
+ if (ret >= 0)
+ s3c2410wdt_start();
+ else
+ goto err;
+ }
+
+done:
+ return 0;
+
+ err:
+ dev_err(wdt_dev, "cannot set new value for timeout %d\n", tmr_margin);
+ return ret;
+}
+
+static struct notifier_block s3c2410wdt_cpufreq_transition_nb = {
+ .notifier_call = s3c2410wdt_cpufreq_transition,
+};
+
+static inline int s3c2410wdt_cpufreq_register(void)
+{
+ return cpufreq_register_notifier(&s3c2410wdt_cpufreq_transition_nb,
+ CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+static inline void s3c2410wdt_cpufreq_deregister(void)
+{
+ cpufreq_unregister_notifier(&s3c2410wdt_cpufreq_transition_nb,
+ CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+#else
+static inline int s3c2410wdt_cpufreq_register(void)
+{
+ return 0;
+}
+
+static inline void s3c2410wdt_cpufreq_deregister(void)
+{
+}
+#endif
+
+
+
/* device interface */
static int __devinit s3c2410wdt_probe(struct platform_device *pdev)
@@ -387,6 +460,11 @@ static int __devinit s3c2410wdt_probe(struct platform_device *pdev)
clk_enable(wdt_clock);
+ if (s3c2410wdt_cpufreq_register() < 0) {
+ printk(KERN_ERR PFX "failed to register cpufreq\n");
+ goto err_clk;
+ }
+
/* see if we can actually set the requested timer margin, and if
* not, try the default value */
@@ -407,7 +485,7 @@ static int __devinit s3c2410wdt_probe(struct platform_device *pdev)
if (ret) {
dev_err(dev, "cannot register miscdev on minor=%d (%d)\n",
WATCHDOG_MINOR, ret);
- goto err_clk;
+ goto err_cpufreq;
}
if (tmr_atboot && started == 0) {
@@ -432,6 +510,9 @@ static int __devinit s3c2410wdt_probe(struct platform_device *pdev)
return 0;
+ err_cpufreq:
+ s3c2410wdt_cpufreq_deregister();
+
err_clk:
clk_disable(wdt_clock);
clk_put(wdt_clock);
@@ -451,6 +532,8 @@ static int __devinit s3c2410wdt_probe(struct platform_device *pdev)
static int __devexit s3c2410wdt_remove(struct platform_device *dev)
{
+ s3c2410wdt_cpufreq_deregister();
+
release_resource(wdt_mem);
kfree(wdt_mem);
wdt_mem = NULL;
diff --git a/drivers/watchdog/sb_wdog.c b/drivers/watchdog/sb_wdog.c
index 9748eed..c8eadd4 100644
--- a/drivers/watchdog/sb_wdog.c
+++ b/drivers/watchdog/sb_wdog.c
@@ -1,7 +1,7 @@
/*
* Watchdog driver for SiByte SB1 SoCs
*
- * Copyright (C) 2007 OnStor, Inc. * Andrew Sharp <andy.sharp@onstor.com>
+ * Copyright (C) 2007 OnStor, Inc. * Andrew Sharp <andy.sharp@lsi.com>
*
* This driver is intended to make the second of two hardware watchdogs
* on the Sibyte 12XX and 11XX SoCs available to the user. There are two
@@ -326,7 +326,7 @@ static void __exit sbwdog_exit(void)
module_init(sbwdog_init);
module_exit(sbwdog_exit);
-MODULE_AUTHOR("Andrew Sharp <andy.sharp@onstor.com>");
+MODULE_AUTHOR("Andrew Sharp <andy.sharp@lsi.com>");
MODULE_DESCRIPTION("SiByte Watchdog");
module_param(timeout, ulong, 0);
diff --git a/drivers/watchdog/wdrtas.c b/drivers/watchdog/wdrtas.c
index 3bde56b..5bfb1f2 100644
--- a/drivers/watchdog/wdrtas.c
+++ b/drivers/watchdog/wdrtas.c
@@ -542,7 +542,7 @@ static struct notifier_block wdrtas_notifier = {
/**
* wdrtas_get_tokens - reads in RTAS tokens
*
- * returns 0 on succes, <0 on failure
+ * returns 0 on success, <0 on failure
*
* wdrtas_get_tokens reads in the tokens for the RTAS calls used in
* this watchdog driver. It tolerates, if "get-sensor-state" and
@@ -598,7 +598,7 @@ static void wdrtas_unregister_devs(void)
/**
* wdrtas_register_devs - registers the misc dev handlers
*
- * returns 0 on succes, <0 on failure
+ * returns 0 on success, <0 on failure
*
* wdrtas_register_devs registers the watchdog and temperature watchdog
* misc devs
@@ -630,7 +630,7 @@ static int wdrtas_register_devs(void)
/**
* wdrtas_init - init function of the watchdog driver
*
- * returns 0 on succes, <0 on failure
+ * returns 0 on success, <0 on failure
*
* registers the file handlers and the reboot notifier
*/
diff --git a/drivers/xen/cpu_hotplug.c b/drivers/xen/cpu_hotplug.c
index bdfd584..0f765a9 100644
--- a/drivers/xen/cpu_hotplug.c
+++ b/drivers/xen/cpu_hotplug.c
@@ -86,7 +86,7 @@ static int setup_cpu_watcher(struct notifier_block *notifier,
for_each_possible_cpu(cpu) {
if (vcpu_online(cpu) == 0) {
(void)cpu_down(cpu);
- cpu_clear(cpu, cpu_present_map);
+ set_cpu_present(cpu, false);
}
}
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index b9b3bb5..d15ea17 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -767,7 +767,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
current->mm->start_stack = bprm->p;
- /* Now we do a little grungy work by mmaping the ELF image into
+ /* Now we do a little grungy work by mmapping the ELF image into
the correct location in memory. */
for(i = 0, elf_ppnt = elf_phdata;
i < loc->elf_ex.e_phnum; i++, elf_ppnt++) {
diff --git a/fs/bio.c b/fs/bio.c
index e23a63f..76e6713 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -272,7 +272,7 @@ EXPORT_SYMBOL(bio_init);
* for a &struct bio to become free. If a %NULL @bs is passed in, we will
* fall back to just using @kmalloc to allocate the required memory.
*
- * Note that the caller must set ->bi_destructor on succesful return
+ * Note that the caller must set ->bi_destructor on successful return
* of a bio, to do the appropriate freeing of the bio once the reference
* count drops to zero.
**/
diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c
index ccbdcb5..46bea0f 100644
--- a/fs/btrfs/extent_map.c
+++ b/fs/btrfs/extent_map.c
@@ -256,7 +256,7 @@ out:
* Insert @em into @tree or perform a simple forward/backward merge with
* existing mappings. The extent_map struct passed in will be inserted
* into the tree directly, with an additional reference taken, or a
- * reference dropped if the merge attempt was sucessfull.
+ * reference dropped if the merge attempt was successfull.
*/
int add_extent_mapping(struct extent_map_tree *tree,
struct extent_map *em)
diff --git a/fs/cifs/README b/fs/cifs/README
index 79c1a93..a727b7c 100644
--- a/fs/cifs/README
+++ b/fs/cifs/README
@@ -423,7 +423,7 @@ A partial list of the supported mount options follows:
source name to use to represent the client netbios machine
name when doing the RFC1001 netbios session initialize.
direct Do not do inode data caching on files opened on this mount.
- This precludes mmaping files on this mount. In some cases
+ This precludes mmapping files on this mount. In some cases
with fast networks and little or no caching benefits on the
client (e.g. when the application is doing large sequential
reads bigger than page size without rereading the same data)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 5d0fde1..4b35f7e 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -39,7 +39,7 @@
/*
* MAX_REQ is the maximum number of requests that WE will send
- * on one socket concurently. It also matches the most common
+ * on one socket concurrently. It also matches the most common
* value of max multiplex returned by servers. We may
* eventually want to use the negotiated value (in case
* future servers can handle more) when we are more confident that
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 2d07f89..3877737 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -1227,7 +1227,7 @@ typedef struct smb_com_setattr_rsp {
/* empty wct response to setattr */
/*******************************************************/
-/* NT Transact structure defintions follow */
+/* NT Transact structure definitions follow */
/* Currently only ioctl, acl (get security descriptor) */
/* and notify are implemented */
/*******************************************************/
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index cababd8..cf18ee7 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -914,8 +914,8 @@ undo_setattr:
/*
* If dentry->d_inode is null (usually meaning the cached dentry
* is a negative dentry) then we would attempt a standard SMB delete, but
- * if that fails we can not attempt the fall back mechanisms on EACESS
- * but will return the EACESS to the caller. Note that the VFS does not call
+ * if that fails we can not attempt the fall back mechanisms on EACCESS
+ * but will return the EACCESS to the caller. Note that the VFS does not call
* unlink on negative dentries currently.
*/
int cifs_unlink(struct inode *dir, struct dentry *dentry)
diff --git a/fs/cifs/smbdes.c b/fs/cifs/smbdes.c
index 224a1f4..b6b6dcb 100644
--- a/fs/cifs/smbdes.c
+++ b/fs/cifs/smbdes.c
@@ -371,7 +371,7 @@ E_P24(unsigned char *p21, const unsigned char *c8, unsigned char *p24)
smbhash(p24 + 16, c8, p21 + 14, 1);
}
-#if 0 /* currently unsued */
+#if 0 /* currently unused */
static void
D_P16(unsigned char *p14, unsigned char *in, unsigned char *out)
{
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 229e722..2346895 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -1920,7 +1920,7 @@ COMPATIBLE_IOCTL(TIOCSLTC)
#endif
#ifdef TIOCSTART
/*
- * For these two we have defintions in ioctls.h and/or termios.h on
+ * For these two we have definitions in ioctls.h and/or termios.h on
* some architectures but no actual implemention. Some applications
* like bash call them if they are defined in the headers, so we provide
* entries here to avoid syslog message spew.
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index d22438e..0d23b52 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -184,7 +184,7 @@ static int debugfs_create_by_name(const char *name, mode_t mode,
/**
* debugfs_create_file - create a file in the debugfs filesystem
* @name: a pointer to a string containing the name of the file to create.
- * @mode: the permission that the file should have
+ * @mode: the permission that the file should have.
* @parent: a pointer to the parent dentry for this file. This should be a
* directory dentry if set. If this paramater is NULL, then the
* file will be created in the root of the debugfs filesystem.
@@ -195,8 +195,8 @@ static int debugfs_create_by_name(const char *name, mode_t mode,
* this file.
*
* This is the basic "create a file" function for debugfs. It allows for a
- * wide range of flexibility in createing a file, or a directory (if you
- * want to create a directory, the debugfs_create_dir() function is
+ * wide range of flexibility in creating a file, or a directory (if you want
+ * to create a directory, the debugfs_create_dir() function is
* recommended to be used instead.)
*
* This function will return a pointer to a dentry if it succeeds. This
diff --git a/fs/dlm/plock.c b/fs/dlm/plock.c
index 16f682e..b540aa5 100644
--- a/fs/dlm/plock.c
+++ b/fs/dlm/plock.c
@@ -143,7 +143,7 @@ out:
}
EXPORT_SYMBOL_GPL(dlm_posix_lock);
-/* Returns failure iff a succesful lock operation should be canceled */
+/* Returns failure iff a successful lock operation should be canceled */
static int dlm_plock_callback(struct plock_op *op)
{
struct file *file;
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index 354ed3b..2db9577 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -2033,7 +2033,7 @@ static Indirect *ext3_find_shared(struct inode *inode, int depth,
int k, err;
*top = 0;
- /* Make k index the deepest non-null offest + 1 */
+ /* Make k index the deepest non-null offset + 1 */
for (k = depth; k > 1 && !offsets[k-1]; k--)
;
partial = ext3_get_branch(inode, k, offsets, chain, &err);
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 2c8caa5..4e8e2f1 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -2933,7 +2933,7 @@ retry:
ret = write_cache_pages(mapping, wbc, __mpage_da_writepage,
&mpd);
/*
- * If we have a contigous extent of pages and we
+ * If we have a contiguous extent of pages and we
* haven't done the I/O yet, map the blocks and submit
* them for I/O.
*/
@@ -4064,7 +4064,7 @@ static Indirect *ext4_find_shared(struct inode *inode, int depth,
int k, err;
*top = 0;
- /* Make k index the deepest non-null offest + 1 */
+ /* Make k index the deepest non-null offset + 1 */
for (k = depth; k > 1 && !offsets[k-1]; k--)
;
partial = ext4_get_branch(inode, k, offsets, chain, &err);
@@ -5376,7 +5376,7 @@ static int ext4_index_trans_blocks(struct inode *inode, int nrblocks, int chunk)
* worse case, the indexs blocks spread over different block groups
*
* If datablocks are discontiguous, they are possible to spread over
- * different block groups too. If they are contiugous, with flexbg,
+ * different block groups too. If they are contiuguous, with flexbg,
* they could still across block group boundary.
*
* Also account for superblock, inode, quota and xattr blocks
@@ -5452,7 +5452,7 @@ int ext4_writepage_trans_blocks(struct inode *inode)
* Calculate the journal credits for a chunk of data modification.
*
* This is called from DIO, fallocate or whoever calling
- * ext4_get_blocks() to map/allocate a chunk of contigous disk blocks.
+ * ext4_get_blocks() to map/allocate a chunk of contiguous disk blocks.
*
* journal buffers for data blocks are not included here, as DIO
* and fallocate do no need to journal data buffers.
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index bba1282..74e495d 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -142,7 +142,7 @@
* 2 blocks and the order of allocation is >= sbi->s_mb_order2_reqs. The
* value of s_mb_order2_reqs can be tuned via
* /sys/fs/ext4/<partition>/mb_order2_req. If the request len is equal to
- * stripe size (sbi->s_stripe), we try to search for contigous block in
+ * stripe size (sbi->s_stripe), we try to search for contiguous block in
* stripe size. This should result in better allocation on RAID setups. If
* not, we search in the specific group using bitmap for best extents. The
* tunable min_to_scan and max_to_scan control the behaviour here.
diff --git a/fs/jffs2/compr.c b/fs/jffs2/compr.c
index f25e70c..f029441 100644
--- a/fs/jffs2/compr.c
+++ b/fs/jffs2/compr.c
@@ -177,7 +177,7 @@ uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
spin_unlock(&jffs2_compressor_list_lock);
break;
default:
- printk(KERN_ERR "JFFS2: unknow compression mode.\n");
+ printk(KERN_ERR "JFFS2: unknown compression mode.\n");
}
out:
if (ret == JFFS2_COMPR_NONE) {
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c
index 1a80301..378991c 100644
--- a/fs/jffs2/readinode.c
+++ b/fs/jffs2/readinode.c
@@ -931,7 +931,7 @@ static inline int read_unknown(struct jffs2_sb_info *c, struct jffs2_raw_node_re
* Helper function for jffs2_get_inode_nodes().
* The function detects whether more data should be read and reads it if yes.
*
- * Returns: 0 on succes;
+ * Returns: 0 on success;
* negative error code on failure.
*/
static int read_more(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref,
diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c
index 082e844..4b10788 100644
--- a/fs/jffs2/xattr.c
+++ b/fs/jffs2/xattr.c
@@ -31,7 +31,7 @@
* is used to release xattr name/value pair and detach from c->xattrindex.
* reclaim_xattr_datum(c)
* is used to reclaim xattr name/value pairs on the xattr name/value pair cache when
- * memory usage by cache is over c->xdatum_mem_threshold. Currentry, this threshold
+ * memory usage by cache is over c->xdatum_mem_threshold. Currently, this threshold
* is hard coded as 32KiB.
* do_verify_xattr_datum(c, xd)
* is used to load the xdatum informations without name/value pair from the medium.
diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c
index 2bc7d8a..d9b031c 100644
--- a/fs/jfs/jfs_dmap.c
+++ b/fs/jfs/jfs_dmap.c
@@ -755,7 +755,7 @@ int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results)
* allocation group.
*/
if ((blkno & (bmp->db_agsize - 1)) == 0)
- /* check if the AG is currenly being written to.
+ /* check if the AG is currently being written to.
* if so, call dbNextAG() to find a non-busy
* AG with sufficient free space.
*/
@@ -3337,7 +3337,7 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks)
for (i = 0, n = 0; i < agno; n++) {
bmp->db_agfree[n] = 0; /* init collection point */
- /* coalesce cotiguous k AGs; */
+ /* coalesce contiguous k AGs; */
for (j = 0; j < k && i < agno; j++, i++) {
/* merge AGi to AGn */
bmp->db_agfree[n] += bmp->db_agfree[i];
diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c
index 0d58caf..ec8f45f 100644
--- a/fs/ncpfs/ioctl.c
+++ b/fs/ncpfs/ioctl.c
@@ -835,7 +835,7 @@ static int ncp_ioctl_need_write(unsigned int cmd)
case NCP_IOC_SETROOT:
return 0;
default:
- /* unkown IOCTL command, assume write */
+ /* unknown IOCTL command, assume write */
return 1;
}
}
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c
index 1d1d1a2..5ef5f36 100644
--- a/fs/notify/inotify/inotify_user.c
+++ b/fs/notify/inotify/inotify_user.c
@@ -741,10 +741,6 @@ SYSCALL_DEFINE3(inotify_add_watch, int, fd, const char __user *, pathname,
/* create/update an inode mark */
ret = inotify_update_watch(group, inode, mask);
- if (unlikely(ret))
- goto path_put_and_out;
-
-path_put_and_out:
path_put(&path);
fput_and_out:
fput_light(filp, fput_needed);
diff --git a/fs/ntfs/compress.c b/fs/ntfs/compress.c
index 9669541..08f7530 100644
--- a/fs/ntfs/compress.c
+++ b/fs/ntfs/compress.c
@@ -927,7 +927,7 @@ lock_retry_remap:
return 0;
ntfs_debug("Failed. Returning error code %s.", err == -EOVERFLOW ?
- "EOVERFLOW" : (!err ? "EIO" : "unkown error"));
+ "EOVERFLOW" : (!err ? "EIO" : "unknown error"));
return err < 0 ? err : -EIO;
read_err:
diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c
index 663c0e3..43179dd 100644
--- a/fs/ntfs/file.c
+++ b/fs/ntfs/file.c
@@ -399,7 +399,7 @@ static inline void ntfs_fault_in_pages_readable_iovec(const struct iovec *iov,
* @cached_page: allocated but as yet unused page
* @lru_pvec: lru-buffering pagevec of caller
*
- * Obtain @nr_pages locked page cache pages from the mapping @maping and
+ * Obtain @nr_pages locked page cache pages from the mapping @mapping and
* starting at index @index.
*
* If a page is newly created, increment its refcount and add it to the
@@ -1281,7 +1281,7 @@ rl_not_mapped_enoent:
/*
* Copy as much as we can into the pages and return the number of bytes which
- * were sucessfully copied. If a fault is encountered then clear the pages
+ * were successfully copied. If a fault is encountered then clear the pages
* out to (ofs + bytes) and return the number of bytes which were copied.
*/
static inline size_t ntfs_copy_from_user(struct page **pages,
diff --git a/fs/ntfs/logfile.c b/fs/ntfs/logfile.c
index 89b0298..4dadcdf 100644
--- a/fs/ntfs/logfile.c
+++ b/fs/ntfs/logfile.c
@@ -338,7 +338,7 @@ err_out:
* copy of the complete multi sector transfer deprotected page. On failure,
* *@wrp is undefined.
*
- * Simillarly, if @lsn is not NULL, on succes *@lsn will be set to the current
+ * Simillarly, if @lsn is not NULL, on success *@lsn will be set to the current
* logfile lsn according to this restart page. On failure, *@lsn is undefined.
*
* The following error codes are defined:
diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c
index 38a42f5..7c7198a 100644
--- a/fs/ocfs2/alloc.c
+++ b/fs/ocfs2/alloc.c
@@ -2398,7 +2398,7 @@ static int ocfs2_leftmost_rec_contains(struct ocfs2_extent_list *el, u32 cpos)
*
* The array is assumed to be large enough to hold an entire path (tree depth).
*
- * Upon succesful return from this function:
+ * Upon successful return from this function:
*
* - The 'right_path' array will contain a path to the leaf block
* whose range contains e_cpos.
diff --git a/fs/ocfs2/blockcheck.c b/fs/ocfs2/blockcheck.c
index a1163b8..b7428c5 100644
--- a/fs/ocfs2/blockcheck.c
+++ b/fs/ocfs2/blockcheck.c
@@ -47,7 +47,7 @@
* Calculate the bit offset in the hamming code buffer based on the bit's
* offset in the data buffer. Since the hamming code reserves all
* power-of-two bits for parity, the data bit number and the code bit
- * number are offest by all the parity bits beforehand.
+ * number are offset by all the parity bits beforehand.
*
* Recall that bit numbers in hamming code are 1-based. This function
* takes the 0-based data bit from the caller.
diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c
index 83bcaf2..03ccf9a 100644
--- a/fs/ocfs2/dlm/dlmmaster.c
+++ b/fs/ocfs2/dlm/dlmmaster.c
@@ -2586,7 +2586,7 @@ fail:
* is complete everywhere. if the target dies while this is
* going on, some nodes could potentially see the target as the
* master, so it is important that my recovery finds the migration
- * mle and sets the master to UNKNONWN. */
+ * mle and sets the master to UNKNOWN. */
/* wait for new node to assert master */
diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c
index 0d38d67..c5e4a49 100644
--- a/fs/ocfs2/dlmglue.c
+++ b/fs/ocfs2/dlmglue.c
@@ -1855,7 +1855,7 @@ int ocfs2_file_lock(struct file *file, int ex, int trylock)
* outstanding lock request, so a cancel convert is
* required. We intentionally overwrite 'ret' - if the
* cancel fails and the lock was granted, it's easier
- * to just bubble sucess back up to the user.
+ * to just bubble success back up to the user.
*/
ret = ocfs2_flock_handle_signal(lockres, level);
} else if (!ret && (level > lockres->l_level)) {
diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c
index 54c16b6..bf34c49 100644
--- a/fs/ocfs2/journal.c
+++ b/fs/ocfs2/journal.c
@@ -659,7 +659,7 @@ static int __ocfs2_journal_access(handle_t *handle,
default:
status = -EINVAL;
- mlog(ML_ERROR, "Uknown access type!\n");
+ mlog(ML_ERROR, "Unknown access type!\n");
}
if (!status && ocfs2_meta_ecc(osb) && triggers)
jbd2_journal_set_triggers(bh, &triggers->ot_triggers);
diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c
index 3a0df7a..30967e3 100644
--- a/fs/ocfs2/refcounttree.c
+++ b/fs/ocfs2/refcounttree.c
@@ -2431,7 +2431,7 @@ out:
* we gonna touch and whether we need to create new blocks.
*
* Normally the refcount blocks store these refcount should be
- * continguous also, so that we can get the number easily.
+ * contiguous also, so that we can get the number easily.
* As for meta_ac, we will at most add split 2 refcount record and
* 2 more refcount block, so just check it in a rough way.
*
diff --git a/fs/omfs/bitmap.c b/fs/omfs/bitmap.c
index e1c0ec0..0822345 100644
--- a/fs/omfs/bitmap.c
+++ b/fs/omfs/bitmap.c
@@ -85,7 +85,7 @@ out:
}
/*
- * Tries to allocate exactly one block. Returns true if sucessful.
+ * Tries to allocate exactly one block. Returns true if successful.
*/
int omfs_allocate_block(struct super_block *sb, u64 block)
{
diff --git a/fs/qnx4/bitmap.c b/fs/qnx4/bitmap.c
index 0afba06..32f5d13 100644
--- a/fs/qnx4/bitmap.c
+++ b/fs/qnx4/bitmap.c
@@ -67,7 +67,7 @@ unsigned long qnx4_count_free_blocks(struct super_block *sb)
while (total < size) {
if ((bh = sb_bread(sb, start + offset)) == NULL) {
- printk("qnx4: I/O error in counting free blocks\n");
+ printk(KERN_ERR "qnx4: I/O error in counting free blocks\n");
break;
}
count_bits(bh->b_data, size - total, &total_free);
diff --git a/fs/qnx4/dir.c b/fs/qnx4/dir.c
index 86cc39c..6f30c3d 100644
--- a/fs/qnx4/dir.c
+++ b/fs/qnx4/dir.c
@@ -26,8 +26,8 @@ static int qnx4_readdir(struct file *filp, void *dirent, filldir_t filldir)
int ix, ino;
int size;
- QNX4DEBUG(("qnx4_readdir:i_size = %ld\n", (long) inode->i_size));
- QNX4DEBUG(("filp->f_pos = %ld\n", (long) filp->f_pos));
+ QNX4DEBUG((KERN_INFO "qnx4_readdir:i_size = %ld\n", (long) inode->i_size));
+ QNX4DEBUG((KERN_INFO "filp->f_pos = %ld\n", (long) filp->f_pos));
lock_kernel();
@@ -50,7 +50,7 @@ static int qnx4_readdir(struct file *filp, void *dirent, filldir_t filldir)
size = QNX4_NAME_MAX;
if ( ( de->di_status & (QNX4_FILE_USED|QNX4_FILE_LINK) ) != 0 ) {
- QNX4DEBUG(("qnx4_readdir:%.*s\n", size, de->di_fname));
+ QNX4DEBUG((KERN_INFO "qnx4_readdir:%.*s\n", size, de->di_fname));
if ( ( de->di_status & QNX4_FILE_LINK ) == 0 )
ino = blknum * QNX4_INODES_PER_BLOCK + ix - 1;
else {
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c
index d2cd179..449f5a6 100644
--- a/fs/qnx4/inode.c
+++ b/fs/qnx4/inode.c
@@ -107,7 +107,7 @@ static int qnx4_get_block( struct inode *inode, sector_t iblock, struct buffer_h
{
unsigned long phys;
- QNX4DEBUG(("qnx4: qnx4_get_block inode=[%ld] iblock=[%ld]\n",inode->i_ino,iblock));
+ QNX4DEBUG((KERN_INFO "qnx4: qnx4_get_block inode=[%ld] iblock=[%ld]\n",inode->i_ino,iblock));
phys = qnx4_block_map( inode, iblock );
if ( phys ) {
@@ -142,12 +142,12 @@ unsigned long qnx4_block_map( struct inode *inode, long iblock )
// read next xtnt block.
bh = sb_bread(inode->i_sb, i_xblk - 1);
if ( !bh ) {
- QNX4DEBUG(("qnx4: I/O error reading xtnt block [%ld])\n", i_xblk - 1));
+ QNX4DEBUG((KERN_ERR "qnx4: I/O error reading xtnt block [%ld])\n", i_xblk - 1));
return -EIO;
}
xblk = (struct qnx4_xblk*)bh->b_data;
if ( memcmp( xblk->xblk_signature, "IamXblk", 7 ) ) {
- QNX4DEBUG(("qnx4: block at %ld is not a valid xtnt\n", qnx4_inode->i_xblk));
+ QNX4DEBUG((KERN_ERR "qnx4: block at %ld is not a valid xtnt\n", qnx4_inode->i_xblk));
return -EIO;
}
}
@@ -168,7 +168,7 @@ unsigned long qnx4_block_map( struct inode *inode, long iblock )
brelse( bh );
}
- QNX4DEBUG(("qnx4: mapping block %ld of inode %ld = %ld\n",iblock,inode->i_ino,block));
+ QNX4DEBUG((KERN_INFO "qnx4: mapping block %ld of inode %ld = %ld\n",iblock,inode->i_ino,block));
return block;
}
@@ -209,7 +209,7 @@ static const char *qnx4_checkroot(struct super_block *sb)
if (*(qnx4_sb(sb)->sb->RootDir.di_fname) != '/') {
return "no qnx4 filesystem (no root dir).";
} else {
- QNX4DEBUG(("QNX4 filesystem found on dev %s.\n", sb->s_id));
+ QNX4DEBUG((KERN_NOTICE "QNX4 filesystem found on dev %s.\n", sb->s_id));
rd = le32_to_cpu(qnx4_sb(sb)->sb->RootDir.di_first_xtnt.xtnt_blk) - 1;
rl = le32_to_cpu(qnx4_sb(sb)->sb->RootDir.di_first_xtnt.xtnt_size);
for (j = 0; j < rl; j++) {
@@ -220,7 +220,7 @@ static const char *qnx4_checkroot(struct super_block *sb)
for (i = 0; i < QNX4_INODES_PER_BLOCK; i++) {
rootdir = (struct qnx4_inode_entry *) (bh->b_data + i * QNX4_DIR_ENTRY_SIZE);
if (rootdir->di_fname != NULL) {
- QNX4DEBUG(("Rootdir entry found : [%s]\n", rootdir->di_fname));
+ QNX4DEBUG((KERN_INFO "rootdir entry found : [%s]\n", rootdir->di_fname));
if (!strncmp(rootdir->di_fname, QNX4_BMNAME, sizeof QNX4_BMNAME)) {
found = 1;
qnx4_sb(sb)->BitMap = kmalloc( sizeof( struct qnx4_inode_entry ), GFP_KERNEL );
@@ -265,12 +265,12 @@ static int qnx4_fill_super(struct super_block *s, void *data, int silent)
if we don't belong here... */
bh = sb_bread(s, 1);
if (!bh) {
- printk("qnx4: unable to read the superblock\n");
+ printk(KERN_ERR "qnx4: unable to read the superblock\n");
goto outnobh;
}
if ( le32_to_cpup((__le32*) bh->b_data) != QNX4_SUPER_MAGIC ) {
if (!silent)
- printk("qnx4: wrong fsid in superblock.\n");
+ printk(KERN_ERR "qnx4: wrong fsid in superblock.\n");
goto out;
}
s->s_op = &qnx4_sops;
@@ -284,14 +284,14 @@ static int qnx4_fill_super(struct super_block *s, void *data, int silent)
errmsg = qnx4_checkroot(s);
if (errmsg != NULL) {
if (!silent)
- printk("qnx4: %s\n", errmsg);
+ printk(KERN_ERR "qnx4: %s\n", errmsg);
goto out;
}
/* does root not have inode number QNX4_ROOT_INO ?? */
root = qnx4_iget(s, QNX4_ROOT_INO * QNX4_INODES_PER_BLOCK);
if (IS_ERR(root)) {
- printk("qnx4: get inode failed\n");
+ printk(KERN_ERR "qnx4: get inode failed\n");
ret = PTR_ERR(root);
goto out;
}
@@ -374,7 +374,7 @@ struct inode *qnx4_iget(struct super_block *sb, unsigned long ino)
qnx4_inode = qnx4_raw_inode(inode);
inode->i_mode = 0;
- QNX4DEBUG(("Reading inode : [%d]\n", ino));
+ QNX4DEBUG((KERN_INFO "reading inode : [%d]\n", ino));
if (!ino) {
printk(KERN_ERR "qnx4: bad inode number on dev %s: %lu is "
"out of range\n",
@@ -385,7 +385,7 @@ struct inode *qnx4_iget(struct super_block *sb, unsigned long ino)
block = ino / QNX4_INODES_PER_BLOCK;
if (!(bh = sb_bread(sb, block))) {
- printk("qnx4: major problem: unable to read inode from dev "
+ printk(KERN_ERR "qnx4: major problem: unable to read inode from dev "
"%s\n", sb->s_id);
iget_failed(inode);
return ERR_PTR(-EIO);
@@ -499,7 +499,7 @@ static int __init init_qnx4_fs(void)
return err;
}
- printk("QNX4 filesystem 0.2.3 registered.\n");
+ printk(KERN_INFO "QNX4 filesystem 0.2.3 registered.\n");
return 0;
}
diff --git a/fs/qnx4/namei.c b/fs/qnx4/namei.c
index ae1e7ed..58703eb 100644
--- a/fs/qnx4/namei.c
+++ b/fs/qnx4/namei.c
@@ -30,7 +30,7 @@ static int qnx4_match(int len, const char *name,
int namelen, thislen;
if (bh == NULL) {
- printk("qnx4: matching unassigned buffer !\n");
+ printk(KERN_WARNING "qnx4: matching unassigned buffer !\n");
return 0;
}
de = (struct qnx4_inode_entry *) (bh->b_data + *offset);
@@ -66,7 +66,7 @@ static struct buffer_head *qnx4_find_entry(int len, struct inode *dir,
*res_dir = NULL;
if (!dir->i_sb) {
- printk("qnx4: no superblock on dir.\n");
+ printk(KERN_WARNING "qnx4: no superblock on dir.\n");
return NULL;
}
bh = NULL;
@@ -124,7 +124,7 @@ struct dentry * qnx4_lookup(struct inode *dir, struct dentry *dentry, struct nam
foundinode = qnx4_iget(dir->i_sb, ino);
if (IS_ERR(foundinode)) {
unlock_kernel();
- QNX4DEBUG(("qnx4: lookup->iget -> error %ld\n",
+ QNX4DEBUG((KERN_ERR "qnx4: lookup->iget -> error %ld\n",
PTR_ERR(foundinode)));
return ERR_CAST(foundinode);
}
diff --git a/fs/reiserfs/Makefile b/fs/reiserfs/Makefile
index 7c5ab63..6a9e30c 100644
--- a/fs/reiserfs/Makefile
+++ b/fs/reiserfs/Makefile
@@ -7,7 +7,7 @@ obj-$(CONFIG_REISERFS_FS) += reiserfs.o
reiserfs-objs := bitmap.o do_balan.o namei.o inode.o file.o dir.o fix_node.o \
super.o prints.o objectid.o lbalance.o ibalance.o stree.o \
hashes.o tail_conversion.o journal.o resize.o \
- item_ops.o ioctl.o procfs.o xattr.o
+ item_ops.o ioctl.o procfs.o xattr.o lock.o
ifeq ($(CONFIG_REISERFS_FS_XATTR),y)
reiserfs-objs += xattr_user.o xattr_trusted.o
diff --git a/fs/reiserfs/bitmap.c b/fs/reiserfs/bitmap.c
index e716161..6854957 100644
--- a/fs/reiserfs/bitmap.c
+++ b/fs/reiserfs/bitmap.c
@@ -1249,14 +1249,18 @@ struct buffer_head *reiserfs_read_bitmap_block(struct super_block *sb,
else if (bitmap == 0)
block = (REISERFS_DISK_OFFSET_IN_BYTES >> sb->s_blocksize_bits) + 1;
+ reiserfs_write_unlock(sb);
bh = sb_bread(sb, block);
+ reiserfs_write_lock(sb);
if (bh == NULL)
reiserfs_warning(sb, "sh-2029: %s: bitmap block (#%u) "
"reading failed", __func__, block);
else {
if (buffer_locked(bh)) {
PROC_INFO_INC(sb, scan_bitmap.wait);
+ reiserfs_write_unlock(sb);
__wait_on_buffer(bh);
+ reiserfs_write_lock(sb);
}
BUG_ON(!buffer_uptodate(bh));
BUG_ON(atomic_read(&bh->b_count) == 0);
diff --git a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c
index 6d2668f..c094f58 100644
--- a/fs/reiserfs/dir.c
+++ b/fs/reiserfs/dir.c
@@ -20,7 +20,7 @@ const struct file_operations reiserfs_dir_operations = {
.read = generic_read_dir,
.readdir = reiserfs_readdir,
.fsync = reiserfs_dir_fsync,
- .ioctl = reiserfs_ioctl,
+ .unlocked_ioctl = reiserfs_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = reiserfs_compat_ioctl,
#endif
@@ -174,14 +174,22 @@ int reiserfs_readdir_dentry(struct dentry *dentry, void *dirent,
// user space buffer is swapped out. At that time
// entry can move to somewhere else
memcpy(local_buf, d_name, d_reclen);
+
+ /*
+ * Since filldir might sleep, we can release
+ * the write lock here for other waiters
+ */
+ reiserfs_write_unlock(inode->i_sb);
if (filldir
(dirent, local_buf, d_reclen, d_off, d_ino,
DT_UNKNOWN) < 0) {
+ reiserfs_write_lock(inode->i_sb);
if (local_buf != small_buf) {
kfree(local_buf);
}
goto end;
}
+ reiserfs_write_lock(inode->i_sb);
if (local_buf != small_buf) {
kfree(local_buf);
}
diff --git a/fs/reiserfs/do_balan.c b/fs/reiserfs/do_balan.c
index 128d3f7..60c0804 100644
--- a/fs/reiserfs/do_balan.c
+++ b/fs/reiserfs/do_balan.c
@@ -21,14 +21,6 @@
#include <linux/buffer_head.h>
#include <linux/kernel.h>
-#ifdef CONFIG_REISERFS_CHECK
-
-struct tree_balance *cur_tb = NULL; /* detects whether more than one
- copy of tb exists as a means
- of checking whether schedule
- is interrupting do_balance */
-#endif
-
static inline void buffer_info_init_left(struct tree_balance *tb,
struct buffer_info *bi)
{
@@ -1840,11 +1832,12 @@ static int check_before_balancing(struct tree_balance *tb)
{
int retval = 0;
- if (cur_tb) {
+ if (REISERFS_SB(tb->tb_sb)->cur_tb) {
reiserfs_panic(tb->tb_sb, "vs-12335", "suspect that schedule "
"occurred based on cur_tb not being null at "
"this point in code. do_balance cannot properly "
- "handle schedule occurring while it runs.");
+ "handle concurrent tree accesses on a same "
+ "mount point.");
}
/* double check that buffers that we will modify are unlocked. (fix_nodes should already have
@@ -1986,7 +1979,7 @@ static inline void do_balance_starts(struct tree_balance *tb)
"check");*/
RFALSE(check_before_balancing(tb), "PAP-12340: locked buffers in TB");
#ifdef CONFIG_REISERFS_CHECK
- cur_tb = tb;
+ REISERFS_SB(tb->tb_sb)->cur_tb = tb;
#endif
}
@@ -1996,7 +1989,7 @@ static inline void do_balance_completed(struct tree_balance *tb)
#ifdef CONFIG_REISERFS_CHECK
check_leaf_level(tb);
check_internal_levels(tb);
- cur_tb = NULL;
+ REISERFS_SB(tb->tb_sb)->cur_tb = NULL;
#endif
/* reiserfs_free_block is no longer schedule safe. So, we need to
diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c
index 9f43666..da2dba0 100644
--- a/fs/reiserfs/file.c
+++ b/fs/reiserfs/file.c
@@ -284,7 +284,7 @@ static ssize_t reiserfs_file_write(struct file *file, /* the file we are going t
const struct file_operations reiserfs_file_operations = {
.read = do_sync_read,
.write = reiserfs_file_write,
- .ioctl = reiserfs_ioctl,
+ .unlocked_ioctl = reiserfs_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = reiserfs_compat_ioctl,
#endif
diff --git a/fs/reiserfs/fix_node.c b/fs/reiserfs/fix_node.c
index 5e5a4e6..6591cb2 100644
--- a/fs/reiserfs/fix_node.c
+++ b/fs/reiserfs/fix_node.c
@@ -563,9 +563,6 @@ static int get_num_ver(int mode, struct tree_balance *tb, int h,
return needed_nodes;
}
-#ifdef CONFIG_REISERFS_CHECK
-extern struct tree_balance *cur_tb;
-#endif
/* Set parameters for balancing.
* Performs write of results of analysis of balancing into structure tb,
@@ -834,7 +831,7 @@ static int get_empty_nodes(struct tree_balance *tb, int h)
RFALSE(buffer_dirty(new_bh) ||
buffer_journaled(new_bh) ||
buffer_journal_dirty(new_bh),
- "PAP-8140: journlaled or dirty buffer %b for the new block",
+ "PAP-8140: journaled or dirty buffer %b for the new block",
new_bh);
/* Put empty buffers into the array. */
@@ -1022,7 +1019,11 @@ static int get_far_parent(struct tree_balance *tb,
/* Check whether the common parent is locked. */
if (buffer_locked(*pcom_father)) {
+
+ /* Release the write lock while the buffer is busy */
+ reiserfs_write_unlock(tb->tb_sb);
__wait_on_buffer(*pcom_father);
+ reiserfs_write_lock(tb->tb_sb);
if (FILESYSTEM_CHANGED_TB(tb)) {
brelse(*pcom_father);
return REPEAT_SEARCH;
@@ -1927,7 +1928,9 @@ static int get_direct_parent(struct tree_balance *tb, int h)
return REPEAT_SEARCH;
if (buffer_locked(bh)) {
+ reiserfs_write_unlock(tb->tb_sb);
__wait_on_buffer(bh);
+ reiserfs_write_lock(tb->tb_sb);
if (FILESYSTEM_CHANGED_TB(tb))
return REPEAT_SEARCH;
}
@@ -1965,7 +1968,9 @@ static int get_neighbors(struct tree_balance *tb, int h)
tb->FL[h]) ? tb->lkey[h] : B_NR_ITEMS(tb->
FL[h]);
son_number = B_N_CHILD_NUM(tb->FL[h], child_position);
+ reiserfs_write_unlock(sb);
bh = sb_bread(sb, son_number);
+ reiserfs_write_lock(sb);
if (!bh)
return IO_ERROR;
if (FILESYSTEM_CHANGED_TB(tb)) {
@@ -2003,7 +2008,9 @@ static int get_neighbors(struct tree_balance *tb, int h)
child_position =
(bh == tb->FR[h]) ? tb->rkey[h] + 1 : 0;
son_number = B_N_CHILD_NUM(tb->FR[h], child_position);
+ reiserfs_write_unlock(sb);
bh = sb_bread(sb, son_number);
+ reiserfs_write_lock(sb);
if (!bh)
return IO_ERROR;
if (FILESYSTEM_CHANGED_TB(tb)) {
@@ -2278,7 +2285,9 @@ static int wait_tb_buffers_until_unlocked(struct tree_balance *tb)
REPEAT_SEARCH : CARRY_ON;
}
#endif
+ reiserfs_write_unlock(tb->tb_sb);
__wait_on_buffer(locked);
+ reiserfs_write_lock(tb->tb_sb);
if (FILESYSTEM_CHANGED_TB(tb))
return REPEAT_SEARCH;
}
@@ -2349,12 +2358,14 @@ int fix_nodes(int op_mode, struct tree_balance *tb,
/* if it possible in indirect_to_direct conversion */
if (buffer_locked(tbS0)) {
+ reiserfs_write_unlock(tb->tb_sb);
__wait_on_buffer(tbS0);
+ reiserfs_write_lock(tb->tb_sb);
if (FILESYSTEM_CHANGED_TB(tb))
return REPEAT_SEARCH;
}
#ifdef CONFIG_REISERFS_CHECK
- if (cur_tb) {
+ if (REISERFS_SB(tb->tb_sb)->cur_tb) {
print_cur_tb("fix_nodes");
reiserfs_panic(tb->tb_sb, "PAP-8305",
"there is pending do_balance");
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
index a14d6cd..3a28e77 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -251,7 +251,6 @@ static int _get_block_create_0(struct inode *inode, sector_t block,
struct cpu_key key;
struct buffer_head *bh;
struct item_head *ih, tmp_ih;
- int fs_gen;
b_blocknr_t blocknr;
char *p = NULL;
int chars;
@@ -265,7 +264,6 @@ static int _get_block_create_0(struct inode *inode, sector_t block,
(loff_t) block * inode->i_sb->s_blocksize + 1, TYPE_ANY,
3);
- research:
result = search_for_position_by_key(inode->i_sb, &key, &path);
if (result != POSITION_FOUND) {
pathrelse(&path);
@@ -340,7 +338,6 @@ static int _get_block_create_0(struct inode *inode, sector_t block,
}
// read file tail into part of page
offset = (cpu_key_k_offset(&key) - 1) & (PAGE_CACHE_SIZE - 1);
- fs_gen = get_generation(inode->i_sb);
copy_item_head(&tmp_ih, ih);
/* we only want to kmap if we are reading the tail into the page.
@@ -348,13 +345,9 @@ static int _get_block_create_0(struct inode *inode, sector_t block,
** sure we need to. But, this means the item might move if
** kmap schedules
*/
- if (!p) {
+ if (!p)
p = (char *)kmap(bh_result->b_page);
- if (fs_changed(fs_gen, inode->i_sb)
- && item_moved(&tmp_ih, &path)) {
- goto research;
- }
- }
+
p += offset;
memset(p, 0, inode->i_sb->s_blocksize);
do {
@@ -489,10 +482,14 @@ static int reiserfs_get_blocks_direct_io(struct inode *inode,
disappeared */
if (REISERFS_I(inode)->i_flags & i_pack_on_close_mask) {
int err;
- lock_kernel();
+
+ reiserfs_write_lock(inode->i_sb);
+
err = reiserfs_commit_for_inode(inode);
REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask;
- unlock_kernel();
+
+ reiserfs_write_unlock(inode->i_sb);
+
if (err < 0)
ret = err;
}
@@ -601,6 +598,7 @@ int reiserfs_get_block(struct inode *inode, sector_t block,
__le32 *item;
int done;
int fs_gen;
+ int lock_depth;
struct reiserfs_transaction_handle *th = NULL;
/* space reserved in transaction batch:
. 3 balancings in direct->indirect conversion
@@ -616,12 +614,11 @@ int reiserfs_get_block(struct inode *inode, sector_t block,
loff_t new_offset =
(((loff_t) block) << inode->i_sb->s_blocksize_bits) + 1;
- /* bad.... */
- reiserfs_write_lock(inode->i_sb);
+ lock_depth = reiserfs_write_lock_once(inode->i_sb);
version = get_inode_item_key_version(inode);
if (!file_capable(inode, block)) {
- reiserfs_write_unlock(inode->i_sb);
+ reiserfs_write_unlock_once(inode->i_sb, lock_depth);
return -EFBIG;
}
@@ -633,7 +630,7 @@ int reiserfs_get_block(struct inode *inode, sector_t block,
/* find number of block-th logical block of the file */
ret = _get_block_create_0(inode, block, bh_result,
create | GET_BLOCK_READ_DIRECT);
- reiserfs_write_unlock(inode->i_sb);
+ reiserfs_write_unlock_once(inode->i_sb, lock_depth);
return ret;
}
/*
@@ -751,7 +748,7 @@ int reiserfs_get_block(struct inode *inode, sector_t block,
if (!dangle && th)
retval = reiserfs_end_persistent_transaction(th);
- reiserfs_write_unlock(inode->i_sb);
+ reiserfs_write_unlock_once(inode->i_sb, lock_depth);
/* the item was found, so new blocks were not added to the file
** there is no need to make sure the inode is updated with this
@@ -935,7 +932,7 @@ int reiserfs_get_block(struct inode *inode, sector_t block,
if (blocks_needed == 1) {
un = &unf_single;
} else {
- un = kzalloc(min(blocks_needed, max_to_insert) * UNFM_P_SIZE, GFP_ATOMIC); // We need to avoid scheduling.
+ un = kzalloc(min(blocks_needed, max_to_insert) * UNFM_P_SIZE, GFP_NOFS);
if (!un) {
un = &unf_single;
blocks_needed = 1;
@@ -997,10 +994,16 @@ int reiserfs_get_block(struct inode *inode, sector_t block,
if (retval)
goto failure;
}
- /* inserting indirect pointers for a hole can take a
- ** long time. reschedule if needed
+ /*
+ * inserting indirect pointers for a hole can take a
+ * long time. reschedule if needed and also release the write
+ * lock for others.
*/
- cond_resched();
+ if (need_resched()) {
+ reiserfs_write_unlock_once(inode->i_sb, lock_depth);
+ schedule();
+ lock_depth = reiserfs_write_lock_once(inode->i_sb);
+ }
retval = search_for_position_by_key(inode->i_sb, &key, &path);
if (retval == IO_ERROR) {
@@ -1035,7 +1038,7 @@ int reiserfs_get_block(struct inode *inode, sector_t block,
retval = err;
}
- reiserfs_write_unlock(inode->i_sb);
+ reiserfs_write_unlock_once(inode->i_sb, lock_depth);
reiserfs_check_path(&path);
return retval;
}
@@ -2072,8 +2075,9 @@ int reiserfs_truncate_file(struct inode *inode, int update_timestamps)
int error;
struct buffer_head *bh = NULL;
int err2;
+ int lock_depth;
- reiserfs_write_lock(inode->i_sb);
+ lock_depth = reiserfs_write_lock_once(inode->i_sb);
if (inode->i_size > 0) {
error = grab_tail_page(inode, &page, &bh);
@@ -2142,14 +2146,17 @@ int reiserfs_truncate_file(struct inode *inode, int update_timestamps)
page_cache_release(page);
}
- reiserfs_write_unlock(inode->i_sb);
+ reiserfs_write_unlock_once(inode->i_sb, lock_depth);
+
return 0;
out:
if (page) {
unlock_page(page);
page_cache_release(page);
}
- reiserfs_write_unlock(inode->i_sb);
+
+ reiserfs_write_unlock_once(inode->i_sb, lock_depth);
+
return error;
}
@@ -2608,7 +2615,10 @@ int reiserfs_prepare_write(struct file *f, struct page *page,
int ret;
int old_ref = 0;
+ reiserfs_write_unlock(inode->i_sb);
reiserfs_wait_on_write_block(inode->i_sb);
+ reiserfs_write_lock(inode->i_sb);
+
fix_tail_page_for_writing(page);
if (reiserfs_transaction_running(inode->i_sb)) {
struct reiserfs_transaction_handle *th;
@@ -2664,6 +2674,8 @@ static int reiserfs_write_end(struct file *file, struct address_space *mapping,
int update_sd = 0;
struct reiserfs_transaction_handle *th;
unsigned start;
+ int lock_depth = 0;
+ bool locked = false;
if ((unsigned long)fsdata & AOP_FLAG_CONT_EXPAND)
pos ++;
@@ -2690,9 +2702,11 @@ static int reiserfs_write_end(struct file *file, struct address_space *mapping,
** to do the i_size updates here.
*/
pos += copied;
+
if (pos > inode->i_size) {
struct reiserfs_transaction_handle myth;
- reiserfs_write_lock(inode->i_sb);
+ lock_depth = reiserfs_write_lock_once(inode->i_sb);
+ locked = true;
/* If the file have grown beyond the border where it
can have a tail, unmark it as needing a tail
packing */
@@ -2703,10 +2717,9 @@ static int reiserfs_write_end(struct file *file, struct address_space *mapping,
REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask;
ret = journal_begin(&myth, inode->i_sb, 1);
- if (ret) {
- reiserfs_write_unlock(inode->i_sb);
+ if (ret)
goto journal_error;
- }
+
reiserfs_update_inode_transaction(inode);
inode->i_size = pos;
/*
@@ -2718,34 +2731,36 @@ static int reiserfs_write_end(struct file *file, struct address_space *mapping,
reiserfs_update_sd(&myth, inode);
update_sd = 1;
ret = journal_end(&myth, inode->i_sb, 1);
- reiserfs_write_unlock(inode->i_sb);
if (ret)
goto journal_error;
}
if (th) {
- reiserfs_write_lock(inode->i_sb);
+ if (!locked) {
+ lock_depth = reiserfs_write_lock_once(inode->i_sb);
+ locked = true;
+ }
if (!update_sd)
mark_inode_dirty(inode);
ret = reiserfs_end_persistent_transaction(th);
- reiserfs_write_unlock(inode->i_sb);
if (ret)
goto out;
}
out:
+ if (locked)
+ reiserfs_write_unlock_once(inode->i_sb, lock_depth);
unlock_page(page);
page_cache_release(page);
return ret == 0 ? copied : ret;
journal_error:
+ reiserfs_write_unlock_once(inode->i_sb, lock_depth);
+ locked = false;
if (th) {
- reiserfs_write_lock(inode->i_sb);
if (!update_sd)
reiserfs_update_sd(th, inode);
ret = reiserfs_end_persistent_transaction(th);
- reiserfs_write_unlock(inode->i_sb);
}
-
goto out;
}
@@ -2758,7 +2773,10 @@ int reiserfs_commit_write(struct file *f, struct page *page,
int update_sd = 0;
struct reiserfs_transaction_handle *th = NULL;
+ reiserfs_write_unlock(inode->i_sb);
reiserfs_wait_on_write_block(inode->i_sb);
+ reiserfs_write_lock(inode->i_sb);
+
if (reiserfs_transaction_running(inode->i_sb)) {
th = current->journal_info;
}
@@ -2770,7 +2788,6 @@ int reiserfs_commit_write(struct file *f, struct page *page,
*/
if (pos > inode->i_size) {
struct reiserfs_transaction_handle myth;
- reiserfs_write_lock(inode->i_sb);
/* If the file have grown beyond the border where it
can have a tail, unmark it as needing a tail
packing */
@@ -2781,10 +2798,9 @@ int reiserfs_commit_write(struct file *f, struct page *page,
REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask;
ret = journal_begin(&myth, inode->i_sb, 1);
- if (ret) {
- reiserfs_write_unlock(inode->i_sb);
+ if (ret)
goto journal_error;
- }
+
reiserfs_update_inode_transaction(inode);
inode->i_size = pos;
/*
@@ -2796,16 +2812,13 @@ int reiserfs_commit_write(struct file *f, struct page *page,
reiserfs_update_sd(&myth, inode);
update_sd = 1;
ret = journal_end(&myth, inode->i_sb, 1);
- reiserfs_write_unlock(inode->i_sb);
if (ret)
goto journal_error;
}
if (th) {
- reiserfs_write_lock(inode->i_sb);
if (!update_sd)
mark_inode_dirty(inode);
ret = reiserfs_end_persistent_transaction(th);
- reiserfs_write_unlock(inode->i_sb);
if (ret)
goto out;
}
@@ -2815,11 +2828,9 @@ int reiserfs_commit_write(struct file *f, struct page *page,
journal_error:
if (th) {
- reiserfs_write_lock(inode->i_sb);
if (!update_sd)
reiserfs_update_sd(th, inode);
ret = reiserfs_end_persistent_transaction(th);
- reiserfs_write_unlock(inode->i_sb);
}
return ret;
diff --git a/fs/reiserfs/ioctl.c b/fs/reiserfs/ioctl.c
index 0ccc3fd..ace7745 100644
--- a/fs/reiserfs/ioctl.c
+++ b/fs/reiserfs/ioctl.c
@@ -13,44 +13,52 @@
#include <linux/compat.h>
/*
-** reiserfs_ioctl - handler for ioctl for inode
-** supported commands:
-** 1) REISERFS_IOC_UNPACK - try to unpack tail from direct item into indirect
-** and prevent packing file (argument arg has to be non-zero)
-** 2) REISERFS_IOC_[GS]ETFLAGS, REISERFS_IOC_[GS]ETVERSION
-** 3) That's all for a while ...
-*/
-int reiserfs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
+ * reiserfs_ioctl - handler for ioctl for inode
+ * supported commands:
+ * 1) REISERFS_IOC_UNPACK - try to unpack tail from direct item into indirect
+ * and prevent packing file (argument arg has to be non-zero)
+ * 2) REISERFS_IOC_[GS]ETFLAGS, REISERFS_IOC_[GS]ETVERSION
+ * 3) That's all for a while ...
+ */
+long reiserfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
+ struct inode *inode = filp->f_path.dentry->d_inode;
unsigned int flags;
int err = 0;
+ reiserfs_write_lock(inode->i_sb);
+
switch (cmd) {
case REISERFS_IOC_UNPACK:
if (S_ISREG(inode->i_mode)) {
if (arg)
- return reiserfs_unpack(inode, filp);
- else
- return 0;
+ err = reiserfs_unpack(inode, filp);
} else
- return -ENOTTY;
- /* following two cases are taken from fs/ext2/ioctl.c by Remy
- Card (card@masi.ibp.fr) */
+ err = -ENOTTY;
+ break;
+ /*
+ * following two cases are taken from fs/ext2/ioctl.c by Remy
+ * Card (card@masi.ibp.fr)
+ */
case REISERFS_IOC_GETFLAGS:
- if (!reiserfs_attrs(inode->i_sb))
- return -ENOTTY;
+ if (!reiserfs_attrs(inode->i_sb)) {
+ err = -ENOTTY;
+ break;
+ }
flags = REISERFS_I(inode)->i_attrs;
i_attrs_to_sd_attrs(inode, (__u16 *) & flags);
- return put_user(flags, (int __user *)arg);
+ err = put_user(flags, (int __user *)arg);
+ break;
case REISERFS_IOC_SETFLAGS:{
- if (!reiserfs_attrs(inode->i_sb))
- return -ENOTTY;
+ if (!reiserfs_attrs(inode->i_sb)) {
+ err = -ENOTTY;
+ break;
+ }
err = mnt_want_write(filp->f_path.mnt);
if (err)
- return err;
+ break;
if (!is_owner_or_cap(inode)) {
err = -EPERM;
@@ -90,16 +98,18 @@ int reiserfs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
mark_inode_dirty(inode);
setflags_out:
mnt_drop_write(filp->f_path.mnt);
- return err;
+ break;
}
case REISERFS_IOC_GETVERSION:
- return put_user(inode->i_generation, (int __user *)arg);
+ err = put_user(inode->i_generation, (int __user *)arg);
+ break;
case REISERFS_IOC_SETVERSION:
if (!is_owner_or_cap(inode))
- return -EPERM;
+ err = -EPERM;
+ break;
err = mnt_want_write(filp->f_path.mnt);
if (err)
- return err;
+ break;
if (get_user(inode->i_generation, (int __user *)arg)) {
err = -EFAULT;
goto setversion_out;
@@ -108,19 +118,20 @@ setflags_out:
mark_inode_dirty(inode);
setversion_out:
mnt_drop_write(filp->f_path.mnt);
- return err;
+ break;
default:
- return -ENOTTY;
+ err = -ENOTTY;
}
+
+ reiserfs_write_unlock(inode->i_sb);
+
+ return err;
}
#ifdef CONFIG_COMPAT
long reiserfs_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
- struct inode *inode = file->f_path.dentry->d_inode;
- int ret;
-
/* These are just misnamed, they actually get/put from/to user an int */
switch (cmd) {
case REISERFS_IOC32_UNPACK:
@@ -141,10 +152,8 @@ long reiserfs_compat_ioctl(struct file *file, unsigned int cmd,
default:
return -ENOIOCTLCMD;
}
- lock_kernel();
- ret = reiserfs_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg));
- unlock_kernel();
- return ret;
+
+ return reiserfs_ioctl(file, cmd, (unsigned long) compat_ptr(arg));
}
#endif
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
index 9062220..2f8a7e7 100644
--- a/fs/reiserfs/journal.c
+++ b/fs/reiserfs/journal.c
@@ -429,21 +429,6 @@ static void clear_prepared_bits(struct buffer_head *bh)
clear_buffer_journal_restore_dirty(bh);
}
-/* utility function to force a BUG if it is called without the big
-** kernel lock held. caller is the string printed just before calling BUG()
-*/
-void reiserfs_check_lock_depth(struct super_block *sb, char *caller)
-{
-#ifdef CONFIG_SMP
- if (current->lock_depth < 0) {
- reiserfs_panic(sb, "journal-1", "%s called without kernel "
- "lock held", caller);
- }
-#else
- ;
-#endif
-}
-
/* return a cnode with same dev, block number and size in table, or null if not found */
static inline struct reiserfs_journal_cnode *get_journal_hash_dev(struct
super_block
@@ -556,7 +541,8 @@ static inline void insert_journal_hash(struct reiserfs_journal_cnode **table,
static inline void lock_journal(struct super_block *sb)
{
PROC_INFO_INC(sb, journal.lock_journal);
- mutex_lock(&SB_JOURNAL(sb)->j_mutex);
+
+ reiserfs_mutex_lock_safe(&SB_JOURNAL(sb)->j_mutex, sb);
}
/* unlock the current transaction */
@@ -708,7 +694,9 @@ static void check_barrier_completion(struct super_block *s,
disable_barrier(s);
set_buffer_uptodate(bh);
set_buffer_dirty(bh);
+ reiserfs_write_unlock(s);
sync_dirty_buffer(bh);
+ reiserfs_write_lock(s);
}
}
@@ -996,8 +984,13 @@ static int reiserfs_async_progress_wait(struct super_block *s)
{
DEFINE_WAIT(wait);
struct reiserfs_journal *j = SB_JOURNAL(s);
- if (atomic_read(&j->j_async_throttle))
+
+ if (atomic_read(&j->j_async_throttle)) {
+ reiserfs_write_unlock(s);
congestion_wait(BLK_RW_ASYNC, HZ / 10);
+ reiserfs_write_lock(s);
+ }
+
return 0;
}
@@ -1043,7 +1036,8 @@ static int flush_commit_list(struct super_block *s,
}
/* make sure nobody is trying to flush this one at the same time */
- mutex_lock(&jl->j_commit_mutex);
+ reiserfs_mutex_lock_safe(&jl->j_commit_mutex, s);
+
if (!journal_list_still_alive(s, trans_id)) {
mutex_unlock(&jl->j_commit_mutex);
goto put_jl;
@@ -1061,12 +1055,17 @@ static int flush_commit_list(struct super_block *s,
if (!list_empty(&jl->j_bh_list)) {
int ret;
- unlock_kernel();
+
+ /*
+ * We might sleep in numerous places inside
+ * write_ordered_buffers. Relax the write lock.
+ */
+ reiserfs_write_unlock(s);
ret = write_ordered_buffers(&journal->j_dirty_buffers_lock,
journal, jl, &jl->j_bh_list);
if (ret < 0 && retval == 0)
retval = ret;
- lock_kernel();
+ reiserfs_write_lock(s);
}
BUG_ON(!list_empty(&jl->j_bh_list));
/*
@@ -1085,8 +1084,11 @@ static int flush_commit_list(struct super_block *s,
SB_ONDISK_JOURNAL_SIZE(s);
tbh = journal_find_get_block(s, bn);
if (tbh) {
- if (buffer_dirty(tbh))
- ll_rw_block(WRITE, 1, &tbh) ;
+ if (buffer_dirty(tbh)) {
+ reiserfs_write_unlock(s);
+ ll_rw_block(WRITE, 1, &tbh);
+ reiserfs_write_lock(s);
+ }
put_bh(tbh) ;
}
}
@@ -1114,12 +1116,19 @@ static int flush_commit_list(struct super_block *s,
bn = SB_ONDISK_JOURNAL_1st_BLOCK(s) +
(jl->j_start + i) % SB_ONDISK_JOURNAL_SIZE(s);
tbh = journal_find_get_block(s, bn);
+
+ reiserfs_write_unlock(s);
wait_on_buffer(tbh);
+ reiserfs_write_lock(s);
// since we're using ll_rw_blk above, it might have skipped over
// a locked buffer. Double check here
//
- if (buffer_dirty(tbh)) /* redundant, sync_dirty_buffer() checks */
+ /* redundant, sync_dirty_buffer() checks */
+ if (buffer_dirty(tbh)) {
+ reiserfs_write_unlock(s);
sync_dirty_buffer(tbh);
+ reiserfs_write_lock(s);
+ }
if (unlikely(!buffer_uptodate(tbh))) {
#ifdef CONFIG_REISERFS_CHECK
reiserfs_warning(s, "journal-601",
@@ -1143,10 +1152,15 @@ static int flush_commit_list(struct super_block *s,
if (buffer_dirty(jl->j_commit_bh))
BUG();
mark_buffer_dirty(jl->j_commit_bh) ;
+ reiserfs_write_unlock(s);
sync_dirty_buffer(jl->j_commit_bh) ;
+ reiserfs_write_lock(s);
}
- } else
+ } else {
+ reiserfs_write_unlock(s);
wait_on_buffer(jl->j_commit_bh);
+ reiserfs_write_lock(s);
+ }
check_barrier_completion(s, jl->j_commit_bh);
@@ -1286,7 +1300,9 @@ static int _update_journal_header_block(struct super_block *sb,
if (trans_id >= journal->j_last_flush_trans_id) {
if (buffer_locked((journal->j_header_bh))) {
+ reiserfs_write_unlock(sb);
wait_on_buffer((journal->j_header_bh));
+ reiserfs_write_lock(sb);
if (unlikely(!buffer_uptodate(journal->j_header_bh))) {
#ifdef CONFIG_REISERFS_CHECK
reiserfs_warning(sb, "journal-699",
@@ -1312,12 +1328,16 @@ static int _update_journal_header_block(struct super_block *sb,
disable_barrier(sb);
goto sync;
}
+ reiserfs_write_unlock(sb);
wait_on_buffer(journal->j_header_bh);
+ reiserfs_write_lock(sb);
check_barrier_completion(sb, journal->j_header_bh);
} else {
sync:
set_buffer_dirty(journal->j_header_bh);
+ reiserfs_write_unlock(sb);
sync_dirty_buffer(journal->j_header_bh);
+ reiserfs_write_lock(sb);
}
if (!buffer_uptodate(journal->j_header_bh)) {
reiserfs_warning(sb, "journal-837",
@@ -1409,7 +1429,7 @@ static int flush_journal_list(struct super_block *s,
/* if flushall == 0, the lock is already held */
if (flushall) {
- mutex_lock(&journal->j_flush_mutex);
+ reiserfs_mutex_lock_safe(&journal->j_flush_mutex, s);
} else if (mutex_trylock(&journal->j_flush_mutex)) {
BUG();
}
@@ -1553,7 +1573,11 @@ static int flush_journal_list(struct super_block *s,
reiserfs_panic(s, "journal-1011",
"cn->bh is NULL");
}
+
+ reiserfs_write_unlock(s);
wait_on_buffer(cn->bh);
+ reiserfs_write_lock(s);
+
if (!cn->bh) {
reiserfs_panic(s, "journal-1012",
"cn->bh is NULL");
@@ -1769,7 +1793,7 @@ static int kupdate_transactions(struct super_block *s,
struct reiserfs_journal *journal = SB_JOURNAL(s);
chunk.nr = 0;
- mutex_lock(&journal->j_flush_mutex);
+ reiserfs_mutex_lock_safe(&journal->j_flush_mutex, s);
if (!journal_list_still_alive(s, orig_trans_id)) {
goto done;
}
@@ -1973,11 +1997,19 @@ static int do_journal_release(struct reiserfs_transaction_handle *th,
reiserfs_mounted_fs_count--;
/* wait for all commits to finish */
cancel_delayed_work(&SB_JOURNAL(sb)->j_work);
+
+ /*
+ * We must release the write lock here because
+ * the workqueue job (flush_async_commit) needs this lock
+ */
+ reiserfs_write_unlock(sb);
flush_workqueue(commit_wq);
+
if (!reiserfs_mounted_fs_count) {
destroy_workqueue(commit_wq);
commit_wq = NULL;
}
+ reiserfs_write_lock(sb);
free_journal_ram(sb);
@@ -2243,7 +2275,11 @@ static int journal_read_transaction(struct super_block *sb,
/* read in the log blocks, memcpy to the corresponding real block */
ll_rw_block(READ, get_desc_trans_len(desc), log_blocks);
for (i = 0; i < get_desc_trans_len(desc); i++) {
+
+ reiserfs_write_unlock(sb);
wait_on_buffer(log_blocks[i]);
+ reiserfs_write_lock(sb);
+
if (!buffer_uptodate(log_blocks[i])) {
reiserfs_warning(sb, "journal-1212",
"REPLAY FAILURE fsck required! "
@@ -2765,11 +2801,27 @@ int journal_init(struct super_block *sb, const char *j_dev_name,
goto free_and_return;
}
+ /*
+ * We need to unlock here to avoid creating the following
+ * dependency:
+ * reiserfs_lock -> sysfs_mutex
+ * Because the reiserfs mmap path creates the following dependency:
+ * mm->mmap -> reiserfs_lock, hence we have
+ * mm->mmap -> reiserfs_lock ->sysfs_mutex
+ * This would ends up in a circular dependency with sysfs readdir path
+ * which does sysfs_mutex -> mm->mmap_sem
+ * This is fine because the reiserfs lock is useless in mount path,
+ * at least until we call journal_begin. We keep it for paranoid
+ * reasons.
+ */
+ reiserfs_write_unlock(sb);
if (journal_init_dev(sb, journal, j_dev_name) != 0) {
+ reiserfs_write_lock(sb);
reiserfs_warning(sb, "sh-462",
"unable to initialize jornal device");
goto free_and_return;
}
+ reiserfs_write_lock(sb);
rs = SB_DISK_SUPER_BLOCK(sb);
@@ -2881,8 +2933,11 @@ int journal_init(struct super_block *sb, const char *j_dev_name,
}
reiserfs_mounted_fs_count++;
- if (reiserfs_mounted_fs_count <= 1)
+ if (reiserfs_mounted_fs_count <= 1) {
+ reiserfs_write_unlock(sb);
commit_wq = create_workqueue("reiserfs");
+ reiserfs_write_lock(sb);
+ }
INIT_DELAYED_WORK(&journal->j_work, flush_async_commits);
journal->j_work_sb = sb;
@@ -2964,8 +3019,11 @@ static void queue_log_writer(struct super_block *s)
init_waitqueue_entry(&wait, current);
add_wait_queue(&journal->j_join_wait, &wait);
set_current_state(TASK_UNINTERRUPTIBLE);
- if (test_bit(J_WRITERS_QUEUED, &journal->j_state))
+ if (test_bit(J_WRITERS_QUEUED, &journal->j_state)) {
+ reiserfs_write_unlock(s);
schedule();
+ reiserfs_write_lock(s);
+ }
__set_current_state(TASK_RUNNING);
remove_wait_queue(&journal->j_join_wait, &wait);
}
@@ -2982,7 +3040,9 @@ static void let_transaction_grow(struct super_block *sb, unsigned int trans_id)
struct reiserfs_journal *journal = SB_JOURNAL(sb);
unsigned long bcount = journal->j_bcount;
while (1) {
+ reiserfs_write_unlock(sb);
schedule_timeout_uninterruptible(1);
+ reiserfs_write_lock(sb);
journal->j_current_jl->j_state |= LIST_COMMIT_PENDING;
while ((atomic_read(&journal->j_wcount) > 0 ||
atomic_read(&journal->j_jlock)) &&
@@ -3033,7 +3093,9 @@ static int do_journal_begin_r(struct reiserfs_transaction_handle *th,
if (test_bit(J_WRITERS_BLOCKED, &journal->j_state)) {
unlock_journal(sb);
+ reiserfs_write_unlock(sb);
reiserfs_wait_on_write_block(sb);
+ reiserfs_write_lock(sb);
PROC_INFO_INC(sb, journal.journal_relock_writers);
goto relock;
}
@@ -3506,14 +3568,14 @@ static void flush_async_commits(struct work_struct *work)
struct reiserfs_journal_list *jl;
struct list_head *entry;
- lock_kernel();
+ reiserfs_write_lock(sb);
if (!list_empty(&journal->j_journal_list)) {
/* last entry is the youngest, commit it and you get everything */
entry = journal->j_journal_list.prev;
jl = JOURNAL_LIST_ENTRY(entry);
flush_commit_list(sb, jl, 1);
}
- unlock_kernel();
+ reiserfs_write_unlock(sb);
}
/*
@@ -4041,7 +4103,7 @@ static int do_journal_end(struct reiserfs_transaction_handle *th,
* the new transaction is fully setup, and we've already flushed the
* ordered bh list
*/
- mutex_lock(&jl->j_commit_mutex);
+ reiserfs_mutex_lock_safe(&jl->j_commit_mutex, sb);
/* save the transaction id in case we need to commit it later */
commit_trans_id = jl->j_trans_id;
@@ -4156,7 +4218,9 @@ static int do_journal_end(struct reiserfs_transaction_handle *th,
next = cn->next;
free_cnode(sb, cn);
cn = next;
+ reiserfs_write_unlock(sb);
cond_resched();
+ reiserfs_write_lock(sb);
}
/* we are done with both the c_bh and d_bh, but
@@ -4203,10 +4267,10 @@ static int do_journal_end(struct reiserfs_transaction_handle *th,
* is lost.
*/
if (!list_empty(&jl->j_tail_bh_list)) {
- unlock_kernel();
+ reiserfs_write_unlock(sb);
write_ordered_buffers(&journal->j_dirty_buffers_lock,
journal, jl, &jl->j_tail_bh_list);
- lock_kernel();
+ reiserfs_write_lock(sb);
}
BUG_ON(!list_empty(&jl->j_tail_bh_list));
mutex_unlock(&jl->j_commit_mutex);
diff --git a/fs/reiserfs/lock.c b/fs/reiserfs/lock.c
new file mode 100644
index 0000000..ee2cfc0
--- /dev/null
+++ b/fs/reiserfs/lock.c
@@ -0,0 +1,88 @@
+#include <linux/reiserfs_fs.h>
+#include <linux/mutex.h>
+
+/*
+ * The previous reiserfs locking scheme was heavily based on
+ * the tricky properties of the Bkl:
+ *
+ * - it was acquired recursively by a same task
+ * - the performances relied on the release-while-schedule() property
+ *
+ * Now that we replace it by a mutex, we still want to keep the same
+ * recursive property to avoid big changes in the code structure.
+ * We use our own lock_owner here because the owner field on a mutex
+ * is only available in SMP or mutex debugging, also we only need this field
+ * for this mutex, no need for a system wide mutex facility.
+ *
+ * Also this lock is often released before a call that could block because
+ * reiserfs performances were partialy based on the release while schedule()
+ * property of the Bkl.
+ */
+void reiserfs_write_lock(struct super_block *s)
+{
+ struct reiserfs_sb_info *sb_i = REISERFS_SB(s);
+
+ if (sb_i->lock_owner != current) {
+ mutex_lock(&sb_i->lock);
+ sb_i->lock_owner = current;
+ }
+
+ /* No need to protect it, only the current task touches it */
+ sb_i->lock_depth++;
+}
+
+void reiserfs_write_unlock(struct super_block *s)
+{
+ struct reiserfs_sb_info *sb_i = REISERFS_SB(s);
+
+ /*
+ * Are we unlocking without even holding the lock?
+ * Such a situation must raise a BUG() if we don't want
+ * to corrupt the data.
+ */
+ BUG_ON(sb_i->lock_owner != current);
+
+ if (--sb_i->lock_depth == -1) {
+ sb_i->lock_owner = NULL;
+ mutex_unlock(&sb_i->lock);
+ }
+}
+
+/*
+ * If we already own the lock, just exit and don't increase the depth.
+ * Useful when we don't want to lock more than once.
+ *
+ * We always return the lock_depth we had before calling
+ * this function.
+ */
+int reiserfs_write_lock_once(struct super_block *s)
+{
+ struct reiserfs_sb_info *sb_i = REISERFS_SB(s);
+
+ if (sb_i->lock_owner != current) {
+ mutex_lock(&sb_i->lock);
+ sb_i->lock_owner = current;
+ return sb_i->lock_depth++;
+ }
+
+ return sb_i->lock_depth;
+}
+
+void reiserfs_write_unlock_once(struct super_block *s, int lock_depth)
+{
+ if (lock_depth == -1)
+ reiserfs_write_unlock(s);
+}
+
+/*
+ * Utility function to force a BUG if it is called without the superblock
+ * write lock held. caller is the string printed just before calling BUG()
+ */
+void reiserfs_check_lock_depth(struct super_block *sb, char *caller)
+{
+ struct reiserfs_sb_info *sb_i = REISERFS_SB(sb);
+
+ if (sb_i->lock_depth < 0)
+ reiserfs_panic(sb, "%s called without kernel lock held %d",
+ caller);
+}
diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c
index 2715791..e296ff7 100644
--- a/fs/reiserfs/namei.c
+++ b/fs/reiserfs/namei.c
@@ -324,6 +324,7 @@ static struct dentry *reiserfs_lookup(struct inode *dir, struct dentry *dentry,
struct nameidata *nd)
{
int retval;
+ int lock_depth;
struct inode *inode = NULL;
struct reiserfs_dir_entry de;
INITIALIZE_PATH(path_to_entry);
@@ -331,7 +332,13 @@ static struct dentry *reiserfs_lookup(struct inode *dir, struct dentry *dentry,
if (REISERFS_MAX_NAME(dir->i_sb->s_blocksize) < dentry->d_name.len)
return ERR_PTR(-ENAMETOOLONG);
- reiserfs_write_lock(dir->i_sb);
+ /*
+ * Might be called with or without the write lock, must be careful
+ * to not recursively hold it in case we want to release the lock
+ * before rescheduling.
+ */
+ lock_depth = reiserfs_write_lock_once(dir->i_sb);
+
de.de_gen_number_bit_string = NULL;
retval =
reiserfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len,
@@ -341,7 +348,7 @@ static struct dentry *reiserfs_lookup(struct inode *dir, struct dentry *dentry,
inode = reiserfs_iget(dir->i_sb,
(struct cpu_key *)&(de.de_dir_id));
if (!inode || IS_ERR(inode)) {
- reiserfs_write_unlock(dir->i_sb);
+ reiserfs_write_unlock_once(dir->i_sb, lock_depth);
return ERR_PTR(-EACCES);
}
@@ -350,7 +357,7 @@ static struct dentry *reiserfs_lookup(struct inode *dir, struct dentry *dentry,
if (IS_PRIVATE(dir))
inode->i_flags |= S_PRIVATE;
}
- reiserfs_write_unlock(dir->i_sb);
+ reiserfs_write_unlock_once(dir->i_sb, lock_depth);
if (retval == IO_ERROR) {
return ERR_PTR(-EIO);
}
@@ -725,6 +732,7 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
struct inode *inode;
struct reiserfs_transaction_handle th;
struct reiserfs_security_handle security;
+ int lock_depth;
/* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */
int jbegin_count =
JOURNAL_PER_BALANCE_CNT * 3 +
@@ -748,7 +756,7 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
return retval;
}
jbegin_count += retval;
- reiserfs_write_lock(dir->i_sb);
+ lock_depth = reiserfs_write_lock_once(dir->i_sb);
retval = journal_begin(&th, dir->i_sb, jbegin_count);
if (retval) {
@@ -798,8 +806,8 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
d_instantiate(dentry, inode);
unlock_new_inode(inode);
retval = journal_end(&th, dir->i_sb, jbegin_count);
- out_failed:
- reiserfs_write_unlock(dir->i_sb);
+out_failed:
+ reiserfs_write_unlock_once(dir->i_sb, lock_depth);
return retval;
}
diff --git a/fs/reiserfs/prints.c b/fs/reiserfs/prints.c
index 536eaca..adbc6f5 100644
--- a/fs/reiserfs/prints.c
+++ b/fs/reiserfs/prints.c
@@ -349,10 +349,6 @@ void reiserfs_debug(struct super_block *s, int level, const char *fmt, ...)
. */
-#ifdef CONFIG_REISERFS_CHECK
-extern struct tree_balance *cur_tb;
-#endif
-
void __reiserfs_panic(struct super_block *sb, const char *id,
const char *function, const char *fmt, ...)
{
diff --git a/fs/reiserfs/resize.c b/fs/reiserfs/resize.c
index 18b315d..b3a94d2 100644
--- a/fs/reiserfs/resize.c
+++ b/fs/reiserfs/resize.c
@@ -141,7 +141,9 @@ int reiserfs_resize(struct super_block *s, unsigned long block_count_new)
set_buffer_uptodate(bh);
mark_buffer_dirty(bh);
+ reiserfs_write_unlock(s);
sync_dirty_buffer(bh);
+ reiserfs_write_lock(s);
// update bitmap_info stuff
bitmap[i].free_count = sb_blocksize(sb) * 8 - 1;
brelse(bh);
diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c
index d036ee5..5fa7118 100644
--- a/fs/reiserfs/stree.c
+++ b/fs/reiserfs/stree.c
@@ -222,9 +222,6 @@ static inline int bin_search(const void *key, /* Key to search for. */
return ITEM_NOT_FOUND;
}
-#ifdef CONFIG_REISERFS_CHECK
-extern struct tree_balance *cur_tb;
-#endif
/* Minimal possible key. It is never in the tree. */
const struct reiserfs_key MIN_KEY = { 0, 0, {{0, 0},} };
@@ -519,25 +516,48 @@ static int is_tree_node(struct buffer_head *bh, int level)
#define SEARCH_BY_KEY_READA 16
-/* The function is NOT SCHEDULE-SAFE! */
-static void search_by_key_reada(struct super_block *s,
+/*
+ * The function is NOT SCHEDULE-SAFE!
+ * It might unlock the write lock if we needed to wait for a block
+ * to be read. Note that in this case it won't recover the lock to avoid
+ * high contention resulting from too much lock requests, especially
+ * the caller (search_by_key) will perform other schedule-unsafe
+ * operations just after calling this function.
+ *
+ * @return true if we have unlocked
+ */
+static bool search_by_key_reada(struct super_block *s,
struct buffer_head **bh,
b_blocknr_t *b, int num)
{
int i, j;
+ bool unlocked = false;
for (i = 0; i < num; i++) {
bh[i] = sb_getblk(s, b[i]);
}
+ /*
+ * We are going to read some blocks on which we
+ * have a reference. It's safe, though we might be
+ * reading blocks concurrently changed if we release
+ * the lock. But it's still fine because we check later
+ * if the tree changed
+ */
for (j = 0; j < i; j++) {
/*
* note, this needs attention if we are getting rid of the BKL
* you have to make sure the prepared bit isn't set on this buffer
*/
- if (!buffer_uptodate(bh[j]))
+ if (!buffer_uptodate(bh[j])) {
+ if (!unlocked) {
+ reiserfs_write_unlock(s);
+ unlocked = true;
+ }
ll_rw_block(READA, 1, bh + j);
+ }
brelse(bh[j]);
}
+ return unlocked;
}
/**************************************************************************
@@ -625,11 +645,26 @@ int search_by_key(struct super_block *sb, const struct cpu_key *key, /* Key to s
have a pointer to it. */
if ((bh = last_element->pe_buffer =
sb_getblk(sb, block_number))) {
+ bool unlocked = false;
+
if (!buffer_uptodate(bh) && reada_count > 1)
- search_by_key_reada(sb, reada_bh,
+ /* may unlock the write lock */
+ unlocked = search_by_key_reada(sb, reada_bh,
reada_blocks, reada_count);
+ /*
+ * If we haven't already unlocked the write lock,
+ * then we need to do that here before reading
+ * the current block
+ */
+ if (!buffer_uptodate(bh) && !unlocked) {
+ reiserfs_write_unlock(sb);
+ unlocked = true;
+ }
ll_rw_block(READ, 1, &bh);
wait_on_buffer(bh);
+
+ if (unlocked)
+ reiserfs_write_lock(sb);
if (!buffer_uptodate(bh))
goto io_error;
} else {
@@ -673,7 +708,7 @@ int search_by_key(struct super_block *sb, const struct cpu_key *key, /* Key to s
!key_in_buffer(search_path, key, sb),
"PAP-5130: key is not in the buffer");
#ifdef CONFIG_REISERFS_CHECK
- if (cur_tb) {
+ if (REISERFS_SB(sb)->cur_tb) {
print_cur_tb("5140");
reiserfs_panic(sb, "PAP-5140",
"schedule occurred in do_balance!");
@@ -1024,7 +1059,9 @@ static char prepare_for_delete_or_cut(struct reiserfs_transaction_handle *th, st
reiserfs_free_block(th, inode, block, 1);
}
+ reiserfs_write_unlock(sb);
cond_resched();
+ reiserfs_write_lock(sb);
if (item_moved (&s_ih, path)) {
need_re_search = 1;
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
index f0ad05f..339b0ba 100644
--- a/fs/reiserfs/super.c
+++ b/fs/reiserfs/super.c
@@ -465,7 +465,7 @@ static void reiserfs_put_super(struct super_block *s)
struct reiserfs_transaction_handle th;
th.t_trans_id = 0;
- lock_kernel();
+ reiserfs_write_lock(s);
if (s->s_dirt)
reiserfs_write_super(s);
@@ -499,10 +499,10 @@ static void reiserfs_put_super(struct super_block *s)
reiserfs_proc_info_done(s);
+ reiserfs_write_unlock(s);
+ mutex_destroy(&REISERFS_SB(s)->lock);
kfree(s->s_fs_info);
s->s_fs_info = NULL;
-
- unlock_kernel();
}
static struct kmem_cache *reiserfs_inode_cachep;
@@ -554,25 +554,28 @@ static void reiserfs_dirty_inode(struct inode *inode)
struct reiserfs_transaction_handle th;
int err = 0;
+ int lock_depth;
+
if (inode->i_sb->s_flags & MS_RDONLY) {
reiserfs_warning(inode->i_sb, "clm-6006",
"writing inode %lu on readonly FS",
inode->i_ino);
return;
}
- reiserfs_write_lock(inode->i_sb);
+ lock_depth = reiserfs_write_lock_once(inode->i_sb);
/* this is really only used for atime updates, so they don't have
** to be included in O_SYNC or fsync
*/
err = journal_begin(&th, inode->i_sb, 1);
- if (err) {
- reiserfs_write_unlock(inode->i_sb);
- return;
- }
+ if (err)
+ goto out;
+
reiserfs_update_sd(&th, inode);
journal_end(&th, inode->i_sb, 1);
- reiserfs_write_unlock(inode->i_sb);
+
+out:
+ reiserfs_write_unlock_once(inode->i_sb, lock_depth);
}
#ifdef CONFIG_QUOTA
@@ -1168,11 +1171,14 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
unsigned int qfmt = 0;
#ifdef CONFIG_QUOTA
int i;
+#endif
+
+ reiserfs_write_lock(s);
+#ifdef CONFIG_QUOTA
memcpy(qf_names, REISERFS_SB(s)->s_qf_names, sizeof(qf_names));
#endif
- lock_kernel();
rs = SB_DISK_SUPER_BLOCK(s);
if (!reiserfs_parse_options
@@ -1295,12 +1301,12 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
out_ok:
replace_mount_options(s, new_opts);
- unlock_kernel();
+ reiserfs_write_unlock(s);
return 0;
out_err:
kfree(new_opts);
- unlock_kernel();
+ reiserfs_write_unlock(s);
return err;
}
@@ -1404,7 +1410,9 @@ static int read_super_block(struct super_block *s, int offset)
static int reread_meta_blocks(struct super_block *s)
{
ll_rw_block(READ, 1, &(SB_BUFFER_WITH_SB(s)));
+ reiserfs_write_unlock(s);
wait_on_buffer(SB_BUFFER_WITH_SB(s));
+ reiserfs_write_lock(s);
if (!buffer_uptodate(SB_BUFFER_WITH_SB(s))) {
reiserfs_warning(s, "reiserfs-2504", "error reading the super");
return 1;
@@ -1613,7 +1621,7 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
sbi = kzalloc(sizeof(struct reiserfs_sb_info), GFP_KERNEL);
if (!sbi) {
errval = -ENOMEM;
- goto error;
+ goto error_alloc;
}
s->s_fs_info = sbi;
/* Set default values for options: non-aggressive tails, RO on errors */
@@ -1627,6 +1635,20 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
/* setup default block allocator options */
reiserfs_init_alloc_options(s);
+ mutex_init(&REISERFS_SB(s)->lock);
+ REISERFS_SB(s)->lock_depth = -1;
+
+ /*
+ * This function is called with the bkl, which also was the old
+ * locking used here.
+ * do_journal_begin() will soon check if we hold the lock (ie: was the
+ * bkl). This is likely because do_journal_begin() has several another
+ * callers because at this time, it doesn't seem to be necessary to
+ * protect against anything.
+ * Anyway, let's be conservative and lock for now.
+ */
+ reiserfs_write_lock(s);
+
jdev_name = NULL;
if (reiserfs_parse_options
(s, (char *)data, &(sbi->s_mount_opt), &blocks, &jdev_name,
@@ -1852,9 +1874,13 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
init_waitqueue_head(&(sbi->s_wait));
spin_lock_init(&sbi->bitmap_lock);
+ reiserfs_write_unlock(s);
+
return (0);
error:
+ reiserfs_write_unlock(s);
+error_alloc:
if (jinit_done) { /* kill the commit thread, free journal ram */
journal_release_error(NULL, s);
}
diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c
index 6925b83..58aa8e7 100644
--- a/fs/reiserfs/xattr.c
+++ b/fs/reiserfs/xattr.c
@@ -975,7 +975,7 @@ int reiserfs_lookup_privroot(struct super_block *s)
int err = 0;
/* If we don't have the privroot located yet - go find it */
- mutex_lock(&s->s_root->d_inode->i_mutex);
+ reiserfs_mutex_lock_safe(&s->s_root->d_inode->i_mutex, s);
dentry = lookup_one_len(PRIVROOT_NAME, s->s_root,
strlen(PRIVROOT_NAME));
if (!IS_ERR(dentry)) {
@@ -1004,14 +1004,14 @@ int reiserfs_xattr_init(struct super_block *s, int mount_flags)
goto error;
if (!privroot->d_inode && !(mount_flags & MS_RDONLY)) {
- mutex_lock(&s->s_root->d_inode->i_mutex);
+ reiserfs_mutex_lock_safe(&s->s_root->d_inode->i_mutex, s);
err = create_privroot(REISERFS_SB(s)->priv_root);
mutex_unlock(&s->s_root->d_inode->i_mutex);
}
if (privroot->d_inode) {
s->s_xattr = reiserfs_xattr_handlers;
- mutex_lock(&privroot->d_inode->i_mutex);
+ reiserfs_mutex_lock_safe(&privroot->d_inode->i_mutex, s);
if (!REISERFS_SB(s)->xattr_root) {
struct dentry *dentry;
dentry = lookup_one_len(XAROOT_NAME, privroot,
diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c
index f94ddf7..868a55e 100644
--- a/fs/ubifs/recovery.c
+++ b/fs/ubifs/recovery.c
@@ -23,7 +23,7 @@
/*
* This file implements functions needed to recover from unclean un-mounts.
* When UBIFS is mounted, it checks a flag on the master node to determine if
- * an un-mount was completed sucessfully. If not, the process of mounting
+ * an un-mount was completed successfully. If not, the process of mounting
* incorparates additional checking and fixing of on-flash data structures.
* UBIFS always cleans away all remnants of an unclean un-mount, so that
* errors do not accumulate. However UBIFS defers recovery if it is mounted
diff --git a/fs/xfs/quota/xfs_dquot.h b/fs/xfs/quota/xfs_dquot.h
index 6533ead..a2c16bc 100644
--- a/fs/xfs/quota/xfs_dquot.h
+++ b/fs/xfs/quota/xfs_dquot.h
@@ -98,7 +98,7 @@ typedef struct xfs_dquot {
#define dq_flags q_lists.dqm_flags
/*
- * Lock hierachy for q_qlock:
+ * Lock hierarchy for q_qlock:
* XFS_QLOCK_NORMAL is the implicit default,
* XFS_QLOCK_NESTED is the dquot with the higher id in xfs_dqlock2
*/
diff --git a/include/asm-generic/memory_model.h b/include/asm-generic/memory_model.h
index 4c8d0af..fb2d63f 100644
--- a/include/asm-generic/memory_model.h
+++ b/include/asm-generic/memory_model.h
@@ -47,7 +47,7 @@
#elif defined(CONFIG_SPARSEMEM_VMEMMAP)
-/* memmap is virtually contigious. */
+/* memmap is virtually contiguous. */
#define __pfn_to_page(pfn) (vmemmap + (pfn))
#define __page_to_pfn(page) (unsigned long)((page) - vmemmap)
diff --git a/include/asm-generic/unistd.h b/include/asm-generic/unistd.h
index d76b66a..7c38c14 100644
--- a/include/asm-generic/unistd.h
+++ b/include/asm-generic/unistd.h
@@ -631,7 +631,7 @@ __SYSCALL(__NR_perf_event_open, sys_perf_event_open)
* these are provided for both review and as a porting
* help for the C library version.
*
- * Last chance: are any of these important enought to
+ * Last chance: are any of these important enough to
* enable by default?
*/
#ifdef __ARCH_WANT_SYSCALL_NO_AT
diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h
index 1ffb53f..fc0d575 100644
--- a/include/crypto/algapi.h
+++ b/include/crypto/algapi.h
@@ -106,7 +106,6 @@ struct blkcipher_walk {
extern const struct crypto_type crypto_ablkcipher_type;
extern const struct crypto_type crypto_aead_type;
extern const struct crypto_type crypto_blkcipher_type;
-extern const struct crypto_type crypto_hash_type;
void crypto_mod_put(struct crypto_alg *alg);
diff --git a/include/crypto/cryptd.h b/include/crypto/cryptd.h
index 2f65a6e..1c96b25 100644
--- a/include/crypto/cryptd.h
+++ b/include/crypto/cryptd.h
@@ -39,6 +39,7 @@ static inline struct cryptd_ahash *__cryptd_ahash_cast(
struct cryptd_ahash *cryptd_alloc_ahash(const char *alg_name,
u32 type, u32 mask);
struct crypto_shash *cryptd_ahash_child(struct cryptd_ahash *tfm);
+struct shash_desc *cryptd_shash_desc(struct ahash_request *req);
void cryptd_free_ahash(struct cryptd_ahash *tfm);
#endif
diff --git a/include/linux/cciss_ioctl.h b/include/linux/cciss_ioctl.h
index cb57c30..eb130b4 100644
--- a/include/linux/cciss_ioctl.h
+++ b/include/linux/cciss_ioctl.h
@@ -39,7 +39,7 @@ typedef __u32 DriverVer_type;
#ifndef CCISS_CMD_H
// This defines are duplicated in cciss_cmd.h in the driver directory
-//general boundary defintions
+//general boundary definitions
#define SENSEINFOBYTES 32//note that this value may vary between host implementations
//Command Status value
diff --git a/include/linux/chio.h b/include/linux/chio.h
index 519248d..d9bac7f 100644
--- a/include/linux/chio.h
+++ b/include/linux/chio.h
@@ -21,7 +21,7 @@
* query vendor-specific element types
*
* accessing elements works by specifing type and unit of the element.
- * for eample, storage elements are addressed with type = CHET_ST and
+ * for example, storage elements are addressed with type = CHET_ST and
* unit = 0 .. cp_nslots-1
*
*/
diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h
index 3a1dbba..0cf725b 100644
--- a/include/linux/clockchips.h
+++ b/include/linux/clockchips.h
@@ -77,10 +77,10 @@ enum clock_event_nofitiers {
struct clock_event_device {
const char *name;
unsigned int features;
- unsigned long max_delta_ns;
- unsigned long min_delta_ns;
- unsigned long mult;
- int shift;
+ u64 max_delta_ns;
+ u64 min_delta_ns;
+ u32 mult;
+ u32 shift;
int rating;
int irq;
const struct cpumask *cpumask;
@@ -116,8 +116,8 @@ static inline unsigned long div_sc(unsigned long ticks, unsigned long nsec,
}
/* Clock event layer functions */
-extern unsigned long clockevent_delta2ns(unsigned long latch,
- struct clock_event_device *evt);
+extern u64 clockevent_delta2ns(unsigned long latch,
+ struct clock_event_device *evt);
extern void clockevents_register_device(struct clock_event_device *dev);
extern void clockevents_exchange_device(struct clock_event_device *old,
@@ -130,6 +130,13 @@ extern int clockevents_program_event(struct clock_event_device *dev,
extern void clockevents_handle_noop(struct clock_event_device *dev);
+static inline void
+clockevents_calc_mult_shift(struct clock_event_device *ce, u32 freq, u32 minsec)
+{
+ return clocks_calc_mult_shift(&ce->mult, &ce->shift, NSEC_PER_SEC,
+ freq, minsec);
+}
+
#ifdef CONFIG_GENERIC_CLOCKEVENTS
extern void clockevents_notify(unsigned long reason, void *arg);
#else
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index 83d2fbd..8a4a130 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -151,6 +151,7 @@ extern u64 timecounter_cyc2time(struct timecounter *tc,
* subtraction of non 64 bit counters
* @mult: cycle to nanosecond multiplier
* @shift: cycle to nanosecond divisor (power of two)
+ * @max_idle_ns: max idle time permitted by the clocksource (nsecs)
* @flags: flags describing special properties
* @vread: vsyscall based read
* @resume: resume function for the clocksource, if necessary
@@ -168,6 +169,7 @@ struct clocksource {
cycle_t mask;
u32 mult;
u32 shift;
+ u64 max_idle_ns;
unsigned long flags;
cycle_t (*vread)(void);
void (*resume)(void);
@@ -279,11 +281,23 @@ extern void clocksource_resume(void);
extern struct clocksource * __init __weak clocksource_default_clock(void);
extern void clocksource_mark_unstable(struct clocksource *cs);
+extern void
+clocks_calc_mult_shift(u32 *mult, u32 *shift, u32 from, u32 to, u32 minsec);
+
+static inline void
+clocksource_calc_mult_shift(struct clocksource *cs, u32 freq, u32 minsec)
+{
+ return clocks_calc_mult_shift(&cs->mult, &cs->shift, freq,
+ NSEC_PER_SEC, minsec);
+}
+
#ifdef CONFIG_GENERIC_TIME_VSYSCALL
-extern void update_vsyscall(struct timespec *ts, struct clocksource *c);
+extern void
+update_vsyscall(struct timespec *ts, struct clocksource *c, u32 mult);
extern void update_vsyscall_tz(void);
#else
-static inline void update_vsyscall(struct timespec *ts, struct clocksource *c)
+static inline void
+update_vsyscall(struct timespec *ts, struct clocksource *c, u32 mult)
{
}
diff --git a/include/linux/crypto.h b/include/linux/crypto.h
index fd92988..24d2e30 100644
--- a/include/linux/crypto.h
+++ b/include/linux/crypto.h
@@ -250,29 +250,6 @@ struct cipher_alg {
void (*cia_decrypt)(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
};
-struct digest_alg {
- unsigned int dia_digestsize;
- void (*dia_init)(struct crypto_tfm *tfm);
- void (*dia_update)(struct crypto_tfm *tfm, const u8 *data,
- unsigned int len);
- void (*dia_final)(struct crypto_tfm *tfm, u8 *out);
- int (*dia_setkey)(struct crypto_tfm *tfm, const u8 *key,
- unsigned int keylen);
-};
-
-struct hash_alg {
- int (*init)(struct hash_desc *desc);
- int (*update)(struct hash_desc *desc, struct scatterlist *sg,
- unsigned int nbytes);
- int (*final)(struct hash_desc *desc, u8 *out);
- int (*digest)(struct hash_desc *desc, struct scatterlist *sg,
- unsigned int nbytes, u8 *out);
- int (*setkey)(struct crypto_hash *tfm, const u8 *key,
- unsigned int keylen);
-
- unsigned int digestsize;
-};
-
struct compress_alg {
int (*coa_compress)(struct crypto_tfm *tfm, const u8 *src,
unsigned int slen, u8 *dst, unsigned int *dlen);
@@ -293,8 +270,6 @@ struct rng_alg {
#define cra_aead cra_u.aead
#define cra_blkcipher cra_u.blkcipher
#define cra_cipher cra_u.cipher
-#define cra_digest cra_u.digest
-#define cra_hash cra_u.hash
#define cra_compress cra_u.compress
#define cra_rng cra_u.rng
@@ -320,8 +295,6 @@ struct crypto_alg {
struct aead_alg aead;
struct blkcipher_alg blkcipher;
struct cipher_alg cipher;
- struct digest_alg digest;
- struct hash_alg hash;
struct compress_alg compress;
struct rng_alg rng;
} cra_u;
diff --git a/include/linux/dm-log-userspace.h b/include/linux/dm-log-userspace.h
index 8a1f972..0c3c3a2 100644
--- a/include/linux/dm-log-userspace.h
+++ b/include/linux/dm-log-userspace.h
@@ -363,7 +363,7 @@
* various request types above. The remaining 24-bits are currently
* set to zero and are reserved for future use and compatibility concerns.
*
- * User-space should always use DM_ULOG_REQUEST_TYPE to aquire the
+ * User-space should always use DM_ULOG_REQUEST_TYPE to acquire the
* request type from the 'request_type' field to maintain forward compatibility.
*/
#define DM_ULOG_REQUEST_MASK 0xFF
diff --git a/include/linux/dmar.h b/include/linux/dmar.h
index 5de4c9e..d7cecc9 100644
--- a/include/linux/dmar.h
+++ b/include/linux/dmar.h
@@ -126,7 +126,9 @@ extern int free_irte(int irq);
extern int irq_remapped(int irq);
extern struct intel_iommu *map_dev_to_ir(struct pci_dev *dev);
extern struct intel_iommu *map_ioapic_to_ir(int apic);
+extern struct intel_iommu *map_hpet_to_ir(u8 id);
extern int set_ioapic_sid(struct irte *irte, int apic);
+extern int set_hpet_sid(struct irte *irte, u8 id);
extern int set_msi_sid(struct irte *irte, struct pci_dev *dev);
#else
static inline int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
@@ -158,10 +160,18 @@ static inline struct intel_iommu *map_ioapic_to_ir(int apic)
{
return NULL;
}
+static inline struct intel_iommu *map_hpet_to_ir(unsigned int hpet_id)
+{
+ return NULL;
+}
static inline int set_ioapic_sid(struct irte *irte, int apic)
{
return 0;
}
+static inline int set_hpet_sid(struct irte *irte, u8 id)
+{
+ return -1;
+}
static inline int set_msi_sid(struct irte *irte, struct pci_dev *dev)
{
return 0;
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 10f6284..8709365 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -312,6 +312,7 @@ struct hid_item {
#define HID_QUIRK_MULTI_INPUT 0x00000040
#define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000
#define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000
+#define HID_QUIRK_NO_INIT_REPORTS 0x20000000
/*
* This is the global environment of the parser. This information is
diff --git a/include/linux/hpet.h b/include/linux/hpet.h
index 79f63a2..219ca4f 100644
--- a/include/linux/hpet.h
+++ b/include/linux/hpet.h
@@ -126,4 +126,6 @@ struct hpet_info {
#define HPET_DPI _IO('h', 0x05) /* disable periodic */
#define HPET_IRQFREQ _IOW('h', 0x6, unsigned long) /* IRQFREQ usec */
+#define MAX_HPET_TBS 8 /* maximum hpet timer blocks */
+
#endif /* !__HPET__ */
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
index ff037f0..9bace4b 100644
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -446,7 +446,7 @@ extern void timer_stats_update_stats(void *timer, pid_t pid, void *startf,
static inline void timer_stats_account_hrtimer(struct hrtimer *timer)
{
- if (likely(!timer->start_site))
+ if (likely(!timer_stats_active))
return;
timer_stats_update_stats(timer, timer->start_pid, timer->start_site,
timer->function, timer->start_comm, 0);
@@ -457,8 +457,6 @@ extern void __timer_stats_hrtimer_set_start_info(struct hrtimer *timer,
static inline void timer_stats_hrtimer_set_start_info(struct hrtimer *timer)
{
- if (likely(!timer_stats_active))
- return;
__timer_stats_hrtimer_set_start_info(timer, __builtin_return_address(0));
}
diff --git a/include/linux/hw_random.h b/include/linux/hw_random.h
index 7244456..9bede76 100644
--- a/include/linux/hw_random.h
+++ b/include/linux/hw_random.h
@@ -22,10 +22,12 @@
* @cleanup: Cleanup callback (can be NULL).
* @data_present: Callback to determine if data is available
* on the RNG. If NULL, it is assumed that
- * there is always data available.
+ * there is always data available. *OBSOLETE*
* @data_read: Read data from the RNG device.
* Returns the number of lower random bytes in "data".
- * Must not be NULL.
+ * Must not be NULL. *OSOLETE*
+ * @read: New API. drivers can fill up to max bytes of data
+ * into the buffer. The buffer is aligned for any type.
* @priv: Private data, for use by the RNG driver.
*/
struct hwrng {
@@ -34,6 +36,7 @@ struct hwrng {
void (*cleanup)(struct hwrng *rng);
int (*data_present)(struct hwrng *rng, int wait);
int (*data_read)(struct hwrng *rng, u32 *data);
+ int (*read)(struct hwrng *rng, void *data, size_t max, bool wait);
unsigned long priv;
/* internal. */
diff --git a/include/linux/ide.h b/include/linux/ide.h
index e4135d6..0ec6129 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -125,8 +125,8 @@ struct ide_io_ports {
* Timeouts for various operations:
*/
enum {
- /* spec allows up to 20ms */
- WAIT_DRQ = HZ / 10, /* 100ms */
+ /* spec allows up to 20ms, but CF cards and SSD drives need more */
+ WAIT_DRQ = 1 * HZ, /* 1s */
/* some laptops are very slow */
WAIT_READY = 5 * HZ, /* 5s */
/* should be less than 3ms (?), if all ATAPI CD is closed at boot */
diff --git a/include/linux/in6.h b/include/linux/in6.h
index dfa2916..bd55c6e 100644
--- a/include/linux/in6.h
+++ b/include/linux/in6.h
@@ -110,7 +110,7 @@ struct in6_flowlabel_req {
#define IPV6_FLOWINFO_FLOWLABEL 0x000fffff
#define IPV6_FLOWINFO_PRIORITY 0x0ff00000
-/* These defintions are obsolete */
+/* These definitions are obsolete */
#define IPV6_PRIORITY_UNCHARACTERIZED 0x0000
#define IPV6_PRIORITY_FILLER 0x0100
#define IPV6_PRIORITY_UNATTENDED 0x0200
diff --git a/arch/sh/include/asm/sh_keysc.h b/include/linux/input/sh_keysc.h
index 4a65b1e..c211b5c 100644
--- a/arch/sh/include/asm/sh_keysc.h
+++ b/include/linux/input/sh_keysc.h
@@ -1,5 +1,5 @@
-#ifndef __ASM_KEYSC_H__
-#define __ASM_KEYSC_H__
+#ifndef __SH_KEYSC_H__
+#define __SH_KEYSC_H__
#define SH_KEYSC_MAXKEYS 30
@@ -11,4 +11,4 @@ struct sh_keysc_info {
int keycodes[SH_KEYSC_MAXKEYS];
};
-#endif /* __ASM_KEYSC_H__ */
+#endif /* __SH_KEYSC_H__ */
diff --git a/include/linux/irq.h b/include/linux/irq.h
index ae9653d..a287cfc 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -282,7 +282,7 @@ extern irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action);
/*
* Built-in IRQ handlers for various IRQ types,
- * callable via desc->chip->handle_irq()
+ * callable via desc->handle_irq()
*/
extern void handle_level_irq(unsigned int irq, struct irq_desc *desc);
extern void handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc);
diff --git a/include/linux/libata.h b/include/linux/libata.h
index a5b3dc7..6a9c4dd 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -1024,7 +1024,7 @@ extern int ata_std_bios_param(struct scsi_device *sdev,
extern int ata_scsi_slave_config(struct scsi_device *sdev);
extern void ata_scsi_slave_destroy(struct scsi_device *sdev);
extern int ata_scsi_change_queue_depth(struct scsi_device *sdev,
- int queue_depth);
+ int queue_depth, int reason);
extern struct ata_device *ata_dev_pair(struct ata_device *adev);
extern int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev);
diff --git a/include/linux/mfd/ezx-pcap.h b/include/linux/mfd/ezx-pcap.h
index e5124ce..3402042 100644
--- a/include/linux/mfd/ezx-pcap.h
+++ b/include/linux/mfd/ezx-pcap.h
@@ -45,7 +45,7 @@ void pcap_set_ts_bits(struct pcap_chip *, u32);
#define PCAP_CLEAR_INTERRUPT_REGISTER 0x01ffffff
#define PCAP_MASK_ALL_INTERRUPT 0x01ffffff
-/* registers acessible by both pcap ports */
+/* registers accessible by both pcap ports */
#define PCAP_REG_ISR 0x0 /* Interrupt Status */
#define PCAP_REG_MSR 0x1 /* Interrupt Mask */
#define PCAP_REG_PSTAT 0x2 /* Processor Status */
@@ -67,7 +67,7 @@ void pcap_set_ts_bits(struct pcap_chip *, u32);
#define PCAP_REG_VENDOR_TEST1 0x1e
#define PCAP_REG_VENDOR_TEST2 0x1f
-/* registers acessible by pcap port 1 only (a1200, e2 & e6) */
+/* registers accessible by pcap port 1 only (a1200, e2 & e6) */
#define PCAP_REG_INT_SEL 0x3 /* Interrupt Select */
#define PCAP_REG_SWCTRL 0x4 /* Switching Regulator Control */
#define PCAP_REG_VREG1 0x5 /* Regulator Bank 1 Control */
diff --git a/include/linux/mfd/sh_mobile_sdhi.h b/include/linux/mfd/sh_mobile_sdhi.h
new file mode 100644
index 0000000..3bcd716
--- /dev/null
+++ b/include/linux/mfd/sh_mobile_sdhi.h
@@ -0,0 +1,8 @@
+#ifndef __SH_MOBILE_SDHI_H__
+#define __SH_MOBILE_SDHI_H__
+
+struct sh_mobile_sdhi_info {
+ void (*set_pwr)(struct platform_device *pdev, int state);
+};
+
+#endif /* __SH_MOBILE_SDHI_H__ */
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index cabf074..eae1f86 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -1587,6 +1587,8 @@
#define PCI_VENDOR_ID_COMPEX 0x11f6
#define PCI_DEVICE_ID_COMPEX_ENET100VG4 0x0112
+#define PCI_VENDOR_ID_PMC_Sierra 0x11f8
+
#define PCI_VENDOR_ID_RP 0x11fe
#define PCI_DEVICE_ID_RP32INTF 0x0001
#define PCI_DEVICE_ID_RP8INTF 0x0002
diff --git a/include/linux/pktcdvd.h b/include/linux/pktcdvd.h
index d745f5b..76e5053 100644
--- a/include/linux/pktcdvd.h
+++ b/include/linux/pktcdvd.h
@@ -30,7 +30,7 @@
/*
* use drive write caching -- we need deferred error handling to be
- * able to sucessfully recover with this option (drive will return good
+ * able to successfully recover with this option (drive will return good
* status as soon as the cdb is validated).
*/
#if defined(CONFIG_CDROM_PKTCDVD_WCACHE)
diff --git a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h
index dd31e7b..a05b4a2 100644
--- a/include/linux/reiserfs_fs.h
+++ b/include/linux/reiserfs_fs.h
@@ -52,11 +52,63 @@
#define REISERFS_IOC32_GETVERSION FS_IOC32_GETVERSION
#define REISERFS_IOC32_SETVERSION FS_IOC32_SETVERSION
-/* Locking primitives */
-/* Right now we are still falling back to (un)lock_kernel, but eventually that
- would evolve into real per-fs locks */
-#define reiserfs_write_lock( sb ) lock_kernel()
-#define reiserfs_write_unlock( sb ) unlock_kernel()
+/*
+ * Locking primitives. The write lock is a per superblock
+ * special mutex that has properties close to the Big Kernel Lock
+ * which was used in the previous locking scheme.
+ */
+void reiserfs_write_lock(struct super_block *s);
+void reiserfs_write_unlock(struct super_block *s);
+int reiserfs_write_lock_once(struct super_block *s);
+void reiserfs_write_unlock_once(struct super_block *s, int lock_depth);
+
+/*
+ * Several mutexes depend on the write lock.
+ * However sometimes we want to relax the write lock while we hold
+ * these mutexes, according to the release/reacquire on schedule()
+ * properties of the Bkl that were used.
+ * Reiserfs performances and locking were based on this scheme.
+ * Now that the write lock is a mutex and not the bkl anymore, doing so
+ * may result in a deadlock:
+ *
+ * A acquire write_lock
+ * A acquire j_commit_mutex
+ * A release write_lock and wait for something
+ * B acquire write_lock
+ * B can't acquire j_commit_mutex and sleep
+ * A can't acquire write lock anymore
+ * deadlock
+ *
+ * What we do here is avoiding such deadlock by playing the same game
+ * than the Bkl: if we can't acquire a mutex that depends on the write lock,
+ * we release the write lock, wait a bit and then retry.
+ *
+ * The mutexes concerned by this hack are:
+ * - The commit mutex of a journal list
+ * - The flush mutex
+ * - The journal lock
+ * - The inode mutex
+ */
+static inline void reiserfs_mutex_lock_safe(struct mutex *m,
+ struct super_block *s)
+{
+ reiserfs_write_unlock(s);
+ mutex_lock(m);
+ reiserfs_write_lock(s);
+}
+
+/*
+ * When we schedule, we usually want to also release the write lock,
+ * according to the previous bkl based locking scheme of reiserfs.
+ */
+static inline void reiserfs_cond_resched(struct super_block *s)
+{
+ if (need_resched()) {
+ reiserfs_write_unlock(s);
+ schedule();
+ reiserfs_write_lock(s);
+ }
+}
struct fid;
@@ -1329,7 +1381,11 @@ static inline loff_t max_reiserfs_offset(struct inode *inode)
#define get_generation(s) atomic_read (&fs_generation(s))
#define FILESYSTEM_CHANGED_TB(tb) (get_generation((tb)->tb_sb) != (tb)->fs_gen)
#define __fs_changed(gen,s) (gen != get_generation (s))
-#define fs_changed(gen,s) ({cond_resched(); __fs_changed(gen, s);})
+#define fs_changed(gen,s) \
+({ \
+ reiserfs_cond_resched(s); \
+ __fs_changed(gen, s); \
+})
/***************************************************************************/
/* FIXATE NODES */
@@ -2258,8 +2314,7 @@ __u32 r5_hash(const signed char *msg, int len);
#define SPARE_SPACE 500
/* prototypes from ioctl.c */
-int reiserfs_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+long reiserfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
long reiserfs_compat_ioctl(struct file *filp,
unsigned int cmd, unsigned long arg);
int reiserfs_unpack(struct inode *inode, struct file *filp);
diff --git a/include/linux/reiserfs_fs_sb.h b/include/linux/reiserfs_fs_sb.h
index dab68bb..52c83b6 100644
--- a/include/linux/reiserfs_fs_sb.h
+++ b/include/linux/reiserfs_fs_sb.h
@@ -7,6 +7,8 @@
#ifdef __KERNEL__
#include <linux/workqueue.h>
#include <linux/rwsem.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
#endif
typedef enum {
@@ -355,6 +357,13 @@ struct reiserfs_sb_info {
struct reiserfs_journal *s_journal; /* pointer to journal information */
unsigned short s_mount_state; /* reiserfs state (valid, invalid) */
+ /* Serialize writers access, replace the old bkl */
+ struct mutex lock;
+ /* Owner of the lock (can be recursive) */
+ struct task_struct *lock_owner;
+ /* Depth of the lock, start from -1 like the bkl */
+ int lock_depth;
+
/* Comment? -Hans */
void (*end_io_handler) (struct buffer_head *, int);
hashf_t s_hash_function; /* pointer to function which is used
@@ -408,6 +417,17 @@ struct reiserfs_sb_info {
char *s_qf_names[MAXQUOTAS];
int s_jquota_fmt;
#endif
+#ifdef CONFIG_REISERFS_CHECK
+
+ struct tree_balance *cur_tb; /*
+ * Detects whether more than one
+ * copy of tb exists per superblock
+ * as a means of checking whether
+ * do_balance is executing concurrently
+ * against another tree reader/writer
+ * on a same mount point.
+ */
+#endif
};
/* Definitions of reiserfs on-disk properties: */
diff --git a/include/linux/screen_info.h b/include/linux/screen_info.h
index 1ee2c05..899fbb4 100644
--- a/include/linux/screen_info.h
+++ b/include/linux/screen_info.h
@@ -14,7 +14,8 @@ struct screen_info {
__u16 orig_video_page; /* 0x04 */
__u8 orig_video_mode; /* 0x06 */
__u8 orig_video_cols; /* 0x07 */
- __u16 unused2; /* 0x08 */
+ __u8 flags; /* 0x08 */
+ __u8 unused2; /* 0x09 */
__u16 orig_video_ega_bx;/* 0x0a */
__u16 unused3; /* 0x0c */
__u8 orig_video_lines; /* 0x0e */
@@ -65,6 +66,8 @@ struct screen_info {
#define VIDEO_TYPE_EFI 0x70 /* EFI graphic mode */
+#define VIDEO_FLAGS_NOCURSOR (1 << 0) /* The video mode has no cursor set */
+
#ifdef __KERNEL__
extern struct screen_info screen_info;
diff --git a/include/linux/serial_reg.h b/include/linux/serial_reg.h
index 850db2e..cf9327c 100644
--- a/include/linux/serial_reg.h
+++ b/include/linux/serial_reg.h
@@ -216,10 +216,10 @@
#define UART_IIR_TOD 0x08 /* Character Timeout Indication Detected */
-#define UART_FCR_PXAR1 0x00 /* receive FIFO treshold = 1 */
-#define UART_FCR_PXAR8 0x40 /* receive FIFO treshold = 8 */
-#define UART_FCR_PXAR16 0x80 /* receive FIFO treshold = 16 */
-#define UART_FCR_PXAR32 0xc0 /* receive FIFO treshold = 32 */
+#define UART_FCR_PXAR1 0x00 /* receive FIFO threshold = 1 */
+#define UART_FCR_PXAR8 0x40 /* receive FIFO threshold = 8 */
+#define UART_FCR_PXAR16 0x80 /* receive FIFO threshold = 16 */
+#define UART_FCR_PXAR32 0xc0 /* receive FIFO threshold = 32 */
diff --git a/include/linux/sh_intc.h b/include/linux/sh_intc.h
index 68e212f..4ef246f 100644
--- a/include/linux/sh_intc.h
+++ b/include/linux/sh_intc.h
@@ -57,10 +57,8 @@ struct intc_desc {
struct intc_sense_reg *sense_regs;
unsigned int nr_sense_regs;
char *name;
-#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A)
struct intc_mask_reg *ack_regs;
unsigned int nr_ack_regs;
-#endif
};
#define _INTC_ARRAY(a) a, sizeof(a)/sizeof(*a)
@@ -73,7 +71,6 @@ struct intc_desc symbol __initdata = { \
chipname, \
}
-#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A)
#define DECLARE_INTC_DESC_ACK(symbol, chipname, vectors, groups, \
mask_regs, prio_regs, sense_regs, ack_regs) \
struct intc_desc symbol __initdata = { \
@@ -83,9 +80,11 @@ struct intc_desc symbol __initdata = { \
chipname, \
_INTC_ARRAY(ack_regs), \
}
-#endif
void __init register_intc_controller(struct intc_desc *desc);
int intc_set_priority(unsigned int irq, unsigned int prio);
+int reserve_irq_vector(unsigned int irq);
+void reserve_irq_legacy(void);
+
#endif /* __SH_INTC_H */
diff --git a/include/linux/sh_pfc.h b/include/linux/sh_pfc.h
new file mode 100644
index 0000000..07c08af
--- /dev/null
+++ b/include/linux/sh_pfc.h
@@ -0,0 +1,96 @@
+/*
+ * SuperH Pin Function Controller Support
+ *
+ * Copyright (c) 2008 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.
+ */
+
+#ifndef __SH_PFC_H
+#define __SH_PFC_H
+
+#include <asm-generic/gpio.h>
+
+typedef unsigned short pinmux_enum_t;
+typedef unsigned short pinmux_flag_t;
+
+#define PINMUX_TYPE_NONE 0
+#define PINMUX_TYPE_FUNCTION 1
+#define PINMUX_TYPE_GPIO 2
+#define PINMUX_TYPE_OUTPUT 3
+#define PINMUX_TYPE_INPUT 4
+#define PINMUX_TYPE_INPUT_PULLUP 5
+#define PINMUX_TYPE_INPUT_PULLDOWN 6
+
+#define PINMUX_FLAG_TYPE (0x7)
+#define PINMUX_FLAG_WANT_PULLUP (1 << 3)
+#define PINMUX_FLAG_WANT_PULLDOWN (1 << 4)
+
+#define PINMUX_FLAG_DBIT_SHIFT 5
+#define PINMUX_FLAG_DBIT (0x1f << PINMUX_FLAG_DBIT_SHIFT)
+#define PINMUX_FLAG_DREG_SHIFT 10
+#define PINMUX_FLAG_DREG (0x3f << PINMUX_FLAG_DREG_SHIFT)
+
+struct pinmux_gpio {
+ pinmux_enum_t enum_id;
+ pinmux_flag_t flags;
+};
+
+#define PINMUX_GPIO(gpio, data_or_mark) [gpio] = { data_or_mark }
+#define PINMUX_DATA(data_or_mark, ids...) data_or_mark, ids, 0
+
+struct pinmux_cfg_reg {
+ unsigned long reg, reg_width, field_width;
+ unsigned long *cnt;
+ pinmux_enum_t *enum_ids;
+};
+
+#define PINMUX_CFG_REG(name, r, r_width, f_width) \
+ .reg = r, .reg_width = r_width, .field_width = f_width, \
+ .cnt = (unsigned long [r_width / f_width]) {}, \
+ .enum_ids = (pinmux_enum_t [(r_width / f_width) * (1 << f_width)]) \
+
+struct pinmux_data_reg {
+ unsigned long reg, reg_width, reg_shadow;
+ pinmux_enum_t *enum_ids;
+};
+
+#define PINMUX_DATA_REG(name, r, r_width) \
+ .reg = r, .reg_width = r_width, \
+ .enum_ids = (pinmux_enum_t [r_width]) \
+
+struct pinmux_range {
+ pinmux_enum_t begin;
+ pinmux_enum_t end;
+ pinmux_enum_t force;
+};
+
+struct pinmux_info {
+ char *name;
+ pinmux_enum_t reserved_id;
+ struct pinmux_range data;
+ struct pinmux_range input;
+ struct pinmux_range input_pd;
+ struct pinmux_range input_pu;
+ struct pinmux_range output;
+ struct pinmux_range mark;
+ struct pinmux_range function;
+
+ unsigned first_gpio, last_gpio;
+
+ struct pinmux_gpio *gpios;
+ struct pinmux_cfg_reg *cfg_regs;
+ struct pinmux_data_reg *data_regs;
+
+ pinmux_enum_t *gpio_data;
+ unsigned int gpio_data_size;
+
+ unsigned long *gpio_in_use;
+ struct gpio_chip chip;
+};
+
+int register_pinmux(struct pinmux_info *pip);
+
+#endif /* __SH_PFC_H */
diff --git a/include/linux/spi/spi_bitbang.h b/include/linux/spi/spi_bitbang.h
index eed4254..3274c50 100644
--- a/include/linux/spi/spi_bitbang.h
+++ b/include/linux/spi/spi_bitbang.h
@@ -15,7 +15,7 @@
* Some hardware works well with requests at spi_transfer scope:
*
* - Drivers leveraging smarter hardware, with fifos or DMA; or for half
- * duplex (MicroWire) controllers. Provide chipslect() and txrx_bufs(),
+ * duplex (MicroWire) controllers. Provide chipselect() and txrx_bufs(),
* and custom setup()/cleanup() methods.
*/
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 56af3ca..877ba03 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -89,8 +89,8 @@ enum
KERN_VERSION=4, /* string: compile time info */
KERN_SECUREMASK=5, /* struct: maximum rights mask */
KERN_PROF=6, /* table: profiling information */
- KERN_NODENAME=7,
- KERN_DOMAINNAME=8,
+ KERN_NODENAME=7, /* string: hostname */
+ KERN_DOMAINNAME=8, /* string: domainname */
KERN_PANIC=15, /* int: panic timeout */
KERN_REALROOTDEV=16, /* real root device to mount after initrd */
@@ -102,8 +102,8 @@ enum
KERN_PPC_HTABRECLAIM=25, /* turn htab reclaimation on/off on PPC */
KERN_PPC_ZEROPAGED=26, /* turn idle page zeroing on/off on PPC */
KERN_PPC_POWERSAVE_NAP=27, /* use nap mode for power saving */
- KERN_MODPROBE=28,
- KERN_SG_BIG_BUFF=29,
+ KERN_MODPROBE=28, /* string: modprobe path */
+ KERN_SG_BIG_BUFF=29, /* int: sg driver reserved buffer size */
KERN_ACCT=30, /* BSD process accounting parameters */
KERN_PPC_L2CR=31, /* l2cr register on PPC */
@@ -150,7 +150,7 @@ enum
KERN_ACPI_VIDEO_FLAGS=71, /* int: flags for setting up video after ACPI sleep */
KERN_IA64_UNALIGNED=72, /* int: ia64 unaligned userland trap enable */
KERN_COMPAT_LOG=73, /* int: print compat layer messages */
- KERN_MAX_LOCK_DEPTH=74,
+ KERN_MAX_LOCK_DEPTH=74, /* int: rtmutex's maximum lock depth */
KERN_NMI_WATCHDOG=75, /* int: enable/disable nmi watchdog */
KERN_PANIC_ON_NMI=76, /* int: whether we will panic on an unrecovered */
};
diff --git a/include/linux/tick.h b/include/linux/tick.h
index 0482229..d2ae79e 100644
--- a/include/linux/tick.h
+++ b/include/linux/tick.h
@@ -43,6 +43,7 @@ enum tick_nohz_mode {
* @idle_exittime: Time when the idle state was left
* @idle_sleeptime: Sum of the time slept in idle with sched tick stopped
* @sleep_length: Duration of the current idle sleep
+ * @do_timer_lst: CPU was the last one doing do_timer before going idle
*/
struct tick_sched {
struct hrtimer sched_timer;
@@ -64,6 +65,7 @@ struct tick_sched {
unsigned long last_jiffies;
unsigned long next_jiffies;
ktime_t idle_expires;
+ int do_timer_last;
};
extern void __init tick_init(void);
@@ -98,6 +100,9 @@ extern int tick_check_oneshot_change(int allow_nohz);
extern struct tick_sched *tick_get_tick_sched(int cpu);
extern void tick_check_idle(int cpu);
extern int tick_oneshot_mode_active(void);
+# ifndef arch_needs_cpu
+# define arch_needs_cpu(cpu) (0)
+# endif
# else
static inline void tick_clock_notify(void) { }
static inline int tick_check_oneshot_change(int allow_nohz) { return 0; }
diff --git a/include/linux/time.h b/include/linux/time.h
index fe04e5e..6e026e4 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -148,6 +148,7 @@ extern void monotonic_to_bootbased(struct timespec *ts);
extern struct timespec timespec_trunc(struct timespec t, unsigned gran);
extern int timekeeping_valid_for_hres(void);
+extern u64 timekeeping_max_deferment(void);
extern void update_wall_time(void);
extern void update_xtime_cache(u64 nsec);
extern void timekeeping_leap_insert(int leapsecond);
diff --git a/include/linux/timex.h b/include/linux/timex.h
index e6967d1..94f8fae 100644
--- a/include/linux/timex.h
+++ b/include/linux/timex.h
@@ -115,13 +115,16 @@ struct timex {
#define ADJ_OFFSET_SS_READ 0xa001 /* read-only adjtime */
#endif
-/* xntp 3.4 compatibility names */
+/* NTP userland likes the MOD_ prefix better */
#define MOD_OFFSET ADJ_OFFSET
#define MOD_FREQUENCY ADJ_FREQUENCY
#define MOD_MAXERROR ADJ_MAXERROR
#define MOD_ESTERROR ADJ_ESTERROR
#define MOD_STATUS ADJ_STATUS
#define MOD_TIMECONST ADJ_TIMECONST
+#define MOD_TAI ADJ_TAI
+#define MOD_MICRO ADJ_MICRO
+#define MOD_NANO ADJ_NANO
/*
@@ -261,11 +264,7 @@ static inline int ntp_synced(void)
#define NTP_SCALE_SHIFT 32
-#ifdef CONFIG_NO_HZ
-#define NTP_INTERVAL_FREQ (2)
-#else
#define NTP_INTERVAL_FREQ (HZ)
-#endif
#define NTP_INTERVAL_LENGTH (NSEC_PER_SEC/NTP_INTERVAL_FREQ)
/* Returns how long ticks are at present, in ns / 2^NTP_SCALE_SHIFT. */
diff --git a/include/linux/usb/wusb.h b/include/linux/usb/wusb.h
index 429c631..63ebdcc 100644
--- a/include/linux/usb/wusb.h
+++ b/include/linux/usb/wusb.h
@@ -74,7 +74,7 @@ enum {
* WUSB defines that CHIDs, CDIDs and CKs are a 16 byte string of
* data. In order to avoid confusion and enforce types, we wrap it.
*
- * Make it packed, as we use it in some hw defintions.
+ * Make it packed, as we use it in some hw definitions.
*/
struct wusb_ckhdid {
u8 data[16];
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index b59e78c..dfd4745 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -490,7 +490,7 @@ struct v4l2_jpegcompression {
* you do, leave them untouched.
* Inluding less markers will make the
* resulting code smaller, but there will
- * be fewer aplications which can read it.
+ * be fewer applications which can read it.
* The presence of the APP and COM marker
* is influenced by APP_len and COM_len
* ONLY, not by this property! */
diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h
index c0c4e11..7f56db4 100644
--- a/include/linux/vt_kern.h
+++ b/include/linux/vt_kern.h
@@ -110,6 +110,7 @@ extern char con_buf[CON_BUF_SIZE];
extern struct mutex con_buf_mtx;
extern char vt_dont_switch;
extern int default_utf8;
+extern int global_cursor_default;
struct vt_spawn_console {
spinlock_t lock;
@@ -130,4 +131,6 @@ struct vt_notifier_param {
extern int register_vt_notifier(struct notifier_block *nb);
extern int unregister_vt_notifier(struct notifier_block *nb);
+extern void hide_boot_cursor(bool hide);
+
#endif /* _VT_KERN_H */
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index 7571e32..ff30177 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -989,7 +989,7 @@ struct sctp_transport {
int init_sent_count;
/* state : The current state of this destination,
- * : i.e. SCTP_ACTIVE, SCTP_INACTIVE, SCTP_UNKOWN.
+ * : i.e. SCTP_ACTIVE, SCTP_INACTIVE, SCTP_UNKNOWN.
*/
int state;
diff --git a/include/net/tcp.h b/include/net/tcp.h
index e2d2ca2..5740b85 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -1262,7 +1262,7 @@ static inline struct sk_buff *tcp_write_queue_prev(struct sock *sk, struct sk_bu
skb_queue_walk_from_safe(&(sk)->sk_write_queue, skb, tmp)
/* This function calculates a "timeout" which is equivalent to the timeout of a
- * TCP connection after "boundary" unsucessful, exponentially backed-off
+ * TCP connection after "boundary" unsuccessful, exponentially backed-off
* retransmissions with an initial RTO of TCP_RTO_MIN.
*/
static inline bool retransmits_timed_out(const struct sock *sk,
diff --git a/include/net/wimax.h b/include/net/wimax.h
index d69c4a7..3461aa1 100644
--- a/include/net/wimax.h
+++ b/include/net/wimax.h
@@ -79,7 +79,7 @@
* drivers have to only report state changes due to external
* conditions.
*
- * All API operations are 'atomic', serialized thorough a mutex in the
+ * All API operations are 'atomic', serialized through a mutex in the
* `struct wimax_dev`.
*
* EXPORTING TO USER SPACE THROUGH GENERIC NETLINK
diff --git a/include/scsi/Kbuild b/include/scsi/Kbuild
index 33b2750..b3a0ee6 100644
--- a/include/scsi/Kbuild
+++ b/include/scsi/Kbuild
@@ -2,3 +2,4 @@ header-y += scsi.h
header-y += scsi_netlink.h
header-y += scsi_netlink_fc.h
header-y += scsi_bsg_fc.h
+header-y += fc/
diff --git a/include/scsi/fc/Kbuild b/include/scsi/fc/Kbuild
new file mode 100644
index 0000000..5660381
--- /dev/null
+++ b/include/scsi/fc/Kbuild
@@ -0,0 +1,4 @@
+header-y += fc_els.h
+header-y += fc_fs.h
+header-y += fc_gs.h
+header-y += fc_ns.h
diff --git a/include/scsi/fc/fc_els.h b/include/scsi/fc/fc_els.h
index 195ca01..f943281 100644
--- a/include/scsi/fc/fc_els.h
+++ b/include/scsi/fc/fc_els.h
@@ -20,6 +20,8 @@
#ifndef _FC_ELS_H_
#define _FC_ELS_H_
+#include <linux/types.h>
+
/*
* Fibre Channel Switch - Enhanced Link Services definitions.
* From T11 FC-LS Rev 1.2 June 7, 2005.
@@ -248,10 +250,12 @@ struct fc_els_csp {
/*
* sp_features
*/
-#define FC_SP_FT_CIRO 0x8000 /* continuously increasing rel. off. */
+#define FC_SP_FT_NPIV 0x8000 /* multiple N_Port_ID support (FLOGI) */
+#define FC_SP_FT_CIRO 0x8000 /* continuously increasing rel off (PLOGI) */
#define FC_SP_FT_CLAD 0x8000 /* clean address (in FLOGI LS_ACC) */
#define FC_SP_FT_RAND 0x4000 /* random relative offset */
#define FC_SP_FT_VAL 0x2000 /* valid vendor version level */
+#define FC_SP_FT_NPIV_ACC 0x2000 /* NPIV assignment (FLOGI LS_ACC) */
#define FC_SP_FT_FPORT 0x1000 /* F port (1) vs. N port (0) */
#define FC_SP_FT_ABB 0x0800 /* alternate BB_credit management */
#define FC_SP_FT_EDTR 0x0400 /* E_D_TOV Resolution is nanoseconds */
diff --git a/include/scsi/fc/fc_fcoe.h b/include/scsi/fc/fc_fcoe.h
index ccb3dbe..e6ad3d2 100644
--- a/include/scsi/fc/fc_fcoe.h
+++ b/include/scsi/fc/fc_fcoe.h
@@ -86,6 +86,18 @@ struct fcoe_crc_eof {
#define FCOE_MIN_FRAME 46
/*
+ * FCoE Link Error Status Block: T11 FC-BB-5 Rev2.0, Clause 7.10.
+ */
+struct fcoe_fc_els_lesb {
+ __be32 lesb_link_fail; /* link failure count */
+ __be32 lesb_vlink_fail; /* virtual link failure count */
+ __be32 lesb_miss_fka; /* missing FIP keep-alive count */
+ __be32 lesb_symb_err; /* symbol error during carrier count */
+ __be32 lesb_err_block; /* errored block count */
+ __be32 lesb_fcs_error; /* frame check sequence error count */
+};
+
+/*
* fc_fcoe_set_mac - Store OUI + DID into MAC address field.
* @mac: mac address to be set
* @did: fc dest id to use
diff --git a/include/scsi/fc/fc_fcp.h b/include/scsi/fc/fc_fcp.h
index 5d38f19..747e2c7 100644
--- a/include/scsi/fc/fc_fcp.h
+++ b/include/scsi/fc/fc_fcp.h
@@ -83,6 +83,8 @@ struct fcp_cmnd32 {
* fc_tm_flags - task management flags field.
*/
#define FCP_TMF_CLR_ACA 0x40 /* clear ACA condition */
+#define FCP_TMF_TGT_RESET 0x20 /* target reset task management,
+ deprecated as of FCP-3 */
#define FCP_TMF_LUN_RESET 0x10 /* logical unit reset task management */
#define FCP_TMF_CLR_TASK_SET 0x04 /* clear task set */
#define FCP_TMF_ABT_TASK_SET 0x02 /* abort task set */
@@ -196,4 +198,10 @@ struct fcp_srr {
__u8 srr_resvd2[3]; /* reserved */
};
+/*
+ * Feature bits in name server FC-4 Features object.
+ */
+#define FCP_FEAT_TARG (1 << 0) /* target function supported */
+#define FCP_FEAT_INIT (1 << 1) /* initiator function supported */
+
#endif /* _FC_FCP_H_ */
diff --git a/include/scsi/fc/fc_fip.h b/include/scsi/fc/fc_fip.h
index 3d138c1..17baa19 100644
--- a/include/scsi/fc/fc_fip.h
+++ b/include/scsi/fc/fc_fip.h
@@ -214,11 +214,21 @@ struct fip_vn_desc {
*/
struct fip_fka_desc {
struct fip_desc fd_desc;
- __u8 fd_resvd[2];
+ __u8 fd_resvd;
+ __u8 fd_flags; /* bit0 is fka disable flag */
__be32 fd_fka_period; /* adv./keep-alive period in mS */
} __attribute__((packed));
/*
+ * flags for fip_fka_desc.fd_flags
+ */
+enum fip_fka_flags {
+ FIP_FKA_ADV_D = 0x01, /* no need for FKA from ENode */
+};
+
+/* FIP_DT_FKA flags */
+
+/*
* FIP_DT_VENDOR descriptor.
*/
struct fip_vendor_desc {
diff --git a/include/scsi/fc/fc_fs.h b/include/scsi/fc/fc_fs.h
index ac4cd38..50f28b1 100644
--- a/include/scsi/fc/fc_fs.h
+++ b/include/scsi/fc/fc_fs.h
@@ -20,6 +20,8 @@
#ifndef _FC_FS_H_
#define _FC_FS_H_
+#include <linux/types.h>
+
/*
* Fibre Channel Framing and Signalling definitions.
* From T11 FC-FS-2 Rev 0.90 - 9 August 2005.
diff --git a/include/scsi/fc/fc_gs.h b/include/scsi/fc/fc_gs.h
index 324dd0e..a37346d 100644
--- a/include/scsi/fc/fc_gs.h
+++ b/include/scsi/fc/fc_gs.h
@@ -20,6 +20,8 @@
#ifndef _FC_GS_H_
#define _FC_GS_H_
+#include <linux/types.h>
+
/*
* Fibre Channel Services - Common Transport.
* From T11.org FC-GS-2 Rev 5.3 November 1998.
diff --git a/include/scsi/fc/fc_ns.h b/include/scsi/fc/fc_ns.h
index 790d7b9..e7d3ac4 100644
--- a/include/scsi/fc/fc_ns.h
+++ b/include/scsi/fc/fc_ns.h
@@ -20,6 +20,8 @@
#ifndef _FC_NS_H_
#define _FC_NS_H_
+#include <linux/types.h>
+
/*
* Fibre Channel Services - Name Service (dNS)
* From T11.org FC-GS-2 Rev 5.3 November 1998.
@@ -44,9 +46,12 @@ enum fc_ns_req {
FC_NS_GID_FT = 0x0171, /* get IDs by FC4 type */
FC_NS_GPN_FT = 0x0172, /* get port names by FC4 type */
FC_NS_GID_PT = 0x01a1, /* get IDs by port type */
- FC_NS_RFT_ID = 0x0217, /* reg FC4 type for ID */
FC_NS_RPN_ID = 0x0212, /* reg port name for ID */
FC_NS_RNN_ID = 0x0213, /* reg node name for ID */
+ FC_NS_RFT_ID = 0x0217, /* reg FC4 type for ID */
+ FC_NS_RSPN_ID = 0x0218, /* reg symbolic port name */
+ FC_NS_RFF_ID = 0x021f, /* reg FC4 Features for ID */
+ FC_NS_RSNN_NN = 0x0239, /* reg symbolic node name */
};
/*
@@ -156,4 +161,32 @@ struct fc_ns_rn_id {
__be64 fr_wwn; /* node name or port name */
} __attribute__((__packed__));
+/*
+ * RSNN_NN request - register symbolic node name
+ */
+struct fc_ns_rsnn {
+ __be64 fr_wwn; /* node name */
+ __u8 fr_name_len;
+ char fr_name[];
+} __attribute__((__packed__));
+
+/*
+ * RSPN_ID request - register symbolic port name
+ */
+struct fc_ns_rspn {
+ struct fc_ns_fid fr_fid; /* port ID object */
+ __u8 fr_name_len;
+ char fr_name[];
+} __attribute__((__packed__));
+
+/*
+ * RFF_ID request - register FC-4 Features for ID.
+ */
+struct fc_ns_rff_id {
+ struct fc_ns_fid fr_fid; /* port ID object */
+ __u8 fr_resvd[2];
+ __u8 fr_feat; /* FC-4 Feature bits */
+ __u8 fr_type; /* FC-4 type */
+} __attribute__((__packed__));
+
#endif /* _FC_NS_H_ */
diff --git a/include/scsi/fc_encode.h b/include/scsi/fc_encode.h
index 27dad70..8eb0a0f 100644
--- a/include/scsi/fc_encode.h
+++ b/include/scsi/fc_encode.h
@@ -32,7 +32,10 @@ struct fc_ct_req {
struct fc_ns_gid_ft gid;
struct fc_ns_rn_id rn;
struct fc_ns_rft rft;
+ struct fc_ns_rff_id rff;
struct fc_ns_fid fid;
+ struct fc_ns_rsnn snn;
+ struct fc_ns_rspn spn;
} payload;
};
@@ -109,6 +112,7 @@ static inline int fc_ct_fill(struct fc_lport *lport,
enum fc_fh_type *fh_type)
{
struct fc_ct_req *ct;
+ size_t len;
switch (op) {
case FC_NS_GPN_FT:
@@ -128,12 +132,41 @@ static inline int fc_ct_fill(struct fc_lport *lport,
ct->payload.rft.fts = lport->fcts;
break;
- case FC_NS_RPN_ID:
+ case FC_NS_RFF_ID:
+ ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rff_id));
+ hton24(ct->payload.rff.fr_fid.fp_fid,
+ fc_host_port_id(lport->host));
+ ct->payload.rff.fr_type = FC_TYPE_FCP;
+ if (lport->service_params & FCP_SPPF_INIT_FCN)
+ ct->payload.rff.fr_feat = FCP_FEAT_INIT;
+ if (lport->service_params & FCP_SPPF_TARG_FCN)
+ ct->payload.rff.fr_feat |= FCP_FEAT_TARG;
+ break;
+
+ case FC_NS_RNN_ID:
ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rn_id));
hton24(ct->payload.rn.fr_fid.fp_fid,
fc_host_port_id(lport->host));
- ct->payload.rft.fts = lport->fcts;
- put_unaligned_be64(lport->wwpn, &ct->payload.rn.fr_wwn);
+ put_unaligned_be64(lport->wwnn, &ct->payload.rn.fr_wwn);
+ break;
+
+ case FC_NS_RSPN_ID:
+ len = strnlen(fc_host_symbolic_name(lport->host), 255);
+ ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rspn) + len);
+ hton24(ct->payload.spn.fr_fid.fp_fid,
+ fc_host_port_id(lport->host));
+ strncpy(ct->payload.spn.fr_name,
+ fc_host_symbolic_name(lport->host), len);
+ ct->payload.spn.fr_name_len = len;
+ break;
+
+ case FC_NS_RSNN_NN:
+ len = strnlen(fc_host_symbolic_name(lport->host), 255);
+ ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rsnn) + len);
+ put_unaligned_be64(lport->wwnn, &ct->payload.snn.fr_wwn);
+ strncpy(ct->payload.snn.fr_name,
+ fc_host_symbolic_name(lport->host), len);
+ ct->payload.snn.fr_name_len = len;
break;
default:
@@ -198,6 +231,31 @@ static inline void fc_flogi_fill(struct fc_lport *lport, struct fc_frame *fp)
sp->sp_bb_data = htons((u16) lport->mfs);
cp = &flogi->fl_cssp[3 - 1]; /* class 3 parameters */
cp->cp_class = htons(FC_CPC_VALID | FC_CPC_SEQ);
+ if (lport->does_npiv)
+ sp->sp_features = htons(FC_SP_FT_NPIV);
+}
+
+/**
+ * fc_fdisc_fill - Fill in a fdisc request frame.
+ */
+static inline void fc_fdisc_fill(struct fc_lport *lport, struct fc_frame *fp)
+{
+ struct fc_els_csp *sp;
+ struct fc_els_cssp *cp;
+ struct fc_els_flogi *fdisc;
+
+ fdisc = fc_frame_payload_get(fp, sizeof(*fdisc));
+ memset(fdisc, 0, sizeof(*fdisc));
+ fdisc->fl_cmd = (u8) ELS_FDISC;
+ put_unaligned_be64(lport->wwpn, &fdisc->fl_wwpn);
+ put_unaligned_be64(lport->wwnn, &fdisc->fl_wwnn);
+ sp = &fdisc->fl_csp;
+ sp->sp_hi_ver = 0x20;
+ sp->sp_lo_ver = 0x20;
+ sp->sp_bb_cred = htons(10); /* this gets set by gateway */
+ sp->sp_bb_data = htons((u16) lport->mfs);
+ cp = &fdisc->fl_cssp[3 - 1]; /* class 3 parameters */
+ cp->cp_class = htons(FC_CPC_VALID | FC_CPC_SEQ);
}
/**
@@ -296,6 +354,10 @@ static inline int fc_els_fill(struct fc_lport *lport,
fc_flogi_fill(lport, fp);
break;
+ case ELS_FDISC:
+ fc_fdisc_fill(lport, fp);
+ break;
+
case ELS_LOGO:
fc_logo_fill(lport, fp);
break;
diff --git a/include/scsi/fc_frame.h b/include/scsi/fc_frame.h
index c35d238..4d3e9c7 100644
--- a/include/scsi/fc_frame.h
+++ b/include/scsi/fc_frame.h
@@ -28,6 +28,8 @@
#include <scsi/fc/fc_fcp.h>
#include <scsi/fc/fc_encaps.h>
+#include <linux/if_ether.h>
+
/*
* The fc_frame interface is used to pass frame data between functions.
* The frame includes the data buffer, length, and SOF / EOF delimiter types.
@@ -37,6 +39,9 @@
#define FC_FRAME_HEADROOM 32 /* headroom for VLAN + FCoE headers */
#define FC_FRAME_TAILROOM 8 /* trailer space for FCoE */
+/* Max number of skb frags allowed, reserving one for fcoe_crc_eof page */
+#define FC_FRAME_SG_LEN (MAX_SKB_FRAGS - 1)
+
#define fp_skb(fp) (&((fp)->skb))
#define fr_hdr(fp) ((fp)->skb.data)
#define fr_len(fp) ((fp)->skb.len)
@@ -64,6 +69,7 @@ struct fcoe_rcv_info {
enum fc_sof fr_sof; /* start of frame delimiter */
enum fc_eof fr_eof; /* end of frame delimiter */
u8 fr_flags; /* flags - see below */
+ u8 granted_mac[ETH_ALEN]; /* FCoE MAC address */
};
@@ -94,17 +100,7 @@ static inline void fc_frame_init(struct fc_frame *fp)
}
struct fc_frame *fc_frame_alloc_fill(struct fc_lport *, size_t payload_len);
-
-struct fc_frame *__fc_frame_alloc(size_t payload_len);
-
-/*
- * Get frame for sending via port.
- */
-static inline struct fc_frame *_fc_frame_alloc(struct fc_lport *dev,
- size_t payload_len)
-{
- return __fc_frame_alloc(payload_len);
-}
+struct fc_frame *_fc_frame_alloc(size_t payload_len);
/*
* Allocate fc_frame structure and buffer. Set the initial length to
@@ -118,10 +114,10 @@ static inline struct fc_frame *fc_frame_alloc(struct fc_lport *dev, size_t len)
* Note: Since len will often be a constant multiple of 4,
* this check will usually be evaluated and eliminated at compile time.
*/
- if ((len % 4) != 0)
+ if (len && len % 4)
fp = fc_frame_alloc_fill(dev, len);
else
- fp = _fc_frame_alloc(dev, len);
+ fp = _fc_frame_alloc(len);
return fp;
}
diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h
index d67dda2..66d377b 100644
--- a/include/scsi/iscsi_if.h
+++ b/include/scsi/iscsi_if.h
@@ -311,6 +311,8 @@ enum iscsi_param {
ISCSI_PARAM_IFACE_NAME,
ISCSI_PARAM_ISID,
ISCSI_PARAM_INITIATOR_NAME,
+
+ ISCSI_PARAM_TGT_RESET_TMO,
/* must always be last */
ISCSI_PARAM_MAX,
};
@@ -350,6 +352,7 @@ enum iscsi_param {
#define ISCSI_IFACE_NAME (1ULL << ISCSI_PARAM_IFACE_NAME)
#define ISCSI_ISID (1ULL << ISCSI_PARAM_ISID)
#define ISCSI_INITIATOR_NAME (1ULL << ISCSI_PARAM_INITIATOR_NAME)
+#define ISCSI_TGT_RESET_TMO (1ULL << ISCSI_PARAM_TGT_RESET_TMO)
/* iSCSI HBA params */
enum iscsi_host_param {
diff --git a/include/scsi/iscsi_proto.h b/include/scsi/iscsi_proto.h
index f2a2c11..dd0a52c 100644
--- a/include/scsi/iscsi_proto.h
+++ b/include/scsi/iscsi_proto.h
@@ -279,6 +279,8 @@ struct iscsi_tm {
#define ISCSI_TM_FUNC_TARGET_COLD_RESET 7
#define ISCSI_TM_FUNC_TASK_REASSIGN 8
+#define ISCSI_TM_FUNC_VALUE(hdr) ((hdr)->flags & ISCSI_FLAG_TM_FUNC_MASK)
+
/* SCSI Task Management Response Header */
struct iscsi_tm_rsp {
uint8_t opcode;
diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h
index 65dc9aa..4b912ee 100644
--- a/include/scsi/libfc.h
+++ b/include/scsi/libfc.h
@@ -26,6 +26,7 @@
#include <scsi/scsi_transport.h>
#include <scsi/scsi_transport_fc.h>
+#include <scsi/scsi_bsg_fc.h>
#include <scsi/fc/fc_fcp.h>
#include <scsi/fc/fc_ns.h>
@@ -34,67 +35,6 @@
#include <scsi/fc_frame.h>
-#define FC_LIBFC_LOGGING 0x01 /* General logging, not categorized */
-#define FC_LPORT_LOGGING 0x02 /* lport layer logging */
-#define FC_DISC_LOGGING 0x04 /* discovery layer logging */
-#define FC_RPORT_LOGGING 0x08 /* rport layer logging */
-#define FC_FCP_LOGGING 0x10 /* I/O path logging */
-#define FC_EM_LOGGING 0x20 /* Exchange Manager logging */
-#define FC_EXCH_LOGGING 0x40 /* Exchange/Sequence logging */
-#define FC_SCSI_LOGGING 0x80 /* SCSI logging (mostly error handling) */
-
-extern unsigned int fc_debug_logging;
-
-#define FC_CHECK_LOGGING(LEVEL, CMD) \
-do { \
- if (unlikely(fc_debug_logging & LEVEL)) \
- do { \
- CMD; \
- } while (0); \
-} while (0)
-
-#define FC_LIBFC_DBG(fmt, args...) \
- FC_CHECK_LOGGING(FC_LIBFC_LOGGING, \
- printk(KERN_INFO "libfc: " fmt, ##args))
-
-#define FC_LPORT_DBG(lport, fmt, args...) \
- FC_CHECK_LOGGING(FC_LPORT_LOGGING, \
- printk(KERN_INFO "host%u: lport %6x: " fmt, \
- (lport)->host->host_no, \
- fc_host_port_id((lport)->host), ##args))
-
-#define FC_DISC_DBG(disc, fmt, args...) \
- FC_CHECK_LOGGING(FC_DISC_LOGGING, \
- printk(KERN_INFO "host%u: disc: " fmt, \
- (disc)->lport->host->host_no, \
- ##args))
-
-#define FC_RPORT_ID_DBG(lport, port_id, fmt, args...) \
- FC_CHECK_LOGGING(FC_RPORT_LOGGING, \
- printk(KERN_INFO "host%u: rport %6x: " fmt, \
- (lport)->host->host_no, \
- (port_id), ##args))
-
-#define FC_RPORT_DBG(rdata, fmt, args...) \
- FC_RPORT_ID_DBG((rdata)->local_port, (rdata)->ids.port_id, fmt, ##args)
-
-#define FC_FCP_DBG(pkt, fmt, args...) \
- FC_CHECK_LOGGING(FC_FCP_LOGGING, \
- printk(KERN_INFO "host%u: fcp: %6x: " fmt, \
- (pkt)->lp->host->host_no, \
- pkt->rport->port_id, ##args))
-
-#define FC_EXCH_DBG(exch, fmt, args...) \
- FC_CHECK_LOGGING(FC_EXCH_LOGGING, \
- printk(KERN_INFO "host%u: xid %4x: " fmt, \
- (exch)->lp->host->host_no, \
- exch->xid, ##args))
-
-#define FC_SCSI_DBG(lport, fmt, args...) \
- FC_CHECK_LOGGING(FC_SCSI_LOGGING, \
- printk(KERN_INFO "host%u: scsi: " fmt, \
- (lport)->host->host_no, ##args))
-
/*
* libfc error codes
*/
@@ -115,15 +55,28 @@ do { \
p[2] = ((v) & 0xFF); \
} while (0)
-/*
- * FC HBA status
+/**
+ * enum fc_lport_state - Local port states
+ * @LPORT_ST_DISABLED: Disabled
+ * @LPORT_ST_FLOGI: Fabric login (FLOGI) sent
+ * @LPORT_ST_DNS: Waiting for name server remote port to become ready
+ * @LPORT_ST_RPN_ID: Register port name by ID (RPN_ID) sent
+ * @LPORT_ST_RFT_ID: Register Fibre Channel types by ID (RFT_ID) sent
+ * @LPORT_ST_RFF_ID: Register FC-4 Features by ID (RFF_ID) sent
+ * @LPORT_ST_SCR: State Change Register (SCR) sent
+ * @LPORT_ST_READY: Ready for use
+ * @LPORT_ST_LOGO: Local port logout (LOGO) sent
+ * @LPORT_ST_RESET: Local port reset
*/
enum fc_lport_state {
LPORT_ST_DISABLED = 0,
LPORT_ST_FLOGI,
LPORT_ST_DNS,
- LPORT_ST_RPN_ID,
+ LPORT_ST_RNN_ID,
+ LPORT_ST_RSNN_NN,
+ LPORT_ST_RSPN_ID,
LPORT_ST_RFT_ID,
+ LPORT_ST_RFF_ID,
LPORT_ST_SCR,
LPORT_ST_READY,
LPORT_ST_LOGO,
@@ -136,15 +89,28 @@ enum fc_disc_event {
DISC_EV_FAILED
};
+/**
+ * enum fc_rport_state - Remote port states
+ * @RPORT_ST_INIT: Initialized
+ * @RPORT_ST_PLOGI: Waiting for PLOGI completion
+ * @RPORT_ST_PRLI: Waiting for PRLI completion
+ * @RPORT_ST_RTV: Waiting for RTV completion
+ * @RPORT_ST_READY: Ready for use
+ * @RPORT_ST_LOGO: Remote port logout (LOGO) sent
+ * @RPORT_ST_ADISC: Discover Address sent
+ * @RPORT_ST_DELETE: Remote port being deleted
+ * @RPORT_ST_RESTART: Remote port being deleted and will restart
+*/
enum fc_rport_state {
- RPORT_ST_INIT, /* initialized */
- RPORT_ST_PLOGI, /* waiting for PLOGI completion */
- RPORT_ST_PRLI, /* waiting for PRLI completion */
- RPORT_ST_RTV, /* waiting for RTV completion */
- RPORT_ST_READY, /* ready for use */
- RPORT_ST_LOGO, /* port logout sent */
- RPORT_ST_ADISC, /* Discover Address sent */
- RPORT_ST_DELETE, /* port being deleted */
+ RPORT_ST_INIT,
+ RPORT_ST_PLOGI,
+ RPORT_ST_PRLI,
+ RPORT_ST_RTV,
+ RPORT_ST_READY,
+ RPORT_ST_LOGO,
+ RPORT_ST_ADISC,
+ RPORT_ST_DELETE,
+ RPORT_ST_RESTART,
};
/**
@@ -155,12 +121,20 @@ enum fc_rport_state {
* @port_id: Port ID of the discovered port
*/
struct fc_disc_port {
- struct fc_lport *lp;
- struct list_head peers;
- struct work_struct rport_work;
- u32 port_id;
+ struct fc_lport *lp;
+ struct list_head peers;
+ struct work_struct rport_work;
+ u32 port_id;
};
+/**
+ * enum fc_rport_event - Remote port events
+ * @RPORT_EV_NONE: No event
+ * @RPORT_EV_READY: Remote port is ready for use
+ * @RPORT_EV_FAILED: State machine failed, remote port is not ready
+ * @RPORT_EV_STOP: Remote port has been stopped
+ * @RPORT_EV_LOGO: Remote port logout (LOGO) sent
+ */
enum fc_rport_event {
RPORT_EV_NONE = 0,
RPORT_EV_READY,
@@ -171,6 +145,10 @@ enum fc_rport_event {
struct fc_rport_priv;
+/**
+ * struct fc_rport_operations - Operations for a remote port
+ * @event_callback: Function to be called for remote port events
+ */
struct fc_rport_operations {
void (*event_callback)(struct fc_lport *, struct fc_rport_priv *,
enum fc_rport_event);
@@ -178,11 +156,11 @@ struct fc_rport_operations {
/**
* struct fc_rport_libfc_priv - libfc internal information about a remote port
- * @local_port: Fibre Channel host port instance
- * @rp_state: indicates READY for I/O or DELETE when blocked.
- * @flags: REC and RETRY supported flags
- * @e_d_tov: error detect timeout value (in msec)
- * @r_a_tov: resource allocation timeout value (in msec)
+ * @local_port: The associated local port
+ * @rp_state: Indicates READY for I/O or DELETE when blocked
+ * @flags: REC and RETRY supported flags
+ * @e_d_tov: Error detect timeout value (in msec)
+ * @r_a_tov: Resource allocation timeout value (in msec)
*/
struct fc_rport_libfc_priv {
struct fc_lport *local_port;
@@ -195,47 +173,66 @@ struct fc_rport_libfc_priv {
};
/**
- * struct fc_rport_priv - libfc rport and discovery info about a remote port
- * @local_port: Fibre Channel host port instance
- * @rport: transport remote port
- * @kref: reference counter
- * @rp_state: state tracks progress of PLOGI, PRLI, and RTV exchanges
- * @ids: remote port identifiers and roles
- * @flags: REC and RETRY supported flags
- * @max_seq: maximum number of concurrent sequences
- * @disc_id: discovery identifier
- * @maxframe_size: maximum frame size
- * @retries: retry count in current state
- * @e_d_tov: error detect timeout value (in msec)
- * @r_a_tov: resource allocation timeout value (in msec)
- * @rp_mutex: mutex protects rport
- * @retry_work:
- * @event_callback: Callback for rport READY, FAILED or LOGO
+ * struct fc_rport_priv - libfc remote port and discovery info
+ * @local_port: The associated local port
+ * @rport: The FC transport remote port
+ * @kref: Reference counter
+ * @rp_state: Enumeration that tracks progress of PLOGI, PRLI,
+ * and RTV exchanges
+ * @ids: The remote port identifiers and roles
+ * @flags: REC and RETRY supported flags
+ * @max_seq: Maximum number of concurrent sequences
+ * @disc_id: The discovery identifier
+ * @maxframe_size: The maximum frame size
+ * @retries: The retry count for the current state
+ * @e_d_tov: Error detect timeout value (in msec)
+ * @r_a_tov: Resource allocation timeout value (in msec)
+ * @rp_mutex: The mutex that protects the remote port
+ * @retry_work: Handle for retries
+ * @event_callback: Callback when READY, FAILED or LOGO states complete
*/
struct fc_rport_priv {
- struct fc_lport *local_port;
- struct fc_rport *rport;
- struct kref kref;
- enum fc_rport_state rp_state;
+ struct fc_lport *local_port;
+ struct fc_rport *rport;
+ struct kref kref;
+ enum fc_rport_state rp_state;
struct fc_rport_identifiers ids;
- u16 flags;
- u16 max_seq;
- u16 disc_id;
- u16 maxframe_size;
- unsigned int retries;
- unsigned int e_d_tov;
- unsigned int r_a_tov;
- struct mutex rp_mutex;
- struct delayed_work retry_work;
- enum fc_rport_event event;
- struct fc_rport_operations *ops;
- struct list_head peers;
- struct work_struct event_work;
- u32 supported_classes;
+ u16 flags;
+ u16 max_seq;
+ u16 disc_id;
+ u16 maxframe_size;
+ unsigned int retries;
+ unsigned int e_d_tov;
+ unsigned int r_a_tov;
+ struct mutex rp_mutex;
+ struct delayed_work retry_work;
+ enum fc_rport_event event;
+ struct fc_rport_operations *ops;
+ struct list_head peers;
+ struct work_struct event_work;
+ u32 supported_classes;
};
-/*
- * fcoe stats structure
+/**
+ * struct fcoe_dev_stats - fcoe stats structure
+ * @SecondsSinceLastReset: Seconds since the last reset
+ * @TxFrames: Number of transmitted frames
+ * @TxWords: Number of transmitted words
+ * @RxFrames: Number of received frames
+ * @RxWords: Number of received words
+ * @ErrorFrames: Number of received error frames
+ * @DumpedFrames: Number of dumped frames
+ * @LinkFailureCount: Number of link failures
+ * @LossOfSignalCount: Number for signal losses
+ * @InvalidTxWordCount: Number of invalid transmitted words
+ * @InvalidCRCCount: Number of invalid CRCs
+ * @InputRequests: Number of input requests
+ * @OutputRequests: Number of output requests
+ * @ControlRequests: Number of control requests
+ * @InputMegabytes: Number of received megabytes
+ * @OutputMegabytes: Number of transmitted megabytes
+ * @VLinkFailureCount: Number of virtual link failures
+ * @MissDiscAdvCount: Number of missing FIP discovery advertisement
*/
struct fcoe_dev_stats {
u64 SecondsSinceLastReset;
@@ -254,12 +251,17 @@ struct fcoe_dev_stats {
u64 ControlRequests;
u64 InputMegabytes;
u64 OutputMegabytes;
+ u64 VLinkFailureCount;
+ u64 MissDiscAdvCount;
};
-/*
- * els data is used for passing ELS respone specific
- * data to send ELS response mainly using infomation
- * in exchange and sequence in EM layer.
+/**
+ * struct fc_seq_els_data - ELS data used for passing ELS specific responses
+ * @fp: The ELS frame
+ * @reason: The reason for rejection
+ * @explan: The explaination of the rejection
+ *
+ * Mainly used by the exchange manager layer.
*/
struct fc_seq_els_data {
struct fc_frame *fp;
@@ -267,77 +269,87 @@ struct fc_seq_els_data {
enum fc_els_rjt_explan explan;
};
-/*
- * FCP request structure, one for each scsi cmd request
+/**
+ * struct fc_fcp_pkt - FCP request structure (one for each scsi_cmnd request)
+ * @lp: The associated local port
+ * @state: The state of the I/O
+ * @tgt_flags: Target's flags
+ * @ref_cnt: Reference count
+ * @scsi_pkt_lock: Lock to protect the SCSI packet (must be taken before the
+ * host_lock if both are to be held at the same time)
+ * @cmd: The SCSI command (set and clear with the host_lock held)
+ * @list: Tracks queued commands (accessed with the host_lock held)
+ * @timer: The command timer
+ * @tm_done: Completion indicator
+ * @wait_for_comp: Indicator to wait for completion of the I/O (in jiffies)
+ * @start_time: Timestamp indicating the start of the I/O (in jiffies)
+ * @end_time: Timestamp indicating the end of the I/O (in jiffies)
+ * @last_pkt_time: Timestamp of the last frame received (in jiffies)
+ * @data_len: The length of the data
+ * @cdb_cmd: The CDB command
+ * @xfer_len: The transfer length
+ * @xfer_ddp: Indicates if this transfer used DDP (XID of the exchange
+ * will be set here if DDP was setup)
+ * @xfer_contig_end: The offset into the buffer if the buffer is contiguous
+ * (Tx and Rx)
+ * @max_payload: The maximum payload size (in bytes)
+ * @io_status: SCSI result (upper 24 bits)
+ * @cdb_status: CDB status
+ * @status_code: FCP I/O status
+ * @scsi_comp_flags: Completion flags (bit 3 Underrun bit 2: overrun)
+ * @req_flags: Request flags (bit 0: read bit:1 write)
+ * @scsi_resid: SCSI residule length
+ * @rport: The remote port that the SCSI command is targeted at
+ * @seq_ptr: The sequence that will carry the SCSI command
+ * @recov_retry: Number of recovery retries
+ * @recov_seq: The sequence for REC or SRR
*/
struct fc_fcp_pkt {
- /*
- * housekeeping stuff
- */
- struct fc_lport *lp; /* handle to hba struct */
- u16 state; /* scsi_pkt state state */
- u16 tgt_flags; /* target flags */
- atomic_t ref_cnt; /* fcp pkt ref count */
- spinlock_t scsi_pkt_lock; /* Must be taken before the host lock
- * if both are held at the same time */
- /*
- * SCSI I/O related stuff
- */
- struct scsi_cmnd *cmd; /* scsi command pointer. set/clear
- * under host lock */
- struct list_head list; /* tracks queued commands. access under
- * host lock */
- /*
- * timeout related stuff
- */
- struct timer_list timer; /* command timer */
+ /* Housekeeping information */
+ struct fc_lport *lp;
+ u16 state;
+ u16 tgt_flags;
+ atomic_t ref_cnt;
+ spinlock_t scsi_pkt_lock;
+
+ /* SCSI I/O related information */
+ struct scsi_cmnd *cmd;
+ struct list_head list;
+
+ /* Timeout related information */
+ struct timer_list timer;
struct completion tm_done;
- int wait_for_comp;
- unsigned long start_time; /* start jiffie */
- unsigned long end_time; /* end jiffie */
- unsigned long last_pkt_time; /* jiffies of last frame received */
-
- /*
- * scsi cmd and data transfer information
- */
- u32 data_len;
- /*
- * transport related veriables
- */
- struct fcp_cmnd cdb_cmd;
- size_t xfer_len;
- u16 xfer_ddp; /* this xfer is ddped */
- u32 xfer_contig_end; /* offset of end of contiguous xfer */
- u16 max_payload; /* max payload size in bytes */
-
- /*
- * scsi/fcp return status
- */
- u32 io_status; /* SCSI result upper 24 bits */
- u8 cdb_status;
- u8 status_code; /* FCP I/O status */
- /* bit 3 Underrun bit 2: overrun */
- u8 scsi_comp_flags;
- u32 req_flags; /* bit 0: read bit:1 write */
- u32 scsi_resid; /* residule length */
-
- struct fc_rport *rport; /* remote port pointer */
- struct fc_seq *seq_ptr; /* current sequence pointer */
- /*
- * Error Processing
- */
- u8 recov_retry; /* count of recovery retries */
- struct fc_seq *recov_seq; /* sequence for REC or SRR */
+ int wait_for_comp;
+ unsigned long start_time;
+ unsigned long end_time;
+ unsigned long last_pkt_time;
+
+ /* SCSI command and data transfer information */
+ u32 data_len;
+
+ /* Transport related veriables */
+ struct fcp_cmnd cdb_cmd;
+ size_t xfer_len;
+ u16 xfer_ddp;
+ u32 xfer_contig_end;
+ u16 max_payload;
+
+ /* SCSI/FCP return status */
+ u32 io_status;
+ u8 cdb_status;
+ u8 status_code;
+ u8 scsi_comp_flags;
+ u32 req_flags;
+ u32 scsi_resid;
+
+ /* Associated structures */
+ struct fc_rport *rport;
+ struct fc_seq *seq_ptr;
+
+ /* Error Processing information */
+ u8 recov_retry;
+ struct fc_seq *recov_seq;
};
-/*
- * FC_FCP HELPER FUNCTIONS
- *****************************/
-static inline bool fc_fcp_is_read(const struct fc_fcp_pkt *fsp)
-{
- if (fsp && fsp->cmd)
- return fsp->cmd->sc_data_direction == DMA_FROM_DEVICE;
- return false;
-}
/*
* Structure and function definitions for managing Fibre Channel Exchanges
@@ -350,23 +362,51 @@ static inline bool fc_fcp_is_read(const struct fc_fcp_pkt *fsp)
struct fc_exch_mgr;
struct fc_exch_mgr_anchor;
-extern u16 fc_cpu_mask; /* cpu mask for possible cpus */
+extern u16 fc_cpu_mask; /* cpu mask for possible cpus */
-/*
- * Sequence.
+/**
+ * struct fc_seq - FC sequence
+ * @id: The sequence ID
+ * @ssb_stat: Status flags for the sequence status block (SSB)
+ * @cnt: Number of frames sent so far
+ * @rec_data: FC-4 value for REC
*/
struct fc_seq {
- u8 id; /* seq ID */
- u16 ssb_stat; /* status flags for sequence status block */
- u16 cnt; /* frames sent so far on sequence */
- u32 rec_data; /* FC-4 value for REC */
+ u8 id;
+ u16 ssb_stat;
+ u16 cnt;
+ u32 rec_data;
};
#define FC_EX_DONE (1 << 0) /* ep is completed */
#define FC_EX_RST_CLEANUP (1 << 1) /* reset is forcing completion */
-/*
- * Exchange.
+/**
+ * struct fc_exch - Fibre Channel Exchange
+ * @em: Exchange manager
+ * @pool: Exchange pool
+ * @state: The exchange's state
+ * @xid: The exchange ID
+ * @ex_list: Handle used by the EM to track free exchanges
+ * @ex_lock: Lock that protects the exchange
+ * @ex_refcnt: Reference count
+ * @timeout_work: Handle for timeout handler
+ * @lp: The local port that this exchange is on
+ * @oxid: Originator's exchange ID
+ * @rxid: Responder's exchange ID
+ * @oid: Originator's FCID
+ * @sid: Source FCID
+ * @did: Destination FCID
+ * @esb_stat: ESB exchange status
+ * @r_a_tov: Resouce allocation time out value (in msecs)
+ * @seq_id: The next sequence ID to use
+ * @f_ctl: F_CTL flags for the sequence
+ * @fh_type: The frame type
+ * @class: The class of service
+ * @seq: The sequence in use on this exchange
+ * @resp: Callback for responses on this exchange
+ * @destructor: Called when destroying the exchange
+ * @arg: Passed as a void pointer to the resp() callback
*
* Locking notes: The ex_lock protects following items:
* state, esb_stat, f_ctl, seq.ssb_stat
@@ -374,76 +414,59 @@ struct fc_seq {
* sequence allocation
*/
struct fc_exch {
- struct fc_exch_mgr *em; /* exchange manager */
- struct fc_exch_pool *pool; /* per cpu exches pool */
- u32 state; /* internal driver state */
- u16 xid; /* our exchange ID */
- struct list_head ex_list; /* free or busy list linkage */
- spinlock_t ex_lock; /* lock covering exchange state */
- atomic_t ex_refcnt; /* reference counter */
- struct delayed_work timeout_work; /* timer for upper level protocols */
- struct fc_lport *lp; /* fc device instance */
- u16 oxid; /* originator's exchange ID */
- u16 rxid; /* responder's exchange ID */
- u32 oid; /* originator's FCID */
- u32 sid; /* source FCID */
- u32 did; /* destination FCID */
- u32 esb_stat; /* exchange status for ESB */
- u32 r_a_tov; /* r_a_tov from rport (msec) */
- u8 seq_id; /* next sequence ID to use */
- u32 f_ctl; /* F_CTL flags for sequences */
- u8 fh_type; /* frame type */
- enum fc_class class; /* class of service */
- struct fc_seq seq; /* single sequence */
- /*
- * Handler for responses to this current exchange.
- */
- void (*resp)(struct fc_seq *, struct fc_frame *, void *);
- void (*destructor)(struct fc_seq *, void *);
- /*
- * arg is passed as void pointer to exchange
- * resp and destructor handlers
- */
- void *arg;
+ struct fc_exch_mgr *em;
+ struct fc_exch_pool *pool;
+ u32 state;
+ u16 xid;
+ struct list_head ex_list;
+ spinlock_t ex_lock;
+ atomic_t ex_refcnt;
+ struct delayed_work timeout_work;
+ struct fc_lport *lp;
+ u16 oxid;
+ u16 rxid;
+ u32 oid;
+ u32 sid;
+ u32 did;
+ u32 esb_stat;
+ u32 r_a_tov;
+ u8 seq_id;
+ u32 f_ctl;
+ u8 fh_type;
+ enum fc_class class;
+ struct fc_seq seq;
+
+ void (*resp)(struct fc_seq *, struct fc_frame *, void *);
+ void *arg;
+
+ void (*destructor)(struct fc_seq *, void *);
+
};
#define fc_seq_exch(sp) container_of(sp, struct fc_exch, seq)
-struct libfc_function_template {
+struct libfc_function_template {
/*
* Interface to send a FC frame
*
* STATUS: REQUIRED
*/
- int (*frame_send)(struct fc_lport *lp, struct fc_frame *fp);
+ int (*frame_send)(struct fc_lport *, struct fc_frame *);
/*
* Interface to send ELS/CT frames
*
* STATUS: OPTIONAL
*/
- struct fc_seq *(*elsct_send)(struct fc_lport *lport,
- u32 did,
- struct fc_frame *fp,
- unsigned int op,
+ struct fc_seq *(*elsct_send)(struct fc_lport *, u32 did,
+ struct fc_frame *, unsigned int op,
void (*resp)(struct fc_seq *,
- struct fc_frame *fp,
- void *arg),
+ struct fc_frame *, void *arg),
void *arg, u32 timer_msec);
/*
* Send the FC frame payload using a new exchange and sequence.
*
- * The frame pointer with some of the header's fields must be
- * filled before calling exch_seq_send(), those fields are,
- *
- * - routing control
- * - FC port did
- * - FC port sid
- * - FC header type
- * - frame control
- * - parameter or relative offset
- *
* The exchange response handler is set in this routine to resp()
* function pointer. It can be called in two scenarios: if a timeout
* occurs or if a response frame is received for the exchange. The
@@ -464,14 +487,13 @@ struct libfc_function_template {
*
* STATUS: OPTIONAL
*/
- struct fc_seq *(*exch_seq_send)(struct fc_lport *lp,
- struct fc_frame *fp,
- void (*resp)(struct fc_seq *sp,
- struct fc_frame *fp,
- void *arg),
- void (*destructor)(struct fc_seq *sp,
- void *arg),
- void *arg, unsigned int timer_msec);
+ struct fc_seq *(*exch_seq_send)(struct fc_lport *, struct fc_frame *,
+ void (*resp)(struct fc_seq *,
+ struct fc_frame *,
+ void *),
+ void (*destructor)(struct fc_seq *,
+ void *),
+ void *, unsigned int timer_msec);
/*
* Sets up the DDP context for a given exchange id on the given
@@ -479,22 +501,28 @@ struct libfc_function_template {
*
* STATUS: OPTIONAL
*/
- int (*ddp_setup)(struct fc_lport *lp, u16 xid,
- struct scatterlist *sgl, unsigned int sgc);
+ int (*ddp_setup)(struct fc_lport *, u16, struct scatterlist *,
+ unsigned int);
/*
* Completes the DDP transfer and returns the length of data DDPed
* for the given exchange id.
*
* STATUS: OPTIONAL
*/
- int (*ddp_done)(struct fc_lport *lp, u16 xid);
+ int (*ddp_done)(struct fc_lport *, u16);
+ /*
+ * Allow LLD to fill its own Link Error Status Block
+ *
+ * STATUS: OPTIONAL
+ */
+ void (*get_lesb)(struct fc_lport *, struct fc_els_lesb *lesb);
/*
* Send a frame using an existing sequence and exchange.
*
* STATUS: OPTIONAL
*/
- int (*seq_send)(struct fc_lport *lp, struct fc_seq *sp,
- struct fc_frame *fp);
+ int (*seq_send)(struct fc_lport *, struct fc_seq *,
+ struct fc_frame *);
/*
* Send an ELS response using infomation from a previous
@@ -502,8 +530,8 @@ struct libfc_function_template {
*
* STATUS: OPTIONAL
*/
- void (*seq_els_rsp_send)(struct fc_seq *sp, enum fc_els_cmd els_cmd,
- struct fc_seq_els_data *els_data);
+ void (*seq_els_rsp_send)(struct fc_seq *, enum fc_els_cmd,
+ struct fc_seq_els_data *);
/*
* Abort an exchange and sequence. Generally called because of a
@@ -515,7 +543,7 @@ struct libfc_function_template {
*
* STATUS: OPTIONAL
*/
- int (*seq_exch_abort)(const struct fc_seq *req_sp,
+ int (*seq_exch_abort)(const struct fc_seq *,
unsigned int timer_msec);
/*
@@ -524,14 +552,14 @@ struct libfc_function_template {
*
* STATUS: OPTIONAL
*/
- void (*exch_done)(struct fc_seq *sp);
+ void (*exch_done)(struct fc_seq *);
/*
* Start a new sequence on the same exchange/sequence tuple.
*
* STATUS: OPTIONAL
*/
- struct fc_seq *(*seq_start_next)(struct fc_seq *sp);
+ struct fc_seq *(*seq_start_next)(struct fc_seq *);
/*
* Reset an exchange manager, completing all sequences and exchanges.
@@ -540,8 +568,7 @@ struct libfc_function_template {
*
* STATUS: OPTIONAL
*/
- void (*exch_mgr_reset)(struct fc_lport *,
- u32 s_id, u32 d_id);
+ void (*exch_mgr_reset)(struct fc_lport *, u32 s_id, u32 d_id);
/*
* Flush the rport work queue. Generally used before shutdown.
@@ -555,8 +582,8 @@ struct libfc_function_template {
*
* STATUS: OPTIONAL
*/
- void (*lport_recv)(struct fc_lport *lp, struct fc_seq *sp,
- struct fc_frame *fp);
+ void (*lport_recv)(struct fc_lport *, struct fc_seq *,
+ struct fc_frame *);
/*
* Reset the local port.
@@ -566,6 +593,26 @@ struct libfc_function_template {
int (*lport_reset)(struct fc_lport *);
/*
+ * Set the local port FC_ID.
+ *
+ * This may be provided by the LLD to allow it to be
+ * notified when the local port is assigned a FC-ID.
+ *
+ * The frame, if non-NULL, is the incoming frame with the
+ * FLOGI LS_ACC or FLOGI, and may contain the granted MAC
+ * address for the LLD. The frame pointer may be NULL if
+ * no MAC is associated with this assignment (LOGO or PLOGI).
+ *
+ * If FC_ID is non-zero, r_a_tov and e_d_tov must be valid.
+ *
+ * Note: this is called with the local port mutex held.
+ *
+ * STATUS: OPTIONAL
+ */
+ void (*lport_set_port_id)(struct fc_lport *, u32 port_id,
+ struct fc_frame *);
+
+ /*
* Create a remote port with a given port ID
*
* STATUS: OPTIONAL
@@ -622,31 +669,31 @@ struct libfc_function_template {
*
* STATUS: OPTIONAL
*/
- int (*fcp_cmd_send)(struct fc_lport *lp, struct fc_fcp_pkt *fsp,
- void (*resp)(struct fc_seq *, struct fc_frame *fp,
- void *arg));
+ int (*fcp_cmd_send)(struct fc_lport *, struct fc_fcp_pkt *,
+ void (*resp)(struct fc_seq *, struct fc_frame *,
+ void *));
/*
* Cleanup the FCP layer, used durring link down and reset
*
* STATUS: OPTIONAL
*/
- void (*fcp_cleanup)(struct fc_lport *lp);
+ void (*fcp_cleanup)(struct fc_lport *);
/*
* Abort all I/O on a local port
*
* STATUS: OPTIONAL
*/
- void (*fcp_abort_io)(struct fc_lport *lp);
+ void (*fcp_abort_io)(struct fc_lport *);
/*
* Receive a request for the discovery layer.
*
* STATUS: OPTIONAL
*/
- void (*disc_recv_req)(struct fc_seq *,
- struct fc_frame *, struct fc_lport *);
+ void (*disc_recv_req)(struct fc_seq *, struct fc_frame *,
+ struct fc_lport *);
/*
* Start discovery for a local port.
@@ -675,419 +722,340 @@ struct libfc_function_template {
void (*disc_stop_final) (struct fc_lport *);
};
-/* information used by the discovery layer */
+/**
+ * struct fc_disc - Discovery context
+ * @retry_count: Number of retries
+ * @pending: 1 if discovery is pending, 0 if not
+ * @requesting: 1 if discovery has been requested, 0 if not
+ * @seq_count: Number of sequences used for discovery
+ * @buf_len: Length of the discovery buffer
+ * @disc_id: Discovery ID
+ * @rports: List of discovered remote ports
+ * @lport: The local port that discovery is for
+ * @disc_mutex: Mutex that protects the discovery context
+ * @partial_buf: Partial name buffer (if names are returned
+ * in multiple frames)
+ * @disc_work: handle for delayed work context
+ * @disc_callback: Callback routine called when discovery completes
+ */
struct fc_disc {
- unsigned char retry_count;
- unsigned char pending;
- unsigned char requested;
- unsigned short seq_count;
- unsigned char buf_len;
- u16 disc_id;
+ unsigned char retry_count;
+ unsigned char pending;
+ unsigned char requested;
+ unsigned short seq_count;
+ unsigned char buf_len;
+ u16 disc_id;
+
+ struct list_head rports;
+ struct fc_lport *lport;
+ struct mutex disc_mutex;
+ struct fc_gpn_ft_resp partial_buf;
+ struct delayed_work disc_work;
void (*disc_callback)(struct fc_lport *,
enum fc_disc_event);
-
- struct list_head rports;
- struct fc_lport *lport;
- struct mutex disc_mutex;
- struct fc_gpn_ft_resp partial_buf; /* partial name buffer */
- struct delayed_work disc_work;
};
+/**
+ * struct fc_lport - Local port
+ * @host: The SCSI host associated with a local port
+ * @ema_list: Exchange manager anchor list
+ * @dns_rdata: The directory server remote port
+ * @ptp_rdata: Point to point remote port
+ * @scsi_priv: FCP layer internal data
+ * @disc: Discovery context
+ * @vports: Child vports if N_Port
+ * @vport: Parent vport if VN_Port
+ * @tt: Libfc function template
+ * @link_up: Link state (1 = link up, 0 = link down)
+ * @qfull: Queue state (1 queue is full, 0 queue is not full)
+ * @state: Identifies the state
+ * @boot_time: Timestamp indicating when the local port came online
+ * @host_stats: SCSI host statistics
+ * @dev_stats: FCoE device stats (TODO: libfc should not be
+ * FCoE aware)
+ * @retry_count: Number of retries in the current state
+ * @wwpn: World Wide Port Name
+ * @wwnn: World Wide Node Name
+ * @service_params: Common service parameters
+ * @e_d_tov: Error detection timeout value
+ * @r_a_tov: Resouce allocation timeout value
+ * @rnid_gen: RNID information
+ * @sg_supp: Indicates if scatter gather is supported
+ * @seq_offload: Indicates if sequence offload is supported
+ * @crc_offload: Indicates if CRC offload is supported
+ * @lro_enabled: Indicates if large receive offload is supported
+ * @does_npiv: Supports multiple vports
+ * @npiv_enabled: Switch/fabric allows NPIV
+ * @mfs: The maximum Fibre Channel payload size
+ * @max_retry_count: The maximum retry attempts
+ * @max_rport_retry_count: The maximum remote port retry attempts
+ * @lro_xid: The maximum XID for LRO
+ * @lso_max: The maximum large offload send size
+ * @fcts: FC-4 type mask
+ * @lp_mutex: Mutex to protect the local port
+ * @list: Handle for list of local ports
+ * @retry_work: Handle to local port for delayed retry context
+ */
struct fc_lport {
- struct list_head list;
-
/* Associations */
- struct Scsi_Host *host;
- struct list_head ema_list;
- struct fc_rport_priv *dns_rp;
- struct fc_rport_priv *ptp_rp;
- void *scsi_priv;
- struct fc_disc disc;
+ struct Scsi_Host *host;
+ struct list_head ema_list;
+ struct fc_rport_priv *dns_rdata;
+ struct fc_rport_priv *ptp_rdata;
+ void *scsi_priv;
+ struct fc_disc disc;
+
+ /* Virtual port information */
+ struct list_head vports;
+ struct fc_vport *vport;
/* Operational Information */
struct libfc_function_template tt;
- u8 link_up;
- u8 qfull;
- enum fc_lport_state state;
- unsigned long boot_time;
-
- struct fc_host_statistics host_stats;
- struct fcoe_dev_stats *dev_stats;
-
- u64 wwpn;
- u64 wwnn;
- u8 retry_count;
+ u8 link_up;
+ u8 qfull;
+ enum fc_lport_state state;
+ unsigned long boot_time;
+ struct fc_host_statistics host_stats;
+ struct fcoe_dev_stats *dev_stats;
+ u8 retry_count;
+
+ /* Fabric information */
+ u64 wwpn;
+ u64 wwnn;
+ unsigned int service_params;
+ unsigned int e_d_tov;
+ unsigned int r_a_tov;
+ struct fc_els_rnid_gen rnid_gen;
/* Capabilities */
- u32 sg_supp:1; /* scatter gather supported */
- u32 seq_offload:1; /* seq offload supported */
- u32 crc_offload:1; /* crc offload supported */
- u32 lro_enabled:1; /* large receive offload */
- u32 mfs; /* max FC payload size */
- unsigned int service_params;
- unsigned int e_d_tov;
- unsigned int r_a_tov;
- u8 max_retry_count;
- u8 max_rport_retry_count;
- u16 link_speed;
- u16 link_supported_speeds;
- u16 lro_xid; /* max xid for fcoe lro */
- unsigned int lso_max; /* max large send size */
- struct fc_ns_fts fcts; /* FC-4 type masks */
- struct fc_els_rnid_gen rnid_gen; /* RNID information */
-
- /* Semaphores */
- struct mutex lp_mutex;
+ u32 sg_supp:1;
+ u32 seq_offload:1;
+ u32 crc_offload:1;
+ u32 lro_enabled:1;
+ u32 does_npiv:1;
+ u32 npiv_enabled:1;
+ u32 mfs;
+ u8 max_retry_count;
+ u8 max_rport_retry_count;
+ u16 link_speed;
+ u16 link_supported_speeds;
+ u16 lro_xid;
+ unsigned int lso_max;
+ struct fc_ns_fts fcts;
/* Miscellaneous */
- struct delayed_work retry_work;
- struct delayed_work disc_work;
+ struct mutex lp_mutex;
+ struct list_head list;
+ struct delayed_work retry_work;
};
/*
* FC_LPORT HELPER FUNCTIONS
*****************************/
-static inline int fc_lport_test_ready(struct fc_lport *lp)
+
+/**
+ * fc_lport_test_ready() - Determine if a local port is in the READY state
+ * @lport: The local port to test
+ */
+static inline int fc_lport_test_ready(struct fc_lport *lport)
{
- return lp->state == LPORT_ST_READY;
+ return lport->state == LPORT_ST_READY;
}
-static inline void fc_set_wwnn(struct fc_lport *lp, u64 wwnn)
+/**
+ * fc_set_wwnn() - Set the World Wide Node Name of a local port
+ * @lport: The local port whose WWNN is to be set
+ * @wwnn: The new WWNN
+ */
+static inline void fc_set_wwnn(struct fc_lport *lport, u64 wwnn)
{
- lp->wwnn = wwnn;
+ lport->wwnn = wwnn;
}
-static inline void fc_set_wwpn(struct fc_lport *lp, u64 wwnn)
+/**
+ * fc_set_wwpn() - Set the World Wide Port Name of a local port
+ * @lport: The local port whose WWPN is to be set
+ * @wwnn: The new WWPN
+ */
+static inline void fc_set_wwpn(struct fc_lport *lport, u64 wwnn)
{
- lp->wwpn = wwnn;
+ lport->wwpn = wwnn;
}
-static inline void fc_lport_state_enter(struct fc_lport *lp,
+/**
+ * fc_lport_state_enter() - Change a local port's state
+ * @lport: The local port whose state is to change
+ * @state: The new state
+ */
+static inline void fc_lport_state_enter(struct fc_lport *lport,
enum fc_lport_state state)
{
- if (state != lp->state)
- lp->retry_count = 0;
- lp->state = state;
+ if (state != lport->state)
+ lport->retry_count = 0;
+ lport->state = state;
}
-static inline int fc_lport_init_stats(struct fc_lport *lp)
+/**
+ * fc_lport_init_stats() - Allocate per-CPU statistics for a local port
+ * @lport: The local port whose statistics are to be initialized
+ */
+static inline int fc_lport_init_stats(struct fc_lport *lport)
{
- /* allocate per cpu stats block */
- lp->dev_stats = alloc_percpu(struct fcoe_dev_stats);
- if (!lp->dev_stats)
+ lport->dev_stats = alloc_percpu(struct fcoe_dev_stats);
+ if (!lport->dev_stats)
return -ENOMEM;
return 0;
}
-static inline void fc_lport_free_stats(struct fc_lport *lp)
+/**
+ * fc_lport_free_stats() - Free memory for a local port's statistics
+ * @lport: The local port whose statistics are to be freed
+ */
+static inline void fc_lport_free_stats(struct fc_lport *lport)
{
- free_percpu(lp->dev_stats);
+ free_percpu(lport->dev_stats);
}
-static inline struct fcoe_dev_stats *fc_lport_get_stats(struct fc_lport *lp)
+/**
+ * fc_lport_get_stats() - Get a local port's statistics
+ * @lport: The local port whose statistics are to be retreived
+ */
+static inline struct fcoe_dev_stats *fc_lport_get_stats(struct fc_lport *lport)
{
- return per_cpu_ptr(lp->dev_stats, smp_processor_id());
+ return per_cpu_ptr(lport->dev_stats, smp_processor_id());
}
-static inline void *lport_priv(const struct fc_lport *lp)
+/**
+ * lport_priv() - Return the private data from a local port
+ * @lport: The local port whose private data is to be retreived
+ */
+static inline void *lport_priv(const struct fc_lport *lport)
{
- return (void *)(lp + 1);
+ return (void *)(lport + 1);
}
/**
- * libfc_host_alloc() - Allocate a Scsi_Host with room for the fc_lport
- * @sht: ptr to the scsi host templ
- * @priv_size: size of private data after fc_lport
+ * libfc_host_alloc() - Allocate a Scsi_Host with room for a local port and
+ * LLD private data
+ * @sht: The SCSI host template
+ * @priv_size: Size of private data
*
- * Returns: ptr to Scsi_Host
+ * Returns: libfc lport
*/
-static inline struct Scsi_Host *
+static inline struct fc_lport *
libfc_host_alloc(struct scsi_host_template *sht, int priv_size)
{
- return scsi_host_alloc(sht, sizeof(struct fc_lport) + priv_size);
+ struct fc_lport *lport;
+ struct Scsi_Host *shost;
+
+ shost = scsi_host_alloc(sht, sizeof(*lport) + priv_size);
+ if (!shost)
+ return NULL;
+ lport = shost_priv(shost);
+ lport->host = shost;
+ INIT_LIST_HEAD(&lport->ema_list);
+ INIT_LIST_HEAD(&lport->vports);
+ return lport;
}
/*
- * LOCAL PORT LAYER
+ * FC_FCP HELPER FUNCTIONS
*****************************/
-int fc_lport_init(struct fc_lport *lp);
-
-/*
- * Destroy the specified local port by finding and freeing all
- * fc_rports associated with it and then by freeing the fc_lport
- * itself.
- */
-int fc_lport_destroy(struct fc_lport *lp);
-
-/*
- * Logout the specified local port from the fabric
- */
-int fc_fabric_logoff(struct fc_lport *lp);
-
-/*
- * Initiate the LP state machine. This handler will use fc_host_attr
- * to store the FLOGI service parameters, so fc_host_attr must be
- * initialized before calling this handler.
- */
-int fc_fabric_login(struct fc_lport *lp);
+static inline bool fc_fcp_is_read(const struct fc_fcp_pkt *fsp)
+{
+ if (fsp && fsp->cmd)
+ return fsp->cmd->sc_data_direction == DMA_FROM_DEVICE;
+ return false;
+}
/*
- * The link is up for the given local port.
- */
+ * LOCAL PORT LAYER
+ *****************************/
+int fc_lport_init(struct fc_lport *);
+int fc_lport_destroy(struct fc_lport *);
+int fc_fabric_logoff(struct fc_lport *);
+int fc_fabric_login(struct fc_lport *);
+void __fc_linkup(struct fc_lport *);
void fc_linkup(struct fc_lport *);
-
-/*
- * Link is down for the given local port.
- */
+void __fc_linkdown(struct fc_lport *);
void fc_linkdown(struct fc_lport *);
-
-/*
- * Configure the local port.
- */
+void fc_vport_setlink(struct fc_lport *);
+void fc_vports_linkchange(struct fc_lport *);
int fc_lport_config(struct fc_lport *);
-
-/*
- * Reset the local port.
- */
int fc_lport_reset(struct fc_lport *);
-
-/*
- * Set the mfs or reset
- */
-int fc_set_mfs(struct fc_lport *lp, u32 mfs);
-
+int fc_set_mfs(struct fc_lport *, u32 mfs);
+struct fc_lport *libfc_vport_create(struct fc_vport *, int privsize);
+struct fc_lport *fc_vport_id_lookup(struct fc_lport *, u32 port_id);
+int fc_lport_bsg_request(struct fc_bsg_job *);
/*
* REMOTE PORT LAYER
*****************************/
-int fc_rport_init(struct fc_lport *lp);
-void fc_rport_terminate_io(struct fc_rport *rp);
+int fc_rport_init(struct fc_lport *);
+void fc_rport_terminate_io(struct fc_rport *);
/*
* DISCOVERY LAYER
*****************************/
-int fc_disc_init(struct fc_lport *lp);
-
+int fc_disc_init(struct fc_lport *);
/*
- * SCSI LAYER
+ * FCP LAYER
*****************************/
-/*
- * Initialize the SCSI block of libfc
- */
int fc_fcp_init(struct fc_lport *);
-
-/*
- * This section provides an API which allows direct interaction
- * with the SCSI-ml. Each of these functions satisfies a function
- * pointer defined in Scsi_Host and therefore is always called
- * directly from the SCSI-ml.
- */
-int fc_queuecommand(struct scsi_cmnd *sc_cmd,
- void (*done)(struct scsi_cmnd *));
-
-/*
- * complete processing of a fcp packet
- *
- * This function may sleep if a fsp timer is pending.
- * The host lock must not be held by caller.
- */
-void fc_fcp_complete(struct fc_fcp_pkt *fsp);
-
-/*
- * Send an ABTS frame to the target device. The sc_cmd argument
- * is a pointer to the SCSI command to be aborted.
- */
-int fc_eh_abort(struct scsi_cmnd *sc_cmd);
-
-/*
- * Reset a LUN by sending send the tm cmd to the target.
- */
-int fc_eh_device_reset(struct scsi_cmnd *sc_cmd);
-
-/*
- * Reset the host adapter.
- */
-int fc_eh_host_reset(struct scsi_cmnd *sc_cmd);
-
-/*
- * Check rport status.
- */
-int fc_slave_alloc(struct scsi_device *sdev);
-
-/*
- * Adjust the queue depth.
- */
-int fc_change_queue_depth(struct scsi_device *sdev, int qdepth);
-
-/*
- * Change the tag type.
- */
-int fc_change_queue_type(struct scsi_device *sdev, int tag_type);
-
-/*
- * Free memory pools used by the FCP layer.
- */
void fc_fcp_destroy(struct fc_lport *);
/*
- * Set up direct-data placement for this I/O request
- */
-void fc_fcp_ddp_setup(struct fc_fcp_pkt *fsp, u16 xid);
+ * SCSI INTERACTION LAYER
+ *****************************/
+int fc_queuecommand(struct scsi_cmnd *,
+ void (*done)(struct scsi_cmnd *));
+int fc_eh_abort(struct scsi_cmnd *);
+int fc_eh_device_reset(struct scsi_cmnd *);
+int fc_eh_host_reset(struct scsi_cmnd *);
+int fc_slave_alloc(struct scsi_device *);
+int fc_change_queue_depth(struct scsi_device *, int qdepth, int reason);
+int fc_change_queue_type(struct scsi_device *, int tag_type);
/*
* ELS/CT interface
*****************************/
-/*
- * Initializes ELS/CT interface
- */
-int fc_elsct_init(struct fc_lport *lp);
+int fc_elsct_init(struct fc_lport *);
+struct fc_seq *fc_elsct_send(struct fc_lport *, u32 did,
+ struct fc_frame *,
+ unsigned int op,
+ void (*resp)(struct fc_seq *,
+ struct fc_frame *,
+ void *arg),
+ void *arg, u32 timer_msec);
+void fc_lport_flogi_resp(struct fc_seq *, struct fc_frame *, void *);
+void fc_lport_logo_resp(struct fc_seq *, struct fc_frame *, void *);
/*
* EXCHANGE MANAGER LAYER
*****************************/
-/*
- * Initializes Exchange Manager related
- * function pointers in struct libfc_function_template.
- */
-int fc_exch_init(struct fc_lport *lp);
-
-/*
- * Adds Exchange Manager (EM) mp to lport.
- *
- * Adds specified mp to lport using struct fc_exch_mgr_anchor,
- * the struct fc_exch_mgr_anchor allows same EM sharing by
- * more than one lport with their specified match function,
- * the match function is used in allocating exchange from
- * added mp.
- */
-struct fc_exch_mgr_anchor *fc_exch_mgr_add(struct fc_lport *lport,
- struct fc_exch_mgr *mp,
+int fc_exch_init(struct fc_lport *);
+struct fc_exch_mgr_anchor *fc_exch_mgr_add(struct fc_lport *,
+ struct fc_exch_mgr *,
bool (*match)(struct fc_frame *));
-
-/*
- * Deletes Exchange Manager (EM) from lport by removing
- * its anchor ema from lport.
- *
- * If removed anchor ema was the last user of its associated EM
- * then also destroys associated EM.
- */
-void fc_exch_mgr_del(struct fc_exch_mgr_anchor *ema);
-
-/*
- * Allocates an Exchange Manager (EM).
- *
- * The EM manages exchanges for their allocation and
- * free, also allows exchange lookup for received
- * frame.
- *
- * The class is used for initializing FC class of
- * allocated exchange from EM.
- *
- * The min_xid and max_xid will limit new
- * exchange ID (XID) within this range for
- * a new exchange.
- * The LLD may choose to have multiple EMs,
- * e.g. one EM instance per CPU receive thread in LLD.
- *
- * Specified match function is used in allocating exchanges
- * from newly allocated EM.
- */
-struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp,
- enum fc_class class,
- u16 min_xid,
- u16 max_xid,
+void fc_exch_mgr_del(struct fc_exch_mgr_anchor *);
+int fc_exch_mgr_list_clone(struct fc_lport *src, struct fc_lport *dst);
+struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *, enum fc_class class,
+ u16 min_xid, u16 max_xid,
bool (*match)(struct fc_frame *));
-
-/*
- * Free all exchange managers of a lport.
- */
-void fc_exch_mgr_free(struct fc_lport *lport);
-
-/*
- * Receive a frame on specified local port and exchange manager.
- */
-void fc_exch_recv(struct fc_lport *lp, struct fc_frame *fp);
-
-/*
- * This function is for exch_seq_send function pointer in
- * struct libfc_function_template, see comment block on
- * exch_seq_send for description of this function.
- */
-struct fc_seq *fc_exch_seq_send(struct fc_lport *lp,
- struct fc_frame *fp,
- void (*resp)(struct fc_seq *sp,
- struct fc_frame *fp,
- void *arg),
- void (*destructor)(struct fc_seq *sp,
- void *arg),
- void *arg, u32 timer_msec);
-
-/*
- * send a frame using existing sequence and exchange.
- */
-int fc_seq_send(struct fc_lport *lp, struct fc_seq *sp, struct fc_frame *fp);
-
-/*
- * Send ELS response using mainly infomation
- * in exchange and sequence in EM layer.
- */
-void fc_seq_els_rsp_send(struct fc_seq *sp, enum fc_els_cmd els_cmd,
- struct fc_seq_els_data *els_data);
-
-/*
- * This function is for seq_exch_abort function pointer in
- * struct libfc_function_template, see comment block on
- * seq_exch_abort for description of this function.
- */
-int fc_seq_exch_abort(const struct fc_seq *req_sp, unsigned int timer_msec);
-
-/*
- * Indicate that an exchange/sequence tuple is complete and the memory
- * allocated for the related objects may be freed.
- */
-void fc_exch_done(struct fc_seq *sp);
-
-/*
- * Allocate a new exchange and sequence pair.
- */
-struct fc_exch *fc_exch_alloc(struct fc_lport *lport, struct fc_frame *fp);
-/*
- * Start a new sequence on the same exchange as the supplied sequence.
- */
-struct fc_seq *fc_seq_start_next(struct fc_seq *sp);
-
-
-/*
- * Reset all EMs of a lport, releasing its all sequences and
- * exchanges. If sid is non-zero, then reset only exchanges
- * we sourced from that FID. If did is non-zero, reset only
- * exchanges destined to that FID.
- */
+void fc_exch_mgr_free(struct fc_lport *);
+void fc_exch_recv(struct fc_lport *, struct fc_frame *);
void fc_exch_mgr_reset(struct fc_lport *, u32 s_id, u32 d_id);
/*
* Functions for fc_functions_template
*/
-void fc_get_host_speed(struct Scsi_Host *shost);
-void fc_get_host_port_type(struct Scsi_Host *shost);
-void fc_get_host_port_state(struct Scsi_Host *shost);
-void fc_set_rport_loss_tmo(struct fc_rport *rport, u32 timeout);
+void fc_get_host_speed(struct Scsi_Host *);
+void fc_get_host_port_type(struct Scsi_Host *);
+void fc_get_host_port_state(struct Scsi_Host *);
+void fc_set_rport_loss_tmo(struct fc_rport *, u32 timeout);
struct fc_host_statistics *fc_get_host_stats(struct Scsi_Host *);
-/*
- * module setup functions.
- */
-int fc_setup_exch_mgr(void);
-void fc_destroy_exch_mgr(void);
-int fc_setup_rport(void);
-void fc_destroy_rport(void);
-
-/*
- * Internal libfc functions.
- */
-const char *fc_els_resp_type(struct fc_frame *);
-
#endif /* _LIBFC_H_ */
diff --git a/include/scsi/libfcoe.h b/include/scsi/libfcoe.h
index b241060..c603f4a 100644
--- a/include/scsi/libfcoe.h
+++ b/include/scsi/libfcoe.h
@@ -53,33 +53,36 @@ enum fip_state {
};
/**
- * struct fcoe_ctlr - FCoE Controller and FIP state.
- * @state: internal FIP state for network link and FIP or non-FIP mode.
- * @lp: &fc_lport: libfc local port.
- * @sel_fcf: currently selected FCF, or NULL.
- * @fcfs: list of discovered FCFs.
- * @fcf_count: number of discovered FCF entries.
- * @sol_time: time when a multicast solicitation was last sent.
- * @sel_time: time after which to select an FCF.
- * @port_ka_time: time of next port keep-alive.
- * @ctlr_ka_time: time of next controller keep-alive.
- * @timer: timer struct used for all delayed events.
- * @link_work: &work_struct for doing FCF selection.
- * @recv_work: &work_struct for receiving FIP frames.
+ * struct fcoe_ctlr - FCoE Controller and FIP state
+ * @state: internal FIP state for network link and FIP or non-FIP mode.
+ * @mode: LLD-selected mode.
+ * @lp: &fc_lport: libfc local port.
+ * @sel_fcf: currently selected FCF, or NULL.
+ * @fcfs: list of discovered FCFs.
+ * @fcf_count: number of discovered FCF entries.
+ * @sol_time: time when a multicast solicitation was last sent.
+ * @sel_time: time after which to select an FCF.
+ * @port_ka_time: time of next port keep-alive.
+ * @ctlr_ka_time: time of next controller keep-alive.
+ * @timer: timer struct used for all delayed events.
+ * @link_work: &work_struct for doing FCF selection.
+ * @recv_work: &work_struct for receiving FIP frames.
* @fip_recv_list: list of received FIP frames.
- * @user_mfs: configured maximum FC frame size, including FC header.
- * @flogi_oxid: exchange ID of most recent fabric login.
- * @flogi_count: number of FLOGI attempts in AUTO mode.
- * @link: current link status for libfc.
- * @last_link: last link state reported to libfc.
- * @map_dest: use the FC_MAP mode for destination MAC addresses.
- * @spma: supports SPMA server-provided MACs mode
- * @dest_addr: MAC address of the selected FC forwarder.
- * @ctl_src_addr: the native MAC address of our local port.
- * @data_src_addr: the assigned MAC address for the local port after FLOGI.
- * @send: LLD-supplied function to handle sending of FIP Ethernet frames.
- * @update_mac: LLD-supplied function to handle changes to MAC addresses.
- * @lock: lock protecting this structure.
+ * @user_mfs: configured maximum FC frame size, including FC header.
+ * @flogi_oxid: exchange ID of most recent fabric login.
+ * @flogi_count: number of FLOGI attempts in AUTO mode.
+ * @link: current link status for libfc.
+ * @last_link: last link state reported to libfc.
+ * @map_dest: use the FC_MAP mode for destination MAC addresses.
+ * @spma: supports SPMA server-provided MACs mode
+ * @send_ctlr_ka: need to send controller keep alive
+ * @send_port_ka: need to send port keep alives
+ * @dest_addr: MAC address of the selected FC forwarder.
+ * @ctl_src_addr: the native MAC address of our local port.
+ * @send: LLD-supplied function to handle sending FIP Ethernet frames
+ * @update_mac: LLD-supplied function to handle changes to MAC addresses.
+ * @get_src_addr: LLD-supplied function to supply a source MAC address.
+ * @lock: lock protecting this structure.
*
* This structure is used by all FCoE drivers. It contains information
* needed by all FCoE low-level drivers (LLDs) as well as internal state
@@ -87,6 +90,7 @@ enum fip_state {
*/
struct fcoe_ctlr {
enum fip_state state;
+ enum fip_state mode;
struct fc_lport *lp;
struct fcoe_fcf *sel_fcf;
struct list_head fcfs;
@@ -104,29 +108,32 @@ struct fcoe_ctlr {
u8 flogi_count;
u8 link;
u8 last_link;
+ u8 reset_req;
u8 map_dest;
u8 spma;
+ u8 send_ctlr_ka;
+ u8 send_port_ka;
u8 dest_addr[ETH_ALEN];
u8 ctl_src_addr[ETH_ALEN];
- u8 data_src_addr[ETH_ALEN];
void (*send)(struct fcoe_ctlr *, struct sk_buff *);
- void (*update_mac)(struct fcoe_ctlr *, u8 *old, u8 *new);
+ void (*update_mac)(struct fc_lport *, u8 *addr);
+ u8 * (*get_src_addr)(struct fc_lport *);
spinlock_t lock;
};
-/*
- * struct fcoe_fcf - Fibre-Channel Forwarder.
- * @list: list linkage.
- * @time: system time (jiffies) when an advertisement was last received.
- * @switch_name: WWN of switch from advertisement.
- * @fabric_name: WWN of fabric from advertisement.
- * @fc_map: FC_MAP value from advertisement.
- * @fcf_mac: Ethernet address of the FCF.
- * @vfid: virtual fabric ID.
- * @pri: seletion priority, smaller values are better.
- * @flags: flags received from advertisement.
- * @fka_period: keep-alive period, in jiffies.
+/**
+ * struct fcoe_fcf - Fibre-Channel Forwarder
+ * @list: list linkage
+ * @time: system time (jiffies) when an advertisement was last received
+ * @switch_name: WWN of switch from advertisement
+ * @fabric_name: WWN of fabric from advertisement
+ * @fc_map: FC_MAP value from advertisement
+ * @fcf_mac: Ethernet address of the FCF
+ * @vfid: virtual fabric ID
+ * @pri: selection priority, smaller values are better
+ * @flags: flags received from advertisement
+ * @fka_period: keep-alive period, in jiffies
*
* A Fibre-Channel Forwarder (FCF) is the entity on the Ethernet that
* passes FCoE frames on to an FC fabric. This structure represents
@@ -148,6 +155,7 @@ struct fcoe_fcf {
u8 pri;
u16 flags;
u32 fka_period;
+ u8 fd_flags:1;
};
/* FIP API functions */
@@ -155,9 +163,10 @@ void fcoe_ctlr_init(struct fcoe_ctlr *);
void fcoe_ctlr_destroy(struct fcoe_ctlr *);
void fcoe_ctlr_link_up(struct fcoe_ctlr *);
int fcoe_ctlr_link_down(struct fcoe_ctlr *);
-int fcoe_ctlr_els_send(struct fcoe_ctlr *, struct sk_buff *);
+int fcoe_ctlr_els_send(struct fcoe_ctlr *, struct fc_lport *, struct sk_buff *);
void fcoe_ctlr_recv(struct fcoe_ctlr *, struct sk_buff *);
-int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *, struct fc_frame *fp, u8 *sa);
+int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *, struct fc_lport *,
+ struct fc_frame *);
/* libfcoe funcs */
u64 fcoe_wwn_from_mac(unsigned char mac[], unsigned int, unsigned int);
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index a72edd4..7394e3b 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -267,6 +267,7 @@ struct iscsi_session {
/* configuration */
int abort_timeout;
int lu_reset_timeout;
+ int tgt_reset_timeout;
int initial_r2t_en;
unsigned max_r2t;
int imm_data_en;
@@ -333,7 +334,8 @@ struct iscsi_host {
/*
* scsi host template
*/
-extern int iscsi_change_queue_depth(struct scsi_device *sdev, int depth);
+extern int iscsi_change_queue_depth(struct scsi_device *sdev, int depth,
+ int reason);
extern int iscsi_eh_abort(struct scsi_cmnd *sc);
extern int iscsi_eh_target_reset(struct scsi_cmnd *sc);
extern int iscsi_eh_device_reset(struct scsi_cmnd *sc);
diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
index e78d3b6..9eaa3f0 100644
--- a/include/scsi/libsas.h
+++ b/include/scsi/libsas.h
@@ -634,7 +634,8 @@ extern int sas_target_alloc(struct scsi_target *);
extern int sas_slave_alloc(struct scsi_device *);
extern int sas_slave_configure(struct scsi_device *);
extern void sas_slave_destroy(struct scsi_device *);
-extern int sas_change_queue_depth(struct scsi_device *, int new_depth);
+extern int sas_change_queue_depth(struct scsi_device *, int new_depth,
+ int reason);
extern int sas_change_queue_type(struct scsi_device *, int qt);
extern int sas_bios_param(struct scsi_device *,
struct block_device *,
diff --git a/include/scsi/osd_initiator.h b/include/scsi/osd_initiator.h
index 02bd9f7..39d6d10 100644
--- a/include/scsi/osd_initiator.h
+++ b/include/scsi/osd_initiator.h
@@ -48,7 +48,6 @@ enum osd_std_version {
*/
struct osd_dev {
struct scsi_device *scsi_device;
- struct file *file;
unsigned def_timeout;
#ifdef OSD_VER1_SUPPORT
@@ -56,10 +55,24 @@ struct osd_dev {
#endif
};
-/* Retrieve/return osd_dev(s) for use by Kernel clients */
-struct osd_dev *osduld_path_lookup(const char *dev_name); /*Use IS_ERR/ERR_PTR*/
+/* Unique Identification of an OSD device */
+struct osd_dev_info {
+ unsigned systemid_len;
+ u8 systemid[OSD_SYSTEMID_LEN];
+ unsigned osdname_len;
+ u8 *osdname;
+};
+
+/* Retrieve/return osd_dev(s) for use by Kernel clients
+ * Use IS_ERR/ERR_PTR on returned "osd_dev *".
+ */
+struct osd_dev *osduld_path_lookup(const char *dev_name);
+struct osd_dev *osduld_info_lookup(const struct osd_dev_info *odi);
void osduld_put_device(struct osd_dev *od);
+const struct osd_dev_info *osduld_device_info(struct osd_dev *od);
+bool osduld_device_same(struct osd_dev *od, const struct osd_dev_info *odi);
+
/* Add/remove test ioctls from external modules */
typedef int (do_test_fn)(struct osd_dev *od, unsigned cmd, unsigned long arg);
int osduld_register_test(unsigned ioctl, do_test_fn *do_test);
@@ -69,8 +82,24 @@ void osduld_unregister_test(unsigned ioctl);
void osd_dev_init(struct osd_dev *od, struct scsi_device *scsi_device);
void osd_dev_fini(struct osd_dev *od);
-/* some hi level device operations */
-int osd_auto_detect_ver(struct osd_dev *od, void *caps); /* GFP_KERNEL */
+/**
+ * osd_auto_detect_ver - Detect the OSD version, return Unique Identification
+ *
+ * @od: OSD target lun handle
+ * @caps: Capabilities authorizing OSD root read attributes access
+ * @odi: Retrieved information uniquely identifying the osd target lun
+ * Note: odi->osdname must be kfreed by caller.
+ *
+ * Auto detects the OSD version of the OSD target and sets the @od
+ * accordingly. Meanwhile also returns the "system id" and "osd name" root
+ * attributes which uniquely identify the OSD target. This member is usually
+ * called by the ULD. ULD users should call osduld_device_info().
+ * This rutine allocates osd requests and memory at GFP_KERNEL level and might
+ * sleep.
+ */
+int osd_auto_detect_ver(struct osd_dev *od,
+ void *caps, struct osd_dev_info *odi);
+
static inline struct request_queue *osd_request_queue(struct osd_dev *od)
{
return od->scsi_device->request_queue;
@@ -84,6 +113,15 @@ static inline void osd_dev_set_ver(struct osd_dev *od, enum osd_std_version v)
#endif
}
+static inline bool osd_dev_is_ver1(struct osd_dev *od)
+{
+#ifdef OSD_VER1_SUPPORT
+ return od->version == OSD_VER1;
+#else
+ return false;
+#endif
+}
+
struct osd_request;
typedef void (osd_req_done_fn)(struct osd_request *or, void *private);
@@ -120,14 +158,9 @@ struct osd_request {
int async_error;
};
-/* OSD Version control */
static inline bool osd_req_is_ver1(struct osd_request *or)
{
-#ifdef OSD_VER1_SUPPORT
- return or->osd_dev->version == OSD_VER1;
-#else
- return false;
-#endif
+ return osd_dev_is_ver1(or->osd_dev);
}
/*
@@ -234,7 +267,7 @@ int osd_execute_request_async(struct osd_request *or,
* @bad_attr_list - List of failing attributes (optional)
* @max_attr - Size of @bad_attr_list.
*
- * After execution, sense + return code can be analyzed using this function. The
+ * After execution, osd_request results are analyzed using this function. The
* return code is the final disposition on the error. So it is possible that a
* CHECK_CONDITION was returned from target but this will return NO_ERROR, for
* example on recovered errors. All parameters are optional if caller does
@@ -243,7 +276,31 @@ int osd_execute_request_async(struct osd_request *or,
* of the SCSI_OSD_DPRINT_SENSE Kconfig value. Set @silent if you know the
* command would routinely fail, to not spam the dmsg file.
*/
+
+/**
+ * osd_err_priority - osd categorized return codes in ascending severity.
+ *
+ * The categories are borrowed from the pnfs_osd_errno enum.
+ * See comments for translated Linux codes returned by osd_req_decode_sense.
+ */
+enum osd_err_priority {
+ OSD_ERR_PRI_NO_ERROR = 0,
+ /* Recoverable, caller should clear_highpage() all pages */
+ OSD_ERR_PRI_CLEAR_PAGES = 1, /* -EFAULT */
+ OSD_ERR_PRI_RESOURCE = 2, /* -ENOMEM */
+ OSD_ERR_PRI_BAD_CRED = 3, /* -EINVAL */
+ OSD_ERR_PRI_NO_ACCESS = 4, /* -EACCES */
+ OSD_ERR_PRI_UNREACHABLE = 5, /* any other */
+ OSD_ERR_PRI_NOT_FOUND = 6, /* -ENOENT */
+ OSD_ERR_PRI_NO_SPACE = 7, /* -ENOSPC */
+ OSD_ERR_PRI_EIO = 8, /* -EIO */
+};
+
struct osd_sense_info {
+ u64 out_resid; /* Zero on success otherwise out residual */
+ u64 in_resid; /* Zero on success otherwise in residual */
+ enum osd_err_priority osd_err_pri;
+
int key; /* one of enum scsi_sense_keys */
int additional_code ; /* enum osd_additional_sense_codes */
union { /* Sense specific information */
diff --git a/include/scsi/osd_protocol.h b/include/scsi/osd_protocol.h
index 2cc8e8b..6856612 100644
--- a/include/scsi/osd_protocol.h
+++ b/include/scsi/osd_protocol.h
@@ -17,6 +17,7 @@
#define __OSD_PROTOCOL_H__
#include <linux/types.h>
+#include <linux/kernel.h>
#include <asm/unaligned.h>
#include <scsi/scsi.h>
diff --git a/include/scsi/osd_sense.h b/include/scsi/osd_sense.h
index ff9b33c..91db543 100644
--- a/include/scsi/osd_sense.h
+++ b/include/scsi/osd_sense.h
@@ -255,6 +255,9 @@ enum osdv2_cdb_field_offset {
OSD_CFO_STARTING_BYTE = OSD_CDB_OFFSET(v2.start_address),
OSD_CFO_PARTITION_ID = OSD_CDB_OFFSET(partition),
OSD_CFO_OBJECT_ID = OSD_CDB_OFFSET(object),
+ OSD_CFO_PERMISSIONS = sizeof(struct osd_cdb_head) +
+ offsetof(struct osd_capability_head,
+ permissions_bit_mask),
};
#endif /* ndef __OSD_SENSE_H__ */
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
index 34c46ab..8b4deca 100644
--- a/include/scsi/scsi.h
+++ b/include/scsi/scsi.h
@@ -94,6 +94,7 @@ struct scsi_cmnd;
#define WRITE_LONG 0x3f
#define CHANGE_DEFINITION 0x40
#define WRITE_SAME 0x41
+#define UNMAP 0x42
#define READ_TOC 0x43
#define LOG_SELECT 0x4c
#define LOG_SENSE 0x4d
@@ -122,9 +123,11 @@ struct scsi_cmnd;
#define READ_16 0x88
#define WRITE_16 0x8a
#define VERIFY_16 0x8f
+#define WRITE_SAME_16 0x93
#define SERVICE_ACTION_IN 0x9e
/* values for service action in */
#define SAI_READ_CAPACITY_16 0x10
+#define SAI_GET_LBA_STATUS 0x12
/* values for maintenance in */
#define MI_REPORT_TARGET_PGS 0x0a
/* values for maintenance out */
@@ -132,6 +135,7 @@ struct scsi_cmnd;
/* values for variable length command */
#define READ_32 0x09
#define WRITE_32 0x0b
+#define WRITE_SAME_32 0x0d
/* Values for T10/04-262r7 */
#define ATA_16 0x85 /* 16-byte pass-thru */
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index f097ae3..7c44499 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -81,11 +81,14 @@ struct scsi_device {
struct list_head starved_entry;
struct scsi_cmnd *current_cmnd; /* currently active command */
unsigned short queue_depth; /* How deep of a queue we want */
+ unsigned short max_queue_depth; /* max queue depth */
unsigned short last_queue_full_depth; /* These two are used by */
unsigned short last_queue_full_count; /* scsi_track_queue_full() */
- unsigned long last_queue_full_time;/* don't let QUEUE_FULLs on the same
- jiffie count on our counter, they
- could all be from the same event. */
+ unsigned long last_queue_full_time; /* last queue full time */
+ unsigned long queue_ramp_up_period; /* ramp up period in jiffies */
+#define SCSI_DEFAULT_RAMP_UP_PERIOD (120 * HZ)
+
+ unsigned long last_queue_ramp_up; /* last queue ramp up time */
unsigned int id, lun, channel;
@@ -175,6 +178,7 @@ struct scsi_dh_devlist {
char *model;
};
+typedef void (*activate_complete)(void *, int);
struct scsi_device_handler {
/* Used by the infrastructure */
struct list_head list; /* list of scsi_device_handlers */
@@ -186,7 +190,7 @@ struct scsi_device_handler {
int (*check_sense)(struct scsi_device *, struct scsi_sense_hdr *);
int (*attach)(struct scsi_device *);
void (*detach)(struct scsi_device *);
- int (*activate)(struct scsi_device *);
+ int (*activate)(struct scsi_device *, activate_complete, void *);
int (*prep_fn)(struct scsi_device *, struct request *);
int (*set_params)(struct scsi_device *, const char *);
};
diff --git a/include/scsi/scsi_dh.h b/include/scsi/scsi_dh.h
index ff24074..e3f2db2 100644
--- a/include/scsi/scsi_dh.h
+++ b/include/scsi/scsi_dh.h
@@ -56,14 +56,16 @@ enum {
SCSI_DH_DRIVER_MAX,
};
#if defined(CONFIG_SCSI_DH) || defined(CONFIG_SCSI_DH_MODULE)
-extern int scsi_dh_activate(struct request_queue *);
+extern int scsi_dh_activate(struct request_queue *, activate_complete, void *);
extern int scsi_dh_handler_exist(const char *);
extern int scsi_dh_attach(struct request_queue *, const char *);
extern void scsi_dh_detach(struct request_queue *);
extern int scsi_dh_set_params(struct request_queue *, const char *);
#else
-static inline int scsi_dh_activate(struct request_queue *req)
+static inline int scsi_dh_activate(struct request_queue *req,
+ activate_complete fn, void *data)
{
+ fn(data, 0);
return 0;
}
static inline int scsi_dh_handler_exist(const char *name)
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index 47941fc..c50a97f 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -43,6 +43,12 @@ struct blk_queue_tags;
#define DISABLE_CLUSTERING 0
#define ENABLE_CLUSTERING 1
+enum {
+ SCSI_QDEPTH_DEFAULT, /* default requested change, e.g. from sysfs */
+ SCSI_QDEPTH_QFULL, /* scsi-ml requested due to queue full */
+ SCSI_QDEPTH_RAMP_UP, /* scsi-ml requested due to threshhold event */
+};
+
struct scsi_host_template {
struct module *module;
const char *name;
@@ -294,7 +300,7 @@ struct scsi_host_template {
*
* Status: OPTIONAL
*/
- int (* change_queue_depth)(struct scsi_device *, int);
+ int (* change_queue_depth)(struct scsi_device *, int, int);
/*
* Fill in this function to allow the changing of tag types
@@ -677,6 +683,12 @@ struct Scsi_Host {
void *shost_data;
/*
+ * Points to the physical bus device we'd use to do DMA
+ * Needed just in case we have virtual hosts.
+ */
+ struct device *dma_dev;
+
+ /*
* We should ensure that this is aligned, both for better performance
* and also because some compilers (m68k) don't automatically force
* alignment to a long boundary.
@@ -720,7 +732,9 @@ extern int scsi_queue_work(struct Scsi_Host *, struct work_struct *);
extern void scsi_flush_work(struct Scsi_Host *);
extern struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *, int);
-extern int __must_check scsi_add_host(struct Scsi_Host *, struct device *);
+extern int __must_check scsi_add_host_with_dma(struct Scsi_Host *,
+ struct device *,
+ struct device *);
extern void scsi_scan_host(struct Scsi_Host *);
extern void scsi_rescan_device(struct device *);
extern void scsi_remove_host(struct Scsi_Host *);
@@ -731,6 +745,12 @@ extern const char *scsi_host_state_name(enum scsi_host_state);
extern u64 scsi_calculate_bounce_limit(struct Scsi_Host *);
+static inline int __must_check scsi_add_host(struct Scsi_Host *host,
+ struct device *dev)
+{
+ return scsi_add_host_with_dma(host, dev, dev);
+}
+
static inline struct device *scsi_get_device(struct Scsi_Host *shost)
{
return shost->shost_gendev.parent;
diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h
index fc50bd6..8e86a94 100644
--- a/include/scsi/scsi_transport_fc.h
+++ b/include/scsi/scsi_transport_fc.h
@@ -807,5 +807,6 @@ void fc_host_post_vendor_event(struct Scsi_Host *shost, u32 event_number,
struct fc_vport *fc_vport_create(struct Scsi_Host *shost, int channel,
struct fc_vport_identifiers *);
int fc_vport_terminate(struct fc_vport *vport);
+void fc_block_scsi_eh(struct scsi_cmnd *cmnd);
#endif /* SCSI_TRANSPORT_FC_H */
diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h
index 3dae3f7..4940045 100644
--- a/include/sound/ac97_codec.h
+++ b/include/sound/ac97_codec.h
@@ -593,7 +593,7 @@ enum {
struct ac97_quirk {
unsigned short subvendor; /* PCI subsystem vendor id */
- unsigned short subdevice; /* PCI sybsystem device id */
+ unsigned short subdevice; /* PCI subsystem device id */
unsigned short mask; /* device id bit mask, 0 = accept all */
unsigned int codec_id; /* codec id (if any), 0 = accept all */
const char *name; /* name shown as info */
diff --git a/include/sound/wm8993.h b/include/sound/wm8993.h
index 9c661f2..eee19f6 100644
--- a/include/sound/wm8993.h
+++ b/include/sound/wm8993.h
@@ -36,7 +36,7 @@ struct wm8993_platform_data {
unsigned int micbias1_lvl:1;
unsigned int micbias2_lvl:1;
- /* Jack detect threashold levels, see datasheet for values */
+ /* Jack detect threshold levels, see datasheet for values */
unsigned int jd_scthr:2;
unsigned int jd_thr:2;
};
diff --git a/include/video/sgivw.h b/include/video/sgivw.h
index 55f2a7c..f6aa569 100644
--- a/include/video/sgivw.h
+++ b/include/video/sgivw.h
@@ -351,7 +351,7 @@ typedef enum {
struct dbe_timing_info
{
dbe_timing_t type;
- int flags;
+ int flags;
short width; /* Monitor resolution */
short height;
int fields_sec; /* fields/sec (Hz -3 dec. places */
@@ -389,11 +389,11 @@ struct dbe_timing_info dbeVTimings[] = {
{
DBE_VT_640_480_60,
/* flags, width, height, fields_sec, cfreq */
- 0, 640, 480, 59940, 25175,
+ 0, 640, 480, 59940, 25175,
/* htotal, hblank_start, hblank_end, hsync_start, hsync_end */
- 800, 640, 800, 656, 752,
+ 800, 640, 800, 656, 752,
/* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */
- 525, 480, 525, 490, 492,
+ 525, 480, 525, 490, 492,
/* pll_m, pll_n, pll_p */
15, 2, 3
},
@@ -650,7 +650,7 @@ struct dbe_timing_info dbeVTimings[] = {
/* pll_m, pll_n, pll_p */
6, 1, 0
},
-
+
{
DBE_VT_1920_1200_60,
/* flags, width, height, fields_sec, cfreq */
@@ -676,7 +676,6 @@ struct dbe_timing_info dbeVTimings[] = {
}
};
-#define DBE_VT_SIZE (sizeof(dbeVTimings)/sizeof(dbeVTimings[0]))
#endif // INCLUDE_TIMING_TABLE_DATA
#endif // ! __SGIVWFB_H__
diff --git a/init/Kconfig b/init/Kconfig
index 3889924..54c655c 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -615,7 +615,7 @@ config SYSFS_DEPRECATED
bool
config SYSFS_DEPRECATED_V2
- bool "enable deprecated sysfs features which may confuse old userspace tools"
+ bool "enable deprecated sysfs features to support old userspace tools"
depends on SYSFS
default n
select SYSFS_DEPRECATED
diff --git a/init/calibrate.c b/init/calibrate.c
index a379c90..6eb48e5 100644
--- a/init/calibrate.c
+++ b/init/calibrate.c
@@ -123,23 +123,26 @@ void __cpuinit calibrate_delay(void)
{
unsigned long ticks, loopbit;
int lps_precision = LPS_PREC;
+ static bool printed;
if (preset_lpj) {
loops_per_jiffy = preset_lpj;
- printk(KERN_INFO
- "Calibrating delay loop (skipped) preset value.. ");
- } else if ((smp_processor_id() == 0) && lpj_fine) {
+ if (!printed)
+ pr_info("Calibrating delay loop (skipped) "
+ "preset value.. ");
+ } else if ((!printed) && lpj_fine) {
loops_per_jiffy = lpj_fine;
- printk(KERN_INFO
- "Calibrating delay loop (skipped), "
+ pr_info("Calibrating delay loop (skipped), "
"value calculated using timer frequency.. ");
} else if ((loops_per_jiffy = calibrate_delay_direct()) != 0) {
- printk(KERN_INFO
- "Calibrating delay using timer specific routine.. ");
+ if (!printed)
+ pr_info("Calibrating delay using timer "
+ "specific routine.. ");
} else {
loops_per_jiffy = (1<<12);
- printk(KERN_INFO "Calibrating delay loop... ");
+ if (!printed)
+ pr_info("Calibrating delay loop... ");
while ((loops_per_jiffy <<= 1) != 0) {
/* wait for "start of" clock tick */
ticks = jiffies;
@@ -170,7 +173,10 @@ void __cpuinit calibrate_delay(void)
loops_per_jiffy &= ~loopbit;
}
}
- printk(KERN_CONT "%lu.%02lu BogoMIPS (lpj=%lu)\n",
+ if (!printed)
+ pr_cont("%lu.%02lu BogoMIPS (lpj=%lu)\n",
loops_per_jiffy/(500000/HZ),
(loops_per_jiffy/(5000/HZ)) % 100, loops_per_jiffy);
+
+ printed = true;
}
diff --git a/ipc/msg.c b/ipc/msg.c
index 2ceab7f..085bd58 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -412,7 +412,7 @@ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
struct msqid_ds __user *buf, int version)
{
struct kern_ipc_perm *ipcp;
- struct msqid64_ds msqid64;
+ struct msqid64_ds uninitialized_var(msqid64);
struct msg_queue *msq;
int err;
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 6ba0f1e..7c4e271 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -392,10 +392,9 @@ int disable_nonboot_cpus(void)
if (cpu == first_cpu)
continue;
error = _cpu_down(cpu, 1);
- if (!error) {
+ if (!error)
cpumask_set_cpu(cpu, frozen_cpus);
- printk("CPU%d is down\n", cpu);
- } else {
+ else {
printk(KERN_ERR "Error taking CPU%d down: %d\n",
cpu, error);
break;
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index 3e1c36e..ede5277 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -1238,7 +1238,8 @@ hrtimer_interrupt_hanging(struct clock_event_device *dev,
force_clock_reprogram = 1;
dev->min_delta_ns = (unsigned long)try_time.tv64 * 3;
printk(KERN_WARNING "hrtimer: interrupt too slow, "
- "forcing clock min delta to %lu ns\n", dev->min_delta_ns);
+ "forcing clock min delta to %llu ns\n",
+ (unsigned long long) dev->min_delta_ns);
}
/*
* High resolution timer interrupt
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index bde4c66..7305b29 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -1067,7 +1067,7 @@ int request_threaded_irq(unsigned int irq, irq_handler_t handler,
kfree(action);
#ifdef CONFIG_DEBUG_SHIRQ
- if (irqflags & IRQF_SHARED) {
+ if (!retval && (irqflags & IRQF_SHARED)) {
/*
* It's a shared IRQ -- the driver ought to be prepared for it
* to happen immediately, so let's make sure....
diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c
index 22b0a6e..e49ea1c 100644
--- a/kernel/irq/spurious.c
+++ b/kernel/irq/spurious.c
@@ -220,7 +220,7 @@ void note_interrupt(unsigned int irq, struct irq_desc *desc,
/*
* If we are seeing only the odd spurious IRQ caused by
* bus asynchronicity then don't eventually trigger an error,
- * otherwise the couter becomes a doomsday timer for otherwise
+ * otherwise the counter becomes a doomsday timer for otherwise
* working systems
*/
if (time_after(jiffies, desc->last_unhandled + HZ/10))
diff --git a/kernel/itimer.c b/kernel/itimer.c
index b03451e..d802883 100644
--- a/kernel/itimer.c
+++ b/kernel/itimer.c
@@ -146,6 +146,7 @@ static void set_cpu_itimer(struct task_struct *tsk, unsigned int clock_id,
{
cputime_t cval, nval, cinterval, ninterval;
s64 ns_ninterval, ns_nval;
+ u32 error, incr_error;
struct cpu_itimer *it = &tsk->signal->it[clock_id];
nval = timeval_to_cputime(&value->it_value);
@@ -153,8 +154,8 @@ static void set_cpu_itimer(struct task_struct *tsk, unsigned int clock_id,
ninterval = timeval_to_cputime(&value->it_interval);
ns_ninterval = timeval_to_ns(&value->it_interval);
- it->incr_error = cputime_sub_ns(ninterval, ns_ninterval);
- it->error = cputime_sub_ns(nval, ns_nval);
+ error = cputime_sub_ns(nval, ns_nval);
+ incr_error = cputime_sub_ns(ninterval, ns_ninterval);
spin_lock_irq(&tsk->sighand->siglock);
@@ -168,6 +169,8 @@ static void set_cpu_itimer(struct task_struct *tsk, unsigned int clock_id,
}
it->expires = nval;
it->incr = ninterval;
+ it->error = error;
+ it->incr_error = incr_error;
trace_itimer_state(clock_id == CPUCLOCK_VIRT ?
ITIMER_VIRTUAL : ITIMER_PROF, value, nval);
diff --git a/kernel/perf_event.c b/kernel/perf_event.c
index 6b7ddba..40a996e 100644
--- a/kernel/perf_event.c
+++ b/kernel/perf_event.c
@@ -476,7 +476,7 @@ static void perf_event_remove_from_context(struct perf_event *event)
if (!task) {
/*
* Per cpu events are removed via an smp call and
- * the removal is always sucessful.
+ * the removal is always successful.
*/
smp_call_function_single(event->cpu,
__perf_event_remove_from_context,
@@ -845,7 +845,7 @@ perf_install_in_context(struct perf_event_context *ctx,
if (!task) {
/*
* Per cpu events are installed via an smp call and
- * the install is always sucessful.
+ * the install is always successful.
*/
smp_call_function_single(cpu, __perf_install_in_context,
event, 1);
diff --git a/kernel/pm_qos_params.c b/kernel/pm_qos_params.c
index dfdec52..3db49b9 100644
--- a/kernel/pm_qos_params.c
+++ b/kernel/pm_qos_params.c
@@ -29,7 +29,6 @@
#include <linux/pm_qos_params.h>
#include <linux/sched.h>
-#include <linux/smp_lock.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/time.h>
@@ -344,37 +343,33 @@ int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier)
}
EXPORT_SYMBOL_GPL(pm_qos_remove_notifier);
-#define PID_NAME_LEN sizeof("process_1234567890")
-static char name[PID_NAME_LEN];
+#define PID_NAME_LEN 32
static int pm_qos_power_open(struct inode *inode, struct file *filp)
{
int ret;
long pm_qos_class;
+ char name[PID_NAME_LEN];
- lock_kernel();
pm_qos_class = find_pm_qos_object_by_minor(iminor(inode));
if (pm_qos_class >= 0) {
filp->private_data = (void *)pm_qos_class;
- sprintf(name, "process_%d", current->pid);
+ snprintf(name, PID_NAME_LEN, "process_%d", current->pid);
ret = pm_qos_add_requirement(pm_qos_class, name,
PM_QOS_DEFAULT_VALUE);
- if (ret >= 0) {
- unlock_kernel();
+ if (ret >= 0)
return 0;
- }
}
- unlock_kernel();
-
return -EPERM;
}
static int pm_qos_power_release(struct inode *inode, struct file *filp)
{
int pm_qos_class;
+ char name[PID_NAME_LEN];
pm_qos_class = (long)filp->private_data;
- sprintf(name, "process_%d", current->pid);
+ snprintf(name, PID_NAME_LEN, "process_%d", current->pid);
pm_qos_remove_requirement(pm_qos_class, name);
return 0;
@@ -385,13 +380,14 @@ static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
{
s32 value;
int pm_qos_class;
+ char name[PID_NAME_LEN];
pm_qos_class = (long)filp->private_data;
if (count != sizeof(s32))
return -EINVAL;
if (copy_from_user(&value, buf, sizeof(s32)))
return -EFAULT;
- sprintf(name, "process_%d", current->pid);
+ snprintf(name, PID_NAME_LEN, "process_%d", current->pid);
pm_qos_update_requirement(pm_qos_class, name, value);
return sizeof(s32);
diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c
index 5c9dc22..438ff45 100644
--- a/kernel/posix-cpu-timers.c
+++ b/kernel/posix-cpu-timers.c
@@ -384,7 +384,8 @@ int posix_cpu_clock_get(const clockid_t which_clock, struct timespec *tp)
/*
* Validate the clockid_t for a new CPU-clock timer, and initialize the timer.
- * This is called from sys_timer_create with the new timer already locked.
+ * This is called from sys_timer_create() and do_cpu_nanosleep() with the
+ * new timer already all-zeros initialized.
*/
int posix_cpu_timer_create(struct k_itimer *new_timer)
{
@@ -396,8 +397,6 @@ int posix_cpu_timer_create(struct k_itimer *new_timer)
return -EINVAL;
INIT_LIST_HEAD(&new_timer->it.cpu.entry);
- new_timer->it.cpu.incr.sched = 0;
- new_timer->it.cpu.expires.sched = 0;
read_lock(&tasklist_lock);
if (CPUCLOCK_PERTHREAD(new_timer->it_clock)) {
diff --git a/kernel/sys.c b/kernel/sys.c
index 9968c5f..585d6cd 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -8,7 +8,6 @@
#include <linux/mm.h>
#include <linux/utsname.h>
#include <linux/mman.h>
-#include <linux/smp_lock.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
#include <linux/prctl.h>
@@ -349,6 +348,9 @@ void kernel_power_off(void)
machine_power_off();
}
EXPORT_SYMBOL_GPL(kernel_power_off);
+
+static DEFINE_MUTEX(reboot_mutex);
+
/*
* Reboot system call: for obvious reasons only root may call it,
* and even root needs to set up some magic numbers in the registers
@@ -381,7 +383,7 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off)
cmd = LINUX_REBOOT_CMD_HALT;
- lock_kernel();
+ mutex_lock(&reboot_mutex);
switch (cmd) {
case LINUX_REBOOT_CMD_RESTART:
kernel_restart(NULL);
@@ -397,20 +399,18 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
case LINUX_REBOOT_CMD_HALT:
kernel_halt();
- unlock_kernel();
do_exit(0);
panic("cannot halt");
case LINUX_REBOOT_CMD_POWER_OFF:
kernel_power_off();
- unlock_kernel();
do_exit(0);
break;
case LINUX_REBOOT_CMD_RESTART2:
if (strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1) < 0) {
- unlock_kernel();
- return -EFAULT;
+ ret = -EFAULT;
+ break;
}
buffer[sizeof(buffer) - 1] = '\0';
@@ -433,7 +433,7 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
ret = -EINVAL;
break;
}
- unlock_kernel();
+ mutex_unlock(&reboot_mutex);
return ret;
}
diff --git a/kernel/time.c b/kernel/time.c
index 8047980..c6324d9 100644
--- a/kernel/time.c
+++ b/kernel/time.c
@@ -136,7 +136,6 @@ static inline void warp_clock(void)
write_seqlock_irq(&xtime_lock);
wall_to_monotonic.tv_sec -= sys_tz.tz_minuteswest * 60;
xtime.tv_sec += sys_tz.tz_minuteswest * 60;
- update_xtime_cache(0);
write_sequnlock_irq(&xtime_lock);
clock_was_set();
}
diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c
index 620b58a..20a8920 100644
--- a/kernel/time/clockevents.c
+++ b/kernel/time/clockevents.c
@@ -20,6 +20,8 @@
#include <linux/sysdev.h>
#include <linux/tick.h>
+#include "tick-internal.h"
+
/* The registered clock event devices */
static LIST_HEAD(clockevent_devices);
static LIST_HEAD(clockevents_released);
@@ -37,10 +39,9 @@ static DEFINE_SPINLOCK(clockevents_lock);
*
* Math helper, returns latch value converted to nanoseconds (bound checked)
*/
-unsigned long clockevent_delta2ns(unsigned long latch,
- struct clock_event_device *evt)
+u64 clockevent_delta2ns(unsigned long latch, struct clock_event_device *evt)
{
- u64 clc = ((u64) latch << evt->shift);
+ u64 clc = (u64) latch << evt->shift;
if (unlikely(!evt->mult)) {
evt->mult = 1;
@@ -50,10 +51,10 @@ unsigned long clockevent_delta2ns(unsigned long latch,
do_div(clc, evt->mult);
if (clc < 1000)
clc = 1000;
- if (clc > LONG_MAX)
- clc = LONG_MAX;
+ if (clc > KTIME_MAX)
+ clc = KTIME_MAX;
- return (unsigned long) clc;
+ return clc;
}
EXPORT_SYMBOL_GPL(clockevent_delta2ns);
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index 4a31090..e85c234 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -107,6 +107,59 @@ u64 timecounter_cyc2time(struct timecounter *tc,
}
EXPORT_SYMBOL_GPL(timecounter_cyc2time);
+/**
+ * clocks_calc_mult_shift - calculate mult/shift factors for scaled math of clocks
+ * @mult: pointer to mult variable
+ * @shift: pointer to shift variable
+ * @from: frequency to convert from
+ * @to: frequency to convert to
+ * @minsec: guaranteed runtime conversion range in seconds
+ *
+ * The function evaluates the shift/mult pair for the scaled math
+ * operations of clocksources and clockevents.
+ *
+ * @to and @from are frequency values in HZ. For clock sources @to is
+ * NSEC_PER_SEC == 1GHz and @from is the counter frequency. For clock
+ * event @to is the counter frequency and @from is NSEC_PER_SEC.
+ *
+ * The @minsec conversion range argument controls the time frame in
+ * seconds which must be covered by the runtime conversion with the
+ * calculated mult and shift factors. This guarantees that no 64bit
+ * overflow happens when the input value of the conversion is
+ * multiplied with the calculated mult factor. Larger ranges may
+ * reduce the conversion accuracy by chosing smaller mult and shift
+ * factors.
+ */
+void
+clocks_calc_mult_shift(u32 *mult, u32 *shift, u32 from, u32 to, u32 minsec)
+{
+ u64 tmp;
+ u32 sft, sftacc= 32;
+
+ /*
+ * Calculate the shift factor which is limiting the conversion
+ * range:
+ */
+ tmp = ((u64)minsec * from) >> 32;
+ while (tmp) {
+ tmp >>=1;
+ sftacc--;
+ }
+
+ /*
+ * Find the conversion shift/mult pair which has the best
+ * accuracy and fits the maxsec conversion range:
+ */
+ for (sft = 32; sft > 0; sft--) {
+ tmp = (u64) to << sft;
+ do_div(tmp, from);
+ if ((tmp >> sftacc) == 0)
+ break;
+ }
+ *mult = tmp;
+ *shift = sft;
+}
+
/*[Clocksource internal variables]---------
* curr_clocksource:
* currently selected clocksource.
@@ -413,6 +466,47 @@ void clocksource_touch_watchdog(void)
clocksource_resume_watchdog();
}
+/**
+ * clocksource_max_deferment - Returns max time the clocksource can be deferred
+ * @cs: Pointer to clocksource
+ *
+ */
+static u64 clocksource_max_deferment(struct clocksource *cs)
+{
+ u64 max_nsecs, max_cycles;
+
+ /*
+ * Calculate the maximum number of cycles that we can pass to the
+ * cyc2ns function without overflowing a 64-bit signed result. The
+ * maximum number of cycles is equal to ULLONG_MAX/cs->mult which
+ * is equivalent to the below.
+ * max_cycles < (2^63)/cs->mult
+ * max_cycles < 2^(log2((2^63)/cs->mult))
+ * max_cycles < 2^(log2(2^63) - log2(cs->mult))
+ * max_cycles < 2^(63 - log2(cs->mult))
+ * max_cycles < 1 << (63 - log2(cs->mult))
+ * Please note that we add 1 to the result of the log2 to account for
+ * any rounding errors, ensure the above inequality is satisfied and
+ * no overflow will occur.
+ */
+ max_cycles = 1ULL << (63 - (ilog2(cs->mult) + 1));
+
+ /*
+ * The actual maximum number of cycles we can defer the clocksource is
+ * determined by the minimum of max_cycles and cs->mask.
+ */
+ max_cycles = min_t(u64, max_cycles, (u64) cs->mask);
+ max_nsecs = clocksource_cyc2ns(max_cycles, cs->mult, cs->shift);
+
+ /*
+ * To ensure that the clocksource does not wrap whilst we are idle,
+ * limit the time the clocksource can be deferred by 12.5%. Please
+ * note a margin of 12.5% is used because this can be computed with
+ * a shift, versus say 10% which would require division.
+ */
+ return max_nsecs - (max_nsecs >> 5);
+}
+
#ifdef CONFIG_GENERIC_TIME
/**
@@ -511,6 +605,9 @@ static void clocksource_enqueue(struct clocksource *cs)
*/
int clocksource_register(struct clocksource *cs)
{
+ /* calculate max idle time permitted for this clocksource */
+ cs->max_idle_ns = clocksource_max_deferment(cs);
+
mutex_lock(&clocksource_mutex);
clocksource_enqueue(cs);
clocksource_select();
@@ -580,7 +677,7 @@ sysfs_show_current_clocksources(struct sys_device *dev,
* @count: length of buffer
*
* Takes input from sysfs interface for manually overriding the default
- * clocksource selction.
+ * clocksource selection.
*/
static ssize_t sysfs_override_clocksource(struct sys_device *dev,
struct sysdev_attribute *attr,
diff --git a/kernel/time/tick-oneshot.c b/kernel/time/tick-oneshot.c
index a96c0e2..0a8a213 100644
--- a/kernel/time/tick-oneshot.c
+++ b/kernel/time/tick-oneshot.c
@@ -50,9 +50,9 @@ int tick_dev_program_event(struct clock_event_device *dev, ktime_t expires,
dev->min_delta_ns += dev->min_delta_ns >> 1;
printk(KERN_WARNING
- "CE: %s increasing min_delta_ns to %lu nsec\n",
+ "CE: %s increasing min_delta_ns to %llu nsec\n",
dev->name ? dev->name : "?",
- dev->min_delta_ns << 1);
+ (unsigned long long) dev->min_delta_ns << 1);
i = 0;
}
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index 89aed59..f992762 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -134,18 +134,13 @@ __setup("nohz=", setup_tick_nohz);
* value. We do this unconditionally on any cpu, as we don't know whether the
* cpu, which has the update task assigned is in a long sleep.
*/
-static void tick_nohz_update_jiffies(void)
+static void tick_nohz_update_jiffies(ktime_t now)
{
int cpu = smp_processor_id();
struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
unsigned long flags;
- ktime_t now;
-
- if (!ts->tick_stopped)
- return;
cpumask_clear_cpu(cpu, nohz_cpu_mask);
- now = ktime_get();
ts->idle_waketime = now;
local_irq_save(flags);
@@ -155,20 +150,17 @@ static void tick_nohz_update_jiffies(void)
touch_softlockup_watchdog();
}
-static void tick_nohz_stop_idle(int cpu)
+static void tick_nohz_stop_idle(int cpu, ktime_t now)
{
struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
+ ktime_t delta;
- if (ts->idle_active) {
- ktime_t now, delta;
- now = ktime_get();
- delta = ktime_sub(now, ts->idle_entrytime);
- ts->idle_lastupdate = now;
- ts->idle_sleeptime = ktime_add(ts->idle_sleeptime, delta);
- ts->idle_active = 0;
+ delta = ktime_sub(now, ts->idle_entrytime);
+ ts->idle_lastupdate = now;
+ ts->idle_sleeptime = ktime_add(ts->idle_sleeptime, delta);
+ ts->idle_active = 0;
- sched_clock_idle_wakeup_event(0);
- }
+ sched_clock_idle_wakeup_event(0);
}
static ktime_t tick_nohz_start_idle(struct tick_sched *ts)
@@ -216,6 +208,7 @@ void tick_nohz_stop_sched_tick(int inidle)
struct tick_sched *ts;
ktime_t last_update, expires, now;
struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev;
+ u64 time_delta;
int cpu;
local_irq_save(flags);
@@ -263,7 +256,7 @@ void tick_nohz_stop_sched_tick(int inidle)
if (ratelimit < 10) {
printk(KERN_ERR "NOHZ: local_softirq_pending %02x\n",
- local_softirq_pending());
+ (unsigned int) local_softirq_pending());
ratelimit++;
}
goto end;
@@ -275,14 +268,18 @@ void tick_nohz_stop_sched_tick(int inidle)
seq = read_seqbegin(&xtime_lock);
last_update = last_jiffies_update;
last_jiffies = jiffies;
+ time_delta = timekeeping_max_deferment();
} while (read_seqretry(&xtime_lock, seq));
- /* Get the next timer wheel timer */
- next_jiffies = get_next_timer_interrupt(last_jiffies);
- delta_jiffies = next_jiffies - last_jiffies;
-
- if (rcu_needs_cpu(cpu) || printk_needs_cpu(cpu))
+ if (rcu_needs_cpu(cpu) || printk_needs_cpu(cpu) ||
+ arch_needs_cpu(cpu)) {
+ next_jiffies = last_jiffies + 1;
delta_jiffies = 1;
+ } else {
+ /* Get the next timer wheel timer */
+ next_jiffies = get_next_timer_interrupt(last_jiffies);
+ delta_jiffies = next_jiffies - last_jiffies;
+ }
/*
* Do not stop the tick, if we are only one off
* or if the cpu is required for rcu
@@ -294,22 +291,51 @@ void tick_nohz_stop_sched_tick(int inidle)
if ((long)delta_jiffies >= 1) {
/*
- * calculate the expiry time for the next timer wheel
- * timer
- */
- expires = ktime_add_ns(last_update, tick_period.tv64 *
- delta_jiffies);
-
- /*
* If this cpu is the one which updates jiffies, then
* give up the assignment and let it be taken by the
* cpu which runs the tick timer next, which might be
* this cpu as well. If we don't drop this here the
* jiffies might be stale and do_timer() never
- * invoked.
+ * invoked. Keep track of the fact that it was the one
+ * which had the do_timer() duty last. If this cpu is
+ * the one which had the do_timer() duty last, we
+ * limit the sleep time to the timekeeping
+ * max_deferement value which we retrieved
+ * above. Otherwise we can sleep as long as we want.
*/
- if (cpu == tick_do_timer_cpu)
+ if (cpu == tick_do_timer_cpu) {
tick_do_timer_cpu = TICK_DO_TIMER_NONE;
+ ts->do_timer_last = 1;
+ } else if (tick_do_timer_cpu != TICK_DO_TIMER_NONE) {
+ time_delta = KTIME_MAX;
+ ts->do_timer_last = 0;
+ } else if (!ts->do_timer_last) {
+ time_delta = KTIME_MAX;
+ }
+
+ /*
+ * calculate the expiry time for the next timer wheel
+ * timer. delta_jiffies >= NEXT_TIMER_MAX_DELTA signals
+ * that there is no timer pending or at least extremely
+ * far into the future (12 days for HZ=1000). In this
+ * case we set the expiry to the end of time.
+ */
+ if (likely(delta_jiffies < NEXT_TIMER_MAX_DELTA)) {
+ /*
+ * Calculate the time delta for the next timer event.
+ * If the time delta exceeds the maximum time delta
+ * permitted by the current clocksource then adjust
+ * the time delta accordingly to ensure the
+ * clocksource does not wrap.
+ */
+ time_delta = min_t(u64, time_delta,
+ tick_period.tv64 * delta_jiffies);
+ }
+
+ if (time_delta < KTIME_MAX)
+ expires = ktime_add_ns(last_update, time_delta);
+ else
+ expires.tv64 = KTIME_MAX;
if (delta_jiffies > 1)
cpumask_set_cpu(cpu, nohz_cpu_mask);
@@ -342,22 +368,19 @@ void tick_nohz_stop_sched_tick(int inidle)
ts->idle_sleeps++;
+ /* Mark expires */
+ ts->idle_expires = expires;
+
/*
- * delta_jiffies >= NEXT_TIMER_MAX_DELTA signals that
- * there is no timer pending or at least extremly far
- * into the future (12 days for HZ=1000). In this case
- * we simply stop the tick timer:
+ * If the expiration time == KTIME_MAX, then
+ * in this case we simply stop the tick timer.
*/
- if (unlikely(delta_jiffies >= NEXT_TIMER_MAX_DELTA)) {
- ts->idle_expires.tv64 = KTIME_MAX;
+ if (unlikely(expires.tv64 == KTIME_MAX)) {
if (ts->nohz_mode == NOHZ_MODE_HIGHRES)
hrtimer_cancel(&ts->sched_timer);
goto out;
}
- /* Mark expiries */
- ts->idle_expires = expires;
-
if (ts->nohz_mode == NOHZ_MODE_HIGHRES) {
hrtimer_start(&ts->sched_timer, expires,
HRTIMER_MODE_ABS_PINNED);
@@ -436,7 +459,11 @@ void tick_nohz_restart_sched_tick(void)
ktime_t now;
local_irq_disable();
- tick_nohz_stop_idle(cpu);
+ if (ts->idle_active || (ts->inidle && ts->tick_stopped))
+ now = ktime_get();
+
+ if (ts->idle_active)
+ tick_nohz_stop_idle(cpu, now);
if (!ts->inidle || !ts->tick_stopped) {
ts->inidle = 0;
@@ -450,7 +477,6 @@ void tick_nohz_restart_sched_tick(void)
/* Update jiffies first */
select_nohz_load_balancer(0);
- now = ktime_get();
tick_do_update_jiffies64(now);
cpumask_clear_cpu(cpu, nohz_cpu_mask);
@@ -584,22 +610,18 @@ static void tick_nohz_switch_to_nohz(void)
* timer and do not touch the other magic bits which need to be done
* when idle is left.
*/
-static void tick_nohz_kick_tick(int cpu)
+static void tick_nohz_kick_tick(int cpu, ktime_t now)
{
#if 0
/* Switch back to 2.6.27 behaviour */
struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
- ktime_t delta, now;
-
- if (!ts->tick_stopped)
- return;
+ ktime_t delta;
/*
* Do not touch the tick device, when the next expiry is either
* already reached or less/equal than the tick period.
*/
- now = ktime_get();
delta = ktime_sub(hrtimer_get_expires(&ts->sched_timer), now);
if (delta.tv64 <= tick_period.tv64)
return;
@@ -608,9 +630,26 @@ static void tick_nohz_kick_tick(int cpu)
#endif
}
+static inline void tick_check_nohz(int cpu)
+{
+ struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
+ ktime_t now;
+
+ if (!ts->idle_active && !ts->tick_stopped)
+ return;
+ now = ktime_get();
+ if (ts->idle_active)
+ tick_nohz_stop_idle(cpu, now);
+ if (ts->tick_stopped) {
+ tick_nohz_update_jiffies(now);
+ tick_nohz_kick_tick(cpu, now);
+ }
+}
+
#else
static inline void tick_nohz_switch_to_nohz(void) { }
+static inline void tick_check_nohz(int cpu) { }
#endif /* NO_HZ */
@@ -620,11 +659,7 @@ static inline void tick_nohz_switch_to_nohz(void) { }
void tick_check_idle(int cpu)
{
tick_check_oneshot_broadcast(cpu);
-#ifdef CONFIG_NO_HZ
- tick_nohz_stop_idle(cpu);
- tick_nohz_update_jiffies();
- tick_nohz_kick_tick(cpu);
-#endif
+ tick_check_nohz(cpu);
}
/*
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index c3a4e29..af4135f 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -165,19 +165,12 @@ struct timespec raw_time;
/* flag for if timekeeping is suspended */
int __read_mostly timekeeping_suspended;
-static struct timespec xtime_cache __attribute__ ((aligned (16)));
-void update_xtime_cache(u64 nsec)
-{
- xtime_cache = xtime;
- timespec_add_ns(&xtime_cache, nsec);
-}
-
/* must hold xtime_lock */
void timekeeping_leap_insert(int leapsecond)
{
xtime.tv_sec += leapsecond;
wall_to_monotonic.tv_sec -= leapsecond;
- update_vsyscall(&xtime, timekeeper.clock);
+ update_vsyscall(&xtime, timekeeper.clock, timekeeper.mult);
}
#ifdef CONFIG_GENERIC_TIME
@@ -332,12 +325,10 @@ int do_settimeofday(struct timespec *tv)
xtime = *tv;
- update_xtime_cache(0);
-
timekeeper.ntp_error = 0;
ntp_clear();
- update_vsyscall(&xtime, timekeeper.clock);
+ update_vsyscall(&xtime, timekeeper.clock, timekeeper.mult);
write_sequnlock_irqrestore(&xtime_lock, flags);
@@ -488,6 +479,17 @@ int timekeeping_valid_for_hres(void)
}
/**
+ * timekeeping_max_deferment - Returns max time the clocksource can be deferred
+ *
+ * Caller must observe xtime_lock via read_seqbegin/read_seqretry to
+ * ensure that the clocksource does not change!
+ */
+u64 timekeeping_max_deferment(void)
+{
+ return timekeeper.clock->max_idle_ns;
+}
+
+/**
* read_persistent_clock - Return time from the persistent clock.
*
* Weak dummy function for arches that do not yet support it.
@@ -548,7 +550,6 @@ void __init timekeeping_init(void)
}
set_normalized_timespec(&wall_to_monotonic,
-boot.tv_sec, -boot.tv_nsec);
- update_xtime_cache(0);
total_sleep_time.tv_sec = 0;
total_sleep_time.tv_nsec = 0;
write_sequnlock_irqrestore(&xtime_lock, flags);
@@ -582,7 +583,6 @@ static int timekeeping_resume(struct sys_device *dev)
wall_to_monotonic = timespec_sub(wall_to_monotonic, ts);
total_sleep_time = timespec_add_safe(total_sleep_time, ts);
}
- update_xtime_cache(0);
/* re-base the last cycle value */
timekeeper.clock->cycle_last = timekeeper.clock->read(timekeeper.clock);
timekeeper.ntp_error = 0;
@@ -723,6 +723,49 @@ static void timekeeping_adjust(s64 offset)
}
/**
+ * logarithmic_accumulation - shifted accumulation of cycles
+ *
+ * This functions accumulates a shifted interval of cycles into
+ * into a shifted interval nanoseconds. Allows for O(log) accumulation
+ * loop.
+ *
+ * Returns the unconsumed cycles.
+ */
+static cycle_t logarithmic_accumulation(cycle_t offset, int shift)
+{
+ u64 nsecps = (u64)NSEC_PER_SEC << timekeeper.shift;
+
+ /* If the offset is smaller then a shifted interval, do nothing */
+ if (offset < timekeeper.cycle_interval<<shift)
+ return offset;
+
+ /* Accumulate one shifted interval */
+ offset -= timekeeper.cycle_interval << shift;
+ timekeeper.clock->cycle_last += timekeeper.cycle_interval << shift;
+
+ timekeeper.xtime_nsec += timekeeper.xtime_interval << shift;
+ while (timekeeper.xtime_nsec >= nsecps) {
+ timekeeper.xtime_nsec -= nsecps;
+ xtime.tv_sec++;
+ second_overflow();
+ }
+
+ /* Accumulate into raw time */
+ raw_time.tv_nsec += timekeeper.raw_interval << shift;;
+ while (raw_time.tv_nsec >= NSEC_PER_SEC) {
+ raw_time.tv_nsec -= NSEC_PER_SEC;
+ raw_time.tv_sec++;
+ }
+
+ /* Accumulate error between NTP and clock interval */
+ timekeeper.ntp_error += tick_length << shift;
+ timekeeper.ntp_error -= timekeeper.xtime_interval <<
+ (timekeeper.ntp_error_shift + shift);
+
+ return offset;
+}
+
+/**
* update_wall_time - Uses the current clocksource to increment the wall time
*
* Called from the timer interrupt, must hold a write on xtime_lock.
@@ -731,7 +774,7 @@ void update_wall_time(void)
{
struct clocksource *clock;
cycle_t offset;
- u64 nsecs;
+ int shift = 0, maxshift;
/* Make sure we're fully resumed: */
if (unlikely(timekeeping_suspended))
@@ -745,33 +788,22 @@ void update_wall_time(void)
#endif
timekeeper.xtime_nsec = (s64)xtime.tv_nsec << timekeeper.shift;
- /* normally this loop will run just once, however in the
- * case of lost or late ticks, it will accumulate correctly.
+ /*
+ * With NO_HZ we may have to accumulate many cycle_intervals
+ * (think "ticks") worth of time at once. To do this efficiently,
+ * we calculate the largest doubling multiple of cycle_intervals
+ * that is smaller then the offset. We then accumulate that
+ * chunk in one go, and then try to consume the next smaller
+ * doubled multiple.
*/
+ shift = ilog2(offset) - ilog2(timekeeper.cycle_interval);
+ shift = max(0, shift);
+ /* Bound shift to one less then what overflows tick_length */
+ maxshift = (8*sizeof(tick_length) - (ilog2(tick_length)+1)) - 1;
+ shift = min(shift, maxshift);
while (offset >= timekeeper.cycle_interval) {
- u64 nsecps = (u64)NSEC_PER_SEC << timekeeper.shift;
-
- /* accumulate one interval */
- offset -= timekeeper.cycle_interval;
- clock->cycle_last += timekeeper.cycle_interval;
-
- timekeeper.xtime_nsec += timekeeper.xtime_interval;
- if (timekeeper.xtime_nsec >= nsecps) {
- timekeeper.xtime_nsec -= nsecps;
- xtime.tv_sec++;
- second_overflow();
- }
-
- raw_time.tv_nsec += timekeeper.raw_interval;
- if (raw_time.tv_nsec >= NSEC_PER_SEC) {
- raw_time.tv_nsec -= NSEC_PER_SEC;
- raw_time.tv_sec++;
- }
-
- /* accumulate error between NTP and clock interval */
- timekeeper.ntp_error += tick_length;
- timekeeper.ntp_error -= timekeeper.xtime_interval <<
- timekeeper.ntp_error_shift;
+ offset = logarithmic_accumulation(offset, shift);
+ shift--;
}
/* correct the clock when NTP error is too big */
@@ -807,11 +839,8 @@ void update_wall_time(void)
timekeeper.ntp_error += timekeeper.xtime_nsec <<
timekeeper.ntp_error_shift;
- nsecs = clocksource_cyc2ns(offset, timekeeper.mult, timekeeper.shift);
- update_xtime_cache(nsecs);
-
/* check to see if there is a new clocksource to use */
- update_vsyscall(&xtime, timekeeper.clock);
+ update_vsyscall(&xtime, timekeeper.clock, timekeeper.mult);
}
/**
@@ -846,13 +875,13 @@ void monotonic_to_bootbased(struct timespec *ts)
unsigned long get_seconds(void)
{
- return xtime_cache.tv_sec;
+ return xtime.tv_sec;
}
EXPORT_SYMBOL(get_seconds);
struct timespec __current_kernel_time(void)
{
- return xtime_cache;
+ return xtime;
}
struct timespec current_kernel_time(void)
@@ -862,8 +891,7 @@ struct timespec current_kernel_time(void)
do {
seq = read_seqbegin(&xtime_lock);
-
- now = xtime_cache;
+ now = xtime;
} while (read_seqretry(&xtime_lock, seq));
return now;
@@ -877,8 +905,7 @@ struct timespec get_monotonic_coarse(void)
do {
seq = read_seqbegin(&xtime_lock);
-
- now = xtime_cache;
+ now = xtime;
mono = wall_to_monotonic;
} while (read_seqretry(&xtime_lock, seq));
diff --git a/kernel/time/timer_list.c b/kernel/time/timer_list.c
index 1b5b7aa..665c76e 100644
--- a/kernel/time/timer_list.c
+++ b/kernel/time/timer_list.c
@@ -204,10 +204,12 @@ print_tickdevice(struct seq_file *m, struct tick_device *td, int cpu)
return;
}
SEQ_printf(m, "%s\n", dev->name);
- SEQ_printf(m, " max_delta_ns: %lu\n", dev->max_delta_ns);
- SEQ_printf(m, " min_delta_ns: %lu\n", dev->min_delta_ns);
- SEQ_printf(m, " mult: %lu\n", dev->mult);
- SEQ_printf(m, " shift: %d\n", dev->shift);
+ SEQ_printf(m, " max_delta_ns: %llu\n",
+ (unsigned long long) dev->max_delta_ns);
+ SEQ_printf(m, " min_delta_ns: %llu\n",
+ (unsigned long long) dev->min_delta_ns);
+ SEQ_printf(m, " mult: %u\n", dev->mult);
+ SEQ_printf(m, " shift: %u\n", dev->shift);
SEQ_printf(m, " mode: %d\n", dev->mode);
SEQ_printf(m, " next_event: %Ld nsecs\n",
(unsigned long long) ktime_to_ns(dev->next_event));
diff --git a/kernel/user-return-notifier.c b/kernel/user-return-notifier.c
index 03e2d6f..eb27fd3 100644
--- a/kernel/user-return-notifier.c
+++ b/kernel/user-return-notifier.c
@@ -6,8 +6,6 @@
static DEFINE_PER_CPU(struct hlist_head, return_notifier_list);
-#define URN_LIST_HEAD per_cpu(return_notifier_list, raw_smp_processor_id())
-
/*
* Request a notification when the current cpu returns to userspace. Must be
* called in atomic context. The notifier will also be called in atomic
@@ -16,7 +14,7 @@ static DEFINE_PER_CPU(struct hlist_head, return_notifier_list);
void user_return_notifier_register(struct user_return_notifier *urn)
{
set_tsk_thread_flag(current, TIF_USER_RETURN_NOTIFY);
- hlist_add_head(&urn->link, &URN_LIST_HEAD);
+ hlist_add_head(&urn->link, &__get_cpu_var(return_notifier_list));
}
EXPORT_SYMBOL_GPL(user_return_notifier_register);
@@ -27,7 +25,7 @@ EXPORT_SYMBOL_GPL(user_return_notifier_register);
void user_return_notifier_unregister(struct user_return_notifier *urn)
{
hlist_del(&urn->link);
- if (hlist_empty(&URN_LIST_HEAD))
+ if (hlist_empty(&__get_cpu_var(return_notifier_list)))
clear_tsk_thread_flag(current, TIF_USER_RETURN_NOTIFY);
}
EXPORT_SYMBOL_GPL(user_return_notifier_unregister);
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 0b8f359..96c620a 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -105,7 +105,7 @@ config DEBUG_SECTION_MISMATCH
bool "Enable full Section mismatch analysis"
depends on UNDEFINED
# This option is on purpose disabled for now.
- # It will be enabled when we are down to a resonable number
+ # It will be enabled when we are down to a reasonable number
# of section mismatch warnings (< 10 for an allyesconfig build)
help
The section mismatch analysis checks if there are illegal
diff --git a/lib/decompress_bunzip2.c b/lib/decompress_bunzip2.c
index 600f473..7607420 100644
--- a/lib/decompress_bunzip2.c
+++ b/lib/decompress_bunzip2.c
@@ -299,7 +299,7 @@ static int INIT get_next_block(struct bunzip_data *bd)
again when using them (during symbol decoding).*/
base = hufGroup->base-1;
limit = hufGroup->limit-1;
- /* Calculate permute[]. Concurently, initialize
+ /* Calculate permute[]. Concurrently, initialize
* temp[] and limit[]. */
pp = 0;
for (i = minLen; i <= maxLen; i++) {
diff --git a/lib/dma-debug.c b/lib/dma-debug.c
index ce6b7ea..d9b08e0 100644
--- a/lib/dma-debug.c
+++ b/lib/dma-debug.c
@@ -259,7 +259,7 @@ static struct dma_debug_entry *hash_bucket_find(struct hash_bucket *bucket,
* times. Without a hardware IOMMU this results in the
* same device addresses being put into the dma-debug
* hash multiple times too. This can result in false
- * positives being reported. Therfore we implement a
+ * positives being reported. Therefore we implement a
* best-fit algorithm here which returns the entry from
* the hash which fits best to the reference value
* instead of the first-fit.
diff --git a/lib/idr.c b/lib/idr.c
index 80ca9ac..1cac726 100644
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -281,7 +281,7 @@ static int idr_get_new_above_int(struct idr *idp, void *ptr, int starting_id)
/**
* idr_get_new_above - allocate new idr entry above or equal to a start id
* @idp: idr handle
- * @ptr: pointer you want associated with the ide
+ * @ptr: pointer you want associated with the id
* @start_id: id to start search at
* @id: pointer to the allocated handle
*
@@ -313,7 +313,7 @@ EXPORT_SYMBOL(idr_get_new_above);
/**
* idr_get_new - allocate new idr entry
* @idp: idr handle
- * @ptr: pointer you want associated with the ide
+ * @ptr: pointer you want associated with the id
* @id: pointer to the allocated handle
*
* This is the allocate id function. It should be called with any
diff --git a/lib/swiotlb.c b/lib/swiotlb.c
index 795472d..5bc0180 100644
--- a/lib/swiotlb.c
+++ b/lib/swiotlb.c
@@ -485,7 +485,7 @@ do_unmap_single(struct device *hwdev, char *dma_addr, size_t size, int dir)
/*
* Return the buffer to the free list by setting the corresponding
- * entries to indicate the number of contigous entries available.
+ * entries to indicate the number of contiguous entries available.
* While returning the entries to the free list, we merge the entries
* with slots below and above the pool being returned.
*/
diff --git a/mm/filemap.c b/mm/filemap.c
index ef169f3..c3d3506 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1844,7 +1844,7 @@ static size_t __iovec_copy_from_user_inatomic(char *vaddr,
/*
* Copy as much as we can into the page and return the number of bytes which
- * were sucessfully copied. If a fault is encountered then return the number of
+ * were successfully copied. If a fault is encountered then return the number of
* bytes which were copied.
*/
size_t iov_iter_copy_from_user_atomic(struct page *page,
diff --git a/mm/kmemleak.c b/mm/kmemleak.c
index 8bf765c..13f33b3 100644
--- a/mm/kmemleak.c
+++ b/mm/kmemleak.c
@@ -1050,8 +1050,8 @@ static void scan_object(struct kmemleak_object *object)
unsigned long flags;
/*
- * Once the object->lock is aquired, the corresponding memory block
- * cannot be freed (the same lock is aquired in delete_object).
+ * Once the object->lock is acquired, the corresponding memory block
+ * cannot be freed (the same lock is acquired in delete_object).
*/
spin_lock_irqsave(&object->lock, flags);
if (object->flags & OBJECT_NO_SCAN)
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index f99f599..c31a310 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -209,7 +209,7 @@ struct mem_cgroup {
int prev_priority; /* for recording reclaim priority */
/*
- * While reclaiming in a hiearchy, we cache the last child we
+ * While reclaiming in a hierarchy, we cache the last child we
* reclaimed from.
*/
int last_scanned_child;
@@ -1720,7 +1720,7 @@ int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm,
/*
* While swap-in, try_charge -> commit or cancel, the page is locked.
* And when try_charge() successfully returns, one refcnt to memcg without
- * struct page_cgroup is aquired. This refcnt will be cumsumed by
+ * struct page_cgroup is acquired. This refcnt will be consumed by
* "commit()" or removed by "cancel()"
*/
int mem_cgroup_try_charge_swapin(struct mm_struct *mm,
@@ -2466,7 +2466,7 @@ static int mem_cgroup_hierarchy_write(struct cgroup *cont, struct cftype *cft,
cgroup_lock();
/*
- * If parent's use_hiearchy is set, we can't make any modifications
+ * If parent's use_hierarchy is set, we can't make any modifications
* in the child subtrees. If it is unset, then the change can
* occur, provided the current cgroup has no children.
*
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index dacc641..1ac49fe 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -174,7 +174,7 @@ static void kill_procs_ao(struct list_head *to_kill, int doit, int trapno,
list_for_each_entry_safe (tk, next, to_kill, nd) {
if (doit) {
/*
- * In case something went wrong with munmaping
+ * In case something went wrong with munmapping
* make sure the process doesn't catch the
* signal and then access the memory. Just kill it.
* the signal handlers
diff --git a/mm/truncate.c b/mm/truncate.c
index 450cebd..2c147a7 100644
--- a/mm/truncate.c
+++ b/mm/truncate.c
@@ -490,7 +490,7 @@ EXPORT_SYMBOL_GPL(invalidate_inode_pages2_range);
* Any pages which are found to be mapped into pagetables are unmapped prior to
* invalidation.
*
- * Returns -EIO if any pages could not be invalidated.
+ * Returns -EBUSY if any pages could not be invalidated.
*/
int invalidate_inode_pages2(struct address_space *mapping)
{
diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c
index 29b1b22..ef09c7b 100644
--- a/net/bluetooth/bnep/core.c
+++ b/net/bluetooth/bnep/core.c
@@ -78,7 +78,7 @@ static struct bnep_session *__bnep_get_session(u8 *dst)
static void __bnep_link_session(struct bnep_session *s)
{
/* It's safe to call __module_get() here because sessions are added
- by the socket layer which has to hold the refference to this module.
+ by the socket layer which has to hold the reference to this module.
*/
__module_get(THIS_MODULE);
list_add(&s->list, &bnep_session_list);
@@ -632,7 +632,7 @@ int bnep_del_connection(struct bnep_conndel_req *req)
s = __bnep_get_session(req->dst);
if (s) {
/* Wakeup user-space which is polling for socket errors.
- * This is temporary hack untill we have shutdown in L2CAP */
+ * This is temporary hack until we have shutdown in L2CAP */
s->sock->sk->sk_err = EUNATCH;
/* Kill session thread */
diff --git a/net/ipv4/netfilter/ipt_ECN.c b/net/ipv4/netfilter/ipt_ECN.c
index 549e206..ea5cea2 100644
--- a/net/ipv4/netfilter/ipt_ECN.c
+++ b/net/ipv4/netfilter/ipt_ECN.c
@@ -50,7 +50,7 @@ set_ect_tcp(struct sk_buff *skb, const struct ipt_ECN_info *einfo)
struct tcphdr _tcph, *tcph;
__be16 oldval;
- /* Not enought header? */
+ /* Not enough header? */
tcph = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_tcph), &_tcph);
if (!tcph)
return false;
diff --git a/net/irda/irlap.c b/net/irda/irlap.c
index 356e65b..783c5f3 100644
--- a/net/irda/irlap.c
+++ b/net/irda/irlap.c
@@ -450,10 +450,10 @@ void irlap_disconnect_request(struct irlap_cb *self)
/* Check if we are in the right state for disconnecting */
switch (self->state) {
- case LAP_XMIT_P: /* FALLTROUGH */
- case LAP_XMIT_S: /* FALLTROUGH */
- case LAP_CONN: /* FALLTROUGH */
- case LAP_RESET_WAIT: /* FALLTROUGH */
+ case LAP_XMIT_P: /* FALLTHROUGH */
+ case LAP_XMIT_S: /* FALLTHROUGH */
+ case LAP_CONN: /* FALLTHROUGH */
+ case LAP_RESET_WAIT: /* FALLTHROUGH */
case LAP_RESET_CHECK:
irlap_do_event(self, DISCONNECT_REQUEST, NULL, NULL);
break;
@@ -485,9 +485,9 @@ void irlap_disconnect_indication(struct irlap_cb *self, LAP_REASON reason)
IRDA_DEBUG(1, "%s(), Sending reset request!\n", __func__);
irlap_do_event(self, RESET_REQUEST, NULL, NULL);
break;
- case LAP_NO_RESPONSE: /* FALLTROUGH */
- case LAP_DISC_INDICATION: /* FALLTROUGH */
- case LAP_FOUND_NONE: /* FALLTROUGH */
+ case LAP_NO_RESPONSE: /* FALLTHROUGH */
+ case LAP_DISC_INDICATION: /* FALLTHROUGH */
+ case LAP_FOUND_NONE: /* FALLTHROUGH */
case LAP_MEDIA_BUSY:
irlmp_link_disconnect_indication(self->notify.instance, self,
reason, NULL);
diff --git a/net/irda/irlap_event.c b/net/irda/irlap_event.c
index c5c5195..94a9884 100644
--- a/net/irda/irlap_event.c
+++ b/net/irda/irlap_event.c
@@ -1741,7 +1741,7 @@ static int irlap_state_reset(struct irlap_cb *self, IRLAP_EVENT event,
* Function irlap_state_xmit_s (event, skb, info)
*
* XMIT_S, The secondary station has been given the right to transmit,
- * and we therefor do not expect to receive any transmissions from other
+ * and we therefore do not expect to receive any transmissions from other
* stations.
*/
static int irlap_state_xmit_s(struct irlap_cb *self, IRLAP_EVENT event,
diff --git a/net/irda/irlmp.c b/net/irda/irlmp.c
index 7bf5b91..0e7d8bd 100644
--- a/net/irda/irlmp.c
+++ b/net/irda/irlmp.c
@@ -105,7 +105,7 @@ int __init irlmp_init(void)
init_timer(&irlmp->discovery_timer);
- /* Do discovery every 3 seconds, conditionaly */
+ /* Do discovery every 3 seconds, conditionally */
if (sysctl_discovery)
irlmp_start_discovery_timer(irlmp,
sysctl_discovery_timeout*HZ);
@@ -1842,7 +1842,7 @@ LM_REASON irlmp_convert_lap_reason( LAP_REASON lap_reason)
reason = LM_CONNECT_FAILURE;
break;
default:
- IRDA_DEBUG(1, "%s(), Unknow IrLAP disconnect reason %d!\n",
+ IRDA_DEBUG(1, "%s(), Unknown IrLAP disconnect reason %d!\n",
__func__, lap_reason);
reason = LM_LAP_DISCONNECT;
break;
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index a8da239..0192cfd 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -244,7 +244,7 @@ struct mesh_path *mesh_path_lookup_by_idx(int idx, struct ieee80211_sub_if_data
* @addr: destination address of the path (ETH_ALEN length)
* @sdata: local subif
*
- * Returns: 0 on sucess
+ * Returns: 0 on success
*
* State: the initial state of the new path is set to 0
*/
@@ -532,7 +532,7 @@ static void mesh_path_node_reclaim(struct rcu_head *rp)
* @addr: dst address (ETH_ALEN length)
* @sdata: local subif
*
- * Returns: 0 if succesful
+ * Returns: 0 if successful
*/
int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata)
{
diff --git a/net/netlabel/netlabel_domainhash.c b/net/netlabel/netlabel_domainhash.c
index 7a10bbe..c5d9f97 100644
--- a/net/netlabel/netlabel_domainhash.c
+++ b/net/netlabel/netlabel_domainhash.c
@@ -682,7 +682,7 @@ struct netlbl_domaddr6_map *netlbl_domhsh_getentry_af6(const char *domain,
* buckets and @skip_chain entries. For each entry in the table call
* @callback, if @callback returns a negative value stop 'walking' through the
* table and return. Updates the values in @skip_bkt and @skip_chain on
- * return. Returns zero on succcess, negative values on failure.
+ * return. Returns zero on success, negative values on failure.
*
*/
int netlbl_domhsh_walk(u32 *skip_bkt,
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index 2a74003..64f5e32 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -598,7 +598,7 @@ int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *a,
goto errout;
/* compat_mode being true specifies a call that is supposed
- * to add additional backward compatiblity statistic TLVs.
+ * to add additional backward compatibility statistic TLVs.
*/
if (compat_mode) {
if (a->type == TCA_OLD_COMPAT)
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index d771cc1..4e4ca65 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -717,7 +717,7 @@ static void sctp_cmd_new_state(sctp_cmd_seq_t *cmds,
if (sctp_style(sk, TCP)) {
/* Change the sk->sk_state of a TCP-style socket that has
- * sucessfully completed a connect() call.
+ * successfully completed a connect() call.
*/
if (sctp_state(asoc, ESTABLISHED) && sctp_sstate(sk, CLOSED))
sk->sk_state = SCTP_SS_ESTABLISHED;
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index 1ef9de9..47bc20d 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -3577,7 +3577,7 @@ sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep,
* To do this properly, we'll set the destination address of the chunk
* and at the transmit time, will try look up the transport to use.
* Since ASCONFs may be bundled, the correct transport may not be
- * created untill we process the entire packet, thus this workaround.
+ * created until we process the entire packet, thus this workaround.
*/
asconf_ack->dest = chunk->source;
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(asconf_ack));
diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c
index 419e1e9..832590b 100644
--- a/net/sctp/sysctl.c
+++ b/net/sctp/sysctl.c
@@ -248,7 +248,6 @@ static ctl_table sctp_table[] = {
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec_minmax,
- .strategy = &sysctl_intvec,
.extra1 = &one,
.extra2 = &rwnd_scale_max,
},
diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
index f11be72..b15e1eb 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
@@ -54,7 +54,7 @@
* Assumptions:
* - head[0] is physically contiguous.
* - tail[0] is physically contiguous.
- * - pages[] is not physically or virtually contigous and consists of
+ * - pages[] is not physically or virtually contiguous and consists of
* PAGE_SIZE elements.
*
* Output:
diff --git a/net/wimax/op-reset.c b/net/wimax/op-reset.c
index ca26917..35f3700 100644
--- a/net/wimax/op-reset.c
+++ b/net/wimax/op-reset.c
@@ -62,7 +62,7 @@
* Called when wanting to reset the device for any reason. Device is
* taken back to power on status.
*
- * This call blocks; on succesful return, the device has completed the
+ * This call blocks; on successful return, the device has completed the
* reset process and is ready to operate.
*/
int wimax_reset(struct wimax_dev *wimax_dev)
diff --git a/samples/Kconfig b/samples/Kconfig
index e4be84a..8924f72 100644
--- a/samples/Kconfig
+++ b/samples/Kconfig
@@ -1,5 +1,3 @@
-# samples/Kconfig
-
menuconfig SAMPLES
bool "Sample kernel code"
help
@@ -47,4 +45,3 @@ config SAMPLE_HW_BREAKPOINT
This builds kernel hardware breakpoint example modules.
endif # SAMPLES
-
diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c
index d829535..8413cf3 100644
--- a/scripts/kconfig/mconf.c
+++ b/scripts/kconfig/mconf.c
@@ -213,7 +213,7 @@ load_config_help[] = N_(
"to modify that configuration.\n"
"\n"
"If you are uncertain, then you have probably never used alternate\n"
- "configuration files. You should therefor leave this blank to abort.\n"),
+ "configuration files. You should therefore leave this blank to abort.\n"),
save_config_text[] = N_(
"Enter a filename to which this configuration should be saved "
"as an alternate. Leave blank to abort."),
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c
index e688237..2534400 100644
--- a/security/selinux/netlabel.c
+++ b/security/selinux/netlabel.c
@@ -204,7 +204,7 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
*
* Description
* Call the NetLabel mechanism to set the label of a packet using @sid.
- * Returns zero on auccess, negative values on failure.
+ * Returns zero on success, negative values on failure.
*
*/
int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index d6bb20c..b3efae2 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -836,7 +836,7 @@ int security_bounded_transition(u32 old_sid, u32 new_sid)
goto out;
}
- /* type/domain unchaned */
+ /* type/domain unchanged */
if (old_context->type == new_context->type) {
rc = 0;
goto out;
diff --git a/sound/Kconfig b/sound/Kconfig
index b3e53e6..fcad760 100644
--- a/sound/Kconfig
+++ b/sound/Kconfig
@@ -1,6 +1,3 @@
-# sound/Config.in
-#
-
menuconfig SOUND
tristate "Sound card support"
depends on HAS_IOMEM
@@ -136,4 +133,3 @@ config AC97_BUS
sound subsystem and other function drivers completely unrelated to
sound although they're sharing the AC97 bus. Concerned drivers
should "select" this.
-
diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c
index 93fa672..cc15d1d 100644
--- a/sound/isa/cs423x/cs4236.c
+++ b/sound/isa/cs423x/cs4236.c
@@ -177,7 +177,7 @@ static struct pnp_card_device_id snd_cs423x_pnpids[] = {
{ .id = "CSC0437", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
/* Digital PC 5000 Onboard - CS4236B */
{ .id = "CSC0735", .devs = { { "CSC0000" }, { "CSC0010" } } },
- /* some uknown CS4236B */
+ /* some unknown CS4236B */
{ .id = "CSC0b35", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
/* Intel PR440FX Onboard sound */
{ .id = "CSC0b36", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c
index 6123c75..b865e45 100644
--- a/sound/isa/opti9xx/miro.c
+++ b/sound/isa/opti9xx/miro.c
@@ -133,7 +133,7 @@ struct snd_miro {
static struct snd_miro_aci aci_device;
static char * snd_opti9xx_names[] = {
- "unkown",
+ "unknown",
"82C928", "82C929",
"82C924", "82C925",
"82C930", "82C931", "82C933"
diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c
index d08c389..d622d29 100644
--- a/sound/isa/opti9xx/opti92x-ad1848.c
+++ b/sound/isa/opti9xx/opti92x-ad1848.c
@@ -177,7 +177,7 @@ MODULE_DEVICE_TABLE(pnp_card, snd_opti9xx_pnpids);
#endif
static char * snd_opti9xx_names[] = {
- "unkown",
+ "unknown",
"82C928", "82C929",
"82C924", "82C925",
"82C930", "82C931", "82C933"
diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig
index 135a2b7..a513651 100644
--- a/sound/oss/Kconfig
+++ b/sound/oss/Kconfig
@@ -1,5 +1,3 @@
-# drivers/sound/Config.in
-#
# 18 Apr 1998, Michael Elizabeth Chastain, <mailto:mec@shout.net>
# More hacking for modularisation.
#
diff --git a/sound/oss/dmasound/dmasound_paula.c b/sound/oss/dmasound/dmasound_paula.c
index 06e9e88..bb14e4c 100644
--- a/sound/oss/dmasound/dmasound_paula.c
+++ b/sound/oss/dmasound/dmasound_paula.c
@@ -657,7 +657,7 @@ static int AmiStateInfo(char *buffer, size_t space)
len += sprintf(buffer+len, "\tsound.volume_right = %d [0...64]\n",
dmasound.volume_right);
if (len >= space) {
- printk(KERN_ERR "dmasound_paula: overlowed state buffer alloc.\n") ;
+ printk(KERN_ERR "dmasound_paula: overflowed state buffer alloc.\n") ;
len = space ;
}
return len;
diff --git a/sound/pci/ca0106/ca0106_proc.c b/sound/pci/ca0106/ca0106_proc.c
index 15523e6..0470461 100644
--- a/sound/pci/ca0106/ca0106_proc.c
+++ b/sound/pci/ca0106/ca0106_proc.c
@@ -233,7 +233,7 @@ static void snd_ca0106_proc_dump_iec958( struct snd_info_buffer *buffer, u32 val
snd_iprintf(buffer, "user-defined\n");
break;
default:
- snd_iprintf(buffer, "unkown\n");
+ snd_iprintf(buffer, "unknown\n");
break;
}
snd_iprintf(buffer, "Sample Bits: ");
diff --git a/sound/pci/cs46xx/imgs/cwcdma.asp b/sound/pci/cs46xx/imgs/cwcdma.asp
index 09d24c7..a65e119 100644
--- a/sound/pci/cs46xx/imgs/cwcdma.asp
+++ b/sound/pci/cs46xx/imgs/cwcdma.asp
@@ -26,10 +26,11 @@
//
//
// The purpose of this code is very simple: make it possible to tranfser
-// the samples 'as they are' with no alteration from a PCMreader SCB (DMA from host)
-// to any other SCB. This is useful for AC3 throug SPDIF. SRC (source rate converters)
-// task always alters the samples in some how, however it's from 48khz -> 48khz. The
-// alterations are not audible, but AC3 wont work.
+// the samples 'as they are' with no alteration from a PCMreader
+// SCB (DMA from host) to any other SCB. This is useful for AC3 through SPDIF.
+// SRC (source rate converters) task always alters the samples in somehow,
+// however it's from 48khz -> 48khz.
+// The alterations are not audible, but AC3 wont work.
//
// ...
// |
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c
index 6b8ae7b..1d369ff 100644
--- a/sound/pci/emu10k1/emu10k1x.c
+++ b/sound/pci/emu10k1/emu10k1x.c
@@ -184,7 +184,7 @@ MODULE_PARM_DESC(enable, "Enable the EMU10K1X soundcard.");
* The hardware has 3 channels for playback and 1 for capture.
* - channel 0 is the front channel
* - channel 1 is the rear channel
- * - channel 2 is the center/lfe chanel
+ * - channel 2 is the center/lfe channel
* Volume is controlled by the AC97 for the front and rear channels by
* the PCM Playback Volume, Sigmatel Surround Playback Volume and
* Surround Playback Volume. The Sigmatel 4-Speaker Stereo switch affects
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index 2439e84..4b200da 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -938,7 +938,7 @@ static void init_input(struct hda_codec *codec)
coef |= 0x0500; /* DMIC2 enable 2 channels, disable GPIO1 */
if (is_active_pin(codec, CS_DMIC1_PIN_NID))
coef |= 0x1800; /* DMIC1 enable 2 channels, disable GPIO0
- * No effect if SPDIF_OUT2 is slected in
+ * No effect if SPDIF_OUT2 is selected in
* IDX_SPDIF_CTL.
*/
cs_vendor_coef_set(codec, IDX_ADC_CFG, coef);
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c
index 85c81fe..a45c116 100644
--- a/sound/pci/hda/patch_cmedia.c
+++ b/sound/pci/hda/patch_cmedia.c
@@ -66,7 +66,7 @@ struct cmi_spec {
struct hda_pcm pcm_rec[2]; /* PCM information */
- /* pin deafault configuration */
+ /* pin default configuration */
hda_nid_t pin_nid[NUM_PINS];
unsigned int def_conf[NUM_PINS];
unsigned int pin_def_confs;
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index d967836..db4a736 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -6618,7 +6618,7 @@ static struct hda_input_mux alc889A_mb31_capture_source = {
/* Front Mic (0x01) unused */
{ "Line", 0x2 },
/* Line 2 (0x03) unused */
- /* CD (0x04) unsused? */
+ /* CD (0x04) unused? */
},
};
diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c
index 0c9413d..98bc3b7 100644
--- a/sound/pci/ice1712/juli.c
+++ b/sound/pci/ice1712/juli.c
@@ -380,7 +380,7 @@ static struct snd_kcontrol_new juli_mute_controls[] __devinitdata = {
* inputs) are fed from Xilinx.
*
* I even checked traces on board and coded a support in driver for
- * an alternative possiblity - the unused I2S ICE output channels
+ * an alternative possibility - the unused I2S ICE output channels
* switched to HW-IN/SPDIF-IN and providing the monitoring signal to
* the DAC - to no avail. The I2S outputs seem to be unconnected.
*
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index 0dce331..a1b10d1 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -3017,7 +3017,7 @@ snd_hdspm_proc_read_madi(struct snd_info_entry * entry,
insel = "Coaxial";
break;
default:
- insel = "Unkown";
+ insel = "Unknown";
}
switch (hdspm->control_register & HDSPM_SyncRefMask) {
@@ -3028,7 +3028,7 @@ snd_hdspm_proc_read_madi(struct snd_info_entry * entry,
syncref = "MADI";
break;
default:
- syncref = "Unkown";
+ syncref = "Unknown";
}
snd_iprintf(buffer, "Inputsel = %s, SyncRef = %s\n", insel,
syncref);
diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c
index aa40d98..3e99fe5 100644
--- a/sound/soc/codecs/uda134x.c
+++ b/sound/soc/codecs/uda134x.c
@@ -101,7 +101,7 @@ static int uda134x_write(struct snd_soc_codec *codec, unsigned int reg,
pr_debug("%s reg: %02X, value:%02X\n", __func__, reg, value);
if (reg >= UDA134X_REGS_NUM) {
- printk(KERN_ERR "%s unkown register: reg: %u",
+ printk(KERN_ERR "%s unknown register: reg: %u",
__func__, reg);
return -EINVAL;
}
@@ -552,7 +552,7 @@ static int uda134x_soc_probe(struct platform_device *pdev)
ARRAY_SIZE(uda1341_snd_controls));
break;
default:
- printk(KERN_ERR "%s unkown codec type: %d",
+ printk(KERN_ERR "%s unknown codec type: %d",
__func__, pd->model);
return -EINVAL;
}
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index b8cae17..ce5515e 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -607,7 +607,7 @@ SOC_SINGLE("Right Input PGA Common Mode Switch", WM8903_ANALOGUE_RIGHT_INPUT_1,
SOC_SINGLE("DRC Switch", WM8903_DRC_0, 15, 1, 0),
SOC_ENUM("DRC Compressor Slope R0", drc_slope_r0),
SOC_ENUM("DRC Compressor Slope R1", drc_slope_r1),
-SOC_SINGLE_TLV("DRC Compressor Threashold Volume", WM8903_DRC_3, 5, 124, 1,
+SOC_SINGLE_TLV("DRC Compressor Threshold Volume", WM8903_DRC_3, 5, 124, 1,
drc_tlv_thresh),
SOC_SINGLE_TLV("DRC Volume", WM8903_DRC_3, 0, 30, 1, drc_tlv_amp),
SOC_SINGLE_TLV("DRC Minimum Gain Volume", WM8903_DRC_1, 2, 3, 1, drc_tlv_min),
@@ -617,11 +617,11 @@ SOC_ENUM("DRC Decay Rate", drc_decay),
SOC_ENUM("DRC FF Delay", drc_ff_delay),
SOC_SINGLE("DRC Anticlip Switch", WM8903_DRC_0, 1, 1, 0),
SOC_SINGLE("DRC QR Switch", WM8903_DRC_0, 2, 1, 0),
-SOC_SINGLE_TLV("DRC QR Threashold Volume", WM8903_DRC_0, 6, 3, 0, drc_tlv_max),
+SOC_SINGLE_TLV("DRC QR Threshold Volume", WM8903_DRC_0, 6, 3, 0, drc_tlv_max),
SOC_ENUM("DRC QR Decay Rate", drc_qr_decay),
SOC_SINGLE("DRC Smoothing Switch", WM8903_DRC_0, 3, 1, 0),
SOC_SINGLE("DRC Smoothing Hysteresis Switch", WM8903_DRC_0, 0, 1, 0),
-SOC_ENUM("DRC Smoothing Threashold", drc_smoothing),
+SOC_ENUM("DRC Smoothing Threshold", drc_smoothing),
SOC_SINGLE_TLV("DRC Startup Volume", WM8903_DRC_0, 6, 18, 0, drc_tlv_startup),
SOC_DOUBLE_R_TLV("Digital Capture Volume", WM8903_ADC_DIGITAL_VOLUME_LEFT,
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c
index 5e32f2e..2981afa 100644
--- a/sound/soc/codecs/wm8993.c
+++ b/sound/soc/codecs/wm8993.c
@@ -689,7 +689,7 @@ SOC_DOUBLE_TLV("Digital Sidetone Volume", WM8993_DIGITAL_SIDE_TONE,
SOC_SINGLE("DRC Switch", WM8993_DRC_CONTROL_1, 15, 1, 0),
SOC_ENUM("DRC Path", drc_path),
-SOC_SINGLE_TLV("DRC Compressor Threashold Volume", WM8993_DRC_CONTROL_2,
+SOC_SINGLE_TLV("DRC Compressor Threshold Volume", WM8993_DRC_CONTROL_2,
2, 60, 1, drc_comp_threash),
SOC_SINGLE_TLV("DRC Compressor Amplitude Volume", WM8993_DRC_CONTROL_3,
11, 30, 1, drc_comp_amp),
@@ -709,7 +709,7 @@ SOC_SINGLE_TLV("DRC Quick Release Volume", WM8993_DRC_CONTROL_3, 2, 3, 0,
SOC_ENUM("DRC Quick Release Rate", drc_qr_rate),
SOC_SINGLE("DRC Smoothing Switch", WM8993_DRC_CONTROL_1, 11, 1, 0),
SOC_SINGLE("DRC Smoothing Hysteresis Switch", WM8993_DRC_CONTROL_1, 8, 1, 0),
-SOC_ENUM("DRC Smoothing Hysteresis Threashold", drc_smooth),
+SOC_ENUM("DRC Smoothing Hysteresis Threshold", drc_smooth),
SOC_SINGLE_TLV("DRC Startup Volume", WM8993_DRC_CONTROL_4, 8, 18, 0,
drc_startup_tlv),
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec.c b/sound/soc/s3c24xx/s3c24xx_simtec.c
index 507b2ed..d441c3b 100644
--- a/sound/soc/s3c24xx/s3c24xx_simtec.c
+++ b/sound/soc/s3c24xx/s3c24xx_simtec.c
@@ -270,7 +270,7 @@ static int attach_gpio_amp(struct device *dev,
gpio_direction_output(pd->amp_gain[1], 0);
}
- /* note, curently we assume GPA0 isn't valid amp */
+ /* note, currently we assume GPA0 isn't valid amp */
if (pdata->amp_gpio > 0) {
ret = gpio_request(pd->amp_gpio, "gpio-amp");
if (ret) {
diff --git a/sound/soc/s6000/s6000-pcm.c b/sound/soc/s6000/s6000-pcm.c
index 0eb1722..1d61109 100644
--- a/sound/soc/s6000/s6000-pcm.c
+++ b/sound/soc/s6000/s6000-pcm.c
@@ -196,7 +196,7 @@ static int s6000_pcm_start(struct snd_pcm_substream *substream)
0 /* destination skip after chunk (impossible) */,
4 /* 16 byte burst size */,
-1 /* don't conserve bandwidth */,
- 0 /* low watermark irq descriptor theshold */,
+ 0 /* low watermark irq descriptor threshold */,
0 /* disable hardware timestamps */,
1 /* enable channel */);
diff --git a/sound/sound_core.c b/sound/sound_core.c
index 49c9981..dbca7c9 100644
--- a/sound/sound_core.c
+++ b/sound/sound_core.c
@@ -353,7 +353,7 @@ static struct sound_unit *chains[SOUND_STEP];
* @dev: device pointer
*
* Allocate a special sound device by minor number from the sound
- * subsystem. The allocated number is returned on succes. On failure
+ * subsystem. The allocated number is returned on success. On failure
* a negative error code is returned.
*/
diff --git a/sound/synth/emux/soundfont.c b/sound/synth/emux/soundfont.c
index 63c8f45..67c9123 100644
--- a/sound/synth/emux/soundfont.c
+++ b/sound/synth/emux/soundfont.c
@@ -374,7 +374,7 @@ sf_zone_new(struct snd_sf_list *sflist, struct snd_soundfont *sf)
/*
- * increment sample couter
+ * increment sample counter
*/
static void
set_sample_counter(struct snd_sf_list *sflist, struct snd_soundfont *sf,