From 62320e23c35077e8bc77184e8850d3f45441364b Mon Sep 17 00:00:00 2001 From: Yann Chachkoff Date: Wed, 7 Nov 2007 12:02:27 +0900 Subject: ata_piix: add SATELLITE PRO U200 to broken suspend list Please warmly welcome the PRO variant of Satellite U200 to the broken suspend list. Original patch is from Yann Chachkoff. Patch reformatted and forwarded by Tejun Heo. Signed-off-by: Yann Chachkoff Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ata_piix.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index f08cca21702..328ce8a0842 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -959,6 +959,13 @@ static int piix_broken_suspend(void) DMI_MATCH(DMI_PRODUCT_NAME, "Satellite U200"), }, }, + { + .ident = "Satellite Pro U200", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "SATELLITE PRO U200"), + }, + }, { .ident = "Satellite U205", .matches = { -- cgit v1.2.3 From 647c595dadb20d2c46e18bbd8d2a11e32f2a46e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Luis=20V=C3=A1zquez=20Cao?= Date: Wed, 7 Nov 2007 16:33:49 +0900 Subject: nv_hardreset: update dangling reference to bugzilla entry Signed-off-by: Fernando Luis Vazquez Cao Signed-off-by: Jeff Garzik --- drivers/ata/sata_nv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 35b2df29752..44f9e5d9e36 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -1629,7 +1629,7 @@ static int nv_hardreset(struct ata_link *link, unsigned int *class, /* SATA hardreset fails to retrieve proper device signature on * some controllers. Don't classify on hardreset. For more - * info, see http://bugme.osdl.org/show_bug.cgi?id=3352 + * info, see http://bugzilla.kernel.org/show_bug.cgi?id=3352 */ return sata_std_hardreset(link, &dummy, deadline); } -- cgit v1.2.3 From 12ee7d3ceb08e9ab99a6c17c5c6a387645a32658 Mon Sep 17 00:00:00 2001 From: Mark Lord Date: Wed, 7 Nov 2007 10:52:55 -0500 Subject: libata sata_qstor nuke idle state sata_qstor nuke idle state. We're really only ever in one of two hardware states: packet, or mmio. Get rid of unnecessary "qs_state_idle" state. Signed-off-by: Mark Lord Signed-off-by: Jeff Garzik --- drivers/ata/sata_qstor.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c index 6d43ba79e15..9d3128ca344 100644 --- a/drivers/ata/sata_qstor.c +++ b/drivers/ata/sata_qstor.c @@ -103,7 +103,7 @@ enum { QS_DMA_BOUNDARY = ~0UL }; -typedef enum { qs_state_idle, qs_state_pkt, qs_state_mmio } qs_state_t; +typedef enum { qs_state_mmio, qs_state_pkt } qs_state_t; struct qs_port_priv { u8 *pkt; @@ -219,7 +219,9 @@ static void qs_irq_clear(struct ata_port *ap) static inline void qs_enter_reg_mode(struct ata_port *ap) { u8 __iomem *chan = qs_mmio_base(ap->host) + (ap->port_no * 0x4000); + struct qs_port_priv *pp = ap->private_data; + pp->state = qs_state_mmio; writeb(QS_CTR0_REG, chan + QS_CCT_CTR0); readb(chan + QS_CCT_CTR0); /* flush */ } @@ -235,19 +237,12 @@ static inline void qs_reset_channel_logic(struct ata_port *ap) static void qs_phy_reset(struct ata_port *ap) { - struct qs_port_priv *pp = ap->private_data; - - pp->state = qs_state_idle; qs_reset_channel_logic(ap); sata_phy_reset(ap); } static void qs_eng_timeout(struct ata_port *ap) { - struct qs_port_priv *pp = ap->private_data; - - if (pp->state != qs_state_idle) /* healthy paranoia */ - pp->state = qs_state_mmio; qs_reset_channel_logic(ap); ata_eng_timeout(ap); } @@ -406,7 +401,6 @@ static inline unsigned int qs_intr_pkt(struct ata_host *host) switch (sHST) { case 0: /* successful CPB */ case 3: /* device error */ - pp->state = qs_state_idle; qs_enter_reg_mode(qc->ap); qc->err_mask |= ac_err_mask(sDST); ata_qc_complete(qc); @@ -445,7 +439,6 @@ static inline unsigned int qs_intr_mmio(struct ata_host *host) ap->print_id, qc->tf.protocol, status); /* complete taskfile transaction */ - pp->state = qs_state_idle; qc->err_mask |= ac_err_mask(status); ata_qc_complete(qc); handled = 1; @@ -501,7 +494,6 @@ static int qs_port_start(struct ata_port *ap) rc = ata_port_start(ap); if (rc) return rc; - qs_enter_reg_mode(ap); pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL); if (!pp) return -ENOMEM; @@ -512,6 +504,7 @@ static int qs_port_start(struct ata_port *ap) memset(pp->pkt, 0, QS_PKT_BYTES); ap->private_data = pp; + qs_enter_reg_mode(ap); addr = (u64)pp->pkt_dma; writel((u32) addr, chan + QS_CCF_CPBA); writel((u32)(addr >> 32), chan + QS_CCF_CPBA + 4); -- cgit v1.2.3 From 904c7bad994e6e7f9997174e0b33fcc521862136 Mon Sep 17 00:00:00 2001 From: Mark Lord Date: Wed, 7 Nov 2007 10:53:41 -0500 Subject: libata sata_qstor workaround for spurious interrupts sata_qstor workaround for spurious interrupts. The qstor hardware generates spurious interrupts from time to time when switching in and out of packet mode. These eventually result in the IRQ being disabled, which kills other devices sharing this IRQ with us. This workaround isn't perfect, but it's about the best we can do for this hardware. Spurious interrupts will still happen, but won't be logged as such, and therefore won't cause the IRQ to be inadvertently disabled. Signed-off-by: Mark Lord Signed-off-by: Jeff Garzik --- drivers/ata/sata_qstor.c | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c index 9d3128ca344..7446a335fc9 100644 --- a/drivers/ata/sata_qstor.c +++ b/drivers/ata/sata_qstor.c @@ -425,24 +425,27 @@ static inline unsigned int qs_intr_mmio(struct ata_host *host) if (ap && !(ap->flags & ATA_FLAG_DISABLED)) { struct ata_queued_cmd *qc; - struct qs_port_priv *pp = ap->private_data; - if (!pp || pp->state != qs_state_mmio) - continue; + struct qs_port_priv *pp; qc = ata_qc_from_tag(ap, ap->link.active_tag); - if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) { - - /* check main status, clearing INTRQ */ - u8 status = ata_check_status(ap); - if ((status & ATA_BUSY)) - continue; - DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n", - ap->print_id, qc->tf.protocol, status); - - /* complete taskfile transaction */ - qc->err_mask |= ac_err_mask(status); - ata_qc_complete(qc); + if (!qc || !(qc->flags & ATA_QCFLAG_ACTIVE)) { + /* + * The qstor hardware generates spurious + * interrupts from time to time when switching + * in and out of packet mode. + * There's no obvious way to know if we're + * here now due to that, so just ack the irq + * and pretend we knew it was ours.. (ugh). + * This does not affect packet mode. + */ + ata_check_status(ap); handled = 1; + continue; } + pp = ap->private_data; + if (!pp || pp->state != qs_state_mmio) + continue; + if (!(qc->tf.flags & ATA_TFLAG_POLLING)) + handled |= ata_host_intr(ap, qc); } } return handled; @@ -452,12 +455,13 @@ static irqreturn_t qs_intr(int irq, void *dev_instance) { struct ata_host *host = dev_instance; unsigned int handled = 0; + unsigned long flags; VPRINTK("ENTER\n"); - spin_lock(&host->lock); + spin_lock_irqsave(&host->lock, flags); handled = qs_intr_pkt(host) | qs_intr_mmio(host); - spin_unlock(&host->lock); + spin_unlock_irqrestore(&host->lock, flags); VPRINTK("EXIT\n"); -- cgit v1.2.3 From 6004bda1cce51273ac9e71a39e680831b9ff4503 Mon Sep 17 00:00:00 2001 From: Mark Lord Date: Wed, 7 Nov 2007 10:54:15 -0500 Subject: libata sata_qstor conversion to new error handling (EH). sata_qstor conversion to new error handling (EH). Convert sata_qstor to use the newer libata EH mechanisms. Based on earlier work by Jeff Garzik. Signed-off-by: Mark Lord Signed-off-by: Jeff Garzik --- drivers/ata/sata_qstor.c | 65 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c index 7446a335fc9..2f1de6ec044 100644 --- a/drivers/ata/sata_qstor.c +++ b/drivers/ata/sata_qstor.c @@ -116,14 +116,15 @@ static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val); static int qs_ata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); static int qs_port_start(struct ata_port *ap); static void qs_host_stop(struct ata_host *host); -static void qs_phy_reset(struct ata_port *ap); static void qs_qc_prep(struct ata_queued_cmd *qc); static unsigned int qs_qc_issue(struct ata_queued_cmd *qc); static int qs_check_atapi_dma(struct ata_queued_cmd *qc); static void qs_bmdma_stop(struct ata_queued_cmd *qc); static u8 qs_bmdma_status(struct ata_port *ap); static void qs_irq_clear(struct ata_port *ap); -static void qs_eng_timeout(struct ata_port *ap); +static void qs_freeze(struct ata_port *ap); +static void qs_thaw(struct ata_port *ap); +static void qs_error_handler(struct ata_port *ap); static struct scsi_host_template qs_ata_sht = { .module = THIS_MODULE, @@ -150,11 +151,12 @@ static const struct ata_port_operations qs_ata_ops = { .check_atapi_dma = qs_check_atapi_dma, .exec_command = ata_exec_command, .dev_select = ata_std_dev_select, - .phy_reset = qs_phy_reset, .qc_prep = qs_qc_prep, .qc_issue = qs_qc_issue, .data_xfer = ata_data_xfer, - .eng_timeout = qs_eng_timeout, + .freeze = qs_freeze, + .thaw = qs_thaw, + .error_handler = qs_error_handler, .irq_clear = qs_irq_clear, .irq_on = ata_irq_on, .scr_read = qs_scr_read, @@ -169,8 +171,6 @@ static const struct ata_port_info qs_port_info[] = { /* board_2068_idx */ { .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_SATA_RESET | - //FIXME ATA_FLAG_SRST | ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING, .pio_mask = 0x10, /* pio4 */ .udma_mask = ATA_UDMA6, @@ -235,16 +235,28 @@ static inline void qs_reset_channel_logic(struct ata_port *ap) qs_enter_reg_mode(ap); } -static void qs_phy_reset(struct ata_port *ap) +static void qs_freeze(struct ata_port *ap) { - qs_reset_channel_logic(ap); - sata_phy_reset(ap); + u8 __iomem *mmio_base = qs_mmio_base(ap->host); + + writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */ + qs_enter_reg_mode(ap); +} + +static void qs_thaw(struct ata_port *ap) +{ + u8 __iomem *mmio_base = qs_mmio_base(ap->host); + + qs_enter_reg_mode(ap); + writeb(1, mmio_base + QS_HCT_CTRL); /* enable host interrupts */ } -static void qs_eng_timeout(struct ata_port *ap) +static int qs_prereset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; + qs_reset_channel_logic(ap); - ata_eng_timeout(ap); + return ata_std_prereset(link, deadline); } static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) @@ -255,6 +267,13 @@ static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) return 0; } +static void qs_error_handler(struct ata_port *ap) +{ + qs_enter_reg_mode(ap); + ata_do_eh(ap, qs_prereset, ata_std_softreset, NULL, + ata_std_postreset); +} + static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) { if (sc_reg > SCR_CONTROL) @@ -353,7 +372,6 @@ static unsigned int qs_qc_issue(struct ata_queued_cmd *qc) switch (qc->tf.protocol) { case ATA_PROT_DMA: - pp->state = qs_state_pkt; qs_packet_start(qc); return 0; @@ -370,6 +388,26 @@ static unsigned int qs_qc_issue(struct ata_queued_cmd *qc) return ata_qc_issue_prot(qc); } +static void qs_do_or_die(struct ata_queued_cmd *qc, u8 status) +{ + qc->err_mask |= ac_err_mask(status); + + if (!qc->err_mask) { + ata_qc_complete(qc); + } else { + struct ata_port *ap = qc->ap; + struct ata_eh_info *ehi = &ap->link.eh_info; + + ata_ehi_clear_desc(ehi); + ata_ehi_push_desc(ehi, "status 0x%02X", status); + + if (qc->err_mask == AC_ERR_DEV) + ata_port_abort(ap); + else + ata_port_freeze(ap); + } +} + static inline unsigned int qs_intr_pkt(struct ata_host *host) { unsigned int handled = 0; @@ -402,8 +440,7 @@ static inline unsigned int qs_intr_pkt(struct ata_host *host) case 0: /* successful CPB */ case 3: /* device error */ qs_enter_reg_mode(qc->ap); - qc->err_mask |= ac_err_mask(sDST); - ata_qc_complete(qc); + qs_do_or_die(qc, sDST); break; default: break; -- cgit v1.2.3 From 3d46b2e2faa56d12c6d51bf1071fd11abd009d0b Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Thu, 8 Nov 2007 11:14:56 +0900 Subject: libata: Support PIO polling-only hosts. By default ata_host_activate() expects a valid IRQ in order to successfully register the host. This patch enables a special case for registering polling-only hosts that either don't have IRQs or have buggy IRQ generation (either in terms of handling or sensing), which otherwise work fine. Hosts that want to use polling mode can simply set ATA_FLAG_PIO_POLLING and pass in an invalid IRQ. Signed-off-by: Paul Mundt Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index ec3ce120a51..89fd0e9ed74 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -7178,6 +7178,10 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) * request IRQ and register it. This helper takes necessasry * arguments and performs the three steps in one go. * + * An invalid IRQ skips the IRQ registration and expects the host to + * have set polling mode on the port. In this case, @irq_handler + * should be NULL. + * * LOCKING: * Inherited from calling layer (may sleep). * @@ -7194,6 +7198,12 @@ int ata_host_activate(struct ata_host *host, int irq, if (rc) return rc; + /* Special case for polling mode */ + if (!irq) { + WARN_ON(irq_handler); + return ata_host_register(host, sht); + } + rc = devm_request_irq(host->dev, irq, irq_handler, irq_flags, dev_driver_string(host->dev), host); if (rc) -- cgit v1.2.3 From f7fc0ceb4d72ea5c40d50053b68ebecfbd0cc38c Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Thu, 8 Nov 2007 11:15:21 +0900 Subject: libata: pata_platform: Support polling-mode configuration. Some SH boards (old R2D-1 boards) have generally not had working CF under libata, due to both buswidth issues (handled by Aoi Shinkai in 43f4b8c7578b928892b6f01d374346ae14e5eb70), and buggy interrupt controllers. For these sorts of boards simply disabling the IRQ and polling ends up working fine. This conditionalizes the IRQ resource for pata_platform and lets platforms that want to use polling mode simply omit the resource entirely. Signed-off-by: Paul Mundt Signed-off-by: Jeff Garzik --- drivers/ata/pata_platform.c | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index fc72a965643..ac03a90a616 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -1,7 +1,7 @@ /* * Generic platform device PATA driver * - * Copyright (C) 2006 Paul Mundt + * Copyright (C) 2006 - 2007 Paul Mundt * * Based on pata_pcmcia: * @@ -22,7 +22,7 @@ #include #define DRV_NAME "pata_platform" -#define DRV_VERSION "1.1" +#define DRV_VERSION "1.2" static int pio_mask = 1; @@ -120,15 +120,20 @@ static void pata_platform_setup_port(struct ata_ioports *ioaddr, * Register a platform bus IDE interface. Such interfaces are PIO and we * assume do not support IRQ sharing. * - * Platform devices are expected to contain 3 resources per port: + * Platform devices are expected to contain at least 2 resources per port: * * - I/O Base (IORESOURCE_IO or IORESOURCE_MEM) * - CTL Base (IORESOURCE_IO or IORESOURCE_MEM) + * + * and optionally: + * * - IRQ (IORESOURCE_IRQ) * * If the base resources are both mem types, the ioremap() is handled * here. For IORESOURCE_IO, it's assumed that there's no remapping * necessary. + * + * If no IRQ resource is present, PIO polling mode is used instead. */ static int __devinit pata_platform_probe(struct platform_device *pdev) { @@ -137,11 +142,12 @@ static int __devinit pata_platform_probe(struct platform_device *pdev) struct ata_port *ap; struct pata_platform_info *pp_info; unsigned int mmio; + int irq; /* * Simple resource validation .. */ - if (unlikely(pdev->num_resources != 3)) { + if ((pdev->num_resources != 3) && (pdev->num_resources != 2)) { dev_err(&pdev->dev, "invalid number of resources\n"); return -EINVAL; } @@ -172,6 +178,13 @@ static int __devinit pata_platform_probe(struct platform_device *pdev) mmio = (( io_res->flags == IORESOURCE_MEM) && (ctl_res->flags == IORESOURCE_MEM)); + /* + * And the IRQ + */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) + irq = 0; /* no irq */ + /* * Now that that's out of the way, wire up the port.. */ @@ -184,6 +197,14 @@ static int __devinit pata_platform_probe(struct platform_device *pdev) ap->pio_mask = pio_mask; ap->flags |= ATA_FLAG_SLAVE_POSS; + /* + * Use polling mode if there's no IRQ + */ + if (!irq) { + ap->flags |= ATA_FLAG_PIO_POLLING; + ata_port_desc(ap, "no IRQ, using PIO polling"); + } + /* * Handle the MMIO case */ @@ -213,9 +234,9 @@ static int __devinit pata_platform_probe(struct platform_device *pdev) (unsigned long long)ctl_res->start); /* activate */ - return ata_host_activate(host, platform_get_irq(pdev, 0), - ata_interrupt, pp_info ? pp_info->irq_flags - : 0, &pata_platform_sht); + return ata_host_activate(host, irq, irq ? ata_interrupt : NULL, + pp_info ? pp_info->irq_flags : 0, + &pata_platform_sht); } /** -- cgit v1.2.3 From 1974e20161a2c097c481d2ff711de7db56cb2cd6 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 8 Nov 2007 11:20:18 +0900 Subject: libata: skip 0xff polling for PATA controllers In a presentation of true workmanship, pata_ali asserts IRQ permanantly if the TF status register is read more than once when there's no device attached to the port. Avoid waiting polling for !0xff if it's PATA. It's needed only for some rare SATA devices anyway. This problem is reported by Luca Tettamanti in bugzilla bug 9298. Signed-off-by: Tejun Heo Tested-By: Luca Tettamanti Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 89fd0e9ed74..fd332612d64 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3373,14 +3373,20 @@ void ata_wait_after_reset(struct ata_port *ap, unsigned long deadline) * to clear 0xff after reset. For example, HHD424020F7SV00 * iVDR needs >= 800ms while. Quantum GoVault needs even more * than that. + * + * Note that some PATA controllers (pata_ali) explode if + * status register is read more than once when there's no + * device attached. */ - while (1) { - u8 status = ata_chk_status(ap); + if (ap->flags & ATA_FLAG_SATA) { + while (1) { + u8 status = ata_chk_status(ap); - if (status != 0xff || time_after(jiffies, deadline)) - return; + if (status != 0xff || time_after(jiffies, deadline)) + return; - msleep(50); + msleep(50); + } } } -- cgit v1.2.3 From 32ebbc0c0d5d18c0135b55d1eb0029f48c54aff0 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 8 Nov 2007 13:09:00 +0900 Subject: libata: port and host should be stopped before hardware resources are released Port / host stop calls used to be made from ata_host_release() which is called after all hardware resources acquired after host allocation are released. This is wrong as port and host stop routines often access the hardware. Add separate devres for port / host stop which is invoked right after IRQ is released but with all other hardware resources intact. The devres is added iff ->host_stop and/or ->port_stop exist. This problem has been spotted by Mark Lord. Signed-off-by: Tejun Heo Cc: Mark Lord Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 52 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index fd332612d64..81898036dbc 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6821,19 +6821,6 @@ static void ata_host_release(struct device *gendev, void *res) struct ata_host *host = dev_get_drvdata(gendev); int i; - for (i = 0; i < host->n_ports; i++) { - struct ata_port *ap = host->ports[i]; - - if (!ap) - continue; - - if ((host->flags & ATA_HOST_STARTED) && ap->ops->port_stop) - ap->ops->port_stop(ap); - } - - if ((host->flags & ATA_HOST_STARTED) && host->ops->host_stop) - host->ops->host_stop(host); - for (i = 0; i < host->n_ports; i++) { struct ata_port *ap = host->ports[i]; @@ -6966,6 +6953,24 @@ struct ata_host *ata_host_alloc_pinfo(struct device *dev, return host; } +static void ata_host_stop(struct device *gendev, void *res) +{ + struct ata_host *host = dev_get_drvdata(gendev); + int i; + + WARN_ON(!(host->flags & ATA_HOST_STARTED)); + + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; + + if (ap->ops->port_stop) + ap->ops->port_stop(ap); + } + + if (host->ops->host_stop) + host->ops->host_stop(host); +} + /** * ata_host_start - start and freeze ports of an ATA host * @host: ATA host to start ports for @@ -6984,6 +6989,8 @@ struct ata_host *ata_host_alloc_pinfo(struct device *dev, */ int ata_host_start(struct ata_host *host) { + int have_stop = 0; + void *start_dr = NULL; int i, rc; if (host->flags & ATA_HOST_STARTED) @@ -6995,6 +7002,22 @@ int ata_host_start(struct ata_host *host) if (!host->ops && !ata_port_is_dummy(ap)) host->ops = ap->ops; + if (ap->ops->port_stop) + have_stop = 1; + } + + if (host->ops->host_stop) + have_stop = 1; + + if (have_stop) { + start_dr = devres_alloc(ata_host_stop, 0, GFP_KERNEL); + if (!start_dr) + return -ENOMEM; + } + + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; + if (ap->ops->port_start) { rc = ap->ops->port_start(ap); if (rc) { @@ -7007,6 +7030,8 @@ int ata_host_start(struct ata_host *host) ata_eh_freeze_port(ap); } + if (start_dr) + devres_add(host->dev, start_dr); host->flags |= ATA_HOST_STARTED; return 0; @@ -7017,6 +7042,7 @@ int ata_host_start(struct ata_host *host) if (ap->ops->port_stop) ap->ops->port_stop(ap); } + devres_free(start_dr); return rc; } -- cgit v1.2.3 From 037f6bb79f753c014bc84bca0de9bf98bb5ab169 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Thu, 8 Nov 2007 18:37:07 +0000 Subject: libata: Don't fail device revalidation for bad _GTF methods Experience suggests that the _GTF method may be bad. We currently fail device revalidation in that case, which seems excessive. Signed-off-by: Matthew Garrett Signed-off-by: Jeff Garzik --- drivers/ata/libata-acpi.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index 08a52dd45fb..545ea865ceb 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -312,7 +312,7 @@ EXPORT_SYMBOL_GPL(ata_acpi_stm); * * RETURNS: * Number of taskfiles on success, 0 if _GTF doesn't exist or doesn't - * contain valid data. -errno on other errors. + * contain valid data. */ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf, void **ptr_to_free) @@ -339,7 +339,6 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf, ata_dev_printk(dev, KERN_WARNING, "_GTF evaluation failed (AE 0x%x)\n", status); - rc = -EIO; } goto out_free; } @@ -359,7 +358,6 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf, ata_dev_printk(dev, KERN_WARNING, "_GTF unexpected object type 0x%x\n", out_obj->type); - rc = -EINVAL; goto out_free; } @@ -367,7 +365,6 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf, ata_dev_printk(dev, KERN_WARNING, "unexpected _GTF length (%d)\n", out_obj->buffer.length); - rc = -EINVAL; goto out_free; } @@ -511,10 +508,7 @@ static int ata_acpi_exec_tfs(struct ata_device *dev) int gtf_count, i, rc; /* get taskfiles */ - rc = ata_dev_get_GTF(dev, >f, &ptr_to_free); - if (rc < 0) - return rc; - gtf_count = rc; + gtf_count = ata_dev_get_GTF(dev, >f, &ptr_to_free); /* execute them */ for (i = 0, rc = 0; i < gtf_count; i++) { -- cgit v1.2.3