X-Git-Url: http://git.samba.org/samba.git/?a=blobdiff_plain;f=drivers%2Fata%2Flibata-sff.c;h=20dc572fb45a1c1b780c8d8a8303b88643a6fbbd;hb=ae51801ba5ca27c2c571eb508daa99b392e79bd4;hp=f9e4cd5279423c678343aca53d2078937df6fe7f;hpb=fe2520094d88018423dfc42b3cd0015f74e8adea;p=sfrench%2Fcifs-2.6.git diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index f9e4cd527942..20dc572fb45a 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -56,7 +56,8 @@ u8 ata_irq_on(struct ata_port *ap) ap->ctl &= ~ATA_NIEN; ap->last_ctl = ap->ctl; - iowrite8(ap->ctl, ioaddr->ctl_addr); + if (ioaddr->ctl_addr) + iowrite8(ap->ctl, ioaddr->ctl_addr); tmp = ata_wait_idle(ap); ap->ops->irq_clear(ap); @@ -81,12 +82,14 @@ void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; if (tf->ctl != ap->last_ctl) { - iowrite8(tf->ctl, ioaddr->ctl_addr); + if (ioaddr->ctl_addr) + iowrite8(tf->ctl, ioaddr->ctl_addr); ap->last_ctl = tf->ctl; ata_wait_idle(ap); } if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { + WARN_ON(!ioaddr->ctl_addr); iowrite8(tf->hob_feature, ioaddr->feature_addr); iowrite8(tf->hob_nsect, ioaddr->nsect_addr); iowrite8(tf->hob_lbal, ioaddr->lbal_addr); @@ -147,7 +150,9 @@ void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf) * @tf: ATA taskfile register set for storing input * * Reads ATA taskfile registers for currently-selected device - * into @tf. + * into @tf. Assumes the device has a fully SFF compliant task file + * layout and behaviour. If you device does not (eg has a different + * status method) then you will need to provide a replacement tf_read * * LOCKING: * Inherited from caller. @@ -156,7 +161,7 @@ void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; - tf->command = ata_chk_status(ap); + tf->command = ata_check_status(ap); tf->feature = ioread8(ioaddr->error_addr); tf->nsect = ioread8(ioaddr->nsect_addr); tf->lbal = ioread8(ioaddr->lbal_addr); @@ -165,14 +170,17 @@ void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) tf->device = ioread8(ioaddr->device_addr); if (tf->flags & ATA_TFLAG_LBA48) { - iowrite8(tf->ctl | ATA_HOB, ioaddr->ctl_addr); - tf->hob_feature = ioread8(ioaddr->error_addr); - tf->hob_nsect = ioread8(ioaddr->nsect_addr); - tf->hob_lbal = ioread8(ioaddr->lbal_addr); - tf->hob_lbam = ioread8(ioaddr->lbam_addr); - tf->hob_lbah = ioread8(ioaddr->lbah_addr); - iowrite8(tf->ctl, ioaddr->ctl_addr); - ap->last_ctl = tf->ctl; + if (likely(ioaddr->ctl_addr)) { + iowrite8(tf->ctl | ATA_HOB, ioaddr->ctl_addr); + tf->hob_feature = ioread8(ioaddr->error_addr); + tf->hob_nsect = ioread8(ioaddr->nsect_addr); + tf->hob_lbal = ioread8(ioaddr->lbal_addr); + tf->hob_lbam = ioread8(ioaddr->lbam_addr); + tf->hob_lbah = ioread8(ioaddr->lbah_addr); + iowrite8(tf->ctl, ioaddr->ctl_addr); + ap->last_ctl = tf->ctl; + } else + WARN_ON(1); } } @@ -248,7 +256,7 @@ void ata_bmdma_setup(struct ata_queued_cmd *qc) * LOCKING: * spin_lock_irqsave(host lock) */ -void ata_bmdma_start (struct ata_queued_cmd *qc) +void ata_bmdma_start(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; u8 dmactl; @@ -350,7 +358,8 @@ void ata_bmdma_freeze(struct ata_port *ap) ap->ctl |= ATA_NIEN; ap->last_ctl = ap->ctl; - iowrite8(ap->ctl, ioaddr->ctl_addr); + if (ioaddr->ctl_addr) + iowrite8(ap->ctl, ioaddr->ctl_addr); /* Under certain circumstances, some controllers raise IRQ on * ATA_NIEN manipulation. Also, many controllers fail to mask @@ -415,7 +424,7 @@ void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset, ap->hsm_task_state = HSM_ST_IDLE; if (qc && (qc->tf.protocol == ATA_PROT_DMA || - qc->tf.protocol == ATA_PROT_ATAPI_DMA)) { + qc->tf.protocol == ATAPI_PROT_DMA)) { u8 host_stat; host_stat = ap->ops->bmdma_status(ap); @@ -457,13 +466,14 @@ void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset, */ void ata_bmdma_error_handler(struct ata_port *ap) { - ata_reset_fn_t hardreset; + ata_reset_fn_t softreset = NULL, hardreset = NULL; - hardreset = NULL; + if (ap->ioaddr.ctl_addr) + softreset = ata_std_softreset; if (sata_scr_valid(&ap->link)) hardreset = sata_std_hardreset; - ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, hardreset, + ata_bmdma_drive_eh(ap, ata_std_prereset, softreset, hardreset, ata_std_postreset); } @@ -549,7 +559,7 @@ int ata_pci_init_bmdma(struct ata_host *host) return rc; /* request and iomap DMA region */ - rc = pcim_iomap_regions(pdev, 1 << 4, DRV_NAME); + rc = pcim_iomap_regions(pdev, 1 << 4, dev_driver_string(gdev)); if (rc) { dev_printk(KERN_ERR, gdev, "failed to request/iomap BAR4\n"); return -ENOMEM; @@ -619,7 +629,8 @@ int ata_pci_init_sff_host(struct ata_host *host) continue; } - rc = pcim_iomap_regions(pdev, 0x3 << base, DRV_NAME); + 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 " @@ -710,6 +721,99 @@ int ata_pci_prepare_sff_host(struct pci_dev *pdev, return rc; } +/** + * ata_pci_activate_sff_host - start SFF host, request IRQ and register it + * @host: target SFF ATA host + * @irq_handler: irq_handler used when requesting IRQ(s) + * @sht: scsi_host_template to use when registering the host + * + * This is the counterpart of ata_host_activate() for SFF ATA + * hosts. This separate helper is necessary because SFF hosts + * use two separate interrupts in legacy mode. + * + * LOCKING: + * Inherited from calling layer (may sleep). + * + * RETURNS: + * 0 on success, -errno otherwise. + */ +int ata_pci_activate_sff_host(struct ata_host *host, + irq_handler_t irq_handler, + struct scsi_host_template *sht) +{ + struct device *dev = host->dev; + struct pci_dev *pdev = to_pci_dev(dev); + const char *drv_name = dev_driver_string(host->dev); + int legacy_mode = 0, rc; + + rc = ata_host_start(host); + if (rc) + return rc; + + if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) { + u8 tmp8, mask; + + /* TODO: What if one channel is in native mode ... */ + pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8); + mask = (1 << 2) | (1 << 0); + if ((tmp8 & mask) != mask) + legacy_mode = 1; +#if defined(CONFIG_NO_ATA_LEGACY) + /* Some platforms with PCI limits cannot address compat + port space. In that case we punt if their firmware has + left a device in compatibility mode */ + if (legacy_mode) { + printk(KERN_ERR "ata: Compatibility mode ATA is not supported on this platform, skipping.\n"); + return -EOPNOTSUPP; + } +#endif + } + + if (!devres_open_group(dev, NULL, GFP_KERNEL)) + return -ENOMEM; + + if (!legacy_mode && pdev->irq) { + rc = devm_request_irq(dev, pdev->irq, irq_handler, + IRQF_SHARED, drv_name, host); + if (rc) + goto out; + + ata_port_desc(host->ports[0], "irq %d", pdev->irq); + ata_port_desc(host->ports[1], "irq %d", pdev->irq); + } else if (legacy_mode) { + if (!ata_port_is_dummy(host->ports[0])) { + rc = devm_request_irq(dev, ATA_PRIMARY_IRQ(pdev), + irq_handler, IRQF_SHARED, + drv_name, host); + if (rc) + goto out; + + ata_port_desc(host->ports[0], "irq %d", + ATA_PRIMARY_IRQ(pdev)); + } + + if (!ata_port_is_dummy(host->ports[1])) { + rc = devm_request_irq(dev, ATA_SECONDARY_IRQ(pdev), + irq_handler, IRQF_SHARED, + drv_name, host); + if (rc) + goto out; + + ata_port_desc(host->ports[1], "irq %d", + ATA_SECONDARY_IRQ(pdev)); + } + } + + rc = ata_host_register(host, sht); + out: + if (rc == 0) + devres_remove_group(dev, NULL); + else + devres_release_group(dev, NULL); + + return rc; +} + /** * ata_pci_init_one - Initialize/register PCI IDE host controller * @pdev: Controller to be initialized @@ -739,8 +843,6 @@ int ata_pci_init_one(struct pci_dev *pdev, struct device *dev = &pdev->dev; const struct ata_port_info *pi = NULL; struct ata_host *host = NULL; - u8 mask; - int legacy_mode = 0; int i, rc; DPRINTK("ENTER\n"); @@ -762,92 +864,24 @@ int ata_pci_init_one(struct pci_dev *pdev, if (!devres_open_group(dev, NULL, GFP_KERNEL)) return -ENOMEM; - /* FIXME: Really for ATA it isn't safe because the device may be - multi-purpose and we want to leave it alone if it was already - enabled. Secondly for shared use as Arjan says we want refcounting - - Checking dev->is_enabled is insufficient as this is not set at - boot for the primary video which is BIOS enabled - */ - rc = pcim_enable_device(pdev); if (rc) - goto err_out; - - if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) { - u8 tmp8; - - /* TODO: What if one channel is in native mode ... */ - pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8); - mask = (1 << 2) | (1 << 0); - if ((tmp8 & mask) != mask) - legacy_mode = 1; -#if defined(CONFIG_NO_ATA_LEGACY) - /* Some platforms with PCI limits cannot address compat - port space. In that case we punt if their firmware has - left a device in compatibility mode */ - if (legacy_mode) { - printk(KERN_ERR "ata: Compatibility mode ATA is not supported on this platform, skipping.\n"); - rc = -EOPNOTSUPP; - goto err_out; - } -#endif - } + goto out; - /* prepare host */ + /* prepare and activate SFF host */ rc = ata_pci_prepare_sff_host(pdev, ppi, &host); if (rc) - goto err_out; + goto out; pci_set_master(pdev); + rc = ata_pci_activate_sff_host(host, pi->port_ops->irq_handler, + pi->sht); + out: + if (rc == 0) + devres_remove_group(&pdev->dev, NULL); + else + devres_release_group(&pdev->dev, NULL); - /* start host and request IRQ */ - rc = ata_host_start(host); - if (rc) - goto err_out; - - if (!legacy_mode) { - rc = devm_request_irq(dev, pdev->irq, pi->port_ops->irq_handler, - IRQF_SHARED, DRV_NAME, host); - if (rc) - goto err_out; - - ata_port_desc(host->ports[0], "irq %d", pdev->irq); - ata_port_desc(host->ports[1], "irq %d", pdev->irq); - } else { - if (!ata_port_is_dummy(host->ports[0])) { - rc = devm_request_irq(dev, ATA_PRIMARY_IRQ(pdev), - pi->port_ops->irq_handler, - IRQF_SHARED, DRV_NAME, host); - if (rc) - goto err_out; - - ata_port_desc(host->ports[0], "irq %d", - ATA_PRIMARY_IRQ(pdev)); - } - - if (!ata_port_is_dummy(host->ports[1])) { - rc = devm_request_irq(dev, ATA_SECONDARY_IRQ(pdev), - pi->port_ops->irq_handler, - IRQF_SHARED, DRV_NAME, host); - if (rc) - goto err_out; - - ata_port_desc(host->ports[1], "irq %d", - ATA_SECONDARY_IRQ(pdev)); - } - } - - /* register */ - rc = ata_host_register(host, pi->sht); - if (rc) - goto err_out; - - devres_remove_group(dev, NULL); - return 0; - -err_out: - devres_release_group(dev, NULL); return rc; } @@ -856,7 +890,7 @@ err_out: * @pdev: PCI device * * Some PCI ATA devices report simplex mode but in fact can be told to - * enter non simplex mode. This implements the neccessary logic to + * enter non simplex mode. This implements the necessary logic to * perform the task on such devices. Calling it on other devices will * have -undefined- behaviour. */