From f667fdbbbea8bcce6cf9f7acb51b7cb4c264cc61 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 20 Oct 2008 13:11:56 +0900 Subject: [PATCH 1/6] libata: initialize port_task when !CONFIG_ATA_SFF ap->port_task was not initialized if !CONFIG_ATA_SFF later triggering lockdep warning. Make sure it's initialized. Reported by Larry Finger. Signed-off-by: Tejun Heo Cc: Larry Finger Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 1ee9499bd34..bbb3cae5749 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -5373,6 +5373,8 @@ struct ata_port *ata_port_alloc(struct ata_host *host) #ifdef CONFIG_ATA_SFF INIT_DELAYED_WORK(&ap->port_task, ata_pio_task); +#else + INIT_DELAYED_WORK(&ap->port_task, NULL); #endif INIT_DELAYED_WORK(&ap->hotplug_task, ata_scsi_hotplug); INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan); From 570106df6bdb4907ad7f70793079c762f34d561a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 20 Oct 2008 13:10:21 +0900 Subject: [PATCH 2/6] libata-sff: fix ata_sff_post_internal_cmd() ata_sff_post_internal_cmd() needs to grab port lock before calling ata_bmdma_stop() and also need to clear hsm_task_state. Fix it. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-sff.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 2a4c516894f..4b473948632 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -2153,8 +2153,17 @@ void ata_sff_error_handler(struct ata_port *ap) */ void ata_sff_post_internal_cmd(struct ata_queued_cmd *qc) { - if (qc->ap->ioaddr.bmdma_addr) + struct ata_port *ap = qc->ap; + unsigned long flags; + + spin_lock_irqsave(ap->lock, flags); + + ap->hsm_task_state = HSM_ST_IDLE; + + if (ap->ioaddr.bmdma_addr) ata_bmdma_stop(qc); + + spin_unlock_irqrestore(ap->lock, flags); } /** From 848e4c68c4695beae563f9a3d59fce596b466a74 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 21 Oct 2008 14:26:39 +0900 Subject: [PATCH 3/6] libata: transfer EHI control flags to slave ehc.i ATA_EHI_NO_AUTOPSY and ATA_EHI_QUIET are used to control the behavior of EH. As only the master link is visible outside EH, these flags are set only for the master link although they should also apply to the slave link, which causes spurious EH messages during probe and suspend/resume. This patch transfers those two flags to slave ehc.i before performing slave autopsy and reporting. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-eh.c | 5 +++++ include/linux/libata.h | 3 +++ 2 files changed, 8 insertions(+) diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index a93247cc395..d2409a8acec 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2010,8 +2010,13 @@ void ata_eh_autopsy(struct ata_port *ap) struct ata_eh_context *mehc = &ap->link.eh_context; struct ata_eh_context *sehc = &ap->slave_link->eh_context; + /* transfer control flags from master to slave */ + sehc->i.flags |= mehc->i.flags & ATA_EHI_TO_SLAVE_MASK; + + /* perform autopsy on the slave link */ ata_eh_link_autopsy(ap->slave_link); + /* transfer actions from slave to master and clear slave */ ata_eh_about_to_do(ap->slave_link, NULL, ATA_EH_ALL_ACTIONS); mehc->i.action |= sehc->i.action; mehc->i.dev_action[1] |= sehc->i.dev_action[1]; diff --git a/include/linux/libata.h b/include/linux/libata.h index 947cf84e555..c261aa0584b 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -340,6 +340,9 @@ enum { ATA_EHI_DID_RESET = ATA_EHI_DID_SOFTRESET | ATA_EHI_DID_HARDRESET, + /* mask of flags to transfer *to* the slave link */ + ATA_EHI_TO_SLAVE_MASK = ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, + /* max tries if error condition is still set after ->error_handler */ ATA_EH_MAX_TRIES = 5, From a568d1d2e2aff4f114b087c06bfd350e945ad6cf Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 21 Oct 2008 20:37:21 +0900 Subject: [PATCH 4/6] libata-eh: fix slave link EH action mask handling Slave link action mask is transferred to master link and all the EH actions are taken by the master link. ata_eh_about_to_do() and ata_eh_done() are called with ATA_EH_ALL_ACTIONS to clear the slave link actions during transfer. This always sets ATA_PFLAG_RECOVERED flag causing spurious "EH complete" messages. Don't set ATA_PFLAG_RECOVERED for slave link actions. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-eh.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index d2409a8acec..7ccd0ce0e7d 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1206,7 +1206,10 @@ void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev, ata_eh_clear_action(link, dev, ehi, action); - if (!(ehc->i.flags & ATA_EHI_QUIET)) + /* About to take EH action, set RECOVERED. Ignore actions on + * slave links as master will do them again. + */ + if (!(ehc->i.flags & ATA_EHI_QUIET) && link != ap->slave_link) ap->pflags |= ATA_PFLAG_RECOVERED; spin_unlock_irqrestore(ap->lock, flags); From 816ab89782ac139a8b65147cca990822bb7e8675 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 22 Oct 2008 00:31:34 +0900 Subject: [PATCH 5/6] libata: set device class to NONE if phys_offline Reset methods don't have access to phys link status for slave links and may incorrectly indicate device presence causing unnecessary probe failures for unoccupied links. This patch clears device class to NONE during post-reset processing if phys link is offline. As on/offlineness semantics is strictly defined and used in multiple places by the core layer, this won't change behavior for drivers which don't use slave links. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-eh.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 7ccd0ce0e7d..5d687d7cffa 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2455,14 +2455,14 @@ int ata_eh_reset(struct ata_link *link, int classify, dev->pio_mode = XFER_PIO_0; dev->flags &= ~ATA_DFLAG_SLEEPING; - if (ata_phys_link_offline(ata_dev_phys_link(dev))) - continue; - - /* apply class override */ - if (lflags & ATA_LFLAG_ASSUME_ATA) - classes[dev->devno] = ATA_DEV_ATA; - else if (lflags & ATA_LFLAG_ASSUME_SEMB) - classes[dev->devno] = ATA_DEV_SEMB_UNSUP; /* not yet */ + if (!ata_phys_link_offline(ata_dev_phys_link(dev))) { + /* apply class override */ + if (lflags & ATA_LFLAG_ASSUME_ATA) + classes[dev->devno] = ATA_DEV_ATA; + else if (lflags & ATA_LFLAG_ASSUME_SEMB) + classes[dev->devno] = ATA_DEV_SEMB_UNSUP; + } else + classes[dev->devno] = ATA_DEV_NONE; } /* record current link speed */ From b78152e9dbab6d6175e2adcbd8c62959e8f0f922 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 22 Oct 2008 00:45:57 +0900 Subject: [PATCH 6/6] sata_via: load DEVICE register when CTL changes VIA controllers clear DEVICE register when IEN changes. Make sure DEVICE is updated along with CTL. This change is separated from Joseph Chan's larger patch. http://thread.gmane.org/gmane.linux.kernel.commits.mm/40640 Signed-off-by: Tejun Heo Cc: Joseph Chan Signed-off-by: Jeff Garzik --- drivers/ata/sata_via.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index 1cfa74535d9..5b72e734300 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -70,6 +70,7 @@ enum { static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); static int svia_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val); static int svia_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val); +static void svia_tf_load(struct ata_port *ap, const struct ata_taskfile *tf); static void svia_noop_freeze(struct ata_port *ap); static int vt6420_prereset(struct ata_link *link, unsigned long deadline); static int vt6421_pata_cable_detect(struct ata_port *ap); @@ -103,21 +104,26 @@ static struct scsi_host_template svia_sht = { ATA_BMDMA_SHT(DRV_NAME), }; -static struct ata_port_operations vt6420_sata_ops = { +static struct ata_port_operations svia_base_ops = { .inherits = &ata_bmdma_port_ops, + .sff_tf_load = svia_tf_load, +}; + +static struct ata_port_operations vt6420_sata_ops = { + .inherits = &svia_base_ops, .freeze = svia_noop_freeze, .prereset = vt6420_prereset, }; static struct ata_port_operations vt6421_pata_ops = { - .inherits = &ata_bmdma_port_ops, + .inherits = &svia_base_ops, .cable_detect = vt6421_pata_cable_detect, .set_piomode = vt6421_set_pio_mode, .set_dmamode = vt6421_set_dma_mode, }; static struct ata_port_operations vt6421_sata_ops = { - .inherits = &ata_bmdma_port_ops, + .inherits = &svia_base_ops, .scr_read = svia_scr_read, .scr_write = svia_scr_write, }; @@ -168,6 +174,29 @@ static int svia_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val) return 0; } +/** + * svia_tf_load - send taskfile registers to host controller + * @ap: Port to which output is sent + * @tf: ATA taskfile register set + * + * Outputs ATA taskfile to standard ATA host controller. + * + * This is to fix the internal bug of via chipsets, which will + * reset the device register after changing the IEN bit on ctl + * register. + */ +static void svia_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) +{ + struct ata_taskfile ttf; + + if (tf->ctl != ap->last_ctl) { + ttf = *tf; + ttf.flags |= ATA_TFLAG_DEVICE; + tf = &ttf; + } + ata_sff_tf_load(ap, tf); +} + static void svia_noop_freeze(struct ata_port *ap) { /* Some VIA controllers choke if ATA_NIEN is manipulated in