diff options
-rw-r--r-- | drivers/ata/libata-core.c | 74 | ||||
-rw-r--r-- | include/linux/libata.h | 2 |
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 | */ | ||
5863 | int 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); | |||
6446 | EXPORT_SYMBOL_GPL(ata_std_bios_param); | 6493 | EXPORT_SYMBOL_GPL(ata_std_bios_param); |
6447 | EXPORT_SYMBOL_GPL(ata_std_ports); | 6494 | EXPORT_SYMBOL_GPL(ata_std_ports); |
6448 | EXPORT_SYMBOL_GPL(ata_host_init); | 6495 | EXPORT_SYMBOL_GPL(ata_host_init); |
6496 | EXPORT_SYMBOL_GPL(ata_host_start); | ||
6449 | EXPORT_SYMBOL_GPL(ata_device_add); | 6497 | EXPORT_SYMBOL_GPL(ata_device_add); |
6450 | EXPORT_SYMBOL_GPL(ata_host_detach); | 6498 | EXPORT_SYMBOL_GPL(ata_host_detach); |
6451 | EXPORT_SYMBOL_GPL(ata_sg_init); | 6499 | EXPORT_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 |
733 | extern int ata_pci_clear_simplex(struct pci_dev *pdev); | 734 | extern int ata_pci_clear_simplex(struct pci_dev *pdev); |
734 | #endif /* CONFIG_PCI */ | 735 | #endif /* CONFIG_PCI */ |
736 | extern int ata_host_start(struct ata_host *host); | ||
735 | extern int ata_device_add(const struct ata_probe_ent *ent); | 737 | extern int ata_device_add(const struct ata_probe_ent *ent); |
736 | extern void ata_host_detach(struct ata_host *host); | 738 | extern void ata_host_detach(struct ata_host *host); |
737 | extern void ata_host_init(struct ata_host *, struct device *, | 739 | extern void ata_host_init(struct ata_host *, struct device *, |