aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan <alan@lxorguk.ukuu.org.uk>2007-03-27 01:43:34 -0400
committerJeff Garzik <jeff@garzik.org>2007-04-28 14:16:00 -0400
commit4dc5200d70a3e81510956c35fbb9fa3c15b440a5 (patch)
treeb934cafd1657dc5035fecc154d043e4dad80a002
parent120bda35ff8514c937dac6d4e5c7dc6c01c699ac (diff)
pcmcia - spot slave decode flaws (for testing)
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>
-rw-r--r--drivers/ata/pata_pcmcia.c34
1 files changed, 34 insertions, 0 deletions
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c
index 820332a7ec7b..171da0aeb65f 100644
--- a/drivers/ata/pata_pcmcia.c
+++ b/drivers/ata/pata_pcmcia.c
@@ -54,6 +54,39 @@ struct ata_pcmcia_info {
54 dev_node_t node; 54 dev_node_t node;
55}; 55};
56 56
57/**
58 * pcmcia_set_mode - PCMCIA specific mode setup
59 * @ap: Port
60 * @r_failed_dev: Return pointer for failed device
61 *
62 * Perform the tuning and setup of the devices and timings, which
63 * for PCMCIA is the same as any other controller. We wrap it however
64 * as we need to spot hardware with incorrect or missing master/slave
65 * decode, which alas is embarrassingly common in the PC world
66 */
67
68static int pcmcia_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
69{
70 struct ata_device *master = &ap->device[0];
71 struct ata_device *slave = &ap->device[1];
72
73 if (!ata_dev_enabled(master) || !ata_dev_enabled(slave))
74 return ata_do_set_mode(ap, r_failed_dev);
75
76 if (memcmp(master->id + ATA_ID_FW_REV, slave->id + ATA_ID_FW_REV,
77 ATA_ID_FW_REV_LEN + ATA_ID_PROD_LEN) == 0)
78 {
79 /* Suspicious match, but could be two cards from
80 the same vendor - check serial */
81 if (memcmp(master->id + ATA_ID_SERNO, slave->id + ATA_ID_SERNO,
82 ATA_ID_SERNO_LEN) == 0 && master->id[ATA_ID_SERNO] >> 8) {
83 ata_dev_printk(slave, KERN_WARNING, "is a ghost device, ignoring.\n");
84 ata_dev_disable(slave);
85 }
86 }
87 return ata_do_set_mode(ap, r_failed_dev);
88}
89
57static struct scsi_host_template pcmcia_sht = { 90static struct scsi_host_template pcmcia_sht = {
58 .module = THIS_MODULE, 91 .module = THIS_MODULE,
59 .name = DRV_NAME, 92 .name = DRV_NAME,
@@ -73,6 +106,7 @@ static struct scsi_host_template pcmcia_sht = {
73}; 106};
74 107
75static struct ata_port_operations pcmcia_port_ops = { 108static struct ata_port_operations pcmcia_port_ops = {
109 .set_mode = pcmcia_set_mode,
76 .port_disable = ata_port_disable, 110 .port_disable = ata_port_disable,
77 .tf_load = ata_tf_load, 111 .tf_load = ata_tf_load,
78 .tf_read = ata_tf_read, 112 .tf_read = ata_tf_read,