--- drivers/scsi/sata_sil.c.orig 2005-07-07 10:07:19.000000000 +0900 +++ drivers/scsi/sata_sil.c 2005-07-07 23:19:36.000000000 +0900 @@ -54,6 +54,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), @@ -74,6 +75,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_port *ap); +static void sil_host_stop (struct ata_host_set *host_set); static struct pci_device_id sil_pci_tbl[] = { { 0x1095, 0x3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 }, @@ -149,8 +152,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, @@ -161,7 +164,7 @@ .scr_write = sil_scr_write, .port_start = ata_port_start, .port_stop = ata_port_stop, - .host_stop = ata_host_stop, + .host_stop = sil_host_stop, }; static struct ata_port_info sil_port_info[] = { @@ -204,6 +207,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"); @@ -217,6 +224,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_port *ap) +{ + struct sil_host_priv* hpriv = ap->host_set->private_data; + + ata_bmdma_stop(ap); + + if (hpriv->use_gpio) { + void* mmio_base = 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) +{ + if (host_set->private_data) + kfree(host_set->private_data); + + ata_host_stop(host_set); +} + + static void sil_post_set_mode (struct ata_port *ap) { struct ata_host_set *host_set = ap->host_set; @@ -353,6 +402,7 @@ { static int printed_version; struct ata_probe_ent *probe_ent = NULL; + struct sil_host_priv *hpriv = NULL; unsigned long base; void *mmio_base; int rc; @@ -391,6 +441,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); @@ -408,10 +465,11 @@ pci_resource_len(pdev, 5)); 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; @@ -456,6 +514,12 @@ irq_mask = SIL_MASK_2PORT; } + /* check for LED GPIO on 3112 parts */ + tmp = readl(mmio_base + SIL_GPIO); + if ((ent->driver_data == sil_3112) && ((tmp & 0xff) == 0xff)) { + hpriv->use_gpio = 1; + } + /* make sure IDE0/1/2/3 interrupts are not masked */ tmp = readl(mmio_base + SIL_SYSCFG); if (tmp & irq_mask) { @@ -477,6 +541,8 @@ return 0; +err_out_free_hpriv: + kfree(hpriv); err_out_free_ent: kfree(probe_ent); err_out_regions: