Skip to contentSkip to conversation

hotplug polling, take 2

PATCH New Tejun Heo 1 participant 4 messages Jul 5, 2006

Subsystems (2)
lore
Share & tools
lore

Tejun Heo

author
#0 lore raw

PATCH 1/1 hotplug polling, take 2

Hello, all.

This is the second take of hotplug polling patchset. As the name implies, this patchset implements hotplug by polling. Changes from the last take[1] are.

* vt8237 randomly locks up on SCR access and hp-poll support is dropped.

* port/host_set-excl std callbacks are removed.

libata core layer implements hp-poll infrastructure. It interacts with LLDs with three callbacks - hp_poll_activate(), hp_poll_deactivate() and hp_poll(). libata core layer is responsible for activating and deactivating at the right time, invoking the poll callback periodically while activated, and generate hotplug event when poll callback indicates something has happened.

hp-poll is used for the following cases.

* To detect hotplug events on frozen ports after reset fails such that replacing or replugging the failing device make libata automatically retry the port.

* To detect hotplug events on LLDs without hotplug interrupt.

The following drivers are converted to use hp-poll on failed ports.

* ahci
* sata_nv (nf2 and ck804 only) [untested]
* sata_sil
* sata_sil24

The following drivers are converted to use hp-poll for hotplug

* sata_nv (generic) [untested]
* sata_sis [untested]
* sata_svw [untested]
* sata_uli [untested]
* sata_via [SCR access broken, not supported]
* sata_vsc [untested]

vt8237 randomly locks up on SCR access and thus support is dropped. And all other untested drivers need testing.

This patchset is against

upstream (2154cfa6ba560401d25f6cc083fe3fb996cbb571)
+ add-ap-pflags [2]
+ fix-ehc_i_action-setting-in-ata_eh_autopsy [3]
+ cosmetic-replace-ap_lock [4]
+ new PM patchset [5]

This patchset is also available in the following git tree.

http://htj.dyndns.org/git/?p=libata-tj.git;a=shortlog;h=hp-poll
git://htj.dyndns.org/libata-tj hp-poll

Thanks.

--
tejun

[1] http://article.gmane.org/gmane.linux.ide/11827
[2] http://article.gmane.org/gmane.linux.ide/11717
[3] http://article.gmane.org/gmane.linux.ide/11801
[4] http://article.gmane.org/gmane.linux.ide/11802
[5] http://article.gmane.org/gmane.linux.ide/11816

author
#1 lore raw

PATCH 1/3 libata: implement hotplug by polling

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 it by setting ATA_FLAG_HP_POLLING which tells libata to turn on hp-poll by default.

---

 drivers/scsi/libata-core.c |   82 +++++++++++++++++++++++++++
 drivers/scsi/libata-eh.c   |  134 +++++++++++++++++++++++++++++++++++++++++++-
 drivers/scsi/libata.h      |    5 ++
 include/linux/libata.h     |   10 +++
 4 files changed, 229 insertions(+), 2 deletions(-)

fb6848884560d691fc69c6994f490d0918712eae

drivers/scsi/libata-core.c +82 -0
index 46ae4bc..3d4ea35 100644
@@ -2840,6 +2840,76 @@ void ata_std_postreset(struct ata_port *
 }
 
 /**
+ *	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 *)(unsigned long)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
@@ -5290,6 +5360,7 @@ #endif
 	INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan, ap);
 	INIT_LIST_HEAD(&ap->eh_done_q);
 	init_waitqueue_head(&ap->eh_wait_q);
+	INIT_LIST_HEAD(&ap->hp_poll_entry);
 
 	/* set cable type */
 	ap->cbl = ATA_CBL_NONE;
@@ -5586,6 +5657,9 @@ void ata_port_detach(struct ata_port *ap
 	cancel_delayed_work(&ap->hotplug_task);
 	flush_workqueue(ata_aux_wq);
 
+	/* deactivate hotplug polling */
+	ata_hp_poll_deactivate(ap);
+
 	/* remove the associated SCSI host */
 	scsi_remove_host(ap->host);
 }
@@ -5832,6 +5906,12 @@ static int __init ata_init(void)
 
 static void __exit ata_exit(void)
 {
+	/* hp_poll_list gotta be empty by now and thus hp_poll_work
+	 * isn't rearming.
+	 */
+	WARN_ON(!list_empty(&hp_poll_list));
+	cancel_delayed_work(&hp_poll_work);
+
 	destroy_workqueue(ata_wq);
 	destroy_workqueue(ata_aux_wq);
 }
@@ -5966,6 +6046,8 @@ EXPORT_SYMBOL_GPL(ata_std_prereset);
 EXPORT_SYMBOL_GPL(ata_std_softreset);
 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);
drivers/scsi/libata-eh.c +132 -2

179 lines not on this page · raw message

drivers/scsi/libata.h +5 -0
index c325679..3171dde 100644
@@ -109,9 +109,14 @@ extern void ata_schedule_scsi_eh(struct 
 extern void ata_scsi_dev_rescan(void *data);
 
 /* libata-eh.c */
+extern struct list_head hp_poll_list;
+extern struct work_struct hp_poll_work;
+
 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_activate(struct ata_port *ap);
+extern void ata_hp_poll_deactivate(struct ata_port *ap);
 
 #endif /* __LIBATA_H__ */
include/linux/libata.h +10 -0
index 6cc497a..1609309 100644
@@ -162,6 +162,7 @@ enum {
 	ATA_FLAG_SKIP_D2H_BSY	= (1 << 12), /* can't wait for the first D2H
 					      * Register FIS clearing BSY */
 	ATA_FLAG_DEBUGMSG	= (1 << 13),
+	ATA_FLAG_HP_POLLING	= (1 << 14), /* 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
@@ -553,6 +554,9 @@ struct ata_port {
 	pm_message_t		pm_mesg;
 	int			*pm_result;
 
+	struct list_head	hp_poll_entry;	/* hotplug poll list entry */
+	void			*hp_poll_data;
+
 	void			*private_data;
 
 	u8			sector_buf[ATA_SECT_SIZE]; /* owned by EH */
@@ -600,6 +604,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);
+
 	irqreturn_t (*irq_handler)(int, void *, struct pt_regs *);
 	void (*irq_clear) (struct ata_port *);
 
@@ -667,6 +675,8 @@ extern int ata_std_prereset(struct ata_p
 extern int ata_std_softreset(struct ata_port *ap, unsigned int *classes);
 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, int post_reset);
 extern void ata_port_disable(struct ata_port *);
 extern void ata_std_ports(struct ata_ioports *ioaddr);
Signature · 1 line
1.3.2
author
#2 lore raw

PATCH 2/3 libata: add hp-poll support to controllers with hotplug interrutps

In reply to Tejun Heo

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.

---

 drivers/scsi/ahci.c       |    4 +++-
 drivers/scsi/sata_nv.c    |    4 ++++
 drivers/scsi/sata_sil.c   |    2 ++
 drivers/scsi/sata_sil24.c |    3 +++
 4 files changed, 12 insertions(+), 1 deletions(-)

4faf1e519f3a190b35a03fc21be1d4027ac3e499

drivers/scsi/ahci.c +3 -1
index 54f01b2..a404ec0 100644
@@ -253,10 +253,12 @@ static const struct ata_port_operations 
 
 	.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,
+
 	.port_start		= ahci_port_start,
 	.port_stop		= ahci_port_stop,
 };
drivers/scsi/sata_nv.c +4 -0
index 5cc42c6..79b0550 100644
@@ -217,6 +217,8 @@ static const struct ata_port_operations 
 	.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_pio_data_xfer,
 	.irq_handler		= nv_nf2_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
@@ -244,6 +246,8 @@ static const struct ata_port_operations 
 	.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_pio_data_xfer,
 	.irq_handler		= nv_ck804_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
drivers/scsi/sata_sil.c +2 -0
index 9f2a48a..01abe09 100644
@@ -205,6 +205,8 @@ static const struct ata_port_operations 
 	.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,
 	.scr_read		= sil_scr_read,
drivers/scsi/sata_sil24.c +3 -0
index b8e590d..0904088 100644
@@ -405,6 +405,9 @@ static const struct ata_port_operations 
 	.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,
 	.port_stop		= sil24_port_stop,
 	.host_stop		= sil24_host_stop,
Signature · 1 line
1.3.2
author
#3 lore raw

PATCH 3/3 libata: add hp-poll support to controllers without hotplug interrupts

In reply to Tejun Heo

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

* sata_nv (generic)
* sata_sis
* sata_svw
* sata_uli
* sata_via
* 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.

---

 drivers/scsi/sata_nv.c  |    5 ++++-
 drivers/scsi/sata_sis.c |    5 ++++-
 drivers/scsi/sata_svw.c |    4 +++-
 drivers/scsi/sata_uli.c |    6 +++++-
 drivers/scsi/sata_vsc.c |    4 +++-
 5 files changed, 19 insertions(+), 5 deletions(-)

b544ce25c0e1f5b2a5307d77942d4d6dc9d88cfe

drivers/scsi/sata_nv.c +4 -1
index 79b0550..01f25f6 100644
@@ -190,6 +190,8 @@ static const struct ata_port_operations 
 	.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_pio_data_xfer,
 	.irq_handler		= nv_generic_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
@@ -262,7 +264,8 @@ static struct ata_port_info nv_port_info
 	/* generic */
 	{
 		.sht		= &nv_sht,
-		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+				  ATA_FLAG_HP_POLLING,
 		.pio_mask	= NV_PIO_MASK,
 		.mwdma_mask	= NV_MWDMA_MASK,
 		.udma_mask	= NV_UDMA_MASK,
drivers/scsi/sata_sis.c +4 -1
index 809d337..24df9ee 100644
@@ -118,6 +118,8 @@ static const struct ata_port_operations 
 	.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,
 	.scr_read		= sis_scr_read,
@@ -129,7 +131,8 @@ static const struct ata_port_operations 
 
 static struct ata_port_info sis_port_info = {
 	.sht		= &sis_sht,
-	.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+	.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+			  ATA_FLAG_HP_POLLING,
 	.pio_mask	= 0x1f,
 	.mwdma_mask	= 0x7,
 	.udma_mask	= 0x7f,
drivers/scsi/sata_svw.c +3 -1
index 7566c2c..769ba92 100644
@@ -325,6 +325,8 @@ static const struct ata_port_operations 
 	.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,
 	.scr_read		= k2_sata_scr_read,
@@ -425,7 +427,7 @@ static int k2_sata_init_one (struct pci_
 
 	probe_ent->sht = &k2_sata_sht;
 	probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-				ATA_FLAG_MMIO;
+				ATA_FLAG_MMIO | ATA_FLAG_HP_POLLING;
 	probe_ent->port_ops = &k2_sata_ops;
 	probe_ent->n_ports = 4;
 	probe_ent->irq = pdev->irq;
drivers/scsi/sata_uli.c +5 -1
index 64f3c1a..e7bbd80 100644
@@ -116,6 +116,9 @@ static const struct ata_port_operations 
 	.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,
 
@@ -129,7 +132,8 @@ static const struct ata_port_operations 
 
 static struct ata_port_info uli_port_info = {
 	.sht            = &uli_sht,
-	.host_flags     = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+	.host_flags     = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+			  ATA_FLAG_HP_POLLING,
 	.pio_mask       = 0x1f,		/* pio0-4 */
 	.udma_mask      = 0x7f,		/* udma0-6 */
 	.port_ops       = &uli_ops,
drivers/scsi/sata_vsc.c +3 -1
index 616fd96..b00df9a 100644
@@ -302,6 +302,8 @@ static const struct ata_port_operations 
 	.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		= vsc_sata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.scr_read		= vsc_sata_scr_read,
@@ -396,7 +398,7 @@ static int __devinit vsc_sata_init_one (
 
 	probe_ent->sht = &vsc_sata_sht;
 	probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-				ATA_FLAG_MMIO;
+				ATA_FLAG_MMIO | ATA_FLAG_HP_POLLING;
 	probe_ent->port_ops = &vsc_sata_ops;
 	probe_ent->n_ports = 4;
 	probe_ent->irq = pdev->irq;
Signature · 1 line
1.3.2