[PATCH] libata: Don't believe bogus claims in the older PIO mode register
[sfrench/cifs-2.6.git] / drivers / ata / libata-core.c
index 1c9315401f7ad561e7385b0dcf57bc70ac3cae1f..ad8e2c64c867ea1927597032896d471e417660c7 100644 (file)
@@ -616,8 +616,11 @@ ata_dev_try_classify(struct ata_port *ap, unsigned int device, u8 *r_err)
        if (r_err)
                *r_err = err;
 
-       /* see if device passed diags */
-       if (err == 1)
+       /* see if device passed diags: if master then continue and warn later */
+       if (err == 0 && device == 0)
+               /* diagnostic fail : do nothing _YET_ */
+               ap->device[device].horkage |= ATA_HORKAGE_DIAGNOSTIC;
+       else if (err == 1)
                /* do nothing */ ;
        else if ((device == 0) && (err == 0x81))
                /* do nothing */ ;
@@ -867,7 +870,11 @@ static unsigned int ata_id_xfermask(const u16 *id)
                 * the PIO timing number for the maximum. Turn it into
                 * a mask.
                 */
-               pio_mask = (2 << (id[ATA_ID_OLD_PIO_MODES] & 0xFF)) - 1 ;
+               u8 mode = id[ATA_ID_OLD_PIO_MODES] & 0xFF;
+               if (mode < 5)   /* Valid PIO range */
+                       pio_mask = (2 << mode) - 1;
+               else
+                       pio_mask = 1;
 
                /* But wait.. there's more. Design your standards by
                 * committee and you too can get a free iordy field to
@@ -1276,10 +1283,15 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
        swap_buf_le16(id, ATA_ID_WORDS);
 
        /* sanity check */
-       if ((class == ATA_DEV_ATA) != (ata_id_is_ata(id) | ata_id_is_cfa(id))) {
-               rc = -EINVAL;
-               reason = "device reports illegal type";
-               goto err_out;
+       rc = -EINVAL;
+       reason = "device reports illegal type";
+
+       if (class == ATA_DEV_ATA) {
+               if (!ata_id_is_ata(id) && !ata_id_is_cfa(id))
+                       goto err_out;
+       } else {
+               if (ata_id_is_ata(id))
+                       goto err_out;
        }
 
        if (post_reset && class == ATA_DEV_ATA) {
@@ -1518,6 +1530,18 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
                                       cdb_intr_string);
        }
 
+       if (dev->horkage & ATA_HORKAGE_DIAGNOSTIC) {
+               /* Let the user know. We don't want to disallow opens for
+                  rescue purposes, or in case the vendor is just a blithering
+                  idiot */
+                if (print_info) {
+                       ata_dev_printk(dev, KERN_WARNING,
+"Drive reports diagnostics failure. This may indicate a drive\n");
+                       ata_dev_printk(dev, KERN_WARNING,
+"fault or invalid emulation. Contact drive vendor for information.\n");
+               }
+       }
+
        ata_set_port_max_cmd_len(ap);
 
        /* limit bridge transfers to udma5, 200 sectors */
@@ -2320,7 +2344,8 @@ unsigned int ata_busy_sleep (struct ata_port *ap,
 
        if (status & ATA_BUSY)
                ata_port_printk(ap, KERN_WARNING,
-                               "port is slow to respond, please be patient\n");
+                               "port is slow to respond, please be patient "
+                               "(Status 0x%x)\n", status);
 
        timeout = timer_start + tmout;
        while ((status & ATA_BUSY) && (time_before(jiffies, timeout))) {
@@ -2330,7 +2355,8 @@ unsigned int ata_busy_sleep (struct ata_port *ap,
 
        if (status & ATA_BUSY) {
                ata_port_printk(ap, KERN_ERR, "port failed to respond "
-                               "(%lu secs)\n", tmout / HZ);
+                               "(%lu secs, Status 0x%x)\n",
+                               tmout / HZ, status);
                return 1;
        }
 
@@ -5269,11 +5295,19 @@ void ata_port_init(struct ata_port *ap, struct ata_host *host,
        ap->host = host;
        ap->dev = ent->dev;
        ap->port_no = port_no;
-       ap->pio_mask = ent->pio_mask;
-       ap->mwdma_mask = ent->mwdma_mask;
-       ap->udma_mask = ent->udma_mask;
-       ap->flags |= ent->port_flags;
-       ap->ops = ent->port_ops;
+       if (port_no == 1 && ent->pinfo2) {
+               ap->pio_mask = ent->pinfo2->pio_mask;
+               ap->mwdma_mask = ent->pinfo2->mwdma_mask;
+               ap->udma_mask = ent->pinfo2->udma_mask;
+               ap->flags |= ent->pinfo2->flags;
+               ap->ops = ent->pinfo2->port_ops;
+       } else {
+               ap->pio_mask = ent->pio_mask;
+               ap->mwdma_mask = ent->mwdma_mask;
+               ap->udma_mask = ent->udma_mask;
+               ap->flags |= ent->port_flags;
+               ap->ops = ent->port_ops;
+       }
        ap->hw_sata_spd_limit = UINT_MAX;
        ap->active_tag = ATA_TAG_POISON;
        ap->last_ctl = 0xFF;
@@ -5425,6 +5459,11 @@ int ata_device_add(const struct ata_probe_ent *ent)
        int rc;
 
        DPRINTK("ENTER\n");
+       
+       if (ent->irq == 0) {
+               dev_printk(KERN_ERR, dev, "is not available: No interrupt assigned.\n");
+               return 0;
+       }
        /* alloc a container for our list of ATA ports (buses) */
        host = kzalloc(sizeof(struct ata_host) +
                       (ent->n_ports * sizeof(void *)), GFP_KERNEL);
@@ -5445,11 +5484,10 @@ int ata_device_add(const struct ata_probe_ent *ent)
                int irq_line = ent->irq;
 
                ap = ata_port_add(ent, host, i);
+               host->ports[i] = ap;
                if (!ap)
                        goto err_out;
 
-               host->ports[i] = ap;
-
                /* dummy? */
                if (ent->dummy_port_mask & (1 << i)) {
                        ata_port_printk(ap, KERN_INFO, "DUMMY\n");
@@ -5707,7 +5745,7 @@ void ata_host_remove(struct ata_host *host)
 
 /**
  *     ata_scsi_release - SCSI layer callback hook for host unload
- *     @host: libata host to be unloaded
+ *     @shost: libata host to be unloaded
  *
  *     Performs all duties necessary to shut down a libata port...
  *     Kill port kthread, disable port, and release resources.
@@ -5753,6 +5791,7 @@ ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port)
        probe_ent->mwdma_mask = port->mwdma_mask;
        probe_ent->udma_mask = port->udma_mask;
        probe_ent->port_ops = port->port_ops;
+       probe_ent->private_data = port->private_data;
 
        return probe_ent;
 }