Skip to contentSkip to conversation

libata: implement new initialization model, take #3

PATCH New Tejun Heo 4 participants 27 messages Mar 9, 2007 – Mar 14, 2007

Subsystems (2)
lore
Share & tools
lore

Tejun Heo

author
#0 lore raw

PATCH 1/1 libata: implement new initialization model, take #3

Hello, all.

This is the third take of new init model. Previously, libata LLDs should have filled probe_ent with appropriate info and pass it to ata_device_add() which will allocate and initialize ata_host accordingly, request IRQs and attache the host.

The problem with the previous approach was that the info which can be passed via probe_ent is inflexible. This made init path of peculiar controllers twisted. For example, sata_promise and sata_via support heterogeneous configuration where PATA and SATA ports reside on the same host. As probe_ent couldn't carry this information to ata_device_add(), those controllers had to override stuff in ->port_start() and add branches in various places.

New init model is a bit more conventional than the old one. It follows the good old allocate-init-attach model. A LLD allocates a host populated with the specified number of ports, initializes the host as it wishes and tell libata to attach the initialized host. So, LLDs can intialize the host anyway it wants to.

Helpers to do a series of things in one go are provided such that simple/common initialization can be performed easily. Requesting IRQ is now LLD's responsibility and libata knows nothing about it (except in activation helper). This nicely allows MSIX support if ever needed.

This patchset increases code in libata core layer but makes LLDs simpler. For details, please read description in each patch.

As devres is now in place, libata core layer can offload resource management to it. This makes this take very different and much simpler than the last take[L]. As it's a vastly different implementation, detailed change list isn't very meaningful and thus omitted.

This patchset is against...

libata-dev#upstream (bbaa9bb11c6854781ac13c64954f42bc0e067c09)
+ [1] libata-fix-ata_host_release-free-order
+ [2] libata-fix-native-mode-disabled-port-handling
+ [3] iomap-implement-pcim-iounmap-regions
+ [4] ahci-separate-port-number-determination-from-host-initialization

Thanks.

--
tejun

[L] http://thread.gmane.org/gmane.linux.ide/12741
[1] http://article.gmane.org/gmane.linux.ide/16802
[2] http://article.gmane.org/gmane.linux.ide/16804
[3] http://article.gmane.org/gmane.linux.ide/16805
[4] http://article.gmane.org/gmane.linux.ide/16806

author
#1 lore raw

PATCH 1/12 libata: allocate ap separately from shost

Don't embed ap inside shost. Allocate it separately and point it back from shosts's hostdata. This makes port allocation more flexible and allows regular ATA and SAS share host alloc/init paths.

---
 drivers/ata/libata-core.c |   15 +++++++++++----
 include/linux/libata.h    |    2 +-
 2 files changed, 12 insertions(+), 5 deletions(-)
drivers/ata/libata-core.c +11 -4
index 6e124bd..fab488c 100644
@@ -5646,14 +5646,17 @@ static struct ata_port * ata_port_add(const struct ata_probe_ent *ent,
 		return NULL;
 	}
 
-	shost = scsi_host_alloc(ent->sht, sizeof(struct ata_port));
+	ap = kzalloc(sizeof(struct ata_port), GFP_KERNEL);
+	if (!ap)
+		return NULL;
+
+	shost = scsi_host_alloc(ent->sht, sizeof(struct ata_port *));
 	if (!shost)
 		return NULL;
 
+	*(struct ata_port **)&shost->hostdata[0] = ap;
 	shost->transportt = &ata_scsi_transport_template;
 
-	ap = ata_shost_to_port(shost);
-
 	ata_port_init(ap, host, ent, port_no);
 	ata_port_init_shost(ap, shost);
 
@@ -5678,9 +5681,13 @@ static void ata_host_release(struct device *gendev, void *res)
 	for (i = 0; i < host->n_ports; i++) {
 		struct ata_port *ap = host->ports[i];
 
-		if (ap)
+		if (!ap)
+			continue;
+
+		if (ap->scsi_host)
 			scsi_host_put(ap->scsi_host);
 
+		kfree(ap);
 		host->ports[i] = NULL;
 	}
 
include/linux/libata.h +1 -1
index 911ac4e..cfdc617 100644
@@ -1221,7 +1221,7 @@ static inline void ata_pad_free(struct ata_port *ap, struct device *dev)
 
 static inline struct ata_port *ata_shost_to_port(struct Scsi_Host *host)
 {
-	return (struct ata_port *) &host->hostdata[0];
+	return *(struct ata_port **)&host->hostdata[0];
 }
 
 #endif /* __LINUX_LIBATA_H__ */
Signature · 1 line
1.5.0.1
#2 lore raw

Re: [PATCH 01/12] libata: allocate ap separately from shost

Quoted 16 lines · Tejun Heo

Don't embed ap inside shost. Allocate it separately and point it back from shosts's hostdata. This makes port allocation more flexible and allows regular ATA and SAS share host alloc/init paths.

---
 drivers/ata/libata-core.c |   15 +++++++++++----
 include/linux/libata.h    |    2 +-
 2 files changed, 12 insertions(+), 5 deletions(-)
drivers/ata/libata-core.c +0 -0
index 6e124bd..fab488c 100644
@@ -5646,14 +5646,17 @@ static struct ata_port * ata_port_add(const struct ata_probe_ent *ent,
 		return NULL;

drivers/ata/libata-core.c static struct ata_port * ata_port_add(const struct ata_probe_ent *ent, · line 5655

Quoted 10 lines
drivers/ata/libata-core.c +5 -1
 	}
 
-	shost = scsi_host_alloc(ent->sht, sizeof(struct ata_port));
+	ap = kzalloc(sizeof(struct ata_port), GFP_KERNEL);
+	if (!ap)
+		return NULL;
+
+	shost = scsi_host_alloc(ent->sht, sizeof(struct ata_port *));
 	if (!shost)
 		return NULL;

memory leak on error

otherwise OK

author
#3 lore raw

PATCH 2/12 libata: separate out ata_host_start()

In reply to Tejun Heo

Separate out ata_host_start() from ata_device_add(). ata_host_start() calls ->port_start on each port if available and freezes the port.

---
 drivers/ata/libata-core.c |   74 +++++++++++++++++++++++++++++++++++++--------
 include/linux/libata.h    |    2 +
 2 files changed, 63 insertions(+), 13 deletions(-)
drivers/ata/libata-core.c +61 -13
index fab488c..6a4e7a4 100644
@@ -5671,11 +5671,14 @@ static void ata_host_release(struct device *gendev, void *res)
 	for (i = 0; i < host->n_ports; i++) {
 		struct ata_port *ap = host->ports[i];
 
-		if (ap && ap->ops->port_stop)
+		if (!ap)
+			continue;
+
+		if ((host->flags & ATA_HOST_STARTED) && ap->ops->port_stop)
 			ap->ops->port_stop(ap);
 	}
 
-	if (host->ops->host_stop)
+	if ((host->flags & ATA_HOST_STARTED) && host->ops->host_stop)
 		host->ops->host_stop(host);
 
 	for (i = 0; i < host->n_ports; i++) {
@@ -5695,6 +5698,56 @@ static void ata_host_release(struct device *gendev, void *res)
 }
 
 /**
+ *	ata_host_start - start and freeze ports of an ATA host
+ *	@host: ATA host to start ports for
+ *
+ *	Start and then freeze ports of @host.  Started status is
+ *	recorded in host->flags, so this function can be called
+ *	multiple times.  Ports are guaranteed to get started only
+ *	once.
+ *
+ *	LOCKING:
+ *	Inherited from calling layer (may sleep).
+ *
+ *	RETURNS:
+ *	0 if all ports are started successfully, -errno otherwise.
+ */
+int ata_host_start(struct ata_host *host)
+{
+	int i, rc;
+
+	if (host->flags & ATA_HOST_STARTED)
+		return 0;
+
+	for (i = 0; i < host->n_ports; i++) {
+		struct ata_port *ap = host->ports[i];
+
+		if (ap->ops->port_start) {
+			rc = ap->ops->port_start(ap);
+			if (rc) {
+				ata_port_printk(ap, KERN_ERR, "failed to "
+						"start port (errno=%d)\n", rc);
+				goto err_out;
+			}
+		}
+
+		ata_eh_freeze_port(ap);
+	}
+
+	host->flags |= ATA_HOST_STARTED;
+	return 0;
+
+ err_out:
+	while (--i >= 0) {
+		struct ata_port *ap = host->ports[i];
+
+		if (ap->ops->port_stop)
+			ap->ops->port_stop(ap);
+	}
+	return rc;
+}
+
+/**
  *	ata_sas_host_init - Initialize a host struct
  *	@host:	host to initialize
  *	@dev:	device host is attached to
@@ -5783,14 +5836,6 @@ int ata_device_add(const struct ata_probe_ent *ent)
 			continue;
 		}
 
-		/* start port */
-		rc = ap->ops->port_start(ap);
-		if (rc) {
-			host->ports[i] = NULL;
-			scsi_host_put(ap->scsi_host);
-			goto err_out;
-		}
-
 		/* Report the secondary IRQ for second channel legacy */
 		if (i == 1 && ent->irq2)
 			irq_line = ent->irq2;
@@ -5808,11 +5853,13 @@ int ata_device_add(const struct ata_probe_ent *ent)
 				ap->ioaddr.ctl_addr,
 				ap->ioaddr.bmdma_addr,
 				irq_line);
-
-		/* freeze port before requesting IRQ */
-		ata_eh_freeze_port(ap);
 	}
 
+	/* start ports */
+	rc = ata_host_start(host);
+	if (rc)
+		goto err_out;
+
 	/* obtain irq, that may be shared between channels */
 	rc = devm_request_irq(dev, ent->irq, ent->port_ops->irq_handler,
 			      ent->irq_flags, DRV_NAME, host);
@@ -6367,6 +6414,7 @@ EXPORT_SYMBOL_GPL(ata_dummy_port_ops);
 EXPORT_SYMBOL_GPL(ata_std_bios_param);
 EXPORT_SYMBOL_GPL(ata_std_ports);
 EXPORT_SYMBOL_GPL(ata_host_init);
+EXPORT_SYMBOL_GPL(ata_host_start);
 EXPORT_SYMBOL_GPL(ata_device_add);
 EXPORT_SYMBOL_GPL(ata_host_detach);
 EXPORT_SYMBOL_GPL(ata_sg_init);
include/linux/libata.h +2 -0
index cfdc617..296c9ef 100644
@@ -210,6 +210,7 @@ enum {
 
 	/* host set flags */
 	ATA_HOST_SIMPLEX	= (1 << 0),	/* Host is simplex, one DMA channel per host only */
+	ATA_HOST_STARTED	= (1 << 1),	/* Host started */
 
 	/* various lengths of time */
 	ATA_TMOUT_BOOT		= 30 * HZ,	/* heuristic */
@@ -727,6 +728,7 @@ extern int ata_pci_device_resume(struct pci_dev *pdev);
 #endif
 extern int ata_pci_clear_simplex(struct pci_dev *pdev);
 #endif /* CONFIG_PCI */
+extern int ata_host_start(struct ata_host *host);
 extern int ata_device_add(const struct ata_probe_ent *ent);
 extern void ata_host_detach(struct ata_host *host);
 extern void ata_host_init(struct ata_host *, struct device *,
Signature · 1 line
1.5.0.1
author
#4 lore raw

PATCH 3/12 libata: separate out ata_host_alloc() and ata_host_attach()

In reply to Tejun Heo

Reorganize ata_host_alloc() and its subroutines into the following three functions.

* ata_host_alloc() : allocates host and its attached ports. shost is not attached automatically.

* ata_scsi_add_hosts() : allocates and adds shosts associated with an ATA host. Used by ata_host_attach().

* ata_host_attach() : takes a fully initialized ata_host structure and registers it to libata layer and probes it.

Only ata_host_alloc() and ata_host_attach() are exported. ata_device_add() is rewritten using the above functions. This patch does not introduce any observable behavior change. Things worth mentioning.

* print_id is assigned at attach time and LLDs are allowed to overallocate ports and reduce host->n_ports during initialization. ata_host_attach() will throw away unused ports automatically.

* All SCSI host initialization stuff now resides in ata_scsi_add_hosts() in libata-scsi.c, where it should be.

* ipr is now the only user of ata_host_init(). Either kill it by converting ipr to use ata_host_alloc() and friends or rename and move it to libata-scsi.c

---
 drivers/ata/libata-core.c |  469 +++++++++++++++++++++++++--------------------
 drivers/ata/libata-scsi.c |   68 ++++++--
 drivers/ata/libata.h      |    8 +-
 include/linux/libata.h    |    3 +
 4 files changed, 326 insertions(+), 222 deletions(-)
drivers/ata/libata-core.c +263 -206
index 6a4e7a4..b95618d 100644
@@ -72,7 +72,7 @@ static unsigned int ata_dev_init_params(struct ata_device *dev,
 static unsigned int ata_dev_set_xfermode(struct ata_device *dev);
 static void ata_dev_xfermask(struct ata_device *dev);
 
-static unsigned int ata_print_id = 1;
+unsigned int ata_print_id = 1;
 static struct workqueue_struct *ata_wq;
 
 struct workqueue_struct *ata_aux_wq;
@@ -5520,42 +5520,35 @@ void ata_dev_init(struct ata_device *dev)
 }
 
 /**
- *	ata_port_init - Initialize an ata_port structure
- *	@ap: Structure to initialize
- *	@host: Collection of hosts to which @ap belongs
- *	@ent: Probe information provided by low-level driver
- *	@port_no: Port number associated with this ata_port
+ *	ata_port_alloc - allocate and initialize basic ATA port resources
+ *	@host: ATA host this allocated port belongs to
  *
- *	Initialize a new ata_port structure.
+ *	Allocate and initialize basic ATA port resources.
+ *
+ *	RETURNS:
+ *	Allocate ATA port on success, NULL on failure.
  *
  *	LOCKING:
- *	Inherited from caller.
+ *	Inherited from calling layer (may sleep).
  */
-void ata_port_init(struct ata_port *ap, struct ata_host *host,
-		   const struct ata_probe_ent *ent, unsigned int port_no)
+struct ata_port *ata_port_alloc(struct ata_host *host)
 {
+	struct ata_port *ap;
 	unsigned int i;
 
+	DPRINTK("ENTER\n");
+
+	ap = kzalloc(sizeof(*ap), GFP_KERNEL);
+	if (!ap)
+		return NULL;
+
 	ap->lock = &host->lock;
 	ap->flags = ATA_FLAG_DISABLED;
-	ap->print_id = ata_print_id++;
+	ap->print_id = -1;
 	ap->ctl = ATA_DEVCTL_OBS;
 	ap->host = host;
-	ap->dev = ent->dev;
-	ap->port_no = port_no;
-	if (port_no == 1 && ent->pinfo2) {
-		ap->pio_mask = ent->pinfo2->pio_mask;
-		ap->mwdma_mask = ent->pinfo2->mwdma_mask;
-		ap->udma_mask = ent->pinfo2->udma_mask;
-		ap->flags |= ent->pinfo2->flags;
-		ap->ops = ent->pinfo2->port_ops;
-	} else {
-		ap->pio_mask = ent->pio_mask;
-		ap->mwdma_mask = ent->mwdma_mask;
-		ap->udma_mask = ent->udma_mask;
-		ap->flags |= ent->port_flags;
-		ap->ops = ent->port_ops;
-	}
+	ap->dev = host->dev;
+
 	ap->hw_sata_spd_limit = UINT_MAX;
 	ap->active_tag = ATA_TAG_POISON;
 	ap->last_ctl = 0xFF;
@@ -5575,10 +5568,7 @@ void ata_port_init(struct ata_port *ap, struct ata_host *host,
 	INIT_LIST_HEAD(&ap->eh_done_q);
 	init_waitqueue_head(&ap->eh_wait_q);
 
-	/* set cable type */
 	ap->cbl = ATA_CBL_NONE;
-	if (ap->flags & ATA_FLAG_SATA)
-		ap->cbl = ATA_CBL_SATA;
 
 	for (i = 0; i < ATA_MAX_DEVICES; i++) {
 		struct ata_device *dev = &ap->device[i];
@@ -5591,75 +5581,6 @@ void ata_port_init(struct ata_port *ap, struct ata_host *host,
 	ap->stats.unhandled_irq = 1;
 	ap->stats.idle_irq = 1;
 #endif
-
-	memcpy(&ap->ioaddr, &ent->port[port_no], sizeof(struct ata_ioports));
-}
-
-/**
- *	ata_port_init_shost - Initialize SCSI host associated with ATA port
- *	@ap: ATA port to initialize SCSI host for
- *	@shost: SCSI host associated with @ap
- *
- *	Initialize SCSI host @shost associated with ATA port @ap.
- *
- *	LOCKING:
- *	Inherited from caller.
- */
-static void ata_port_init_shost(struct ata_port *ap, struct Scsi_Host *shost)
-{
-	ap->scsi_host = shost;
-
-	shost->unique_id = ap->print_id;
-	shost->max_id = 16;
-	shost->max_lun = 1;
-	shost->max_channel = 1;
-	shost->max_cmd_len = 16;
-}
-
-/**
- *	ata_port_add - Attach low-level ATA driver to system
- *	@ent: Information provided by low-level driver
- *	@host: Collections of ports to which we add
- *	@port_no: Port number associated with this host
- *
- *	Attach low-level ATA driver to system.
- *
- *	LOCKING:
- *	PCI/etc. bus probe sem.
- *
- *	RETURNS:
- *	New ata_port on success, for NULL on error.
- */
-static struct ata_port * ata_port_add(const struct ata_probe_ent *ent,
-				      struct ata_host *host,
-				      unsigned int port_no)
-{
-	struct Scsi_Host *shost;
-	struct ata_port *ap;
-
-	DPRINTK("ENTER\n");
-
-	if (!ent->port_ops->error_handler &&
-	    !(ent->port_flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST))) {
-		printk(KERN_ERR "ata%u: no reset mechanism available\n",
-		       port_no);
-		return NULL;
-	}
-
-	ap = kzalloc(sizeof(struct ata_port), GFP_KERNEL);
-	if (!ap)
-		return NULL;
-
-	shost = scsi_host_alloc(ent->sht, sizeof(struct ata_port *));
-	if (!shost)
-		return NULL;
-
-	*(struct ata_port **)&shost->hostdata[0] = ap;
-	shost->transportt = &ata_scsi_transport_template;
-
-	ata_port_init(ap, host, ent, port_no);
-	ata_port_init_shost(ap, shost);
-
 	return ap;
 }
 
@@ -5698,13 +5619,79 @@ static void ata_host_release(struct device *gendev, void *res)
 }
 
 /**
+ *	ata_host_alloc - allocate and init basic ATA host resources
+ *	@dev: generic device this host is associated with
+ *	@max_ports: maximum number of ATA ports associated with this host
+ *
+ *	Allocate and initialize basic ATA host resources.  LLD calls
+ *	this function to allocate a host, initializes it fully and
+ *	attaches it using ata_host_attach().
+ *
+ *	@max_ports ports are allocated and host->n_ports is
+ *	initialized to @max_ports.  The caller is allowed to decrease
+ *	host->n_ports before calling ata_host_attach().  The unused
+ *	ports will be automatically freed on attach.
+ *
+ *	RETURNS:
+ *	Allocate ATA host on success, NULL on failure.
+ *
+ *	LOCKING:
+ *	Inherited from calling layer (may sleep).
+ */
+struct ata_host *ata_host_alloc(struct device *dev, int max_ports)
+{
+	struct ata_host *host;
+	size_t sz;
+	int i;
+
+	DPRINTK("ENTER\n");
+
+	if (!devres_open_group(dev, NULL, GFP_KERNEL))
+		return NULL;
+
+	/* alloc a container for our list of ATA ports (buses) */
+	sz = sizeof(struct ata_host) + (max_ports + 1) * sizeof(void *);
+	/* alloc a container for our list of ATA ports (buses) */
+	host = devres_alloc(ata_host_release, sz, GFP_KERNEL);
+	if (!host)
+		goto err_out;
+
+	devres_add(dev, host);
+	dev_set_drvdata(dev, host);
+
+	spin_lock_init(&host->lock);
+	host->dev = dev;
+	host->n_ports = max_ports;
+
+	/* allocate ports bound to this host */
+	for (i = 0; i < max_ports; i++) {
+		struct ata_port *ap;
+
+		ap = ata_port_alloc(host);
+		if (!ap)
+			goto err_out;
+
+		ap->port_no = i;
+		host->ports[i] = ap;
+	}
+
+	devres_remove_group(dev, NULL);
+	return host;
+
+ err_out:
+	devres_release_group(dev, NULL);
+	return NULL;
+}
+
+/**
  *	ata_host_start - start and freeze ports of an ATA host
  *	@host: ATA host to start ports for
  *
  *	Start and then freeze ports of @host.  Started status is
  *	recorded in host->flags, so this function can be called
  *	multiple times.  Ports are guaranteed to get started only
- *	once.
+ *	once.  If host->ops isn't initialized yet, its set to the
+ *	first non-dummy port ops.
  *
  *	LOCKING:
  *	Inherited from calling layer (may sleep).
@@ -5722,6 +5709,9 @@ int ata_host_start(struct ata_host *host)
 	for (i = 0; i < host->n_ports; i++) {
 		struct ata_port *ap = host->ports[i];
 
+		if (!host->ops && !ata_port_is_dummy(ap))
+			host->ops = ap->ops;
+
 		if (ap->ops->port_start) {
 			rc = ap->ops->port_start(ap);
 			if (rc) {
@@ -5758,7 +5748,7 @@ int ata_host_start(struct ata_host *host)
  *	PCI/etc. bus probe sem.
  *
  */
-
+/* KILLME - the only user left is ipr */
 void ata_host_init(struct ata_host *host, struct device *dev,
 		   unsigned long flags, const struct ata_port_operations *ops)
 {
@@ -5769,6 +5759,143 @@ void ata_host_init(struct ata_host *host, struct device *dev,
 }
 
 /**
+ *	ata_host_attach - attach initialized ATA host
+ *	@host: ATA host to attach
+ *	@sht: template for SCSI host
+ *
+ *	Attach initialized ATA host.  @host is allocated using
+ *	ata_host_alloc() and fully initialized by LLD.  This function
+ *	starts ports, registers @host with ATA and SCSI layers and
+ *	probe attached devices.
+ *
+ *	LOCKING:
+ *	Inherited from calling layer (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno otherwise.
+ */
+int ata_host_attach(struct ata_host *host, struct scsi_host_template *sht)
+{
+	int i, rc;
+
+	/* host must have been started */
+	if (!(host->flags & ATA_HOST_STARTED)) {
+		dev_printk(KERN_ERR, host->dev,
+			   "BUG: trying to attach unstarted host\n");
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	/* Blow away unused ports.  This happens when LLD can't
+	 * determine the exact number of ports to allocate at
+	 * allocation time.
+	 */
+	for (i = host->n_ports; host->ports[i]; i++)
+		kfree(host->ports[i]);
+
+	/* give ports names and add SCSI hosts */
+	for (i = 0; i < host->n_ports; i++)
+		host->ports[i]->print_id = ata_print_id++;
+
+	rc = ata_scsi_add_hosts(host, sht);
+	if (rc)
+		return rc;
+
+	/* set cable, sata_spd_limit and report */
+	for (i = 0; i < host->n_ports; i++) {
+		struct ata_port *ap = host->ports[i];
+		int irq_line;
+		u32 scontrol;
+		unsigned long xfer_mask;
+
+		/* set SATA cable type if still unset */
+		if (ap->cbl == ATA_CBL_NONE && (ap->flags & ATA_FLAG_SATA))
+			ap->cbl = ATA_CBL_SATA;
+
+		/* init sata_spd_limit to the current value */
+		if (sata_scr_read(ap, SCR_CONTROL, &scontrol) == 0) {
+			int spd = (scontrol >> 4) & 0xf;
+			ap->hw_sata_spd_limit &= (1 << spd) - 1;
+		}
+		ap->sata_spd_limit = ap->hw_sata_spd_limit;
+
+		/* report the secondary IRQ for second channel legacy */
+		irq_line = host->irq;
+		if (i == 1 && host->irq2)
+			irq_line = host->irq2;
+
+		xfer_mask = ata_pack_xfermask(ap->pio_mask, ap->mwdma_mask,
+					      ap->udma_mask);
+
+		/* print per-port info to dmesg */
+		if (!ata_port_is_dummy(ap))
+			ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%p "
+					"ctl 0x%p bmdma 0x%p irq %d\n",
+					ap->cbl == ATA_CBL_SATA ? 'S' : 'P',
+					ata_mode_string(xfer_mask),
+					ap->ioaddr.cmd_addr,
+					ap->ioaddr.ctl_addr,
+					ap->ioaddr.bmdma_addr,
+					irq_line);
+		else
+			ata_port_printk(ap, KERN_INFO, "DUMMY\n");
+	}
+
+	/* perform each probe synchronously */
+	DPRINTK("probe begin\n");
+	for (i = 0; i < host->n_ports; i++) {
+		struct ata_port *ap = host->ports[i];
+		int rc;
+
+		/* probe */
+		if (ap->ops->error_handler) {
+			struct ata_eh_info *ehi = &ap->eh_info;
+			unsigned long flags;
+
+			ata_port_probe(ap);
+
+			/* kick EH for boot probing */
+			spin_lock_irqsave(ap->lock, flags);
+
+			ehi->probe_mask = (1 << ATA_MAX_DEVICES) - 1;
+			ehi->action |= ATA_EH_SOFTRESET;
+			ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
+
+			ap->pflags |= ATA_PFLAG_LOADING;
+			ata_port_schedule_eh(ap);
+
+			spin_unlock_irqrestore(ap->lock, flags);
+
+			/* wait for EH to finish */
+			ata_port_wait_eh(ap);
+		} else {
+			DPRINTK("ata%u: bus probe begin\n", ap->print_id);
+			rc = ata_bus_probe(ap);
+			DPRINTK("ata%u: bus probe end\n", ap->print_id);
+
+			if (rc) {
+				/* FIXME: do something useful here?
+				 * Current libata behavior will
+				 * tear down everything when
+				 * the module is removed
+				 * or the h/w is unplugged.
+				 */
+			}
+		}
+	}
+
+	/* probes are done, now scan each port's disk(s) */
+	DPRINTK("host probe begin\n");
+	for (i = 0; i < host->n_ports; i++) {
+		struct ata_port *ap = host->ports[i];
+
+		ata_scsi_scan_host(ap);
+	}
+
+	return 0;
+}
+
+/**
  *	ata_device_add - Register hardware device with ATA and SCSI layers
  *	@ent: Probe information describing hardware device to be registered
  *
@@ -5800,62 +5927,53 @@ int ata_device_add(const struct ata_probe_ent *ent)
 		return 0;
 	}
 
+	if (!ent->port_ops->error_handler &&
+	    !(ent->port_flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST))) {
+		dev_printk(KERN_ERR, dev, "no reset mechanism available\n");
+		return 0;
+	}
+
 	if (!devres_open_group(dev, ata_device_add, GFP_KERNEL))
 		return 0;
 
-	/* alloc a container for our list of ATA ports (buses) */
-	host = devres_alloc(ata_host_release, sizeof(struct ata_host) +
-			    (ent->n_ports * sizeof(void *)), GFP_KERNEL);
-	if (!host)
-		goto err_out;
-	devres_add(dev, host);
-	dev_set_drvdata(dev, host);
+	/* allocate host */
+	host = ata_host_alloc(dev, ent->n_ports);
 
-	ata_host_init(host, dev, ent->_host_flags, ent->port_ops);
-	host->n_ports = ent->n_ports;
 	host->irq = ent->irq;
 	host->irq2 = ent->irq2;
 	host->iomap = ent->iomap;
 	host->private_data = ent->private_data;
+	host->ops = ent->port_ops;
+	host->flags = ent->_host_flags;
 
-	/* register each port bound to this device */
 	for (i = 0; i < host->n_ports; i++) {
-		struct ata_port *ap;
-		unsigned long xfer_mode_mask;
-		int irq_line = ent->irq;
-
-		ap = ata_port_add(ent, host, i);
-		host->ports[i] = ap;
-		if (!ap)
-			goto err_out;
+		struct ata_port *ap = host->ports[i];
 
 		/* dummy? */
 		if (ent->dummy_port_mask & (1 << i)) {
-			ata_port_printk(ap, KERN_INFO, "DUMMY\n");
 			ap->ops = &ata_dummy_port_ops;
 			continue;
 		}
 
-		/* Report the secondary IRQ for second channel legacy */
-		if (i == 1 && ent->irq2)
-			irq_line = ent->irq2;
-
-		xfer_mode_mask =(ap->udma_mask << ATA_SHIFT_UDMA) |
-				(ap->mwdma_mask << ATA_SHIFT_MWDMA) |
-				(ap->pio_mask << ATA_SHIFT_PIO);
+		if (ap->port_no == 1 && ent->pinfo2) {
+			ap->pio_mask = ent->pinfo2->pio_mask;
+			ap->mwdma_mask = ent->pinfo2->mwdma_mask;
+			ap->udma_mask = ent->pinfo2->udma_mask;
+			ap->flags |= ent->pinfo2->flags;
+			ap->ops = ent->pinfo2->port_ops;
+		} else {
+			ap->pio_mask = ent->pio_mask;
+			ap->mwdma_mask = ent->mwdma_mask;
+			ap->udma_mask = ent->udma_mask;
+			ap->flags |= ent->port_flags;
+			ap->ops = ent->port_ops;
+		}
 
-		/* print per-port info to dmesg */
-		ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%p "
-				"ctl 0x%p bmdma 0x%p irq %d\n",
-				ap->flags & ATA_FLAG_SATA ? 'S' : 'P',
-				ata_mode_string(xfer_mode_mask),
-				ap->ioaddr.cmd_addr,
-				ap->ioaddr.ctl_addr,
-				ap->ioaddr.bmdma_addr,
-				irq_line);
+		memcpy(&ap->ioaddr, &ent->port[ap->port_no],
+		       sizeof(struct ata_ioports));
 	}
 
-	/* start ports */
+	/* start and freeze ports before requesting IRQ */
 	rc = ata_host_start(host);
 	if (rc)
 		goto err_out;
@@ -5888,80 +6006,17 @@ int ata_device_add(const struct ata_probe_ent *ent)
 	/* resource acquisition complete */
 	devres_remove_group(dev, ata_device_add);
 
-	/* perform each probe synchronously */
-	DPRINTK("probe begin\n");
-	for (i = 0; i < host->n_ports; i++) {
-		struct ata_port *ap = host->ports[i];
-		u32 scontrol;
-		int rc;
-
-		/* init sata_spd_limit to the current value */
-		if (sata_scr_read(ap, SCR_CONTROL, &scontrol) == 0) {
-			int spd = (scontrol >> 4) & 0xf;
-			ap->hw_sata_spd_limit &= (1 << spd) - 1;
-		}
-		ap->sata_spd_limit = ap->hw_sata_spd_limit;
-
-		rc = scsi_add_host(ap->scsi_host, dev);
-		if (rc) {
-			ata_port_printk(ap, KERN_ERR, "scsi_add_host failed\n");
-			/* FIXME: do something useful here */
-			/* FIXME: handle unconditional calls to
-			 * scsi_scan_host and ata_host_remove, below,
-			 * at the very least
-			 */
-		}
-
-		if (ap->ops->error_handler) {
-			struct ata_eh_info *ehi = &ap->eh_info;
-			unsigned long flags;
-
-			ata_port_probe(ap);
-
-			/* kick EH for boot probing */
-			spin_lock_irqsave(ap->lock, flags);
-
-			ehi->probe_mask = (1 << ATA_MAX_DEVICES) - 1;
-			ehi->action |= ATA_EH_SOFTRESET;
-			ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
-
-			ap->pflags |= ATA_PFLAG_LOADING;
-			ata_port_schedule_eh(ap);
-
-			spin_unlock_irqrestore(ap->lock, flags);
-
-			/* wait for EH to finish */
-			ata_port_wait_eh(ap);
-		} else {
-			DPRINTK("ata%u: bus probe begin\n", ap->print_id);
-			rc = ata_bus_probe(ap);
-			DPRINTK("ata%u: bus probe end\n", ap->print_id);
-
-			if (rc) {
-				/* FIXME: do something useful here?
-				 * Current libata behavior will
-				 * tear down everything when
-				 * the module is removed
-				 * or the h/w is unplugged.
-				 */
-			}
-		}
-	}
-
-	/* probes are done, now scan each port's disk(s) */
-	DPRINTK("host probe begin\n");
-	for (i = 0; i < host->n_ports; i++) {
-		struct ata_port *ap = host->ports[i];
-
-		ata_scsi_scan_host(ap);
-	}
+	/* attach */
+	rc = ata_host_attach(host, ent->sht);
+	if (rc)
+		goto err_out;
 
-	VPRINTK("EXIT, returning %u\n", ent->n_ports);
-	return ent->n_ports; /* success */
+	VPRINTK("EXIT, returning %u\n", host->n_ports);
+	return host->n_ports; /* success */
 
  err_out:
 	devres_release_group(dev, ata_device_add);
-	VPRINTK("EXIT, returning %d\n", rc);
+	VPRINTK("EXIT, returning 0\n");
 	return 0;
 }
 
@@ -6414,7 +6469,9 @@ EXPORT_SYMBOL_GPL(ata_dummy_port_ops);
 EXPORT_SYMBOL_GPL(ata_std_bios_param);
 EXPORT_SYMBOL_GPL(ata_std_ports);
 EXPORT_SYMBOL_GPL(ata_host_init);
+EXPORT_SYMBOL_GPL(ata_host_alloc);
 EXPORT_SYMBOL_GPL(ata_host_start);
+EXPORT_SYMBOL_GPL(ata_host_attach);
 EXPORT_SYMBOL_GPL(ata_device_add);
 EXPORT_SYMBOL_GPL(ata_host_detach);
 EXPORT_SYMBOL_GPL(ata_sg_init);
drivers/ata/libata-scsi.c +56 -12

98 lines not on this page · raw message

drivers/ata/libata.h +4 -4
index c426714..38949a2 100644
@@ -52,6 +52,7 @@ enum {
 	ATA_DNXFER_QUIET	= (1 << 31),
 };
 
+extern unsigned int ata_print_id;
 extern struct workqueue_struct *ata_aux_wq;
 extern int atapi_enabled;
 extern int atapi_dmadir;
@@ -92,10 +93,9 @@ extern int ata_flush_cache(struct ata_device *dev);
 extern void ata_dev_init(struct ata_device *dev);
 extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg);
 extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg);
-extern void ata_port_init(struct ata_port *ap, struct ata_host *host,
-			  const struct ata_probe_ent *ent, unsigned int port_no);
 extern struct ata_probe_ent *ata_probe_ent_alloc(struct device *dev,
 						 const struct ata_port_info *port);
+extern struct ata_port *ata_port_alloc(struct ata_host *host);
 
 /* libata-acpi.c */
 #ifdef CONFIG_SATA_ACPI
@@ -113,8 +113,8 @@ static inline int ata_acpi_push_id(struct ata_port *ap, unsigned int ix)
 #endif
 
 /* libata-scsi.c */
-extern struct scsi_transport_template ata_scsi_transport_template;
-
+extern int ata_scsi_add_hosts(struct ata_host *host,
+			      struct scsi_host_template *sht);
 extern void ata_scsi_scan_host(struct ata_port *ap);
 extern int ata_scsi_offline_dev(struct ata_device *dev);
 extern void ata_scsi_hotplug(struct work_struct *work);
include/linux/libata.h +3 -0
index 296c9ef..9edb7c7 100644
@@ -728,7 +728,10 @@ extern int ata_pci_device_resume(struct pci_dev *pdev);
 #endif
 extern int ata_pci_clear_simplex(struct pci_dev *pdev);
 #endif /* CONFIG_PCI */
+extern struct ata_host *ata_host_alloc(struct device *dev, int max_ports);
 extern int ata_host_start(struct ata_host *host);
+extern int ata_host_attach(struct ata_host *host,
+			   struct scsi_host_template *sht);
 extern int ata_device_add(const struct ata_probe_ent *ent);
 extern void ata_host_detach(struct ata_host *host);
 extern void ata_host_init(struct ata_host *, struct device *,
Signature · 1 line
1.5.0.1
#5 lore raw

Re: [PATCH 03/12] libata: separate out ata_host_alloc() and ata_host_attach()

Quoted 11 lines · Tejun Heo

Reorganize ata_host_alloc() and its subroutines into the following three functions.

* ata_host_alloc() : allocates host and its attached ports. shost is not attached automatically.

* ata_scsi_add_hosts() : allocates and adds shosts associated with an ATA host. Used by ata_host_attach().

* ata_host_attach() : takes a fully initialized ata_host structure and registers it to libata layer and probes it.

I think it's more common in Linux to use foo_register than foo_attach. attach is more a BSD-ism :)

ACK patches 2-3, modulo the naming comment

#6 lore raw

Re: [PATCH 03/12] libata: separate out ata_host_alloc() and ata_host_attach()

In reply to Tejun Heo
Quoted 3 lines · Tejun Heo

* ipr is now the only user of ata_host_init(). Either kill it by converting ipr to use ata_host_alloc() and friends or rename and move it to libata-scsi.c

One of the problems with converting ipr to use ata_host_alloc and friends is that it then forces ipr to tell libata how many "SATA ports" are possible. On SAS, this number can't really be calculated, since the maximum number of SATA devices which can possibly be cabled to a SAS adapter, particularly with SAS expanders, is a very large number and is not practical for how this is being used in the current implementation. My guess is that aic94xx will have similar issues/concerns.

Brian

Signature · 3 lines
Brian King
eServer Storage I/O
IBM Linux Technology Center
author
#7 lore raw

Re: [PATCH 03/12] libata: separate out ata_host_alloc() and ata_host_attach()

Hello, Brian.

Quoted 5 lines · Brian King
Quoted 3 lines · Tejun Heo

* ipr is now the only user of ata_host_init(). Either kill it by converting ipr to use ata_host_alloc() and friends or rename and move it to libata-scsi.c

Quoted 7 lines

One of the problems with converting ipr to use ata_host_alloc and friends is that it then forces ipr to tell libata how many "SATA ports" are possible. On SAS, this number can't really be calculated, since the maximum number of SATA devices which can possibly be cabled to a SAS adapter, particularly with SAS expanders, is a very large number and is not practical for how this is being used in the current implementation. My guess is that aic94xx will have similar issues/concerns.

I dunno much about SAS integration, so I intentionally left it alone, so this patchset shouldn't change behavior from SAS's point of view. Making host->ports dynamic isn't difficult at all. We can just separate out the ports[] array and make it rcu and supply a few access helpers so that we can adjust its size dynamically.

Association to SCSI host is done via pointer now even for native ATA case, so this should be easier for SAS. What I'm worried about is how EH gets invoked. libata depends on EH to do a lot of things including probing, requesting sense data, etc. How should this work? SAS attached libata port shares EH with the SAS SCSI host, right? How can we connect SAS EH with libata EH and would it be okay for libata EH hold the SCSI EH (thus holding all command execution on the host) to handle ATA exceptions?

Thanks.

Signature · 1 line
tejun
#8 lore raw

Re: [PATCH 03/12] libata: separate out ata_host_alloc() and ata_host_attach()

Quoted 4 lines · Tejun Heo

Association to SCSI host is done via pointer now even for native ATA case, so this should be easier for SAS. What I'm worried about is how EH gets invoked. libata depends on EH to do a lot of things including probing, requesting sense data, etc. How should this work?

For SAS, the scsi_host pointer in the ata port is NULL today, since libata is really not managing the scsi host, the LLDD is. I think the initialization model we want for SAS is a little different than the one you are heading towards on SATA. For SAS, I think we just want to be able to alloc/init and delete/destroy a SATA device a they show up on the transport, without tying it to initialization of the ata host. And this set of patches doesn't necessarily prevent that...

Quoted 1 line

SAS attached libata port shares EH with the SAS SCSI host, right? How can

Right.

Quoted 3 lines

we connect SAS EH with libata EH and would it be okay for libata EH hold the SCSI EH (thus holding all command execution on the host) to handle ATA exceptions?

Currently, ipr calls ata_do_eh from its eh_device_reset_handler function. This seems to work well enough with the testing that I've done, but it would certainly be nice to get to a more layered EH approach, where we could possibly have pluggable error handlers for different device types.

Regarding holding all command execution on the host while performing eh, that doesn't seem to be a huge issue from my perspective, not sure if this would have a larger negative impact on others... Generally speaking, we shouldn't be entering eh very often, and it should only be happening if something went wrong. The biggest issue here might be ATAPI devices, since they tend to report more errors during normal running. The request sense for these devices for SAS is done without entering eh today. Would you want to move this into eh as well?

Brian

Signature · 3 lines
Brian King
eServer Storage I/O
IBM Linux Technology Center
author
#9 lore raw

Re: [PATCH 03/12] libata: separate out ata_host_alloc() and ata_host_attach()

Hello, Brian.

Quoted 6 lines · Brian King
Quoted 4 lines · Tejun Heo

Association to SCSI host is done via pointer now even for native ATA case, so this should be easier for SAS. What I'm worried about is how EH gets invoked. libata depends on EH to do a lot of things including probing, requesting sense data, etc. How should this work?

Quoted 7 lines

For SAS, the scsi_host pointer in the ata port is NULL today, since libata is really not managing the scsi host, the LLDD is. I think the initialization model we want for SAS is a little different than the one you are heading towards on SATA. For SAS, I think we just want to be able to alloc/init and delete/destroy a SATA device a they show up on the transport, without tying it to initialization of the ata host. And this set of patches doesn't necessarily prevent that...

Yeap, I tried to keep SAS bridge functions working. If SAS doesn't need the host abstraction and wanna do stuff per-port basis, ata_port_alloc() can be directly exported and separating out per-port register routine shouldn't be too difficult, but I do think it would still be beneficial to have ata_host structure in SAS case too for code simplicity if not for anything else.

Quoted 4 lines
Quoted 1 line

SAS attached libata port shares EH with the SAS SCSI host, right? How can

Right.

Quoted 8 lines
Quoted 3 lines

we connect SAS EH with libata EH and would it be okay for libata EH hold the SCSI EH (thus holding all command execution on the host) to handle ATA exceptions?

Currently, ipr calls ata_do_eh from its eh_device_reset_handler function. This seems to work well enough with the testing that I've done, but it would certainly be nice to get to a more layered EH approach, where we could possibly have pluggable error handlers for different device types.

That's an unexpected usage of ata_do_eh() but I can see how that works and using ata_do_eh() for that purpose actually makes sense. Most SCSI related dancing is done before and after ata_do_eh() and ata_do_eh() only deals with ATA qc's (except for scsi_eh_finish_cmd() called to finish failed qc's but these are still for only scmds associated with qcs).

In the future, we might need to separate those direct scsi_eh_finish_cmd() calls out of ata_do_eh() so that ata_do_eh() really deals with libata qc proper but that change shouldn't be too difficult for SAS.

Quoted 8 lines

Regarding holding all command execution on the host while performing eh, that doesn't seem to be a huge issue from my perspective, not sure if this would have a larger negative impact on others... Generally speaking, we shouldn't be entering eh very often, and it should only be happening if something went wrong. The biggest issue here might be ATAPI devices, since they tend to report more errors during normal running. The request sense for these devices for SAS is done without entering eh today. Would you want to move this into eh as well?

No, not for SAS. The reasons why I put sense requesting to EH were...

1. to make fast path code straight forward (no qc reusing dance)

2. in native ATA, we have per-port EH thread so sharing is not a problem.

As #2 is not true in SAS case, I think keeping sense requesting out of EH is the right thing to do here. I still think that it's much simpler/reliable to handle any exception case in a separate thread. I think this in the long term should be solved by making EH per-request queue (we of course will need mechanism to synchronize several EHs so that we can take host-wide EH actions).

Thanks.

Signature · 1 line
tejun
#10 lore raw

Re: [PATCH 03/12] libata: separate out ata_host_alloc() and ata_host_attach()

Quoted 9 lines · Tejun Heo
Quoted 7 lines · Brian King

For SAS, the scsi_host pointer in the ata port is NULL today, since libata is really not managing the scsi host, the LLDD is. I think the initialization model we want for SAS is a little different than the one you are heading towards on SATA. For SAS, I think we just want to be able to alloc/init and delete/destroy a SATA device a they show up on the transport, without tying it to initialization of the ata host. And this set of patches doesn't necessarily prevent that...

Quoted 6 lines

Yeap, I tried to keep SAS bridge functions working. If SAS doesn't need the host abstraction and wanna do stuff per-port basis, ata_port_alloc() can be directly exported and separating out per-port register routine shouldn't be too difficult, but I do think it would still be beneficial to have ata_host structure in SAS case too for code simplicity if not for anything else.

I think having the ata_host structure for SAS is fine. It's just a matter of how much of what ends up in it actually gets used for SAS.

Quoted 13 lines
Quoted 8 lines

Regarding holding all command execution on the host while performing eh, that doesn't seem to be a huge issue from my perspective, not sure if this would have a larger negative impact on others... Generally speaking, we shouldn't be entering eh very often, and it should only be happening if something went wrong. The biggest issue here might be ATAPI devices, since they tend to report more errors during normal running. The request sense for these devices for SAS is done without entering eh today. Would you want to move this into eh as well?

No, not for SAS. The reasons why I put sense requesting to EH were...

1. to make fast path code straight forward (no qc reusing dance)

Quoted 8 lines

2. in native ATA, we have per-port EH thread so sharing is not a problem.

As #2 is not true in SAS case, I think keeping sense requesting out of EH is the right thing to do here. I still think that it's much simpler/reliable to handle any exception case in a separate thread. I think this in the long term should be solved by making EH per-request queue (we of course will need mechanism to synchronize several EHs so that we can take host-wide EH actions).

Agreed.

Brian

Signature · 3 lines
Brian King
eServer Storage I/O
IBM Linux Technology Center
author
#11 lore raw

PATCH 4/12 libata: implement ata_host_alloc_pinfo() and ata_host_attach()

In reply to Tejun Heo

Implement ata_host_alloc_pinfo() and ata_host_attach(). These helpers will be used in the following patches to adopt new init model.

---
 drivers/ata/libata-core.c |   93 +++++++++++++++++++++++++++++++++++++++++++++
 include/linux/libata.h    |    5 ++
 2 files changed, 98 insertions(+), 0 deletions(-)
drivers/ata/libata-core.c +93 -0
index b95618d..97e7d9c 100644
@@ -5684,6 +5684,55 @@ struct ata_host *ata_host_alloc(struct device *dev, int max_ports)
 }
 
 /**
+ *	ata_host_alloc_pinfo - alloc host and init with port_info array
+ *	@dev: generic device this host is associated with
+ *	@ppi: array of ATA port_info to initialize host with
+ *	@n_ports: number of ATA ports attached to this host
+ *
+ *	Allocate ATA host and initialize with info from @ppi.  If NULL
+ *	terminated, @ppi may contain fewer entries than @n_ports.  The
+ *	last entry will be used for the remaining ports.
+ *
+ *	RETURNS:
+ *	Allocate ATA host on success, NULL on failure.
+ *
+ *	LOCKING:
+ *	Inherited from calling layer (may sleep).
+ */
+struct ata_host *ata_host_alloc_pinfo(struct device *dev,
+				      const struct ata_port_info * const * ppi,
+				      int n_ports)
+{
+	const struct ata_port_info *pi;
+	struct ata_host *host;
+	int i, j;
+
+	host = ata_host_alloc(dev, n_ports);
+	if (!host)
+		return NULL;
+
+	for (i = 0, j = 0, pi = NULL; i < host->n_ports; i++) {
+		struct ata_port *ap = host->ports[i];
+
+		if (ppi[j])
+			pi = ppi[j++];
+
+		ap->pio_mask = pi->pio_mask;
+		ap->mwdma_mask = pi->mwdma_mask;
+		ap->udma_mask = pi->udma_mask;
+		ap->flags |= pi->flags;
+		ap->ops = pi->port_ops;
+
+		if (!host->ops && (pi->port_ops != &ata_dummy_port_ops))
+			host->ops = pi->port_ops;
+		if (!host->private_data && pi->private_data)
+			host->private_data = pi->private_data;
+	}
+
+	return host;
+}
+
+/**
  *	ata_host_start - start and freeze ports of an ATA host
  *	@host: ATA host to start ports for
  *
@@ -5896,6 +5945,48 @@ int ata_host_attach(struct ata_host *host, struct scsi_host_template *sht)
 }
 
 /**
+ *	ata_host_activate - start host, request IRQ and attach it
+ *	@host: target ATA host
+ *	@irq: IRQ to request
+ *	@irq_handler: irq_handler used when requesting IRQ
+ *	@irq_flags: irq_flags used when requesting IRQ
+ *	@sht: scsi_host_template to use when attaching the host
+ *
+ *	After allocating an ATA host and initializing it, most libata
+ *	LLDs perform three steps to activate the host - start host,
+ *	request IRQ and attach it.  This helper takes necessasry
+ *	arguments and performs the three steps in one go.
+ *
+ *	LOCKING:
+ *	Inherited from calling layer (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno otherwise.
+ */
+int ata_host_activate(struct ata_host *host, int irq,
+		      irq_handler_t irq_handler, unsigned long irq_flags,
+		      struct scsi_host_template *sht)
+{
+	int rc;
+
+	rc = ata_host_start(host);
+	if (rc)
+		return rc;
+
+	rc = devm_request_irq(host->dev, irq, irq_handler, irq_flags,
+			      dev_driver_string(host->dev), host);
+	if (rc)
+		return rc;
+
+	rc = ata_host_attach(host, sht);
+	/* if failed, just free the IRQ and leave ports alone */
+	if (rc)
+		devm_free_irq(host->dev, irq, host);
+
+	return rc;
+}
+
+/**
  *	ata_device_add - Register hardware device with ATA and SCSI layers
  *	@ent: Probe information describing hardware device to be registered
  *
@@ -6470,8 +6561,10 @@ EXPORT_SYMBOL_GPL(ata_std_bios_param);
 EXPORT_SYMBOL_GPL(ata_std_ports);
 EXPORT_SYMBOL_GPL(ata_host_init);
 EXPORT_SYMBOL_GPL(ata_host_alloc);
+EXPORT_SYMBOL_GPL(ata_host_alloc_pinfo);
 EXPORT_SYMBOL_GPL(ata_host_start);
 EXPORT_SYMBOL_GPL(ata_host_attach);
+EXPORT_SYMBOL_GPL(ata_host_activate);
 EXPORT_SYMBOL_GPL(ata_device_add);
 EXPORT_SYMBOL_GPL(ata_host_detach);
 EXPORT_SYMBOL_GPL(ata_sg_init);
include/linux/libata.h +5 -0
index 9edb7c7..202ed7a 100644
@@ -729,9 +729,14 @@ extern int ata_pci_device_resume(struct pci_dev *pdev);
 extern int ata_pci_clear_simplex(struct pci_dev *pdev);
 #endif /* CONFIG_PCI */
 extern struct ata_host *ata_host_alloc(struct device *dev, int max_ports);
+extern struct ata_host *ata_host_alloc_pinfo(struct device *dev,
+			const struct ata_port_info * const * ppi, int n_ports);
 extern int ata_host_start(struct ata_host *host);
 extern int ata_host_attach(struct ata_host *host,
 			   struct scsi_host_template *sht);
+extern int ata_host_activate(struct ata_host *host, int irq,
+			     irq_handler_t irq_handler, unsigned long irq_flags,
+			     struct scsi_host_template *sht);
 extern int ata_device_add(const struct ata_probe_ent *ent);
 extern void ata_host_detach(struct ata_host *host);
 extern void ata_host_init(struct ata_host *, struct device *,
Signature · 1 line
1.5.0.1
#12 lore raw

Re: [PATCH 04/12] libata: implement ata_host_alloc_pinfo() and ata_host_attach()

Quoted 8 lines · Tejun Heo

Implement ata_host_alloc_pinfo() and ata_host_attach(). These helpers will be used in the following patches to adopt new init model.

---
 drivers/ata/libata-core.c |   93 +++++++++++++++++++++++++++++++++++++++++++++
 include/linux/libata.h    |    5 ++
 2 files changed, 98 insertions(+), 0 deletions(-)

ACK if s/attach/register/

author
#13 lore raw

PATCH 5/12 libata: convert legacy PCI host handling to new init model

In reply to Tejun Heo

Convert legacy PCI host handling to alloc-init-attach model. ata_init_legacy_host(), ata_request_legacy_irqs() and ata_pci_init_bmdma() are separated out and follow the new init model.

The two legacy handling functions use separate ata_legacy_devres instead of generic devm_* resources. This reduces devres overhead for legacy hosts which was a bit high because it didn't use PCI/iomap merged resoruces.

ata_pci_init_one() is rewritten in terms of the aboved functions but native mode handling is still using the old method. Conversion will be completed when native mode handling is updated.

---
 drivers/ata/libata-sff.c |  436 +++++++++++++++++++++++++++++++++-------------
 1 files changed, 312 insertions(+), 124 deletions(-)
drivers/ata/libata-sff.c +312 -124
index dfd906c..8287df5 100644
@@ -627,75 +627,278 @@ ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int
 	return probe_ent;
 }
 
-static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev,
-				struct ata_port_info **port, int port_mask)
+/**
+ *	ata_pci_init_bmdma - acquire PCI BMDMA resources and init ATA host
+ *	@host: target ATA host
+ *
+ *	Acquire PCI BMDMA resources and initialize @host accordingly.
+ *
+ *	LOCKING:
+ *	Inherited from calling layer (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno otherwise.
+ */
+static int ata_pci_init_bmdma(struct ata_host *host)
 {
-	struct ata_probe_ent *probe_ent;
-	void __iomem *iomap[5] = { }, *bmdma;
+	struct device *gdev = host->dev;
+	struct pci_dev *pdev = to_pci_dev(gdev);
+	int i, rc;
 
-	if (port_mask & ATA_PORT_PRIMARY) {
-		iomap[0] = devm_ioport_map(&pdev->dev, ATA_PRIMARY_CMD, 8);
-		iomap[1] = devm_ioport_map(&pdev->dev, ATA_PRIMARY_CTL, 1);
-		if (!iomap[0] || !iomap[1])
-			return NULL;
+	/* TODO: If we get no DMA mask we should fall back to PIO */
+	rc = pci_configure_dma_masks(pdev, ATA_DMA_MASK, NULL);
+	if (rc)
+		return rc;
+
+	/* request and iomap DMA region */
+	rc = pcim_iomap_regions(pdev, 1 << 4, DRV_NAME);
+	if (rc) {
+		dev_printk(KERN_ERR, gdev, "failed to request/iomap BAR4\n");
+		return -ENOMEM;
 	}
+	host->iomap = pcim_iomap_table(pdev);
 
-	if (port_mask & ATA_PORT_SECONDARY) {
-		iomap[2] = devm_ioport_map(&pdev->dev, ATA_SECONDARY_CMD, 8);
-		iomap[3] = devm_ioport_map(&pdev->dev, ATA_SECONDARY_CTL, 1);
-		if (!iomap[2] || !iomap[3])
-			return NULL;
+	for (i = 0; i < 2; i++) {
+		struct ata_port *ap = host->ports[i];
+		struct ata_ioports *ioaddr = &ap->ioaddr;
+		void __iomem *bmdma = host->iomap[4] + 8 * i;
+
+		if (ata_port_is_dummy(ap))
+			continue;
+
+		ioaddr->bmdma_addr = bmdma;
+		if ((!(ap->flags & ATA_FLAG_IGN_SIMPLEX)) &&
+		    (ioread8(bmdma + 2) & 0x80))
+			host->flags |= ATA_HOST_SIMPLEX;
 	}
 
-	bmdma = pcim_iomap(pdev, 4, 16); /* may fail */
+	return 0;
+}
+
+struct ata_legacy_devres {
+	unsigned int	mask;
+	unsigned long	cmd_port[2];
+	void __iomem *	cmd_addr[2];
+	void __iomem *	ctl_addr[2];
+	unsigned int	irq[2];
+	void *		irq_dev_id[2];
+};
 
-	/* alloc and init probe_ent */
-	probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]);
-	if (!probe_ent)
-		return NULL;
+static void ata_legacy_free_irqs(struct ata_legacy_devres *legacy_dr)
+{
+	int i;
 
-	probe_ent->n_ports = 2;
-	probe_ent->irq_flags = IRQF_SHARED;
+	for (i = 0; i < 2; i++) {
+		if (!legacy_dr->irq[i])
+			continue;
 
-	if (port_mask & ATA_PORT_PRIMARY) {
-		probe_ent->irq = ATA_PRIMARY_IRQ(pdev);
-		probe_ent->port[0].cmd_addr = iomap[0];
-		probe_ent->port[0].altstatus_addr =
-		probe_ent->port[0].ctl_addr = iomap[1];
-		if (bmdma) {
-			probe_ent->port[0].bmdma_addr = bmdma;
-			if ((!(port[0]->flags & ATA_FLAG_IGN_SIMPLEX)) &&
-			    (ioread8(bmdma + 2) & 0x80))
-				probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
+		free_irq(legacy_dr->irq[i], legacy_dr->irq_dev_id[i]);
+		legacy_dr->irq[i] = 0;
+		legacy_dr->irq_dev_id[i] = NULL;
+	}
+}
+
+static void ata_legacy_release(struct device *gdev, void *res)
+{
+	struct ata_legacy_devres *this = res;
+	int i;
+
+	ata_legacy_free_irqs(this);
+
+	for (i = 0; i < 2; i++) {
+		if (this->cmd_addr[i])
+			ioport_unmap(this->cmd_addr[i]);
+		if (this->ctl_addr[i])
+			ioport_unmap(this->ctl_addr[i]);
+		if (this->cmd_port[i])
+			release_region(this->cmd_port[i], 8);
+	}
+}
+
+static int ata_init_legacy_port(struct ata_port *ap,
+				struct ata_legacy_devres *legacy_dr)
+{
+	struct ata_host *host = ap->host;
+	int port_no = ap->port_no;
+	unsigned long cmd_port, ctl_port;
+
+	if (port_no == 0) {
+		cmd_port = ATA_PRIMARY_CMD;
+		ctl_port = ATA_PRIMARY_CTL;
+	} else {
+		cmd_port = ATA_SECONDARY_CMD;
+		ctl_port = ATA_SECONDARY_CTL;
+	}
+
+	/* request cmd_port */
+	if (request_region(cmd_port, 8, "libata"))
+		legacy_dr->cmd_port[port_no] = cmd_port;
+	else {
+		struct resource *conflict, res;
+
+		/* Deal with combined mode hack. This side of the
+		 * logic all goes away once the combined mode hack is
+		 * killed in 2.6.21.
+		 */
+		res.start = cmd_port;
+		res.end = cmd_port + 8 - 1;
+		conflict = ____request_resource(&ioport_resource, &res);
+		while (conflict->child)
+			conflict = ____request_resource(conflict, &res);
+		if (strcmp(conflict->name, "libata")) {
+			dev_printk(KERN_WARNING, host->dev,
+				   "0x%0lX IDE port busy\n", cmd_port);
+			return -EBUSY;
 		}
-		ata_std_ports(&probe_ent->port[0]);
-	} else
-		probe_ent->dummy_port_mask |= ATA_PORT_PRIMARY;
+		dev_printk(KERN_INFO, host->dev,
+			   "0x%0lX IDE port preallocated\n", cmd_port);
+	}
+
+	/* iomap cmd and ctl ports */
+	legacy_dr->cmd_addr[port_no] = ioport_map(cmd_port, 8);
+	legacy_dr->ctl_addr[port_no] = ioport_map(ctl_port, 1);
+	if (!legacy_dr->cmd_addr[port_no] || !legacy_dr->ctl_addr[port_no])
+		return -ENOMEM;
+
+	/* init IO addresses */
+	ap->ioaddr.cmd_addr = legacy_dr->cmd_addr[port_no];
+	ap->ioaddr.altstatus_addr = legacy_dr->ctl_addr[port_no];
+	ap->ioaddr.ctl_addr = legacy_dr->ctl_addr[port_no];
+	ata_std_ports(&ap->ioaddr);
+
+	return 0;
+}
+
+/**
+ *	ata_init_legacy_host - acquire legacy ATA resources and init ATA host
+ *	@host: target ATA host
+ *	@legacy_mask: out parameter, mask indicating ports is in legacy mode
+ *	@was_busy: out parameter, indicates whether any port was busy
+ *
+ *	Acquire legacy ATA resources for ports.
+ *
+ *	LOCKING:
+ *	Inherited from calling layer (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno otherwise.
+ */
+static int ata_init_legacy_host(struct ata_host *host,
+				unsigned int *legacy_mask, int *was_busy)
+{
+	struct device *gdev = host->dev;
+	struct ata_legacy_devres *legacy_dr;
+	int i, rc;
+
+	if (!devres_open_group(gdev, NULL, GFP_KERNEL))
+		return -ENOMEM;
+
+	rc = -ENOMEM;
+	legacy_dr = devres_alloc(ata_legacy_release, sizeof(*legacy_dr),
+				 GFP_KERNEL);
+	if (!legacy_dr)
+		goto err_out;
+	devres_add(gdev, legacy_dr);
+
+	for (i = 0; i < 2; i++) {
+		*legacy_mask &= ~(1 << i);
+		rc = ata_init_legacy_port(host->ports[i], legacy_dr);
+		if (rc == 0)
+			legacy_dr->mask |= 1 << i;
+		else if (rc == -EBUSY)
+			(*was_busy)++;
+	}
+
+	if (!legacy_dr->mask)
+		return -EBUSY;
 
-	if (port_mask & ATA_PORT_SECONDARY) {
-		if (probe_ent->irq)
-			probe_ent->irq2 = ATA_SECONDARY_IRQ(pdev);
+	for (i = 0; i < 2; i++)
+		if (!(legacy_dr->mask & (1 << i)))
+			host->ports[i]->ops = &ata_dummy_port_ops;
+
+	*legacy_mask |= legacy_dr->mask;
+
+	devres_remove_group(gdev, NULL);
+	return 0;
+
+ err_out:
+	devres_release_group(gdev, NULL);
+	return rc;
+}
+
+/**
+ *	ata_request_legacy_irqs - request legacy ATA IRQs
+ *	@host: target ATA host
+ *	@handler: array of IRQ handlers
+ *	@irq_flags: array of IRQ flags
+ *	@dev_id: array of IRQ dev_ids
+ *
+ *	Request legacy IRQs for non-dummy legacy ports in @host.  All
+ *	IRQ parameters are passed as array to allow ports to have
+ *	separate IRQ handlers.
+ *
+ *	LOCKING:
+ *	Inherited from calling layer (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno otherwise.
+ */
+static int ata_request_legacy_irqs(struct ata_host *host,
+				   irq_handler_t const *handler,
+				   const unsigned int *irq_flags,
+				   void * const *dev_id)
+{
+	struct device *gdev = host->dev;
+	struct ata_legacy_devres *legacy_dr;
+	int i, rc;
+
+	legacy_dr = devres_find(host->dev, ata_legacy_release, NULL, NULL);
+	BUG_ON(!legacy_dr);
+
+	for (i = 0; i < 2; i++) {
+		unsigned int irq;
+
+		/* FIXME: ATA_*_IRQ() should take generic device not pci_dev */
+		if (i == 0)
+			irq = ATA_PRIMARY_IRQ(to_pci_dev(gdev));
 		else
-			probe_ent->irq = ATA_SECONDARY_IRQ(pdev);
-		probe_ent->port[1].cmd_addr = iomap[2];
-		probe_ent->port[1].altstatus_addr =
-		probe_ent->port[1].ctl_addr = iomap[3];
-		if (bmdma) {
-			probe_ent->port[1].bmdma_addr = bmdma + 8;
-			if ((!(port[1]->flags & ATA_FLAG_IGN_SIMPLEX)) &&
-			    (ioread8(bmdma + 10) & 0x80))
-				probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
+			irq = ATA_SECONDARY_IRQ(to_pci_dev(gdev));
+
+		if (!(legacy_dr->mask & (1 << i)))
+			continue;
+
+		if (!handler[i]) {
+			dev_printk(KERN_ERR, gdev,
+				   "NULL handler specified for port %d\n", i);
+			rc = -EINVAL;
+			goto err_out;
 		}
-		ata_std_ports(&probe_ent->port[1]);
 
-		/* FIXME: could be pointing to stack area; must copy */
-		probe_ent->pinfo2 = port[1];
-	} else
-		probe_ent->dummy_port_mask |= ATA_PORT_SECONDARY;
+		rc = request_irq(irq, handler[i], irq_flags[i], DRV_NAME,
+				 dev_id[i]);
+		if (rc) {
+			dev_printk(KERN_ERR, gdev,
+				"irq %u request failed (errno=%d)\n", irq, rc);
+			goto err_out;
+		}
 
-	return probe_ent;
-}
+		/* record irq allocation in legacy_dr */
+		legacy_dr->irq[i] = irq;
+		legacy_dr->irq_dev_id[i] = dev_id[i];
+
+		/* only used to print info */
+		if (i == 0)
+			host->irq = irq;
+		else
+			host->irq2 = irq;
+	}
 
+	return 0;
+
+ err_out:
+	ata_legacy_free_irqs(legacy_dr);
+	return rc;
+}
 
 /**
  *	ata_pci_init_one - Initialize/register PCI IDE host controller
@@ -727,7 +930,8 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
 {
 	struct device *dev = &pdev->dev;
 	struct ata_probe_ent *probe_ent = NULL;
-	struct ata_port_info *port[2];
+	struct ata_host *host = NULL;
+	const struct ata_port_info *port[2];
 	u8 mask;
 	unsigned int legacy_mode = 0;
 	int rc;
@@ -783,87 +987,71 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
 			pcim_pin_device(pdev);
 			goto err_out;
 		}
+
+		/* TODO: If we get no DMA mask we should fall back to PIO */
+		rc = pci_configure_dma_masks(pdev, ATA_DMA_MASK, NULL);
+		if (rc)
+			goto err_out;
+
+		pci_set_master(pdev);
 	} else {
-		/* Deal with combined mode hack. This side of the logic all
-		   goes away once the combined mode hack is killed in 2.6.21 */
-		if (!devm_request_region(dev, ATA_PRIMARY_CMD, 8, "libata")) {
-			struct resource *conflict, res;
-			res.start = ATA_PRIMARY_CMD;
-			res.end = ATA_PRIMARY_CMD + 8 - 1;
-			conflict = ____request_resource(&ioport_resource, &res);
-			while (conflict->child)
-				conflict = ____request_resource(conflict, &res);
-			if (!strcmp(conflict->name, "libata"))
-				legacy_mode |= ATA_PORT_PRIMARY;
-			else {
-				pcim_pin_device(pdev);
-				printk(KERN_WARNING "ata: 0x%0X IDE port busy\n" \
-						    "ata: conflict with %s\n",
-						    ATA_PRIMARY_CMD,
-						    conflict->name);
-			}
-		} else
-			legacy_mode |= ATA_PORT_PRIMARY;
-
-		if (!devm_request_region(dev, ATA_SECONDARY_CMD, 8, "libata")) {
-			struct resource *conflict, res;
-			res.start = ATA_SECONDARY_CMD;
-			res.end = ATA_SECONDARY_CMD + 8 - 1;
-			conflict = ____request_resource(&ioport_resource, &res);
-			while (conflict->child)
-				conflict = ____request_resource(conflict, &res);
-			if (!strcmp(conflict->name, "libata"))
-				legacy_mode |= ATA_PORT_SECONDARY;
-			else {
-				pcim_pin_device(pdev);
-				printk(KERN_WARNING "ata: 0x%X IDE port busy\n" \
-						    "ata: conflict with %s\n",
-						    ATA_SECONDARY_CMD,
-						    conflict->name);
-			}
-		} else
-			legacy_mode |= ATA_PORT_SECONDARY;
-
-		if (legacy_mode & ATA_PORT_PRIMARY)
-			pci_request_region(pdev, 1, DRV_NAME);
-		if (legacy_mode & ATA_PORT_SECONDARY)
-			pci_request_region(pdev, 3, DRV_NAME);
-		/* If there is a DMA resource, allocate it */
-		pci_request_region(pdev, 4, DRV_NAME);
-	}
+		int was_busy = 0;
 
-	/* we have legacy mode, but all ports are unavailable */
-	if (legacy_mode == (1 << 3)) {
-		rc = -EBUSY;
-		goto err_out;
-	}
+		rc = -ENOMEM;
+		host = ata_host_alloc_pinfo(dev, port, 2);
+		if (!host)
+			goto err_out;
 
-	/* TODO: If we get no DMA mask we should fall back to PIO */
-	rc = pci_configure_dma_masks(pdev, ATA_DMA_MASK, NULL);
-	if (rc)
-		goto err_out;
+		rc = ata_init_legacy_host(host, &legacy_mode, &was_busy);
+		if (was_busy)
+			pcim_pin_device(pdev);
+		if (rc)
+			goto err_out;
+
+		/* request respective PCI regions, may fail */
+		rc = pci_request_region(pdev, 1, DRV_NAME);
+		rc = pci_request_region(pdev, 3, DRV_NAME);
+
+		/* init bmdma */
+		ata_pci_init_bmdma(host);
+		pci_set_master(pdev);
+	}
 
 	if (legacy_mode) {
-		probe_ent = ata_pci_init_legacy_port(pdev, port, legacy_mode);
+		irq_handler_t handler[2] = { host->ops->irq_handler,
+					     host->ops->irq_handler };
+		unsigned int irq_flags[2] = { IRQF_SHARED, IRQF_SHARED };
+		void *dev_id[2] = { host, host };
+
+		rc = ata_host_start(host);
+		if (rc)
+			goto err_out;
+
+		rc = ata_request_legacy_irqs(host, handler, irq_flags, dev_id);
+		if (rc)
+			goto err_out;
+
+		rc = ata_host_attach(host, port_info[0]->sht);
+		if (rc)
+			goto err_out;
 	} else {
 		if (n_ports == 2)
-			probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
+			probe_ent = ata_pci_init_native_mode(pdev, (struct ata_port_info **)port, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
 		else
-			probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY);
-	}
-	if (!probe_ent) {
-		rc = -ENOMEM;
-		goto err_out;
-	}
+			probe_ent = ata_pci_init_native_mode(pdev, (struct ata_port_info **)port, ATA_PORT_PRIMARY);
 
-	pci_set_master(pdev);
+		if (!probe_ent) {
+			rc = -ENOMEM;
+			goto err_out;
+		}
 
-	if (!ata_device_add(probe_ent)) {
-		rc = -ENODEV;
-		goto err_out;
-	}
+		if (!ata_device_add(probe_ent)) {
+			rc = -ENODEV;
+			goto err_out;
+		}
 
-	devm_kfree(dev, probe_ent);
+		devm_kfree(dev, probe_ent);
+	}
 	devres_remove_group(dev, NULL);
 	return 0;
 
Signature · 1 line
1.5.0.1
#14 lore raw

Re: [PATCH 05/12] libata: convert legacy PCI host handling to new init model

Quoted 9 lines · Tejun Heo

Convert legacy PCI host handling to alloc-init-attach model. ata_init_legacy_host(), ata_request_legacy_irqs() and ata_pci_init_bmdma() are separated out and follow the new init model.

The two legacy handling functions use separate ata_legacy_devres instead of generic devm_* resources. This reduces devres overhead for legacy hosts which was a bit high because it didn't use PCI/iomap merged resoruces.

Quoted 8 lines

ata_pci_init_one() is rewritten in terms of the aboved functions but native mode handling is still using the old method. Conversion will be completed when native mode handling is updated.

---
 drivers/ata/libata-sff.c |  436 +++++++++++++++++++++++++++++++++-------------
 1 files changed, 312 insertions(+), 124 deletions(-)

ACK patches 5-12

author
#15 lore raw

PATCH 6/12 libata: convert native PCI host handling to new init model

In reply to Tejun Heo

Convert native PCI host handling to alloc-init-attach model. New function ata_pci_init_native_host() follows the new init model and replaces ata_pci_init_native_mode(). As there are remaining LLD users, the old function isn't removed yet.

ata_pci_init_one() is reimplemented using the new function and now fully converted to new init model.

---
 drivers/ata/libata-core.c |    1 +
 drivers/ata/libata-sff.c  |  148 ++++++++++++++++++++++++++++++--------------
 include/linux/libata.h    |    2 +
 3 files changed, 104 insertions(+), 47 deletions(-)
drivers/ata/libata-core.c +1 -0
index 97e7d9c..cf63651 100644
@@ -6649,6 +6649,7 @@ EXPORT_SYMBOL_GPL(ata_timing_merge);
 EXPORT_SYMBOL_GPL(pci_test_config_bits);
 EXPORT_SYMBOL_GPL(pci_configure_dma_masks);
 EXPORT_SYMBOL_GPL(ata_pci_init_native_mode);
+EXPORT_SYMBOL_GPL(ata_pci_init_native_host);
 EXPORT_SYMBOL_GPL(ata_pci_init_one);
 EXPORT_SYMBOL_GPL(ata_pci_remove_one);
 #ifdef CONFIG_PM
drivers/ata/libata-sff.c +101 -47

195 lines not on this page · raw message

include/linux/libata.h +2 -0
index 202ed7a..7aa6085 100644
@@ -881,6 +881,8 @@ struct pci_bits {
 
 extern struct ata_probe_ent *
 ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int portmask);
+extern int ata_pci_init_native_host(struct ata_host *host,
+				    unsigned int port_mask);
 extern int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits);
 extern int pci_configure_dma_masks(struct pci_dev *pdev, u64 dma_mask,
 				   u64 *configured_mask);
Signature · 1 line
1.5.0.1
#16 lore raw

Re: [PATCH 06/12] libata: convert native PCI host handling to new init model

This reminds me to kill combined mode handling. Just putting that in now...

author
#17 lore raw

PATCH 7/12 libata: add init helpers including ata_pci_prepare_native_host()

In reply to Tejun Heo

These will be used to convert LLDs to new init model.

* Add irq_handler field to port_info. In new init model, requesting IRQ is LLD's responsibility and libata doesn't need to know about irq_handler. Most LLDs can simply register their irq_handler but some need different irq_handler depending on specific chip. The added port_info->irq_handler field can be used by LLDs to select the matching IRQ handler in such cases.

* Add ata_dummy_port_info.

* Implement ata_pci_prepare_native_host(), a helper to alloc ATA host, acquire all resources and init the host in one go.

---
 drivers/ata/libata-core.c |    6 ++++
 drivers/ata/libata-sff.c  |   67 +++++++++++++++++++++++++++++++++++++++++++-
 include/linux/libata.h    |    5 +++
 3 files changed, 76 insertions(+), 2 deletions(-)
drivers/ata/libata-core.c +6 -0
index cf63651..4d371fb 100644
@@ -6546,6 +6546,10 @@ const struct ata_port_operations ata_dummy_port_ops = {
 	.port_stop		= ata_dummy_noret,
 };
 
+const struct ata_port_info ata_dummy_port_info = {
+	.port_ops		= &ata_dummy_port_ops,
+};
+
 /*
  * libata is essentially a library of internal helper functions for
  * low-level ATA host controller drivers.  As such, the API/ABI is
@@ -6557,6 +6561,7 @@ EXPORT_SYMBOL_GPL(sata_deb_timing_normal);
 EXPORT_SYMBOL_GPL(sata_deb_timing_hotplug);
 EXPORT_SYMBOL_GPL(sata_deb_timing_long);
 EXPORT_SYMBOL_GPL(ata_dummy_port_ops);
+EXPORT_SYMBOL_GPL(ata_dummy_port_info);
 EXPORT_SYMBOL_GPL(ata_std_bios_param);
 EXPORT_SYMBOL_GPL(ata_std_ports);
 EXPORT_SYMBOL_GPL(ata_host_init);
@@ -6650,6 +6655,7 @@ EXPORT_SYMBOL_GPL(pci_test_config_bits);
 EXPORT_SYMBOL_GPL(pci_configure_dma_masks);
 EXPORT_SYMBOL_GPL(ata_pci_init_native_mode);
 EXPORT_SYMBOL_GPL(ata_pci_init_native_host);
+EXPORT_SYMBOL_GPL(ata_pci_prepare_native_host);
 EXPORT_SYMBOL_GPL(ata_pci_init_one);
 EXPORT_SYMBOL_GPL(ata_pci_remove_one);
 #ifdef CONFIG_PM
drivers/ata/libata-sff.c +65 -2

84 lines not on this page · raw message

include/linux/libata.h +5 -0
index 7aa6085..43d9356 100644
@@ -663,6 +663,7 @@ struct ata_port_info {
 	unsigned long		mwdma_mask;
 	unsigned long		udma_mask;
 	const struct ata_port_operations *port_ops;
+	irq_handler_t		irq_handler;
 	void 			*private_data;
 };
 
@@ -685,6 +686,7 @@ extern const unsigned long sata_deb_timing_hotplug[];
 extern const unsigned long sata_deb_timing_long[];
 
 extern const struct ata_port_operations ata_dummy_port_ops;
+extern const struct ata_port_info ata_dummy_port_info;
 
 static inline const unsigned long *
 sata_ehc_deb_timing(struct ata_eh_context *ehc)
@@ -883,6 +885,9 @@ extern struct ata_probe_ent *
 ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int portmask);
 extern int ata_pci_init_native_host(struct ata_host *host,
 				    unsigned int port_mask);
+extern int ata_pci_prepare_native_host(struct pci_dev *pdev,
+				const struct ata_port_info * const * ppi,
+				int n_ports, struct ata_host **r_host);
 extern int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits);
 extern int pci_configure_dma_masks(struct pci_dev *pdev, u64 dma_mask,
 				   u64 *configured_mask);
Signature · 1 line
1.5.0.1
author
#18 lore raw

PATCH 8/12 libata: convert drivers with combined SATA/PATA ports to new init model

In reply to Tejun Heo

Convert sata_via and sata_promise to nwe init model. Both controllers can have combined configuration (SATA + PATA) and used twisted initialization method (modifying port in ->port_start) to overcome probe_ent limitations.

This patch converts both drivers to new init model in which such configuration is natively supported.

* promise: Combined pata port now uses separate port_info entry right after the sata counterpart entry.

* promise: Controller configuration is discerned using ap->flags. This simplifies init path and makes it look more like other LLDs.

* promise: SATA/PATA branches are converted into separate ops. Remaining ones are converted to more standard ap->cbl == ATA_CBL_SATA check.

* via: Both SATA and PATA ports in vt6421 are represented int their own port_info structure.

Tested on PDC20375 (SATA150 TX2plus) [105a:3375] and PDC40775 (SATA 300 TX2plus) [105a:3d73]. Couldn't test via cuz my c3 won't boot the current kernel.

---
 drivers/ata/sata_promise.c |  278 +++++++++++++++++++------------------------
 drivers/ata/sata_via.c     |  172 ++++++++++++----------------
 2 files changed, 196 insertions(+), 254 deletions(-)
drivers/ata/sata_promise.c +123 -155
index 71a05ad..2ca2e1c 100644
@@ -49,6 +49,7 @@
 
 
 enum {
+	PDC_MAX_PORTS		= 4,
 	PDC_MMIO_BAR		= 3,
 
 	/* register offsets */
@@ -74,10 +75,12 @@ enum {
 				  (1<<8) | (1<<9) | (1<<10),
 
 	board_2037x		= 0,	/* FastTrak S150 TX2plus */
-	board_20319		= 1,	/* FastTrak S150 TX4 */
-	board_20619		= 2,	/* FastTrak TX4000 */
-	board_2057x		= 3,	/* SATAII150 Tx2plus */
-	board_40518		= 4,	/* SATAII150 Tx4 */
+	board_2037x_pata	= 1,	/* FastTrak S150 TX2plus PATA port */
+	board_20319		= 2,	/* FastTrak S150 TX4 */
+	board_20619		= 3,	/* FastTrak TX4000 */
+	board_2057x		= 4,	/* SATAII150 Tx2plus */
+	board_2057x_pata	= 5,	/* SATAII150 Tx2plus */
+	board_40518		= 6,	/* SATAII150 Tx4 */
 
 	PDC_HAS_PATA		= (1 << 1), /* PDC20375/20575 has PATA */
 
@@ -100,8 +103,10 @@ enum {
 				  ATA_FLAG_MMIO |
 				  ATA_FLAG_PIO_POLLING,
 
-	/* hp->flags bits */
-	PDC_FLAG_GEN_II		= (1 << 0),
+	/* ap->flags bits */
+	PDC_FLAG_GEN_II		= (1 << 24),
+	PDC_FLAG_SATA_PATA	= (1 << 25), /* supports SATA + PATA */
+	PDC_FLAG_4_PORTS	= (1 << 26), /* 4 ports */
 };
 
 
@@ -110,26 +115,21 @@ struct pdc_port_priv {
 	dma_addr_t		pkt_dma;
 };
 
-struct pdc_host_priv {
-	unsigned long		flags;
-	unsigned long		port_flags[ATA_MAX_PORTS];
-};
-
 static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg);
 static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static irqreturn_t pdc_interrupt (int irq, void *dev_instance);
 static int pdc_port_start(struct ata_port *ap);
 static void pdc_qc_prep(struct ata_queued_cmd *qc);
 static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
 static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
 static int pdc_check_atapi_dma(struct ata_queued_cmd *qc);
-static int pdc_old_check_atapi_dma(struct ata_queued_cmd *qc);
+static int pdc_old_sata_check_atapi_dma(struct ata_queued_cmd *qc);
 static void pdc_irq_clear(struct ata_port *ap);
 static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc);
 static void pdc_freeze(struct ata_port *ap);
 static void pdc_thaw(struct ata_port *ap);
-static void pdc_error_handler(struct ata_port *ap);
+static void pdc_sata_error_handler(struct ata_port *ap);
+static void pdc_pata_error_handler(struct ata_port *ap);
 static void pdc_post_internal_cmd(struct ata_queued_cmd *qc);
 
 
@@ -164,10 +164,9 @@ static const struct ata_port_operations pdc_sata_ops = {
 	.qc_issue		= pdc_qc_issue_prot,
 	.freeze			= pdc_freeze,
 	.thaw			= pdc_thaw,
-	.error_handler		= pdc_error_handler,
+	.error_handler		= pdc_sata_error_handler,
 	.post_internal_cmd	= pdc_post_internal_cmd,
 	.data_xfer		= ata_data_xfer,
-	.irq_handler		= pdc_interrupt,
 	.irq_clear		= pdc_irq_clear,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
@@ -185,16 +184,15 @@ static const struct ata_port_operations pdc_old_sata_ops = {
 	.check_status		= ata_check_status,
 	.exec_command		= pdc_exec_command_mmio,
 	.dev_select		= ata_std_dev_select,
-	.check_atapi_dma	= pdc_old_check_atapi_dma,
+	.check_atapi_dma	= pdc_old_sata_check_atapi_dma,
 
 	.qc_prep		= pdc_qc_prep,
 	.qc_issue		= pdc_qc_issue_prot,
 	.freeze			= pdc_freeze,
 	.thaw			= pdc_thaw,
-	.error_handler		= pdc_error_handler,
+	.error_handler		= pdc_sata_error_handler,
 	.post_internal_cmd	= pdc_post_internal_cmd,
 	.data_xfer		= ata_data_xfer,
-	.irq_handler		= pdc_interrupt,
 	.irq_clear		= pdc_irq_clear,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
@@ -217,10 +215,9 @@ static const struct ata_port_operations pdc_pata_ops = {
 	.qc_issue		= pdc_qc_issue_prot,
 	.freeze			= pdc_freeze,
 	.thaw			= pdc_thaw,
-	.error_handler		= pdc_error_handler,
+	.error_handler		= pdc_pata_error_handler,
 	.post_internal_cmd	= pdc_post_internal_cmd,
 	.data_xfer		= ata_data_xfer,
-	.irq_handler		= pdc_interrupt,
 	.irq_clear		= pdc_irq_clear,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
@@ -231,18 +228,27 @@ static const struct ata_port_operations pdc_pata_ops = {
 static const struct ata_port_info pdc_port_info[] = {
 	/* board_2037x */
 	{
-		.sht		= &pdc_ata_sht,
-		.flags		= PDC_COMMON_FLAGS,
+		.flags		= PDC_COMMON_FLAGS | ATA_FLAG_SATA |
+				  PDC_FLAG_SATA_PATA,
 		.pio_mask	= 0x1f, /* pio0-4 */
 		.mwdma_mask	= 0x07, /* mwdma0-2 */
 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
 		.port_ops	= &pdc_old_sata_ops,
 	},
 
+	/* board_2037x_pata */
+	{
+		.flags		= PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS,
+		.pio_mask	= 0x1f, /* pio0-4 */
+		.mwdma_mask	= 0x07, /* mwdma0-2 */
+		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
+		.port_ops	= &pdc_pata_ops,
+	},
+
 	/* board_20319 */
 	{
-		.sht		= &pdc_ata_sht,
-		.flags		= PDC_COMMON_FLAGS | ATA_FLAG_SATA,
+		.flags		= PDC_COMMON_FLAGS | ATA_FLAG_SATA |
+				  PDC_FLAG_4_PORTS,
 		.pio_mask	= 0x1f, /* pio0-4 */
 		.mwdma_mask	= 0x07, /* mwdma0-2 */
 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
@@ -251,8 +257,8 @@ static const struct ata_port_info pdc_port_info[] = {
 
 	/* board_20619 */
 	{
-		.sht		= &pdc_ata_sht,
-		.flags		= PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS,
+		.flags		= PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS |
+				  PDC_FLAG_4_PORTS,
 		.pio_mask	= 0x1f, /* pio0-4 */
 		.mwdma_mask	= 0x07, /* mwdma0-2 */
 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
@@ -261,18 +267,28 @@ static const struct ata_port_info pdc_port_info[] = {
 
 	/* board_2057x */
 	{
-		.sht		= &pdc_ata_sht,
-		.flags		= PDC_COMMON_FLAGS,
+		.flags		= PDC_COMMON_FLAGS | ATA_FLAG_SATA |
+				  PDC_FLAG_GEN_II | PDC_FLAG_SATA_PATA,
 		.pio_mask	= 0x1f, /* pio0-4 */
 		.mwdma_mask	= 0x07, /* mwdma0-2 */
 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
 		.port_ops	= &pdc_sata_ops,
 	},
 
+	/* board_2057x_pata */
+	{
+		.flags		= PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS,
+				  PDC_FLAG_GEN_II,
+		.pio_mask	= 0x1f, /* pio0-4 */
+		.mwdma_mask	= 0x07, /* mwdma0-2 */
+		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
+		.port_ops	= &pdc_pata_ops,
+	},
+
 	/* board_40518 */
 	{
-		.sht		= &pdc_ata_sht,
-		.flags		= PDC_COMMON_FLAGS | ATA_FLAG_SATA,
+		.flags		= PDC_COMMON_FLAGS | ATA_FLAG_SATA |
+				  PDC_FLAG_GEN_II | PDC_FLAG_4_PORTS,
 		.pio_mask	= 0x1f, /* pio0-4 */
 		.mwdma_mask	= 0x07, /* mwdma0-2 */
 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
@@ -316,15 +332,10 @@ static struct pci_driver pdc_ata_pci_driver = {
 static int pdc_port_start(struct ata_port *ap)
 {
 	struct device *dev = ap->host->dev;
-	struct pdc_host_priv *hp = ap->host->private_data;
 	struct pdc_port_priv *pp;
 	int rc;
 
 	/* fix up port flags and cable type for SATA+PATA chips */
-	ap->flags |= hp->port_flags[ap->port_no];
-	if (ap->flags & ATA_FLAG_SATA)
-		ap->cbl = ATA_CBL_SATA;
-
 	rc = ata_port_start(ap);
 	if (rc)
 		return rc;
@@ -340,7 +351,7 @@ static int pdc_port_start(struct ata_port *ap)
 	ap->private_data = pp;
 
 	/* fix up PHYMODE4 align timing */
-	if ((hp->flags & PDC_FLAG_GEN_II) && sata_scr_valid(ap)) {
+	if ((ap->flags & PDC_FLAG_GEN_II) && (ap->cbl == ATA_CBL_SATA)) {
 		void __iomem *mmio = (void __iomem *) ap->ioaddr.scr_addr;
 		unsigned int tmp;
 
@@ -390,7 +401,7 @@ static void pdc_pata_cbl_detect(struct ata_port *ap)
 
 static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
 {
-	if (sc_reg > SCR_CONTROL || ap->cbl != ATA_CBL_SATA)
+	if (sc_reg > SCR_CONTROL)
 		return 0xffffffffU;
 	return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
 }
@@ -399,7 +410,7 @@ static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
 static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
 			       u32 val)
 {
-	if (sc_reg > SCR_CONTROL || ap->cbl != ATA_CBL_SATA)
+	if (sc_reg > SCR_CONTROL)
 		return;
 	writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
 }
@@ -436,7 +447,7 @@ static void pdc_atapi_pkt(struct ata_queued_cmd *qc)
 	buf32[2] = 0;				/* no next-packet */
 
 	/* select drive */
-	if (sata_scr_valid(ap)) {
+	if (ap->cbl == ATA_CBL_SATA) {
 		dev_sel = PDC_DEVICE_SATA;
 	} else {
 		dev_sel = ATA_DEVICE_OBS;
@@ -555,26 +566,27 @@ static void pdc_thaw(struct ata_port *ap)
 	readl(mmio + PDC_CTLSTAT); /* flush */
 }
 
-static int pdc_pre_reset(struct ata_port *ap)
+static void pdc_sata_error_handler(struct ata_port *ap)
 {
-	if (!sata_scr_valid(ap))
-		pdc_pata_cbl_detect(ap);
-	return ata_std_prereset(ap);
+	if (!(ap->pflags & ATA_PFLAG_FROZEN))
+		pdc_reset_port(ap);
+
+	ata_bmdma_error_handler(ap);
 }
 
-static void pdc_error_handler(struct ata_port *ap)
+static int pdc_pata_prereset(struct ata_port *ap)
 {
-	ata_reset_fn_t hardreset;
+	pdc_pata_cbl_detect(ap);
 
+	return ata_std_prereset(ap);
+}
+
+static void pdc_pata_error_handler(struct ata_port *ap)
+{
 	if (!(ap->pflags & ATA_PFLAG_FROZEN))
 		pdc_reset_port(ap);
 
-	hardreset = NULL;
-	if (sata_scr_valid(ap))
-		hardreset = sata_std_hardreset;
-
-	/* perform recovery */
-	ata_do_eh(ap, pdc_pre_reset, ata_std_softreset, hardreset,
+	ata_do_eh(ap, pdc_pata_prereset, ata_std_softreset, NULL,
 		  ata_std_postreset);
 }
 
@@ -767,44 +779,40 @@ static int pdc_check_atapi_dma(struct ata_queued_cmd *qc)
 	return pio;
 }
 
-static int pdc_old_check_atapi_dma(struct ata_queued_cmd *qc)
+static int pdc_old_sata_check_atapi_dma(struct ata_queued_cmd *qc)
 {
-	struct ata_port *ap = qc->ap;
-
 	/* First generation chips cannot use ATAPI DMA on SATA ports */
-	if (sata_scr_valid(ap))
-		return 1;
-	return pdc_check_atapi_dma(qc);
+	return 1;
 }
 
-static void pdc_ata_setup_port(struct ata_ioports *port, void __iomem *base,
-			       void __iomem *scr_addr)
+static void pdc_ata_setup_port(struct ata_port *ap,
+			       void __iomem *base, void __iomem *scr_addr)
 {
-	port->cmd_addr		= base;
-	port->data_addr		= base;
-	port->feature_addr	=
-	port->error_addr	= base + 0x4;
-	port->nsect_addr	= base + 0x8;
-	port->lbal_addr		= base + 0xc;
-	port->lbam_addr		= base + 0x10;
-	port->lbah_addr		= base + 0x14;
-	port->device_addr	= base + 0x18;
-	port->command_addr	=
-	port->status_addr	= base + 0x1c;
-	port->altstatus_addr	=
-	port->ctl_addr		= base + 0x38;
-	port->scr_addr		= scr_addr;
+	ap->ioaddr.cmd_addr		= base;
+	ap->ioaddr.data_addr		= base;
+	ap->ioaddr.feature_addr		=
+	ap->ioaddr.error_addr		= base + 0x4;
+	ap->ioaddr.nsect_addr		= base + 0x8;
+	ap->ioaddr.lbal_addr		= base + 0xc;
+	ap->ioaddr.lbam_addr		= base + 0x10;
+	ap->ioaddr.lbah_addr		= base + 0x14;
+	ap->ioaddr.device_addr		= base + 0x18;
+	ap->ioaddr.command_addr		=
+	ap->ioaddr.status_addr		= base + 0x1c;
+	ap->ioaddr.altstatus_addr	=
+	ap->ioaddr.ctl_addr		= base + 0x38;
+	ap->ioaddr.scr_addr		= scr_addr;
 }
 
 
-static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
+static void pdc_host_init(struct ata_host *host)
 {
-	void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
-	struct pdc_host_priv *hp = pe->private_data;
+	void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
+	int is_gen2 = host->ports[0]->flags & PDC_FLAG_GEN_II;
 	int hotplug_offset;
 	u32 tmp;
 
-	if (hp->flags & PDC_FLAG_GEN_II)
+	if (is_gen2)
 		hotplug_offset = PDC2_SATA_PLUG_CSR;
 	else
 		hotplug_offset = PDC_SATA_PLUG_CSR;
@@ -818,7 +826,7 @@ static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
 	/* enable BMR_BURST, maybe change FIFO_SHD to 8 dwords */
 	tmp = readl(mmio + PDC_FLASH_CTL);
 	tmp |= 0x02000;	/* bit 13 (enable bmr burst) */
-	if (!(hp->flags & PDC_FLAG_GEN_II))
+	if (!is_gen2)
 		tmp |= 0x10000;	/* bit 16 (fifo threshold at 8 dw) */
 	writel(tmp, mmio + PDC_FLASH_CTL);
 
@@ -831,7 +839,7 @@ static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
 	writel(tmp | 0xff0000, mmio + hotplug_offset);
 
 	/* don't initialise TBG or SLEW on 2nd generation chips */
-	if (hp->flags & PDC_FLAG_GEN_II)
+	if (is_gen2)
 		return;
 
 	/* reduce TBG clock to 133 Mhz. */
@@ -853,16 +861,16 @@ static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
 static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	static int printed_version;
-	struct ata_probe_ent *probe_ent;
-	struct pdc_host_priv *hp;
+	const struct ata_port_info *pi = &pdc_port_info[ent->driver_data];
+	const struct ata_port_info *ppi[PDC_MAX_PORTS];
+	struct ata_host *host;
 	void __iomem *base;
-	unsigned int board_idx = (unsigned int) ent->driver_data;
-	int rc;
-	u8 tmp;
+	int n_ports, i, rc;
 
 	if (!printed_version++)
 		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
 
+	/* enable and acquire resources */
 	rc = pcim_enable_device(pdev);
 	if (rc)
 		return rc;
@@ -872,86 +880,46 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
 		pcim_pin_device(pdev);
 	if (rc)
 		return rc;
+	base = pcim_iomap_table(pdev)[PDC_MMIO_BAR];
 
-	rc = pci_configure_dma_masks(pdev, ATA_DMA_MASK, NULL);
-	if (rc)
-		return rc;
-
-	probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
-	if (probe_ent == NULL)
-		return -ENOMEM;
+	/* determine port configuration and setup host */
+	n_ports = 2;
+	if (pi->flags & PDC_FLAG_4_PORTS)
+		n_ports = 4;
+	for (i = 0; i < n_ports; i++)
+		ppi[i] = pi;
 
-	probe_ent->dev = pci_dev_to_dev(pdev);
-	INIT_LIST_HEAD(&probe_ent->node);
+	if (pi->flags & PDC_FLAG_SATA_PATA) {
+		u8 tmp = readb(base + PDC_FLASH_CTL+1);
+		if (!(tmp & 0x80)) {
+			ppi[n_ports++] = pi + 1;
+			dev_printk(KERN_INFO, &pdev->dev, "PATA port found\n");
+		}
+	}
 
-	hp = devm_kzalloc(&pdev->dev, sizeof(*hp), GFP_KERNEL);
-	if (hp == NULL)
+	host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
+	if (!host) {
+		dev_printk(KERN_ERR, &pdev->dev, "failed to allocate host\n");
 		return -ENOMEM;
-
-	probe_ent->private_data = hp;
-
-	probe_ent->sht		= pdc_port_info[board_idx].sht;
-	probe_ent->port_flags	= pdc_port_info[board_idx].flags;
-	probe_ent->pio_mask	= pdc_port_info[board_idx].pio_mask;
-	probe_ent->mwdma_mask	= pdc_port_info[board_idx].mwdma_mask;
-	probe_ent->udma_mask	= pdc_port_info[board_idx].udma_mask;
-	probe_ent->port_ops	= pdc_port_info[board_idx].port_ops;
-
-       	probe_ent->irq = pdev->irq;
-       	probe_ent->irq_flags = IRQF_SHARED;
-	probe_ent->iomap = pcim_iomap_table(pdev);
-
-	base = probe_ent->iomap[PDC_MMIO_BAR];
-
-	pdc_ata_setup_port(&probe_ent->port[0], base + 0x200, base + 0x400);
-	pdc_ata_setup_port(&probe_ent->port[1], base + 0x280, base + 0x500);
-
-	/* notice 4-port boards */
-	switch (board_idx) {
-	case board_40518:
-		hp->flags |= PDC_FLAG_GEN_II;
-		/* Fall through */
-	case board_20319:
-       		probe_ent->n_ports = 4;
-		pdc_ata_setup_port(&probe_ent->port[2], base + 0x300, base + 0x600);
-		pdc_ata_setup_port(&probe_ent->port[3], base + 0x380, base + 0x700);
-		break;
-	case board_2057x:
-		hp->flags |= PDC_FLAG_GEN_II;
-		/* Fall through */
-	case board_2037x:
-		/* TX2plus boards also have a PATA port */
-		tmp = readb(base + PDC_FLASH_CTL+1);
-		if (!(tmp & 0x80)) {
-			probe_ent->n_ports = 3;
-			pdc_ata_setup_port(&probe_ent->port[2], base + 0x300, NULL);
-			hp->port_flags[2] = ATA_FLAG_SLAVE_POSS;
-			printk(KERN_INFO DRV_NAME " PATA port found\n");
-		} else
-			probe_ent->n_ports = 2;
-		hp->port_flags[0] = ATA_FLAG_SATA;
-		hp->port_flags[1] = ATA_FLAG_SATA;
-		break;
-	case board_20619:
-		probe_ent->n_ports = 4;
-		pdc_ata_setup_port(&probe_ent->port[2], base + 0x300, NULL);
-		pdc_ata_setup_port(&probe_ent->port[3], base + 0x380, NULL);
-		break;
-	default:
-		BUG();
-		break;
 	}
+	host->iomap = pcim_iomap_table(pdev);
 
-	pci_set_master(pdev);
+	for (i = 0; i < host->n_ports; i++)
+		pdc_ata_setup_port(host->ports[i],
+				   base + 0x200 + i * 0x80,
+				   base + 0x400 + i * 0x100);
 
 	/* initialize adapter */
-	pdc_host_init(board_idx, probe_ent);
+	pdc_host_init(host);
 
-	if (!ata_device_add(probe_ent))
-		return -ENODEV;
+	rc = pci_configure_dma_masks(pdev, ATA_DMA_MASK, NULL);
+	if (rc)
+		return rc;
 
-	devm_kfree(&pdev->dev, probe_ent);
-	return 0;
+	/* start host, request IRQ and attach */
+	pci_set_master(pdev);
+	return ata_host_activate(host, pdev->irq, pdc_interrupt, IRQF_SHARED,
+				 &pdc_ata_sht);
 }
 
 
drivers/ata/sata_via.c +73 -99

274 lines not on this page · raw message

Signature · 1 line
1.5.0.1
#19 lore raw

Re: [PATCH 08/12] libata: convert drivers with combined SATA/PATA ports to new init model

Quoted 3 lines

* promise: SATA/PATA branches are converted into separate ops. Remaining ones are converted to more standard ap->cbl == ATA_CBL_SATA check.

NAK this specifically

I've got some pending and needed patches to spot where drives report SATA and the host is doing PATA cables. This is needed for various warped PATA controller and glue variants and means that the PATA port probe may end up returning with ap->cbl == ATA_CBL_SATA if it finds SATA devices on a supposedly PATA port.

Alan

#20 lore raw

Re: [PATCH 08/12] libata: convert drivers with combined SATA/PATA ports to new init model

Quoted 11 lines · Alan Cox
Quoted 3 lines

* promise: SATA/PATA branches are converted into separate ops. Remaining ones are converted to more standard ap->cbl == ATA_CBL_SATA check.

NAK this specifically

I've got some pending and needed patches to spot where drives report SATA and the host is doing PATA cables. This is needed for various warped PATA controller and glue variants and means that the PATA port probe may end up returning with ap->cbl == ATA_CBL_SATA if it finds SATA devices on a supposedly PATA port.

Indeed.

With the new init model, testing for ATA_FLAG_SATA should be the preferred test, as it makes all the mixed PATA/SATA ->port_start hackery and tests go away.

With the new init model, the LLDD and core should now /always/ know whether the port is PATA or SATA. The LLDD will set it up that way.

Now that different ->ops for PATA and SATA is supported (with Tejun's patches), I would expect the number of "is this port SATA?" tests to drop dramatically, for reasons mentioned in the previous paragraph and also because you can create separate hooks for PATA and SATA that permits the killing of "is this SATA?" or "is this PATA?" tests.

Jeff

author
#21 lore raw

Re: [PATCH 08/12] libata: convert drivers with combined SATA/PATA ports to new init model

Quoted 19 lines · Jeff Garzik
Quoted 11 lines · Alan Cox
Quoted 3 lines

* promise: SATA/PATA branches are converted into separate ops. Remaining ones are converted to more standard ap->cbl == ATA_CBL_SATA check.

NAK this specifically

I've got some pending and needed patches to spot where drives report SATA and the host is doing PATA cables. This is needed for various warped PATA controller and glue variants and means that the PATA port probe may end up returning with ap->cbl == ATA_CBL_SATA if it finds SATA devices on a supposedly PATA port.

Indeed.

With the new init model, testing for ATA_FLAG_SATA should be the preferred test, as it makes all the mixed PATA/SATA ->port_start hackery and tests go away.

Quoted 8 lines

With the new init model, the LLDD and core should now /always/ know whether the port is PATA or SATA. The LLDD will set it up that way.

Now that different ->ops for PATA and SATA is supported (with Tejun's patches), I would expect the number of "is this port SATA?" tests to drop dramatically, for reasons mentioned in the previous paragraph and also because you can create separate hooks for PATA and SATA that permits the killing of "is this SATA?" or "is this PATA?" tests.

I see. I'll drop that part.

Thanks.

Signature · 1 line
tejun
author
#22 lore raw

PATCH 9/12 libata: convert ata_pci_init_native_mode() users to new init model

In reply to Tejun Heo

Convert drivers which use ata_pci_init_native_mode() to new init model. ata_pci_init_native_host() is used instead. sata_nv, sata_uli and sata_sis are in this category.

Tested on nVidia Corporation CK804 Serial ATA Controller [10de:0054] in both BMDMA and ADMA mode.

---
 drivers/ata/sata_nv.c  |   86 +++++++++++++++++++++--------------------------
 drivers/ata/sata_sis.c |   49 +++++++++------------------
 drivers/ata/sata_uli.c |   62 +++++++++++++---------------------
 3 files changed, 79 insertions(+), 118 deletions(-)
drivers/ata/sata_nv.c +38 -48
index eb0f877..37cbea5 100644
@@ -368,7 +368,6 @@ static const struct ata_port_operations nv_generic_ops = {
 	.error_handler		= nv_error_handler,
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
 	.data_xfer		= ata_data_xfer,
-	.irq_handler		= nv_generic_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
@@ -395,7 +394,6 @@ static const struct ata_port_operations nv_nf2_ops = {
 	.error_handler		= nv_error_handler,
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
 	.data_xfer		= ata_data_xfer,
-	.irq_handler		= nv_nf2_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
@@ -422,7 +420,6 @@ static const struct ata_port_operations nv_ck804_ops = {
 	.error_handler		= nv_error_handler,
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
 	.data_xfer		= ata_data_xfer,
-	.irq_handler		= nv_ck804_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
@@ -451,7 +448,6 @@ static const struct ata_port_operations nv_adma_ops = {
 	.error_handler		= nv_adma_error_handler,
 	.post_internal_cmd	= nv_adma_post_internal_cmd,
 	.data_xfer		= ata_data_xfer,
-	.irq_handler		= nv_adma_interrupt,
 	.irq_clear		= nv_adma_irq_clear,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
@@ -476,6 +472,7 @@ static struct ata_port_info nv_port_info[] = {
 		.mwdma_mask	= NV_MWDMA_MASK,
 		.udma_mask	= NV_UDMA_MASK,
 		.port_ops	= &nv_generic_ops,
+		.irq_handler	= nv_generic_interrupt,
 	},
 	/* nforce2/3 */
 	{
@@ -486,6 +483,7 @@ static struct ata_port_info nv_port_info[] = {
 		.mwdma_mask	= NV_MWDMA_MASK,
 		.udma_mask	= NV_UDMA_MASK,
 		.port_ops	= &nv_nf2_ops,
+		.irq_handler	= nv_nf2_interrupt,
 	},
 	/* ck804 */
 	{
@@ -496,6 +494,7 @@ static struct ata_port_info nv_port_info[] = {
 		.mwdma_mask	= NV_MWDMA_MASK,
 		.udma_mask	= NV_UDMA_MASK,
 		.port_ops	= &nv_ck804_ops,
+		.irq_handler	= nv_ck804_interrupt,
 	},
 	/* ADMA */
 	{
@@ -507,6 +506,7 @@ static struct ata_port_info nv_port_info[] = {
 		.mwdma_mask	= NV_MWDMA_MASK,
 		.udma_mask	= NV_UDMA_MASK,
 		.port_ops	= &nv_adma_ops,
+		.irq_handler	= nv_adma_interrupt,
 	},
 };
 
@@ -1068,14 +1068,14 @@ static int nv_adma_port_resume(struct ata_port *ap)
 }
 #endif
 
-static void nv_adma_setup_port(struct ata_probe_ent *probe_ent, unsigned int port)
+static void nv_adma_setup_port(struct ata_port *ap)
 {
-	void __iomem *mmio = probe_ent->iomap[NV_MMIO_BAR];
-	struct ata_ioports *ioport = &probe_ent->port[port];
+	void __iomem *mmio = ap->host->iomap[NV_MMIO_BAR];
+	struct ata_ioports *ioport = &ap->ioaddr;
 
 	VPRINTK("ENTER\n");
 
-	mmio += NV_ADMA_PORT + port * NV_ADMA_PORT_SIZE;
+	mmio += NV_ADMA_PORT + ap->port_no * NV_ADMA_PORT_SIZE;
 
 	ioport->cmd_addr	= mmio;
 	ioport->data_addr	= mmio + (ATA_REG_DATA * 4);
@@ -1092,9 +1092,9 @@ static void nv_adma_setup_port(struct ata_probe_ent *probe_ent, unsigned int por
 	ioport->ctl_addr	= mmio + 0x20;
 }
 
-static int nv_adma_host_init(struct ata_probe_ent *probe_ent)
+static int nv_adma_host_init(struct ata_host *host)
 {
-	struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
+	struct pci_dev *pdev = to_pci_dev(host->dev);
 	unsigned int i;
 	u32 tmp32;
 
@@ -1109,8 +1109,8 @@ static int nv_adma_host_init(struct ata_probe_ent *probe_ent)
 
 	pci_write_config_dword(pdev, NV_MCP_SATA_CFG_20, tmp32);
 
-	for (i = 0; i < probe_ent->n_ports; i++)
-		nv_adma_setup_port(probe_ent, i);
+	for (i = 0; i < host->n_ports; i++)
+		nv_adma_setup_port(host->ports[i]);
 
 	return 0;
 }
@@ -1467,14 +1467,13 @@ static void nv_adma_error_handler(struct ata_port *ap)
 static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	static int printed_version = 0;
-	struct ata_port_info *ppi[2];
-	struct ata_probe_ent *probe_ent;
+	const struct ata_port_info *ppi[2];
+	struct ata_host *host;
 	struct nv_host_priv *hpriv;
 	int rc;
 	u32 bar;
 	void __iomem *base;
 	unsigned long type = ent->driver_data;
-	u64 dma_mask = ATA_DMA_MASK;
 
         // Make sure this is a SATA controller by counting the number of bars
         // (NVIDIA SATA controllers will always have six bars).  Otherwise,
@@ -1490,43 +1489,38 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 	if (rc)
 		return rc;
 
-	rc = pci_request_regions(pdev, DRV_NAME);
-	if (rc) {
-		pcim_pin_device(pdev);
-		return rc;
-	}
-
-	if(type >= CK804 && adma_enabled) {
+	/* determine type and allocate host */
+	if (type >= CK804 && adma_enabled) {
 		dev_printk(KERN_NOTICE, &pdev->dev, "Using ADMA mode\n");
 		type = ADMA;
-		dma_mask = DMA_64BIT_MASK;
 	}
 
-	rc = pci_configure_dma_masks(pdev, dma_mask, NULL);
+	ppi[0] = ppi[1] = &nv_port_info[type];
+	rc = ata_pci_prepare_native_host(pdev, ppi, 2, &host);
 	if (rc)
 		return rc;
 
-	rc = -ENOMEM;
-
 	hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
 	if (!hpriv)
 		return -ENOMEM;
+	hpriv->type = type;
+	host->private_data = hpriv;
 
-	ppi[0] = ppi[1] = &nv_port_info[type];
-	probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
-	if (!probe_ent)
-		return -ENOMEM;
-
-	if (!pcim_iomap(pdev, NV_MMIO_BAR, 0))
-		return -EIO;
-	probe_ent->iomap = pcim_iomap_table(pdev);
+	if (type == ADMA) {
+		rc = pci_configure_dma_masks(pdev, DMA_64BIT_MASK, NULL);
+		if (rc)
+			return rc;
+	}
 
-	probe_ent->private_data = hpriv;
-	hpriv->type = type;
+	/* request and iomap NV_MMIO_BAR */
+	rc = pcim_iomap_regions(pdev, 1 << NV_MMIO_BAR, DRV_NAME);
+	if (rc)
+		return rc;
 
-	base = probe_ent->iomap[NV_MMIO_BAR];
-	probe_ent->port[0].scr_addr = base + NV_PORT0_SCR_REG_OFFSET;
-	probe_ent->port[1].scr_addr = base + NV_PORT1_SCR_REG_OFFSET;
+	/* configure SCR access */
+	base = host->iomap[NV_MMIO_BAR];
+	host->ports[0]->ioaddr.scr_addr = base + NV_PORT0_SCR_REG_OFFSET;
+	host->ports[1]->ioaddr.scr_addr = base + NV_PORT1_SCR_REG_OFFSET;
 
 	/* enable SATA space for CK804 */
 	if (type >= CK804) {
@@ -1537,20 +1531,16 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 		pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval);
 	}
 
-	pci_set_master(pdev);
-
+	/* init ADMA */
 	if (type == ADMA) {
-		rc = nv_adma_host_init(probe_ent);
+		rc = nv_adma_host_init(host);
 		if (rc)
 			return rc;
 	}
 
-	rc = ata_device_add(probe_ent);
-	if (rc != NV_PORTS)
-		return -ENODEV;
-
-	devm_kfree(&pdev->dev, probe_ent);
-	return 0;
+	pci_set_master(pdev);
+	return ata_host_activate(host, pdev->irq, ppi[0]->irq_handler,
+				 IRQF_SHARED, ppi[0]->sht);
 }
 
 static void nv_remove_one (struct pci_dev *pdev)
drivers/ata/sata_sis.c +17 -32

89 lines not on this page · raw message

drivers/ata/sata_uli.c +24 -38

113 lines not on this page · raw message

Signature · 1 line
1.5.0.1
author
#23 lore raw

PATCH 10/12 libata: convert the remaining SATA drivers to new init model

In reply to Tejun Heo

Convert ahci, sata_sil, sata_sil24, sata_svw, sata_qstor, sata_mv, sata_sx4, sata_vsc and sata_inic162x to new init model.

Now that host and ap are available during intialization, functions are converted to take either host or ap instead of low level parameters which were inevitable for functions shared between init and other paths. This simplifies code quite a bit.

* init_one()'s now follow more consistent init order

* ahci_setup_port() and ahci_host_init() collapsed into ahci_init_one() for init order consistency

* sata_vsc uses port_info instead of setting fields manually

* in sata_svw, k2_board_info converted to port_info (info is now in port flags). port number is honored now.

Tested on ICH7/8 AHCI, jmb360, sil3112, 3114, 3124 and 3132.

---
 drivers/ata/ahci.c          |  310 +++++++++++++++++--------------------------
 drivers/ata/sata_inic162x.c |   64 +++------
 drivers/ata/sata_mv.c       |  105 ++++++---------
 drivers/ata/sata_qstor.c    |   62 +++------
 drivers/ata/sata_sil.c      |   89 +++++-------
 drivers/ata/sata_sil24.c    |  107 ++++++----------
 drivers/ata/sata_svw.c      |  105 +++++++--------
 drivers/ata/sata_sx4.c      |  150 +++++++++------------
 drivers/ata/sata_vsc.c      |   72 ++++------
 9 files changed, 419 insertions(+), 645 deletions(-)
drivers/ata/ahci.c +122 -188
index fd9acf3..0895e23 100644
@@ -207,7 +207,6 @@ static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg);
 static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
 static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
-static irqreturn_t ahci_interrupt (int irq, void *dev_instance);
 static void ahci_irq_clear(struct ata_port *ap);
 static int ahci_port_start(struct ata_port *ap);
 static void ahci_port_stop(struct ata_port *ap);
@@ -261,7 +260,6 @@ static const struct ata_port_operations ahci_ops = {
 	.qc_prep		= ahci_qc_prep,
 	.qc_issue		= ahci_qc_issue,
 
-	.irq_handler		= ahci_interrupt,
 	.irq_clear		= ahci_irq_clear,
 	.irq_on			= ata_dummy_irq_on,
 	.irq_ack		= ata_dummy_irq_ack,
@@ -296,7 +294,6 @@ static const struct ata_port_operations ahci_vt8251_ops = {
 	.qc_prep		= ahci_qc_prep,
 	.qc_issue		= ahci_qc_issue,
 
-	.irq_handler		= ahci_interrupt,
 	.irq_clear		= ahci_irq_clear,
 	.irq_on			= ata_dummy_irq_on,
 	.irq_ack		= ata_dummy_irq_ack,
@@ -322,7 +319,6 @@ static const struct ata_port_operations ahci_vt8251_ops = {
 static const struct ata_port_info ahci_port_info[] = {
 	/* board_ahci */
 	{
-		.sht		= &ahci_sht,
 		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
 				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
 				  ATA_FLAG_SKIP_D2H_BSY,
@@ -332,7 +328,6 @@ static const struct ata_port_info ahci_port_info[] = {
 	},
 	/* board_ahci_pi */
 	{
-		.sht		= &ahci_sht,
 		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
 				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
 				  ATA_FLAG_SKIP_D2H_BSY | AHCI_FLAG_HONOR_PI,
@@ -342,7 +337,6 @@ static const struct ata_port_info ahci_port_info[] = {
 	},
 	/* board_ahci_vt8251 */
 	{
-		.sht		= &ahci_sht,
 		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
 				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
 				  ATA_FLAG_SKIP_D2H_BSY |
@@ -353,7 +347,6 @@ static const struct ata_port_info ahci_port_info[] = {
 	},
 	/* board_ahci_ign_iferr */
 	{
-		.sht		= &ahci_sht,
 		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
 				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
 				  ATA_FLAG_SKIP_D2H_BSY |
@@ -456,10 +449,11 @@ static inline int ahci_nr_ports(u32 cap)
 	return (cap & 0x1f) + 1;
 }
 
-static inline void __iomem *ahci_port_base(void __iomem *base,
-					   unsigned int port)
+static inline void __iomem *ahci_port_base(struct ata_port *ap)
 {
-	return base + 0x100 + (port * 0x80);
+	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
+
+	return mmio + 0x100 + (ap->port_no * 0x80);
 }
 
 static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in)
@@ -496,8 +490,9 @@ static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in,
 	writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
 }
 
-static void ahci_start_engine(void __iomem *port_mmio)
+static void ahci_start_engine(struct ata_port *ap)
 {
+	void __iomem *port_mmio = ahci_port_base(ap);
 	u32 tmp;
 
 	/* start DMA */
@@ -507,8 +502,9 @@ static void ahci_start_engine(void __iomem *port_mmio)
 	readl(port_mmio + PORT_CMD); /* flush */
 }
 
-static int ahci_stop_engine(void __iomem *port_mmio)
+static int ahci_stop_engine(struct ata_port *ap)
 {
+	void __iomem *port_mmio = ahci_port_base(ap);
 	u32 tmp;
 
 	tmp = readl(port_mmio + PORT_CMD);
@@ -530,19 +526,23 @@ static int ahci_stop_engine(void __iomem *port_mmio)
 	return 0;
 }
 
-static void ahci_start_fis_rx(void __iomem *port_mmio, u32 cap,
-			      dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma)
+static void ahci_start_fis_rx(struct ata_port *ap)
 {
+	void __iomem *port_mmio = ahci_port_base(ap);
+	struct ahci_host_priv *hpriv = ap->host->private_data;
+	struct ahci_port_priv *pp = ap->private_data;
 	u32 tmp;
 
 	/* set FIS registers */
-	if (cap & HOST_CAP_64)
-		writel((cmd_slot_dma >> 16) >> 16, port_mmio + PORT_LST_ADDR_HI);
-	writel(cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
+	if (hpriv->cap & HOST_CAP_64)
+		writel((pp->cmd_slot_dma >> 16) >> 16,
+		       port_mmio + PORT_LST_ADDR_HI);
+	writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
 
-	if (cap & HOST_CAP_64)
-		writel((rx_fis_dma >> 16) >> 16, port_mmio + PORT_FIS_ADDR_HI);
-	writel(rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
+	if (hpriv->cap & HOST_CAP_64)
+		writel((pp->rx_fis_dma >> 16) >> 16,
+		       port_mmio + PORT_FIS_ADDR_HI);
+	writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
 
 	/* enable FIS reception */
 	tmp = readl(port_mmio + PORT_CMD);
@@ -553,8 +553,9 @@ static void ahci_start_fis_rx(void __iomem *port_mmio, u32 cap,
 	readl(port_mmio + PORT_CMD);
 }
 
-static int ahci_stop_fis_rx(void __iomem *port_mmio)
+static int ahci_stop_fis_rx(struct ata_port *ap)
 {
+	void __iomem *port_mmio = ahci_port_base(ap);
 	u32 tmp;
 
 	/* disable FIS reception */
@@ -571,14 +572,16 @@ static int ahci_stop_fis_rx(void __iomem *port_mmio)
 	return 0;
 }
 
-static void ahci_power_up(void __iomem *port_mmio, u32 cap)
+static void ahci_power_up(struct ata_port *ap)
 {
+	struct ahci_host_priv *hpriv = ap->host->private_data;
+	void __iomem *port_mmio = ahci_port_base(ap);
 	u32 cmd;
 
 	cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
 
 	/* spin up device */
-	if (cap & HOST_CAP_SSS) {
+	if (hpriv->cap & HOST_CAP_SSS) {
 		cmd |= PORT_CMD_SPIN_UP;
 		writel(cmd, port_mmio + PORT_CMD);
 	}
@@ -588,11 +591,13 @@ static void ahci_power_up(void __iomem *port_mmio, u32 cap)
 }
 
 #ifdef CONFIG_PM
-static void ahci_power_down(void __iomem *port_mmio, u32 cap)
+static void ahci_power_down(struct ata_port *ap)
 {
+	struct ahci_host_priv *hpriv = ap->host->private_data;
+	void __iomem *port_mmio = ahci_port_base(ap);
 	u32 cmd, scontrol;
 
-	if (!(cap & HOST_CAP_SSS))
+	if (!(hpriv->cap & HOST_CAP_SSS))
 		return;
 
 	/* put device into listen mode, first set PxSCTL.DET to 0 */
@@ -607,29 +612,28 @@ static void ahci_power_down(void __iomem *port_mmio, u32 cap)
 }
 #endif
 
-static void ahci_init_port(void __iomem *port_mmio, u32 cap,
-			   dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma)
+static void ahci_init_port(struct ata_port *ap)
 {
 	/* enable FIS reception */
-	ahci_start_fis_rx(port_mmio, cap, cmd_slot_dma, rx_fis_dma);
+	ahci_start_fis_rx(ap);
 
 	/* enable DMA */
-	ahci_start_engine(port_mmio);
+	ahci_start_engine(ap);
 }
 
-static int ahci_deinit_port(void __iomem *port_mmio, u32 cap, const char **emsg)
+static int ahci_deinit_port(struct ata_port *ap, const char **emsg)
 {
 	int rc;
 
 	/* disable DMA */
-	rc = ahci_stop_engine(port_mmio);
+	rc = ahci_stop_engine(ap);
 	if (rc) {
 		*emsg = "failed to stop engine";
 		return rc;
 	}
 
 	/* disable FIS reception */
-	rc = ahci_stop_fis_rx(port_mmio);
+	rc = ahci_stop_fis_rx(ap);
 	if (rc) {
 		*emsg = "failed stop FIS RX";
 		return rc;
@@ -638,8 +642,10 @@ static int ahci_deinit_port(void __iomem *port_mmio, u32 cap, const char **emsg)
 	return 0;
 }
 
-static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev)
+static int ahci_reset_controller(struct ata_host *host)
 {
+	struct pci_dev *pdev = to_pci_dev(host->dev);
+	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
 	u32 cap_save, impl_save, tmp;
 
 	cap_save = readl(mmio + HOST_CAP);
@@ -659,7 +665,7 @@ static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev)
 
 	tmp = readl(mmio + HOST_CTL);
 	if (tmp & HOST_RESET) {
-		dev_printk(KERN_ERR, &pdev->dev,
+		dev_printk(KERN_ERR, host->dev,
 			   "controller reset failed (0x%x)\n", tmp);
 		return -EIO;
 	}
@@ -688,23 +694,23 @@ static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev)
 	return 0;
 }
 
-static void ahci_init_controller(void __iomem *mmio, struct pci_dev *pdev,
-				 int n_ports, unsigned int port_flags,
-				 struct ahci_host_priv *hpriv)
+static void ahci_init_controller(struct ata_host *host)
 {
+	struct pci_dev *pdev = to_pci_dev(host->dev);
+	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
 	int i, rc;
 	u32 tmp;
 
-	for (i = 0; i < n_ports; i++) {
-		void __iomem *port_mmio = ahci_port_base(mmio, i);
+	for (i = 0; i < host->n_ports; i++) {
+		struct ata_port *ap = host->ports[i];
+		void __iomem *port_mmio = ahci_port_base(ap);
 		const char *emsg = NULL;
 
-		if ((port_flags & AHCI_FLAG_HONOR_PI) &&
-		    !(hpriv->port_map & (1 << i)))
+		if (ata_port_is_dummy(ap))
 			continue;
 
 		/* make sure port is not active */
-		rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
+		rc = ahci_deinit_port(ap, &emsg);
 		if (rc)
 			dev_printk(KERN_WARNING, &pdev->dev,
 				   "%s (%d)\n", emsg, rc);
@@ -732,7 +738,7 @@ static void ahci_init_controller(void __iomem *mmio, struct pci_dev *pdev,
 
 static unsigned int ahci_dev_classify(struct ata_port *ap)
 {
-	void __iomem *port_mmio = ap->ioaddr.cmd_addr;
+	void __iomem *port_mmio = ahci_port_base(ap);
 	struct ata_taskfile tf;
 	u32 tmp;
 
@@ -782,8 +788,7 @@ static int ahci_clo(struct ata_port *ap)
 static int ahci_softreset(struct ata_port *ap, unsigned int *class)
 {
 	struct ahci_port_priv *pp = ap->private_data;
-	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+	void __iomem *port_mmio = ahci_port_base(ap);
 	const u32 cmd_fis_len = 5; /* five dwords */
 	const char *reason = NULL;
 	struct ata_taskfile tf;
@@ -800,7 +805,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class)
 	}
 
 	/* prepare for SRST (AHCI-1.1 10.4.1) */
-	rc = ahci_stop_engine(port_mmio);
+	rc = ahci_stop_engine(ap);
 	if (rc) {
 		reason = "failed to stop engine";
 		goto fail_restart;
@@ -820,7 +825,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class)
 	}
 
 	/* restart engine */
-	ahci_start_engine(port_mmio);
+	ahci_start_engine(ap);
 
 	ata_tf_init(ap->device, &tf);
 	fis = pp->cmd_tbl;
@@ -879,7 +884,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class)
 	return 0;
 
  fail_restart:
-	ahci_start_engine(port_mmio);
+	ahci_start_engine(ap);
  fail:
 	ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
 	return rc;
@@ -890,13 +895,11 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
 	struct ahci_port_priv *pp = ap->private_data;
 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
 	struct ata_taskfile tf;
-	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
 	int rc;
 
 	DPRINTK("ENTER\n");
 
-	ahci_stop_engine(port_mmio);
+	ahci_stop_engine(ap);
 
 	/* clear D2H reception area to properly wait for D2H FIS */
 	ata_tf_init(ap->device, &tf);
@@ -905,7 +908,7 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
 
 	rc = sata_std_hardreset(ap, class);
 
-	ahci_start_engine(port_mmio);
+	ahci_start_engine(ap);
 
 	if (rc == 0 && ata_port_online(ap))
 		*class = ahci_dev_classify(ap);
@@ -918,20 +921,18 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
 
 static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class)
 {
-	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
 	int rc;
 
 	DPRINTK("ENTER\n");
 
-	ahci_stop_engine(port_mmio);
+	ahci_stop_engine(ap);
 
 	rc = sata_port_hardreset(ap, sata_ehc_deb_timing(&ap->eh_context));
 
 	/* vt8251 needs SError cleared for the port to operate */
 	ahci_scr_write(ap, SCR_ERROR, ahci_scr_read(ap, SCR_ERROR));
 
-	ahci_start_engine(port_mmio);
+	ahci_start_engine(ap);
 
 	DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
 
@@ -943,7 +944,7 @@ static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class)
 
 static void ahci_postreset(struct ata_port *ap, unsigned int *class)
 {
-	void __iomem *port_mmio = ap->ioaddr.cmd_addr;
+	void __iomem *port_mmio = ahci_port_base(ap);
 	u32 new_tmp, tmp;
 
 	ata_std_postreset(ap, class);
@@ -1108,8 +1109,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
 
 static void ahci_host_intr(struct ata_port *ap)
 {
-	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+	void __iomem *port_mmio = ap->ioaddr.cmd_addr;
 	struct ata_eh_info *ehi = &ap->eh_info;
 	struct ahci_port_priv *pp = ap->private_data;
 	u32 status, qc_active;
@@ -1260,7 +1260,7 @@ static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
 static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
-	void __iomem *port_mmio = ap->ioaddr.cmd_addr;
+	void __iomem *port_mmio = ahci_port_base(ap);
 
 	if (qc->tf.protocol == ATA_PROT_NCQ)
 		writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
@@ -1272,8 +1272,7 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
 
 static void ahci_freeze(struct ata_port *ap)
 {
-	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+	void __iomem *port_mmio = ahci_port_base(ap);
 
 	/* turn IRQ off */
 	writel(0, port_mmio + PORT_IRQ_MASK);
@@ -1282,7 +1281,7 @@ static void ahci_freeze(struct ata_port *ap)
 static void ahci_thaw(struct ata_port *ap)
 {
 	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+	void __iomem *port_mmio = ahci_port_base(ap);
 	u32 tmp;
 
 	/* clear IRQ */
@@ -1296,13 +1295,10 @@ static void ahci_thaw(struct ata_port *ap)
 
 static void ahci_error_handler(struct ata_port *ap)
 {
-	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
-
 	if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
 		/* restart engine */
-		ahci_stop_engine(port_mmio);
-		ahci_start_engine(port_mmio);
+		ahci_stop_engine(ap);
+		ahci_start_engine(ap);
 	}
 
 	/* perform recovery */
@@ -1312,13 +1308,10 @@ static void ahci_error_handler(struct ata_port *ap)
 
 static void ahci_vt8251_error_handler(struct ata_port *ap)
 {
-	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
-
 	if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
 		/* restart engine */
-		ahci_stop_engine(port_mmio);
-		ahci_start_engine(port_mmio);
+		ahci_stop_engine(ap);
+		ahci_start_engine(ap);
 	}
 
 	/* perform recovery */
@@ -1329,36 +1322,29 @@ static void ahci_vt8251_error_handler(struct ata_port *ap)
 static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
-	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
 
 	if (qc->flags & ATA_QCFLAG_FAILED)
 		qc->err_mask |= AC_ERR_OTHER;
 
 	if (qc->err_mask) {
 		/* make DMA engine forget about the failed command */
-		ahci_stop_engine(port_mmio);
-		ahci_start_engine(port_mmio);
+		ahci_stop_engine(ap);
+		ahci_start_engine(ap);
 	}
 }
 
 #ifdef CONFIG_PM
 static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
 {
-	struct ahci_host_priv *hpriv = ap->host->private_data;
-	struct ahci_port_priv *pp = ap->private_data;
-	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
 	const char *emsg = NULL;
 	int rc;
 
-	rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
+	rc = ahci_deinit_port(ap, &emsg);
 	if (rc == 0)
-		ahci_power_down(port_mmio, hpriv->cap);
+		ahci_power_down(ap);
 	else {
 		ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc);
-		ahci_init_port(port_mmio, hpriv->cap,
-			       pp->cmd_slot_dma, pp->rx_fis_dma);
+		ahci_init_port(ap);
 	}
 
 	return rc;
@@ -1366,13 +1352,8 @@ static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
 
 static int ahci_port_resume(struct ata_port *ap)
 {
-	struct ahci_port_priv *pp = ap->private_data;
-	struct ahci_host_priv *hpriv = ap->host->private_data;
-	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
-
-	ahci_power_up(port_mmio, hpriv->cap);
-	ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma);
+	ahci_power_up(ap);
+	ahci_init_port(ap);
 
 	return 0;
 }
@@ -1400,8 +1381,6 @@ static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
 static int ahci_pci_device_resume(struct pci_dev *pdev)
 {
 	struct ata_host *host = dev_get_drvdata(&pdev->dev);
-	struct ahci_host_priv *hpriv = host->private_data;
-	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
 	int rc;
 
 	rc = ata_pci_device_do_resume(pdev);
@@ -1409,12 +1388,11 @@ static int ahci_pci_device_resume(struct pci_dev *pdev)
 		return rc;
 
 	if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
-		rc = ahci_reset_controller(mmio, pdev);
+		rc = ahci_reset_controller(host);
 		if (rc)
 			return rc;
 
-		ahci_init_controller(mmio, pdev, host->n_ports,
-				     host->ports[0]->flags, hpriv);
+		ahci_init_controller(host);
 	}
 
 	ata_host_resume(host);
@@ -1426,10 +1404,7 @@ static int ahci_pci_device_resume(struct pci_dev *pdev)
 static int ahci_port_start(struct ata_port *ap)
 {
 	struct device *dev = ap->host->dev;
-	struct ahci_host_priv *hpriv = ap->host->private_data;
 	struct ahci_port_priv *pp;
-	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
 	void *mem;
 	dma_addr_t mem_dma;
 	int rc;
@@ -1477,41 +1452,25 @@ static int ahci_port_start(struct ata_port *ap)
 	ap->private_data = pp;
 
 	/* power up port */
-	ahci_power_up(port_mmio, hpriv->cap);
+	ahci_power_up(ap);
 
 	/* initialize port */
-	ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma);
+	ahci_init_port(ap);
 
 	return 0;
 }
 
 static void ahci_port_stop(struct ata_port *ap)
 {
-	struct ahci_host_priv *hpriv = ap->host->private_data;
-	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
 	const char *emsg = NULL;
 	int rc;
 
 	/* de-initialize port */
-	rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
+	rc = ahci_deinit_port(ap, &emsg);
 	if (rc)
 		ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc);
 }
 
-static void ahci_setup_port(struct ata_ioports *port, void __iomem *base,
-			    unsigned int port_idx)
-{
-	VPRINTK("ENTER, base==0x%lx, port_idx %u\n", base, port_idx);
-	base = ahci_port_base(base, port_idx);
-	VPRINTK("base now==0x%lx\n", base);
-
-	port->cmd_addr		= base;
-	port->scr_addr		= base + PORT_SCR;
-
-	VPRINTK("EXIT\n");
-}
-
 static int ahci_determine_nr_ports(struct pci_dev *pdev,
 				   struct ata_port_info *pi,
 				   struct ahci_host_priv *hpriv,
@@ -1554,43 +1513,11 @@ static int ahci_determine_nr_ports(struct pci_dev *pdev,
 	return max_port + 1;
 }
 
-static int ahci_host_init(struct ata_probe_ent *probe_ent)
+static void ahci_print_info(struct ata_host *host)
 {
-	struct ahci_host_priv *hpriv = probe_ent->private_data;
-	struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
-	void __iomem *mmio = probe_ent->iomap[AHCI_PCI_BAR];
-	unsigned int i;
-	u64 dma_mask;
-	int rc;
-
-	rc = ahci_reset_controller(mmio, pdev);
-	if (rc)
-		return rc;
-
-	dma_mask = DMA_32BIT_MASK;
-	if (hpriv->cap & HOST_CAP_64)
-		dma_mask = DMA_64BIT_MASK;
-
-	rc = pci_configure_dma_masks(pdev, dma_mask, NULL);
-	if (rc)
-		return rc;
-
-	for (i = 0; i < probe_ent->n_ports; i++)
-		ahci_setup_port(&probe_ent->port[i], mmio, i);
-
-	ahci_init_controller(mmio, pdev, probe_ent->n_ports,
-			     probe_ent->port_flags, hpriv);
-
-	pci_set_master(pdev);
-
-	return 0;
-}
-
-static void ahci_print_info(struct ata_probe_ent *probe_ent)
-{
-	struct ahci_host_priv *hpriv = probe_ent->private_data;
-	struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
-	void __iomem *mmio = probe_ent->iomap[AHCI_PCI_BAR];
+	struct ahci_host_priv *hpriv = host->private_data;
+	struct pci_dev *pdev = to_pci_dev(host->dev);
+	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
 	u32 vers, cap, impl, speed;
 	const char *speed_s;
 	u16 cc;
@@ -1660,13 +1587,15 @@ static void ahci_print_info(struct ata_probe_ent *probe_ent)
 static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	static int printed_version;
-	unsigned int board_idx = (unsigned int) ent->driver_data;
-	struct ata_port_info pi = ahci_port_info[board_idx];
+	struct ata_port_info pi = ahci_port_info[ent->driver_data];
+	const struct ata_port_info *ppi[] = { &pi, NULL };
 	struct device *dev = &pdev->dev;
+	unsigned int dummy_mask = 0;
 	void __iomem *mmio;
-	struct ata_probe_ent *probe_ent;
 	struct ahci_host_priv *hpriv;
-	int rc;
+	struct ata_host *host;
+	u64 dma_mask;
+	int n_ports, i, rc;
 
 	VPRINTK("ENTER\n");
 
@@ -1675,6 +1604,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 	if (!printed_version++)
 		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
 
+	/* acquire resources */
 	rc = pcim_enable_device(pdev);
 	if (rc)
 		return rc;
@@ -1689,51 +1619,55 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 	if (pci_enable_msi(pdev))
 		pci_intx(pdev, 1);
 
-	probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
-	if (probe_ent == NULL)
-		return -ENOMEM;
-
-	probe_ent->dev = pci_dev_to_dev(pdev);
-	INIT_LIST_HEAD(&probe_ent->node);
-
 	hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
 	if (!hpriv)
 		return -ENOMEM;
 
-	/* determine number of ports and fill probe_ent */
+	/* determine number of ports */
 	hpriv->cap = readl(mmio + HOST_CAP);
 	hpriv->port_map = readl(mmio + HOST_PORTS_IMPL);
+	n_ports = ahci_determine_nr_ports(pdev, &pi, hpriv, &dummy_mask);
+
+	/* prepare host */
+	if (!(pi.flags & AHCI_FLAG_NO_NCQ) && (hpriv->cap & HOST_CAP_NCQ))
+		pi.flags |= ATA_FLAG_NCQ;
 
-	probe_ent->n_ports = ahci_determine_nr_ports(pdev, &pi, hpriv,
-						&probe_ent->dummy_port_mask);
+	host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
+	if (!host)
+		return -ENOMEM;
+	host->iomap = pcim_iomap_table(pdev);
+	host->private_data = hpriv;
 
-	probe_ent->sht		= pi.sht;
-	probe_ent->port_flags	= pi.flags;
-	probe_ent->pio_mask	= pi.pio_mask;
-	probe_ent->udma_mask	= pi.udma_mask;
-	probe_ent->port_ops	= pi.port_ops;
+	for (i = 0; i < host->n_ports; i++) {
+		if (!(dummy_mask & (1 << i))) {
+			struct ata_port *ap = host->ports[i];
+			void __iomem *port_mmio = ahci_port_base(ap);
 
-       	probe_ent->irq = pdev->irq;
-       	probe_ent->irq_flags = IRQF_SHARED;
-	probe_ent->iomap = pcim_iomap_table(pdev);
-	probe_ent->private_data = hpriv;
+			ap->ioaddr.cmd_addr = port_mmio;
+			ap->ioaddr.scr_addr = port_mmio + PORT_SCR;
+		} else
+			host->ports[i]->ops = &ata_dummy_port_ops;
+	}
 
 	/* initialize adapter */
-	rc = ahci_host_init(probe_ent);
+	dma_mask = DMA_32BIT_MASK;
+	if (hpriv->cap & HOST_CAP_64)
+		dma_mask = DMA_64BIT_MASK;
+
+	rc = pci_configure_dma_masks(pdev, dma_mask, NULL);
 	if (rc)
 		return rc;
 
-	if (!(probe_ent->port_flags & AHCI_FLAG_NO_NCQ) &&
-	    (hpriv->cap & HOST_CAP_NCQ))
-		probe_ent->port_flags |= ATA_FLAG_NCQ;
-
-	ahci_print_info(probe_ent);
+	rc = ahci_reset_controller(host);
+	if (rc)
+		return rc;
 
-	if (!ata_device_add(probe_ent))
-		return -ENODEV;
+	ahci_init_controller(host);
+	ahci_print_info(host);
 
-	devm_kfree(dev, probe_ent);
-	return 0;
+	pci_set_master(pdev);
+	return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED,
+				 &ahci_sht);
 }
 
 static int __init ahci_init(void)
drivers/ata/sata_inic162x.c +20 -44

111 lines not on this page · raw message

drivers/ata/sata_mv.c +40 -65

265 lines not on this page · raw message

drivers/ata/sata_qstor.c +21 -41

131 lines not on this page · raw message

drivers/ata/sata_sil.c +37 -52

186 lines not on this page · raw message

drivers/ata/sata_sil24.c +38 -69

206 lines not on this page · raw message

drivers/ata/sata_svw.c +49 -56

164 lines not on this page · raw message

drivers/ata/sata_sx4.c +64 -86

343 lines not on this page · raw message

drivers/ata/sata_vsc.c +28 -44

121 lines not on this page · raw message

Signature · 1 line
1.5.0.1
author
#24 lore raw

PATCH 11/12 libata: convert the remaining PATA drivers to new init model

In reply to Tejun Heo

Convert pdc_adma, pata_cs5520, pata_isapnp, pata_ixp4xx_cf, pata_legacy, pata_mpc52xx, pata_mpiix, pata_pcmcia, pata_pdc2027x, pata_platform, pata_qdi, pata_scc and pata_winbond to new init model.

* init_one()'s now follow more consistent init order

* cs5520 now registers one host with two ports, not two hosts. If any of the two ports are disabled, it's made dummy as other drivers do.

Tested pdc_adma and pata_legacy. Both are as broken as before. The rest are compile tested only.

---
 drivers/ata/pata_cs5520.c    |  127 +++++++++++++++++++++++-------------------
 drivers/ata/pata_isapnp.c    |   43 ++++++++-------
 drivers/ata/pata_ixp4xx_cf.c |   39 ++++++-------
 drivers/ata/pata_legacy.c    |   38 ++++++------
 drivers/ata/pata_mpc52xx.c   |   46 +++++++--------
 drivers/ata/pata_mpiix.c     |   36 ++++++------
 drivers/ata/pata_pcmcia.c    |   40 +++++++-------
 drivers/ata/pata_pdc2027x.c  |   98 +++++++++++++--------------------
 drivers/ata/pata_platform.c  |   43 +++++++--------
 drivers/ata/pata_qdi.c       |   45 +++++++--------
 drivers/ata/pata_scc.c       |   51 +++++------------
 drivers/ata/pata_winbond.c   |   97 +++++++++++++++-----------------
 drivers/ata/pdc_adma.c       |   85 +++++++++++-----------------
 13 files changed, 360 insertions(+), 428 deletions(-)
drivers/ata/pata_cs5520.c +69 -58
index 6bddae5..0546748 100644
@@ -197,7 +197,6 @@ static struct ata_port_operations cs5520_port_ops = {
 	.qc_issue		= ata_qc_issue_prot,
 	.data_xfer		= ata_data_xfer,
 
-	.irq_handler		= ata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
@@ -205,87 +204,99 @@ static struct ata_port_operations cs5520_port_ops = {
 	.port_start		= ata_port_start,
 };
 
-static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 {
+	struct ata_port_info pi = {
+		.flags		= ATA_FLAG_SLAVE_POSS,
+		.pio_mask	= 0x1f,
+		.port_ops	= &cs5520_port_ops,
+	};
+	const struct ata_port_info *ppi[2];
 	u8 pcicfg;
 	void *iomap[5];
-	static struct ata_probe_ent probe[2];
-	int ports = 0, rc;
+	struct ata_host *host;
+	struct ata_ioports *ioaddr;
+	int i, rc;
 
 	/* IDE port enable bits */
-	pci_read_config_byte(dev, 0x60, &pcicfg);
+	pci_read_config_byte(pdev, 0x60, &pcicfg);
 
 	/* Check if the ATA ports are enabled */
-	if ((pcicfg & 3) == 0)
+	if (!(pcicfg & 3))
 		return -ENODEV;
 
+	ppi[0] = ppi[1] = &ata_dummy_port_info;
+	if (pcicfg & 1)
+		ppi[0] = &pi;
+	if (pcicfg & 2)
+		ppi[1] = &pi;
+
 	if ((pcicfg & 0x40) == 0) {
-		printk(KERN_WARNING DRV_NAME ": DMA mode disabled. Enabling.\n");
-		pci_write_config_byte(dev, 0x60, pcicfg | 0x40);
+		dev_printk(KERN_WARNING, &pdev->dev,
+			   "DMA mode disabled. Enabling.\n");
+		pci_write_config_byte(pdev, 0x60, pcicfg | 0x40);
 	}
 
+	pi.mwdma_mask = id->driver_data;
+
+	host = ata_host_alloc_pinfo(&pdev->dev, ppi, 2);
+	if (!host)
+		return -ENOMEM;
+
 	/* Perform set up for DMA */
-	if (pci_enable_device_bars(dev, 1<<2)) {
+	if (pci_enable_device_bars(pdev, 1<<2)) {
 		printk(KERN_ERR DRV_NAME ": unable to configure BAR2.\n");
 		return -ENODEV;
 	}
-	pci_set_master(dev);
 
-	rc = pci_configure_dma_masks(dev, DMA_32BIT_MASK, NULL);
+	rc = pci_configure_dma_masks(pdev, DMA_32BIT_MASK, NULL);
 	if (rc)
 		return rc;
 
-	/* Map IO ports */
-	iomap[0] = devm_ioport_map(&dev->dev, 0x1F0, 8);
-	iomap[1] = devm_ioport_map(&dev->dev, 0x3F6, 1);
-	iomap[2] = devm_ioport_map(&dev->dev, 0x170, 8);
-	iomap[3] = devm_ioport_map(&dev->dev, 0x376, 1);
-	iomap[4] = pcim_iomap(dev, 2, 0);
+	/* Map IO ports and initialize host accordingly */
+	iomap[0] = devm_ioport_map(&pdev->dev, 0x1F0, 8);
+	iomap[1] = devm_ioport_map(&pdev->dev, 0x3F6, 1);
+	iomap[2] = devm_ioport_map(&pdev->dev, 0x170, 8);
+	iomap[3] = devm_ioport_map(&pdev->dev, 0x376, 1);
+	iomap[4] = pcim_iomap(pdev, 2, 0);
 
 	if (!iomap[0] || !iomap[1] || !iomap[2] || !iomap[3] || !iomap[4])
 		return -ENOMEM;
 
-	/* We have to do our own plumbing as the PCI setup for this
-	   chipset is non-standard so we can't punt to the libata code */
-
-	INIT_LIST_HEAD(&probe[0].node);
-	probe[0].dev = pci_dev_to_dev(dev);
-	probe[0].port_ops = &cs5520_port_ops;
-	probe[0].sht = &cs5520_sht;
-	probe[0].pio_mask = 0x1F;
-	probe[0].mwdma_mask = id->driver_data;
-	probe[0].irq = 14;
-	probe[0].irq_flags = 0;
-	probe[0].port_flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST;
-	probe[0].n_ports = 1;
-	probe[0].port[0].cmd_addr = iomap[0];
-	probe[0].port[0].ctl_addr = iomap[1];
-	probe[0].port[0].altstatus_addr = iomap[1];
-	probe[0].port[0].bmdma_addr = iomap[4];
-
-	/* The secondary lurks at different addresses but is otherwise
-	   the same beastie */
-
-	probe[1] = probe[0];
-	INIT_LIST_HEAD(&probe[1].node);
-	probe[1].irq = 15;
-	probe[1].port[0].cmd_addr = iomap[2];
-	probe[1].port[0].ctl_addr = iomap[3];
-	probe[1].port[0].altstatus_addr = iomap[3];
-	probe[1].port[0].bmdma_addr = iomap[4] + 8;
-
-	/* Let libata fill in the port details */
-	ata_std_ports(&probe[0].port[0]);
-	ata_std_ports(&probe[1].port[0]);
-
-	/* Now add the ports that are active */
-	if (pcicfg & 1)
-		ports += ata_device_add(&probe[0]);
-	if (pcicfg & 2)
-		ports += ata_device_add(&probe[1]);
-	if (ports)
-		return 0;
-	return -ENODEV;
+	ioaddr = &host->ports[0]->ioaddr;
+	ioaddr->cmd_addr = iomap[0];
+	ioaddr->ctl_addr = iomap[1];
+	ioaddr->altstatus_addr = iomap[1];
+	ioaddr->bmdma_addr = iomap[4];
+	ata_std_ports(ioaddr);
+
+	ioaddr = &host->ports[1]->ioaddr;
+	ioaddr->cmd_addr = iomap[2];
+	ioaddr->ctl_addr = iomap[3];
+	ioaddr->altstatus_addr = iomap[3];
+	ioaddr->bmdma_addr = iomap[4] + 8;
+	ata_std_ports(ioaddr);
+
+	/* activate the host */
+	pci_set_master(pdev);
+	rc = ata_host_start(host);
+	if (rc)
+		return rc;
+
+	for (i = 0; i < 2; i++) {
+		static const int irq[] = { 14, 15 };
+		struct ata_port *ap = host->ports[0];
+
+		if (ata_port_is_dummy(ap))
+			continue;
+
+		rc = devm_request_irq(&pdev->dev, irq[ap->port_no],
+				      ata_interrupt, 0, DRV_NAME, host);
+		if (rc)
+			return rc;
+	}
+
+	return ata_host_attach(host, &cs5520_sht);
 }
 
 /**
drivers/ata/pata_isapnp.c +23 -20

72 lines not on this page · raw message

drivers/ata/pata_ixp4xx_cf.c +17 -22
index 9a0523b..1afcdf4 100644
@@ -130,7 +130,6 @@ static struct ata_port_operations ixp4xx_port_ops = {
 	.eng_timeout	= ata_eng_timeout,
 	.data_xfer	= ixp4xx_mmio_data_xfer,
 
-	.irq_handler	= ata_interrupt,
 	.irq_clear	= ixp4xx_irq_clear,
 	.irq_on		= ata_irq_on,
 	.irq_ack	= ata_irq_ack,
@@ -173,12 +172,12 @@ static void ixp4xx_setup_port(struct ata_ioports *ioaddr,
 
 static __devinit int ixp4xx_pata_probe(struct platform_device *pdev)
 {
-	int ret;
 	unsigned int irq;
 	struct resource *cs0, *cs1;
-	struct ata_probe_ent ae;
-
+	struct ata_host *host;
+	struct ata_port *ap;
 	struct ixp4xx_pata_data *data = pdev->dev.platform_data;
+	int rc;
 
 	cs0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	cs1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
@@ -186,6 +185,12 @@ static __devinit int ixp4xx_pata_probe(struct platform_device *pdev)
 	if (!cs0 || !cs1)
 		return -EINVAL;
 
+	/* allocate host */
+	host = ata_host_alloc(&pdev->dev, 1);
+	if (!host)
+		return -ENOMEM;
+
+	/* acquire resources and fill host */
 	pdev->dev.coherent_dma_mask = DMA_32BIT_MASK;
 
 	data->cs0 = devm_ioremap(&pdev->dev, cs0->start, 0x1000);
@@ -199,32 +204,22 @@ static __devinit int ixp4xx_pata_probe(struct platform_device *pdev)
 	*data->cs0_cfg = data->cs0_bits;
 	*data->cs1_cfg = data->cs1_bits;
 
-	memset(&ae, 0, sizeof(struct ata_probe_ent));
-	INIT_LIST_HEAD(&ae.node);
+	ap = host->ports[0];
 
-	ae.dev		= &pdev->dev;
-	ae.port_ops	= &ixp4xx_port_ops;
-	ae.sht		= &ixp4xx_sht;
-	ae.n_ports	= 1;
-	ae.pio_mask	= 0x1f; /* PIO4 */
-	ae.irq		= irq;
-	ae.irq_flags	= 0;
-	ae.port_flags	= ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY
-			| ATA_FLAG_NO_ATAPI | ATA_FLAG_SRST;
+	ap->ops	= &ixp4xx_port_ops;
+	ap->pio_mask = 0x1f; /* PIO4 */
+	ap->flags |= ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY | ATA_FLAG_NO_ATAPI;
 
 	/* run in polling mode if no irq has been assigned */
 	if (!irq)
-		ae.port_flags |= ATA_FLAG_PIO_POLLING;
+		ap->flags |= ATA_FLAG_PIO_POLLING;
 
-	ixp4xx_setup_port(&ae.port[0], data);
+	ixp4xx_setup_port(&ap->ioaddr, data);
 
 	dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
 
-	ret = ata_device_add(&ae);
-	if (ret == 0)
-		return -ENODEV;
-
-	return 0;
+	/* activate host */
+	return ata_host_activate(host, irq, ata_interrupt, 0, &ixp4xx_sht);
 }
 
 static __devexit int ixp4xx_pata_remove(struct platform_device *dev)
drivers/ata/pata_legacy.c +19 -19
index fc5b73d..1fef86a 100644
@@ -709,7 +709,8 @@ static struct ata_port_operations opti82c46x_port_ops = {
 static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl, int irq)
 {
 	struct legacy_data *ld = &legacy_data[nr_legacy_host];
-	struct ata_probe_ent ae;
+	struct ata_host *host;
+	struct ata_port *ap;
 	struct platform_device *pdev;
 	struct ata_port_operations *ops = &legacy_port_ops;
 	void __iomem *io_addr, *ctrl_addr;
@@ -791,24 +792,23 @@ static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl
 	if (ops == &legacy_port_ops && (autospeed & mask))
 		ops = &simple_port_ops;
 
-	memset(&ae, 0, sizeof(struct ata_probe_ent));
-	INIT_LIST_HEAD(&ae.node);
-	ae.dev = &pdev->dev;
-	ae.port_ops = ops;
-	ae.sht = &legacy_sht;
-	ae.n_ports = 1;
-	ae.pio_mask = pio_modes;
-	ae.irq = irq;
-	ae.irq_flags = 0;
-	ae.port_flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST|iordy;
-	ae.port[0].cmd_addr = io_addr;
-	ae.port[0].altstatus_addr = ctrl_addr;
-	ae.port[0].ctl_addr = ctrl_addr;
-	ata_std_ports(&ae.port[0]);
-	ae.private_data = ld;
-
-	ret = -ENODEV;
-	if (!ata_device_add(&ae))
+	ret = -ENOMEM;
+	host = ata_host_alloc(&pdev->dev, 1);
+	if (!host)
+		goto fail;
+	ap = host->ports[0];
+
+	ap->ops = ops;
+	ap->pio_mask = pio_modes;
+	ap->flags |= ATA_FLAG_SLAVE_POSS | iordy;
+	ap->ioaddr.cmd_addr = io_addr;
+	ap->ioaddr.altstatus_addr = ctrl_addr;
+	ap->ioaddr.ctl_addr = ctrl_addr;
+	ata_std_ports(&ap->ioaddr);
+	ap->private_data = ld;
+
+	ret = ata_host_activate(host, irq, ata_interrupt, 0, &legacy_sht);
+	if (ret)
 		goto fail;
 
 	legacy_host[nr_legacy_host++] = dev_get_drvdata(&pdev->dev);
drivers/ata/pata_mpc52xx.c +21 -25

67 lines not on this page · raw message

drivers/ata/pata_mpiix.c +17 -19
index 4abe45a..ba4db4c 100644
@@ -190,7 +190,6 @@ static struct ata_port_operations mpiix_port_ops = {
 	.qc_issue	= mpiix_qc_issue_prot,
 	.data_xfer	= ata_data_xfer,
 
-	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
 	.irq_ack	= ata_irq_ack,
@@ -201,8 +200,9 @@ static struct ata_port_operations mpiix_port_ops = {
 static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
 	/* Single threaded by the PCI probe logic */
-	static struct ata_probe_ent probe;
 	static int printed_version;
+	struct ata_host *host;
+	struct ata_port *ap;
 	void __iomem *cmd_addr, *ctl_addr;
 	u16 idetim;
 	int irq;
@@ -210,6 +210,10 @@ static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 	if (!printed_version++)
 		dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n");
 
+	host = ata_host_alloc(&dev->dev, 1);
+	if (!host)
+		return -ENOMEM;
+
 	/* MPIIX has many functions which can be turned on or off according
 	   to other devices present. Make sure IDE is enabled before we try
 	   and use it */
@@ -238,27 +242,21 @@ static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 	   without BARs set fools the setup.  #2 If you pci_disable_device
 	   the MPIIX your box goes castors up */
 
-	INIT_LIST_HEAD(&probe.node);
-	probe.dev = pci_dev_to_dev(dev);
-	probe.port_ops = &mpiix_port_ops;
-	probe.sht = &mpiix_sht;
-	probe.pio_mask = 0x1F;
-	probe.irq_flags = IRQF_SHARED;
-	probe.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
-	probe.n_ports = 1;
+	ap = host->ports[0];
+	ap->ops = &mpiix_port_ops;
+	ap->pio_mask = 0x1F;
+	ap->flags |= ATA_FLAG_SLAVE_POSS;
 
-	probe.irq = irq;
-	probe.port[0].cmd_addr = cmd_addr;
-	probe.port[0].ctl_addr = ctl_addr;
-	probe.port[0].altstatus_addr = ctl_addr;
+	ap->ioaddr.cmd_addr = cmd_addr;
+	ap->ioaddr.ctl_addr = ctl_addr;
+	ap->ioaddr.altstatus_addr = ctl_addr;
 
 	/* Let libata fill in the port details */
-	ata_std_ports(&probe.port[0]);
+	ata_std_ports(&ap->ioaddr);
 
-	/* Now add the port that is active */
-	if (ata_device_add(&probe))
-		return 0;
-	return -ENODEV;
+	/* activate host */
+	return ata_host_activate(host, irq, ata_interrupt, IRQF_SHARED,
+				 &mpiix_sht);
 }
 
 static const struct pci_device_id mpiix[] = {
drivers/ata/pata_pcmcia.c +20 -20
index 103720f..85719a2 100644
@@ -90,7 +90,6 @@ static struct ata_port_operations pcmcia_port_ops = {
 
 	.data_xfer	= ata_data_xfer_noirq,
 
-	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
 	.irq_ack	= ata_irq_ack,
@@ -111,7 +110,8 @@ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
 static int pcmcia_init_one(struct pcmcia_device *pdev)
 {
-	struct ata_probe_ent ae;
+	struct ata_host *host;
+	struct ata_port *ap;
 	struct ata_pcmcia_info *info;
 	tuple_t tuple;
 	struct {
@@ -255,24 +255,24 @@ next_entry:
  	 *	Having done the PCMCIA plumbing the ATA side is relatively
  	 *	sane.
 	 */
-
-	memset(&ae, 0, sizeof(struct ata_probe_ent));
-	INIT_LIST_HEAD(&ae.node);
-	ae.dev = &pdev->dev;
-	ae.port_ops = &pcmcia_port_ops;
-	ae.sht = &pcmcia_sht;
-	ae.n_ports = 1;
-	ae.pio_mask = 1;		/* ISA so PIO 0 cycles */
-	ae.irq = pdev->irq.AssignedIRQ;
-	ae.irq_flags = IRQF_SHARED;
-	ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
-	ae.port[0].cmd_addr = io_addr;
-	ae.port[0].altstatus_addr = ctl_addr;
-	ae.port[0].ctl_addr = ctl_addr;
-	ata_std_ports(&ae.port[0]);
-
-	ret = -ENODEV;
-	if (ata_device_add(&ae) == 0)
+	ret = -ENOMEM;
+	host = ata_host_alloc(&pdev->dev, 1);
+	if (!host)
+		goto failed;
+	ap = host->ports[0];
+
+	ap->ops = &pcmcia_port_ops;
+	ap->pio_mask = 1;		/* ISA so PIO 0 cycles */
+	ap->flags |= ATA_FLAG_SLAVE_POSS;
+	ap->ioaddr.cmd_addr = io_addr;
+	ap->ioaddr.altstatus_addr = ctl_addr;
+	ap->ioaddr.ctl_addr = ctl_addr;
+	ata_std_ports(&ap->ioaddr);
+
+	/* activate */
+	ret = ata_host_activate(host, pdev->irq.AssignedIRQ, ata_interrupt,
+				IRQF_SHARED, &pcmcia_sht);
+	if (ret)
 		goto failed;
 
 	info->ndev = 1;
drivers/ata/pata_pdc2027x.c +38 -60

215 lines not on this page · raw message

drivers/ata/pata_platform.c +20 -23

78 lines not on this page · raw message

drivers/ata/pata_qdi.c +21 -24

85 lines not on this page · raw message

drivers/ata/pata_scc.c +16 -35

109 lines not on this page · raw message

drivers/ata/pata_winbond.c +46 -51

122 lines not on this page · raw message

drivers/ata/pdc_adma.c +33 -52

194 lines not on this page · raw message

Signature · 1 line
1.5.0.1
Acked-by on v1 11/12
#25 lore raw

Re: [PATCH 11/12] libata: convert the remaining PATA drivers to new init model

Quoted 2 lines

Tested pdc_adma and pata_legacy. Both are as broken as before. The rest are compile tested only.

pata_legacy should be working. If you are using the Jeff/Linus tree you'll need to remove the buggy crap for ACPI and then test.

It does still leave ports around and I need to find a sane way to probe for an ATA port presence before using libata (or have a 'no drives go away' action)

Other than the one noted NAK point the rest of the core changes look good to me and the PATA ones sane, as well as good cleanups.

author
#26 lore raw

PATCH 12/12 libata: kill probe_ent and related helpers

In reply to Tejun Heo

All drivers are converted to new init model. Kill probe_ent, ata_device_add() and ata_pci_init_native_mode().

---
 drivers/ata/libata-core.c |  153 ---------------------------------------------
 drivers/ata/libata-sff.c  |   95 ----------------------------
 drivers/ata/libata.h      |    2 -
 include/linux/libata.h    |   31 ---------
 4 files changed, 0 insertions(+), 281 deletions(-)
drivers/ata/libata-core.c +0 -153
index 4d371fb..5722026 100644
@@ -5987,131 +5987,6 @@ int ata_host_activate(struct ata_host *host, int irq,
 }
 
 /**
- *	ata_device_add - Register hardware device with ATA and SCSI layers
- *	@ent: Probe information describing hardware device to be registered
- *
- *	This function processes the information provided in the probe
- *	information struct @ent, allocates the necessary ATA and SCSI
- *	host information structures, initializes them, and registers
- *	everything with requisite kernel subsystems.
- *
- *	This function requests irqs, probes the ATA bus, and probes
- *	the SCSI bus.
- *
- *	LOCKING:
- *	PCI/etc. bus probe sem.
- *
- *	RETURNS:
- *	Number of ports registered.  Zero on error (no ports registered).
- */
-int ata_device_add(const struct ata_probe_ent *ent)
-{
-	unsigned int i;
-	struct device *dev = ent->dev;
-	struct ata_host *host;
-	int rc;
-
-	DPRINTK("ENTER\n");
-
-	if (ent->irq == 0) {
-		dev_printk(KERN_ERR, dev, "is not available: No interrupt assigned.\n");
-		return 0;
-	}
-
-	if (!ent->port_ops->error_handler &&
-	    !(ent->port_flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST))) {
-		dev_printk(KERN_ERR, dev, "no reset mechanism available\n");
-		return 0;
-	}
-
-	if (!devres_open_group(dev, ata_device_add, GFP_KERNEL))
-		return 0;
-
-	/* allocate host */
-	host = ata_host_alloc(dev, ent->n_ports);
-
-	host->irq = ent->irq;
-	host->irq2 = ent->irq2;
-	host->iomap = ent->iomap;
-	host->private_data = ent->private_data;
-	host->ops = ent->port_ops;
-	host->flags = ent->_host_flags;
-
-	for (i = 0; i < host->n_ports; i++) {
-		struct ata_port *ap = host->ports[i];
-
-		/* dummy? */
-		if (ent->dummy_port_mask & (1 << i)) {
-			ap->ops = &ata_dummy_port_ops;
-			continue;
-		}
-
-		if (ap->port_no == 1 && ent->pinfo2) {
-			ap->pio_mask = ent->pinfo2->pio_mask;
-			ap->mwdma_mask = ent->pinfo2->mwdma_mask;
-			ap->udma_mask = ent->pinfo2->udma_mask;
-			ap->flags |= ent->pinfo2->flags;
-			ap->ops = ent->pinfo2->port_ops;
-		} else {
-			ap->pio_mask = ent->pio_mask;
-			ap->mwdma_mask = ent->mwdma_mask;
-			ap->udma_mask = ent->udma_mask;
-			ap->flags |= ent->port_flags;
-			ap->ops = ent->port_ops;
-		}
-
-		memcpy(&ap->ioaddr, &ent->port[ap->port_no],
-		       sizeof(struct ata_ioports));
-	}
-
-	/* start and freeze ports before requesting IRQ */
-	rc = ata_host_start(host);
-	if (rc)
-		goto err_out;
-
-	/* obtain irq, that may be shared between channels */
-	rc = devm_request_irq(dev, ent->irq, ent->port_ops->irq_handler,
-			      ent->irq_flags, DRV_NAME, host);
-	if (rc) {
-		dev_printk(KERN_ERR, dev, "irq %lu request failed: %d\n",
-			   ent->irq, rc);
-		goto err_out;
-	}
-
-	/* do we have a second IRQ for the other channel, eg legacy mode */
-	if (ent->irq2) {
-		/* We will get weird core code crashes later if this is true
-		   so trap it now */
-		BUG_ON(ent->irq == ent->irq2);
-
-		rc = devm_request_irq(dev, ent->irq2,
-				ent->port_ops->irq_handler, ent->irq_flags,
-				DRV_NAME, host);
-		if (rc) {
-			dev_printk(KERN_ERR, dev, "irq %lu request failed: %d\n",
-				   ent->irq2, rc);
-			goto err_out;
-		}
-	}
-
-	/* resource acquisition complete */
-	devres_remove_group(dev, ata_device_add);
-
-	/* attach */
-	rc = ata_host_attach(host, ent->sht);
-	if (rc)
-		goto err_out;
-
-	VPRINTK("EXIT, returning %u\n", host->n_ports);
-	return host->n_ports; /* success */
-
- err_out:
-	devres_release_group(dev, ata_device_add);
-	VPRINTK("EXIT, returning 0\n");
-	return 0;
-}
-
-/**
  *	ata_port_detach - Detach ATA port in prepration of device removal
  *	@ap: ATA port to be detached
  *
@@ -6186,32 +6061,6 @@ void ata_host_detach(struct ata_host *host)
 		ata_port_detach(host->ports[i]);
 }
 
-struct ata_probe_ent *
-ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port)
-{
-	struct ata_probe_ent *probe_ent;
-
-	probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
-	if (!probe_ent) {
-		printk(KERN_ERR DRV_NAME "(%s): out of memory\n",
-		       kobject_name(&(dev->kobj)));
-		return NULL;
-	}
-
-	INIT_LIST_HEAD(&probe_ent->node);
-	probe_ent->dev = dev;
-
-	probe_ent->sht = port->sht;
-	probe_ent->port_flags = port->flags;
-	probe_ent->pio_mask = port->pio_mask;
-	probe_ent->mwdma_mask = port->mwdma_mask;
-	probe_ent->udma_mask = port->udma_mask;
-	probe_ent->port_ops = port->port_ops;
-	probe_ent->private_data = port->private_data;
-
-	return probe_ent;
-}
-
 /**
  *	ata_std_ports - initialize ioaddr with standard port offsets.
  *	@ioaddr: IO address structure to be initialized
@@ -6570,7 +6419,6 @@ EXPORT_SYMBOL_GPL(ata_host_alloc_pinfo);
 EXPORT_SYMBOL_GPL(ata_host_start);
 EXPORT_SYMBOL_GPL(ata_host_attach);
 EXPORT_SYMBOL_GPL(ata_host_activate);
-EXPORT_SYMBOL_GPL(ata_device_add);
 EXPORT_SYMBOL_GPL(ata_host_detach);
 EXPORT_SYMBOL_GPL(ata_sg_init);
 EXPORT_SYMBOL_GPL(ata_sg_init_one);
@@ -6653,7 +6501,6 @@ EXPORT_SYMBOL_GPL(ata_timing_merge);
 #ifdef CONFIG_PCI
 EXPORT_SYMBOL_GPL(pci_test_config_bits);
 EXPORT_SYMBOL_GPL(pci_configure_dma_masks);
-EXPORT_SYMBOL_GPL(ata_pci_init_native_mode);
 EXPORT_SYMBOL_GPL(ata_pci_init_native_host);
 EXPORT_SYMBOL_GPL(ata_pci_prepare_native_host);
 EXPORT_SYMBOL_GPL(ata_pci_init_one);
drivers/ata/libata-sff.c +0 -95

101 lines not on this page · raw message

drivers/ata/libata.h +0 -2
index 38949a2..242cc7f 100644
@@ -93,8 +93,6 @@ extern int ata_flush_cache(struct ata_device *dev);
 extern void ata_dev_init(struct ata_device *dev);
 extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg);
 extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg);
-extern struct ata_probe_ent *ata_probe_ent_alloc(struct device *dev,
-						 const struct ata_port_info *port);
 extern struct ata_port *ata_port_alloc(struct ata_host *host);
 
 /* libata-acpi.c */
include/linux/libata.h +0 -31
index 43d9356..1126184 100644
@@ -366,34 +366,6 @@ struct ata_ioports {
 	void __iomem		*scr_addr;
 };
 
-struct ata_probe_ent {
-	struct list_head	node;
-	struct device 		*dev;
-	const struct ata_port_operations *port_ops;
-	struct scsi_host_template *sht;
-	struct ata_ioports	port[ATA_MAX_PORTS];
-	unsigned int		n_ports;
-	unsigned int		dummy_port_mask;
-	unsigned int		pio_mask;
-	unsigned int		mwdma_mask;
-	unsigned int		udma_mask;
-	unsigned long		irq;
-	unsigned long		irq2;
-	unsigned int		irq_flags;
-	unsigned long		port_flags;
-	unsigned long		_host_flags;
-	void __iomem * const	*iomap;
-	void			*private_data;
-
-	/* port_info for the secondary port.  Together with irq2, it's
-	 * used to implement non-uniform secondary port.  Currently,
-	 * the only user is ata_piix combined mode.  This workaround
-	 * will be removed together with ata_probe_ent when init model
-	 * is updated.
-	 */
-	const struct ata_port_info *pinfo2;
-};
-
 struct ata_host {
 	spinlock_t		lock;
 	struct device 		*dev;
@@ -739,7 +711,6 @@ extern int ata_host_attach(struct ata_host *host,
 extern int ata_host_activate(struct ata_host *host, int irq,
 			     irq_handler_t irq_handler, unsigned long irq_flags,
 			     struct scsi_host_template *sht);
-extern int ata_device_add(const struct ata_probe_ent *ent);
 extern void ata_host_detach(struct ata_host *host);
 extern void ata_host_init(struct ata_host *, struct device *,
 			  unsigned long, const struct ata_port_operations *);
@@ -881,8 +852,6 @@ struct pci_bits {
 	unsigned long		val;
 };
 
-extern struct ata_probe_ent *
-ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int portmask);
 extern int ata_pci_init_native_host(struct ata_host *host,
 				    unsigned int port_mask);
 extern int ata_pci_prepare_native_host(struct pci_dev *pdev,
Signature · 1 line
1.5.0.1