libata: beef up iterators
PATCH 1/3 libata: beef up iterators
There currently are the following looping constructs.
* __ata_port_for_each_link() for all available links
* ata_port_for_each_link() for edge links
* ata_link_for_each_dev() for all devices
* ata_link_for_each_dev_reverse() for all devices in reverse order
Now there's a need for looping construct which is similar to __ata_port_for_each_link() but iterates over PMP links before the host link. Instead of adding another one with long name, do the following cleanup.
* Implement and export ata_link_next() and ata_dev_next() which take @mode parameter and can be used to build custom loop.
* Implement ata_for_each_link() and ata_for_each_dev() which take looping mode explicitly.
The following iteration modes are implemented.
* ATA_LITER_EDGE : loop over edge links
* ATA_LITER_HOST_FIRST : loop over all links, host link first
* ATA_LITER_PMP_FIRST : loop over all links, PMP links first
* ATA_DITER_ENABLED : loop over enabled devices
* ATA_DITER_ENABLED_REVERSE : loop over enabled devices in reverse order
* ATA_DITER_ALL : loop over all devices
* ATA_DITER_ALL_REVERSE : loop over all devices in reverse order
This change removes exlicit device enabledness checks from many loops and makes it clear which ones are iterated over in which direction.
---
Comments added and retargeted for #upstream.
This patchset is on top of
#upstream-fixes (9ce8e3073d9cfd6f859c22a25441db41b85cbf6e)
+ [1] patches-which-fell-off-the-crack-during-maintainership-handover patchset
+ [2] mask-off-DET-when-restoring-SControl-for-detach
[1] http://thread.gmane.org/gmane.linux.ide/35783
[2] http://article.gmane.org/gmane.linux.ide/35792
drivers/ata/ahci.c | 8 +- drivers/ata/ata_generic.c | 5 +- drivers/ata/libata-acpi.c | 19 ++--- drivers/ata/libata-core.c | 183 ++++++++++++++++++++++++++++-------------- drivers/ata/libata-eh.c | 84 +++++++++----------- drivers/ata/libata-pmp.c | 22 +++--- drivers/ata/libata-scsi.c | 22 +++--- drivers/ata/pata_it821x.c | 34 ++++---- drivers/ata/pata_ixp4xx_cf.c | 14 ++-- drivers/ata/pata_legacy.c | 17 ++--- drivers/ata/pata_pdc2027x.c | 31 +++---- drivers/ata/pata_platform.c | 14 ++-- drivers/ata/pata_rz1000.c | 16 ++-- drivers/ata/sata_sil.c | 2 +- include/linux/libata.h | 76 +++++++++++++----- 15 files changed, 307 insertions(+), 240 deletions(-)
drivers/ata/ahci.c +4 -4
@@ -1119,14 +1119,14 @@ static void ahci_start_port(struct ata_port *ap)/* turn on LEDs */ if (ap->flags &ATA_FLAG_EM ) { -ata_port_for_each_link (link, ap) { +ata_for_each_link (link, ap,EDGE ) { emp = &pp->em_priv[link->pmp];ahci_transmit_led_message (ap, emp->led_state,4 ); } }if (ap->flags &ATA_FLAG_SW_ACTIVITY ) -ata_port_for_each_link (link, ap) +ata_for_each_link (link, ap,EDGE )ahci_init_sw_activity (link); }
@@ -1361,7 +1361,7 @@ static ssize_t ahci_led_show(struct ata_port *ap, char *buf)struct ahci_em_priv *emp;int rc =0 ; -ata_port_for_each_link (link, ap) { +ata_for_each_link (link, ap,EDGE ) { emp = &pp->em_priv[link->pmp]; rc +=sprintf (buf,"%lx\n" , emp->led_state); }
@@ -1941,7 +1941,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)u32 serror;/* determine active link */ -ata_port_for_each_link (link, ap) +ata_for_each_link (link, ap,EDGE )if (ata_link_active (link))break ;if (!link)
drivers/ata/ata_generic.c +1 -4
@@ -57,10 +57,7 @@ static int generic_set_mode(struct ata_link *link, struct ata_device **unused)if (pdev->vendor ==PCI_VENDOR_ID_CENATEK ) dma_enabled =0xFF ; -ata_link_for_each_dev (dev, link) { -if (!ata_dev_enabled (dev)) -continue ; - +ata_for_each_dev (dev, link,ENABLED ) {/* We don't really care */ dev->pio_mode =XFER_PIO_0 ; dev->dma_mode =XFER_MW_DMA_0 ;
drivers/ata/libata-acpi.c +8 -11
@@ -89,7 +89,7 @@ void ata_acpi_associate_sata_port(struct ata_port *ap) ap->link.device->acpi_handle =NULL ; -ata_port_for_each_link (link, ap) { +ata_for_each_link (link, ap,EDGE ) {acpi_integer adr =SATA_ADR (ap->port_no, link->pmp); link->device->acpi_handle =
@@ -129,8 +129,8 @@ static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev)struct ata_link *tlink;struct ata_device *tdev; -ata_port_for_each_link (tlink, ap) -ata_link_for_each_dev (tdev, tlink) +ata_for_each_link (tlink, ap,EDGE ) +ata_for_each_dev (tdev, tlink,ALL ) tdev->flags |=ATA_DFLAG_DETACH ; }
@@ -588,12 +588,9 @@ int ata_acpi_cbl_80wire(struct ata_port *ap, const struct ata_acpi_gtm *gtm) {struct ata_device *dev; -ata_link_for_each_dev (dev, &ap->link) { +ata_for_each_dev (dev, &ap->link,ENABLED ) {unsigned long xfer_mask, udma_mask; -if (!ata_dev_enabled (dev)) -continue ; - xfer_mask =ata_acpi_gtm_xfermask (dev, gtm);ata_unpack_xfermask (xfer_mask,NULL ,NULL , &udma_mask);
@@ -893,7 +890,7 @@ void ata_acpi_on_resume(struct ata_port *ap)* use values set by _STM. Cache _GTF result and * schedule _GTF. */ -ata_link_for_each_dev (dev, &ap->link) { +ata_for_each_dev (dev, &ap->link,ALL ) {ata_acpi_clear_gtf (dev);if (ata_dev_enabled (dev) &&ata_dev_get_GTF (dev,NULL ) >=0 )
@@ -904,7 +901,7 @@ void ata_acpi_on_resume(struct ata_port *ap)* there's no reason to evaluate IDE _GTF early * without _STM. Clear cache and schedule _GTF. */ -ata_link_for_each_dev (dev, &ap->link) { +ata_for_each_dev (dev, &ap->link,ALL ) {ata_acpi_clear_gtf (dev);if (ata_dev_enabled (dev)) dev->flags |=ATA_DFLAG_ACPI_PENDING ;
@@ -932,8 +929,8 @@ void ata_acpi_set_state(struct ata_port *ap, pm_message_t state)if (state.event ==PM_EVENT_ON )acpi_bus_set_power (ap->acpi_handle,ACPI_STATE_D0 ); -ata_link_for_each_dev (dev, &ap->link) { -if (dev->acpi_handle &&ata_dev_enabled (dev)) +ata_for_each_dev (dev, &ap->link,ENABLED ) { +if (dev->acpi_handle)acpi_bus_set_power (dev->acpi_handle, state.event ==PM_EVENT_ON ?ACPI_STATE_D0 :ACPI_STATE_D3 );
drivers/ata/libata-core.c +122 -61
305 lines not on this page · raw message
drivers/ata/libata-eh.c +37 -47
286 lines not on this page · raw message
drivers/ata/libata-pmp.c +11 -11
@@ -321,7 +321,7 @@ static void sata_pmp_quirks(struct ata_port *ap)if (vendor ==0x1095 && devid ==0x3726 ) {/* sil3726 quirks */ -ata_port_for_each_link (link, ap) { +ata_for_each_link (link, ap,EDGE ) {/* Class code report is unreliable and SRST * times out under certain configurations. */
@@ -336,7 +336,7 @@ static void sata_pmp_quirks(struct ata_port *ap) } }else if (vendor ==0x1095 && devid ==0x4723 ) {/* sil4723 quirks */ -ata_port_for_each_link (link, ap) { +ata_for_each_link (link, ap,EDGE ) {/* class code report is unreliable */ if (link->pmp <2 ) link->flags |=ATA_LFLAG_ASSUME_ATA ;
@@ -348,7 +348,7 @@ static void sata_pmp_quirks(struct ata_port *ap) } }else if (vendor ==0x1095 && devid ==0x4726 ) {/* sil4726 quirks */ -ata_port_for_each_link (link, ap) { +ata_for_each_link (link, ap,EDGE ) {/* Class code report is unreliable and SRST * times out under certain configurations. * Config device can be at port 0 or 5 and
@@ -450,7 +450,7 @@ int sata_pmp_attach(struct ata_device *dev)if (ap->ops->pmp_attach) ap->ops->pmp_attach (ap); -ata_port_for_each_link (tlink, ap) +ata_for_each_link (tlink, ap,EDGE )sata_link_init_spd (tlink);ata_acpi_associate_sata_port (ap);
@@ -487,7 +487,7 @@ static void sata_pmp_detach(struct ata_device *dev)if (ap->ops->pmp_detach) ap->ops->pmp_detach (ap); -ata_port_for_each_link (tlink, ap) +ata_for_each_link (tlink, ap,EDGE )ata_eh_detach_dev (tlink->device);spin_lock_irqsave (ap->lock, flags);
@@ -700,7 +700,7 @@ static int sata_pmp_eh_recover_pmp(struct ata_port *ap, }/* PMP is reset, SErrors cannot be trusted, scan all */ -ata_port_for_each_link (tlink, ap) { +ata_for_each_link (tlink, ap,EDGE ) {struct ata_eh_context *ehc = &tlink->eh_context; ehc->i.probe_mask |=ATA_ALL_DEVICES ;
@@ -768,7 +768,7 @@ static int sata_pmp_eh_handle_disabled_links(struct ata_port *ap)spin_lock_irqsave (ap->lock, flags); -ata_port_for_each_link (link, ap) { +ata_for_each_link (link, ap,EDGE ) {if (!(link->flags &ATA_LFLAG_DISABLED ))continue ;
@@ -852,7 +852,7 @@ static int sata_pmp_eh_recover(struct ata_port *ap)int cnt, rc; pmp_tries =ATA_EH_PMP_TRIES ; -ata_port_for_each_link (link, ap) +ata_for_each_link (link, ap,EDGE ) link_tries[link->pmp] =ATA_EH_PMP_LINK_TRIES ; retry:
@@ -861,7 +861,7 @@ static int sata_pmp_eh_recover(struct ata_port *ap) rc =ata_eh_recover (ap, ops->prereset, ops->softreset, ops->hardreset, ops->postreset,NULL );if (rc) { -ata_link_for_each_dev (dev, &ap->link) +ata_for_each_dev (dev, &ap->link,ALL )ata_dev_disable (dev);return rc; }
@@ -870,7 +870,7 @@ static int sata_pmp_eh_recover(struct ata_port *ap)return 0 ;/* new PMP online */ -ata_port_for_each_link (link, ap) +ata_for_each_link (link, ap,EDGE ) link_tries[link->pmp] =ATA_EH_PMP_LINK_TRIES ;/* fall through */
@@ -942,7 +942,7 @@ static int sata_pmp_eh_recover(struct ata_port *ap) } cnt =0 ; -ata_port_for_each_link (link, ap) { +ata_for_each_link (link, ap,EDGE ) {if (!(gscr_error & (1 << link->pmp)))continue ;
drivers/ata/libata-scsi.c +11 -11
@@ -3262,12 +3262,12 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync)return ; repeat: -ata_port_for_each_link (link, ap) { -ata_link_for_each_dev (dev, link) { +ata_for_each_link (link, ap,EDGE ) { +ata_for_each_dev (dev, link,ENABLED ) {struct scsi_device *sdev;int channel =0 , id =0 ; -if (!ata_dev_enabled (dev) || dev->sdev) +if (dev->sdev)continue ;if (ata_is_host_link (link))
@@ -3288,9 +3288,9 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync)* failure occurred, scan would have failed silently. Check * whether all devices are attached. */ -ata_port_for_each_link (link, ap) { -ata_link_for_each_dev (dev, link) { -if (ata_dev_enabled (dev) && !dev->sdev) +ata_for_each_link (link, ap,EDGE ) { +ata_for_each_dev (dev, link,ENABLED ) { +if (!dev->sdev) goto exit_loop; } }
@@ -3414,7 +3414,7 @@ static void ata_scsi_handle_link_detach(struct ata_link *link)struct ata_port *ap = link->ap;struct ata_device *dev; -ata_link_for_each_dev (dev, link) { +ata_for_each_dev (dev, link,ALL ) {unsigned long flags;if (!(dev->flags &ATA_DFLAG_DETACHED ))
@@ -3529,7 +3529,7 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,if (devno ==SCAN_WILD_CARD ) {struct ata_link *link; -ata_port_for_each_link (link, ap) { +ata_for_each_link (link, ap,EDGE ) {struct ata_eh_info *ehi = &link->eh_info; ehi->probe_mask |=ATA_ALL_DEVICES ; ehi->action |=ATA_EH_RESET ;
@@ -3577,11 +3577,11 @@ void ata_scsi_dev_rescan(struct work_struct *work)spin_lock_irqsave (ap->lock, flags); -ata_port_for_each_link (link, ap) { -ata_link_for_each_dev (dev, link) { +ata_for_each_link (link, ap,EDGE ) { +ata_for_each_dev (dev, link,ENABLED ) {struct scsi_device *sdev = dev->sdev; -if (!ata_dev_enabled (dev) || !sdev) +if (!sdev)continue ;if (scsi_device_get (sdev))continue ;
drivers/ata/pata_it821x.c +16 -18
@@ -465,24 +465,22 @@ static int it821x_smart_set_mode(struct ata_link *link, struct ata_device **unus {struct ata_device *dev; -ata_link_for_each_dev (dev, link) { -if (ata_dev_enabled (dev)) { -/* We don't really care */ - dev->pio_mode =XFER_PIO_0 ; - dev->dma_mode =XFER_MW_DMA_0 ; -/* We do need the right mode information for DMA or PIO -and this comes from the current configuration flags */ -if (ata_id_has_dma (dev->id)) { -ata_dev_printk (dev,KERN_INFO ,"configured for DMA\n" ); - dev->xfer_mode =XFER_MW_DMA_0 ; - dev->xfer_shift =ATA_SHIFT_MWDMA ; - dev->flags &= ~ATA_DFLAG_PIO ; - }else { -ata_dev_printk (dev,KERN_INFO ,"configured for PIO\n" ); - dev->xfer_mode =XFER_PIO_0 ; - dev->xfer_shift =ATA_SHIFT_PIO ; - dev->flags |=ATA_DFLAG_PIO ; - } +ata_for_each_dev (dev, link,ENABLED ) { +/* We don't really care */ + dev->pio_mode =XFER_PIO_0 ; + dev->dma_mode =XFER_MW_DMA_0 ; +/* We do need the right mode information for DMA or PIO +and this comes from the current configuration flags */ +if (ata_id_has_dma (dev->id)) { +ata_dev_printk (dev,KERN_INFO ,"configured for DMA\n" ); + dev->xfer_mode =XFER_MW_DMA_0 ; + dev->xfer_shift =ATA_SHIFT_MWDMA ; + dev->flags &= ~ATA_DFLAG_PIO ; + }else { +ata_dev_printk (dev,KERN_INFO ,"configured for PIO\n" ); + dev->xfer_mode =XFER_PIO_0 ; + dev->xfer_shift =ATA_SHIFT_PIO ; + dev->flags |=ATA_DFLAG_PIO ; } }return 0 ;
drivers/ata/pata_ixp4xx_cf.c +6 -8
@@ -30,14 +30,12 @@ static int ixp4xx_set_mode(struct ata_link *link, struct ata_device **error) {struct ata_device *dev; -ata_link_for_each_dev (dev, link) { -if (ata_dev_enabled (dev)) { -ata_dev_printk (dev,KERN_INFO ,"configured for PIO0\n" ); - dev->pio_mode =XFER_PIO_0 ; - dev->xfer_mode =XFER_PIO_0 ; - dev->xfer_shift =ATA_SHIFT_PIO ; - dev->flags |=ATA_DFLAG_PIO ; - } +ata_for_each_dev (dev, link,ENABLED ) { +ata_dev_printk (dev,KERN_INFO ,"configured for PIO0\n" ); + dev->pio_mode =XFER_PIO_0 ; + dev->xfer_mode =XFER_PIO_0 ; + dev->xfer_shift =ATA_SHIFT_PIO ; + dev->flags |=ATA_DFLAG_PIO ; }return 0 ; }
drivers/ata/pata_legacy.c +7 -10
@@ -194,15 +194,12 @@ static int legacy_set_mode(struct ata_link *link, struct ata_device **unused) {struct ata_device *dev; -ata_link_for_each_dev (dev, link) { -if (ata_dev_enabled (dev)) { -ata_dev_printk (dev,KERN_INFO , -"configured for PIO\n" ); - dev->pio_mode =XFER_PIO_0 ; - dev->xfer_mode =XFER_PIO_0 ; - dev->xfer_shift =ATA_SHIFT_PIO ; - dev->flags |=ATA_DFLAG_PIO ; - } +ata_for_each_dev (dev, link,ENABLED ) { +ata_dev_printk (dev,KERN_INFO ,"configured for PIO\n" ); + dev->pio_mode =XFER_PIO_0 ; + dev->xfer_mode =XFER_PIO_0 ; + dev->xfer_shift =ATA_SHIFT_PIO ; + dev->flags |=ATA_DFLAG_PIO ; }return 0 ; }
@@ -1028,7 +1025,7 @@ static __init int legacy_init_one(struct legacy_probe *probe)/* Nothing found means we drop the port as its probably not there */ ret = -ENODEV ; -ata_link_for_each_dev (dev, &ap->link) { +ata_for_each_dev (dev, &ap->link,ALL ) {if (!ata_dev_absent (dev)) { legacy_host[probe->slot] = host; ld->platform_dev = pdev;
drivers/ata/pata_pdc2027x.c +14 -17
@@ -406,23 +406,20 @@ static int pdc2027x_set_mode(struct ata_link *link, struct ata_device **r_failedif (rc <0 )return rc; -ata_link_for_each_dev (dev, link) { -if (ata_dev_enabled (dev)) { - -pdc2027x_set_piomode (ap, dev); - -/* -* Enable prefetch if the device support PIO only. -*/ -if (dev->xfer_shift ==ATA_SHIFT_PIO ) { -u32 ctcr1 =ioread32 (dev_mmio (ap, dev,PDC_CTCR1 )); - ctcr1 |= (1 <<25 ); -iowrite32 (ctcr1,dev_mmio (ap, dev,PDC_CTCR1 )); - -PDPRINTK ("Turn on prefetch\n" ); - }else { -pdc2027x_set_dmamode (ap, dev); - } +ata_for_each_dev (dev, link,ENABLED ) { +pdc2027x_set_piomode (ap, dev); + +/* +* Enable prefetch if the device support PIO only. +*/ +if (dev->xfer_shift ==ATA_SHIFT_PIO ) { +u32 ctcr1 =ioread32 (dev_mmio (ap, dev,PDC_CTCR1 )); + ctcr1 |= (1 <<25 ); +iowrite32 (ctcr1,dev_mmio (ap, dev,PDC_CTCR1 )); + +PDPRINTK ("Turn on prefetch\n" ); + }else { +pdc2027x_set_dmamode (ap, dev); } }return 0 ;
drivers/ata/pata_platform.c +6 -8
@@ -34,14 +34,12 @@ static int pata_platform_set_mode(struct ata_link *link, struct ata_device **unu {struct ata_device *dev; -ata_link_for_each_dev (dev, link) { -if (ata_dev_enabled (dev)) { -/* We don't really care */ - dev->pio_mode = dev->xfer_mode =XFER_PIO_0 ; - dev->xfer_shift =ATA_SHIFT_PIO ; - dev->flags |=ATA_DFLAG_PIO ; -ata_dev_printk (dev,KERN_INFO ,"configured for PIO\n" ); - } +ata_for_each_dev (dev, link,ENABLED ) { +/* We don't really care */ + dev->pio_mode = dev->xfer_mode =XFER_PIO_0 ; + dev->xfer_shift =ATA_SHIFT_PIO ; + dev->flags |=ATA_DFLAG_PIO ; +ata_dev_printk (dev,KERN_INFO ,"configured for PIO\n" ); }return 0 ; }
drivers/ata/pata_rz1000.c +7 -9
@@ -38,15 +38,13 @@ static int rz1000_set_mode(struct ata_link *link, struct ata_device **unused) {struct ata_device *dev; -ata_link_for_each_dev (dev, link) { -if (ata_dev_enabled (dev)) { -/* We don't really care */ - dev->pio_mode =XFER_PIO_0 ; - dev->xfer_mode =XFER_PIO_0 ; - dev->xfer_shift =ATA_SHIFT_PIO ; - dev->flags |=ATA_DFLAG_PIO ; -ata_dev_printk (dev,KERN_INFO ,"configured for PIO\n" ); - } +ata_for_each_dev (dev, link,ENABLED ) { +/* We don't really care */ + dev->pio_mode =XFER_PIO_0 ; + dev->xfer_mode =XFER_PIO_0 ; + dev->xfer_shift =ATA_SHIFT_PIO ; + dev->flags |=ATA_DFLAG_PIO ; +ata_dev_printk (dev,KERN_INFO ,"configured for PIO\n" ); }return 0 ; }
drivers/ata/sata_sil.c +1 -1
@@ -278,7 +278,7 @@ static int sil_set_mode(struct ata_link *link, struct ata_device **r_failed)if (rc)return rc; -ata_link_for_each_dev (dev, link) { +ata_for_each_dev (dev, link,ALL ) {if (!ata_dev_enabled (dev)) dev_mode[dev->devno] =0 ;/* PIO0/1/2 */ else if (dev->flags &ATA_DFLAG_PIO )
include/linux/libata.h +56 -20
82 lines not on this page · raw message
Signature · 1 line
1.5.4.5
PATCH 2/3 libata: when restoring SControl during detach do the PMP links first
When restoring SControl during detach, PMP links should be handled first as changing SControl of the host link can affect SCR access of PMP links.
--- drivers/ata/libata-core.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/ata/libata-core.c +1 -1
@@ -5995,7 +5995,7 @@ static void ata_port_detach(struct ata_port *ap)/* EH is now guaranteed to see UNLOADING - EH context belongs * to us. Restore SControl and disable all existing devices. */ -ata_for_each_link (link, ap,HOST_FIRST ) { +ata_for_each_link (link, ap,PMP_FIRST ) {sata_scr_write (link,SCR_CONTROL , link->saved_scontrol &0xff0 );ata_for_each_dev (dev, link,ALL )ata_dev_disable (dev);
Signature · 1 line
1.5.4.5
PATCH 3/3 libata: perform port detach in EH
ata_port_detach() first made sure EH saw ATA_PFLAG_UNLOADING and then assumed EH context belongs to it and performed detach operation itself. However, UNLOADING doesn't disable all of EH and this could lead to problems including triggering WARN_ON()'s in EH path.
This patch makes port detach behave more like other EH actions such that ata_port_detach() requests EH to detach and waits for completion.
--- drivers/ata/libata-core.c | 23 ++++------------------- drivers/ata/libata-eh.c | 32 +++++++++++++++++++++++++++++++- include/linux/libata.h | 3 ++- 3 files changed, 37 insertions(+), 21 deletions(-)
drivers/ata/libata-core.c +4 -19
@@ -5979,8 +5979,6 @@ int ata_host_activate(struct ata_host *host, int irq,static void ata_port_detach (struct ata_port *ap) {unsigned long flags; -struct ata_link *link; -struct ata_device *dev;if (!ap->ops->error_handler) goto skip_eh;
@@ -5988,28 +5986,15 @@ static void ata_port_detach(struct ata_port *ap)/* tell EH we're leaving & flush EH */ spin_lock_irqsave (ap->lock, flags); ap->pflags |=ATA_PFLAG_UNLOADING ; +ata_port_schedule_eh (ap);spin_unlock_irqrestore (ap->lock, flags); +/* wait till EH commits suicide */ ata_port_wait_eh (ap); -/* EH is now guaranteed to see UNLOADING - EH context belongs -* to us. Restore SControl and disable all existing devices. -*/ -ata_for_each_link (link, ap,PMP_FIRST ) { -sata_scr_write (link,SCR_CONTROL , link->saved_scontrol &0xff0 ); -ata_for_each_dev (dev, link,ALL ) -ata_dev_disable (dev); - } - -/* Final freeze & EH. All in-flight commands are aborted. EH -* will be skipped and retrials will be terminated with bad -* target. -*/ -spin_lock_irqsave (ap->lock, flags); -ata_port_freeze (ap);/* won't be thawed */ -spin_unlock_irqrestore (ap->lock, flags); +/* it better be dead now */ +WARN_ON (!(ap->pflags &ATA_PFLAG_UNLOADED )); -ata_port_wait_eh (ap);cancel_rearming_delayed_work (&ap->hotplug_task); skip_eh:
drivers/ata/libata-eh.c +31 -1
@@ -491,6 +491,31 @@ enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)return ret; } +static void ata_eh_unload (struct ata_port *ap) +{ +struct ata_link *link; +struct ata_device *dev; +unsigned long flags; + +/* Restore SControl IPM and SPD for the next driver and +* disable attached devices. +*/ +ata_for_each_link (link, ap,PMP_FIRST ) { +sata_scr_write (link,SCR_CONTROL , link->saved_scontrol &0xff0 ); +ata_for_each_dev (dev, link,ALL ) +ata_dev_disable (dev); + } + +/* freeze and set UNLOADED */ +spin_lock_irqsave (ap->lock, flags); + +ata_port_freeze (ap);/* won't be thawed */ + ap->pflags &= ~ATA_PFLAG_EH_PENDING ;/* clear pending from freeze */ + ap->pflags |=ATA_PFLAG_UNLOADED ; + +spin_unlock_irqrestore (ap->lock, flags); +} +/** * ata_scsi_error - SCSI layer error handler callback * @host: SCSI host on which error occurred
@@ -621,8 +646,13 @@ void ata_scsi_error(struct Scsi_Host *host)/* invoke EH, skip if unloading or suspended */ if (!(ap->pflags & (ATA_PFLAG_UNLOADING |ATA_PFLAG_SUSPENDED ))) ap->ops->error_handler (ap); -else +else { +/* if unloading, commence suicide */ +if ((ap->pflags &ATA_PFLAG_UNLOADING ) && + !(ap->pflags &ATA_PFLAG_UNLOADED )) +ata_eh_unload (ap);ata_eh_finish (ap); + }/* process port suspend request */ ata_eh_handle_port_suspend (ap);
include/linux/libata.h +2 -1
@@ -215,10 +215,11 @@ enum {ATA_PFLAG_FROZEN = (1 <<2 ),/* port is frozen */ ATA_PFLAG_RECOVERED = (1 <<3 ),/* recovery action performed */ 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_INITIALIZING = (1 <<7 ),/* being initialized, don't touch */ ATA_PFLAG_RESETTING = (1 <<8 ),/* reset in progress */ +ATA_PFLAG_UNLOADING = (1 <<9 ),/* driver is being unloaded */ +ATA_PFLAG_UNLOADED = (1 <<10 ),/* driver is unloaded */ ATA_PFLAG_SUSPENDED = (1 <<17 ),/* port is suspended (power) */ ATA_PFLAG_PM_PENDING = (1 << 18), /* PM operation pending */
Signature · 1 line
1.5.4.5
Quoted 35 lines · Tejun Heo
There currently are the following looping constructs.
*
__ata_port_for_each_link()for all available links
*ata_port_for_each_link()for edge links
*ata_link_for_each_dev()for all devices
*ata_link_for_each_dev_reverse()for all devices in reverse orderNow there's a need for looping construct which is similar to
__ata_port_for_each_link()but iterates over PMP links before the host link. Instead of adding another one with long name, do the following cleanup.* Implement and export
ata_link_next()andata_dev_next()which take @mode parameter and can be used to build custom loop.
* Implementata_for_each_link()andata_for_each_dev()which take looping mode explicitly.The following iteration modes are implemented.
*
ATA_LITER_EDGE: loop over edge links
*ATA_LITER_HOST_FIRST: loop over all links, host link first
*ATA_LITER_PMP_FIRST: loop over all links, PMP links first*
ATA_DITER_ENABLED: loop over enabled devices
*ATA_DITER_ENABLED_REVERSE: loop over enabled devices in reverse order
*ATA_DITER_ALL: loop over all devices
*ATA_DITER_ALL_REVERSE: loop over all devices in reverse orderThis change removes exlicit device enabledness checks from many loops and makes it clear which ones are iterated over in which direction.
Signed-off-by Tejun Heo <[email protected]>---
Comments added and retargeted for #upstream.
Quoted 8 lines
This patchset is on top of
#upstream-fixes (
9ce8e3073d9cfd6f859c22a25441db41b85cbf6e)
+ [1] patches-which-fell-off-the-crack-during-maintainership-handover patchset
+ [2] mask-off-DET-when-restoring-SControl-for-detach[1] http://thread.gmane.org/gmane.linux.ide/35783
[2] http://article.gmane.org/gmane.linux.ide/35792
applied to newly created #upstream (on top of just-sent #upstream-fixes)