hotplug polling, take 4
PATCH 2/3 libata: add hp-poll support to controllers with hotplug interrutps
In reply to Tejun HeoThis 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/ata/ahci.c | 4 +++- drivers/ata/sata_nv.c | 4 ++++ drivers/ata/sata_sil.c | 2 ++ drivers/ata/sata_sil24.c | 3 +++ 4 files changed, 12 insertions(+), 1 deletions(-)
drivers/ata/ahci.c +3 -1
@@ -262,10 +262,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_suspend = ahci_port_suspend, .port_resume = ahci_port_resume,
drivers/ata/sata_nv.c +4 -0
@@ -200,6 +200,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,
@@ -227,6 +229,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/ata/sata_sil.c +2 -0
@@ -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/ata/sata_sil24.c +3 -0
@@ -410,6 +410,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.4.2.3
PATCH 3/3 libata: add hp-poll support to controllers without hotplug interrupts
In reply to Tejun HeoThis 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.
--- drivers/ata/sata_nv.c | 5 ++++- drivers/ata/sata_sil.c | 9 ++++----- drivers/ata/sata_sis.c | 5 ++++- drivers/ata/sata_svw.c | 4 +++- drivers/ata/sata_uli.c | 6 +++++- drivers/ata/sata_vsc.c | 4 +++- 6 files changed, 23 insertions(+), 10 deletions(-)
drivers/ata/sata_nv.c +4 -1
@@ -173,6 +173,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,
@@ -245,7 +247,8 @@ static struct ata_port_info nv_port_info/* generic */ { .sht = &nv_sht, - .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, + .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/ata/sata_sil.c +4 -5
@@ -52,7 +52,6 @@ enum {/* * host flags */ -SIL_FLAG_NO_SATA_IRQ = (1 <<28 ),SIL_FLAG_RERR_ON_DMA_ACT = (1 <<29 ), SIL_FLAG_MOD15WRITE = (1 << 30),
@@ -230,7 +229,7 @@ static const struct ata_port_info sil_po { .sht = &sil_sht, .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 */
@@ -454,8 +453,8 @@ static irqreturn_t sil_interrupt(int irqif (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 ||
@@ -496,7 +495,7 @@ static void sil_thaw(struct ata_port *apata_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 */
drivers/ata/sata_sis.c +4 -1
@@ -117,6 +117,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,
@@ -128,7 +130,8 @@ static const struct ata_port_operationsstatic struct ata_port_info sis_port_info = { .sht = &sis_sht, - .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 ,
drivers/ata/sata_svw.c +3 -1
@@ -324,6 +324,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,
@@ -424,7 +426,7 @@ static int k2_sata_init_one (struct pci_ probe_ent->sht = &k2_sata_sht; probe_ent->port_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/ata/sata_uli.c +5 -1
@@ -115,6 +115,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,
@@ -128,7 +131,8 @@ static const struct ata_port_operationsstatic struct ata_port_info uli_port_info = { .sht = &uli_sht, - .flags =ATA_FLAG_SATA |ATA_FLAG_NO_LEGACY , + .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/ata/sata_vsc.c +3 -1
@@ -301,6 +301,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,
@@ -395,7 +397,7 @@ static int __devinit vsc_sata_init_one ( probe_ent->sht = &vsc_sata_sht; probe_ent->port_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.4.2.3
PATCH 1/1 hotplug polling, take 4
Hello, all.
This is the fourth take of hotplug polling patchset. As the name implies, this patchset implements hotplug by polling. hp-poll is used to
* Monitor ports EH gave up. When EH gives up on a port, it freezes the port to protect the rest of the system from it. The user used to have to issue manual scan to retry the port. hp-poll can monitor such port and retry it when hotplug event is detected. This is also used by PMP support.
* Support hotplug on controllers which can report hotplug conditions but cannot raise interrupt.
Changes from the last take[L] are.
* updated to the current upstream
* global hp_poll_list and hp_poll_work replaced with per-host hp_poll_task
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
(web is temporarily down, but git pull works)
Thanks.
--
tejun
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 so by setting ATA_FLAG_HP_POLLING which tells libata to turn on hp-poll by default.
--- drivers/ata/libata-core.c | 79 +++++++++++++++++++++++++++++ drivers/ata/libata-eh.c | 123 ++++++++++++++++++++++++++++++++++++++++++++- drivers/ata/libata.h | 2 + include/linux/libata.h | 10 ++++ 4 files changed, 211 insertions(+), 3 deletions(-)
drivers/ata/libata-core.c +78 -1
@@ -2909,6 +2909,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 *)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
@@ -5430,6 +5500,7 @@ void ata_host_init(struct ata_host *host host->dev = dev; host->flags = flags; host->ops = ops; +INIT_WORK (&host->hp_poll_task, ata_hp_poll_worker, host); }/**
@@ -5684,11 +5755,15 @@ void ata_port_detach(struct ata_port *apata_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:
@@ -6122,6 +6197,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/ata/libata-eh.c +121 -2
172 lines not on this page · raw message
drivers/ata/libata.h +2 -0
@@ -118,5 +118,7 @@ extern enum scsi_eh_timer_return ata_scsextern 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 (void *data); +extern void ata_hp_poll_deactivate (struct ata_port *ap);#endif /* __LIBATA_H__ */
include/linux/libata.h +10 -0
@@ -175,6 +175,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
@@ -192,6 +193,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) */
@@ -401,6 +403,7 @@ struct ata_host {unsigned long flags;int simplex_claimed;/* Keep seperate in case we ever need to do this locked */ +struct work_struct hp_poll_task;struct ata_port *ports[0 ]; };
@@ -581,6 +584,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 */
@@ -628,6 +632,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 *);
@@ -702,6 +710,8 @@ extern int ata_std_prereset(struct ata_pextern 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.4.2.3