--- /usr/src/linux-source-2.6.15/drivers/scsi/sata_sil.c	2006-03-03 06:18:38.000000000 +0900
+++ drivers/scsi/sata_sil.c	2006-06-11 20:59:11.000000000 +0900
@@ -65,6 +65,7 @@
 	SIL_FIFO_W3		= 0x245,
 
 	SIL_SYSCFG		= 0x48,
+	SIL_GPIO                = 0x54,
 	SIL_MASK_IDE0_INT	= (1 << 22),
 	SIL_MASK_IDE1_INT	= (1 << 23),
 	SIL_MASK_IDE2_INT	= (1 << 24),
@@ -85,6 +86,9 @@
 static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg);
 static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 static void sil_post_set_mode (struct ata_port *ap);
+static void sil_bmdma_start(struct ata_queued_cmd *qc);
+static void sil_bmdma_stop(struct ata_queued_cmd *qc);
+static void sil_host_stop (struct ata_host_set *host_set);
 
 
 static const struct pci_device_id sil_pci_tbl[] = {
@@ -111,7 +115,6 @@
 	{ "ST380013AS",		SIL_QUIRK_MOD15WRITE },
 	{ "ST380023AS",		SIL_QUIRK_MOD15WRITE },
 	{ "ST3120023AS",	SIL_QUIRK_MOD15WRITE },
-	{ "ST3160023AS",	SIL_QUIRK_MOD15WRITE },
 	{ "ST3120026AS",	SIL_QUIRK_MOD15WRITE },
 	{ "ST3200822AS",	SIL_QUIRK_MOD15WRITE },
 	{ "ST340014ASL",	SIL_QUIRK_MOD15WRITE },
@@ -161,8 +164,8 @@
 	.phy_reset		= sata_phy_reset,
 	.post_set_mode		= sil_post_set_mode,
 	.bmdma_setup            = ata_bmdma_setup,
-	.bmdma_start            = ata_bmdma_start,
-	.bmdma_stop		= ata_bmdma_stop,
+	.bmdma_start            = sil_bmdma_start,
+	.bmdma_stop		= sil_bmdma_stop,
 	.bmdma_status		= ata_bmdma_status,
 	.qc_prep		= ata_qc_prep,
 	.qc_issue		= ata_qc_issue_prot,
@@ -173,7 +176,7 @@
 	.scr_write		= sil_scr_write,
 	.port_start		= ata_port_start,
 	.port_stop		= ata_port_stop,
-	.host_stop		= ata_pci_host_stop,
+	.host_stop		= sil_host_stop,
 };
 
 static struct ata_port_info sil_port_info[] = {
@@ -226,6 +229,10 @@
 	/* ... port 3 */
 };
 
+struct sil_host_priv {
+	u8			use_gpio;
+};
+
 MODULE_AUTHOR("Jeff Garzik");
 MODULE_DESCRIPTION("low-level driver for Silicon Image SATA controller");
 MODULE_LICENSE("GPL");
@@ -240,6 +247,48 @@
 	return cache_line;
 }
 
+static void sil_bmdma_start(struct ata_queued_cmd *qc)
+{
+	struct sil_host_priv* hpriv = qc->ap->host_set->private_data;
+	if (hpriv->use_gpio) {
+		void* mmio_base = qc->ap->host_set->mmio_base;
+		u32 gpio = readl(mmio_base + SIL_GPIO);
+
+		/* set the lower 8 bits to activate the LED */
+		gpio |= 0xff;
+		writel(gpio, mmio_base + SIL_GPIO);
+		readl(mmio_base + SIL_GPIO);	/* flush */
+	}
+
+	ata_bmdma_start(qc);
+}
+
+static void sil_bmdma_stop(struct ata_queued_cmd *qc)
+{
+	struct sil_host_priv* hpriv = qc->ap->host_set->private_data;
+
+	ata_bmdma_stop(qc);
+
+	if (hpriv->use_gpio) {
+		void* mmio_base = qc->ap->host_set->mmio_base;
+		u32 gpio = readl(mmio_base + SIL_GPIO);
+
+		/* set bits [15:8] to disable the LED */
+		gpio |= 0xff00;
+		writel(gpio, mmio_base + SIL_GPIO);
+		readl(mmio_base + SIL_GPIO);	/* flush */
+	}
+}
+
+static void sil_host_stop (struct ata_host_set *host_set)
+{
+	ata_pci_host_stop(host_set);
+
+	if (host_set->private_data)
+		kfree(host_set->private_data);
+}
+
+
 static void sil_post_set_mode (struct ata_port *ap)
 {
 	struct ata_host_set *host_set = ap->host_set;
@@ -377,6 +426,7 @@
 {
 	static int printed_version;
 	struct ata_probe_ent *probe_ent = NULL;
+	struct sil_host_priv *hpriv = NULL;
 	unsigned long base;
 	void __iomem *mmio_base;
 	int rc;
@@ -415,6 +465,13 @@
 		goto err_out_regions;
 	}
 
+	hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL);
+	if (!hpriv) {
+		rc = -ENOMEM;
+		goto err_out_free_ent;
+	}
+	memset(hpriv, 0, sizeof(*hpriv));
+
 	memset(probe_ent, 0, sizeof(*probe_ent));
 	INIT_LIST_HEAD(&probe_ent->node);
 	probe_ent->dev = pci_dev_to_dev(pdev);
@@ -431,10 +488,11 @@
 	mmio_base = pci_iomap(pdev, 5, 0);
 	if (mmio_base == NULL) {
 		rc = -ENOMEM;
-		goto err_out_free_ent;
+		goto err_out_free_hpriv;
 	}
 
 	probe_ent->mmio_base = mmio_base;
+	probe_ent->private_data = hpriv;
 
 	base = (unsigned long) mmio_base;
 
@@ -479,6 +537,14 @@
 		irq_mask = SIL_MASK_2PORT;
 	}
 
+	/* check for LED GPIO on 3112 parts */
+	tmp = readl(mmio_base + SIL_GPIO);
+	if ((ent->driver_data == sil_3112 ||
+	    ent->driver_data == sil_3112_m15w) && (tmp & 0xff) == 0xff) {
+		dev_printk(KERN_INFO, &pdev->dev, "using GPIO for LED control\n");
+		hpriv->use_gpio = 1;
+	}
+
 	/* make sure IDE0/1/2/3 interrupts are not masked */
 	tmp = readl(mmio_base + SIL_SYSCFG);
 	if (tmp & irq_mask) {
@@ -500,6 +566,8 @@
 
 	return 0;
 
+err_out_free_hpriv:
+	kfree(hpriv);
 err_out_free_ent:
 	kfree(probe_ent);
 err_out_regions:
