linux-ide.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] hotplug polling, respin
@ 2007-04-25  6:25 Robin H. Johnson
  2007-04-25  6:28 ` [PATCH 1/3] libata: implement hotplug by polling Robin H. Johnson
  2007-04-25  7:08 ` [PATCH 0/3] hotplug polling, respin Tejun Heo
  0 siblings, 2 replies; 11+ messages in thread
From: Robin H. Johnson @ 2007-04-25  6:25 UTC (permalink / raw)
  To: linux-ide

[-- Attachment #1: Type: text/plain, Size: 667 bytes --]

I've been (very) slowly working on re-spinning Tejun's PMP work.

As the very first in the body of work, here is the patchset to implement
hotplug polling.

The last submission of this
(http://thread.gmane.org/gmane.linux.ide/13467) already had a tentative
ACK, pending a link power-saving patchset, that I can't find more
details on.

I only have sata_nv and sata_sil24 online for testing, but it does work
fine for both of those (and Tejun had previously tested many more
controllers).

-- 
Robin Hugh Johnson
Gentoo Linux Developer & Council Member
E-Mail     : robbat2@gentoo.org
GnuPG FP   : 11AC BA4F 4778 E3F6 E4ED  F38E B27B 944E 3488 4E85

[-- Attachment #2: Type: application/pgp-signature, Size: 321 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 1/3] libata: implement hotplug by polling
  2007-04-25  6:25 [PATCH 0/3] hotplug polling, respin Robin H. Johnson
@ 2007-04-25  6:28 ` Robin H. Johnson
  2007-04-25  7:10   ` [PATCH 1/3 take2] " Robin H. Johnson
  2007-04-25  7:13   ` [PATCH 2/3] libata: add hp-poll support to controllers with hotplug interrupts Robin H. Johnson
  2007-04-25  7:08 ` [PATCH 0/3] hotplug polling, respin Tejun Heo
  1 sibling, 2 replies; 11+ messages in thread
From: Robin H. Johnson @ 2007-04-25  6:28 UTC (permalink / raw)
  To: linux-ide; +Cc: htejun, robbat2

[-- Attachment #1: Type: text/plain, Size: 13136 bytes --]

This patch implements hotplug by polling - hp-poll.  It is used for

* hotplug event detection on controllers which don't provide PHY
  status changed interrupt.

* hotplug event detection on disabled ports after reset failure.
  libata used to leave such ports in frozen state to protect the
  system from malfunctioning controller/device.  With hp-poll, hotplug
  events no such ports are watched safely by polling, such that
  removing/replacing the malfunctioning device triggers EH retry on
  the port.

There are three port ops for hp-poll - hp_poll_activate, hp_poll,
hp_poll_deactivate.  Only hp_poll is mandatory for hp-poll to work.
This patch also implements SATA standard polling callbacks which poll
SError.N/X bits - sata_std_hp_poll_activate() and sata_std_hp_poll().

By default, hp-poll is enabled only on disabled ports.  If a LLD
doesn't support hotplug interrupts but can poll for hotplug events, it
should indicate so by setting ATA_FLAG_HP_POLLING which tells libata
to turn on hp-poll by default.

(This revision contains cleanups that prevent the original patch from working
on newer kernels - robbat2).

Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Robin H. Johnson <robbat2@gentoo.org>
---
 drivers/ata/libata-core.c |   80 +++++++++++++++++++++++++++++-
 drivers/ata/libata-eh.c   |  122 ++++++++++++++++++++++++++++++++++++++++++++-
 drivers/ata/libata.h      |    2 +
 include/linux/libata.h    |   11 ++++
 4 files changed, 212 insertions(+), 3 deletions(-)

diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 6d0a946..68ea34b 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -3498,6 +3498,76 @@ void ata_std_postreset(struct ata_port *ap, unsigned int *classes)
 }
 
 /**
+ *	sata_std_hp_poll_activate - standard SATA hotplug polling activation
+ *	@ap: the target ata_port
+ *
+ *	Activate SATA std hotplug polling.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ */
+void sata_std_hp_poll_activate(struct ata_port *ap)
+{
+	u32 serror;
+
+	sata_scr_read(ap, SCR_ERROR, &serror);
+	serror &= SERR_PHYRDY_CHG | SERR_DEV_XCHG;
+	if (serror)
+		sata_scr_write(ap, SCR_ERROR, serror);
+
+	ap->hp_poll_data = 0;
+}
+
+/**
+ *	sata_std_hp_poll - standard SATA hotplug polling callback
+ *	@ap: the target ata_port
+ *
+ *	Poll SError.N/X for hotplug event.  Hotplug event is triggered
+ *	only after PHY stays stable for at least one full polling
+ *	interval after the first event detection.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *	1 if hotplug event has occurred, 0 otherwise.
+ */
+int sata_std_hp_poll(struct ata_port *ap)
+{
+	unsigned long state = (unsigned long)ap->hp_poll_data;
+	u32 serror;
+	int rc = 0;
+
+	sata_scr_read(ap, SCR_ERROR, &serror);
+	serror &= SERR_PHYRDY_CHG | SERR_DEV_XCHG;
+
+	switch (state) {
+	case 0:
+		if (serror) {
+			/* PHY status could be bouncing crazy due to
+			 * faulty controller or device.  Don't fire
+			 * hotplug event till hotplug event stays
+			 * quiescent for one full polling interval.
+			 */
+			sata_scr_write(ap, SCR_ERROR, serror);
+			state = 1;
+		}
+		break;
+
+	case 1:
+		if (!serror)
+			rc = 1;
+		else
+			sata_scr_write(ap, SCR_ERROR, serror);
+		break;
+	}
+
+	ap->hp_poll_data = (void *)state;
+
+	return rc;
+}
+
+/**
  *	ata_dev_same_device - Determine whether new ID matches configured device
  *	@dev: device to compare against
  *	@new_class: class of the new device
@@ -6160,6 +6230,7 @@ void ata_host_init(struct ata_host *host, struct device *dev,
 	host->dev = dev;
 	host->flags = flags;
 	host->ops = ops;
+	INIT_DELAYED_WORK(&host->hp_poll_task, ata_hp_poll_worker);
 }
 
 /**
@@ -6387,11 +6458,15 @@ void ata_port_detach(struct ata_port *ap)
 
 	ata_port_wait_eh(ap);
 
-	/* Flush hotplug task.  The sequence is similar to
+	/* deactivate hotplug polling */
+	ata_hp_poll_deactivate(ap);
+
+	/* Flush hotplug tasks.  The sequence is similar to
 	 * ata_port_flush_task().
 	 */
 	flush_workqueue(ata_aux_wq);
 	cancel_delayed_work(&ap->hotplug_task);
+	cancel_delayed_work(&ap->host->hp_poll_task);
 	flush_workqueue(ata_aux_wq);
 
  skip_eh:
@@ -6752,6 +6827,9 @@ EXPORT_SYMBOL_GPL(ata_std_softreset);
 EXPORT_SYMBOL_GPL(sata_port_hardreset);
 EXPORT_SYMBOL_GPL(sata_std_hardreset);
 EXPORT_SYMBOL_GPL(ata_std_postreset);
+EXPORT_SYMBOL_GPL(sata_std_hp_poll_activate);
+EXPORT_SYMBOL_GPL(sata_std_hp_poll);
+EXPORT_SYMBOL_GPL(ata_dev_revalidate);
 EXPORT_SYMBOL_GPL(ata_dev_classify);
 EXPORT_SYMBOL_GPL(ata_dev_pair);
 EXPORT_SYMBOL_GPL(ata_port_disable);
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 0dbee55..d70aa04 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -33,6 +33,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_eh.h>
@@ -49,6 +50,10 @@ enum {
 	ATA_EH_SPDN_SPEED_DOWN		= (1 << 1),
 	ATA_EH_SPDN_FALLBACK_TO_PIO	= (1 << 2),
 };
+static unsigned long hotplug_polling_interval = 2000;
+module_param(hotplug_polling_interval, ulong, 0644);
+MODULE_PARM_DESC(hotplug_polling_interval,
+		 "Hotplug polling interval in milliseconds (default 2000)");
 
 static void __ata_port_freeze(struct ata_port *ap);
 static void ata_eh_finish(struct ata_port *ap);
@@ -62,6 +67,7 @@ static int ata_eh_resume(struct ata_port *ap, struct ata_device **r_failed_dev);
 #else /* CONFIG_PM */
 static void ata_eh_handle_port_suspend(struct ata_port *ap)
 { }
+static void ata_hp_poll_activate(struct ata_port *ap);
 
 static void ata_eh_handle_port_resume(struct ata_port *ap)
 { }
@@ -644,7 +650,10 @@ int ata_port_freeze(struct ata_port *ap)
  *	ata_eh_freeze_port - EH helper to freeze port
  *	@ap: ATA port to freeze
  *
- *	Freeze @ap.
+ *	Freeze @ap.  As the 'freeze' operation means 'shutdown event
+ *	reporting', it is a perfect place to deactivate hp-poll.  Note
+ *	that ata_port_freeze() always invokes EH and eventually this
+ *	function, so deactivating hp-poll in this function is enough.
  *
  *	LOCKING:
  *	None.
@@ -656,6 +665,8 @@ void ata_eh_freeze_port(struct ata_port *ap)
 	if (!ap->ops->error_handler)
 		return;
 
+	ata_hp_poll_deactivate(ap);
+
 	spin_lock_irqsave(ap->lock, flags);
 	__ata_port_freeze(ap);
 	spin_unlock_irqrestore(ap->lock, flags);
@@ -665,7 +676,7 @@ void ata_eh_freeze_port(struct ata_port *ap)
  *	ata_port_thaw_port - EH helper to thaw port
  *	@ap: ATA port to thaw
  *
- *	Thaw frozen port @ap.
+ *	Thaw frozen port @ap and activate hp-poll if necessary.
  *
  *	LOCKING:
  *	None.
@@ -686,6 +697,9 @@ void ata_eh_thaw_port(struct ata_port *ap)
 
 	spin_unlock_irqrestore(ap->lock, flags);
 
+	if (ap->flags & ATA_FLAG_HP_POLLING)
+		ata_hp_poll_activate(ap);
+
 	DPRINTK("ata%u port thawed\n", ap->print_id);
 }
 
@@ -2229,6 +2243,9 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
 
  out:
 	if (rc) {
+		/* recovery failed, activate hp-poll */
+		ata_hp_poll_activate(ap);
+
 		for (i = 0; i < ATA_MAX_DEVICES; i++)
 			ata_dev_disable(&ap->device[i]);
 	}
@@ -2419,3 +2436,104 @@ static void ata_eh_handle_port_resume(struct ata_port *ap)
 	spin_unlock_irqrestore(ap->lock, flags);
 }
 #endif /* CONFIG_PM */
+
+static unsigned long ata_hp_poll_delay(void)
+{
+	unsigned long interval, now;
+
+	/* Group polls to polling interval boundaries to allow cpu to
+	 * go idle as much as possible.
+	 */
+	interval = hotplug_polling_interval * HZ / 1000;
+	now = jiffies;
+	return roundup(now + 1, interval) - now;
+}
+
+/**
+ *	ata_hp_poll_activate - activate hotplug polling
+ *	@ap: host port to activate hotplug polling for
+ *
+ *	Activate hotplug probing for @ap.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ */
+static void ata_hp_poll_activate(struct ata_port *ap)
+{
+	unsigned long flags;
+
+	if (!ap->ops->hp_poll || (ap->pflags & ATA_PFLAG_HP_POLL))
+		return;
+
+	if (ap->ops->hp_poll_activate)
+		ap->ops->hp_poll_activate(ap);
+
+	queue_delayed_work(ata_aux_wq, &ap->host->hp_poll_task,
+			   ata_hp_poll_delay());
+	ap->hp_poll_data = 0;
+
+	spin_lock_irqsave(ap->lock, flags);
+	ap->pflags |= ATA_PFLAG_HP_POLL;
+	spin_unlock_irqrestore(ap->lock, flags);
+}
+
+/**
+ *	ata_hp_poll_deactivate - deactivate hotplug polling
+ *	@ap: host port to deactivate hotplug polling for
+ *
+ *	Deactivate hotplug probing for @ap.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ */
+void ata_hp_poll_deactivate(struct ata_port *ap)
+{
+	unsigned long flags;
+
+	if (!(ap->pflags & ATA_PFLAG_HP_POLL))
+		return;
+
+	spin_lock_irqsave(ap->lock, flags);
+	ap->pflags &= ~ATA_PFLAG_HP_POLL;
+	spin_unlock_irqrestore(ap->lock, flags);
+
+	if (ap->ops->hp_poll_deactivate)
+		ap->ops->hp_poll_deactivate(ap);
+}
+
+void ata_hp_poll_worker(struct work_struct *work)
+{
+	struct ata_host *host =
+		container_of(work, struct ata_host, hp_poll_task.work);
+	int i, nr_to_poll = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	for (i = 0; i < host->n_ports; i++) {
+		struct ata_port *ap = host->ports[i];
+		int rc;
+
+		if (!(ap->pflags & ATA_PFLAG_HP_POLL))
+			continue;
+
+		/* Poll.  Positive return value indicates hotplug
+		 * event while negative indicates error condition.
+		 */
+		rc = ap->ops->hp_poll(ap);
+		if (rc) {
+			if (rc > 0) {
+				ata_ehi_hotplugged(&ap->eh_info);
+				ata_port_freeze(ap);
+			}
+			ap->pflags &= ~ATA_PFLAG_HP_POLL;
+		} else
+			nr_to_poll++;
+	}
+
+	spin_unlock_irqrestore(&host->lock, flags);
+
+	if (nr_to_poll)
+		queue_delayed_work(ata_aux_wq, &host->hp_poll_task,
+				   ata_hp_poll_delay());
+}
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 5f4d40c..52377dd 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -153,6 +153,8 @@ extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
 extern void ata_scsi_error(struct Scsi_Host *host);
 extern void ata_port_wait_eh(struct ata_port *ap);
 extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc);
+extern void ata_hp_poll_worker(struct work_struct *work);
+extern void ata_hp_poll_deactivate(struct ata_port *ap);
 
 /* libata-sff.c */
 extern u8 ata_irq_on(struct ata_port *ap);
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 73b86dd..0fd2a8b 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -174,6 +174,7 @@ enum {
 	ATA_FLAG_SETXFER_POLLING= (1 << 14), /* use polling for SETXFER */
 	ATA_FLAG_IGN_SIMPLEX	= (1 << 15), /* ignore SIMPLEX */
 	ATA_FLAG_NO_IORDY	= (1 << 16), /* controller lacks iordy */
+	ATA_FLAG_HP_POLLING	= (1 << 17), /* hotplug by polling */
 
 	/* The following flag belongs to ap->pflags but is kept in
 	 * ap->flags because it's referenced in many LLDs and will be
@@ -191,6 +192,7 @@ enum {
 	ATA_PFLAG_LOADING	= (1 << 4), /* boot/loading probe */
 	ATA_PFLAG_UNLOADING	= (1 << 5), /* module is unloading */
 	ATA_PFLAG_SCSI_HOTPLUG	= (1 << 6), /* SCSI hotplug scheduled */
+	ATA_PFLAG_HP_POLL	= (1 << 7), /* hp-poll active */
 
 	ATA_PFLAG_FLUSH_PORT_TASK = (1 << 16), /* flush port task */
 	ATA_PFLAG_SUSPENDED	= (1 << 17), /* port is suspended (power) */
@@ -379,6 +381,7 @@ struct ata_host {
 	const struct ata_port_operations *ops;
 	unsigned long		flags;
 	struct ata_port		*simplex_claimed;	/* channel owning the DMA */
+	struct delayed_work	hp_poll_task;
 	struct ata_port		*ports[0];
 };
 
@@ -564,6 +567,7 @@ struct ata_port {
 	pm_message_t		pm_mesg;
 	int			*pm_result;
 
+	void			*hp_poll_data;
 	void			*private_data;
 
 	u8			sector_buf[ATA_SECT_SIZE]; /* owned by EH */
@@ -613,6 +617,10 @@ struct ata_port_operations {
 	void (*error_handler) (struct ata_port *ap);
 	void (*post_internal_cmd) (struct ata_queued_cmd *qc);
 
+	void (*hp_poll_activate) (struct ata_port *ap);
+	void (*hp_poll_deactivate) (struct ata_port *ap);
+	int (*hp_poll) (struct ata_port *ap);
+
 	irq_handler_t irq_handler;
 	void (*irq_clear) (struct ata_port *);
 	u8 (*irq_on) (struct ata_port *);
@@ -694,6 +702,9 @@ extern int sata_port_hardreset(struct ata_port *ap,
 			       const unsigned long *timing);
 extern int sata_std_hardreset(struct ata_port *ap, unsigned int *class);
 extern void ata_std_postreset(struct ata_port *ap, unsigned int *classes);
+extern void sata_std_hp_poll_activate(struct ata_port *ap);
+extern int sata_std_hp_poll(struct ata_port *ap);
+extern int ata_dev_revalidate(struct ata_device *dev, unsigned int flags);
 extern void ata_port_disable(struct ata_port *);
 extern void ata_std_ports(struct ata_ioports *ioaddr);
 #ifdef CONFIG_PCI



-- 
Robin Hugh Johnson
Gentoo Linux Developer & Council Member
E-Mail     : robbat2@gentoo.org
GnuPG FP   : 11AC BA4F 4778 E3F6 E4ED  F38E B27B 944E 3488 4E85

[-- Attachment #2: Type: application/pgp-signature, Size: 321 bytes --]

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH 0/3] hotplug polling, respin
  2007-04-25  6:25 [PATCH 0/3] hotplug polling, respin Robin H. Johnson
  2007-04-25  6:28 ` [PATCH 1/3] libata: implement hotplug by polling Robin H. Johnson
@ 2007-04-25  7:08 ` Tejun Heo
  2007-04-25  7:30   ` Robin H. Johnson
  2007-04-25 14:35   ` Jeff Garzik
  1 sibling, 2 replies; 11+ messages in thread
From: Tejun Heo @ 2007-04-25  7:08 UTC (permalink / raw)
  To: linux-ide; +Cc: Jeff Garzik

[cc'ing Jeff]

Robin H. Johnson wrote:
> I've been (very) slowly working on re-spinning Tejun's PMP work.
> 
> As the very first in the body of work, here is the patchset to implement
> hotplug polling.
> 
> The last submission of this
> (http://thread.gmane.org/gmane.linux.ide/13467) already had a tentative
> ACK, pending a link power-saving patchset, that I can't find more
> details on.

Yeap, the implementation is ACKed but interface to userland is NACKed.
We need sysfs nodes for ATA devices to do userland interface properly.
I'm working hard to get there.

Thanks a lot for taking care of these patches.  A lot of people have
been asking for patches for newer kernels and I couldn't find time to
update them.

Jeff, can we make a page for PMP patches in linux-ata.org?  It would be
a much better place to direct people to.

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 1/3 take2] libata: implement hotplug by polling
  2007-04-25  6:28 ` [PATCH 1/3] libata: implement hotplug by polling Robin H. Johnson
@ 2007-04-25  7:10   ` Robin H. Johnson
  2007-04-25  7:13   ` [PATCH 2/3] libata: add hp-poll support to controllers with hotplug interrupts Robin H. Johnson
  1 sibling, 0 replies; 11+ messages in thread
From: Robin H. Johnson @ 2007-04-25  7:10 UTC (permalink / raw)
  To: linux-ide; +Cc: htejun, robbat2gentoo.org

[-- Attachment #1: Type: text/plain, Size: 13198 bytes --]

This patch implements hotplug by polling - hp-poll.  It is used for

* hotplug event detection on controllers which don't provide PHY
  status changed interrupt.

* hotplug event detection on disabled ports after reset failure.
  libata used to leave such ports in frozen state to protect the
  system from malfunctioning controller/device.  With hp-poll, hotplug
  events no such ports are watched safely by polling, such that
  removing/replacing the malfunctioning device triggers EH retry on
  the port.

There are three port ops for hp-poll - hp_poll_activate, hp_poll,
hp_poll_deactivate.  Only hp_poll is mandatory for hp-poll to work.
This patch also implements SATA standard polling callbacks which poll
SError.N/X bits - sata_std_hp_poll_activate() and sata_std_hp_poll().

By default, hp-poll is enabled only on disabled ports.  If a LLD
doesn't support hotplug interrupts but can poll for hotplug events, it
should indicate so by setting ATA_FLAG_HP_POLLING which tells libata
to turn on hp-poll by default.

(This revision contains cleanups that prevent the original patch from working
on newer kernels - robbat2).

Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Robin H. Johnson <robbat2@gentoo.org>

-----
The previous version contained a slight mis-merge. A prototype got placed
inside the else tree of CONFIG_PM accidently. This revision just moves it to
the correct place.
---
 drivers/ata/libata-core.c |   80 +++++++++++++++++++++++++++++-
 drivers/ata/libata-eh.c   |  122 ++++++++++++++++++++++++++++++++++++++++++++-
 drivers/ata/libata.h      |    2 +
 include/linux/libata.h    |   11 ++++
 4 files changed, 212 insertions(+), 3 deletions(-)

diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 6d0a946..68ea34b 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -3498,6 +3498,76 @@ void ata_std_postreset(struct ata_port *ap, unsigned int *classes)
 }
 
 /**
+ *	sata_std_hp_poll_activate - standard SATA hotplug polling activation
+ *	@ap: the target ata_port
+ *
+ *	Activate SATA std hotplug polling.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ */
+void sata_std_hp_poll_activate(struct ata_port *ap)
+{
+	u32 serror;
+
+	sata_scr_read(ap, SCR_ERROR, &serror);
+	serror &= SERR_PHYRDY_CHG | SERR_DEV_XCHG;
+	if (serror)
+		sata_scr_write(ap, SCR_ERROR, serror);
+
+	ap->hp_poll_data = 0;
+}
+
+/**
+ *	sata_std_hp_poll - standard SATA hotplug polling callback
+ *	@ap: the target ata_port
+ *
+ *	Poll SError.N/X for hotplug event.  Hotplug event is triggered
+ *	only after PHY stays stable for at least one full polling
+ *	interval after the first event detection.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *	1 if hotplug event has occurred, 0 otherwise.
+ */
+int sata_std_hp_poll(struct ata_port *ap)
+{
+	unsigned long state = (unsigned long)ap->hp_poll_data;
+	u32 serror;
+	int rc = 0;
+
+	sata_scr_read(ap, SCR_ERROR, &serror);
+	serror &= SERR_PHYRDY_CHG | SERR_DEV_XCHG;
+
+	switch (state) {
+	case 0:
+		if (serror) {
+			/* PHY status could be bouncing crazy due to
+			 * faulty controller or device.  Don't fire
+			 * hotplug event till hotplug event stays
+			 * quiescent for one full polling interval.
+			 */
+			sata_scr_write(ap, SCR_ERROR, serror);
+			state = 1;
+		}
+		break;
+
+	case 1:
+		if (!serror)
+			rc = 1;
+		else
+			sata_scr_write(ap, SCR_ERROR, serror);
+		break;
+	}
+
+	ap->hp_poll_data = (void *)state;
+
+	return rc;
+}
+
+/**
  *	ata_dev_same_device - Determine whether new ID matches configured device
  *	@dev: device to compare against
  *	@new_class: class of the new device
@@ -6160,6 +6230,7 @@ void ata_host_init(struct ata_host *host, struct device *dev,
 	host->dev = dev;
 	host->flags = flags;
 	host->ops = ops;
+	INIT_DELAYED_WORK(&host->hp_poll_task, ata_hp_poll_worker);
 }
 
 /**
@@ -6387,11 +6458,15 @@ void ata_port_detach(struct ata_port *ap)
 
 	ata_port_wait_eh(ap);
 
-	/* Flush hotplug task.  The sequence is similar to
+	/* deactivate hotplug polling */
+	ata_hp_poll_deactivate(ap);
+
+	/* Flush hotplug tasks.  The sequence is similar to
 	 * ata_port_flush_task().
 	 */
 	flush_workqueue(ata_aux_wq);
 	cancel_delayed_work(&ap->hotplug_task);
+	cancel_delayed_work(&ap->host->hp_poll_task);
 	flush_workqueue(ata_aux_wq);
 
  skip_eh:
@@ -6752,6 +6827,9 @@ EXPORT_SYMBOL_GPL(ata_std_softreset);
 EXPORT_SYMBOL_GPL(sata_port_hardreset);
 EXPORT_SYMBOL_GPL(sata_std_hardreset);
 EXPORT_SYMBOL_GPL(ata_std_postreset);
+EXPORT_SYMBOL_GPL(sata_std_hp_poll_activate);
+EXPORT_SYMBOL_GPL(sata_std_hp_poll);
+EXPORT_SYMBOL_GPL(ata_dev_revalidate);
 EXPORT_SYMBOL_GPL(ata_dev_classify);
 EXPORT_SYMBOL_GPL(ata_dev_pair);
 EXPORT_SYMBOL_GPL(ata_port_disable);
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 0dbee55..c2bd0d5 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -33,6 +33,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_eh.h>
@@ -49,9 +50,14 @@ enum {
 	ATA_EH_SPDN_SPEED_DOWN		= (1 << 1),
 	ATA_EH_SPDN_FALLBACK_TO_PIO	= (1 << 2),
 };
+static unsigned long hotplug_polling_interval = 2000;
+module_param(hotplug_polling_interval, ulong, 0644);
+MODULE_PARM_DESC(hotplug_polling_interval,
+		 "Hotplug polling interval in milliseconds (default 2000)");
 
 static void __ata_port_freeze(struct ata_port *ap);
 static void ata_eh_finish(struct ata_port *ap);
+static void ata_hp_poll_activate(struct ata_port *ap);
 #ifdef CONFIG_PM
 static void ata_eh_handle_port_suspend(struct ata_port *ap);
 static void ata_eh_handle_port_resume(struct ata_port *ap);
@@ -644,7 +650,10 @@ int ata_port_freeze(struct ata_port *ap)
  *	ata_eh_freeze_port - EH helper to freeze port
  *	@ap: ATA port to freeze
  *
- *	Freeze @ap.
+ *	Freeze @ap.  As the 'freeze' operation means 'shutdown event
+ *	reporting', it is a perfect place to deactivate hp-poll.  Note
+ *	that ata_port_freeze() always invokes EH and eventually this
+ *	function, so deactivating hp-poll in this function is enough.
  *
  *	LOCKING:
  *	None.
@@ -656,6 +665,8 @@ void ata_eh_freeze_port(struct ata_port *ap)
 	if (!ap->ops->error_handler)
 		return;
 
+	ata_hp_poll_deactivate(ap);
+
 	spin_lock_irqsave(ap->lock, flags);
 	__ata_port_freeze(ap);
 	spin_unlock_irqrestore(ap->lock, flags);
@@ -665,7 +676,7 @@ void ata_eh_freeze_port(struct ata_port *ap)
  *	ata_port_thaw_port - EH helper to thaw port
  *	@ap: ATA port to thaw
  *
- *	Thaw frozen port @ap.
+ *	Thaw frozen port @ap and activate hp-poll if necessary.
  *
  *	LOCKING:
  *	None.
@@ -686,6 +697,9 @@ void ata_eh_thaw_port(struct ata_port *ap)
 
 	spin_unlock_irqrestore(ap->lock, flags);
 
+	if (ap->flags & ATA_FLAG_HP_POLLING)
+		ata_hp_poll_activate(ap);
+
 	DPRINTK("ata%u port thawed\n", ap->print_id);
 }
 
@@ -2229,6 +2243,9 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
 
  out:
 	if (rc) {
+		/* recovery failed, activate hp-poll */
+		ata_hp_poll_activate(ap);
+
 		for (i = 0; i < ATA_MAX_DEVICES; i++)
 			ata_dev_disable(&ap->device[i]);
 	}
@@ -2419,3 +2436,104 @@ static void ata_eh_handle_port_resume(struct ata_port *ap)
 	spin_unlock_irqrestore(ap->lock, flags);
 }
 #endif /* CONFIG_PM */
+
+static unsigned long ata_hp_poll_delay(void)
+{
+	unsigned long interval, now;
+
+	/* Group polls to polling interval boundaries to allow cpu to
+	 * go idle as much as possible.
+	 */
+	interval = hotplug_polling_interval * HZ / 1000;
+	now = jiffies;
+	return roundup(now + 1, interval) - now;
+}
+
+/**
+ *	ata_hp_poll_activate - activate hotplug polling
+ *	@ap: host port to activate hotplug polling for
+ *
+ *	Activate hotplug probing for @ap.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ */
+static void ata_hp_poll_activate(struct ata_port *ap)
+{
+	unsigned long flags;
+
+	if (!ap->ops->hp_poll || (ap->pflags & ATA_PFLAG_HP_POLL))
+		return;
+
+	if (ap->ops->hp_poll_activate)
+		ap->ops->hp_poll_activate(ap);
+
+	queue_delayed_work(ata_aux_wq, &ap->host->hp_poll_task,
+			   ata_hp_poll_delay());
+	ap->hp_poll_data = 0;
+
+	spin_lock_irqsave(ap->lock, flags);
+	ap->pflags |= ATA_PFLAG_HP_POLL;
+	spin_unlock_irqrestore(ap->lock, flags);
+}
+
+/**
+ *	ata_hp_poll_deactivate - deactivate hotplug polling
+ *	@ap: host port to deactivate hotplug polling for
+ *
+ *	Deactivate hotplug probing for @ap.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ */
+void ata_hp_poll_deactivate(struct ata_port *ap)
+{
+	unsigned long flags;
+
+	if (!(ap->pflags & ATA_PFLAG_HP_POLL))
+		return;
+
+	spin_lock_irqsave(ap->lock, flags);
+	ap->pflags &= ~ATA_PFLAG_HP_POLL;
+	spin_unlock_irqrestore(ap->lock, flags);
+
+	if (ap->ops->hp_poll_deactivate)
+		ap->ops->hp_poll_deactivate(ap);
+}
+
+void ata_hp_poll_worker(struct work_struct *work)
+{
+	struct ata_host *host =
+		container_of(work, struct ata_host, hp_poll_task.work);
+	int i, nr_to_poll = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	for (i = 0; i < host->n_ports; i++) {
+		struct ata_port *ap = host->ports[i];
+		int rc;
+
+		if (!(ap->pflags & ATA_PFLAG_HP_POLL))
+			continue;
+
+		/* Poll.  Positive return value indicates hotplug
+		 * event while negative indicates error condition.
+		 */
+		rc = ap->ops->hp_poll(ap);
+		if (rc) {
+			if (rc > 0) {
+				ata_ehi_hotplugged(&ap->eh_info);
+				ata_port_freeze(ap);
+			}
+			ap->pflags &= ~ATA_PFLAG_HP_POLL;
+		} else
+			nr_to_poll++;
+	}
+
+	spin_unlock_irqrestore(&host->lock, flags);
+
+	if (nr_to_poll)
+		queue_delayed_work(ata_aux_wq, &host->hp_poll_task,
+				   ata_hp_poll_delay());
+}
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 5f4d40c..52377dd 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -153,6 +153,8 @@ extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
 extern void ata_scsi_error(struct Scsi_Host *host);
 extern void ata_port_wait_eh(struct ata_port *ap);
 extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc);
+extern void ata_hp_poll_worker(struct work_struct *work);
+extern void ata_hp_poll_deactivate(struct ata_port *ap);
 
 /* libata-sff.c */
 extern u8 ata_irq_on(struct ata_port *ap);
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 73b86dd..0fd2a8b 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -174,6 +174,7 @@ enum {
 	ATA_FLAG_SETXFER_POLLING= (1 << 14), /* use polling for SETXFER */
 	ATA_FLAG_IGN_SIMPLEX	= (1 << 15), /* ignore SIMPLEX */
 	ATA_FLAG_NO_IORDY	= (1 << 16), /* controller lacks iordy */
+	ATA_FLAG_HP_POLLING	= (1 << 17), /* hotplug by polling */
 
 	/* The following flag belongs to ap->pflags but is kept in
 	 * ap->flags because it's referenced in many LLDs and will be
@@ -191,6 +192,7 @@ enum {
 	ATA_PFLAG_LOADING	= (1 << 4), /* boot/loading probe */
 	ATA_PFLAG_UNLOADING	= (1 << 5), /* module is unloading */
 	ATA_PFLAG_SCSI_HOTPLUG	= (1 << 6), /* SCSI hotplug scheduled */
+	ATA_PFLAG_HP_POLL	= (1 << 7), /* hp-poll active */
 
 	ATA_PFLAG_FLUSH_PORT_TASK = (1 << 16), /* flush port task */
 	ATA_PFLAG_SUSPENDED	= (1 << 17), /* port is suspended (power) */
@@ -379,6 +381,7 @@ struct ata_host {
 	const struct ata_port_operations *ops;
 	unsigned long		flags;
 	struct ata_port		*simplex_claimed;	/* channel owning the DMA */
+	struct delayed_work	hp_poll_task;
 	struct ata_port		*ports[0];
 };
 
@@ -564,6 +567,7 @@ struct ata_port {
 	pm_message_t		pm_mesg;
 	int			*pm_result;
 
+	void			*hp_poll_data;
 	void			*private_data;
 
 	u8			sector_buf[ATA_SECT_SIZE]; /* owned by EH */
@@ -613,6 +617,10 @@ struct ata_port_operations {
 	void (*error_handler) (struct ata_port *ap);
 	void (*post_internal_cmd) (struct ata_queued_cmd *qc);
 
+	void (*hp_poll_activate) (struct ata_port *ap);
+	void (*hp_poll_deactivate) (struct ata_port *ap);
+	int (*hp_poll) (struct ata_port *ap);
+
 	irq_handler_t irq_handler;
 	void (*irq_clear) (struct ata_port *);
 	u8 (*irq_on) (struct ata_port *);
@@ -694,6 +702,9 @@ extern int sata_port_hardreset(struct ata_port *ap,
 			       const unsigned long *timing);
 extern int sata_std_hardreset(struct ata_port *ap, unsigned int *class);
 extern void ata_std_postreset(struct ata_port *ap, unsigned int *classes);
+extern void sata_std_hp_poll_activate(struct ata_port *ap);
+extern int sata_std_hp_poll(struct ata_port *ap);
+extern int ata_dev_revalidate(struct ata_device *dev, unsigned int flags);
 extern void ata_port_disable(struct ata_port *);
 extern void ata_std_ports(struct ata_ioports *ioaddr);
 #ifdef CONFIG_PCI


-- 
Robin Hugh Johnson
Gentoo Linux Developer & Council Member
E-Mail     : robbat2@gentoo.org
GnuPG FP   : 11AC BA4F 4778 E3F6 E4ED  F38E B27B 944E 3488 4E85

[-- Attachment #2: Type: application/pgp-signature, Size: 321 bytes --]

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 2/3] libata: add hp-poll support to controllers with hotplug interrupts
  2007-04-25  6:28 ` [PATCH 1/3] libata: implement hotplug by polling Robin H. Johnson
  2007-04-25  7:10   ` [PATCH 1/3 take2] " Robin H. Johnson
@ 2007-04-25  7:13   ` Robin H. Johnson
  2007-04-25  7:15     ` [PATCH 3/3] libata: add hp-poll support to controllers without " Robin H. Johnson
  1 sibling, 1 reply; 11+ messages in thread
From: Robin H. Johnson @ 2007-04-25  7:13 UTC (permalink / raw)
  To: linux-ide; +Cc: htejun, robbat2

[-- Attachment #1: Type: text/plain, Size: 3327 bytes --]

This patch adds hp-poll support to the following drivers.

* ahci
* sata_nv (nf2 and c804 only)
* sata_sil
* sata_sil24

All the above controllers are capable of hotplug-by-interrupt and
hp-poll will be used only for watching disabled ports.

Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Robin H. Johnson <robbat2@gentoo.org>
---
 drivers/ata/ahci.c       |    4 +++-
 drivers/ata/sata_nv.c    |    6 ++++++
 drivers/ata/sata_sil.c   |    3 +++
 drivers/ata/sata_sil24.c |    3 +++
 4 files changed, 15 insertions(+), 1 deletions(-)

diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 7c61bc7..3968799 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -273,10 +273,12 @@ static const struct ata_port_operations ahci_ops = {
 
 	.freeze			= ahci_freeze,
 	.thaw			= ahci_thaw,
-
 	.error_handler		= ahci_error_handler,
 	.post_internal_cmd	= ahci_post_internal_cmd,
 
+	.hp_poll_activate	= sata_std_hp_poll_activate,
+	.hp_poll		= sata_std_hp_poll,
+
 #ifdef CONFIG_PM
 	.port_suspend		= ahci_port_suspend,
 	.port_resume		= ahci_port_resume,
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index 0216974..bcf4934 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -394,7 +394,10 @@ static const struct ata_port_operations nv_nf2_ops = {
 	.thaw			= nv_nf2_thaw,
 	.error_handler		= nv_error_handler,
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
+	.hp_poll_activate	= sata_std_hp_poll_activate,
+	.hp_poll		= sata_std_hp_poll,
 	.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,
@@ -420,7 +423,10 @@ static const struct ata_port_operations nv_ck804_ops = {
 	.thaw			= nv_ck804_thaw,
 	.error_handler		= nv_error_handler,
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
+	.hp_poll_activate	= sata_std_hp_poll_activate,
+	.hp_poll		= sata_std_hp_poll,
 	.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,
diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c
index 0a1e417..8f8cc5f 100644
--- a/drivers/ata/sata_sil.c
+++ b/drivers/ata/sata_sil.c
@@ -208,6 +208,9 @@ static const struct ata_port_operations sil_ops = {
 	.thaw			= sil_thaw,
 	.error_handler		= ata_bmdma_error_handler,
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
+	.hp_poll_activate	= sata_std_hp_poll_activate,
+	.hp_poll		= sata_std_hp_poll,
+	.irq_handler		= sil_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index e6223ba..81e6bef 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -412,6 +412,9 @@ static const struct ata_port_operations sil24_ops = {
 	.error_handler		= sil24_error_handler,
 	.post_internal_cmd	= sil24_post_internal_cmd,
 
+	.hp_poll_activate	= sata_std_hp_poll_activate,
+	.hp_poll		= sata_std_hp_poll,
+
 	.port_start		= sil24_port_start,
 };

-- 
Robin Hugh Johnson
Gentoo Linux Developer & Council Member
E-Mail     : robbat2@gentoo.org
GnuPG FP   : 11AC BA4F 4778 E3F6 E4ED  F38E B27B 944E 3488 4E85

[-- Attachment #2: Type: application/pgp-signature, Size: 321 bytes --]

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 3/3] libata: add hp-poll support to controllers without hotplug interrupts
  2007-04-25  7:13   ` [PATCH 2/3] libata: add hp-poll support to controllers with hotplug interrupts Robin H. Johnson
@ 2007-04-25  7:15     ` Robin H. Johnson
  2007-04-25  7:59       ` [PATCH 4/3] ahci: hotplug polling functions for vt8251 hardware variant Robin H. Johnson
  0 siblings, 1 reply; 11+ messages in thread
From: Robin H. Johnson @ 2007-04-25  7:15 UTC (permalink / raw)
  To: linux-ide; +Cc: htejun, robbat2

[-- Attachment #1: Type: text/plain, Size: 8393 bytes --]

This patch adds hp-poll support to the following drivers.

* sata_nv (generic)
* sata_sil (SIL_FLAG_NO_SATA_IRQ replaced w/ ATA_FLAG_HP_POLLING)
* sata_sis
* sata_svw
* sata_uli
* sata_vsc

All the above drivers currently don't support hotplug interrupts (H/W
restrictions or lack of doc/effort) and all hotplug operations should
be done via hp-poll; thus, ATA_FLAG_HP_POLLING is set for these
drivers.

sata_via is excluded because it randomly locks up on SCR register
access.

Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Robin H. Johnson <robbat2@gentoo.org>
---
 drivers/ata/sata_nv.c  |    6 +++++-
 drivers/ata/sata_sil.c |    9 ++++-----
 drivers/ata/sata_sis.c |    6 +++++-
 drivers/ata/sata_svw.c |   25 +++++++++++++++++++++++++
 drivers/ata/sata_uli.c |    7 ++++++-
 drivers/ata/sata_vsc.c |   17 +++++++++++++++++
 6 files changed, 62 insertions(+), 8 deletions(-)

diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index bcf4934..a205991 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -368,7 +368,10 @@ static const struct ata_port_operations nv_generic_ops = {
 	.thaw			= ata_bmdma_thaw,
 	.error_handler		= nv_error_handler,
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
+	.hp_poll_activate	= sata_std_hp_poll_activate,
+	.hp_poll		= sata_std_hp_poll,
 	.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,
@@ -474,7 +477,8 @@ static struct ata_port_info nv_port_info[] = {
 	{
 		.sht		= &nv_sht,
 		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-				  ATA_FLAG_HRST_TO_RESUME,
+				  ATA_FLAG_HRST_TO_RESUME | 
+				  ATA_FLAG_HP_POLLING,
 		.pio_mask	= NV_PIO_MASK,
 		.mwdma_mask	= NV_MWDMA_MASK,
 		.udma_mask	= NV_UDMA_MASK,
diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c
index 8f8cc5f..fa3b0e8 100644
--- a/drivers/ata/sata_sil.c
+++ b/drivers/ata/sata_sil.c
@@ -54,7 +54,6 @@ enum {
 	/*
 	 * host flags
 	 */
-	SIL_FLAG_NO_SATA_IRQ	= (1 << 28),
 	SIL_FLAG_RERR_ON_DMA_ACT = (1 << 29),
 	SIL_FLAG_MOD15WRITE	= (1 << 30),
 
@@ -231,7 +230,7 @@ static const struct ata_port_info sil_port_info[] = {
 	/* sil_3112_no_sata_irq */
 	{
 		.flags		= SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE |
-				  SIL_FLAG_NO_SATA_IRQ,
+				  ATA_FLAG_HP_POLLING,
 		.pio_mask	= 0x1f,			/* pio0-4 */
 		.mwdma_mask	= 0x07,			/* mwdma0-2 */
 		.udma_mask	= 0x3f,			/* udma0-5 */
@@ -480,8 +479,8 @@ static irqreturn_t sil_interrupt(int irq, void *dev_instance)
 		if (unlikely(!ap || ap->flags & ATA_FLAG_DISABLED))
 			continue;
 
-		/* turn off SATA_IRQ if not supported */
-		if (ap->flags & SIL_FLAG_NO_SATA_IRQ)
+		/* ignore SATA_IRQ if not supported */
+		if (ap->flags & ATA_FLAG_HP_POLLING)
 			bmdma2 &= ~SIL_DMA_SATA_IRQ;
 
 		if (bmdma2 == 0xffffffff ||
@@ -522,7 +521,7 @@ static void sil_thaw(struct ata_port *ap)
 	ata_bmdma_irq_clear(ap);
 
 	/* turn on SATA IRQ if supported */
-	if (!(ap->flags & SIL_FLAG_NO_SATA_IRQ))
+	if (!(ap->flags & ATA_FLAG_HP_POLLING))
 		writel(SIL_SIEN_N, mmio_base + sil_port[ap->port_no].sien);
 
 	/* turn on IRQ */
diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c
index d8ee062..fbfe0bf 100644
--- a/drivers/ata/sata_sis.c
+++ b/drivers/ata/sata_sis.c
@@ -121,6 +121,9 @@ static const struct ata_port_operations sis_ops = {
 	.thaw			= ata_bmdma_thaw,
 	.error_handler		= ata_bmdma_error_handler,
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
+	.hp_poll_activate	= sata_std_hp_poll_activate,
+	.hp_poll		= sata_std_hp_poll,
+	.irq_handler		= ata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
@@ -130,7 +133,8 @@ static const struct ata_port_operations sis_ops = {
 };
 
 static struct ata_port_info sis_port_info = {
-	.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+	.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+			  ATA_FLAG_HP_POLLING,
 	.pio_mask	= 0x1f,
 	.mwdma_mask	= 0x7,
 	.udma_mask	= 0x7f,
diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c
index cc07aac..8777e90 100644
--- a/drivers/ata/sata_svw.c
+++ b/drivers/ata/sata_svw.c
@@ -345,6 +345,9 @@ static const struct ata_port_operations k2_sata_ops = {
 	.thaw			= ata_bmdma_thaw,
 	.error_handler		= ata_bmdma_error_handler,
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
+	.hp_poll_activate	= sata_std_hp_poll_activate,
+	.hp_poll		= sata_std_hp_poll,
+	.irq_handler		= ata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
@@ -465,6 +468,28 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
 	writel(0xffffffff, mmio_base + K2_SATA_SCR_ERROR_OFFSET);
 	writel(0x0, mmio_base + K2_SATA_SIM_OFFSET);
 
+	probe_ent->sht = &k2_sata_sht;
+	probe_ent->port_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+				ATA_FLAG_MMIO | ATA_FLAG_HP_POLLING;
+	probe_ent->port_ops = &k2_sata_ops;
+	probe_ent->n_ports = 4;
+	probe_ent->irq = pdev->irq;
+	probe_ent->irq_flags = IRQF_SHARED;
+	probe_ent->mmio_base = mmio_base;
+
+	/* We don't care much about the PIO/UDMA masks, but the core won't like us
+	 * if we don't fill these
+	 */
+	probe_ent->pio_mask = 0x1f;
+	probe_ent->mwdma_mask = 0x7;
+	probe_ent->udma_mask = 0x7f;
+
+	/* different controllers have different number of ports - currently 4 or 8 */
+	/* All ports are on the same function. Multi-function device is no
+	 * longer available. This should not be seen in any system. */
+	for (i = 0; i < ent->driver_data; i++)
+		k2_sata_setup_port(&probe_ent->port[i], base + i * K2_SATA_PORT_OFFSET);
+
 	pci_set_master(pdev);
 	return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED,
 				 &k2_sata_sht);
diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c
index f74e383..533c5d3 100644
--- a/drivers/ata/sata_uli.c
+++ b/drivers/ata/sata_uli.c
@@ -115,6 +115,10 @@ static const struct ata_port_operations uli_ops = {
 	.error_handler		= ata_bmdma_error_handler,
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
 
+	.hp_poll_activate	= sata_std_hp_poll_activate,
+	.hp_poll		= sata_std_hp_poll,
+
+	.irq_handler		= ata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
@@ -127,7 +131,8 @@ static const struct ata_port_operations uli_ops = {
 
 static struct ata_port_info uli_port_info = {
 	.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-			  ATA_FLAG_IGN_SIMPLEX,
+			  ATA_FLAG_IGN_SIMPLEX |
+			  ATA_FLAG_HP_POLLING,
 	.pio_mask       = 0x1f,		/* pio0-4 */
 	.udma_mask      = 0x7f,		/* udma0-6 */
 	.port_ops       = &uli_ops,
diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c
index 80126f8..df8782f 100644
--- a/drivers/ata/sata_vsc.c
+++ b/drivers/ata/sata_vsc.c
@@ -333,6 +333,9 @@ static const struct ata_port_operations vsc_sata_ops = {
 	.thaw			= vsc_thaw,
 	.error_handler		= ata_bmdma_error_handler,
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
+	.hp_poll_activate	= sata_std_hp_poll_activate,
+	.hp_poll		= sata_std_hp_poll,
+	.irq_handler		= vsc_sata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
@@ -425,6 +428,20 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d
 	 * Due to a bug in the chip, the default cache line size can't be
 	 * used (unless the default is non-zero).
 	 */
+	pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x80);
+
+	probe_ent->sht = &vsc_sata_sht;
+	probe_ent->port_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+				ATA_FLAG_MMIO | ATA_FLAG_HP_POLLING;
+	probe_ent->port_ops = &vsc_sata_ops;
+	probe_ent->n_ports = 4;
+	probe_ent->irq = pdev->irq;
+	probe_ent->irq_flags = IRQF_SHARED;
+	probe_ent->mmio_base = mmio_base;
+
+	/* We don't care much about the PIO/UDMA masks, but the core won't like us
+	 * if we don't fill these
+	 */
 	pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cls);
 	if (cls == 0x00)
 		pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x80);
-- 
Robin Hugh Johnson
Gentoo Linux Developer & Council Member
E-Mail     : robbat2@gentoo.org
GnuPG FP   : 11AC BA4F 4778 E3F6 E4ED  F38E B27B 944E 3488 4E85

[-- Attachment #2: Type: application/pgp-signature, Size: 321 bytes --]

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH 0/3] hotplug polling, respin
  2007-04-25  7:08 ` [PATCH 0/3] hotplug polling, respin Tejun Heo
@ 2007-04-25  7:30   ` Robin H. Johnson
  2007-04-25  7:35     ` Tejun Heo
  2007-04-25 14:35   ` Jeff Garzik
  1 sibling, 1 reply; 11+ messages in thread
From: Robin H. Johnson @ 2007-04-25  7:30 UTC (permalink / raw)
  To: Tejun Heo, linux-ide; +Cc: Jeff Garzik

[-- Attachment #1: Type: text/plain, Size: 1615 bytes --]

On Wed, Apr 25, 2007 at 04:08:09PM +0900, Tejun Heo wrote:
> > The last submission of this
> > (http://thread.gmane.org/gmane.linux.ide/13467) already had a tentative
> > ACK, pending a link power-saving patchset, that I can't find more
> > details on.
> Yeap, the implementation is ACKed but interface to userland is NACKed.
> We need sysfs nodes for ATA devices to do userland interface properly.
> I'm working hard to get there.
I'm not sure I follow you here. The only bit of 'userspace' interface I
see in this series is hotplug_polling_interval. What other userspace
bits are in question?

> Thanks a lot for taking care of these patches.  A lot of people have
> been asking for patches for newer kernels and I couldn't find time to
> update them.
As always, it starts with scratching your own itch. My Fusion 500P works
like a charm with the SIL 3132 that I have - the previous scanning issue
where it took forever doing 15 scans (1;1,2;1,2,3;1,2,3,4;1,2,3,4,5)
instead of just 5 seems to have gone away, but the sluggish performance
remains (the sil24 seeming to not do SATA2 speed stuff, did you hear
back from SIL?).

As a gauge of interest in the PMP stuff, I'm presently getting about 3
emails a week asking for work on it.

> Jeff, can we make a page for PMP patches in linux-ata.org?  It would be
> a much better place to direct people to.
I'd host a git tree, but I don't have sufficient stable bandwidth.

-- 
Robin Hugh Johnson
Gentoo Linux Developer & Council Member
E-Mail     : robbat2@gentoo.org
GnuPG FP   : 11AC BA4F 4778 E3F6 E4ED  F38E B27B 944E 3488 4E85

[-- Attachment #2: Type: application/pgp-signature, Size: 321 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 0/3] hotplug polling, respin
  2007-04-25  7:30   ` Robin H. Johnson
@ 2007-04-25  7:35     ` Tejun Heo
  2007-04-25  7:58       ` Robin H. Johnson
  0 siblings, 1 reply; 11+ messages in thread
From: Tejun Heo @ 2007-04-25  7:35 UTC (permalink / raw)
  To: Robin H. Johnson; +Cc: linux-ide, Jeff Garzik

Robin H. Johnson wrote:
> On Wed, Apr 25, 2007 at 04:08:09PM +0900, Tejun Heo wrote:
>>> The last submission of this
>>> (http://thread.gmane.org/gmane.linux.ide/13467) already had a tentative
>>> ACK, pending a link power-saving patchset, that I can't find more
>>> details on.
>> Yeap, the implementation is ACKed but interface to userland is NACKed.
>> We need sysfs nodes for ATA devices to do userland interface properly.
>> I'm working hard to get there.
> I'm not sure I follow you here. The only bit of 'userspace' interface I
> see in this series is hotplug_polling_interval. What other userspace
> bits are in question?

What got NACKed is the lack of per-port interface.  More specifically,
stretching the usage of module parameter too far.

>> Thanks a lot for taking care of these patches.  A lot of people have
>> been asking for patches for newer kernels and I couldn't find time to
>> update them.
> As always, it starts with scratching your own itch. My Fusion 500P works
> like a charm with the SIL 3132 that I have - the previous scanning issue
> where it took forever doing 15 scans (1;1,2;1,2,3;1,2,3,4;1,2,3,4,5)
> instead of just 5 seems to have gone away, but the sluggish performance
> remains (the sil24 seeming to not do SATA2 speed stuff, did you hear
> back from SIL?).

Nope.

> As a gauge of interest in the PMP stuff, I'm presently getting about 3
> emails a week asking for work on it.
> 
>> Jeff, can we make a page for PMP patches in linux-ata.org?  It would be
>> a much better place to direct people to.
> I'd host a git tree, but I don't have sufficient stable bandwidth.

We can host the git tree at kernel.org.  I can get a tree setup there
and pull from you.

-- 
tejun

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 0/3] hotplug polling, respin
  2007-04-25  7:35     ` Tejun Heo
@ 2007-04-25  7:58       ` Robin H. Johnson
  0 siblings, 0 replies; 11+ messages in thread
From: Robin H. Johnson @ 2007-04-25  7:58 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Robin H. Johnson, linux-ide, Jeff Garzik

[-- Attachment #1: Type: text/plain, Size: 802 bytes --]

On Wed, Apr 25, 2007 at 04:35:25PM +0900, Tejun Heo wrote:
> > I'm not sure I follow you here. The only bit of 'userspace' interface I
> > see in this series is hotplug_polling_interval. What other userspace
> > bits are in question?
> What got NACKed is the lack of per-port interface.  More specifically,
> stretching the usage of module parameter too far.
One thing I'd be concerned with in implementing that as a sysfs
attribute right now, is that it's probably going to change location once
the ata_link abstraction comes in.

I'll think about it more tomorrow, when I move on to the ata_link
portion of these patches.

-- 
Robin Hugh Johnson
Gentoo Linux Developer & Council Member
E-Mail     : robbat2@gentoo.org
GnuPG FP   : 11AC BA4F 4778 E3F6 E4ED  F38E B27B 944E 3488 4E85

[-- Attachment #2: Type: application/pgp-signature, Size: 321 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 4/3] ahci: hotplug polling functions for vt8251 hardware variant
  2007-04-25  7:15     ` [PATCH 3/3] libata: add hp-poll support to controllers without " Robin H. Johnson
@ 2007-04-25  7:59       ` Robin H. Johnson
  0 siblings, 0 replies; 11+ messages in thread
From: Robin H. Johnson @ 2007-04-25  7:59 UTC (permalink / raw)
  To: Robin H. Johnson; +Cc: linux-ide, htejun

[-- Attachment #1: Type: text/plain, Size: 747 bytes --]

The VT8251 was missed during the previous 3 patches, as it used to be a
seperate branch by Tejun.

diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index adaa82b..c151af8 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -303,6 +303,9 @@ static const struct ata_port_operations ahci_vt8251_ops = {
 	.error_handler		= ahci_vt8251_error_handler,
 	.post_internal_cmd	= ahci_post_internal_cmd,
 
+	.hp_poll_activate	= sata_std_hp_poll_activate,
+	.hp_poll		= sata_std_hp_poll,
+
 	.port_suspend		= ahci_port_suspend,
 	.port_resume		= ahci_port_resume,

-- 
Robin Hugh Johnson
Gentoo Linux Developer & Council Member
E-Mail     : robbat2@gentoo.org
GnuPG FP   : 11AC BA4F 4778 E3F6 E4ED  F38E B27B 944E 3488 4E85

[-- Attachment #2: Type: application/pgp-signature, Size: 321 bytes --]

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH 0/3] hotplug polling, respin
  2007-04-25  7:08 ` [PATCH 0/3] hotplug polling, respin Tejun Heo
  2007-04-25  7:30   ` Robin H. Johnson
@ 2007-04-25 14:35   ` Jeff Garzik
  1 sibling, 0 replies; 11+ messages in thread
From: Jeff Garzik @ 2007-04-25 14:35 UTC (permalink / raw)
  To: Tejun Heo; +Cc: linux-ide, Alan

Tejun Heo wrote:
> Jeff, can we make a page for PMP patches in linux-ata.org?  It would be
> a much better place to direct people to.


Sure.  Adding content to linux-ata.org is open to anybody.  If you want 
to maintain a page (or pages) yourself, you can email the HTML file to 
me -- or a patch against existing HTML.

Full disclosure:  I may add ads to the pages.  Google AdSense ads 
currently cover 80% of the hosting costs.

This ad-supported setup is unfortunately the most reliable solution I've 
found; the free-for-open-source hosting solutions never wind up as 
reliable as I need them to be.

	Jeff



^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2007-04-25 14:35 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-04-25  6:25 [PATCH 0/3] hotplug polling, respin Robin H. Johnson
2007-04-25  6:28 ` [PATCH 1/3] libata: implement hotplug by polling Robin H. Johnson
2007-04-25  7:10   ` [PATCH 1/3 take2] " Robin H. Johnson
2007-04-25  7:13   ` [PATCH 2/3] libata: add hp-poll support to controllers with hotplug interrupts Robin H. Johnson
2007-04-25  7:15     ` [PATCH 3/3] libata: add hp-poll support to controllers without " Robin H. Johnson
2007-04-25  7:59       ` [PATCH 4/3] ahci: hotplug polling functions for vt8251 hardware variant Robin H. Johnson
2007-04-25  7:08 ` [PATCH 0/3] hotplug polling, respin Tejun Heo
2007-04-25  7:30   ` Robin H. Johnson
2007-04-25  7:35     ` Tejun Heo
2007-04-25  7:58       ` Robin H. Johnson
2007-04-25 14:35   ` Jeff Garzik

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).