pcmcia - spot slave decode flaws (for testing)
authorAlan <alan@lxorguk.ukuu.org.uk>
Tue, 27 Mar 2007 05:43:34 +0000 (21:43 -0800)
committerJeff Garzik <jeff@garzik.org>
Sat, 28 Apr 2007 18:16:00 +0000 (14:16 -0400)
It tries to spot when the slave is a mirror of the master and to fix up
problems that causes.

I've got two confirmations so far that this plus the "can fail set_xfer" patch
work for folks who had problems before.  Also if you are unfortunate enough to
be running something like HAL then it'll automount the same disk twice for you
and corrupt it without the fix (aint that nice...)

Tested (successfully) by Komuro <komurojun-mbn@nifty.com>.

Signed-off-by: Alan Cox <alan@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
drivers/ata/pata_pcmcia.c

index 820332a7ec7b872ff2d84b92515f1c6fe147f1fc..171da0aeb65fe8d4eced335c0e6030d3a4ef0d1e 100644 (file)
@@ -54,6 +54,39 @@ struct ata_pcmcia_info {
        dev_node_t      node;
 };
 
+/**
+ *     pcmcia_set_mode -       PCMCIA specific mode setup
+ *     @ap: Port
+ *     @r_failed_dev: Return pointer for failed device
+ *
+ *     Perform the tuning and setup of the devices and timings, which
+ *     for PCMCIA is the same as any other controller. We wrap it however
+ *     as we need to spot hardware with incorrect or missing master/slave
+ *     decode, which alas is embarrassingly common in the PC world
+ */
+
+static int pcmcia_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
+{
+       struct ata_device *master = &ap->device[0];
+       struct ata_device *slave = &ap->device[1];
+
+       if (!ata_dev_enabled(master) || !ata_dev_enabled(slave))
+               return ata_do_set_mode(ap, r_failed_dev);
+
+       if (memcmp(master->id + ATA_ID_FW_REV,  slave->id + ATA_ID_FW_REV,
+                          ATA_ID_FW_REV_LEN + ATA_ID_PROD_LEN) == 0)
+       {
+               /* Suspicious match, but could be two cards from
+                  the same vendor - check serial */
+               if (memcmp(master->id + ATA_ID_SERNO, slave->id + ATA_ID_SERNO,
+                          ATA_ID_SERNO_LEN) == 0 && master->id[ATA_ID_SERNO] >> 8) {
+                       ata_dev_printk(slave, KERN_WARNING, "is a ghost device, ignoring.\n");
+                       ata_dev_disable(slave);
+               }
+       }
+       return ata_do_set_mode(ap, r_failed_dev);
+}
+
 static struct scsi_host_template pcmcia_sht = {
        .module                 = THIS_MODULE,
        .name                   = DRV_NAME,
@@ -73,6 +106,7 @@ static struct scsi_host_template pcmcia_sht = {
 };
 
 static struct ata_port_operations pcmcia_port_ops = {
+       .set_mode       = pcmcia_set_mode,
        .port_disable   = ata_port_disable,
        .tf_load        = ata_tf_load,
        .tf_read        = ata_tf_read,