--- /dev/null
+From stable-bounces@linux.kernel.org Mon Feb 4 05:57:09 2008
+From: Ian Abbott <abbotti@mev.co.uk>
+Date: Mon, 04 Feb 2008 13:56:36 +0000
+Subject: PCI: Fix fakephp deadlock
+To: stable@kernel.org
+Cc: linux-pci@atrey.karlin.mff.cuni.cz, linux-kernel@vger.kernel.org
+Message-ID: <47A71994.3050409@mev.co.uk>
+
+From: Ian Abbott <abbotti@mev.co.uk>
+
+This patch works around a problem in the fakephp driver when a process
+writing "0" to a "power" sysfs file to fake removal of a PCI device ends
+up deadlocking itself in the sysfs code.
+
+The patch is functionally identical to the one in Linus' tree post 2.6.24:
+http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=5c796ae7a7ebe56967ed9b9963d7c16d733635ff
+
+I have tested it on a 2.6.22 kernel.
+
+Signed-off-by: Ian Abbott <abbotti@mev.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/pci/hotplug/fakephp.c | 39 +++++++++++++++++++++++++++++++++++----
+ 1 file changed, 35 insertions(+), 4 deletions(-)
+
+--- a/drivers/pci/hotplug/fakephp.c
++++ b/drivers/pci/hotplug/fakephp.c
+@@ -39,6 +39,7 @@
+ #include <linux/init.h>
+ #include <linux/string.h>
+ #include <linux/slab.h>
++#include <linux/workqueue.h>
+ #include "../pci.h"
+
+ #if !defined(MODULE)
+@@ -63,10 +64,16 @@ struct dummy_slot {
+ struct list_head node;
+ struct hotplug_slot *slot;
+ struct pci_dev *dev;
++ struct work_struct remove_work;
++ unsigned long removed;
+ };
+
+ static int debug;
+ static LIST_HEAD(slot_list);
++static struct workqueue_struct *dummyphp_wq;
++
++static void pci_rescan_worker(struct work_struct *work);
++static DECLARE_WORK(pci_rescan_work, pci_rescan_worker);
+
+ static int enable_slot (struct hotplug_slot *slot);
+ static int disable_slot (struct hotplug_slot *slot);
+@@ -109,7 +116,7 @@ static int add_slot(struct pci_dev *dev)
+ slot->name = &dev->dev.bus_id[0];
+ dbg("slot->name = %s\n", slot->name);
+
+- dslot = kmalloc(sizeof(struct dummy_slot), GFP_KERNEL);
++ dslot = kzalloc(sizeof(struct dummy_slot), GFP_KERNEL);
+ if (!dslot)
+ goto error_info;
+
+@@ -164,6 +171,14 @@ static void remove_slot(struct dummy_slo
+ err("Problem unregistering a slot %s\n", dslot->slot->name);
+ }
+
++/* called from the single-threaded workqueue handler to remove a slot */
++static void remove_slot_worker(struct work_struct *work)
++{
++ struct dummy_slot *dslot =
++ container_of(work, struct dummy_slot, remove_work);
++ remove_slot(dslot);
++}
++
+ /**
+ * Rescan slot.
+ * Tries hard not to re-enable already existing devices
+@@ -267,11 +282,17 @@ static inline void pci_rescan(void) {
+ pci_rescan_buses(&pci_root_buses);
+ }
+
++/* called from the single-threaded workqueue handler to rescan all pci buses */
++static void pci_rescan_worker(struct work_struct *work)
++{
++ pci_rescan();
++}
+
+ static int enable_slot(struct hotplug_slot *hotplug_slot)
+ {
+ /* mis-use enable_slot for rescanning of the pci bus */
+- pci_rescan();
++ cancel_work_sync(&pci_rescan_work);
++ queue_work(dummyphp_wq, &pci_rescan_work);
+ return -ENODEV;
+ }
+
+@@ -306,6 +327,10 @@ static int disable_slot(struct hotplug_s
+ err("Can't remove PCI devices with other PCI devices behind it yet.\n");
+ return -ENODEV;
+ }
++ if (test_and_set_bit(0, &dslot->removed)) {
++ dbg("Slot already scheduled for removal\n");
++ return -ENODEV;
++ }
+ /* search for subfunctions and disable them first */
+ if (!(dslot->dev->devfn & 7)) {
+ for (func = 1; func < 8; func++) {
+@@ -328,8 +353,9 @@ static int disable_slot(struct hotplug_s
+ /* remove the device from the pci core */
+ pci_remove_bus_device(dslot->dev);
+
+- /* blow away this sysfs entry and other parts. */
+- remove_slot(dslot);
++ /* queue work item to blow away this sysfs entry and other parts. */
++ INIT_WORK(&dslot->remove_work, remove_slot_worker);
++ queue_work(dummyphp_wq, &dslot->remove_work);
+
+ return 0;
+ }
+@@ -340,6 +366,7 @@ static void cleanup_slots (void)
+ struct list_head *next;
+ struct dummy_slot *dslot;
+
++ destroy_workqueue(dummyphp_wq);
+ list_for_each_safe (tmp, next, &slot_list) {
+ dslot = list_entry (tmp, struct dummy_slot, node);
+ remove_slot(dslot);
+@@ -351,6 +378,10 @@ static int __init dummyphp_init(void)
+ {
+ info(DRIVER_DESC "\n");
+
++ dummyphp_wq = create_singlethread_workqueue(MY_NAME);
++ if (!dummyphp_wq)
++ return -ENOMEM;
++
+ return pci_scan_buses();
+ }
+
--- /dev/null
+From stable-bounces@linux.kernel.org Tue Feb 5 13:06:37 2008
+From: Christoph Lameter <clameter@sgi.com>
+Date: Sat, 22 Dec 2007 14:03:23 -0800
+Subject: quicklists: do not release off node pages early
+To: torvalds@linux-foundation.org
+Cc: stable@kernel.org, akpm@linux-foundation.org,
+dhaval@linux.vnet.ibm.com, clameter@sgi.com
+Message-ID: <200712222203.lBMM3Nsk021922@imap1.linux-foundation.org>
+
+
+From: Christoph Lameter <clameter@sgi.com>
+
+patch ed367fc3a7349b17354c7acef551533337764859 in mainline.
+
+quicklists must keep even off node pages on the quicklists until the TLB
+flush has been completed.
+
+Signed-off-by: Christoph Lameter <clameter@sgi.com>
+Cc: Dhaval Giani <dhaval@linux.vnet.ibm.com>
+Cc: Oliver Pinter <oliver.pntr@gmail.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+
+---
+ include/linux/quicklist.h | 8 --------
+ 1 file changed, 8 deletions(-)
+
+--- a/include/linux/quicklist.h
++++ b/include/linux/quicklist.h
+@@ -56,14 +56,6 @@ static inline void __quicklist_free(int
+ struct page *page)
+ {
+ struct quicklist *q;
+- int nid = page_to_nid(page);
+-
+- if (unlikely(nid != numa_node_id())) {
+- if (dtor)
+- dtor(p);
+- __free_page(page);
+- return;
+- }
+
+ q = &get_cpu_var(quicklist)[nr];
+ *(void **)p = q->page;
--- /dev/null
+From stable-bounces@linux.kernel.org Wed Jan 16 01:32:59 2008
+From: Mikael Pettersson <mikpe@it.uu.se>
+Date: Wed, 16 Jan 2008 10:32:17 +0100 (MET)
+Subject: sata_promise: ASIC PRD table bug workaround
+To: stable@kernel.org
+Cc: Jeff Garzik <jeff@garzik.org>
+Message-ID: <200801160932.m0G9WHjG029881@harpo.it.uu.se>
+
+From: Mikael Pettersson <mikpe@it.uu.se>
+
+patch b9ccd4a90bbb964506f01b4bdcff4f50f8d5d334 in mainline.
+
+Second-generation Promise SATA controllers have an ASIC bug
+which can trigger if the last PRD entry is larger than 164 bytes,
+resulting in intermittent errors and possible data corruption.
+
+Work around this by replacing calls to ata_qc_prep() with a
+private version that fills the PRD, checks the size of the
+last entry, and if necessary splits it to avoid the bug.
+Also reduce sg_tablesize by 1 to accommodate the new entry.
+
+Tested on the second-generation SATA300 TX4 and SATA300 TX2plus,
+and the first-generation PDC20378.
+
+Thanks to Alexander Sabourenkov for verifying the bug by
+studying the vendor driver, and for writing the initial patch
+upon which this one is based.
+
+Signed-off-by: Mikael Pettersson <mikpe@it.uu.se>
+Cc: Jeff Garzik <jeff@garzik.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/ata/sata_promise.c | 87 ++++++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 83 insertions(+), 4 deletions(-)
+
+--- a/drivers/ata/sata_promise.c
++++ b/drivers/ata/sata_promise.c
+@@ -51,6 +51,7 @@
+ enum {
+ PDC_MAX_PORTS = 4,
+ PDC_MMIO_BAR = 3,
++ PDC_MAX_PRD = LIBATA_MAX_PRD - 1, /* -1 for ASIC PRD bug workaround */
+
+ /* register offsets */
+ PDC_FEATURE = 0x04, /* Feature/Error reg (per port) */
+@@ -157,7 +158,7 @@ static struct scsi_host_template pdc_ata
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+- .sg_tablesize = LIBATA_MAX_PRD,
++ .sg_tablesize = PDC_MAX_PRD,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+@@ -531,6 +532,84 @@ static void pdc_atapi_pkt(struct ata_que
+ memcpy(buf+31, cdb, cdb_len);
+ }
+
++/**
++ * pdc_fill_sg - Fill PCI IDE PRD table
++ * @qc: Metadata associated with taskfile to be transferred
++ *
++ * Fill PCI IDE PRD (scatter-gather) table with segments
++ * associated with the current disk command.
++ * Make sure hardware does not choke on it.
++ *
++ * LOCKING:
++ * spin_lock_irqsave(host lock)
++ *
++ */
++static void pdc_fill_sg(struct ata_queued_cmd *qc)
++{
++ struct ata_port *ap = qc->ap;
++ struct scatterlist *sg;
++ unsigned int idx;
++ const u32 SG_COUNT_ASIC_BUG = 41*4;
++
++ if (!(qc->flags & ATA_QCFLAG_DMAMAP))
++ return;
++
++ WARN_ON(qc->__sg == NULL);
++ WARN_ON(qc->n_elem == 0 && qc->pad_len == 0);
++
++ idx = 0;
++ ata_for_each_sg(sg, qc) {
++ u32 addr, offset;
++ u32 sg_len, len;
++
++ /* determine if physical DMA addr spans 64K boundary.
++ * Note h/w doesn't support 64-bit, so we unconditionally
++ * truncate dma_addr_t to u32.
++ */
++ addr = (u32) sg_dma_address(sg);
++ sg_len = sg_dma_len(sg);
++
++ while (sg_len) {
++ offset = addr & 0xffff;
++ len = sg_len;
++ if ((offset + sg_len) > 0x10000)
++ len = 0x10000 - offset;
++
++ ap->prd[idx].addr = cpu_to_le32(addr);
++ ap->prd[idx].flags_len = cpu_to_le32(len & 0xffff);
++ VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len);
++
++ idx++;
++ sg_len -= len;
++ addr += len;
++ }
++ }
++
++ if (idx) {
++ u32 len = le32_to_cpu(ap->prd[idx - 1].flags_len);
++
++ if (len > SG_COUNT_ASIC_BUG) {
++ u32 addr;
++
++ VPRINTK("Splitting last PRD.\n");
++
++ addr = le32_to_cpu(ap->prd[idx - 1].addr);
++ ap->prd[idx - 1].flags_len = cpu_to_le32(len - SG_COUNT_ASIC_BUG);
++ VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx - 1, addr, SG_COUNT_ASIC_BUG);
++
++ addr = addr + len - SG_COUNT_ASIC_BUG;
++ len = SG_COUNT_ASIC_BUG;
++ ap->prd[idx].addr = cpu_to_le32(addr);
++ ap->prd[idx].flags_len = cpu_to_le32(len);
++ VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len);
++
++ idx++;
++ }
++
++ ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
++ }
++}
++
+ static void pdc_qc_prep(struct ata_queued_cmd *qc)
+ {
+ struct pdc_port_priv *pp = qc->ap->private_data;
+@@ -540,7 +619,7 @@ static void pdc_qc_prep(struct ata_queue
+
+ switch (qc->tf.protocol) {
+ case ATA_PROT_DMA:
+- ata_qc_prep(qc);
++ pdc_fill_sg(qc);
+ /* fall through */
+
+ case ATA_PROT_NODATA:
+@@ -556,11 +635,11 @@ static void pdc_qc_prep(struct ata_queue
+ break;
+
+ case ATA_PROT_ATAPI:
+- ata_qc_prep(qc);
++ pdc_fill_sg(qc);
+ break;
+
+ case ATA_PROT_ATAPI_DMA:
+- ata_qc_prep(qc);
++ pdc_fill_sg(qc);
+ /*FALLTHROUGH*/
+ case ATA_PROT_ATAPI_NODATA:
+ pdc_atapi_pkt(qc);
--- /dev/null
+From stable-bounces@linux.kernel.org Wed Jan 16 02:34:27 2008
+From: Mikael Pettersson <mikpe@it.uu.se>
+Date: Wed, 16 Jan 2008 10:31:22 +0100 (MET)
+Subject: sata_promise: FastTrack TX4200 is a second-generation chip
+To: stable@kernel.org
+Cc: Jeff Garzik <jeff@garzik.org>
+Message-ID: <200801160931.m0G9VMOw029868@harpo.it.uu.se>
+
+From: Mikael Pettersson <mikpe@it.uu.se>
+
+patch 7f9992a23190418592f0810900e4f91546ec41da in mainline.
+
+This patch corrects sata_promise to classify FastTrack TX4200
+(DID 3515/3519) as a second-generation chip. Promise's partial-
+source FT TX4200 driver confirms this classification.
+
+Treating it as a first-generation chip causes several problems:
+1. Detection failures. This is a recent regression triggered by
+ the hotplug-enabling changes in 2.6.23-rc1.
+2. Various "failed to resume link for reset" warnings.
+
+This patch fixes <http://bugzilla.kernel.org/show_bug.cgi?id=8936>.
+
+Thanks to Stephen Ziemba for reporting the bug and for testing the fix.
+
+Signed-off-by: Mikael Pettersson <mikpe@it.uu.se>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/ata/sata_promise.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/ata/sata_promise.c
++++ b/drivers/ata/sata_promise.c
+@@ -330,8 +330,8 @@ static const struct pci_device_id pdc_at
+
+ { PCI_VDEVICE(PROMISE, 0x3318), board_20319 },
+ { PCI_VDEVICE(PROMISE, 0x3319), board_20319 },
+- { PCI_VDEVICE(PROMISE, 0x3515), board_20319 },
+- { PCI_VDEVICE(PROMISE, 0x3519), board_20319 },
++ { PCI_VDEVICE(PROMISE, 0x3515), board_40518 },
++ { PCI_VDEVICE(PROMISE, 0x3519), board_40518 },
+ { PCI_VDEVICE(PROMISE, 0x3d17), board_40518 },
+ { PCI_VDEVICE(PROMISE, 0x3d18), board_40518 },
+
--- /dev/null
+sata_promise-fasttrack-tx4200-is-a-second-generation-chip.patch
+sata_promise-asic-prd-table-bug-workaround.patch
+pci-fix-fakephp-deadlock.patch
+quicklists-do-not-release-off-node-pages-early.patch