Merge git://git.kernel.org/pub/scm/linux/kernel/git/perex/alsa
authorLinus Torvalds <torvalds@g5.osdl.org>
Wed, 22 Mar 2006 18:59:20 +0000 (10:59 -0800)
committerLinus Torvalds <torvalds@g5.osdl.org>
Wed, 22 Mar 2006 18:59:20 +0000 (10:59 -0800)
* git://git.kernel.org/pub/scm/linux/kernel/git/perex/alsa: (124 commits)
  [ALSA] version 1.0.11rc4
  [PATCH] Intruduce DMA_28BIT_MASK
  [ALSA] hda-codec - Add support for ASUS P4GPL-X
  [ALSA] hda-codec - Add support for HP nx9420 laptop
  [ALSA] Fix memory leaks in error path of control.c
  [ALSA] AMD Au1x00: AC'97 controller is memory mapped
  [ALSA] AMD Au1x00: fix DMA init/cleanup
  [ALSA] hda-codec - Fix generic auto-configurator
  [ALSA] hda-codec - Fix BIOS auto-configuration
  [ALSA] Fixes typos in Audiophile-USB.txt
  [ALSA] ice1712 - typo fixes for dxr_enable module option
  [ALSA] AMD Au1x00: make driver build after cleanup
  [ALSA] ice1712 - Fix wrong value types for enum items
  [ALSA] fix resource leak in usbmixer
  [ALSA] Fix gus_pcm dereference before NULL
  [ALSA] Fix seq_clientmgr dereferences before NULL check
  [ALSA] hda-codec - Fix for Samsung R65 and ASUS A6J
  [ALSA] hda-codec - Add support for VAIO FE550G and SZ110
  [ALSA] usb-audio: add Maya44 mixer control names
  [ALSA] usb-audio: add Casio PL-40R support
  ...

308 files changed:
.gitignore
Documentation/BUG-HUNTING
Documentation/dvb/get_dvb_firmware
Documentation/filesystems/isofs.txt
Documentation/filesystems/jfs.txt
Documentation/filesystems/vfat.txt
Documentation/spinlocks.txt
MAINTAINERS
arch/alpha/mm/init.c
arch/arm/mm/consistent.c
arch/arm/mm/init.c
arch/arm26/mm/init.c
arch/cris/mm/init.c
arch/frv/kernel/frv_ksyms.c
arch/frv/mm/dma-alloc.c
arch/frv/mm/init.c
arch/h8300/kernel/h8300_ksyms.c
arch/h8300/mm/init.c
arch/i386/kernel/efi.c
arch/i386/kernel/smp.c
arch/i386/kernel/sys_i386.c
arch/i386/kernel/timers/timer_hpet.c
arch/i386/kernel/timers/timer_tsc.c
arch/i386/mm/hugetlbpage.c
arch/i386/mm/init.c
arch/i386/mm/pageattr.c
arch/ia64/mm/hugetlbpage.c
arch/ia64/mm/init.c
arch/m32r/mm/init.c
arch/m68k/mm/init.c
arch/m68k/mm/memory.c
arch/m68k/mm/motorola.c
arch/m68knommu/kernel/m68k_ksyms.c
arch/m68knommu/mm/init.c
arch/mips/arc/memory.c
arch/mips/dec/prom/memory.c
arch/mips/mips-boards/generic/memory.c
arch/mips/mips-boards/sim/sim_mem.c
arch/mips/mm/init.c
arch/mips/sgi-ip27/ip27-memory.c
arch/parisc/mm/init.c
arch/powerpc/mm/hugetlbpage.c
arch/powerpc/mm/init_32.c
arch/powerpc/mm/init_64.c
arch/powerpc/mm/mem.c
arch/powerpc/platforms/cell/setup.c
arch/ppc/kernel/dma-mapping.c
arch/ppc/mm/init.c
arch/s390/mm/init.c
arch/sh/mm/consistent.c
arch/sh/mm/hugetlbpage.c
arch/sh/mm/init.c
arch/sh64/mm/hugetlbpage.c
arch/sh64/mm/init.c
arch/sparc/kernel/sun4d_smp.c
arch/sparc/kernel/sun4m_smp.c
arch/sparc/mm/generic.c
arch/sparc/mm/init.c
arch/sparc/mm/loadmmu.c
arch/sparc/mm/srmmu.c
arch/sparc/mm/sun4c.c
arch/sparc64/Kconfig
arch/sparc64/kernel/pci.c
arch/sparc64/kernel/sun4v_tlb_miss.S
arch/sparc64/kernel/traps.c
arch/sparc64/kernel/tsb.S
arch/sparc64/mm/fault.c
arch/sparc64/mm/generic.c
arch/sparc64/mm/hugetlbpage.c
arch/sparc64/mm/init.c
arch/sparc64/mm/tsb.c
arch/um/kernel/mem.c
arch/um/kernel/physmem.c
arch/x86_64/kernel/time.c
arch/x86_64/kernel/x8664_ksyms.c
arch/x86_64/mm/init.c
arch/x86_64/mm/pageattr.c
arch/xtensa/mm/init.c
arch/xtensa/mm/pgtable.c
drivers/base/bus.c
drivers/base/platform.c
drivers/block/cciss.c
drivers/char/drm/drm_vm.c
drivers/char/tb0219.c
drivers/char/vr41xx_giu.c
drivers/char/vr41xx_rtc.c
drivers/char/watchdog/mv64x60_wdt.c
drivers/firmware/dcdbas.c
drivers/md/dm.c
drivers/message/fusion/Kconfig
drivers/message/fusion/Makefile
drivers/message/fusion/lsi/mpi_log_sas.h
drivers/message/fusion/mptbase.c
drivers/message/fusion/mptbase.h
drivers/message/fusion/mptctl.c
drivers/message/fusion/mptfc.c
drivers/message/fusion/mptlan.c
drivers/message/fusion/mptsas.c
drivers/message/fusion/mptscsih.c
drivers/message/fusion/mptscsih.h
drivers/message/fusion/mptspi.c
drivers/message/i2o/exec-osm.c
drivers/net/Kconfig
drivers/net/tg3.c
drivers/s390/net/claw.c
drivers/sbus/char/flash.c
drivers/scsi/3w-9xxx.c
drivers/scsi/3w-9xxx.h
drivers/scsi/53c700.c
drivers/scsi/FlashPoint.c
drivers/scsi/NCR_D700.c
drivers/scsi/aacraid/aacraid.h
drivers/scsi/aacraid/comminit.c
drivers/scsi/aacraid/commsup.c
drivers/scsi/aacraid/linit.c
drivers/scsi/aha152x.c
drivers/scsi/ahci.c
drivers/scsi/aic7xxx/aic79xx_core.c
drivers/scsi/aic7xxx/aic79xx_osm.c
drivers/scsi/aic7xxx/aic79xx_osm.h
drivers/scsi/aic7xxx/aic7xxx_core.c
drivers/scsi/aic7xxx/aic7xxx_osm.c
drivers/scsi/aic7xxx/aic7xxx_osm.h
drivers/scsi/ata_piix.c
drivers/scsi/ch.c
drivers/scsi/dmx3191d.c
drivers/scsi/hosts.c
drivers/scsi/ibmmca.c
drivers/scsi/ipr.c
drivers/scsi/ips.c
drivers/scsi/iscsi_tcp.c
drivers/scsi/jazz_esp.c
drivers/scsi/libata-core.c
drivers/scsi/libata-scsi.c
drivers/scsi/libata.h
drivers/scsi/lpfc/lpfc.h
drivers/scsi/lpfc/lpfc_attr.c
drivers/scsi/lpfc/lpfc_crtn.h
drivers/scsi/lpfc/lpfc_ct.c
drivers/scsi/lpfc/lpfc_disc.h
drivers/scsi/lpfc/lpfc_els.c
drivers/scsi/lpfc/lpfc_hbadisc.c
drivers/scsi/lpfc/lpfc_hw.h
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_mbox.c
drivers/scsi/lpfc/lpfc_nportdisc.c
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/lpfc/lpfc_scsi.h
drivers/scsi/lpfc/lpfc_sli.c
drivers/scsi/lpfc/lpfc_sli.h
drivers/scsi/lpfc/lpfc_version.h
drivers/scsi/megaraid/megaraid_sas.c
drivers/scsi/ncr53c8xx.c
drivers/scsi/ncr53c8xx.h
drivers/scsi/osst.c
drivers/scsi/osst.h
drivers/scsi/pdc_adma.c
drivers/scsi/qla2xxx/Kconfig
drivers/scsi/qla2xxx/Makefile
drivers/scsi/qla2xxx/ql2300.c
drivers/scsi/qla2xxx/ql2300_fw.c
drivers/scsi/qla2xxx/ql2322.c
drivers/scsi/qla2xxx/ql2322_fw.c
drivers/scsi/qla2xxx/ql2400.c
drivers/scsi/qla2xxx/ql2400_fw.c
drivers/scsi/qla2xxx/ql6312.c [deleted file]
drivers/scsi/qla2xxx/ql6312_fw.c [deleted file]
drivers/scsi/qla2xxx/qla_attr.c
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_devtbl.h
drivers/scsi/qla2xxx/qla_fw.h
drivers/scsi/qla2xxx/qla_gbl.h
drivers/scsi/qla2xxx/qla_gs.c
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_inline.h
drivers/scsi/qla2xxx/qla_iocb.c
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/qla2xxx/qla_mbx.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qla2xxx/qla_sup.c
drivers/scsi/sata_mv.c
drivers/scsi/sata_nv.c
drivers/scsi/sata_promise.c
drivers/scsi/sata_qstor.c
drivers/scsi/sata_sil.c
drivers/scsi/sata_sil24.c
drivers/scsi/sata_sis.c
drivers/scsi/sata_svw.c
drivers/scsi/sata_sx4.c
drivers/scsi/sata_uli.c
drivers/scsi/sata_via.c
drivers/scsi/sata_vsc.c
drivers/scsi/scsi.c
drivers/scsi/scsi_debug.c
drivers/scsi/scsi_error.c
drivers/scsi/scsi_ioctl.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_scan.c
drivers/scsi/scsi_sysfs.c
drivers/scsi/scsi_transport_fc.c
drivers/scsi/scsi_transport_iscsi.c
drivers/scsi/scsi_transport_sas.c
drivers/scsi/scsi_transport_spi.c
drivers/scsi/sd.c
drivers/scsi/sg.c
drivers/scsi/sgiwd93.c
drivers/scsi/sim710.c
drivers/scsi/sr.c
drivers/scsi/st.c
drivers/scsi/sym53c8xx_2/sym_hipd.c
drivers/scsi/wd33c93.c
drivers/serial/Kconfig
drivers/serial/serial_txx9.c
drivers/serial/vr41xx_siu.c
drivers/video/acornfb.c
drivers/video/fbmem.c
drivers/video/i810/i810_main.c
drivers/video/sbuslib.c
fs/9p/vfs_inode.c
fs/befs/linuxvfs.c
fs/buffer.c
fs/cifs/CHANGES
fs/fat/dir.c
fs/fat/inode.c
fs/hugetlbfs/inode.c
fs/isofs/joliet.c
fs/nls/Kconfig
fs/ocfs2/super.c
fs/ramfs/file-nommu.c
fs/xfs/linux-2.6/xfs_buf.c
include/asm-i386/acpi.h
include/asm-i386/pgtable.h
include/asm-ia64/page.h
include/asm-ia64/pgtable.h
include/asm-mips/termbits.h
include/asm-powerpc/pgtable.h
include/asm-s390/pgalloc.h
include/asm-sh64/pgalloc.h
include/asm-sparc/pgtable.h
include/asm-sparc64/cpudata.h
include/asm-sparc64/mmu.h
include/asm-sparc64/mmu_context.h
include/asm-sparc64/page.h
include/asm-sparc64/pgtable.h
include/asm-x86_64/pgtable.h
include/linux/device.h
include/linux/hugetlb.h
include/linux/libata.h
include/linux/migrate.h [new file with mode: 0644]
include/linux/mm.h
include/linux/mm_inline.h
include/linux/msdos_fs.h
include/linux/net.h
include/linux/page-flags.h
include/linux/pci_ids.h
include/linux/rtc.h
include/linux/slab.h
include/linux/smp.h
include/linux/swap.h
include/linux/workqueue.h
include/linux/x25.h
include/net/compat.h
include/net/x25.h
include/scsi/scsi.h
include/scsi/scsi_cmnd.h
include/scsi/scsi_device.h
include/scsi/scsi_host.h
include/scsi/scsi_transport.h
include/scsi/scsi_transport_sas.h
include/scsi/scsi_transport_spi.h
ipc/mqueue.c
kernel/fork.c
kernel/sched.c
kernel/softirq.c
kernel/workqueue.c
lib/string.c
mm/Kconfig
mm/Makefile
mm/filemap.c
mm/hugetlb.c
mm/internal.h
mm/memory.c
mm/mempolicy.c
mm/mempool.c
mm/migrate.c [new file with mode: 0644]
mm/mmap.c
mm/mprotect.c
mm/nommu.c
mm/page_alloc.c
mm/readahead.c
mm/rmap.c
mm/shmem.c
mm/slab.c
mm/swap.c
mm/swap_state.c
mm/swapfile.c
mm/vmscan.c
net/bluetooth/bnep/core.c
net/compat.c
net/socket.c
net/x25/af_x25.c
net/x25/x25_facilities.c
net/x25/x25_in.c
net/x25/x25_subr.c
security/keys/process_keys.c
security/selinux/hooks.c
security/selinux/selinuxfs.c
security/selinux/ss/services.c

index 53e53f2791f882d2c3f2ec58ca472573eeda14f3..27fd37621255799602d74e94d670ff7a1658d40a 100644 (file)
@@ -16,6 +16,7 @@
 #
 # Top-level generic files
 #
+tags
 vmlinux*
 System.map
 Module.symvers
index ca29242dbc38d83328c2866d5413e719a3662997..65b97e1dbf70cabf7a92dee53831f191f16b4015 100644 (file)
@@ -1,3 +1,56 @@
+Table of contents
+=================
+
+Last updated: 20 December 2005
+
+Contents
+========
+
+- Introduction
+- Devices not appearing
+- Finding patch that caused a bug
+-- Finding using git-bisect
+-- Finding it the old way
+- Fixing the bug
+
+Introduction
+============
+
+Always try the latest kernel from kernel.org and build from source. If you are
+not confident in doing that please report the bug to your distribution vendor
+instead of to a kernel developer.
+
+Finding bugs is not always easy. Have a go though. If you can't find it don't
+give up. Report as much as you have found to the relevant maintainer. See
+MAINTAINERS for who that is for the subsystem you have worked on.
+
+Before you submit a bug report read REPORTING-BUGS.
+
+Devices not appearing
+=====================
+
+Often this is caused by udev. Check that first before blaming it on the
+kernel.
+
+Finding patch that caused a bug
+===============================
+
+
+
+Finding using git-bisect
+------------------------
+
+Using the provided tools with git makes finding bugs easy provided the bug is
+reproducible.
+
+Steps to do it:
+- start using git for the kernel source
+- read the man page for git-bisect
+- have fun
+
+Finding it the old way
+----------------------
+
 [Sat Mar  2 10:32:33 PST 1996 KERNEL_BUG-HOWTO lm@sgi.com (Larry McVoy)]
 
 This is how to track down a bug if you know nothing about kernel hacking.  
@@ -90,3 +143,63 @@ it does work and it lets non-hackers help fix bugs.  And it is cool
 because Linux snapshots will let you do this - something that you can't
 do with vendor supplied releases.
 
+Fixing the bug
+==============
+
+Nobody is going to tell you how to fix bugs. Seriously. You need to work it
+out. But below are some hints on how to use the tools.
+
+To debug a kernel, use objdump and look for the hex offset from the crash
+output to find the valid line of code/assembler. Without debug symbols, you
+will see the assembler code for the routine shown, but if your kernel has
+debug symbols the C code will also be available. (Debug symbols can be enabled
+in the kernel hacking menu of the menu configuration.) For example:
+
+    objdump -r -S -l --disassemble net/dccp/ipv4.o
+
+NB.: you need to be at the top level of the kernel tree for this to pick up
+your C files.
+
+If you don't have access to the code you can also debug on some crash dumps
+e.g. crash dump output as shown by Dave Miller.
+
+>    EIP is at ip_queue_xmit+0x14/0x4c0
+>     ...
+>    Code: 44 24 04 e8 6f 05 00 00 e9 e8 fe ff ff 8d 76 00 8d bc 27 00 00
+>    00 00 55 57  56 53 81 ec bc 00 00 00 8b ac 24 d0 00 00 00 8b 5d 08
+>    <8b> 83 3c 01 00 00 89 44  24 14 8b 45 28 85 c0 89 44 24 18 0f 85
+>
+>    Put the bytes into a "foo.s" file like this:
+>
+>           .text
+>           .globl foo
+>    foo:
+>           .byte  .... /* bytes from Code: part of OOPS dump */
+>
+>    Compile it with "gcc -c -o foo.o foo.s" then look at the output of
+>    "objdump --disassemble foo.o".
+>
+>    Output:
+>
+>    ip_queue_xmit:
+>        push       %ebp
+>        push       %edi
+>        push       %esi
+>        push       %ebx
+>        sub        $0xbc, %esp
+>        mov        0xd0(%esp), %ebp        ! %ebp = arg0 (skb)
+>        mov        0x8(%ebp), %ebx         ! %ebx = skb->sk
+>        mov        0x13c(%ebx), %eax       ! %eax = inet_sk(sk)->opt
+
+Another very useful option of the Kernel Hacking section in menuconfig is
+Debug memory allocations. This will help you see whether data has been
+initialised and not set before use etc. To see the values that get assigned
+with this look at mm/slab.c and search for POISON_INUSE. When using this an
+Oops will often show the poisoned data instead of zero which is the default.
+
+Once you have worked out a fix please submit it upstream. After all open
+source is about sharing what you do and don't you want to be recognised for
+your genius?
+
+Please do read Documentation/SubmittingPatches though to help your code get
+accepted.
index bb55f49f2745e6f556d6aa6e24c80e6648e67e03..15fc8fbef67e3fa48a8d68365b1852103e501115 100644 (file)
@@ -246,7 +246,7 @@ sub vp7041 {
 }
 
 sub dibusb {
-       my $url = "http://www.linuxtv.org/downloads/firmware/dvb-dibusb-5.0.0.11.fw";
+       my $url = "http://www.linuxtv.org/downloads/firmware/dvb-usb-dibusb-5.0.0.11.fw";
        my $outfile = "dvb-dibusb-5.0.0.11.fw";
        my $hash = "fa490295a527360ca16dcdf3224ca243";
 
index 424585ff6ea1c18daf7b9f47da97edd72b72dba1..758e50401c1635654fa073d9f9bcc8931ad8b9af 100644 (file)
@@ -9,9 +9,9 @@ when using discs encoded using Microsoft's Joliet extensions.
   iocharset=name Character set to use for converting from Unicode to
                ASCII.  Joliet filenames are stored in Unicode format, but
                Unix for the most part doesn't know how to deal with Unicode.
-               There is also an option of doing UTF8 translations with the
+               There is also an option of doing UTF-8 translations with the
                utf8 option.
-  utf8          Encode Unicode names in UTF8 format. Default is no.
+  utf8          Encode Unicode names in UTF-8 format. Default is no.
 
 Mount options unique to the isofs filesystem.
   block=512     Set the block size for the disk to 512 bytes
index 3e992daf99adb22e318ce3bcc63e931e14e8b68e..bae128663748ebcac0df61ab910827bfaf932f96 100644 (file)
@@ -6,7 +6,7 @@ The following mount options are supported:
 
 iocharset=name Character set to use for converting from Unicode to
                ASCII.  The default is to do no conversion.  Use
-               iocharset=utf8 for UTF8 translations.  This requires
+               iocharset=utf8 for UTF-8 translations.  This requires
                CONFIG_NLS_UTF8 to be set in the kernel .config file.
                iocharset=none specifies the default behavior explicitly.
 
index 5ead20c6c7443f4b2667f3c90ba29e45f45a63c9..2001abbc60e6f599fc53abc3b746ce2effc75187 100644 (file)
@@ -28,16 +28,16 @@ iocharset=name -- Character set to use for converting between the
                 know how to deal with Unicode.
                 By default, FAT_DEFAULT_IOCHARSET setting is used.
 
-                There is also an option of doing UTF8 translations
+                There is also an option of doing UTF-8 translations
                 with the utf8 option.
 
                 NOTE: "iocharset=utf8" is not recommended. If unsure,
                 you should consider the following option instead.
 
-utf8=<bool>   -- UTF8 is the filesystem safe version of Unicode that
+utf8=<bool>   -- UTF-8 is the filesystem safe version of Unicode that
                 is used by the console.  It can be be enabled for the
                 filesystem with this option. If 'uni_xlate' gets set,
-                UTF8 gets disabled.
+                UTF-8 gets disabled.
 
 uni_xlate=<bool> -- Translate unhandled Unicode characters to special
                 escaped sequences.  This would let you backup and
index c2122996631e4d413fffe6be3d1173f827a8649c..a661d684768e99c2cb9737b1e5f85925554f9235 100644 (file)
@@ -9,7 +9,7 @@ removed soon. So for any new code dynamic initialization should be used:
    static int __init xxx_init(void)
    {
        spin_lock_init(&xxx_lock);
-       rw_lock_init(&xxx_rw_lock);
+       rwlock_init(&xxx_rw_lock);
        ...
    }
 
index ebef0ae90e2e3d8e4c45c66ebe69d9442cba0add..dd1351dc32b895b5298fabe7c0c37062af9489c4 100644 (file)
@@ -2145,7 +2145,7 @@ S:        Maintained
 
 QLOGIC QLA2XXX FC-SCSI DRIVER
 P:     Andrew Vasquez
-M:     andrew.vasquez@qlogic.com
+M:     linux-driver@qlogic.com
 L:     linux-scsi@vger.kernel.org
 S:     Supported
 
index 486d7945583d1d59fde2dbff8e2f919f1ef06273..544ac5dc09eb60e2b00eb5ea58e6da483a266030 100644 (file)
@@ -357,7 +357,7 @@ free_reserved_mem(void *start, void *end)
        void *__start = start;
        for (; __start < end; __start += PAGE_SIZE) {
                ClearPageReserved(virt_to_page(__start));
-               set_page_count(virt_to_page(__start), 1);
+               init_page_count(virt_to_page(__start));
                free_page((long)__start);
                totalram_pages++;
        }
index c2ee18d2075e7bd22312835cf9c3d859c0913f5b..8a1bfcd500871dde0eb02b72962ef06060ae6b88 100644 (file)
@@ -223,6 +223,8 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
                pte = consistent_pte[idx] + off;
                c->vm_pages = page;
 
+               split_page(page, order);
+
                /*
                 * Set the "dma handle"
                 */
@@ -231,7 +233,6 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
                do {
                        BUG_ON(!pte_none(*pte));
 
-                       set_page_count(page, 1);
                        /*
                         * x86 does not mark the pages reserved...
                         */
@@ -250,7 +251,6 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
                 * Free the otherwise unused pages.
                 */
                while (page < end) {
-                       set_page_count(page, 1);
                        __free_page(page);
                        page++;
                }
index 8b276ee38acfabdb65b35e6b07903716b9db100d..b0321e943b7693a5e1122e7c2d453218f1efd798 100644 (file)
@@ -531,7 +531,7 @@ static inline void free_area(unsigned long addr, unsigned long end, char *s)
        for (; addr < end; addr += PAGE_SIZE) {
                struct page *page = virt_to_page(addr);
                ClearPageReserved(page);
-               set_page_count(page, 1);
+               init_page_count(page);
                free_page(addr);
                totalram_pages++;
        }
index 1f09a9d0fb8375297c97f38d2907f3f03793bfaf..e3ecaa4537478d8cb8c9f47f114f9eae76d46228 100644 (file)
@@ -324,7 +324,7 @@ static inline void free_area(unsigned long addr, unsigned long end, char *s)
        for (; addr < end; addr += PAGE_SIZE) {
                struct page *page = virt_to_page(addr);
                ClearPageReserved(page);
-               set_page_count(page, 1);
+               init_page_count(page);
                free_page(addr);
                totalram_pages++;
        }
index 31a0018b525aa795793c50e25ac58cae1b259371..b7842ff213a6688f3e675e5c39b78bf311a34c12 100644 (file)
@@ -216,7 +216,7 @@ free_initmem(void)
         addr = (unsigned long)(&__init_begin);
         for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
                 ClearPageReserved(virt_to_page(addr));
-                set_page_count(virt_to_page(addr), 1);
+                init_page_count(virt_to_page(addr));
                 free_page(addr);
                 totalram_pages++;
         }
index 0f1c6cbc4f50706e50267be0f41b666784afa83e..aa6b7d0a2109388f4be5515c922162f5aa61fc87 100644 (file)
@@ -27,6 +27,7 @@ EXPORT_SYMBOL(__ioremap);
 EXPORT_SYMBOL(iounmap);
 
 EXPORT_SYMBOL(strnlen);
+EXPORT_SYMBOL(strpbrk);
 EXPORT_SYMBOL(strrchr);
 EXPORT_SYMBOL(strstr);
 EXPORT_SYMBOL(strchr);
index 342823aad758c13087c0f20c8c06e6ccc3d1dffd..636b2f8b5d981934e2b1a99635ae397d0779d7de 100644 (file)
@@ -115,9 +115,7 @@ void *consistent_alloc(gfp_t gfp, size_t size, dma_addr_t *dma_handle)
         */
        if (order > 0) {
                struct page *rpage = virt_to_page(page);
-
-               for (i = 1; i < (1 << order); i++)
-                       set_page_count(rpage + i, 1);
+               split_page(rpage, order);
        }
 
        err = 0;
index 765088ea8a505844649258d9f2dd7cb60904e047..8899aa1a4f06f6e0d32a8d125b4a3b247ca53025 100644 (file)
@@ -169,7 +169,7 @@ void __init mem_init(void)
                struct page *page = &mem_map[pfn];
 
                ClearPageReserved(page);
-               set_page_count(page, 1);
+               init_page_count(page);
                __free_page(page);
                totalram_pages++;
        }
@@ -210,7 +210,7 @@ void __init free_initmem(void)
        /* next to check that the page we free is not a partial page */
        for (addr = start; addr < end; addr += PAGE_SIZE) {
                ClearPageReserved(virt_to_page(addr));
-               set_page_count(virt_to_page(addr), 1);
+               init_page_count(virt_to_page(addr));
                free_page(addr);
                totalram_pages++;
        }
@@ -230,7 +230,7 @@ void __init free_initrd_mem(unsigned long start, unsigned long end)
        int pages = 0;
        for (; start < end; start += PAGE_SIZE) {
                ClearPageReserved(virt_to_page(start));
-               set_page_count(virt_to_page(start), 1);
+               init_page_count(virt_to_page(start));
                free_page(start);
                totalram_pages++;
                pages++;
index 5cc76efaf7aa2838ccd711052732c0a2e8fc6021..69d6ad32d56c86794c70f32687278ff8846bce6d 100644 (file)
@@ -25,6 +25,7 @@ extern char h8300_debug_device[];
 /* platform dependent support */
 
 EXPORT_SYMBOL(strnlen);
+EXPORT_SYMBOL(strpbrk);
 EXPORT_SYMBOL(strrchr);
 EXPORT_SYMBOL(strstr);
 EXPORT_SYMBOL(strchr);
index 1e0929ddc8c46b6c897cee48668779a1c989895c..09efc4b1f038f5b66ba444bd904660bdac44c319 100644 (file)
@@ -196,7 +196,7 @@ void free_initrd_mem(unsigned long start, unsigned long end)
        int pages = 0;
        for (; start < end; start += PAGE_SIZE) {
                ClearPageReserved(virt_to_page(start));
-               set_page_count(virt_to_page(start), 1);
+               init_page_count(virt_to_page(start));
                free_page(start);
                totalram_pages++;
                pages++;
@@ -219,7 +219,7 @@ free_initmem()
        /* next to check that the page we free is not a partial page */
        for (; addr + PAGE_SIZE < (unsigned long)(&__init_end); addr +=PAGE_SIZE) {
                ClearPageReserved(virt_to_page(addr));
-               set_page_count(virt_to_page(addr), 1);
+               init_page_count(virt_to_page(addr));
                free_page(addr);
                totalram_pages++;
        }
index c9cad7ba0d2d5eced0508ff256eb1c1a62c92764..aeabb41968610f3aedce1fbff43fad4e3bbebd35 100644 (file)
@@ -115,7 +115,7 @@ static void efi_call_phys_epilog(void)
        unsigned long cr4;
        struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, 0);
 
-       cpu_gdt_descr->address = __va(cpu_gdt_descr->address);
+       cpu_gdt_descr->address = (unsigned long)__va(cpu_gdt_descr->address);
        load_gdt(cpu_gdt_descr);
 
        cr4 = read_cr4();
index 218d725a5a1e89ff7f3dc7175ca22c59624e7b96..d134e9643a58a0303cb67672486709d9da244591 100644 (file)
@@ -504,27 +504,23 @@ void unlock_ipi_call_lock(void)
        spin_unlock_irq(&call_lock);
 }
 
-static struct call_data_struct * call_data;
-
-/*
- * this function sends a 'generic call function' IPI to all other CPUs
- * in the system.
- */
-
-int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
-                       int wait)
-/*
- * [SUMMARY] Run a function on all other CPUs.
- * <func> The function to run. This must be fast and non-blocking.
- * <info> An arbitrary pointer to pass to the function.
- * <nonatomic> currently unused.
- * <wait> If true, wait (atomically) until function has completed on other CPUs.
- * [RETURNS] 0 on success, else a negative status code. Does not return until
+static struct call_data_struct *call_data;
+
+/**
+ * smp_call_function(): Run a function on all other CPUs.
+ * @func: The function to run. This must be fast and non-blocking.
+ * @info: An arbitrary pointer to pass to the function.
+ * @nonatomic: currently unused.
+ * @wait: If true, wait (atomically) until function has completed on other CPUs.
+ *
+ * Returns 0 on success, else a negative status code. Does not return until
  * remote CPUs are nearly ready to execute <<func>> or are or have executed.
  *
  * You must not call this function with disabled interrupts or from a
  * hardware interrupt handler or from a bottom half handler.
  */
+int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
+                       int wait)
 {
        struct call_data_struct data;
        int cpus;
index a4a61976ecb922fea01df1a5ea4d07dbc3f155bf..8fdb1fb17a5f0ca457cdf0bdaa8e3d998fcd0ccf 100644 (file)
@@ -40,14 +40,13 @@ asmlinkage int sys_pipe(unsigned long __user * fildes)
        return error;
 }
 
-/* common code for old and new mmaps */
-static inline long do_mmap2(
-       unsigned long addr, unsigned long len,
-       unsigned long prot, unsigned long flags,
-       unsigned long fd, unsigned long pgoff)
+asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
+                         unsigned long prot, unsigned long flags,
+                         unsigned long fd, unsigned long pgoff)
 {
        int error = -EBADF;
-       struct file * file = NULL;
+       struct file *file = NULL;
+       struct mm_struct *mm = current->mm;
 
        flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
        if (!(flags & MAP_ANONYMOUS)) {
@@ -56,9 +55,9 @@ static inline long do_mmap2(
                        goto out;
        }
 
-       down_write(&current->mm->mmap_sem);
+       down_write(&mm->mmap_sem);
        error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-       up_write(&current->mm->mmap_sem);
+       up_write(&mm->mmap_sem);
 
        if (file)
                fput(file);
@@ -66,13 +65,6 @@ out:
        return error;
 }
 
-asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
-       unsigned long prot, unsigned long flags,
-       unsigned long fd, unsigned long pgoff)
-{
-       return do_mmap2(addr, len, prot, flags, fd, pgoff);
-}
-
 /*
  * Perform the select(nd, in, out, ex, tv) and mmap() system
  * calls. Linux/i386 didn't use to be able to handle more than
@@ -101,7 +93,8 @@ asmlinkage int old_mmap(struct mmap_arg_struct __user *arg)
        if (a.offset & ~PAGE_MASK)
                goto out;
 
-       err = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
+       err = sys_mmap2(a.addr, a.len, a.prot, a.flags,
+                       a.fd, a.offset >> PAGE_SHIFT);
 out:
        return err;
 }
index be242723c33988fc2cf8222ea20430554e775c89..17a6fe7166e7b48c2a2956a440918131e470f712 100644 (file)
@@ -46,7 +46,7 @@ static seqlock_t monotonic_lock = SEQLOCK_UNLOCKED;
  *
  *                     -johnstul@us.ibm.com "math is hard, lets go shopping!"
  */
-static unsigned long cyc2ns_scale;
+static unsigned long cyc2ns_scale __read_mostly;
 #define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */
 
 static inline void set_cyc2ns_scale(unsigned long cpu_khz)
index a7f5a2aceba2d335402a48168d749f2736dadf41..5e41ee29c8cff1dff22ffd7142b7dfc96f9e3594 100644 (file)
@@ -74,7 +74,7 @@ late_initcall(start_lost_tick_compensation);
  *
  *                     -johnstul@us.ibm.com "math is hard, lets go shopping!"
  */
-static unsigned long cyc2ns_scale
+static unsigned long cyc2ns_scale __read_mostly;
 #define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */
 
 static inline void set_cyc2ns_scale(unsigned long cpu_khz)
index d524127c9afc3b2f92b3e5ad6b3dbce20bec42f7..a7d8915854116264048f62c84d63dc495fc212b7 100644 (file)
@@ -48,18 +48,6 @@ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
        return (pte_t *) pmd;
 }
 
-/*
- * This function checks for proper alignment of input addr and len parameters.
- */
-int is_aligned_hugepage_range(unsigned long addr, unsigned long len)
-{
-       if (len & ~HPAGE_MASK)
-               return -EINVAL;
-       if (addr & ~HPAGE_MASK)
-               return -EINVAL;
-       return 0;
-}
-
 #if 0  /* This is just for testing */
 struct page *
 follow_huge_addr(struct mm_struct *mm, unsigned long address, int write)
index 2700f01994ba1645ff788bc0310898492ac86ede..7ba55a6e2dbcd3e51dadce36e32a7a33260ddaad 100644 (file)
@@ -270,7 +270,7 @@ static void __init permanent_kmaps_init(pgd_t *pgd_base)
 
 static void __meminit free_new_highpage(struct page *page)
 {
-       set_page_count(page, 1);
+       init_page_count(page);
        __free_page(page);
        totalhigh_pages++;
 }
@@ -727,7 +727,7 @@ void free_initmem(void)
        addr = (unsigned long)(&__init_begin);
        for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
                ClearPageReserved(virt_to_page(addr));
-               set_page_count(virt_to_page(addr), 1);
+               init_page_count(virt_to_page(addr));
                memset((void *)addr, 0xcc, PAGE_SIZE);
                free_page(addr);
                totalram_pages++;
@@ -766,7 +766,7 @@ void free_initrd_mem(unsigned long start, unsigned long end)
                printk (KERN_INFO "Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
        for (; start < end; start += PAGE_SIZE) {
                ClearPageReserved(virt_to_page(start));
-               set_page_count(virt_to_page(start), 1);
+               init_page_count(virt_to_page(start));
                free_page(start);
                totalram_pages++;
        }
index d0cadb33b54c1088f4eb609a28409fecf7ed7c74..92c3d9f0e7314f984fdd60a3ffbbfd3b01259edc 100644 (file)
@@ -51,6 +51,13 @@ static struct page *split_large_page(unsigned long address, pgprot_t prot,
        if (!base) 
                return NULL;
 
+       /*
+        * page_private is used to track the number of entries in
+        * the page table page that have non standard attributes.
+        */
+       SetPagePrivate(base);
+       page_private(base) = 0;
+
        address = __pa(address);
        addr = address & LARGE_PAGE_MASK; 
        pbase = (pte_t *)page_address(base);
@@ -143,11 +150,12 @@ __change_page_attr(struct page *page, pgprot_t prot)
                                return -ENOMEM;
                        set_pmd_pte(kpte,address,mk_pte(split, ref_prot));
                        kpte_page = split;
-               }       
-               get_page(kpte_page);
+               }
+               page_private(kpte_page)++;
        } else if ((pte_val(*kpte) & _PAGE_PSE) == 0) { 
                set_pte_atomic(kpte, mk_pte(page, PAGE_KERNEL));
-               __put_page(kpte_page);
+               BUG_ON(page_private(kpte_page) == 0);
+               page_private(kpte_page)--;
        } else
                BUG();
 
@@ -157,10 +165,8 @@ __change_page_attr(struct page *page, pgprot_t prot)
         * replace it with a largepage.
         */
        if (!PageReserved(kpte_page)) {
-               /* memleak and potential failed 2M page regeneration */
-               BUG_ON(!page_count(kpte_page));
-
-               if (cpu_has_pse && (page_count(kpte_page) == 1)) {
+               if (cpu_has_pse && (page_private(kpte_page) == 0)) {
+                       ClearPagePrivate(kpte_page);
                        list_add(&kpte_page->lru, &df_list);
                        revert_page(kpte_page, address);
                }
index 2d13889d0a9915da645b074ecbef1f8a0b56d116..9dbc7dadd1653a79b078fa1b79f1e43266db84db 100644 (file)
@@ -68,9 +68,10 @@ huge_pte_offset (struct mm_struct *mm, unsigned long addr)
 #define mk_pte_huge(entry) { pte_val(entry) |= _PAGE_P; }
 
 /*
- * This function checks for proper alignment of input addr and len parameters.
+ * Don't actually need to do any preparation, but need to make sure
+ * the address is in the right region.
  */
-int is_aligned_hugepage_range(unsigned long addr, unsigned long len)
+int prepare_hugepage_range(unsigned long addr, unsigned long len)
 {
        if (len & ~HPAGE_MASK)
                return -EINVAL;
index b38b6d213c158ad0651a20a343e4a3f8327d7f98..08d94e6bfa18bcd2bc823231e3a73944927bf041 100644 (file)
@@ -197,7 +197,7 @@ free_initmem (void)
        eaddr = (unsigned long) ia64_imva(__init_end);
        while (addr < eaddr) {
                ClearPageReserved(virt_to_page(addr));
-               set_page_count(virt_to_page(addr), 1);
+               init_page_count(virt_to_page(addr));
                free_page(addr);
                ++totalram_pages;
                addr += PAGE_SIZE;
@@ -252,7 +252,7 @@ free_initrd_mem (unsigned long start, unsigned long end)
                        continue;
                page = virt_to_page(start);
                ClearPageReserved(page);
-               set_page_count(page, 1);
+               init_page_count(page);
                free_page(start);
                ++totalram_pages;
        }
@@ -640,7 +640,7 @@ mem_init (void)
 void online_page(struct page *page)
 {
        ClearPageReserved(page);
-       set_page_count(page, 1);
+       init_page_count(page);
        __free_page(page);
        totalram_pages++;
        num_physpages++;
index 6facf15b04f30d1353840e65fa8362fc664c4be1..c9e7dad860b741cf02e1b42022c91226c27388d9 100644 (file)
@@ -226,7 +226,7 @@ void free_initmem(void)
        addr = (unsigned long)(&__init_begin);
        for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
                ClearPageReserved(virt_to_page(addr));
-               set_page_count(virt_to_page(addr), 1);
+               init_page_count(virt_to_page(addr));
                free_page(addr);
                totalram_pages++;
        }
@@ -244,7 +244,7 @@ void free_initrd_mem(unsigned long start, unsigned long end)
        unsigned long p;
        for (p = start; p < end; p += PAGE_SIZE) {
                ClearPageReserved(virt_to_page(p));
-               set_page_count(virt_to_page(p), 1);
+               init_page_count(virt_to_page(p));
                free_page(p);
                totalram_pages++;
        }
index c45beb955943d6c1d5e3c89e6917b8de9ec0bca3..a190e39c907ad747fc3a2ab336a9da2745e79e3c 100644 (file)
@@ -137,7 +137,7 @@ void free_initrd_mem(unsigned long start, unsigned long end)
        int pages = 0;
        for (; start < end; start += PAGE_SIZE) {
                ClearPageReserved(virt_to_page(start));
-               set_page_count(virt_to_page(start), 1);
+               init_page_count(virt_to_page(start));
                free_page(start);
                totalram_pages++;
                pages++;
index 559942ce0e1e7bde2773ac90f5150dca5e542e5e..d6d582a5abb001b49114a05a71e6204a37a9f39e 100644 (file)
@@ -54,7 +54,7 @@ void __init init_pointer_table(unsigned long ptable)
 
        /* unreserve the page so it's possible to free that page */
        PD_PAGE(dp)->flags &= ~(1 << PG_reserved);
-       set_page_count(PD_PAGE(dp), 1);
+       init_page_count(PD_PAGE(dp));
 
        return;
 }
index d855fec263172c0ad0bb65ffa67a8121066e71fc..afb57eeafdcb191c68a22058db46a6ba9044686e 100644 (file)
@@ -276,7 +276,7 @@ void free_initmem(void)
        addr = (unsigned long)&__init_begin;
        for (; addr < (unsigned long)&__init_end; addr += PAGE_SIZE) {
                virt_to_page(addr)->flags &= ~(1 << PG_reserved);
-               set_page_count(virt_to_page(addr), 1);
+               init_page_count(virt_to_page(addr));
                free_page(addr);
                totalram_pages++;
        }
index eddb8d3e130ab116e7957349e2a17beb0566646b..d844c755945a2c3df9343cd7739c7a6d0563acca 100644 (file)
@@ -26,6 +26,7 @@ EXPORT_SYMBOL(__ioremap);
 EXPORT_SYMBOL(iounmap);
 EXPORT_SYMBOL(dump_fpu);
 EXPORT_SYMBOL(strnlen);
+EXPORT_SYMBOL(strpbrk);
 EXPORT_SYMBOL(strrchr);
 EXPORT_SYMBOL(strstr);
 EXPORT_SYMBOL(strchr);
index 89f0b554ffb79fb8acfc2d62e7487f75ce61e09e..d79503fe6e42f4d81a4cf9331d7cba0e387191ec 100644 (file)
@@ -195,7 +195,7 @@ void free_initrd_mem(unsigned long start, unsigned long end)
        int pages = 0;
        for (; start < end; start += PAGE_SIZE) {
                ClearPageReserved(virt_to_page(start));
-               set_page_count(virt_to_page(start), 1);
+               init_page_count(virt_to_page(start));
                free_page(start);
                totalram_pages++;
                pages++;
@@ -218,7 +218,7 @@ free_initmem()
        /* next to check that the page we free is not a partial page */
        for (; addr + PAGE_SIZE < (unsigned long)(&__init_end); addr +=PAGE_SIZE) {
                ClearPageReserved(virt_to_page(addr));
-               set_page_count(virt_to_page(addr), 1);
+               init_page_count(virt_to_page(addr));
                free_page(addr);
                totalram_pages++;
        }
index 958d2eb78862e5f66c18fa0747b0bb69b9f02fab..8a9ef58cc399313b2b46125cf0b207cc4c9ce2ab 100644 (file)
@@ -158,7 +158,7 @@ unsigned long __init prom_free_prom_memory(void)
                while (addr < boot_mem_map.map[i].addr
                              + boot_mem_map.map[i].size) {
                        ClearPageReserved(virt_to_page(__va(addr)));
-                       set_page_count(virt_to_page(__va(addr)), 1);
+                       init_page_count(virt_to_page(__va(addr)));
                        free_page((unsigned long)__va(addr));
                        addr += PAGE_SIZE;
                        freed += PAGE_SIZE;
index 81cb5a76cfb7b9b07e3acf3616902cf1cace0879..1edaf3074ee93f9bed2c287b21619b6c6fda7419 100644 (file)
@@ -118,7 +118,7 @@ unsigned long __init prom_free_prom_memory(void)
        addr = PAGE_SIZE;
        while (addr < end) {
                ClearPageReserved(virt_to_page(__va(addr)));
-               set_page_count(virt_to_page(__va(addr)), 1);
+               init_page_count(virt_to_page(__va(addr)));
                free_page((unsigned long)__va(addr));
                addr += PAGE_SIZE;
        }
index 2c8afd77a20b2a4f9df12a4923b4a8e8c8409627..ee5e70c95cf3fbdadd877ebd347231d6df955cab 100644 (file)
@@ -174,7 +174,7 @@ unsigned long __init prom_free_prom_memory(void)
                while (addr < boot_mem_map.map[i].addr
                              + boot_mem_map.map[i].size) {
                        ClearPageReserved(virt_to_page(__va(addr)));
-                       set_page_count(virt_to_page(__va(addr)), 1);
+                       init_page_count(virt_to_page(__va(addr)));
                        free_page((unsigned long)__va(addr));
                        addr += PAGE_SIZE;
                        freed += PAGE_SIZE;
index 0dbd7435bb2aff83985e0ad25360d93ab13f04de..1ec4e75656bd11c395559c9a65b1fff628becd56 100644 (file)
@@ -117,7 +117,7 @@ unsigned long __init prom_free_prom_memory(void)
                while (addr < boot_mem_map.map[i].addr
                              + boot_mem_map.map[i].size) {
                        ClearPageReserved(virt_to_page(__va(addr)));
-                       set_page_count(virt_to_page(__va(addr)), 1);
+                       init_page_count(virt_to_page(__va(addr)));
                        free_page((unsigned long)__va(addr));
                        addr += PAGE_SIZE;
                        freed += PAGE_SIZE;
index 0ff9a348b84317b2c915de9aeb485839fb1ff1ce..52f7d59fe6123b28469802a36120722e6224f365 100644 (file)
@@ -54,7 +54,8 @@ unsigned long empty_zero_page, zero_page_mask;
  */
 unsigned long setup_zero_pages(void)
 {
-       unsigned long order, size;
+       unsigned int order;
+       unsigned long size;
        struct page *page;
 
        if (cpu_has_vce)
@@ -67,9 +68,9 @@ unsigned long setup_zero_pages(void)
                panic("Oh boy, that early out of memory?");
 
        page = virt_to_page(empty_zero_page);
+       split_page(page, order);
        while (page < virt_to_page(empty_zero_page + (PAGE_SIZE << order))) {
                SetPageReserved(page);
-               set_page_count(page, 1);
                page++;
        }
 
@@ -244,7 +245,7 @@ void __init mem_init(void)
 #ifdef CONFIG_LIMITED_DMA
                set_page_address(page, lowmem_page_address(page));
 #endif
-               set_page_count(page, 1);
+               init_page_count(page);
                __free_page(page);
                totalhigh_pages++;
        }
@@ -291,7 +292,7 @@ void free_initrd_mem(unsigned long start, unsigned long end)
 
        for (; start < end; start += PAGE_SIZE) {
                ClearPageReserved(virt_to_page(start));
-               set_page_count(virt_to_page(start), 1);
+               init_page_count(virt_to_page(start));
                free_page(start);
                totalram_pages++;
        }
@@ -314,7 +315,7 @@ void free_initmem(void)
                page = addr;
 #endif
                ClearPageReserved(virt_to_page(page));
-               set_page_count(virt_to_page(page), 1);
+               init_page_count(virt_to_page(page));
                free_page(page);
                totalram_pages++;
                freed += PAGE_SIZE;
index ed93a9792959f240555f1746dd28daaa97dff506..e0d095daa5ed76782116ed5909d751e41345404f 100644 (file)
@@ -559,7 +559,7 @@ void __init mem_init(void)
                                /* if (!page_is_ram(pgnr)) continue; */
                                /* commented out until page_is_ram works */
                                ClearPageReserved(p);
-                               set_page_count(p, 1);
+                               init_page_count(p);
                                __free_page(p);
                                totalram_pages++;
                        }
index 7847ca13d6c2933b2be345e8d73a9ffd3d1229db..852eda3953dc7c86114e0b7cdeff08775485ed43 100644 (file)
@@ -398,7 +398,7 @@ void free_initmem(void)
        addr = (unsigned long)(&__init_begin);
        for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
                ClearPageReserved(virt_to_page(addr));
-               set_page_count(virt_to_page(addr), 1);
+               init_page_count(virt_to_page(addr));
                free_page(addr);
                num_physpages++;
                totalram_pages++;
@@ -1018,7 +1018,7 @@ void free_initrd_mem(unsigned long start, unsigned long end)
                printk(KERN_INFO "Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
        for (; start < end; start += PAGE_SIZE) {
                ClearPageReserved(virt_to_page(start));
-               set_page_count(virt_to_page(start), 1);
+               init_page_count(virt_to_page(start));
                free_page(start);
                num_physpages++;
                totalram_pages++;
index b51bb28c054bbb5e14007af0d9efee7be0806a3a..7370f9f33e2943d038025a6d05ba6b4e02755beb 100644 (file)
@@ -133,21 +133,6 @@ pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
        return __pte(old);
 }
 
-/*
- * This function checks for proper alignment of input addr and len parameters.
- */
-int is_aligned_hugepage_range(unsigned long addr, unsigned long len)
-{
-       if (len & ~HPAGE_MASK)
-               return -EINVAL;
-       if (addr & ~HPAGE_MASK)
-               return -EINVAL;
-       if (! (within_hugepage_low_range(addr, len)
-              || within_hugepage_high_range(addr, len)) )
-               return -EINVAL;
-       return 0;
-}
-
 struct slb_flush_info {
        struct mm_struct *mm;
        u16 newareas;
index 7d0d75c11848ec7ca0e1c8b0468e7958e47a1331..b57fb3a2b7bb25767d10596f978a5ed4df985c47 100644 (file)
@@ -216,7 +216,7 @@ static void free_sec(unsigned long start, unsigned long end, const char *name)
 
        while (start < end) {
                ClearPageReserved(virt_to_page(start));
-               set_page_count(virt_to_page(start), 1);
+               init_page_count(virt_to_page(start));
                free_page(start);
                cnt++;
                start += PAGE_SIZE;
@@ -248,7 +248,7 @@ void free_initrd_mem(unsigned long start, unsigned long end)
                printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
        for (; start < end; start += PAGE_SIZE) {
                ClearPageReserved(virt_to_page(start));
-               set_page_count(virt_to_page(start), 1);
+               init_page_count(virt_to_page(start));
                free_page(start);
                totalram_pages++;
        }
index 81cfb0c2ec58bf5bd1d056b48206b551b1aad935..bacb71c89811b27c48f8e5f05b8dbf3dbe27fd3f 100644 (file)
@@ -140,7 +140,7 @@ void free_initmem(void)
        for (; addr < (unsigned long)__init_end; addr += PAGE_SIZE) {
                memset((void *)addr, 0xcc, PAGE_SIZE);
                ClearPageReserved(virt_to_page(addr));
-               set_page_count(virt_to_page(addr), 1);
+               init_page_count(virt_to_page(addr));
                free_page(addr);
                totalram_pages++;
        }
@@ -155,7 +155,7 @@ void free_initrd_mem(unsigned long start, unsigned long end)
                printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
        for (; start < end; start += PAGE_SIZE) {
                ClearPageReserved(virt_to_page(start));
-               set_page_count(virt_to_page(start), 1);
+               init_page_count(virt_to_page(start));
                free_page(start);
                totalram_pages++;
        }
index 550517c2dd42babc88c7064763556b5851467dd4..454cac01d8cc0667dfee9314372153d32adeefbf 100644 (file)
@@ -108,8 +108,8 @@ EXPORT_SYMBOL(phys_mem_access_prot);
 void online_page(struct page *page)
 {
        ClearPageReserved(page);
-       set_page_count(page, 0);
-       free_cold_page(page);
+       init_page_count(page);
+       __free_page(page);
        totalram_pages++;
        num_physpages++;
 }
@@ -376,7 +376,7 @@ void __init mem_init(void)
                        struct page *page = pfn_to_page(pfn);
 
                        ClearPageReserved(page);
-                       set_page_count(page, 1);
+                       init_page_count(page);
                        __free_page(page);
                        totalhigh_pages++;
                }
index b33a4443f5a9368344f6ac3f3507ac6593a86e77..fec8e65b36ea421a7f5f879acf2efe3ce00c5d0c 100644 (file)
@@ -115,7 +115,7 @@ static void __init cell_spuprop_present(struct device_node *spe,
                for (pfn = start_pfn; pfn < end_pfn; pfn++) {
                        struct page *page = pfn_to_page(pfn);
                        set_page_links(page, ZONE_DMA, node_id, pfn);
-                       set_page_count(page, 1);
+                       init_page_count(page);
                        reset_page_mapcount(page);
                        SetPageReserved(page);
                        INIT_LIST_HEAD(&page->lru);
index 685fd0defe23484772bf89e99b772bd9cbd65486..61465ec88bc7268b0325001bac308c28d1db8588 100644 (file)
@@ -223,6 +223,8 @@ __dma_alloc_coherent(size_t size, dma_addr_t *handle, gfp_t gfp)
                pte_t *pte = consistent_pte + CONSISTENT_OFFSET(vaddr);
                struct page *end = page + (1 << order);
 
+               split_page(page, order);
+
                /*
                 * Set the "dma handle"
                 */
@@ -231,7 +233,6 @@ __dma_alloc_coherent(size_t size, dma_addr_t *handle, gfp_t gfp)
                do {
                        BUG_ON(!pte_none(*pte));
 
-                       set_page_count(page, 1);
                        SetPageReserved(page);
                        set_pte_at(&init_mm, vaddr,
                                   pte, mk_pte(page, pgprot_noncached(PAGE_KERNEL)));
@@ -244,7 +245,6 @@ __dma_alloc_coherent(size_t size, dma_addr_t *handle, gfp_t gfp)
                 * Free the otherwise unused pages.
                 */
                while (page < end) {
-                       set_page_count(page, 1);
                        __free_page(page);
                        page++;
                }
index 134db5c0420319bbe31888b6b06cb3844849e214..cb1c294fb932678a9d32429b5022582de7518f8b 100644 (file)
@@ -140,7 +140,7 @@ static void free_sec(unsigned long start, unsigned long end, const char *name)
 
        while (start < end) {
                ClearPageReserved(virt_to_page(start));
-               set_page_count(virt_to_page(start), 1);
+               init_page_count(virt_to_page(start));
                free_page(start);
                cnt++;
                start += PAGE_SIZE;
@@ -172,7 +172,7 @@ void free_initrd_mem(unsigned long start, unsigned long end)
 
        for (; start < end; start += PAGE_SIZE) {
                ClearPageReserved(virt_to_page(start));
-               set_page_count(virt_to_page(start), 1);
+               init_page_count(virt_to_page(start));
                free_page(start);
                totalram_pages++;
        }
@@ -441,7 +441,7 @@ void __init mem_init(void)
                        struct page *page = mem_map + pfn;
 
                        ClearPageReserved(page);
-                       set_page_count(page, 1);
+                       init_page_count(page);
                        __free_page(page);
                        totalhigh_pages++;
                }
index df953383724d9d0686997e7e931f3c98ad40becb..a055894f3bd89a59f4e843c1c113ef5ce80547aa 100644 (file)
@@ -292,7 +292,7 @@ void free_initmem(void)
         addr = (unsigned long)(&__init_begin);
         for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
                ClearPageReserved(virt_to_page(addr));
-               set_page_count(virt_to_page(addr), 1);
+               init_page_count(virt_to_page(addr));
                free_page(addr);
                totalram_pages++;
         }
@@ -307,7 +307,7 @@ void free_initrd_mem(unsigned long start, unsigned long end)
                 printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
         for (; start < end; start += PAGE_SIZE) {
                 ClearPageReserved(virt_to_page(start));
-                set_page_count(virt_to_page(start), 1);
+                init_page_count(virt_to_page(start));
                 free_page(start);
                 totalram_pages++;
         }
index df3a9e452cc55321c238143b05190557401bb867..ee73e30263af947b683e2833bb88e52806151f21 100644 (file)
@@ -23,6 +23,7 @@ void *consistent_alloc(gfp_t gfp, size_t size, dma_addr_t *handle)
        page = alloc_pages(gfp, order);
        if (!page)
                return NULL;
+       split_page(page, order);
 
        ret = page_address(page);
        *handle = virt_to_phys(ret);
@@ -37,8 +38,6 @@ void *consistent_alloc(gfp_t gfp, size_t size, dma_addr_t *handle)
        end  = page + (1 << order);
 
        while (++page < end) {
-               set_page_count(page, 1);
-
                /* Free any unused pages */
                if (page >= free) {
                        __free_page(page);
index 6b7a7688c98e87178d4915a1f17e8118213a5e63..a3568fd51508e4435dfb217f4c6d42089dc7ea0c 100644 (file)
@@ -84,18 +84,6 @@ pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
        return entry;
 }
 
-/*
- * This function checks for proper alignment of input addr and len parameters.
- */
-int is_aligned_hugepage_range(unsigned long addr, unsigned long len)
-{
-       if (len & ~HPAGE_MASK)
-               return -EINVAL;
-       if (addr & ~HPAGE_MASK)
-               return -EINVAL;
-       return 0;
-}
-
 struct page *follow_huge_addr(struct mm_struct *mm,
                              unsigned long address, int write)
 {
index e342565f75fbc464684faf8e54f28e05134475ea..77b4a838fe10f494e9c0896c06479f9abb699721 100644 (file)
@@ -273,7 +273,7 @@ void free_initmem(void)
        addr = (unsigned long)(&__init_begin);
        for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
                ClearPageReserved(virt_to_page(addr));
-               set_page_count(virt_to_page(addr), 1);
+               init_page_count(virt_to_page(addr));
                free_page(addr);
                totalram_pages++;
        }
@@ -286,7 +286,7 @@ void free_initrd_mem(unsigned long start, unsigned long end)
        unsigned long p;
        for (p = start; p < end; p += PAGE_SIZE) {
                ClearPageReserved(virt_to_page(p));
-               set_page_count(virt_to_page(p), 1);
+               init_page_count(virt_to_page(p));
                free_page(p);
                totalram_pages++;
        }
index ed6a505b3ee2b9e7194268449067c8e8746ae681..3d89f2a6c785cf70582cac9d231fb4e729e8eb01 100644 (file)
@@ -84,18 +84,6 @@ pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
        return entry;
 }
 
-/*
- * This function checks for proper alignment of input addr and len parameters.
- */
-int is_aligned_hugepage_range(unsigned long addr, unsigned long len)
-{
-       if (len & ~HPAGE_MASK)
-               return -EINVAL;
-       if (addr & ~HPAGE_MASK)
-               return -EINVAL;
-       return 0;
-}
-
 struct page *follow_huge_addr(struct mm_struct *mm,
                              unsigned long address, int write)
 {
index a65e8bb2c3cc5e8cbf644799d4f3ffdda0d4fdaa..1169757fb38b1cfe05ab454a77ca01cc06c00c51 100644 (file)
@@ -173,7 +173,7 @@ void free_initmem(void)
        addr = (unsigned long)(&__init_begin);
        for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
                ClearPageReserved(virt_to_page(addr));
-               set_page_count(virt_to_page(addr), 1);
+               init_page_count(virt_to_page(addr));
                free_page(addr);
                totalram_pages++;
        }
@@ -186,7 +186,7 @@ void free_initrd_mem(unsigned long start, unsigned long end)
        unsigned long p;
        for (p = start; p < end; p += PAGE_SIZE) {
                ClearPageReserved(virt_to_page(p));
-               set_page_count(virt_to_page(p), 1);
+               init_page_count(virt_to_page(p));
                free_page(p);
                totalram_pages++;
        }
index 40d426cce8244f16969e3a12f876855f0893bd0f..4219dd2ce3a2332094340c731d4142f4b569c461 100644 (file)
@@ -266,19 +266,19 @@ void __init smp4d_boot_cpus(void)
 
        /* Free unneeded trap tables */
        ClearPageReserved(virt_to_page(trapbase_cpu1));
-       set_page_count(virt_to_page(trapbase_cpu1), 1);
+       init_page_count(virt_to_page(trapbase_cpu1));
        free_page((unsigned long)trapbase_cpu1);
        totalram_pages++;
        num_physpages++;
 
        ClearPageReserved(virt_to_page(trapbase_cpu2));
-       set_page_count(virt_to_page(trapbase_cpu2), 1);
+       init_page_count(virt_to_page(trapbase_cpu2));
        free_page((unsigned long)trapbase_cpu2);
        totalram_pages++;
        num_physpages++;
 
        ClearPageReserved(virt_to_page(trapbase_cpu3));
-       set_page_count(virt_to_page(trapbase_cpu3), 1);
+       init_page_count(virt_to_page(trapbase_cpu3));
        free_page((unsigned long)trapbase_cpu3);
        totalram_pages++;
        num_physpages++;
index a21f27d10e55737881f81522262b4e07751476e9..fbbd8a474c4c62bfbc47ac5949f835c3dcad2a1f 100644 (file)
@@ -233,21 +233,21 @@ void __init smp4m_boot_cpus(void)
        /* Free unneeded trap tables */
        if (!cpu_isset(i, cpu_present_map)) {
                ClearPageReserved(virt_to_page(trapbase_cpu1));
-               set_page_count(virt_to_page(trapbase_cpu1), 1);
+               init_page_count(virt_to_page(trapbase_cpu1));
                free_page((unsigned long)trapbase_cpu1);
                totalram_pages++;
                num_physpages++;
        }
        if (!cpu_isset(2, cpu_present_map)) {
                ClearPageReserved(virt_to_page(trapbase_cpu2));
-               set_page_count(virt_to_page(trapbase_cpu2), 1);
+               init_page_count(virt_to_page(trapbase_cpu2));
                free_page((unsigned long)trapbase_cpu2);
                totalram_pages++;
                num_physpages++;
        }
        if (!cpu_isset(3, cpu_present_map)) {
                ClearPageReserved(virt_to_page(trapbase_cpu3));
-               set_page_count(virt_to_page(trapbase_cpu3), 1);
+               init_page_count(virt_to_page(trapbase_cpu3));
                free_page((unsigned long)trapbase_cpu3);
                totalram_pages++;
                num_physpages++;
index 2cb0728cee052012c7856b017f7499fa5638ce82..1ef7fa03fefe74f7c98daa9bf71cbdcc5bdb3747 100644 (file)
@@ -76,7 +76,6 @@ int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
        vma->vm_pgoff = (offset >> PAGE_SHIFT) |
                ((unsigned long)space << 28UL);
 
-       prot = __pgprot(pg_iobits);
        offset -= from;
        dir = pgd_offset(mm, from);
        flush_cache_range(vma, beg, end);
index c03babaa0498b95787eac1bd3ec2244364208339..898669732466a2a51994efb09557ff75a546918d 100644 (file)
@@ -383,7 +383,7 @@ void map_high_region(unsigned long start_pfn, unsigned long end_pfn)
                struct page *page = pfn_to_page(tmp);
 
                ClearPageReserved(page);
-               set_page_count(page, 1);
+               init_page_count(page);
                __free_page(page);
                totalhigh_pages++;
        }
@@ -480,7 +480,7 @@ void free_initmem (void)
                p = virt_to_page(addr);
 
                ClearPageReserved(p);
-               set_page_count(p, 1);
+               init_page_count(p);
                __free_page(p);
                totalram_pages++;
                num_physpages++;
@@ -497,7 +497,7 @@ void free_initrd_mem(unsigned long start, unsigned long end)
                struct page *p = virt_to_page(start);
 
                ClearPageReserved(p);
-               set_page_count(p, 1);
+               init_page_count(p);
                __free_page(p);
                num_physpages++;
        }
index e9f9571601baac35ac103b2321c0e9459c3ef88b..36b4d24988f8f64c75cbfdca09b7b9ca499cd730 100644 (file)
@@ -22,8 +22,6 @@ struct ctx_list *ctx_list_pool;
 struct ctx_list ctx_free;
 struct ctx_list ctx_used;
 
-unsigned int pg_iobits;
-
 extern void ld_mmu_sun4c(void);
 extern void ld_mmu_srmmu(void);
 
index c664b962987cdde1ad1a5bd17d288dbd2e907c75..27b0e0ba8581ec2214b2197531432455e46e12b1 100644 (file)
@@ -2130,6 +2130,13 @@ static unsigned long srmmu_pte_to_pgoff(pte_t pte)
        return pte_val(pte) >> SRMMU_PTE_FILE_SHIFT;
 }
 
+static pgprot_t srmmu_pgprot_noncached(pgprot_t prot)
+{
+       prot &= ~__pgprot(SRMMU_CACHE);
+
+       return prot;
+}
+
 /* Load up routines and constants for sun4m and sun4d mmu */
 void __init ld_mmu_srmmu(void)
 {
@@ -2150,9 +2157,9 @@ void __init ld_mmu_srmmu(void)
        BTFIXUPSET_INT(page_readonly, pgprot_val(SRMMU_PAGE_RDONLY));
        BTFIXUPSET_INT(page_kernel, pgprot_val(SRMMU_PAGE_KERNEL));
        page_kernel = pgprot_val(SRMMU_PAGE_KERNEL);
-       pg_iobits = SRMMU_VALID | SRMMU_WRITE | SRMMU_REF;
 
        /* Functions */
+       BTFIXUPSET_CALL(pgprot_noncached, srmmu_pgprot_noncached, BTFIXUPCALL_NORM);
 #ifndef CONFIG_SMP     
        BTFIXUPSET_CALL(___xchg32, ___xchg32_sun4md, BTFIXUPCALL_SWAPG1G2);
 #endif
index 731f19603cad719951c7a180fd3c9ca136b55fd6..49f28c1bdc6d52318d7c4fc0c77c5aa450907907 100644 (file)
@@ -1589,7 +1589,10 @@ static void sun4c_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
 
 static inline void sun4c_mapioaddr(unsigned long physaddr, unsigned long virt_addr)
 {
-       unsigned long page_entry;
+       unsigned long page_entry, pg_iobits;
+
+       pg_iobits = _SUN4C_PAGE_PRESENT | _SUN4C_READABLE | _SUN4C_WRITEABLE |
+                   _SUN4C_PAGE_IO | _SUN4C_PAGE_NOCACHE;
 
        page_entry = ((physaddr >> PAGE_SHIFT) & SUN4C_PFN_MASK);
        page_entry |= ((pg_iobits | _SUN4C_PAGE_PRIV) & ~(_SUN4C_PAGE_PRESENT));
@@ -2134,6 +2137,13 @@ void __init sun4c_paging_init(void)
        printk("SUN4C: %d mmu entries for the kernel\n", cnt);
 }
 
+static pgprot_t sun4c_pgprot_noncached(pgprot_t prot)
+{
+       prot |= __pgprot(_SUN4C_PAGE_IO | _SUN4C_PAGE_NOCACHE);
+
+       return prot;
+}
+
 /* Load up routines and constants for sun4c mmu */
 void __init ld_mmu_sun4c(void)
 {
@@ -2156,10 +2166,9 @@ void __init ld_mmu_sun4c(void)
        BTFIXUPSET_INT(page_readonly, pgprot_val(SUN4C_PAGE_READONLY));
        BTFIXUPSET_INT(page_kernel, pgprot_val(SUN4C_PAGE_KERNEL));
        page_kernel = pgprot_val(SUN4C_PAGE_KERNEL);
-       pg_iobits = _SUN4C_PAGE_PRESENT | _SUN4C_READABLE | _SUN4C_WRITEABLE |
-                   _SUN4C_PAGE_IO | _SUN4C_PAGE_NOCACHE;
 
        /* Functions */
+       BTFIXUPSET_CALL(pgprot_noncached, sun4c_pgprot_noncached, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(___xchg32, ___xchg32_sun4c, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(do_check_pgt_cache, sun4c_check_pgt_cache, BTFIXUPCALL_NORM);
        
index c3685b314d71469ad9319736b5ddf247a3e547b9..267afddf63cfaaef0db000a0f0bc5426fa75f6b1 100644 (file)
@@ -175,11 +175,11 @@ config HUGETLB_PAGE_SIZE_4MB
        bool "4MB"
 
 config HUGETLB_PAGE_SIZE_512K
-       depends on !SPARC64_PAGE_SIZE_4MB
+       depends on !SPARC64_PAGE_SIZE_4MB && !SPARC64_PAGE_SIZE_512KB
        bool "512K"
 
 config HUGETLB_PAGE_SIZE_64K
-       depends on !SPARC64_PAGE_SIZE_4MB && !SPARC64_PAGE_SIZE_512KB
+       depends on !SPARC64_PAGE_SIZE_4MB && !SPARC64_PAGE_SIZE_512KB && !SPARC64_PAGE_SIZE_64K
        bool "64K"
 
 endchoice
index 95ffa94186203a477dc7e2d26bae2548914385b4..dfccff29e182c1b2c68876debad304b6bf52ed11 100644 (file)
@@ -656,6 +656,7 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
        __pci_mmap_set_flags(dev, vma, mmap_state);
        __pci_mmap_set_pgprot(dev, vma, mmap_state);
 
+       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
        ret = io_remap_pfn_range(vma, vma->vm_start,
                                 vma->vm_pgoff,
                                 vma->vm_end - vma->vm_start,
@@ -663,7 +664,6 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
        if (ret)
                return ret;
 
-       vma->vm_flags |= VM_IO;
        return 0;
 }
 
index ab23ddb7116e52dda47df59cef5533b32248de3b..b731881224e81fa091ca81447d1b50eddd33ac8c 100644 (file)
         *
         * index_mask = (512 << (tsb_reg & 0x7UL)) - 1UL;
         * tsb_base = tsb_reg & ~0x7UL;
-        * tsb_index = ((vaddr >> PAGE_SHIFT) & tsb_mask);
+        * tsb_index = ((vaddr >> HASH_SHIFT) & tsb_mask);
         * tsb_ptr = tsb_base + (tsb_index * 16);
         */
-#define COMPUTE_TSB_PTR(TSB_PTR, VADDR, TMP1, TMP2)    \
+#define COMPUTE_TSB_PTR(TSB_PTR, VADDR, HASH_SHIFT, TMP1, TMP2) \
        and     TSB_PTR, 0x7, TMP1;                     \
        mov     512, TMP2;                              \
        andn    TSB_PTR, 0x7, TSB_PTR;                  \
        sllx    TMP2, TMP1, TMP2;                       \
-       srlx    VADDR, PAGE_SHIFT, TMP1;                \
+       srlx    VADDR, HASH_SHIFT, TMP1;                \
        sub     TMP2, 1, TMP2;                          \
        and     TMP1, TMP2, TMP1;                       \
        sllx    TMP1, 4, TMP1;                          \
@@ -53,7 +53,7 @@ sun4v_itlb_miss:
 
        LOAD_ITLB_INFO(%g2, %g4, %g5)
        COMPUTE_TAG_TARGET(%g6, %g4, %g5, kvmap_itlb_4v)
-       COMPUTE_TSB_PTR(%g1, %g4, %g3, %g7)
+       COMPUTE_TSB_PTR(%g1, %g4, PAGE_SHIFT, %g3, %g7)
 
        /* Load TSB tag/pte into %g2/%g3 and compare the tag.  */
        ldda    [%g1] ASI_QUAD_LDD_PHYS_4V, %g2
@@ -99,7 +99,7 @@ sun4v_dtlb_miss:
 
        LOAD_DTLB_INFO(%g2, %g4, %g5)
        COMPUTE_TAG_TARGET(%g6, %g4, %g5, kvmap_dtlb_4v)
-       COMPUTE_TSB_PTR(%g1, %g4, %g3, %g7)
+       COMPUTE_TSB_PTR(%g1, %g4, PAGE_SHIFT, %g3, %g7)
 
        /* Load TSB tag/pte into %g2/%g3 and compare the tag.  */
        ldda    [%g1] ASI_QUAD_LDD_PHYS_4V, %g2
@@ -171,21 +171,26 @@ sun4v_dtsb_miss:
 
        /* fallthrough */
 
-       /* Create TSB pointer into %g1.  This is something like:
-        *
-        * index_mask = (512 << (tsb_reg & 0x7UL)) - 1UL;
-        * tsb_base = tsb_reg & ~0x7UL;
-        * tsb_index = ((vaddr >> PAGE_SHIFT) & tsb_mask);
-        * tsb_ptr = tsb_base + (tsb_index * 16);
-        */
 sun4v_tsb_miss_common:
-       COMPUTE_TSB_PTR(%g1, %g4, %g5, %g7)
+       COMPUTE_TSB_PTR(%g1, %g4, PAGE_SHIFT, %g5, %g7)
 
-       /* Branch directly to page table lookup.  We have SCRATCHPAD_MMU_MISS
-        * still in %g2, so it's quite trivial to get at the PGD PHYS value
-        * so we can preload it into %g7.
-        */
        sub     %g2, TRAP_PER_CPU_FAULT_INFO, %g2
+
+#ifdef CONFIG_HUGETLB_PAGE
+       mov     SCRATCHPAD_UTSBREG2, %g5
+       ldxa    [%g5] ASI_SCRATCHPAD, %g5
+       cmp     %g5, -1
+       be,pt   %xcc, 80f
+        nop
+       COMPUTE_TSB_PTR(%g5, %g4, HPAGE_SHIFT, %g2, %g7)
+
+       /* That clobbered %g2, reload it.  */
+       ldxa    [%g0] ASI_SCRATCHPAD, %g2
+       sub     %g2, TRAP_PER_CPU_FAULT_INFO, %g2
+
+80:    stx     %g5, [%g2 + TRAP_PER_CPU_TSB_HUGE_TEMP]
+#endif
+
        ba,pt   %xcc, tsb_miss_page_table_walk_sun4v_fastpath
         ldx    [%g2 + TRAP_PER_CPU_PGD_PADDR], %g7
 
index 7f7dba0ca96a9470231de4c15a1426730a48fb5f..df612e4f75f9d74e0f77910a6bbf0084ebf103de 100644 (file)
@@ -2482,6 +2482,7 @@ void init_cur_cpu_trap(struct thread_info *t)
 
 extern void thread_info_offsets_are_bolixed_dave(void);
 extern void trap_per_cpu_offsets_are_bolixed_dave(void);
+extern void tsb_config_offsets_are_bolixed_dave(void);
 
 /* Only invoked on boot processor. */
 void __init trap_init(void)
@@ -2535,9 +2536,27 @@ void __init trap_init(void)
            (TRAP_PER_CPU_CPU_MONDO_BLOCK_PA !=
             offsetof(struct trap_per_cpu, cpu_mondo_block_pa)) ||
            (TRAP_PER_CPU_CPU_LIST_PA !=
-            offsetof(struct trap_per_cpu, cpu_list_pa)))
+            offsetof(struct trap_per_cpu, cpu_list_pa)) ||
+           (TRAP_PER_CPU_TSB_HUGE !=
+            offsetof(struct trap_per_cpu, tsb_huge)) ||
+           (TRAP_PER_CPU_TSB_HUGE_TEMP !=
+            offsetof(struct trap_per_cpu, tsb_huge_temp)))
                trap_per_cpu_offsets_are_bolixed_dave();
 
+       if ((TSB_CONFIG_TSB !=
+            offsetof(struct tsb_config, tsb)) ||
+           (TSB_CONFIG_RSS_LIMIT !=
+            offsetof(struct tsb_config, tsb_rss_limit)) ||
+           (TSB_CONFIG_NENTRIES !=
+            offsetof(struct tsb_config, tsb_nentries)) ||
+           (TSB_CONFIG_REG_VAL !=
+            offsetof(struct tsb_config, tsb_reg_val)) ||
+           (TSB_CONFIG_MAP_VADDR !=
+            offsetof(struct tsb_config, tsb_map_vaddr)) ||
+           (TSB_CONFIG_MAP_PTE !=
+            offsetof(struct tsb_config, tsb_map_pte)))
+               tsb_config_offsets_are_bolixed_dave();
+
        /* Attach to the address space of init_task.  On SMP we
         * do this in smp.c:smp_callin for other cpus.
         */
index 118baea44f699df722bbcc51903b2e821aea10ac..a0c8ba58920bdcc09ae502848bb515ed691b2191 100644 (file)
@@ -3,8 +3,13 @@
  * Copyright (C) 2006 David S. Miller <davem@davemloft.net>
  */
 
+#include <linux/config.h>
+
 #include <asm/tsb.h>
 #include <asm/hypervisor.h>
+#include <asm/page.h>
+#include <asm/cpudata.h>
+#include <asm/mmu.h>
 
        .text
        .align  32
@@ -34,34 +39,124 @@ tsb_miss_itlb:
         ldxa           [%g4] ASI_IMMU, %g4
 
        /* At this point we have:
-        * %g1 --       TSB entry address
+        * %g1 --       PAGE_SIZE TSB entry address
         * %g3 --       FAULT_CODE_{D,I}TLB
         * %g4 --       missing virtual address
         * %g6 --       TAG TARGET (vaddr >> 22)
         */
 tsb_miss_page_table_walk:
-       TRAP_LOAD_PGD_PHYS(%g7, %g5)
+       TRAP_LOAD_TRAP_BLOCK(%g7, %g5)
 
-       /* And now we have the PGD base physical address in %g7.  */
-tsb_miss_page_table_walk_sun4v_fastpath:
-       USER_PGTABLE_WALK_TL1(%g4, %g7, %g5, %g2, tsb_do_fault)
+       /* Before committing to a full page table walk,
+        * check the huge page TSB.
+        */
+#ifdef CONFIG_HUGETLB_PAGE
+
+661:   ldx             [%g7 + TRAP_PER_CPU_TSB_HUGE], %g5
+       nop
+       .section        .sun4v_2insn_patch, "ax"
+       .word           661b
+       mov             SCRATCHPAD_UTSBREG2, %g5
+       ldxa            [%g5] ASI_SCRATCHPAD, %g5
+       .previous
+
+       cmp             %g5, -1
+       be,pt           %xcc, 80f
+        nop
+
+       /* We need an aligned pair of registers containing 2 values
+        * which can be easily rematerialized.  %g6 and %g7 foot the
+        * bill just nicely.  We'll save %g6 away into %g2 for the
+        * huge page TSB TAG comparison.
+        *
+        * Perform a huge page TSB lookup.
+        */
+       mov             %g6, %g2
+       and             %g5, 0x7, %g6
+       mov             512, %g7
+       andn            %g5, 0x7, %g5
+       sllx            %g7, %g6, %g7
+       srlx            %g4, HPAGE_SHIFT, %g6
+       sub             %g7, 1, %g7
+       and             %g6, %g7, %g6
+       sllx            %g6, 4, %g6
+       add             %g5, %g6, %g5
+
+       TSB_LOAD_QUAD(%g5, %g6)
+       cmp             %g6, %g2
+       be,a,pt         %xcc, tsb_tlb_reload
+        mov            %g7, %g5
+
+       /* No match, remember the huge page TSB entry address,
+        * and restore %g6 and %g7.
+        */
+       TRAP_LOAD_TRAP_BLOCK(%g7, %g6)
+       srlx            %g4, 22, %g6
+80:    stx             %g5, [%g7 + TRAP_PER_CPU_TSB_HUGE_TEMP]
+
+#endif
+
+       ldx             [%g7 + TRAP_PER_CPU_PGD_PADDR], %g7
 
        /* At this point we have:
         * %g1 --       TSB entry address
         * %g3 --       FAULT_CODE_{D,I}TLB
-        * %g5 --       physical address of PTE in Linux page tables
+        * %g4 --       missing virtual address
         * %g6 --       TAG TARGET (vaddr >> 22)
+        * %g7 --       page table physical address
+        *
+        * We know that both the base PAGE_SIZE TSB and the HPAGE_SIZE
+        * TSB both lack a matching entry.
         */
-tsb_reload:
-       TSB_LOCK_TAG(%g1, %g2, %g7)
+tsb_miss_page_table_walk_sun4v_fastpath:
+       USER_PGTABLE_WALK_TL1(%g4, %g7, %g5, %g2, tsb_do_fault)
 
        /* Load and check PTE.  */
        ldxa            [%g5] ASI_PHYS_USE_EC, %g5
-       mov             1, %g7
-       sllx            %g7, TSB_TAG_INVALID_BIT, %g7
-       brgez,a,pn      %g5, tsb_do_fault
-        TSB_STORE(%g1, %g7)
+       brgez,pn        %g5, tsb_do_fault
+        nop
+
+#ifdef CONFIG_HUGETLB_PAGE
+661:   sethi           %uhi(_PAGE_SZALL_4U), %g7
+       sllx            %g7, 32, %g7
+       .section        .sun4v_2insn_patch, "ax"
+       .word           661b
+       mov             _PAGE_SZALL_4V, %g7
+       nop
+       .previous
+
+       and             %g5, %g7, %g2
+
+661:   sethi           %uhi(_PAGE_SZHUGE_4U), %g7
+       sllx            %g7, 32, %g7
+       .section        .sun4v_2insn_patch, "ax"
+       .word           661b
+       mov             _PAGE_SZHUGE_4V, %g7
+       nop
+       .previous
+
+       cmp             %g2, %g7
+       bne,pt          %xcc, 60f
+        nop
+
+       /* It is a huge page, use huge page TSB entry address we
+        * calculated above.
+        */
+       TRAP_LOAD_TRAP_BLOCK(%g7, %g2)
+       ldx             [%g7 + TRAP_PER_CPU_TSB_HUGE_TEMP], %g2
+       cmp             %g2, -1
+       movne           %xcc, %g2, %g1
+60:
+#endif
 
+       /* At this point we have:
+        * %g1 --       TSB entry address
+        * %g3 --       FAULT_CODE_{D,I}TLB
+        * %g5 --       valid PTE
+        * %g6 --       TAG TARGET (vaddr >> 22)
+        */
+tsb_reload:
+       TSB_LOCK_TAG(%g1, %g2, %g7)
        TSB_WRITE(%g1, %g5, %g6)
 
        /* Finally, load TLB and return from trap.  */
@@ -240,10 +335,9 @@ tsb_flush:
         * schedule() time.
         *
         * %o0: page table physical address
-        * %o1: TSB register value
-        * %o2: TSB virtual address
-        * %o3: TSB mapping locked PTE
-        * %o4: Hypervisor TSB descriptor physical address
+        * %o1: TSB base config pointer
+        * %o2: TSB huge config pointer, or NULL if none
+        * %o3: Hypervisor TSB descriptor physical address
         *
         * We have to run this whole thing with interrupts
         * disabled so that the current cpu doesn't change
@@ -253,63 +347,79 @@ tsb_flush:
        .globl  __tsb_context_switch
        .type   __tsb_context_switch,#function
 __tsb_context_switch:
-       rdpr    %pstate, %o5
-       wrpr    %o5, PSTATE_IE, %pstate
+       rdpr    %pstate, %g1
+       wrpr    %g1, PSTATE_IE, %pstate
+
+       TRAP_LOAD_TRAP_BLOCK(%g2, %g3)
 
-       ldub    [%g6 + TI_CPU], %g1
-       sethi   %hi(trap_block), %g2
-       sllx    %g1, TRAP_BLOCK_SZ_SHIFT, %g1
-       or      %g2, %lo(trap_block), %g2
-       add     %g2, %g1, %g2
        stx     %o0, [%g2 + TRAP_PER_CPU_PGD_PADDR]
 
-       sethi   %hi(tlb_type), %g1
-       lduw    [%g1 + %lo(tlb_type)], %g1
-       cmp     %g1, 3
-       bne,pt  %icc, 1f
+       ldx     [%o1 + TSB_CONFIG_REG_VAL], %o0
+       brz,pt  %o2, 1f
+        mov    -1, %g3
+
+       ldx     [%o2 + TSB_CONFIG_REG_VAL], %g3
+
+1:     stx     %g3, [%g2 + TRAP_PER_CPU_TSB_HUGE]
+
+       sethi   %hi(tlb_type), %g2
+       lduw    [%g2 + %lo(tlb_type)], %g2
+       cmp     %g2, 3
+       bne,pt  %icc, 50f
         nop
 
        /* Hypervisor TSB switch. */
-       mov     SCRATCHPAD_UTSBREG1, %g1
-       stxa    %o1, [%g1] ASI_SCRATCHPAD
-       mov     -1, %g2
-       mov     SCRATCHPAD_UTSBREG2, %g1
-       stxa    %g2, [%g1] ASI_SCRATCHPAD
-
-       /* Save away %o5's %pstate, we have to use %o5 for
-        * the hypervisor call.
-        */
-       mov     %o5, %g1
+       mov     SCRATCHPAD_UTSBREG1, %o5
+       stxa    %o0, [%o5] ASI_SCRATCHPAD
+       mov     SCRATCHPAD_UTSBREG2, %o5
+       stxa    %g3, [%o5] ASI_SCRATCHPAD
+
+       mov     2, %o0
+       cmp     %g3, -1
+       move    %xcc, 1, %o0
 
        mov     HV_FAST_MMU_TSB_CTXNON0, %o5
-       mov     1, %o0
-       mov     %o4, %o1
+       mov     %o3, %o1
        ta      HV_FAST_TRAP
 
-       /* Finish up and restore %o5.  */
+       /* Finish up.  */
        ba,pt   %xcc, 9f
-        mov    %g1, %o5
+        nop
 
        /* SUN4U TSB switch.  */
-1:     mov     TSB_REG, %g1
-       stxa    %o1, [%g1] ASI_DMMU
+50:    mov     TSB_REG, %o5
+       stxa    %o0, [%o5] ASI_DMMU
        membar  #Sync
-       stxa    %o1, [%g1] ASI_IMMU
+       stxa    %o0, [%o5] ASI_IMMU
        membar  #Sync
 
-2:     brz     %o2, 9f
-        nop
+2:     ldx     [%o1 + TSB_CONFIG_MAP_VADDR], %o4
+       brz     %o4, 9f
+        ldx    [%o1 + TSB_CONFIG_MAP_PTE], %o5
 
        sethi   %hi(sparc64_highest_unlocked_tlb_ent), %g2
-       mov     TLB_TAG_ACCESS, %g1
+       mov     TLB_TAG_ACCESS, %g3
        lduw    [%g2 + %lo(sparc64_highest_unlocked_tlb_ent)], %g2
-       stxa    %o2, [%g1] ASI_DMMU
+       stxa    %o4, [%g3] ASI_DMMU
        membar  #Sync
        sllx    %g2, 3, %g2
-       stxa    %o3, [%g2] ASI_DTLB_DATA_ACCESS
+       stxa    %o5, [%g2] ASI_DTLB_DATA_ACCESS
+       membar  #Sync
+
+       brz,pt  %o2, 9f
+        nop
+
+       ldx     [%o2 + TSB_CONFIG_MAP_VADDR], %o4
+       ldx     [%o2 + TSB_CONFIG_MAP_PTE], %o5
+       mov     TLB_TAG_ACCESS, %g3
+       stxa    %o4, [%g3] ASI_DMMU
+       membar  #Sync
+       sub     %g2, (1 << 3), %g2
+       stxa    %o5, [%g2] ASI_DTLB_DATA_ACCESS
        membar  #Sync
+
 9:
-       wrpr    %o5, %pstate
+       wrpr    %g1, %pstate
 
        retl
         nop
index 63b6cc0cd5d58688926ab307f94a9809adb89329..d21ff3230c0227be384b83503e85f530a9b5fd22 100644 (file)
@@ -410,9 +410,18 @@ good_area:
        up_read(&mm->mmap_sem);
 
        mm_rss = get_mm_rss(mm);
-       if (unlikely(mm_rss >= mm->context.tsb_rss_limit))
-               tsb_grow(mm, mm_rss);
-
+#ifdef CONFIG_HUGETLB_PAGE
+       mm_rss -= (mm->context.huge_pte_count * (HPAGE_SIZE / PAGE_SIZE));
+#endif
+       if (unlikely(mm_rss >=
+                    mm->context.tsb_block[MM_TSB_BASE].tsb_rss_limit))
+               tsb_grow(mm, MM_TSB_BASE, mm_rss);
+#ifdef CONFIG_HUGETLB_PAGE
+       mm_rss = mm->context.huge_pte_count;
+       if (unlikely(mm_rss >=
+                    mm->context.tsb_block[MM_TSB_HUGE].tsb_rss_limit))
+               tsb_grow(mm, MM_TSB_HUGE, mm_rss);
+#endif
        return;
 
        /*
index 5fc5c579e35effc7532981871dfefeec1cfed907..8cb06205d265347e62f3517795cda2173d45632e 100644 (file)
@@ -140,7 +140,6 @@ int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
        vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP;
        vma->vm_pgoff = phys_base >> PAGE_SHIFT;
 
-       prot = __pgprot(pg_iobits);
        offset -= from;
        dir = pgd_offset(mm, from);
        flush_cache_range(vma, beg, end);
index a7a24869d04576b67ec56216e474fef4ff3632a8..074620d413d4733db87aca5f0ce6f09be09a080e 100644 (file)
@@ -199,13 +199,11 @@ pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr)
        pte_t *pte = NULL;
 
        pgd = pgd_offset(mm, addr);
-       if (pgd) {
-               pud = pud_offset(pgd, addr);
-               if (pud) {
-                       pmd = pmd_alloc(mm, pud, addr);
-                       if (pmd)
-                               pte = pte_alloc_map(mm, pmd, addr);
-               }
+       pud = pud_alloc(mm, pgd, addr);
+       if (pud) {
+               pmd = pmd_alloc(mm, pud, addr);
+               if (pmd)
+                       pte = pte_alloc_map(mm, pmd, addr);
        }
        return pte;
 }
@@ -231,13 +229,14 @@ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
        return pte;
 }
 
-#define mk_pte_huge(entry) do { pte_val(entry) |= _PAGE_SZHUGE; } while (0)
-
 void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
                     pte_t *ptep, pte_t entry)
 {
        int i;
 
+       if (!pte_present(*ptep) && pte_present(entry))
+               mm->context.huge_pte_count++;
+
        for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
                set_pte_at(mm, addr, ptep, entry);
                ptep++;
@@ -253,6 +252,8 @@ pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
        int i;
 
        entry = *ptep;
+       if (pte_present(entry))
+               mm->context.huge_pte_count--;
 
        for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
                pte_clear(mm, addr, ptep);
@@ -263,18 +264,6 @@ pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
        return entry;
 }
 
-/*
- * This function checks for proper alignment of input addr and len parameters.
- */
-int is_aligned_hugepage_range(unsigned long addr, unsigned long len)
-{
-       if (len & ~HPAGE_MASK)
-               return -EINVAL;
-       if (addr & ~HPAGE_MASK)
-               return -EINVAL;
-       return 0;
-}
-
 struct page *follow_huge_addr(struct mm_struct *mm,
                              unsigned long address, int write)
 {
@@ -302,6 +291,15 @@ static void context_reload(void *__data)
 
 void hugetlb_prefault_arch_hook(struct mm_struct *mm)
 {
+       struct tsb_config *tp = &mm->context.tsb_block[MM_TSB_HUGE];
+
+       if (likely(tp->tsb != NULL))
+               return;
+
+       tsb_grow(mm, MM_TSB_HUGE, 0);
+       tsb_context_switch(mm);
+       smp_tsb_sync(mm);
+
        /* On UltraSPARC-III+ and later, configure the second half of
         * the Data-TLB for huge pages.
         */
index c2b556106fc175cad9e92cef28eb9f99237392a9..ded63ee9c4fd4376b8c3e81c172ed65b516c7555 100644 (file)
@@ -283,6 +283,7 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t p
        struct mm_struct *mm;
        struct tsb *tsb;
        unsigned long tag, flags;
+       unsigned long tsb_index, tsb_hash_shift;
 
        if (tlb_type != hypervisor) {
                unsigned long pfn = pte_pfn(pte);
@@ -312,10 +313,26 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t p
 
        mm = vma->vm_mm;
 
+       tsb_index = MM_TSB_BASE;
+       tsb_hash_shift = PAGE_SHIFT;
+
        spin_lock_irqsave(&mm->context.lock, flags);
 
-       tsb = &mm->context.tsb[(address >> PAGE_SHIFT) &
-                              (mm->context.tsb_nentries - 1UL)];
+#ifdef CONFIG_HUGETLB_PAGE
+       if (mm->context.tsb_block[MM_TSB_HUGE].tsb != NULL) {
+               if ((tlb_type == hypervisor &&
+                    (pte_val(pte) & _PAGE_SZALL_4V) == _PAGE_SZHUGE_4V) ||
+                   (tlb_type != hypervisor &&
+                    (pte_val(pte) & _PAGE_SZALL_4U) == _PAGE_SZHUGE_4U)) {
+                       tsb_index = MM_TSB_HUGE;
+                       tsb_hash_shift = HPAGE_SHIFT;
+               }
+       }
+#endif
+
+       tsb = mm->context.tsb_block[tsb_index].tsb;
+       tsb += ((address >> tsb_hash_shift) &
+               (mm->context.tsb_block[tsb_index].tsb_nentries - 1UL));
        tag = (address >> 22UL);
        tsb_insert(tsb, tag, pte_val(pte));
 
@@ -1461,7 +1478,7 @@ void free_initmem(void)
                p = virt_to_page(page);
 
                ClearPageReserved(p);
-               set_page_count(p, 1);
+               init_page_count(p);
                __free_page(p);
                num_physpages++;
                totalram_pages++;
@@ -1477,7 +1494,7 @@ void free_initrd_mem(unsigned long start, unsigned long end)
                struct page *p = virt_to_page(start);
 
                ClearPageReserved(p);
-               set_page_count(p, 1);
+               init_page_count(p);
                __free_page(p);
                num_physpages++;
                totalram_pages++;
index b2064e2a44d6fe278826e4391f04203092600a2a..beaa02810f0e9e27ee6b65b8016984610bbdda0a 100644 (file)
@@ -15,9 +15,9 @@
 
 extern struct tsb swapper_tsb[KERNEL_TSB_NENTRIES];
 
-static inline unsigned long tsb_hash(unsigned long vaddr, unsigned long nentries)
+static inline unsigned long tsb_hash(unsigned long vaddr, unsigned long hash_shift, unsigned long nentries)
 {
-       vaddr >>= PAGE_SHIFT;
+       vaddr >>= hash_shift;
        return vaddr & (nentries - 1);
 }
 
@@ -36,7 +36,8 @@ void flush_tsb_kernel_range(unsigned long start, unsigned long end)
        unsigned long v;
 
        for (v = start; v < end; v += PAGE_SIZE) {
-               unsigned long hash = tsb_hash(v, KERNEL_TSB_NENTRIES);
+               unsigned long hash = tsb_hash(v, PAGE_SHIFT,
+                                             KERNEL_TSB_NENTRIES);
                struct tsb *ent = &swapper_tsb[hash];
 
                if (tag_compare(ent->tag, v)) {
@@ -46,49 +47,91 @@ void flush_tsb_kernel_range(unsigned long start, unsigned long end)
        }
 }
 
-void flush_tsb_user(struct mmu_gather *mp)
+static void __flush_tsb_one(struct mmu_gather *mp, unsigned long hash_shift, unsigned long tsb, unsigned long nentries)
 {
-       struct mm_struct *mm = mp->mm;
-       unsigned long nentries, base, flags;
-       struct tsb *tsb;
-       int i;
-
-       spin_lock_irqsave(&mm->context.lock, flags);
-
-       tsb = mm->context.tsb;
-       nentries = mm->context.tsb_nentries;
+       unsigned long i;
 
-       if (tlb_type == cheetah_plus || tlb_type == hypervisor)
-               base = __pa(tsb);
-       else
-               base = (unsigned long) tsb;
-       
        for (i = 0; i < mp->tlb_nr; i++) {
                unsigned long v = mp->vaddrs[i];
                unsigned long tag, ent, hash;
 
                v &= ~0x1UL;
 
-               hash = tsb_hash(v, nentries);
-               ent = base + (hash * sizeof(struct tsb));
+               hash = tsb_hash(v, hash_shift, nentries);
+               ent = tsb + (hash * sizeof(struct tsb));
                tag = (v >> 22UL);
 
                tsb_flush(ent, tag);
        }
+}
+
+void flush_tsb_user(struct mmu_gather *mp)
+{
+       struct mm_struct *mm = mp->mm;
+       unsigned long nentries, base, flags;
+
+       spin_lock_irqsave(&mm->context.lock, flags);
 
+       base = (unsigned long) mm->context.tsb_block[MM_TSB_BASE].tsb;
+       nentries = mm->context.tsb_block[MM_TSB_BASE].tsb_nentries;
+       if (tlb_type == cheetah_plus || tlb_type == hypervisor)
+               base = __pa(base);
+       __flush_tsb_one(mp, PAGE_SHIFT, base, nentries);
+
+#ifdef CONFIG_HUGETLB_PAGE
+       if (mm->context.tsb_block[MM_TSB_HUGE].tsb) {
+               base = (unsigned long) mm->context.tsb_block[MM_TSB_HUGE].tsb;
+               nentries = mm->context.tsb_block[MM_TSB_HUGE].tsb_nentries;
+               if (tlb_type == cheetah_plus || tlb_type == hypervisor)
+                       base = __pa(base);
+               __flush_tsb_one(mp, HPAGE_SHIFT, base, nentries);
+       }
+#endif
        spin_unlock_irqrestore(&mm->context.lock, flags);
 }
 
-static void setup_tsb_params(struct mm_struct *mm, unsigned long tsb_bytes)
+#if defined(CONFIG_SPARC64_PAGE_SIZE_8KB)
+#define HV_PGSZ_IDX_BASE       HV_PGSZ_IDX_8K
+#define HV_PGSZ_MASK_BASE      HV_PGSZ_MASK_8K
+#elif defined(CONFIG_SPARC64_PAGE_SIZE_64KB)
+#define HV_PGSZ_IDX_BASE       HV_PGSZ_IDX_64K
+#define HV_PGSZ_MASK_BASE      HV_PGSZ_MASK_64K
+#elif defined(CONFIG_SPARC64_PAGE_SIZE_512KB)
+#define HV_PGSZ_IDX_BASE       HV_PGSZ_IDX_512K
+#define HV_PGSZ_MASK_BASE      HV_PGSZ_MASK_512K
+#elif defined(CONFIG_SPARC64_PAGE_SIZE_4MB)
+#define HV_PGSZ_IDX_BASE       HV_PGSZ_IDX_4MB
+#define HV_PGSZ_MASK_BASE      HV_PGSZ_MASK_4MB
+#else
+#error Broken base page size setting...
+#endif
+
+#ifdef CONFIG_HUGETLB_PAGE
+#if defined(CONFIG_HUGETLB_PAGE_SIZE_64K)
+#define HV_PGSZ_IDX_HUGE       HV_PGSZ_IDX_64K
+#define HV_PGSZ_MASK_HUGE      HV_PGSZ_MASK_64K
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_512K)
+#define HV_PGSZ_IDX_HUGE       HV_PGSZ_IDX_512K
+#define HV_PGSZ_MASK_HUGE      HV_PGSZ_MASK_512K
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_4MB)
+#define HV_PGSZ_IDX_HUGE       HV_PGSZ_IDX_4MB
+#define HV_PGSZ_MASK_HUGE      HV_PGSZ_MASK_4MB
+#else
+#error Broken huge page size setting...
+#endif
+#endif
+
+static void setup_tsb_params(struct mm_struct *mm, unsigned long tsb_idx, unsigned long tsb_bytes)
 {
        unsigned long tsb_reg, base, tsb_paddr;
        unsigned long page_sz, tte;
 
-       mm->context.tsb_nentries = tsb_bytes / sizeof(struct tsb);
+       mm->context.tsb_block[tsb_idx].tsb_nentries =
+               tsb_bytes / sizeof(struct tsb);
 
        base = TSBMAP_BASE;
        tte = pgprot_val(PAGE_KERNEL_LOCKED);
-       tsb_paddr = __pa(mm->context.tsb);
+       tsb_paddr = __pa(mm->context.tsb_block[tsb_idx].tsb);
        BUG_ON(tsb_paddr & (tsb_bytes - 1UL));
 
        /* Use the smallest page size that can map the whole TSB
@@ -147,61 +190,49 @@ static void setup_tsb_params(struct mm_struct *mm, unsigned long tsb_bytes)
                /* Physical mapping, no locked TLB entry for TSB.  */
                tsb_reg |= tsb_paddr;
 
-               mm->context.tsb_reg_val = tsb_reg;
-               mm->context.tsb_map_vaddr = 0;
-               mm->context.tsb_map_pte = 0;
+               mm->context.tsb_block[tsb_idx].tsb_reg_val = tsb_reg;
+               mm->context.tsb_block[tsb_idx].tsb_map_vaddr = 0;
+               mm->context.tsb_block[tsb_idx].tsb_map_pte = 0;
        } else {
                tsb_reg |= base;
                tsb_reg |= (tsb_paddr & (page_sz - 1UL));
                tte |= (tsb_paddr & ~(page_sz - 1UL));
 
-               mm->context.tsb_reg_val = tsb_reg;
-               mm->context.tsb_map_vaddr = base;
-               mm->context.tsb_map_pte = tte;
+               mm->context.tsb_block[tsb_idx].tsb_reg_val = tsb_reg;
+               mm->context.tsb_block[tsb_idx].tsb_map_vaddr = base;
+               mm->context.tsb_block[tsb_idx].tsb_map_pte = tte;
        }
 
        /* Setup the Hypervisor TSB descriptor.  */
        if (tlb_type == hypervisor) {
-               struct hv_tsb_descr *hp = &mm->context.tsb_descr;
+               struct hv_tsb_descr *hp = &mm->context.tsb_descr[tsb_idx];
 
-               switch (PAGE_SIZE) {
-               case 8192:
-               default:
-                       hp->pgsz_idx = HV_PGSZ_IDX_8K;
+               switch (tsb_idx) {
+               case MM_TSB_BASE:
+                       hp->pgsz_idx = HV_PGSZ_IDX_BASE;
                        break;
-
-               case 64 * 1024:
-                       hp->pgsz_idx = HV_PGSZ_IDX_64K;
-                       break;
-
-               case 512 * 1024:
-                       hp->pgsz_idx = HV_PGSZ_IDX_512K;
-                       break;
-
-               case 4 * 1024 * 1024:
-                       hp->pgsz_idx = HV_PGSZ_IDX_4MB;
+#ifdef CONFIG_HUGETLB_PAGE
+               case MM_TSB_HUGE:
+                       hp->pgsz_idx = HV_PGSZ_IDX_HUGE;
                        break;
+#endif
+               default:
+                       BUG();
                };
                hp->assoc = 1;
                hp->num_ttes = tsb_bytes / 16;
                hp->ctx_idx = 0;
-               switch (PAGE_SIZE) {
-               case 8192:
-               default:
-                       hp->pgsz_mask = HV_PGSZ_MASK_8K;
-                       break;
-
-               case 64 * 1024:
-                       hp->pgsz_mask = HV_PGSZ_MASK_64K;
-                       break;
-
-               case 512 * 1024:
-                       hp->pgsz_mask = HV_PGSZ_MASK_512K;
+               switch (tsb_idx) {
+               case MM_TSB_BASE:
+                       hp->pgsz_mask = HV_PGSZ_MASK_BASE;
                        break;
-
-               case 4 * 1024 * 1024:
-                       hp->pgsz_mask = HV_PGSZ_MASK_4MB;
+#ifdef CONFIG_HUGETLB_PAGE
+               case MM_TSB_HUGE:
+                       hp->pgsz_mask = HV_PGSZ_MASK_HUGE;
                        break;
+#endif
+               default:
+                       BUG();
                };
                hp->tsb_base = tsb_paddr;
                hp->resv = 0;
@@ -241,11 +272,11 @@ void __init tsb_cache_init(void)
        }
 }
 
-/* When the RSS of an address space exceeds mm->context.tsb_rss_limit,
- * do_sparc64_fault() invokes this routine to try and grow the TSB.
+/* When the RSS of an address space exceeds tsb_rss_limit for a TSB,
+ * do_sparc64_fault() invokes this routine to try and grow it.
  *
  * When we reach the maximum TSB size supported, we stick ~0UL into
- * mm->context.tsb_rss_limit so the grow checks in update_mmu_cache()
+ * tsb_rss_limit for that TSB so the grow checks in do_sparc64_fault()
  * will not trigger any longer.
  *
  * The TSB can be anywhere from 8K to 1MB in size, in increasing powers
@@ -257,7 +288,7 @@ void __init tsb_cache_init(void)
  * the number of entries that the current TSB can hold at once.  Currently,
  * we trigger when the RSS hits 3/4 of the TSB capacity.
  */
-void tsb_grow(struct mm_struct *mm, unsigned long rss)
+void tsb_grow(struct mm_struct *mm, unsigned long tsb_index, unsigned long rss)
 {
        unsigned long max_tsb_size = 1 * 1024 * 1024;
        unsigned long new_size, old_size, flags;
@@ -297,7 +328,8 @@ retry_tsb_alloc:
                 * down to a 0-order allocation and force no TSB
                 * growing for this address space.
                 */
-               if (mm->context.tsb == NULL && new_cache_index > 0) {
+               if (mm->context.tsb_block[tsb_index].tsb == NULL &&
+                   new_cache_index > 0) {
                        new_cache_index = 0;
                        new_size = 8192;
                        new_rss_limit = ~0UL;
@@ -307,8 +339,8 @@ retry_tsb_alloc:
                /* If we failed on a TSB grow, we are under serious
                 * memory pressure so don't try to grow any more.
                 */
-               if (mm->context.tsb != NULL)
-                       mm->context.tsb_rss_limit = ~0UL;
+               if (mm->context.tsb_block[tsb_index].tsb != NULL)
+                       mm->context.tsb_block[tsb_index].tsb_rss_limit = ~0UL;
                return;
        }
 
@@ -339,23 +371,26 @@ retry_tsb_alloc:
         */
        spin_lock_irqsave(&mm->context.lock, flags);
 
-       old_tsb = mm->context.tsb;
-       old_cache_index = (mm->context.tsb_reg_val & 0x7UL);
-       old_size = mm->context.tsb_nentries * sizeof(struct tsb);
+       old_tsb = mm->context.tsb_block[tsb_index].tsb;
+       old_cache_index =
+               (mm->context.tsb_block[tsb_index].tsb_reg_val & 0x7UL);
+       old_size = (mm->context.tsb_block[tsb_index].tsb_nentries *
+                   sizeof(struct tsb));
 
 
        /* Handle multiple threads trying to grow the TSB at the same time.
         * One will get in here first, and bump the size and the RSS limit.
         * The others will get in here next and hit this check.
         */
-       if (unlikely(old_tsb && (rss < mm->context.tsb_rss_limit))) {
+       if (unlikely(old_tsb &&
+                    (rss < mm->context.tsb_block[tsb_index].tsb_rss_limit))) {
                spin_unlock_irqrestore(&mm->context.lock, flags);
 
                kmem_cache_free(tsb_caches[new_cache_index], new_tsb);
                return;
        }
 
-       mm->context.tsb_rss_limit = new_rss_limit;
+       mm->context.tsb_block[tsb_index].tsb_rss_limit = new_rss_limit;
 
        if (old_tsb) {
                extern void copy_tsb(unsigned long old_tsb_base,
@@ -372,8 +407,8 @@ retry_tsb_alloc:
                copy_tsb(old_tsb_base, old_size, new_tsb_base, new_size);
        }
 
-       mm->context.tsb = new_tsb;
-       setup_tsb_params(mm, new_size);
+       mm->context.tsb_block[tsb_index].tsb = new_tsb;
+       setup_tsb_params(mm, tsb_index, new_size);
 
        spin_unlock_irqrestore(&mm->context.lock, flags);
 
@@ -394,40 +429,65 @@ retry_tsb_alloc:
 
 int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
 {
+#ifdef CONFIG_HUGETLB_PAGE
+       unsigned long huge_pte_count;
+#endif
+       unsigned int i;
+
        spin_lock_init(&mm->context.lock);
 
        mm->context.sparc64_ctx_val = 0UL;
 
+#ifdef CONFIG_HUGETLB_PAGE
+       /* We reset it to zero because the fork() page copying
+        * will re-increment the counters as the parent PTEs are
+        * copied into the child address space.
+        */
+       huge_pte_count = mm->context.huge_pte_count;
+       mm->context.huge_pte_count = 0;
+#endif
+
        /* copy_mm() copies over the parent's mm_struct before calling
         * us, so we need to zero out the TSB pointer or else tsb_grow()
         * will be confused and think there is an older TSB to free up.
         */
-       mm->context.tsb = NULL;
+       for (i = 0; i < MM_NUM_TSBS; i++)
+               mm->context.tsb_block[i].tsb = NULL;
 
        /* If this is fork, inherit the parent's TSB size.  We would
         * grow it to that size on the first page fault anyways.
         */
-       tsb_grow(mm, get_mm_rss(mm));
+       tsb_grow(mm, MM_TSB_BASE, get_mm_rss(mm));
 
-       if (unlikely(!mm->context.tsb))
+#ifdef CONFIG_HUGETLB_PAGE
+       if (unlikely(huge_pte_count))
+               tsb_grow(mm, MM_TSB_HUGE, huge_pte_count);
+#endif
+
+       if (unlikely(!mm->context.tsb_block[MM_TSB_BASE].tsb))
                return -ENOMEM;
 
        return 0;
 }
 
-void destroy_context(struct mm_struct *mm)
+static void tsb_destroy_one(struct tsb_config *tp)
 {
-       unsigned long flags, cache_index;
+       unsigned long cache_index;
 
-       cache_index = (mm->context.tsb_reg_val & 0x7UL);
-       kmem_cache_free(tsb_caches[cache_index], mm->context.tsb);
+       if (!tp->tsb)
+               return;
+       cache_index = tp->tsb_reg_val & 0x7UL;
+       kmem_cache_free(tsb_caches[cache_index], tp->tsb);
+       tp->tsb = NULL;
+       tp->tsb_reg_val = 0UL;
+}
 
-       /* We can remove these later, but for now it's useful
-        * to catch any bogus post-destroy_context() references
-        * to the TSB.
-        */
-       mm->context.tsb = NULL;
-       mm->context.tsb_reg_val = 0UL;
+void destroy_context(struct mm_struct *mm)
+{
+       unsigned long flags, i;
+
+       for (i = 0; i < MM_NUM_TSBS; i++)
+               tsb_destroy_one(&mm->context.tsb_block[i]);
 
        spin_lock_irqsave(&ctx_alloc_lock, flags);
 
index fa4f915be5c59e15fb5c393e12f40e0a0f77f24e..92cce96b5e24d01f50d7502ba81f1b64e98a1683 100644 (file)
@@ -57,7 +57,7 @@ static void setup_highmem(unsigned long highmem_start,
        for(i = 0; i < highmem_len >> PAGE_SHIFT; i++){
                page = &mem_map[highmem_pfn + i];
                ClearPageReserved(page);
-               set_page_count(page, 1);
+               init_page_count(page);
                __free_page(page);
        }
 }
@@ -296,7 +296,7 @@ void free_initrd_mem(unsigned long start, unsigned long end)
                        (end - start) >> 10);
        for (; start < end; start += PAGE_SIZE) {
                ClearPageReserved(virt_to_page(start));
-               set_page_count(virt_to_page(start), 1);
+               init_page_count(virt_to_page(start));
                free_page(start);
                totalram_pages++;
        }
index 544665e04513b33b4106ccd564be392e22d09b8f..0e65340eee33704f141621b46cc2641de0e4f949 100644 (file)
@@ -279,7 +279,7 @@ int init_maps(unsigned long physmem, unsigned long iomem, unsigned long highmem)
 
        for(i = 0; i < total_pages; i++){
                p = &map[i];
-               set_page_count(p, 0);
+               memset(p, 0, sizeof(struct page));
                SetPageReserved(p);
                INIT_LIST_HEAD(&p->lru);
        }
index 3080f84bf7b76f8f68274d84c5af15d705afc625..ee5ce3d3cbc3e8c50c2bdbaba99070e3e64d9957 100644 (file)
@@ -477,7 +477,7 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        return IRQ_HANDLED;
 }
 
-static unsigned int cyc2ns_scale;
+static unsigned int cyc2ns_scale __read_mostly;
 #define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */
 
 static inline void set_cyc2ns_scale(unsigned long cpu_khz)
index 3496abc8d372eb1dfe57297d032f670c2d839af9..c9dc7e46731e1cc4878c0cc59fa2fa8695d660a5 100644 (file)
@@ -124,6 +124,7 @@ extern void * __memcpy(void *,const void *,__kernel_size_t);
 
 EXPORT_SYMBOL(memset);
 EXPORT_SYMBOL(strlen);
+EXPORT_SYMBOL(strpbrk);
 EXPORT_SYMBOL(memmove);
 EXPORT_SYMBOL(memcpy);
 EXPORT_SYMBOL(__memcpy);
index 7af1742aa958a8f6247a1e323a9b2c6f45d75bf5..40ed13d263cd5ccccb6a210cee4b0005927822fc 100644 (file)
@@ -486,7 +486,7 @@ void __init clear_kernel_mapping(unsigned long address, unsigned long size)
 void online_page(struct page *page)
 {
        ClearPageReserved(page);
-       set_page_count(page, 1);
+       init_page_count(page);
        __free_page(page);
        totalram_pages++;
        num_physpages++;
@@ -592,7 +592,7 @@ void free_initmem(void)
        addr = (unsigned long)(&__init_begin);
        for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
                ClearPageReserved(virt_to_page(addr));
-               set_page_count(virt_to_page(addr), 1);
+               init_page_count(virt_to_page(addr));
                memset((void *)(addr & ~(PAGE_SIZE-1)), 0xcc, PAGE_SIZE); 
                free_page(addr);
                totalram_pages++;
@@ -632,7 +632,7 @@ void free_initrd_mem(unsigned long start, unsigned long end)
        printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
        for (; start < end; start += PAGE_SIZE) {
                ClearPageReserved(virt_to_page(start));
-               set_page_count(virt_to_page(start), 1);
+               init_page_count(virt_to_page(start));
                free_page(start);
                totalram_pages++;
        }
index 35f1f1aab0638ac41699ec718980c26fd40b383d..531ad21447b1c95e4e5a9d9bc020f13784b01d7f 100644 (file)
@@ -45,6 +45,13 @@ static struct page *split_large_page(unsigned long address, pgprot_t prot,
        pte_t *pbase;
        if (!base) 
                return NULL;
+       /*
+        * page_private is used to track the number of entries in
+        * the page table page have non standard attributes.
+        */
+       SetPagePrivate(base);
+       page_private(base) = 0;
+
        address = __pa(address);
        addr = address & LARGE_PAGE_MASK; 
        pbase = (pte_t *)page_address(base);
@@ -77,26 +84,12 @@ static inline void flush_map(unsigned long address)
        on_each_cpu(flush_kernel_map, (void *)address, 1, 1);
 }
 
-struct deferred_page { 
-       struct deferred_page *next; 
-       struct page *fpage;
-       unsigned long address;
-}; 
-static struct deferred_page *df_list; /* protected by init_mm.mmap_sem */
+static struct page *deferred_pages; /* protected by init_mm.mmap_sem */
 
-static inline void save_page(unsigned long address, struct page *fpage)
+static inline void save_page(struct page *fpage)
 {
-       struct deferred_page *df;
-       df = kmalloc(sizeof(struct deferred_page), GFP_KERNEL); 
-       if (!df) {
-               flush_map(address);
-               __free_page(fpage);
-       } else { 
-               df->next = df_list;
-               df->fpage = fpage;
-               df->address = address;
-               df_list = df;
-       }                       
+       fpage->lru.next = (struct list_head *)deferred_pages;
+       deferred_pages = fpage;
 }
 
 /* 
@@ -138,8 +131,8 @@ __change_page_attr(unsigned long address, unsigned long pfn, pgprot_t prot,
                        set_pte(kpte, pfn_pte(pfn, prot));
                } else {
                        /*
-                        * split_large_page will take the reference for this change_page_attr
-                        * on the split page.
+                        * split_large_page will take the reference for this
+                        * change_page_attr on the split page.
                         */
 
                        struct page *split;
@@ -151,23 +144,20 @@ __change_page_attr(unsigned long address, unsigned long pfn, pgprot_t prot,
                        set_pte(kpte,mk_pte(split, ref_prot2));
                        kpte_page = split;
                }       
-               get_page(kpte_page);
+               page_private(kpte_page)++;
        } else if ((kpte_flags & _PAGE_PSE) == 0) { 
                set_pte(kpte, pfn_pte(pfn, ref_prot));
-               __put_page(kpte_page);
+               BUG_ON(page_private(kpte_page) == 0);
+               page_private(kpte_page)--;
        } else
                BUG();
 
        /* on x86-64 the direct mapping set at boot is not using 4k pages */
        BUG_ON(PageReserved(kpte_page));
 
-       switch (page_count(kpte_page)) {
-       case 1:
-               save_page(address, kpte_page);               
+       if (page_private(kpte_page) == 0) {
+               save_page(kpte_page);
                revert_page(address, ref_prot);
-               break;
-       case 0:
-               BUG(); /* memleak and failed 2M page regeneration */
        }
        return 0;
 } 
@@ -220,17 +210,18 @@ int change_page_attr(struct page *page, int numpages, pgprot_t prot)
 
 void global_flush_tlb(void)
 { 
-       struct deferred_page *df, *next_df;
+       struct page *dpage;
 
        down_read(&init_mm.mmap_sem);
-       df = xchg(&df_list, NULL);
+       dpage = xchg(&deferred_pages, NULL);
        up_read(&init_mm.mmap_sem);
-       flush_map((df && !df->next) ? df->address : 0);
-       for (; df; df = next_df) { 
-               next_df = df->next;
-               if (df->fpage) 
-                       __free_page(df->fpage);
-               kfree(df);
+
+       flush_map((dpage && !dpage->lru.next) ? (unsigned long)page_address(dpage) : 0);
+       while (dpage) {
+               struct page *tmp = dpage;
+               dpage = (struct page *)dpage->lru.next;
+               ClearPagePrivate(tmp);
+               __free_page(tmp);
        } 
 } 
 
index 5a91d6c9e66db45402c50ec487b127fd6901931c..e1be4235f3671a256ba89be01b45c9c4ff8c6a0a 100644 (file)
@@ -272,7 +272,7 @@ free_reserved_mem(void *start, void *end)
 {
        for (; start < end; start += PAGE_SIZE) {
                ClearPageReserved(virt_to_page(start));
-               set_page_count(virt_to_page(start), 1);
+               init_page_count(virt_to_page(start));
                free_page((unsigned long)start);
                totalram_pages++;
        }
index e5e119c820e4713d5badfd650c0a9792aca99e72..7d28914d11cbc63afcf131c7ee030288803441d9 100644 (file)
 
 pte_t* pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
 {
-       pte_t *ptep;
+       pte_t *pte = NULL, *p;
        int color = ADDR_COLOR(address);
        int i;
 
        p = (pte_t*) __get_free_pages(GFP_KERNEL|__GFP_REPEAT, COLOR_ORDER);
 
        if (likely(p)) {
-               struct page *page;
-
-               for (i = 0; i < COLOR_SIZE; i++, p++) {
-                       page = virt_to_page(pte);
-
-                       set_page_count(page, 1);
-                       ClearPageCompound(page);
+               split_page(virt_to_page(p), COLOR_ORDER);
 
+               for (i = 0; i < COLOR_SIZE; i++) {
                        if (ADDR_COLOR(p) == color)
                                pte = p;
                        else
                                free_page(p);
+                       p += PTRS_PER_PTE;
                }
                clear_page(pte);
        }
@@ -49,20 +45,20 @@ int flush;
 
 struct page* pte_alloc_one(struct mm_struct *mm, unsigned long address)
 {
-       struct page *pagep;
+       struct page *page = NULL, *p;
        int color = ADDR_COLOR(address);
 
        p = alloc_pages(GFP_KERNEL | __GFP_REPEAT, PTE_ORDER);
 
        if (likely(p)) {
-               for (i = 0; i < PAGE_ORDER; i++) {
-                       set_page_count(p, 1);
-                       ClearPageCompound(p);
+               split_page(p, COLOR_ORDER);
 
-                       if (PADDR_COLOR(page_address(pg)) == color)
+               for (i = 0; i < PAGE_ORDER; i++) {
+                       if (PADDR_COLOR(page_address(p)) == color)
                                page = p;
                        else
-                               free_page(p);
+                               __free_page(p);
+                       p++;
                }
                clear_highpage(page);
        }
index c3141565d59d503250fce52deddbd4df74ffe9ac..48718b7f4fa01737326174f42a775cdabbcc81a8 100644 (file)
@@ -536,6 +536,28 @@ void bus_rescan_devices(struct bus_type * bus)
        bus_for_each_dev(bus, NULL, NULL, bus_rescan_devices_helper);
 }
 
+/**
+ * device_reprobe - remove driver for a device and probe for a new driver
+ * @dev: the device to reprobe
+ *
+ * This function detaches the attached driver (if any) for the given
+ * device and restarts the driver probing process.  It is intended
+ * to use if probing criteria changed during a devices lifetime and
+ * driver attachment should change accordingly.
+ */
+void device_reprobe(struct device *dev)
+{
+       if (dev->driver) {
+               if (dev->parent)        /* Needed for USB */
+                       down(&dev->parent->sem);
+               device_release_driver(dev);
+               if (dev->parent)
+                       up(&dev->parent->sem);
+       }
+
+       bus_rescan_devices_helper(dev, NULL);
+}
+EXPORT_SYMBOL_GPL(device_reprobe);
 
 struct bus_type * get_bus(struct bus_type * bus)
 {
index 89b268321321bf3e7695e88fe18412f24f87d0bf..83f5c5984d1a96da2aab912b3ab936e11f2854d4 100644 (file)
@@ -326,7 +326,7 @@ EXPORT_SYMBOL_GPL(platform_device_register);
  *     platform_device_unregister - unregister a platform-level device
  *     @pdev:  platform device we're unregistering
  *
- *     Unregistration is done in 2 steps. Fisrt we release all resources
+ *     Unregistration is done in 2 steps. First we release all resources
  *     and remove it from the subsystem, then we drop reference count by
  *     calling platform_device_put().
  */
index 0d65394707dbd5653057cfe1dbca6c94fdd98c47..cf39cf9aac257b44fa98deaf4292a81c81eade6e 100644 (file)
@@ -2137,7 +2137,7 @@ static void start_io( ctlr_info_t *h)
                        break;
                }
 
-               /* Get the frist entry from the Request Q */ 
+               /* Get the first entry from the Request Q */ 
                removeQ(&(h->reqQ), c);
                h->Qdepth--;
        
@@ -3251,8 +3251,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
 
 clean4:
 #ifdef CONFIG_CISS_SCSI_TAPE
-       if(hba[i]->scsi_rejects.complete)
-               kfree(hba[i]->scsi_rejects.complete);
+       kfree(hba[i]->scsi_rejects.complete);
 #endif
        kfree(hba[i]->cmd_pool_bits);
        if(hba[i]->cmd_pool)
index 0291cd62c69f2b955db736952fd45dc69f444a09..ffd0800ed601b286863f5a3a80c2538042340af1 100644 (file)
@@ -619,6 +619,7 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
 #endif
                offset = dev->driver->get_reg_ofs(dev);
 #ifdef __sparc__
+               vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
                if (io_remap_pfn_range(DRM_RPR_ARG(vma) vma->vm_start,
                                       (map->offset + offset) >> PAGE_SHIFT,
                                       vma->vm_end - vma->vm_start,
index ac2a297ce37c5a23354fdeca5ec0d84ffaa18079..a80c83210872b544551573f214e5e9223c3921c6 100644 (file)
@@ -283,7 +283,7 @@ static void tb0219_pci_irq_init(void)
        vr41xx_set_irq_level(TB0219_PCI_SLOT3_PIN, IRQ_LEVEL_LOW);
 }
 
-static int tb0219_probe(struct platform_device *dev)
+static int __devinit tb0219_probe(struct platform_device *dev)
 {
        int retval;
 
@@ -319,7 +319,7 @@ static int tb0219_probe(struct platform_device *dev)
        return 0;
 }
 
-static int tb0219_remove(struct platform_device *dev)
+static int __devexit tb0219_remove(struct platform_device *dev)
 {
        _machine_restart = old_machine_restart;
 
@@ -335,19 +335,26 @@ static struct platform_device *tb0219_platform_device;
 
 static struct platform_driver tb0219_device_driver = {
        .probe          = tb0219_probe,
-       .remove         = tb0219_remove,
+       .remove         = __devexit_p(tb0219_remove),
        .driver         = {
                .name   = "TB0219",
+               .owner  = THIS_MODULE,
        },
 };
 
-static int __devinit tanbac_tb0219_init(void)
+static int __init tanbac_tb0219_init(void)
 {
        int retval;
 
-       tb0219_platform_device = platform_device_register_simple("TB0219", -1, NULL, 0);
-       if (IS_ERR(tb0219_platform_device))
-               return PTR_ERR(tb0219_platform_device);
+       tb0219_platform_device = platform_device_alloc("TB0219", -1);
+       if (!tb0219_platform_device)
+               return -ENOMEM;
+
+       retval = platform_device_add(tb0219_platform_device);
+       if (retval < 0) {
+               platform_device_put(tb0219_platform_device);
+               return retval;
+       }
 
        retval = platform_driver_register(&tb0219_device_driver);
        if (retval < 0)
@@ -356,10 +363,9 @@ static int __devinit tanbac_tb0219_init(void)
        return retval;
 }
 
-static void __devexit tanbac_tb0219_exit(void)
+static void __exit tanbac_tb0219_exit(void)
 {
        platform_driver_unregister(&tb0219_device_driver);
-
        platform_device_unregister(tb0219_platform_device);
 }
 
index 2267c7b81799d5b2cdeb55d8d0cc787fd1bf7821..05e6e814d86fd64d4670dccd38fe8e1eb7132138 100644 (file)
@@ -613,7 +613,7 @@ static struct file_operations gpio_fops = {
        .release        = gpio_release,
 };
 
-static int giu_probe(struct platform_device *dev)
+static int __devinit giu_probe(struct platform_device *dev)
 {
        unsigned long start, size, flags = 0;
        unsigned int nr_pins = 0;
@@ -697,7 +697,7 @@ static int giu_probe(struct platform_device *dev)
        return cascade_irq(GIUINT_IRQ, giu_get_irq);
 }
 
-static int giu_remove(struct platform_device *dev)
+static int __devexit giu_remove(struct platform_device *dev)
 {
        iounmap(giu_base);
 
@@ -712,9 +712,10 @@ static struct platform_device *giu_platform_device;
 
 static struct platform_driver giu_device_driver = {
        .probe          = giu_probe,
-       .remove         = giu_remove,
+       .remove         = __devexit_p(giu_remove),
        .driver         = {
                .name   = "GIU",
+               .owner  = THIS_MODULE,
        },
 };
 
@@ -722,9 +723,15 @@ static int __init vr41xx_giu_init(void)
 {
        int retval;
 
-       giu_platform_device = platform_device_register_simple("GIU", -1, NULL, 0);
-       if (IS_ERR(giu_platform_device))
-               return PTR_ERR(giu_platform_device);
+       giu_platform_device = platform_device_alloc("GIU", -1);
+       if (!giu_platform_device)
+               return -ENOMEM;
+
+       retval = platform_device_add(giu_platform_device);
+       if (retval < 0) {
+               platform_device_put(giu_platform_device);
+               return retval;
+       }
 
        retval = platform_driver_register(&giu_device_driver);
        if (retval < 0)
index bc1b4a15212c2d939e4ed4508dcf5c70eacfe405..b109d9a502d63dfde26ba6c04a2083ed2bdd4b3d 100644 (file)
@@ -558,7 +558,7 @@ static struct miscdevice rtc_miscdevice = {
        .fops   = &rtc_fops,
 };
 
-static int rtc_probe(struct platform_device *pdev)
+static int __devinit rtc_probe(struct platform_device *pdev)
 {
        unsigned int irq;
        int retval;
@@ -631,7 +631,7 @@ static int rtc_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int rtc_remove(struct platform_device *dev)
+static int __devexit rtc_remove(struct platform_device *dev)
 {
        int retval;
 
@@ -653,13 +653,14 @@ static struct platform_device *rtc_platform_device;
 
 static struct platform_driver rtc_device_driver = {
        .probe          = rtc_probe,
-       .remove         = rtc_remove,
+       .remove         = __devexit_p(rtc_remove),
        .driver         = {
                .name   = rtc_name,
+               .owner  = THIS_MODULE,
        },
 };
 
-static int __devinit vr41xx_rtc_init(void)
+static int __init vr41xx_rtc_init(void)
 {
        int retval;
 
@@ -684,10 +685,20 @@ static int __devinit vr41xx_rtc_init(void)
                break;
        }
 
-       rtc_platform_device = platform_device_register_simple("RTC", -1,
-                             rtc_resource, ARRAY_SIZE(rtc_resource));
-       if (IS_ERR(rtc_platform_device))
-               return PTR_ERR(rtc_platform_device);
+       rtc_platform_device = platform_device_alloc("RTC", -1);
+       if (!rtc_platform_device)
+               return -ENOMEM;
+
+       retval = platform_device_add_resources(rtc_platform_device,
+                               rtc_resource, ARRAY_SIZE(rtc_resource));
+
+       if (retval == 0)
+               retval = platform_device_add(rtc_platform_device);
+
+       if (retval < 0) {
+               platform_device_put(rtc_platform_device);
+               return retval;
+       }
 
        retval = platform_driver_register(&rtc_device_driver);
        if (retval < 0)
@@ -696,10 +707,9 @@ static int __devinit vr41xx_rtc_init(void)
        return retval;
 }
 
-static void __devexit vr41xx_rtc_exit(void)
+static void __exit vr41xx_rtc_exit(void)
 {
        platform_driver_unregister(&rtc_device_driver);
-
        platform_device_unregister(rtc_platform_device);
 }
 
index 00d9ef04a3697dde00f1d2121c526c33f4ec0c5e..f1b9cf89f153ab727d357435437c0f6fc54dea73 100644 (file)
@@ -228,15 +228,25 @@ static int __init mv64x60_wdt_init(void)
 
        printk(KERN_INFO "MV64x60 watchdog driver\n");
 
-       mv64x60_wdt_dev = platform_device_register_simple(MV64x60_WDT_NAME,
-                                                         -1, NULL, 0);
-       if (IS_ERR(mv64x60_wdt_dev)) {
-               ret = PTR_ERR(mv64x60_wdt_dev);
+       mv64x60_wdt_dev = platform_device_alloc(MV64x60_WDT_NAME, -1);
+       if (!mv64x60_wdt_dev) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       ret = platform_device_add(mv64x60_wdt_dev);
+       if (ret) {
+               platform_device_put(mv64x60_wdt_dev);
                goto out;
        }
 
        ret = platform_driver_register(&mv64x60_wdt_driver);
-      out:
+       if (ret) {
+               platform_device_unregister(mv64x60_wdt_dev);
+               goto out;
+       }
+
+ out:
        return ret;
 }
 
index 4652512f7d1a928a6830b5d15d91f4c20bdfc59e..3a4e5c5b4e1fc9d0fb421f9ed3cedd38a5f1fa26 100644 (file)
@@ -530,30 +530,27 @@ static DCDBAS_DEV_ATTR_RW(host_control_action);
 static DCDBAS_DEV_ATTR_RW(host_control_smi_type);
 static DCDBAS_DEV_ATTR_RW(host_control_on_shutdown);
 
-static struct device_attribute *dcdbas_dev_attrs[] = {
-       &dev_attr_smi_data_buf_size,
-       &dev_attr_smi_data_buf_phys_addr,
-       &dev_attr_smi_request,
-       &dev_attr_host_control_action,
-       &dev_attr_host_control_smi_type,
-       &dev_attr_host_control_on_shutdown,
+static struct attribute *dcdbas_dev_attrs[] = {
+       &dev_attr_smi_data_buf_size.attr,
+       &dev_attr_smi_data_buf_phys_addr.attr,
+       &dev_attr_smi_request.attr,
+       &dev_attr_host_control_action.attr,
+       &dev_attr_host_control_smi_type.attr,
+       &dev_attr_host_control_on_shutdown.attr,
        NULL
 };
 
-/**
- * dcdbas_init: initialize driver
- */
-static int __init dcdbas_init(void)
+static struct attribute_group dcdbas_attr_group = {
+       .attrs = dcdbas_dev_attrs,
+};
+
+static int __devinit dcdbas_probe(struct platform_device *dev)
 {
-       int i;
+       int i, error;
 
        host_control_action = HC_ACTION_NONE;
        host_control_smi_type = HC_SMITYPE_NONE;
 
-       dcdbas_pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0);
-       if (IS_ERR(dcdbas_pdev))
-               return PTR_ERR(dcdbas_pdev);
-
        /*
         * BIOS SMI calls require buffer addresses be in 32-bit address space.
         * This is done by setting the DMA mask below.
@@ -561,19 +558,79 @@ static int __init dcdbas_init(void)
        dcdbas_pdev->dev.coherent_dma_mask = DMA_32BIT_MASK;
        dcdbas_pdev->dev.dma_mask = &dcdbas_pdev->dev.coherent_dma_mask;
 
+       error = sysfs_create_group(&dev->dev.kobj, &dcdbas_attr_group);
+       if (error)
+               return error;
+
+       for (i = 0; dcdbas_bin_attrs[i]; i++) {
+               error = sysfs_create_bin_file(&dev->dev.kobj,
+                                             dcdbas_bin_attrs[i]);
+               if (error) {
+                       while (--i >= 0)
+                               sysfs_remove_bin_file(&dev->dev.kobj,
+                                                     dcdbas_bin_attrs[i]);
+                       sysfs_create_group(&dev->dev.kobj, &dcdbas_attr_group);
+                       return error;
+               }
+       }
+
        register_reboot_notifier(&dcdbas_reboot_nb);
 
+       dev_info(&dev->dev, "%s (version %s)\n",
+                DRIVER_DESCRIPTION, DRIVER_VERSION);
+
+       return 0;
+}
+
+static int __devexit dcdbas_remove(struct platform_device *dev)
+{
+       int i;
+
+       unregister_reboot_notifier(&dcdbas_reboot_nb);
        for (i = 0; dcdbas_bin_attrs[i]; i++)
-               sysfs_create_bin_file(&dcdbas_pdev->dev.kobj,
-                                     dcdbas_bin_attrs[i]);
+               sysfs_remove_bin_file(&dev->dev.kobj, dcdbas_bin_attrs[i]);
+       sysfs_remove_group(&dev->dev.kobj, &dcdbas_attr_group);
 
-       for (i = 0; dcdbas_dev_attrs[i]; i++)
-               device_create_file(&dcdbas_pdev->dev, dcdbas_dev_attrs[i]);
+       return 0;
+}
 
-       dev_info(&dcdbas_pdev->dev, "%s (version %s)\n",
-                DRIVER_DESCRIPTION, DRIVER_VERSION);
+static struct platform_driver dcdbas_driver = {
+       .driver         = {
+               .name   = DRIVER_NAME,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = dcdbas_probe,
+       .remove         = __devexit_p(dcdbas_remove),
+};
+
+/**
+ * dcdbas_init: initialize driver
+ */
+static int __init dcdbas_init(void)
+{
+       int error;
+
+       error = platform_driver_register(&dcdbas_driver);
+       if (error)
+               return error;
+
+       dcdbas_pdev = platform_device_alloc(DRIVER_NAME, -1);
+       if (!dcdbas_pdev) {
+               error = -ENOMEM;
+               goto err_unregister_driver;
+       }
+
+       error = platform_device_add(dcdbas_pdev);
+       if (error)
+               goto err_free_device;
 
        return 0;
+
+ err_free_device:
+       platform_device_put(dcdbas_pdev);
+ err_unregister_driver:
+       platform_driver_unregister(&dcdbas_driver);
+       return error;
 }
 
 /**
@@ -588,6 +645,15 @@ static void __exit dcdbas_exit(void)
        unregister_reboot_notifier(&dcdbas_reboot_nb);
        smi_data_buf_free();
        platform_device_unregister(dcdbas_pdev);
+       platform_driver_unregister(&dcdbas_driver);
+
+       /*
+        * We have to free the buffer here instead of dcdbas_remove
+        * because only in module exit function we can be sure that
+        * all sysfs attributes belonging to this module have been
+        * released.
+        */
+       smi_data_buf_free();
 }
 
 module_init(dcdbas_init);
index 88d60202b9db409bcfcc48069ef7bc49547172af..26b08ee425c74d6b0ce9ecee09a5d817a1e51841 100644 (file)
@@ -533,30 +533,35 @@ static void __clone_and_map(struct clone_info *ci)
 
        } else {
                /*
-                * Create two copy bios to deal with io that has
-                * been split across a target.
+                * Handle a bvec that must be split between two or more targets.
                 */
                struct bio_vec *bv = bio->bi_io_vec + ci->idx;
+               sector_t remaining = to_sector(bv->bv_len);
+               unsigned int offset = 0;
 
-               clone = split_bvec(bio, ci->sector, ci->idx,
-                                  bv->bv_offset, max);
-               __map_bio(ti, clone, tio);
+               do {
+                       if (offset) {
+                               ti = dm_table_find_target(ci->map, ci->sector);
+                               max = max_io_len(ci->md, ci->sector, ti);
 
-               ci->sector += max;
-               ci->sector_count -= max;
-               ti = dm_table_find_target(ci->map, ci->sector);
-
-               len = to_sector(bv->bv_len) - max;
-               clone = split_bvec(bio, ci->sector, ci->idx,
-                                  bv->bv_offset + to_bytes(max), len);
-               tio = alloc_tio(ci->md);
-               tio->io = ci->io;
-               tio->ti = ti;
-               memset(&tio->info, 0, sizeof(tio->info));
-               __map_bio(ti, clone, tio);
+                               tio = alloc_tio(ci->md);
+                               tio->io = ci->io;
+                               tio->ti = ti;
+                               memset(&tio->info, 0, sizeof(tio->info));
+                       }
+
+                       len = min(remaining, max);
+
+                       clone = split_bvec(bio, ci->sector, ci->idx,
+                                          bv->bv_offset + offset, len);
+
+                       __map_bio(ti, clone, tio);
+
+                       ci->sector += len;
+                       ci->sector_count -= len;
+                       offset += to_bytes(len);
+               } while (remaining -= len);
 
-               ci->sector += len;
-               ci->sector_count -= len;
                ci->idx++;
        }
 }
index e67cf15e9c3961af697067c4007e78ffd359da4b..bbc229852881e133affea9a4984a6ce806f1f622 100644 (file)
@@ -9,6 +9,7 @@ config FUSION_SPI
        tristate "Fusion MPT ScsiHost drivers for SPI"
        depends on PCI && SCSI
        select FUSION
+       select SCSI_SPI_ATTRS
        ---help---
          SCSI HOST support for a parallel SCSI host adapters.
 
index 33ace373241cb4b80997b60bb52b29dc46c87f8b..51740b346224b35fd80d79ad7e56882647d4a18b 100644 (file)
@@ -4,6 +4,7 @@
 #EXTRA_CFLAGS += -DMPT_DEBUG_MSG_FRAME
 #EXTRA_CFLAGS += -DMPT_DEBUG_SG
 #EXTRA_CFLAGS += -DMPT_DEBUG_EVENTS
+#EXTRA_CFLAGS += -DMPT_DEBUG_VERBOSE_EVENTS
 #EXTRA_CFLAGS += -DMPT_DEBUG_INIT
 #EXTRA_CFLAGS += -DMPT_DEBUG_EXIT
 #EXTRA_CFLAGS += -DMPT_DEBUG_FAIL
index 9259d1ad6e6e579b47ac61908abfd99c8caa6c09..a9c14ad132ce1a2dda6b965acf20211c2a0b6e9c 100644 (file)
@@ -3,38 +3,11 @@
  *                                                                         *
  *  Copyright 2003 LSI Logic Corporation.  All rights reserved.            *
  *                                                                         *
- *  This file is confidential and a trade secret of LSI Logic.  The        *
- *  receipt of or possession of this file does not convey any rights to    *
- *  reproduce or disclose its contents or to manufacture, use, or sell     *
- *  anything it may describe, in whole, or in part, without the specific   *
- *  written consent of LSI Logic Corporation.                              *
+ * Description                                                             *
+ * ------------                                                            *
+ * This include file contains SAS firmware interface IOC Log Info codes    *
  *                                                                         *
- ***************************************************************************
- *
- *           Name:  iopiIocLogInfo.h
- *          Title:  SAS Firmware IOP Interface IOC Log Info Definitions
- *     Programmer:  Guy Kendall
- *  Creation Date:  September 24, 2003
- *
- *  Version History
- *  ---------------
- *
- *  Last Updated
- *  -------------
- *  Version         %version: 22 %
- *  Date Updated    %date_modified: %
- *  Programmer      %created_by: nperucca %
- *
- *  Date      Who   Description
- *  --------  ---   -------------------------------------------------------
- *  09/24/03  GWK   Initial version
- *
- *
- * Description
- * ------------
- * This include file contains SAS firmware interface IOC Log Info codes
- *
- *-------------------------------------------------------------------------
+ *-------------------------------------------------------------------------*
  */
 
 #ifndef IOPI_IOCLOGINFO_H_INCLUDED
@@ -57,6 +30,8 @@
 #define IOC_LOGINFO_ORIGINATOR_PL                       (0x01000000)
 #define IOC_LOGINFO_ORIGINATOR_IR                       (0x02000000)
 
+#define IOC_LOGINFO_ORIGINATOR_MASK                     (0x0F000000)
+
 /****************************************************************************/
 /* LOGINFO_CODE defines                                                     */
 /****************************************************************************/
 #define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_DEFAULT    (0x00030700) /* Default Page not found */
 #define IOP_LOGINFO_CODE_TASK_TERMINATED                (0x00050000)
 
+#define IOP_LOGINFO_CODE_ENCL_MGMT_READ_ACTION_ERR0R    (0x00060001) /* Read Action not supported for SEP msg */
+#define IOP_LOGINFO_CODE_ENCL_MGMT_INVALID_BUS_ID_ERR0R (0x00060002) /* Invalid Bus/ID in SEP msg */
+
+#define IOP_LOGINFO_CODE_TARGET_ASSIST_TERMINATED       (0x00070001)
+#define IOP_LOGINFO_CODE_TARGET_STATUS_SEND_TERMINATED  (0x00070002)
+#define IOP_LOGINFO_CODE_TARGET_MODE_ABORT_ALL_IO       (0x00070003)
+#define IOP_LOGINFO_CODE_TARGET_MODE_ABORT_EXACT_IO     (0x00070004)
+#define IOP_LOGINFO_CODE_TARGET_MODE_ABORT_EXACT_IO_REQ (0x00070005)
 
 /****************************************************************************/
 /* PL LOGINFO_CODE defines, valid if IOC_LOGINFO_ORIGINATOR = PL            */
 /****************************************************************************/
 #define PL_LOGINFO_CODE_OPEN_FAILURE                        (0x00010000)
+#define PL_LOG_INFO_CODE_OPEN_FAILURE_NO_DEST_TIME_OUT      (0x00010001)
+#define PL_LOGINFO_CODE_OPEN_FAILURE_BAD_DESTINATION        (0x00010011)
+#define PL_LOGINFO_CODE_OPEN_FAILURE_PROTOCOL_NOT_SUPPORTED (0x00010013)
+#define PL_LOGINFO_CODE_OPEN_FAILURE_STP_RESOURCES_BSY      (0x00010018)
+#define PL_LOGINFO_CODE_OPEN_FAILURE_WRONG_DESTINATION      (0x00010019)
+#define PL_LOGINFO_CODE_OPEN_FAILURE_ORR_TIMEOUT            (0X0001001A)
+#define PL_LOGINFO_CODE_OPEN_FAILURE_PATHWAY_BLOCKED        (0x0001001B)
+#define PL_LOGINFO_CODE_OPEN_FAILURE_AWT_MAXED              (0x0001001C)
 #define PL_LOGINFO_CODE_INVALID_SGL                         (0x00020000)
 #define PL_LOGINFO_CODE_WRONG_REL_OFF_OR_FRAME_LENGTH       (0x00030000)
 #define PL_LOGINFO_CODE_FRAME_XFER_ERROR                    (0x00040000)
@@ -97,6 +88,7 @@
 #define PL_LOGINFO_CODE_SATA_LINK_DOWN                      (0x000D0000)
 #define PL_LOGINFO_CODE_DISCOVERY_SATA_INIT_W_IOS           (0x000E0000)
 #define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE                 (0x000F0000)
+#define PL_LOGINFO_CODE_CONFIG_PL_NOT_INITIALIZED           (0x000F0001) /* PL not yet initialized, can't do config page req. */
 #define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_PT              (0x000F0100) /* Invalid Page Type */
 #define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_NUM_PHYS        (0x000F0200) /* Invalid Number of Phys */
 #define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_NOT_IMP         (0x000F0300) /* Case Not Handled */
 #define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_PHY             (0x000F0600) /* Invalid Phy */
 #define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_NO_OWNER        (0x000F0700) /* No Owner Found */
 #define PL_LOGINFO_CODE_DSCVRY_SATA_INIT_TIMEOUT            (0x00100000)
-#define PL_LOGINFO_CODE_RESET                               (0x00110000)
-#define PL_LOGINFO_CODE_ABORT                               (0x00120000)
+#define PL_LOGINFO_CODE_RESET                               (0x00110000) /* See Sub-Codes below */
+#define PL_LOGINFO_CODE_ABORT                               (0x00120000) /* See Sub-Codes below */
 #define PL_LOGINFO_CODE_IO_NOT_YET_EXECUTED                 (0x00130000)
 #define PL_LOGINFO_CODE_IO_EXECUTED                         (0x00140000)
+#define PL_LOGINFO_CODE_PERS_RESV_OUT_NOT_AFFIL_OWNER       (0x00150000)
+#define PL_LOGINFO_CODE_OPEN_TXDMA_ABORT                    (0x00160000)
 #define PL_LOGINFO_SUB_CODE_OPEN_FAILURE                    (0x00000100)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_NO_DEST_TIMEOUT    (0x00000101)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_ORR_TIMEOUT        (0x0000011A) /* Open Reject (Retry) Timeout */
+#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_PATHWAY_BLOCKED    (0x0000011B)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_AWT_MAXED          (0x0000011C) /* Arbitration Wait Timer Maxed */
+
+#define PL_LOGINFO_SUB_CODE_TARGET_BUS_RESET                (0x00000120)
+#define PL_LOGINFO_SUB_CODE_TRANSPORT_LAYER                 (0x00000130)  /* Leave lower nibble (1-f) reserved. */
+#define PL_LOGINFO_SUB_CODE_PORT_LAYER                      (0x00000140)  /* Leave lower nibble (1-f) reserved. */
+
+
 #define PL_LOGINFO_SUB_CODE_INVALID_SGL                     (0x00000200)
 #define PL_LOGINFO_SUB_CODE_WRONG_REL_OFF_OR_FRAME_LENGTH   (0x00000300)
 #define PL_LOGINFO_SUB_CODE_FRAME_XFER_ERROR                (0x00000400)
 #define PL_LOGINFO_SUB_CODE_RX_FM_CURRENT_FRAME_ERROR       (0x00000C00)
 #define PL_LOGINFO_SUB_CODE_SATA_LINK_DOWN                  (0x00000D00)
 #define PL_LOGINFO_SUB_CODE_DISCOVERY_SATA_INIT_W_IOS       (0x00000E00)
+#define PL_LOGINFO_SUB_CODE_DISCOVERY_REMOTE_SEP_RESET      (0x00000E01)
+#define PL_LOGINFO_SUB_CODE_SECOND_OPEN                     (0x00000F00)
 #define PL_LOGINFO_SUB_CODE_DSCVRY_SATA_INIT_TIMEOUT        (0x00001000)
 
 
 #define PL_LOGINFO_CODE_ENCL_MGMT_SMP_FRAME_FAILURE         (0x00200000) /* Can't get SMP Frame */
-#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_READ_ERROR            (0x00200001) /* Error occured on SMP Read */
-#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_WRITE_ERROR           (0x00200002) /* Error occured on SMP Write */
-#define PL_LOGINFO_CODE_ENCL_MGMT_NOT_SUPPORTED_ON_ENCL     (0x00200004) /* Encl Mgmt services not available for this WWID */
-#define PL_LOGINFO_CODE_ENCL_MGMT_ADDR_MODE_NOT_SUPPORTED   (0x00200005) /* Address Mode not suppored */
-#define PL_LOGINFO_CODE_ENCL_MGMT_BAD_SLOT_NUM              (0x00200006) /* Invalid Slot Number in SEP Msg */
-#define PL_LOGINFO_CODE_ENCL_MGMT_SGPIO_NOT_PRESENT         (0x00200007) /* SGPIO not present/enabled */
+#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_READ_ERROR            (0x00200010) /* Error occured on SMP Read */
+#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_WRITE_ERROR           (0x00200020) /* Error occured on SMP Write */
+#define PL_LOGINFO_CODE_ENCL_MGMT_NOT_SUPPORTED_ON_ENCL     (0x00200040) /* Encl Mgmt services not available for this WWID */
+#define PL_LOGINFO_CODE_ENCL_MGMT_ADDR_MODE_NOT_SUPPORTED   (0x00200050) /* Address Mode not suppored */
+#define PL_LOGINFO_CODE_ENCL_MGMT_BAD_SLOT_NUM              (0x00200060) /* Invalid Slot Number in SEP Msg */
+#define PL_LOGINFO_CODE_ENCL_MGMT_SGPIO_NOT_PRESENT         (0x00200070) /* SGPIO not present/enabled */
+#define PL_LOGINFO_CODE_ENCL_MGMT_GPIO_NOT_CONFIGURED       (0x00200080) /* GPIO not configured */
+#define PL_LOGINFO_CODE_ENCL_MGMT_GPIO_FRAME_ERROR          (0x00200090) /* GPIO can't allocate a frame */
+#define PL_LOGINFO_CODE_ENCL_MGMT_GPIO_CONFIG_PAGE_ERROR    (0x002000A0) /* GPIO failed config page request */
+#define PL_LOGINFO_CODE_ENCL_MGMT_SES_FRAME_ALLOC_ERROR     (0x002000B0) /* Can't get frame for SES command */
+#define PL_LOGINFO_CODE_ENCL_MGMT_SES_IO_ERROR              (0x002000C0) /* I/O execution error */
+#define PL_LOGINFO_CODE_ENCL_MGMT_SES_RETRIES_EXHAUSTED     (0x002000D0) /* SEP I/O retries exhausted */
+#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_FRAME_ALLOC_ERROR     (0x002000E0) /* Can't get frame for SMP command */
 
 #define PL_LOGINFO_DA_SEP_NOT_PRESENT                       (0x00200100) /* SEP not present when msg received */
 #define PL_LOGINFO_DA_SEP_SINGLE_THREAD_ERROR               (0x00200101) /* Can only accept 1 msg at a time */
 #define PL_LOGINFO_DA_SEP_ISTWI_INTR_IN_IDLE_STATE          (0x00200102) /* ISTWI interrupt recvd. while IDLE */
 #define PL_LOGINFO_DA_SEP_RECEIVED_NACK_FROM_SLAVE          (0x00200103) /* SEP NACK'd, it is busy */
-#define PL_LOGINFO_DA_SEP_BAD_STATUS_HDR_CHKSUM             (0x00200104) /* SEP stopped or sent bad chksum in Hdr */
-#define PL_LOGINFO_DA_SEP_UNSUPPORTED_SCSI_STATUS_1         (0x00200105) /* SEP returned unknown scsi status */
-#define PL_LOGINFO_DA_SEP_UNSUPPORTED_SCSI_STATUS_2         (0x00200106) /* SEP returned unknown scsi status */
-#define PL_LOGINFO_DA_SEP_CHKSUM_ERROR_AFTER_STOP           (0x00200107) /* SEP returned bad chksum after STOP */
-#define PL_LOGINFO_DA_SEP_CHKSUM_ERROR_AFTER_STOP_GETDATA   (0x00200108) /* SEP returned bad chksum after STOP while gettin data*/
+#define PL_LOGINFO_DA_SEP_DID_NOT_RECEIVE_ACK               (0x00200104) /* SEP didn't rcv. ACK (Last Rcvd Bit = 1) */
+#define PL_LOGINFO_DA_SEP_BAD_STATUS_HDR_CHKSUM             (0x00200105) /* SEP stopped or sent bad chksum in Hdr */
+#define PL_LOGINFO_DA_SEP_STOP_ON_DATA                      (0x00200106) /* SEP stopped while transfering data */
+#define PL_LOGINFO_DA_SEP_STOP_ON_SENSE_DATA                (0x00200107) /* SEP stopped while transfering sense data */
+#define PL_LOGINFO_DA_SEP_UNSUPPORTED_SCSI_STATUS_1         (0x00200108) /* SEP returned unknown scsi status */
+#define PL_LOGINFO_DA_SEP_UNSUPPORTED_SCSI_STATUS_2         (0x00200109) /* SEP returned unknown scsi status */
+#define PL_LOGINFO_DA_SEP_CHKSUM_ERROR_AFTER_STOP           (0x0020010A) /* SEP returned bad chksum after STOP */
+#define PL_LOGINFO_DA_SEP_CHKSUM_ERROR_AFTER_STOP_GETDATA   (0x0020010B) /* SEP returned bad chksum after STOP while gettin data*/
+#define PL_LOGINFO_DA_SEP_UNSUPPORTED_COMMAND               (0x0020010C) /* SEP doesn't support CDB opcode */
 
 
 /****************************************************************************/
index 642a61b6d0a4ebd3a89732c002a071dc633156ce..266414ca2814e935b1d589f4c68aa7eed49c028e 100644 (file)
@@ -180,6 +180,7 @@ static void mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
 static void    mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
 static void    mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
 static void    mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
+static int     mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
 
 /* module entry point */
 static int  __init    fusion_init  (void);
@@ -428,7 +429,7 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
                results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
                if (results != evHandlers) {
                        /* CHECKME! Any special handling needed here? */
-                       devtprintk((MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
+                       devtverboseprintk((MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
                                        ioc->name, evHandlers, results));
                }
 
@@ -438,10 +439,10 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
                 */
                if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) {
                        freereq = 0;
-                       devtprintk((MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p does not return Request frame\n",
+                       devtverboseprintk((MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p does not return Request frame\n",
                                ioc->name, pEvReply));
                } else {
-                       devtprintk((MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
+                       devtverboseprintk((MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
                                ioc->name, pEvReply));
                }
 
@@ -1120,65 +1121,6 @@ mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
        return -1;
 }
 
-int
-mpt_alt_ioc_wait(MPT_ADAPTER *ioc)
-{
-       int loop_count = 30 * 4;  /* Wait 30 seconds */
-       int status = -1; /* -1 means failed to get board READY */
-
-       do {
-               spin_lock(&ioc->initializing_hba_lock);
-               if (ioc->initializing_hba_lock_flag == 0) {
-                       ioc->initializing_hba_lock_flag=1;
-                       spin_unlock(&ioc->initializing_hba_lock);
-                       status = 0;
-                       break;
-               }
-               spin_unlock(&ioc->initializing_hba_lock);
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout(HZ/4);
-       } while (--loop_count);
-
-       return status;
-}
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- *     mpt_bringup_adapter - This is a wrapper function for mpt_do_ioc_recovery
- *     @ioc: Pointer to MPT adapter structure
- *     @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
- *
- *     This routine performs all the steps necessary to bring the IOC
- *     to a OPERATIONAL state.
- *
- *      Special Note: This function was added with spin lock's so as to allow
- *      the dv(domain validation) work thread to succeed on the other channel
- *      that maybe occuring at the same time when this function is called.
- *      Without this lock, the dv would fail when message frames were
- *      requested during hba bringup on the alternate ioc.
- */
-static int
-mpt_bringup_adapter(MPT_ADAPTER *ioc, int sleepFlag)
-{
-       int r;
-
-       if(ioc->alt_ioc) {
-               if((r=mpt_alt_ioc_wait(ioc->alt_ioc)!=0))
-                       return r;
-       }
-
-       r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
-           CAN_SLEEP);
-
-       if(ioc->alt_ioc) {
-               spin_lock(&ioc->alt_ioc->initializing_hba_lock);
-               ioc->alt_ioc->initializing_hba_lock_flag=0;
-               spin_unlock(&ioc->alt_ioc->initializing_hba_lock);
-       }
-
-return r;
-}
-
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *     mpt_attach - Install a PCI intelligent MPT adapter.
@@ -1482,7 +1424,8 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
         */
        mpt_detect_bound_ports(ioc, pdev);
 
-       if ((r = mpt_bringup_adapter(ioc, CAN_SLEEP)) != 0){
+       if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
+           CAN_SLEEP)) != 0){
                printk(KERN_WARNING MYNAM
                  ": WARNING - %s did not initialize properly! (%d)\n",
                  ioc->name, r);
@@ -1629,7 +1572,6 @@ mpt_resume(struct pci_dev *pdev)
        MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
        u32 device_state = pdev->current_state;
        int recovery_state;
-       int ii;
 
        printk(MYIOC_s_INFO_FMT
        "pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n",
@@ -1643,14 +1585,6 @@ mpt_resume(struct pci_dev *pdev)
        CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
        ioc->active = 1;
 
-       /* F/W not running */
-       if(!CHIPREG_READ32(&ioc->chip->Doorbell)) {
-               /* enable domain validation flags */
-               for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
-                       ioc->spi_data.dvStatus[ii] |= MPT_SCSICFG_NEED_DV;
-               }
-       }
-
        printk(MYIOC_s_INFO_FMT
                "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
                ioc->name,
@@ -4938,7 +4872,7 @@ done_and_free:
        return rc;
 }
 
-int
+static int
 mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
 {
        IOCPage3_t              *pIoc3;
@@ -5146,13 +5080,13 @@ SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
 
        evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
        if (evnp == NULL) {
-               devtprintk((MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
+               devtverboseprintk((MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
                                ioc->name));
                return 0;
        }
        memset(evnp, 0, sizeof(*evnp));
 
-       devtprintk((MYIOC_s_INFO_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
+       devtverboseprintk((MYIOC_s_INFO_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
 
        evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
        evnp->ChainOffset = 0;
@@ -5907,24 +5841,27 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr)
                break;
        case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
        {
+               char buf[50];
+               u8 id = (u8)(evData0);
                u8 ReasonCode = (u8)(evData0 >> 16);
                switch (ReasonCode) {
                case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
-                       ds = "SAS Device Status Change: Added";
+                       sprintf(buf,"SAS Device Status Change: Added: id=%d", id);
                        break;
                case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
-                       ds = "SAS Device Status Change: Deleted";
+                       sprintf(buf,"SAS Device Status Change: Deleted: id=%d", id);
                        break;
                case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
-                       ds = "SAS Device Status Change: SMART Data";
+                       sprintf(buf,"SAS Device Status Change: SMART Data: id=%d", id);
                        break;
                case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
-                       ds = "SAS Device Status Change: No Persistancy Added";
+                       sprintf(buf,"SAS Device Status Change: No Persistancy Added: id=%d", id);
                        break;
                default:
-                       ds = "SAS Device Status Change: Unknown";
+                       sprintf(buf,"SAS Device Status Change: Unknown: id=%d", id);
                break;
                }
+               ds = buf;
                break;
        }
        case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
@@ -5940,11 +5877,97 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr)
                ds = "Persistent Table Full";
                break;
        case MPI_EVENT_SAS_PHY_LINK_STATUS:
-               ds = "SAS PHY Link Status";
+       {
+               char buf[50];
+               u8 LinkRates = (u8)(evData0 >> 8);
+               u8 PhyNumber = (u8)(evData0);
+               LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
+                       MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
+               switch (LinkRates) {
+               case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
+                       sprintf(buf,"SAS PHY Link Status: Phy=%d:"
+                          " Rate Unknown",PhyNumber);
+                       break;
+               case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
+                       sprintf(buf,"SAS PHY Link Status: Phy=%d:"
+                          " Phy Disabled",PhyNumber);
+                       break;
+               case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
+                       sprintf(buf,"SAS PHY Link Status: Phy=%d:"
+                          " Failed Speed Nego",PhyNumber);
+                       break;
+               case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
+                       sprintf(buf,"SAS PHY Link Status: Phy=%d:"
+                          " Sata OOB Completed",PhyNumber);
+                       break;
+               case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
+                       sprintf(buf,"SAS PHY Link Status: Phy=%d:"
+                          " Rate 1.5 Gbps",PhyNumber);
+                       break;
+               case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
+                       sprintf(buf,"SAS PHY Link Status: Phy=%d:"
+                          " Rate 3.0 Gpbs",PhyNumber);
+                       break;
+               default:
+                       sprintf(buf,"SAS PHY Link Status: Phy=%d", PhyNumber);
+                       break;
+               }
+               ds = buf;
                break;
+       }
        case MPI_EVENT_SAS_DISCOVERY_ERROR:
                ds = "SAS Discovery Error";
                break;
+       case MPI_EVENT_IR_RESYNC_UPDATE:
+       {
+               u8 resync_complete = (u8)(evData0 >> 16);
+               char buf[40];
+               sprintf(buf,"IR Resync Update: Complete = %d:",resync_complete);
+               ds = buf;
+               break;
+       }
+       case MPI_EVENT_IR2:
+       {
+               u8 ReasonCode = (u8)(evData0 >> 16);
+               switch (ReasonCode) {
+               case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
+                       ds = "IR2: LD State Changed";
+                       break;
+               case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
+                       ds = "IR2: PD State Changed";
+                       break;
+               case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
+                       ds = "IR2: Bad Block Table Full";
+                       break;
+               case MPI_EVENT_IR2_RC_PD_INSERTED:
+                       ds = "IR2: PD Inserted";
+                       break;
+               case MPI_EVENT_IR2_RC_PD_REMOVED:
+                       ds = "IR2: PD Removed";
+                       break;
+               case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
+                       ds = "IR2: Foreign CFG Detected";
+                       break;
+               case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
+                       ds = "IR2: Rebuild Medium Error";
+                       break;
+               default:
+                       ds = "IR2";
+               break;
+               }
+               break;
+       }
+       case MPI_EVENT_SAS_DISCOVERY:
+       {
+               if (evData0)
+                       ds = "SAS Discovery: Start";
+               else
+                       ds = "SAS Discovery: Stop";
+               break;
+       }
+       case MPI_EVENT_LOG_ENTRY_ADDED:
+               ds = "SAS Log Entry Added";
+               break;
 
        /*
         *  MPT base "custom" events may be added here...
@@ -5989,12 +6012,12 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply
        }
 
        EventDescriptionStr(event, evData0, evStr);
-       devtprintk((MYIOC_s_INFO_FMT "MPT event (%s=%02Xh) detected!\n",
+       devtprintk((MYIOC_s_INFO_FMT "MPT event:(%02Xh) : %s\n",
                        ioc->name,
-                       evStr,
-                       event));
+                       event,
+                       evStr));
 
-#if defined(MPT_DEBUG) || defined(MPT_DEBUG_EVENTS)
+#if defined(MPT_DEBUG) || defined(MPT_DEBUG_VERBOSE_EVENTS)
        printk(KERN_INFO MYNAM ": Event data:\n" KERN_INFO);
        for (ii = 0; ii < evDataLen; ii++)
                printk(" %08x", le32_to_cpu(pEventReply->Data[ii]));
@@ -6053,7 +6076,7 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply
         */
        for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
                if (MptEvHandlers[ii]) {
-                       devtprintk((MYIOC_s_INFO_FMT "Routing Event to event handler #%d\n",
+                       devtverboseprintk((MYIOC_s_INFO_FMT "Routing Event to event handler #%d\n",
                                        ioc->name, ii));
                        r += (*(MptEvHandlers[ii]))(ioc, pEventReply);
                        handlers++;
@@ -6065,10 +6088,10 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply
         *  If needed, send (a single) EventAck.
         */
        if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
-               devtprintk((MYIOC_s_WARN_FMT
+               devtverboseprintk((MYIOC_s_WARN_FMT
                        "EventAck required\n",ioc->name));
                if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
-                       devtprintk((MYIOC_s_WARN_FMT "SendEventAck returned %d\n",
+                       devtverboseprintk((MYIOC_s_WARN_FMT "SendEventAck returned %d\n",
                                        ioc->name, ii));
                }
        }
@@ -6205,8 +6228,8 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
                "Abort",                                        /* 12h */
                "IO Not Yet Executed",                          /* 13h */
                "IO Executed",                                  /* 14h */
-               NULL,                                           /* 15h */
-               NULL,                                           /* 16h */
+               "Persistant Reservation Out Not Affiliation Owner", /* 15h */
+               "Open Transmit DMA Abort",                      /* 16h */
                NULL,                                           /* 17h */
                NULL,                                           /* 18h */
                NULL,                                           /* 19h */
@@ -6431,11 +6454,9 @@ EXPORT_SYMBOL(mpt_stm_index);
 EXPORT_SYMBOL(mpt_HardResetHandler);
 EXPORT_SYMBOL(mpt_config);
 EXPORT_SYMBOL(mpt_findImVolumes);
-EXPORT_SYMBOL(mpt_read_ioc_pg_3);
 EXPORT_SYMBOL(mpt_alloc_fw_memory);
 EXPORT_SYMBOL(mpt_free_fw_memory);
 EXPORT_SYMBOL(mptbase_sas_persist_operation);
-EXPORT_SYMBOL(mpt_alt_ioc_wait);
 EXPORT_SYMBOL(mptbase_GetFcPortPage0);
 
 
index 723d543009530262d3f2bdbe68ea3486108856f5..be7e8501b53c1d4243691625003cd690c0b75932 100644 (file)
@@ -76,8 +76,8 @@
 #define COPYRIGHT      "Copyright (c) 1999-2005 " MODULEAUTHOR
 #endif
 
-#define MPT_LINUX_VERSION_COMMON       "3.03.07"
-#define MPT_LINUX_PACKAGE_NAME         "@(#)mptlinux-3.03.07"
+#define MPT_LINUX_VERSION_COMMON       "3.03.08"
+#define MPT_LINUX_PACKAGE_NAME         "@(#)mptlinux-3.03.08"
 #define WHAT_MAGIC_STRING              "@" "(" "#" ")"
 
 #define show_mptmod_ver(s,ver)  \
@@ -331,6 +331,7 @@ typedef struct _SYSIF_REGS
  *     VirtDevice - FC LUN device or SCSI target device
  */
 typedef struct _VirtTarget {
+       struct scsi_target      *starget;
        u8                       tflags;
        u8                       ioc_id;
        u8                       target_id;
@@ -343,14 +344,10 @@ typedef struct _VirtTarget {
        u8                       type;          /* byte 0 of Inquiry data */
        u32                      num_luns;
        u32                      luns[8];               /* Max LUNs is 256 */
-       u8                       inq_data[8];
 } VirtTarget;
 
 typedef struct _VirtDevice {
-       VirtTarget              *vtarget;
-       u8                       ioc_id;
-       u8                       bus_id;
-       u8                       target_id;
+       VirtTarget              *vtarget;
        u8                       configured_lun;
        u32                      lun;
 } VirtDevice;
@@ -364,6 +361,7 @@ typedef struct _VirtDevice {
 #define MPT_TARGET_FLAGS_Q_YES         0x08
 #define MPT_TARGET_FLAGS_VALID_56      0x10
 #define MPT_TARGET_FLAGS_SAF_TE_ISSUED 0x20
+#define MPT_TARGET_FLAGS_RAID_COMPONENT        0x40
 
 /*
  *     /proc/mpt interface
@@ -447,13 +445,6 @@ typedef struct _mpt_ioctl_events {
  *     Substructure to store SCSI specific configuration page data
  */
                                                /* dvStatus defines: */
-#define MPT_SCSICFG_NEGOTIATE          0x01    /* Negotiate on next IO */
-#define MPT_SCSICFG_NEED_DV            0x02    /* Schedule DV */
-#define MPT_SCSICFG_DV_PENDING         0x04    /* DV on this physical id pending */
-#define MPT_SCSICFG_DV_NOT_DONE                0x08    /* DV has not been performed */
-#define MPT_SCSICFG_BLK_NEGO           0x10    /* WriteSDP1 with WDTR and SDTR disabled */
-#define MPT_SCSICFG_RELOAD_IOC_PG3     0x20    /* IOC Pg 3 data is obsolete */
-                                               /* Args passed to writeSDP1: */
 #define MPT_SCSICFG_USE_NVRAM          0x01    /* WriteSDP1 using NVRAM */
 #define MPT_SCSICFG_ALL_IDS            0x02    /* WriteSDP1 to all IDS */
 /* #define MPT_SCSICFG_BLK_NEGO                0x10       WriteSDP1 with WDTR and SDTR disabled */
@@ -464,7 +455,6 @@ typedef     struct _SpiCfgData {
        IOCPage4_t      *pIocPg4;               /* SEP devices addressing */
        dma_addr_t       IocPg4_dma;            /* Phys Addr of IOCPage4 data */
        int              IocPg4Sz;              /* IOCPage4 size */
-       u8               dvStatus[MPT_MAX_SCSI_DEVICES];
        u8               minSyncFactor;         /* 0xFF if async */
        u8               maxSyncOffset;         /* 0 if async */
        u8               maxBusWidth;           /* 0 if narrow, 1 if wide */
@@ -474,13 +464,11 @@ typedef   struct _SpiCfgData {
        u8               sdp0version;           /* SDP0 version */
        u8               sdp0length;            /* SDP0 length  */
        u8               dvScheduled;           /* 1 if scheduled */
-       u8               forceDv;               /* 1 to force DV scheduling */
        u8               noQas;                 /* Disable QAS for this adapter */
        u8               Saf_Te;                /* 1 to force all Processors as
                                                 * SAF-TE if Inquiry data length
                                                 * is too short to check for SAF-TE
                                                 */
-       u8               mpt_dv;                /* command line option: enhanced=1, basic=0 */
        u8               bus_reset;             /* 1 to allow bus reset */
        u8               rsvd[1];
 }SpiCfgData;
@@ -631,6 +619,10 @@ typedef struct _MPT_ADAPTER
        struct net_device       *netdev;
        struct list_head         sas_topology;
        struct mutex             sas_topology_mutex;
+       struct mutex             sas_discovery_mutex;
+       u8                       sas_discovery_runtime;
+       u8                       sas_discovery_ignore_events;
+       int                      sas_index; /* index refrencing */
        MPT_SAS_MGMT             sas_mgmt;
        int                      num_ports;
        struct work_struct       mptscsih_persistTask;
@@ -728,12 +720,18 @@ typedef struct _mpt_sge {
 #define dhsprintk(x)
 #endif
 
-#ifdef MPT_DEBUG_EVENTS
+#if defined(MPT_DEBUG_EVENTS) || defined(MPT_DEBUG_VERBOSE_EVENTS)
 #define devtprintk(x)  printk x
 #else
 #define devtprintk(x)
 #endif
 
+#ifdef MPT_DEBUG_VERBOSE_EVENTS
+#define devtverboseprintk(x)  printk x
+#else
+#define devtverboseprintk(x)
+#endif
+
 #ifdef MPT_DEBUG_RESET
 #define drsprintk(x)  printk x
 #else
@@ -1030,10 +1028,8 @@ extern int        mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *cfg);
 extern void     mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size);
 extern void     mpt_free_fw_memory(MPT_ADAPTER *ioc);
 extern int      mpt_findImVolumes(MPT_ADAPTER *ioc);
-extern int      mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
 extern int      mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
 extern int      mptbase_GetFcPortPage0(MPT_ADAPTER *ioc, int portnum);
-extern int      mpt_alt_ioc_wait(MPT_ADAPTER *ioc);
 
 /*
  *  Public data decl's...
index 9b64e07400da464606d1153fce1f6c20f1eb7d4d..b4967bb8a7d64521b23207520fa22702fbce034d 100644 (file)
@@ -140,7 +140,7 @@ static int  mptctl_ioc_reset(MPT_ADAPTER *ioc, int reset_phase);
  * Event Handler function
  */
 static int mptctl_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
-struct fasync_struct *async_queue=NULL;
+static struct fasync_struct *async_queue=NULL;
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -497,7 +497,7 @@ mptctl_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
         if (event == 0x21 ) {
                ioc->aen_event_read_flag=1;
                dctlprintk(("Raised SIGIO to application\n"));
-               devtprintk(("Raised SIGIO to application\n"));
+               devtverboseprintk(("Raised SIGIO to application\n"));
                kill_fasync(&async_queue, SIGIO, POLL_IN);
                return 1;
         }
@@ -515,7 +515,7 @@ mptctl_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
        if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
                ioc->aen_event_read_flag=1;
                dctlprintk(("Raised SIGIO to application\n"));
-               devtprintk(("Raised SIGIO to application\n"));
+               devtverboseprintk(("Raised SIGIO to application\n"));
                kill_fasync(&async_queue, SIGIO, POLL_IN);
        }
        return 1;
@@ -2968,7 +2968,7 @@ static int __init mptctl_init(void)
        }
 
        if (mpt_event_register(mptctl_id, mptctl_event_process) == 0) {
-               devtprintk((KERN_INFO MYNAM
+               devtverboseprintk((KERN_INFO MYNAM
                  ": Registered for IOC event notifications\n"));
        }
 
index c3a3499bce2ae8c3ece665ce11f98b6027a1cd83..b343f2a68b1c755ceff84c70aaa774f8eff3576f 100644 (file)
@@ -154,7 +154,7 @@ MODULE_DEVICE_TABLE(pci, mptfc_pci_table);
 
 static struct scsi_transport_template *mptfc_transport_template = NULL;
 
-struct fc_function_template mptfc_transport_functions = {
+static struct fc_function_template mptfc_transport_functions = {
        .dd_fcrport_size = 8,
        .show_host_node_name = 1,
        .show_host_port_name = 1,
@@ -348,24 +348,6 @@ mptfc_generate_rport_ids(FCDevicePage0_t *pg0, struct fc_rport_identifiers *rid)
        return 0;
 }
 
-static void
-mptfc_remap_sdev(struct scsi_device *sdev, void *arg)
-{
-       VirtDevice              *vdev;
-       VirtTarget              *vtarget;
-       struct scsi_target      *starget;
-
-       starget = scsi_target(sdev);
-       if (starget->hostdata == arg) {
-               vtarget = arg;
-               vdev = sdev->hostdata;
-               if (vdev) {
-                       vdev->bus_id = vtarget->bus_id;
-                       vdev->target_id = vtarget->target_id;
-               }
-       }
-}
-
 static void
 mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
 {
@@ -423,8 +405,6 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
                                if (vtarget) {
                                        vtarget->target_id = pg0->CurrentTargetID;
                                        vtarget->bus_id = pg0->CurrentBus;
-                                       starget_for_each_device(ri->starget,
-                                               vtarget,mptfc_remap_sdev);
                                }
                                ri->remap_needed = 0;
                        }
@@ -432,7 +412,7 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
                                "mptfc_reg_dev.%d: %x, %llx / %llx, tid %d, "
                                "rport tid %d, tmo %d\n",
                                        ioc->name,
-                                       oc->sh->host_no,
+                                       ioc->sh->host_no,
                                        pg0->PortIdentifier,
                                        pg0->WWNN,
                                        pg0->WWPN,
@@ -514,7 +494,7 @@ mptfc_target_alloc(struct scsi_target *starget)
  *     Return non-zero if allocation fails.
  *     Init memory once per LUN.
  */
-int
+static int
 mptfc_slave_alloc(struct scsi_device *sdev)
 {
        MPT_SCSI_HOST           *hd;
@@ -553,23 +533,26 @@ mptfc_slave_alloc(struct scsi_device *sdev)
        }
 
        vdev->vtarget = vtarget;
-       vdev->ioc_id = hd->ioc->id;
        vdev->lun = sdev->lun;
-       vdev->target_id = vtarget->target_id;
-       vdev->bus_id = vtarget->bus_id;
 
        spin_unlock_irqrestore(&hd->ioc->fc_rport_lock,flags);
 
        vtarget->num_luns++;
 
+#ifdef DMPT_DEBUG_FC
+        {
+       struct mptfc_rport_info *ri;
+       ri = *((struct mptfc_rport_info **)rport->dd_data);
        dfcprintk ((MYIOC_s_INFO_FMT
                "mptfc_slv_alloc.%d: num_luns %d, sdev.id %d, "
                "CurrentTargetID %d, %x %llx %llx\n",
-               ioc->name,
+               hd->ioc->name,
                sdev->host->host_no,
                vtarget->num_luns,
                sdev->id, ri->pg0.CurrentTargetID,
                ri->pg0.PortIdentifier, ri->pg0.WWPN, ri->pg0.WWNN));
+       }
+#endif
 
        return 0;
 }
@@ -941,7 +924,7 @@ mptfc_init(void)
        mptfcInternalCtx = mpt_register(mptscsih_scandv_complete, MPTFC_DRIVER);
 
        if (mpt_event_register(mptfcDoneCtx, mptscsih_event_process) == 0) {
-               devtprintk((KERN_INFO MYNAM
+               devtverboseprintk((KERN_INFO MYNAM
                  ": Registered for IOC event notifications\n"));
        }
 
index 73f59528212ae3aa92590eb6058457999afb3776..314c3a27585d8cc686a01243f930fe7489f6a2ed 100644 (file)
@@ -1152,10 +1152,7 @@ mpt_lan_receive_post_reply(struct net_device *dev,
                                priv->mpt_rxfidx_tail,
                                MPT_LAN_MAX_BUCKETS_OUT);
 
-               panic("Damn it Jim! I'm a doctor, not a programmer! "
-                               "Oh, wait a sec, I am a programmer. "
-                               "And, who's Jim?!?!\n"
-                               "Arrgghh! We've done it again!\n");
+               return -1;
        }
 
        if (remaining == 0)
index 2512d0e6155ede3b55f1996b13fe69b6b78eda0a..010d4a39269b8c55dc39eab53516f4a68636f44c 100644 (file)
@@ -104,6 +104,13 @@ struct mptsas_hotplug_event {
        u16                     handle;
        u16                     parent_handle;
        u8                      phy_id;
+       u8                      phys_disk_num;
+       u8                      phys_disk_num_valid;
+};
+
+struct mptsas_discovery_event {
+       struct work_struct      work;
+       MPT_ADAPTER             *ioc;
 };
 
 /*
@@ -117,6 +124,8 @@ struct mptsas_hotplug_event {
 struct mptsas_devinfo {
        u16     handle;         /* unique id to address this device */
        u16     handle_parent;  /* unique id to address parent device */
+       u16     handle_enclosure; /* enclosure identifier of the enclosure */
+       u16     slot;           /* physical slot in enclosure */
        u8      phy_id;         /* phy number of parent device */
        u8      port_id;        /* sas physical port this device
                                   is assoc'd with */
@@ -137,6 +146,7 @@ struct mptsas_phyinfo {
        struct mptsas_devinfo attached; /* point to attached device info */
        struct sas_phy *phy;
        struct sas_rphy *rphy;
+       struct scsi_target *starget;
 };
 
 struct mptsas_portinfo {
@@ -146,6 +156,17 @@ struct mptsas_portinfo {
        struct mptsas_phyinfo *phy_info;
 };
 
+struct mptsas_enclosure {
+       u64     enclosure_logical_id;   /* The WWN for the enclosure */
+       u16     enclosure_handle;       /* unique id to address this */
+       u16     flags;                  /* details enclosure management */
+       u16     num_slot;               /* num slots */
+       u16     start_slot;             /* first slot */
+       u8      start_id;               /* starting logical target id */
+       u8      start_channel;          /* starting logical channel id */
+       u8      sep_id;                 /* SEP device logical target id */
+       u8      sep_channel;            /* SEP channel logical channel id */
+};
 
 #ifdef SASDEBUG
 static void mptsas_print_phy_data(MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
@@ -205,6 +226,7 @@ static void mptsas_print_device_pg0(SasDevicePage0_t *pg0)
 
        printk("---- SAS DEVICE PAGE 0 ---------\n");
        printk("Handle=0x%X\n" ,le16_to_cpu(pg0->DevHandle));
+       printk("Parent Handle=0x%X\n" ,le16_to_cpu(pg0->ParentDevHandle));
        printk("Enclosure Handle=0x%X\n", le16_to_cpu(pg0->EnclosureHandle));
        printk("Slot=0x%X\n", le16_to_cpu(pg0->Slot));
        printk("SAS Address=0x%llX\n", le64_to_cpu(sas_address));
@@ -243,6 +265,111 @@ static void mptsas_print_expander_pg1(SasExpanderPage1_t *pg1)
 #define mptsas_print_expander_pg1(pg1)         do { } while (0)
 #endif
 
+static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
+{
+       struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
+       return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
+}
+
+static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy)
+{
+       struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
+       return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
+}
+
+/*
+ * mptsas_find_portinfo_by_handle
+ *
+ * This function should be called with the sas_topology_mutex already held
+ */
+static struct mptsas_portinfo *
+mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
+{
+       struct mptsas_portinfo *port_info, *rc=NULL;
+       int i;
+
+       list_for_each_entry(port_info, &ioc->sas_topology, list)
+               for (i = 0; i < port_info->num_phys; i++)
+                       if (port_info->phy_info[i].identify.handle == handle) {
+                               rc = port_info;
+                               goto out;
+                       }
+ out:
+       return rc;
+}
+
+static int
+mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
+               u32 form, u32 form_specific)
+{
+       ConfigExtendedPageHeader_t hdr;
+       CONFIGPARMS cfg;
+       SasEnclosurePage0_t *buffer;
+       dma_addr_t dma_handle;
+       int error;
+       __le64 le_identifier;
+
+       memset(&hdr, 0, sizeof(hdr));
+       hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION;
+       hdr.PageNumber = 0;
+       hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
+       hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE;
+
+       cfg.cfghdr.ehdr = &hdr;
+       cfg.physAddr = -1;
+       cfg.pageAddr = form + form_specific;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.dir = 0;    /* read */
+       cfg.timeout = 10;
+
+       error = mpt_config(ioc, &cfg);
+       if (error)
+               goto out;
+       if (!hdr.ExtPageLength) {
+               error = -ENXIO;
+               goto out;
+       }
+
+       buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
+                       &dma_handle);
+       if (!buffer) {
+               error = -ENOMEM;
+               goto out;
+       }
+
+       cfg.physAddr = dma_handle;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+       error = mpt_config(ioc, &cfg);
+       if (error)
+               goto out_free_consistent;
+
+       /* save config data */
+       memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64));
+       enclosure->enclosure_logical_id = le64_to_cpu(le_identifier);
+       enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle);
+       enclosure->flags = le16_to_cpu(buffer->Flags);
+       enclosure->num_slot = le16_to_cpu(buffer->NumSlots);
+       enclosure->start_slot = le16_to_cpu(buffer->StartSlot);
+       enclosure->start_id = buffer->StartTargetID;
+       enclosure->start_channel = buffer->StartBus;
+       enclosure->sep_id = buffer->SEPTargetID;
+       enclosure->sep_channel = buffer->SEPBus;
+
+ out_free_consistent:
+       pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
+                           buffer, dma_handle);
+ out:
+       return error;
+}
+
+static int
+mptsas_slave_configure(struct scsi_device *sdev)
+{
+       sas_read_port_mode_page(sdev);
+
+       return mptscsih_slave_configure(sdev);
+}
 
 /*
  * This is pretty ugly.  We will be able to seriously clean it up
@@ -259,6 +386,7 @@ mptsas_slave_alloc(struct scsi_device *sdev)
        VirtTarget              *vtarget;
        VirtDevice              *vdev;
        struct scsi_target      *starget;
+       u32                     target_id;
        int i;
 
        vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
@@ -267,10 +395,10 @@ mptsas_slave_alloc(struct scsi_device *sdev)
                                hd->ioc->name, sizeof(VirtDevice));
                return -ENOMEM;
        }
-       vdev->ioc_id = hd->ioc->id;
        sdev->hostdata = vdev;
        starget = scsi_target(sdev);
        vtarget = starget->hostdata;
+       vtarget->ioc_id = hd->ioc->id;
        vdev->vtarget = vtarget;
        if (vtarget->num_luns == 0) {
                vtarget->tflags = MPT_TARGET_FLAGS_Q_YES|MPT_TARGET_FLAGS_VALID_INQUIRY;
@@ -281,8 +409,8 @@ mptsas_slave_alloc(struct scsi_device *sdev)
          RAID volumes placed beyond the last expected port.
        */
        if (sdev->channel == hd->ioc->num_ports) {
-               vdev->target_id = sdev->id;
-               vdev->bus_id = 0;
+               target_id = sdev->id;
+               vtarget->bus_id = 0;
                vdev->lun = 0;
                goto out;
        }
@@ -293,11 +421,21 @@ mptsas_slave_alloc(struct scsi_device *sdev)
                for (i = 0; i < p->num_phys; i++) {
                        if (p->phy_info[i].attached.sas_address ==
                                        rphy->identify.sas_address) {
-                               vdev->target_id =
-                                       p->phy_info[i].attached.id;
-                               vdev->bus_id = p->phy_info[i].attached.channel;
+                               target_id = p->phy_info[i].attached.id;
+                               vtarget->bus_id = p->phy_info[i].attached.channel;
                                vdev->lun = sdev->lun;
-       mutex_unlock(&hd->ioc->sas_topology_mutex);
+                               p->phy_info[i].starget = sdev->sdev_target;
+                               /*
+                                * Exposing hidden disk (RAID)
+                                */
+                               if (mptscsih_is_phys_disk(hd->ioc, target_id)) {
+                                       target_id = mptscsih_raid_id_to_num(hd,
+                                                       target_id);
+                                       vdev->vtarget->tflags |=
+                                           MPT_TARGET_FLAGS_RAID_COMPONENT;
+                                       sdev->no_uld_attach = 1;
+                               }
+                               mutex_unlock(&hd->ioc->sas_topology_mutex);
                                goto out;
                        }
                }
@@ -308,9 +446,7 @@ mptsas_slave_alloc(struct scsi_device *sdev)
        return -ENXIO;
 
  out:
-       vtarget->ioc_id = vdev->ioc_id;
-       vtarget->target_id = vdev->target_id;
-       vtarget->bus_id = vdev->bus_id;
+       vtarget->target_id = target_id;
        vtarget->num_luns++;
        return 0;
 }
@@ -320,32 +456,8 @@ mptsas_slave_destroy(struct scsi_device *sdev)
 {
        struct Scsi_Host *host = sdev->host;
        MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
-       struct sas_rphy *rphy;
-       struct mptsas_portinfo *p;
-       int i;
        VirtDevice *vdev;
 
-       /*
-        * Handle hotplug removal case.
-        * We need to clear out attached data structure.
-        */
-       rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
-
-       mutex_lock(&hd->ioc->sas_topology_mutex);
-       list_for_each_entry(p, &hd->ioc->sas_topology, list) {
-               for (i = 0; i < p->num_phys; i++) {
-                       if (p->phy_info[i].attached.sas_address ==
-                                       rphy->identify.sas_address) {
-                               memset(&p->phy_info[i].attached, 0,
-                                   sizeof(struct mptsas_devinfo));
-                               p->phy_info[i].rphy = NULL;
-                               goto out;
-                       }
-               }
-       }
-
- out:
-       mutex_unlock(&hd->ioc->sas_topology_mutex);
        /*
         * Issue target reset to flush firmware outstanding commands.
         */
@@ -353,8 +465,8 @@ mptsas_slave_destroy(struct scsi_device *sdev)
        if (vdev->configured_lun){
                if (mptscsih_TMHandler(hd,
                     MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
-                    vdev->bus_id,
-                    vdev->target_id,
+                    vdev->vtarget->bus_id,
+                    vdev->vtarget->target_id,
                     0, 0, 5 /* 5 second timeout */)
                     < 0){
 
@@ -364,7 +476,7 @@ mptsas_slave_destroy(struct scsi_device *sdev)
                        printk(MYIOC_s_WARN_FMT
                       "Error processing TaskMgmt id=%d TARGET_RESET\n",
                                hd->ioc->name,
-                               vdev->target_id);
+                               vdev->vtarget->target_id);
 
                        hd->tmPending = 0;
                        hd->tmState = TM_STATE_NONE;
@@ -382,7 +494,7 @@ static struct scsi_host_template mptsas_driver_template = {
        .queuecommand                   = mptscsih_qcmd,
        .target_alloc                   = mptscsih_target_alloc,
        .slave_alloc                    = mptsas_slave_alloc,
-       .slave_configure                = mptscsih_slave_configure,
+       .slave_configure                = mptsas_slave_configure,
        .target_destroy                 = mptscsih_target_destroy,
        .slave_destroy                  = mptsas_slave_destroy,
        .change_queue_depth             = mptscsih_change_queue_depth,
@@ -399,12 +511,6 @@ static struct scsi_host_template mptsas_driver_template = {
        .use_clustering                 = ENABLE_CLUSTERING,
 };
 
-static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
-{
-       struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
-       return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
-}
-
 static int mptsas_get_linkerrors(struct sas_phy *phy)
 {
        MPT_ADAPTER *ioc = phy_to_ioc(phy);
@@ -546,8 +652,67 @@ static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
        return error;
 }
 
+static int
+mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
+{
+       MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
+       int i, error;
+       struct mptsas_portinfo *p;
+       struct mptsas_enclosure enclosure_info;
+       u64 enclosure_handle;
+
+       mutex_lock(&ioc->sas_topology_mutex);
+       list_for_each_entry(p, &ioc->sas_topology, list) {
+               for (i = 0; i < p->num_phys; i++) {
+                       if (p->phy_info[i].attached.sas_address ==
+                           rphy->identify.sas_address) {
+                               enclosure_handle = p->phy_info[i].
+                                       attached.handle_enclosure;
+                               goto found_info;
+                       }
+               }
+       }
+       mutex_unlock(&ioc->sas_topology_mutex);
+       return -ENXIO;
+
+ found_info:
+       mutex_unlock(&ioc->sas_topology_mutex);
+       memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
+       error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
+                       (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
+                        MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
+       if (!error)
+               *identifier = enclosure_info.enclosure_logical_id;
+       return error;
+}
+
+static int
+mptsas_get_bay_identifier(struct sas_rphy *rphy)
+{
+       MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
+       struct mptsas_portinfo *p;
+       int i, rc;
+
+       mutex_lock(&ioc->sas_topology_mutex);
+       list_for_each_entry(p, &ioc->sas_topology, list) {
+               for (i = 0; i < p->num_phys; i++) {
+                       if (p->phy_info[i].attached.sas_address ==
+                           rphy->identify.sas_address) {
+                               rc = p->phy_info[i].attached.slot;
+                               goto out;
+                       }
+               }
+       }
+       rc = -ENXIO;
+ out:
+       mutex_unlock(&ioc->sas_topology_mutex);
+       return rc;
+}
+
 static struct sas_function_template mptsas_transport_functions = {
        .get_linkerrors         = mptsas_get_linkerrors,
+       .get_enclosure_identifier = mptsas_get_enclosure_identifier,
+       .get_bay_identifier     = mptsas_get_bay_identifier,
        .phy_reset              = mptsas_phy_reset,
 };
 
@@ -607,6 +772,9 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
                goto out_free_consistent;
        }
 
+       if (port_info->num_phys)
+               port_info->handle =
+                   le16_to_cpu(buffer->PhyData[0].ControllerDevHandle);
        for (i = 0; i < port_info->num_phys; i++) {
                mptsas_print_phy_data(&buffer->PhyData[i]);
                port_info->phy_info[i].phy_id = i;
@@ -713,6 +881,7 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
        cfg.dir = 0;    /* read */
        cfg.timeout = 10;
 
+       memset(device_info, 0, sizeof(struct mptsas_devinfo));
        error = mpt_config(ioc, &cfg);
        if (error)
                goto out;
@@ -739,6 +908,9 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
 
        device_info->handle = le16_to_cpu(buffer->DevHandle);
        device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
+       device_info->handle_enclosure =
+           le16_to_cpu(buffer->EnclosureHandle);
+       device_info->slot = le16_to_cpu(buffer->Slot);
        device_info->phy_id = buffer->PhyNum;
        device_info->port_id = buffer->PhysicalPort;
        device_info->id = buffer->TargetID;
@@ -780,6 +952,7 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
        cfg.dir = 0;    /* read */
        cfg.timeout = 10;
 
+       memset(port_info, 0, sizeof(struct mptsas_portinfo));
        error = mpt_config(ioc, &cfg);
        if (error)
                goto out;
@@ -880,7 +1053,6 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
        phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
        phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
 
-
  out_free_consistent:
        pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
                            buffer, dma_handle);
@@ -970,12 +1142,19 @@ mptsas_parse_device_info(struct sas_identify *identify,
 static int mptsas_probe_one_phy(struct device *dev,
                struct mptsas_phyinfo *phy_info, int index, int local)
 {
+       MPT_ADAPTER *ioc;
        struct sas_phy *phy;
        int error;
 
-       phy = sas_phy_alloc(dev, index);
-       if (!phy)
-               return -ENOMEM;
+       if (!dev)
+               return -ENODEV;
+
+       if (!phy_info->phy) {
+               phy = sas_phy_alloc(dev, index);
+               if (!phy)
+                       return -ENOMEM;
+       } else
+               phy = phy_info->phy;
 
        phy->port_identifier = phy_info->port_id;
        mptsas_parse_device_info(&phy->identify, &phy_info->identify);
@@ -1061,24 +1240,54 @@ static int mptsas_probe_one_phy(struct device *dev,
                break;
        }
 
-       if (local)
-               phy->local_attached = 1;
+       if (!phy_info->phy) {
 
-       error = sas_phy_add(phy);
-       if (error) {
-               sas_phy_free(phy);
-               return error;
+               if (local)
+                       phy->local_attached = 1;
+
+               error = sas_phy_add(phy);
+               if (error) {
+                       sas_phy_free(phy);
+                       return error;
+               }
+               phy_info->phy = phy;
        }
-       phy_info->phy = phy;
 
-       if (phy_info->attached.handle) {
+       if ((phy_info->attached.handle) &&
+           (!phy_info->rphy)) {
+
                struct sas_rphy *rphy;
+               struct sas_identify identify;
+
+               ioc = phy_to_ioc(phy_info->phy);
 
-               rphy = sas_rphy_alloc(phy);
+               /*
+                * Let the hotplug_work thread handle processing
+                * the adding/removing of devices that occur
+                * after start of day.
+                */
+               if (ioc->sas_discovery_runtime &&
+                       mptsas_is_end_device(&phy_info->attached))
+                       return 0;
+
+               mptsas_parse_device_info(&identify, &phy_info->attached);
+               switch (identify.device_type) {
+               case SAS_END_DEVICE:
+                       rphy = sas_end_device_alloc(phy);
+                       break;
+               case SAS_EDGE_EXPANDER_DEVICE:
+               case SAS_FANOUT_EXPANDER_DEVICE:
+                       rphy = sas_expander_alloc(phy, identify.device_type);
+                       break;
+               default:
+                       rphy = NULL;
+                       break;
+               }
                if (!rphy)
                        return 0; /* non-fatal: an rphy can be added later */
 
-               mptsas_parse_device_info(&rphy->identify, &phy_info->attached);
+               rphy->identify = identify;
+
                error = sas_rphy_add(rphy);
                if (error) {
                        sas_rphy_free(rphy);
@@ -1092,24 +1301,37 @@ static int mptsas_probe_one_phy(struct device *dev,
 }
 
 static int
-mptsas_probe_hba_phys(MPT_ADAPTER *ioc, int *index)
+mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
 {
-       struct mptsas_portinfo *port_info;
+       struct mptsas_portinfo *port_info, *hba;
        u32 handle = 0xFFFF;
        int error = -ENOMEM, i;
 
-       port_info = kzalloc(sizeof(*port_info), GFP_KERNEL);
-       if (!port_info)
+       hba = kzalloc(sizeof(*port_info), GFP_KERNEL);
+       if (! hba)
                goto out;
 
-       error = mptsas_sas_io_unit_pg0(ioc, port_info);
+       error = mptsas_sas_io_unit_pg0(ioc, hba);
        if (error)
                goto out_free_port_info;
 
-       ioc->num_ports = port_info->num_phys;
        mutex_lock(&ioc->sas_topology_mutex);
-       list_add_tail(&port_info->list, &ioc->sas_topology);
+       port_info = mptsas_find_portinfo_by_handle(ioc, hba->handle);
+       if (!port_info) {
+               port_info = hba;
+               list_add_tail(&port_info->list, &ioc->sas_topology);
+       } else {
+               port_info->handle = hba->handle;
+               for (i = 0; i < hba->num_phys; i++)
+                       port_info->phy_info[i].negotiated_link_rate =
+                               hba->phy_info[i].negotiated_link_rate;
+               if (hba->phy_info)
+                       kfree(hba->phy_info);
+               kfree(hba);
+               hba = NULL;
+       }
        mutex_unlock(&ioc->sas_topology_mutex);
+       ioc->num_ports = port_info->num_phys;
 
        for (i = 0; i < port_info->num_phys; i++) {
                mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
@@ -1132,38 +1354,49 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc, int *index)
                }
 
                mptsas_probe_one_phy(&ioc->sh->shost_gendev,
-                                    &port_info->phy_info[i], *index, 1);
-               (*index)++;
+                   &port_info->phy_info[i], ioc->sas_index, 1);
+               ioc->sas_index++;
        }
 
        return 0;
 
  out_free_port_info:
-       kfree(port_info);
+       if (hba)
+               kfree(hba);
  out:
        return error;
 }
 
 static int
-mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle, int *index)
+mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)
 {
-       struct mptsas_portinfo *port_info, *p;
+       struct mptsas_portinfo *port_info, *p, *ex;
        int error = -ENOMEM, i, j;
 
-       port_info = kzalloc(sizeof(*port_info), GFP_KERNEL);
-       if (!port_info)
+       ex = kzalloc(sizeof(*port_info), GFP_KERNEL);
+       if (!ex)
                goto out;
 
-       error = mptsas_sas_expander_pg0(ioc, port_info,
+       error = mptsas_sas_expander_pg0(ioc, ex,
                (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
                 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle);
        if (error)
                goto out_free_port_info;
 
-       *handle = port_info->handle;
+       *handle = ex->handle;
 
        mutex_lock(&ioc->sas_topology_mutex);
-       list_add_tail(&port_info->list, &ioc->sas_topology);
+       port_info = mptsas_find_portinfo_by_handle(ioc, *handle);
+       if (!port_info) {
+               port_info = ex;
+               list_add_tail(&port_info->list, &ioc->sas_topology);
+       } else {
+               port_info->handle = ex->handle;
+               if (ex->phy_info)
+                       kfree(ex->phy_info);
+               kfree(ex);
+               ex = NULL;
+       }
        mutex_unlock(&ioc->sas_topology_mutex);
 
        for (i = 0; i < port_info->num_phys; i++) {
@@ -1189,6 +1422,8 @@ mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle, int *index)
                                (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
                                 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
                                port_info->phy_info[i].attached.handle);
+                       port_info->phy_info[i].attached.phy_id =
+                           port_info->phy_info[i].phy_id;
                }
 
                /*
@@ -1208,27 +1443,137 @@ mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle, int *index)
                mutex_unlock(&ioc->sas_topology_mutex);
 
                mptsas_probe_one_phy(parent, &port_info->phy_info[i],
-                                    *index, 0);
-               (*index)++;
+                   ioc->sas_index, 0);
+               ioc->sas_index++;
        }
 
        return 0;
 
  out_free_port_info:
-       kfree(port_info);
+       if (ex) {
+               if (ex->phy_info)
+                       kfree(ex->phy_info);
+               kfree(ex);
+       }
  out:
        return error;
 }
 
+/*
+ * mptsas_delete_expander_phys
+ *
+ *
+ * This will traverse topology, and remove expanders
+ * that are no longer present
+ */
+static void
+mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
+{
+       struct mptsas_portinfo buffer;
+       struct mptsas_portinfo *port_info, *n, *parent;
+       int i;
+
+       mutex_lock(&ioc->sas_topology_mutex);
+       list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) {
+
+               if (port_info->phy_info &&
+                   (!(port_info->phy_info[0].identify.device_info &
+                   MPI_SAS_DEVICE_INFO_SMP_TARGET)))
+                       continue;
+
+               if (mptsas_sas_expander_pg0(ioc, &buffer,
+                    (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
+                    MPI_SAS_EXPAND_PGAD_FORM_SHIFT), port_info->handle)) {
+
+                       /*
+                        * Obtain the port_info instance to the parent port
+                        */
+                       parent = mptsas_find_portinfo_by_handle(ioc,
+                           port_info->phy_info[0].identify.handle_parent);
+
+                       if (!parent)
+                               goto next_port;
+
+                       /*
+                        * Delete rphys in the parent that point
+                        * to this expander.  The transport layer will
+                        * cleanup all the children.
+                        */
+                       for (i = 0; i < parent->num_phys; i++) {
+                               if ((!parent->phy_info[i].rphy) ||
+                                   (parent->phy_info[i].attached.sas_address !=
+                                  port_info->phy_info[i].identify.sas_address))
+                                       continue;
+                               sas_rphy_delete(parent->phy_info[i].rphy);
+                               memset(&parent->phy_info[i].attached, 0,
+                                   sizeof(struct mptsas_devinfo));
+                               parent->phy_info[i].rphy = NULL;
+                               parent->phy_info[i].starget = NULL;
+                       }
+ next_port:
+                       list_del(&port_info->list);
+                       if (port_info->phy_info)
+                               kfree(port_info->phy_info);
+                       kfree(port_info);
+               }
+               /*
+               * Free this memory allocated from inside
+               * mptsas_sas_expander_pg0
+               */
+               if (buffer.phy_info)
+                       kfree(buffer.phy_info);
+       }
+       mutex_unlock(&ioc->sas_topology_mutex);
+}
+
+/*
+ * Start of day discovery
+ */
 static void
 mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
 {
        u32 handle = 0xFFFF;
-       int index = 0;
+       int i;
+
+       mutex_lock(&ioc->sas_discovery_mutex);
+       mptsas_probe_hba_phys(ioc);
+       while (!mptsas_probe_expander_phys(ioc, &handle))
+               ;
+       /*
+         Reporting RAID volumes.
+       */
+       if (!ioc->raid_data.pIocPg2)
+               goto out;
+       if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
+               goto out;
+       for (i=0; i<ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
+               scsi_add_device(ioc->sh, ioc->num_ports,
+                   ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
+       }
+ out:
+       mutex_unlock(&ioc->sas_discovery_mutex);
+}
+
+/*
+ * Work queue thread to handle Runtime discovery
+ * Mere purpose is the hot add/delete of expanders
+ */
+static void
+mptscsih_discovery_work(void * arg)
+{
+       struct mptsas_discovery_event *ev = arg;
+       MPT_ADAPTER *ioc = ev->ioc;
+       u32 handle = 0xFFFF;
 
-       mptsas_probe_hba_phys(ioc, &index);
-       while (!mptsas_probe_expander_phys(ioc, &handle, &index))
+       mutex_lock(&ioc->sas_discovery_mutex);
+       ioc->sas_discovery_runtime=1;
+       mptsas_delete_expander_phys(ioc);
+       mptsas_probe_hba_phys(ioc);
+       while (!mptsas_probe_expander_phys(ioc, &handle))
                ;
+       kfree(ev);
+       ioc->sas_discovery_runtime=0;
+       mutex_unlock(&ioc->sas_discovery_mutex);
 }
 
 static struct mptsas_phyinfo *
@@ -1246,10 +1591,8 @@ mptsas_find_phyinfo_by_parent(MPT_ADAPTER *ioc, u16 parent_handle, u8 phy_id)
                (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
                 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
                parent_handle);
-       if (error) {
-               printk("mptsas: failed to retrieve device page\n");
+       if (error)
                return NULL;
-       }
 
        /*
         * The phy_info structures are never deallocated during lifetime of
@@ -1296,6 +1639,35 @@ mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u32 id)
        return phy_info;
 }
 
+/*
+ * Work queue thread to clear the persitency table
+ */
+static void
+mptscsih_sas_persist_clear_table(void * arg)
+{
+       MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg;
+
+       mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT);
+}
+
+static void
+mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
+{
+       sdev->no_uld_attach = data ? 1 : 0;
+       scsi_device_reprobe(sdev);
+}
+
+static void
+mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
+{
+       starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
+                       mptsas_reprobe_lun);
+}
+
+
+/*
+ * Work queue thread to handle SAS hotplug events
+ */
 static void
 mptsas_hotplug_work(void *arg)
 {
@@ -1304,16 +1676,39 @@ mptsas_hotplug_work(void *arg)
        struct mptsas_phyinfo *phy_info;
        struct sas_rphy *rphy;
        struct scsi_device *sdev;
+       struct sas_identify identify;
        char *ds = NULL;
        struct mptsas_devinfo sas_device;
+       VirtTarget *vtarget;
+
+       mutex_lock(&ioc->sas_discovery_mutex);
 
        switch (ev->event_type) {
        case MPTSAS_DEL_DEVICE:
 
                phy_info = mptsas_find_phyinfo_by_target(ioc, ev->id);
-               if (!phy_info) {
-                       printk("mptsas: remove event for non-existant PHY.\n");
+
+               /*
+                * Sanity checks, for non-existing phys and remote rphys.
+                */
+               if (!phy_info)
                        break;
+               if (!phy_info->rphy)
+           &