libata: fallback to the other IDENTIFY on device error, take#2
[cascardo/linux.git] / drivers / ata / libata-core.c
index 6ac4f32..335ac8f 100644 (file)
@@ -1660,7 +1660,7 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
        struct ata_taskfile tf;
        unsigned int err_mask = 0;
        const char *reason;
-       int tried_spinup = 0;
+       int may_fallback = 1, tried_spinup = 0;
        int rc;
 
        if (ata_msg_ctl(ap))
@@ -1704,11 +1704,31 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
                        return -ENOENT;
                }
 
+               /* Device or controller might have reported the wrong
+                * device class.  Give a shot at the other IDENTIFY if
+                * the current one is aborted by the device.
+                */
+               if (may_fallback &&
+                   (err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) {
+                       may_fallback = 0;
+
+                       if (class == ATA_DEV_ATA)
+                               class = ATA_DEV_ATAPI;
+                       else
+                               class = ATA_DEV_ATA;
+                       goto retry;
+               }
+
                rc = -EIO;
                reason = "I/O error";
                goto err_out;
        }
 
+       /* Falling back doesn't make sense if ID data was read
+        * successfully at least once.
+        */
+       may_fallback = 0;
+
        swap_buf_le16(id, ATA_ID_WORDS);
 
        /* sanity check */