aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/ata/libata-core.c74
-rw-r--r--include/linux/libata.h2
2 files changed, 63 insertions, 13 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index c831c9efee60..aea766a48e05 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -5819,11 +5819,14 @@ static void ata_host_release(struct device *gendev, void *res)
5819 for (i = 0; i < host->n_ports; i++) { 5819 for (i = 0; i < host->n_ports; i++) {
5820 struct ata_port *ap = host->ports[i]; 5820 struct ata_port *ap = host->ports[i];
5821 5821
5822 if (ap && ap->ops->port_stop) 5822 if (!ap)
5823 continue;
5824
5825 if ((host->flags & ATA_HOST_STARTED) && ap->ops->port_stop)
5823 ap->ops->port_stop(ap); 5826 ap->ops->port_stop(ap);
5824 } 5827 }
5825 5828
5826 if (host->ops->host_stop) 5829 if ((host->flags & ATA_HOST_STARTED) && host->ops->host_stop)
5827 host->ops->host_stop(host); 5830 host->ops->host_stop(host);
5828 5831
5829 for (i = 0; i < host->n_ports; i++) { 5832 for (i = 0; i < host->n_ports; i++) {
@@ -5843,6 +5846,56 @@ static void ata_host_release(struct device *gendev, void *res)
5843} 5846}
5844 5847
5845/** 5848/**
5849 * ata_host_start - start and freeze ports of an ATA host
5850 * @host: ATA host to start ports for
5851 *
5852 * Start and then freeze ports of @host. Started status is
5853 * recorded in host->flags, so this function can be called
5854 * multiple times. Ports are guaranteed to get started only
5855 * once.
5856 *
5857 * LOCKING:
5858 * Inherited from calling layer (may sleep).
5859 *
5860 * RETURNS:
5861 * 0 if all ports are started successfully, -errno otherwise.
5862 */
5863int ata_host_start(struct ata_host *host)
5864{
5865 int i, rc;
5866
5867 if (host->flags & ATA_HOST_STARTED)
5868 return 0;
5869
5870 for (i = 0; i < host->n_ports; i++) {
5871 struct ata_port *ap = host->ports[i];
5872
5873 if (ap->ops->port_start) {
5874 rc = ap->ops->port_start(ap);
5875 if (rc) {
5876 ata_port_printk(ap, KERN_ERR, "failed to "
5877 "start port (errno=%d)\n", rc);
5878 goto err_out;
5879 }
5880 }
5881
5882 ata_eh_freeze_port(ap);
5883 }
5884
5885 host->flags |= ATA_HOST_STARTED;
5886 return 0;
5887
5888 err_out:
5889 while (--i >= 0) {
5890 struct ata_port *ap = host->ports[i];
5891
5892 if (ap->ops->port_stop)
5893 ap->ops->port_stop(ap);
5894 }
5895 return rc;
5896}
5897
5898/**
5846 * ata_sas_host_init - Initialize a host struct 5899 * ata_sas_host_init - Initialize a host struct
5847 * @host: host to initialize 5900 * @host: host to initialize
5848 * @dev: device host is attached to 5901 * @dev: device host is attached to
@@ -5931,14 +5984,6 @@ int ata_device_add(const struct ata_probe_ent *ent)
5931 continue; 5984 continue;
5932 } 5985 }
5933 5986
5934 /* start port */
5935 rc = ap->ops->port_start(ap);
5936 if (rc) {
5937 host->ports[i] = NULL;
5938 scsi_host_put(ap->scsi_host);
5939 goto err_out;
5940 }
5941
5942 /* Report the secondary IRQ for second channel legacy */ 5987 /* Report the secondary IRQ for second channel legacy */
5943 if (i == 1 && ent->irq2) 5988 if (i == 1 && ent->irq2)
5944 irq_line = ent->irq2; 5989 irq_line = ent->irq2;
@@ -5956,11 +6001,13 @@ int ata_device_add(const struct ata_probe_ent *ent)
5956 ap->ioaddr.ctl_addr, 6001 ap->ioaddr.ctl_addr,
5957 ap->ioaddr.bmdma_addr, 6002 ap->ioaddr.bmdma_addr,
5958 irq_line); 6003 irq_line);
5959
5960 /* freeze port before requesting IRQ */
5961 ata_eh_freeze_port(ap);
5962 } 6004 }
5963 6005
6006 /* start ports */
6007 rc = ata_host_start(host);
6008 if (rc)
6009 goto err_out;
6010
5964 /* obtain irq, that may be shared between channels */ 6011 /* obtain irq, that may be shared between channels */
5965 rc = devm_request_irq(dev, ent->irq, ent->port_ops->irq_handler, 6012 rc = devm_request_irq(dev, ent->irq, ent->port_ops->irq_handler,
5966 ent->irq_flags, DRV_NAME, host); 6013 ent->irq_flags, DRV_NAME, host);
@@ -6446,6 +6493,7 @@ EXPORT_SYMBOL_GPL(ata_dummy_port_ops);
6446EXPORT_SYMBOL_GPL(ata_std_bios_param); 6493EXPORT_SYMBOL_GPL(ata_std_bios_param);
6447EXPORT_SYMBOL_GPL(ata_std_ports); 6494EXPORT_SYMBOL_GPL(ata_std_ports);
6448EXPORT_SYMBOL_GPL(ata_host_init); 6495EXPORT_SYMBOL_GPL(ata_host_init);
6496EXPORT_SYMBOL_GPL(ata_host_start);
6449EXPORT_SYMBOL_GPL(ata_device_add); 6497EXPORT_SYMBOL_GPL(ata_device_add);
6450EXPORT_SYMBOL_GPL(ata_host_detach); 6498EXPORT_SYMBOL_GPL(ata_host_detach);
6451EXPORT_SYMBOL_GPL(ata_sg_init); 6499EXPORT_SYMBOL_GPL(ata_sg_init);
diff --git a/include/linux/libata.h b/include/linux/libata.h
index ced9dd54035e..bda26e86f05f 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -210,6 +210,7 @@ enum {
210 210
211 /* host set flags */ 211 /* host set flags */
212 ATA_HOST_SIMPLEX = (1 << 0), /* Host is simplex, one DMA channel per host only */ 212 ATA_HOST_SIMPLEX = (1 << 0), /* Host is simplex, one DMA channel per host only */
213 ATA_HOST_STARTED = (1 << 1), /* Host started */
213 214
214 /* various lengths of time */ 215 /* various lengths of time */
215 ATA_TMOUT_BOOT = 30 * HZ, /* heuristic */ 216 ATA_TMOUT_BOOT = 30 * HZ, /* heuristic */
@@ -732,6 +733,7 @@ extern int ata_pci_device_resume(struct pci_dev *pdev);
732#endif 733#endif
733extern int ata_pci_clear_simplex(struct pci_dev *pdev); 734extern int ata_pci_clear_simplex(struct pci_dev *pdev);
734#endif /* CONFIG_PCI */ 735#endif /* CONFIG_PCI */
736extern int ata_host_start(struct ata_host *host);
735extern int ata_device_add(const struct ata_probe_ent *ent); 737extern int ata_device_add(const struct ata_probe_ent *ent);
736extern void ata_host_detach(struct ata_host *host); 738extern void ata_host_detach(struct ata_host *host);
737extern void ata_host_init(struct ata_host *, struct device *, 739extern void ata_host_init(struct ata_host *, struct device *,