diff options
Diffstat (limited to 'drivers/ata/libata-sff.c')
-rw-r--r-- | drivers/ata/libata-sff.c | 205 |
1 files changed, 99 insertions, 106 deletions
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index b1b926c..22edc92 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -35,6 +35,7 @@ #include <linux/kernel.h> #include <linux/gfp.h> #include <linux/pci.h> +#include <linux/module.h> #include <linux/libata.h> #include <linux/highmem.h> @@ -227,9 +228,9 @@ int ata_sff_busy_sleep(struct ata_port *ap, } if (status != 0xff && (status & ATA_BUSY)) - ata_port_printk(ap, KERN_WARNING, - "port is slow to respond, please be patient " - "(Status 0x%x)\n", status); + ata_port_warn(ap, + "port is slow to respond, please be patient (Status 0x%x)\n", + status); timeout = ata_deadline(timer_start, tmout); while (status != 0xff && (status & ATA_BUSY) && @@ -242,9 +243,9 @@ int ata_sff_busy_sleep(struct ata_port *ap, return -ENODEV; if (status & ATA_BUSY) { - ata_port_printk(ap, KERN_ERR, "port failed to respond " - "(%lu secs, Status 0x%x)\n", - DIV_ROUND_UP(tmout, 1000), status); + ata_port_err(ap, + "port failed to respond (%lu secs, Status 0x%x)\n", + DIV_ROUND_UP(tmout, 1000), status); return -EBUSY; } @@ -350,8 +351,8 @@ static void ata_dev_select(struct ata_port *ap, unsigned int device, unsigned int wait, unsigned int can_sleep) { if (ata_msg_probe(ap)) - ata_port_printk(ap, KERN_INFO, "ata_dev_select: ENTER, " - "device %u, wait %u\n", device, wait); + ata_port_info(ap, "ata_dev_select: ENTER, device %u, wait %u\n", + device, wait); if (wait) ata_wait_idle(ap); @@ -569,7 +570,7 @@ unsigned int ata_sff_data_xfer(struct ata_device *dev, unsigned char *buf, /* Transfer trailing byte, if any. */ if (unlikely(buflen & 0x01)) { - unsigned char pad[2]; + unsigned char pad[2] = { }; /* Point buf to the tail of buffer */ buf += buflen - 1; @@ -628,7 +629,7 @@ unsigned int ata_sff_data_xfer32(struct ata_device *dev, unsigned char *buf, /* Transfer trailing bytes, if any */ if (unlikely(slop)) { - unsigned char pad[4]; + unsigned char pad[4] = { }; /* Point buf to the tail of buffer */ buf += buflen - slop; @@ -678,7 +679,7 @@ unsigned int ata_sff_data_xfer_noirq(struct ata_device *dev, unsigned char *buf, unsigned int consumed; local_irq_save(flags); - consumed = ata_sff_data_xfer(dev, buf, buflen, rw); + consumed = ata_sff_data_xfer32(dev, buf, buflen, rw); local_irq_restore(flags); return consumed; @@ -1332,10 +1333,23 @@ void ata_sff_flush_pio_task(struct ata_port *ap) DPRINTK("ENTER\n"); cancel_delayed_work_sync(&ap->sff_pio_task); + + /* + * We wanna reset the HSM state to IDLE. If we do so without + * grabbing the port lock, critical sections protected by it which + * expect the HSM state to stay stable may get surprised. For + * example, we may set IDLE in between the time + * __ata_sff_port_intr() checks for HSM_ST_IDLE and before it calls + * ata_sff_hsm_move() causing ata_sff_hsm_move() to BUG(). + */ + spin_lock_irq(ap->lock); ap->hsm_task_state = HSM_ST_IDLE; + spin_unlock_irq(ap->lock); + + ap->sff_pio_task_link = NULL; if (ata_msg_ctl(ap)) - ata_port_printk(ap, KERN_DEBUG, "%s: EXIT\n", __func__); + ata_port_dbg(ap, "%s: EXIT\n", __func__); } static void ata_sff_pio_task(struct work_struct *work) @@ -1513,7 +1527,7 @@ static unsigned int ata_sff_idle_irq(struct ata_port *ap) ap->ops->sff_check_status(ap); if (ap->ops->sff_irq_clear) ap->ops->sff_irq_clear(ap); - ata_port_printk(ap, KERN_WARNING, "irq trap\n"); + ata_port_warn(ap, "irq trap\n"); return 1; } #endif @@ -1711,7 +1725,7 @@ void ata_sff_lost_interrupt(struct ata_port *ap) /* There was a command running, we are no longer busy and we have no interrupt. */ - ata_port_printk(ap, KERN_WARNING, "lost interrupt (Status 0x%x)\n", + ata_port_warn(ap, "lost interrupt (Status 0x%x)\n", status); /* Run the host interrupt logic as if the interrupt had not been lost */ @@ -1798,8 +1812,9 @@ int ata_sff_prereset(struct ata_link *link, unsigned long deadline) if (!ata_link_offline(link)) { rc = ata_sff_wait_ready(link, deadline); if (rc && rc != -ENODEV) { - ata_link_printk(link, KERN_WARNING, "device not ready " - "(errno=%d), forcing hardreset\n", rc); + ata_link_warn(link, + "device not ready (errno=%d), forcing hardreset\n", + rc); ehc->i.action |= ATA_EH_HARDRESET; } } @@ -2005,13 +2020,15 @@ static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask, DPRINTK("ata%u: bus reset via SRST\n", ap->print_id); - /* software reset. causes dev0 to be selected */ - iowrite8(ap->ctl, ioaddr->ctl_addr); - udelay(20); /* FIXME: flush */ - iowrite8(ap->ctl | ATA_SRST, ioaddr->ctl_addr); - udelay(20); /* FIXME: flush */ - iowrite8(ap->ctl, ioaddr->ctl_addr); - ap->last_ctl = ap->ctl; + if (ap->ioaddr.ctl_addr) { + /* software reset. causes dev0 to be selected */ + iowrite8(ap->ctl, ioaddr->ctl_addr); + udelay(20); /* FIXME: flush */ + iowrite8(ap->ctl | ATA_SRST, ioaddr->ctl_addr); + udelay(20); /* FIXME: flush */ + iowrite8(ap->ctl, ioaddr->ctl_addr); + ap->last_ctl = ap->ctl; + } /* wait the port to become ready */ return ata_sff_wait_after_reset(&ap->link, devmask, deadline); @@ -2056,7 +2073,7 @@ int ata_sff_softreset(struct ata_link *link, unsigned int *classes, rc = ata_bus_softreset(ap, devmask, deadline); /* if link is occupied, -ENODEV too is an error */ if (rc && (rc != -ENODEV || sata_scr_valid(link))) { - ata_link_printk(link, KERN_ERR, "SRST failed (errno=%d)\n", rc); + ata_link_err(link, "SRST failed (errno=%d)\n", rc); return rc; } @@ -2170,8 +2187,7 @@ void ata_sff_drain_fifo(struct ata_queued_cmd *qc) /* Can become DEBUG later */ if (count) - ata_port_printk(ap, KERN_DEBUG, - "drained %d bytes to clear DRQ.\n", count); + ata_port_dbg(ap, "drained %d bytes to clear DRQ\n", count); } EXPORT_SYMBOL_GPL(ata_sff_drain_fifo); @@ -2213,10 +2229,6 @@ void ata_sff_error_handler(struct ata_port *ap) spin_unlock_irqrestore(ap->lock, flags); - /* ignore ata_sff_softreset if ctl isn't accessible */ - if (softreset == ata_sff_softreset && !ap->ioaddr.ctl_addr) - softreset = NULL; - /* ignore built-in hardresets if SCR access is not available */ if ((hardreset == sata_std_hardreset || hardreset == sata_sff_hardreset) && !sata_scr_valid(&ap->link)) @@ -2316,9 +2328,9 @@ int ata_pci_sff_init_host(struct ata_host *host) rc = pcim_iomap_regions(pdev, 0x3 << base, dev_driver_string(gdev)); if (rc) { - dev_printk(KERN_WARNING, gdev, - "failed to request/iomap BARs for port %d " - "(errno=%d)\n", i, rc); + dev_warn(gdev, + "failed to request/iomap BARs for port %d (errno=%d)\n", + i, rc); if (rc == -EBUSY) pcim_pin_device(pdev); ap->ops = &ata_dummy_port_ops; @@ -2340,7 +2352,7 @@ int ata_pci_sff_init_host(struct ata_host *host) } if (!mask) { - dev_printk(KERN_ERR, gdev, "no available native port\n"); + dev_err(gdev, "no available native port\n"); return -ENODEV; } @@ -2375,8 +2387,7 @@ int ata_pci_sff_prepare_host(struct pci_dev *pdev, host = ata_host_alloc_pinfo(&pdev->dev, ppi, 2); if (!host) { - dev_printk(KERN_ERR, &pdev->dev, - "failed to allocate ATA host\n"); + dev_err(&pdev->dev, "failed to allocate ATA host\n"); rc = -ENOMEM; goto err_out; } @@ -2507,31 +2518,10 @@ static const struct ata_port_info *ata_sff_find_valid_pi( return NULL; } -/** - * ata_pci_sff_init_one - Initialize/register PIO-only PCI IDE controller - * @pdev: Controller to be initialized - * @ppi: array of port_info, must be enough for two ports - * @sht: scsi_host_template to use when registering the host - * @host_priv: host private_data - * @hflag: host flags - * - * This is a helper function which can be called from a driver's - * xxx_init_one() probe function if the hardware uses traditional - * IDE taskfile registers and is PIO only. - * - * ASSUMPTION: - * Nobody makes a single channel controller that appears solely as - * the secondary legacy port on PCI. - * - * LOCKING: - * Inherited from PCI layer (may sleep). - * - * RETURNS: - * Zero on success, negative on errno-based value on error. - */ -int ata_pci_sff_init_one(struct pci_dev *pdev, - const struct ata_port_info * const *ppi, - struct scsi_host_template *sht, void *host_priv, int hflag) +static int ata_pci_init_one(struct pci_dev *pdev, + const struct ata_port_info * const *ppi, + struct scsi_host_template *sht, void *host_priv, + int hflags, bool bmdma) { struct device *dev = &pdev->dev; const struct ata_port_info *pi; @@ -2542,8 +2532,7 @@ int ata_pci_sff_init_one(struct pci_dev *pdev, pi = ata_sff_find_valid_pi(ppi); if (!pi) { - dev_printk(KERN_ERR, &pdev->dev, - "no valid port_info specified\n"); + dev_err(&pdev->dev, "no valid port_info specified\n"); return -EINVAL; } @@ -2554,14 +2543,26 @@ int ata_pci_sff_init_one(struct pci_dev *pdev, if (rc) goto out; - /* prepare and activate SFF host */ - rc = ata_pci_sff_prepare_host(pdev, ppi, &host); +#ifdef CONFIG_ATA_BMDMA + if (bmdma) + /* prepare and activate BMDMA host */ + rc = ata_pci_bmdma_prepare_host(pdev, ppi, &host); + else +#endif + /* prepare and activate SFF host */ + rc = ata_pci_sff_prepare_host(pdev, ppi, &host); if (rc) goto out; host->private_data = host_priv; - host->flags |= hflag; + host->flags |= hflags; - rc = ata_pci_sff_activate_host(host, ata_sff_interrupt, sht); +#ifdef CONFIG_ATA_BMDMA + if (bmdma) { + pci_set_master(pdev); + rc = ata_pci_sff_activate_host(host, ata_bmdma_interrupt, sht); + } else +#endif + rc = ata_pci_sff_activate_host(host, ata_sff_interrupt, sht); out: if (rc == 0) devres_remove_group(&pdev->dev, NULL); @@ -2570,6 +2571,35 @@ out: return rc; } + +/** + * ata_pci_sff_init_one - Initialize/register PIO-only PCI IDE controller + * @pdev: Controller to be initialized + * @ppi: array of port_info, must be enough for two ports + * @sht: scsi_host_template to use when registering the host + * @host_priv: host private_data + * @hflag: host flags + * + * This is a helper function which can be called from a driver's + * xxx_init_one() probe function if the hardware uses traditional + * IDE taskfile registers and is PIO only. + * + * ASSUMPTION: + * Nobody makes a single channel controller that appears solely as + * the secondary legacy port on PCI. + * + * LOCKING: + * Inherited from PCI layer (may sleep). + * + * RETURNS: + * Zero on success, negative on errno-based value on error. + */ +int ata_pci_sff_init_one(struct pci_dev *pdev, + const struct ata_port_info * const *ppi, + struct scsi_host_template *sht, void *host_priv, int hflag) +{ + return ata_pci_init_one(pdev, ppi, sht, host_priv, hflag, 0); +} EXPORT_SYMBOL_GPL(ata_pci_sff_init_one); #endif /* CONFIG_PCI */ @@ -3164,8 +3194,7 @@ static void ata_bmdma_nodma(struct ata_host *host, const char *reason) { int i; - dev_printk(KERN_ERR, host->dev, "BMDMA: %s, falling back to PIO\n", - reason); + dev_err(host->dev, "BMDMA: %s, falling back to PIO\n", reason); for (i = 0; i < 2; i++) { host->ports[i]->mwdma_mask = 0; @@ -3288,43 +3317,7 @@ int ata_pci_bmdma_init_one(struct pci_dev *pdev, struct scsi_host_template *sht, void *host_priv, int hflags) { - struct device *dev = &pdev->dev; - const struct ata_port_info *pi; - struct ata_host *host = NULL; - int rc; - - DPRINTK("ENTER\n"); - - pi = ata_sff_find_valid_pi(ppi); - if (!pi) { - dev_printk(KERN_ERR, &pdev->dev, - "no valid port_info specified\n"); - return -EINVAL; - } - - if (!devres_open_group(dev, NULL, GFP_KERNEL)) - return -ENOMEM; - - rc = pcim_enable_device(pdev); - if (rc) - goto out; - - /* prepare and activate BMDMA host */ - rc = ata_pci_bmdma_prepare_host(pdev, ppi, &host); - if (rc) - goto out; - host->private_data = host_priv; - host->flags |= hflags; - - pci_set_master(pdev); - rc = ata_pci_sff_activate_host(host, ata_bmdma_interrupt, sht); - out: - if (rc == 0) - devres_remove_group(&pdev->dev, NULL); - else - devres_release_group(&pdev->dev, NULL); - - return rc; + return ata_pci_init_one(pdev, ppi, sht, host_priv, hflags, 1); } EXPORT_SYMBOL_GPL(ata_pci_bmdma_init_one); |