]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/ata/sata_nv.c
Merge branch 'upstream-2.6.28' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarz...
[linux-2.6-omap-h63xx.git] / drivers / ata / sata_nv.c
index 109b07495721ebf684710d50949f00db78e63f8d..fae3841de0d8726468adc4b6a93202f0d4177ed7 100644 (file)
@@ -302,8 +302,8 @@ static void nv_ck804_host_stop(struct ata_host *host);
 static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance);
 static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance);
 static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance);
-static int nv_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
-static int nv_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int nv_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
+static int nv_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
 
 static void nv_nf2_freeze(struct ata_port *ap);
 static void nv_nf2_thaw(struct ata_port *ap);
@@ -405,28 +405,45 @@ static struct scsi_host_template nv_swncq_sht = {
        .slave_configure        = nv_swncq_slave_config,
 };
 
-static struct ata_port_operations nv_generic_ops = {
+/* OSDL bz3352 reports that some nv controllers can't determine device
+ * signature reliably and nv_hardreset is implemented to work around
+ * the problem.  This was reported on nf3 and it's unclear whether any
+ * other controllers are affected.  However, the workaround has been
+ * applied to all variants and there isn't much to gain by trying to
+ * find out exactly which ones are affected at this point especially
+ * because NV has moved over to ahci for newer controllers.
+ */
+static struct ata_port_operations nv_common_ops = {
        .inherits               = &ata_bmdma_port_ops,
        .hardreset              = nv_hardreset,
        .scr_read               = nv_scr_read,
        .scr_write              = nv_scr_write,
 };
 
+/* OSDL bz11195 reports that link doesn't come online after hardreset
+ * on generic nv's and there have been several other similar reports
+ * on linux-ide.  Disable hardreset for generic nv's.
+ */
+static struct ata_port_operations nv_generic_ops = {
+       .inherits               = &nv_common_ops,
+       .hardreset              = ATA_OP_NULL,
+};
+
 static struct ata_port_operations nv_nf2_ops = {
-       .inherits               = &nv_generic_ops,
+       .inherits               = &nv_common_ops,
        .freeze                 = nv_nf2_freeze,
        .thaw                   = nv_nf2_thaw,
 };
 
 static struct ata_port_operations nv_ck804_ops = {
-       .inherits               = &nv_generic_ops,
+       .inherits               = &nv_common_ops,
        .freeze                 = nv_ck804_freeze,
        .thaw                   = nv_ck804_thaw,
        .host_stop              = nv_ck804_host_stop,
 };
 
 static struct ata_port_operations nv_adma_ops = {
-       .inherits               = &nv_generic_ops,
+       .inherits               = &nv_common_ops,
 
        .check_atapi_dma        = nv_adma_check_atapi_dma,
        .sff_tf_read            = nv_adma_tf_read,
@@ -450,7 +467,7 @@ static struct ata_port_operations nv_adma_ops = {
 };
 
 static struct ata_port_operations nv_swncq_ops = {
-       .inherits               = &nv_generic_ops,
+       .inherits               = &nv_common_ops,
 
        .qc_defer               = ata_std_qc_defer,
        .qc_prep                = nv_swncq_qc_prep,
@@ -1494,21 +1511,21 @@ static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance)
        return ret;
 }
 
-static int nv_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
+static int nv_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
 {
        if (sc_reg > SCR_CONTROL)
                return -EINVAL;
 
-       *val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
+       *val = ioread32(link->ap->ioaddr.scr_addr + (sc_reg * 4));
        return 0;
 }
 
-static int nv_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int nv_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
 {
        if (sc_reg > SCR_CONTROL)
                return -EINVAL;
 
-       iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+       iowrite32(val, link->ap->ioaddr.scr_addr + (sc_reg * 4));
        return 0;
 }
 
@@ -1591,13 +1608,16 @@ static void nv_mcp55_thaw(struct ata_port *ap)
 static int nv_hardreset(struct ata_link *link, unsigned int *class,
                        unsigned long deadline)
 {
-       unsigned int dummy;
+       int rc;
 
        /* SATA hardreset fails to retrieve proper device signature on
-        * some controllers.  Don't classify on hardreset.  For more
-        * info, see http://bugzilla.kernel.org/show_bug.cgi?id=3352
+        * some controllers.  Request follow up SRST.  For more info,
+        * see http://bugzilla.kernel.org/show_bug.cgi?id=3352
         */
-       return sata_sff_hardreset(link, &dummy, deadline);
+       rc = sata_sff_hardreset(link, class, deadline);
+       if (rc)
+               return rc;
+       return -EAGAIN;
 }
 
 static void nv_adma_error_handler(struct ata_port *ap)
@@ -2198,9 +2218,9 @@ static void nv_swncq_host_interrupt(struct ata_port *ap, u16 fis)
        if (!pp->qc_active)
                return;
 
-       if (ap->ops->scr_read(ap, SCR_ERROR, &serror))
+       if (ap->ops->scr_read(&ap->link, SCR_ERROR, &serror))
                return;
-       ap->ops->scr_write(ap, SCR_ERROR, serror);
+       ap->ops->scr_write(&ap->link, SCR_ERROR, serror);
 
        if (ata_stat & ATA_ERR) {
                ata_ehi_clear_desc(ehi);