[PATCH] libata basic detection and errata for PATA->SATA bridges

From: Brad Campbell (brad_at_wasp.net.au)
Date: 08/31/04

  • Next message: Francesco Biscani: "Re: System freeze: __iounmap: bad address dfd00000"
    Date:	Tue, 31 Aug 2004 12:26:14 +0400
    To: lkml <linux-kernel@vger.kernel.org>, Jeff Garzik <jgarzik@pobox.com>
    
    
    

    Ok Jeff, I can take a hint! :p)
    Patch against 2.6.9-rc1 Vanilla

    This patch works around an issue with WD drives (and possibly others) over SiL PATA->SATA Bridges on
    SATA controllers locking up with transfers > 200 sectors.

    Signed-off-by: Brad Campbell <brad@wasp.net.au>

    
    

    diff -ur orig/linux-2.6.0/drivers/scsi/libata-core.c linux-2.6.9-rc1/drivers/scsi/libata-core.c
    --- orig/linux-2.6.0/drivers/scsi/libata-core.c 2004-08-30 20:48:35.000000000 +0400
    +++ linux-2.6.9-rc1/drivers/scsi/libata-core.c 2004-08-30 21:02:42.000000000 +0400
    @@ -1128,6 +1128,37 @@
             DPRINTK("EXIT, err\n");
     }
     
    +
    +static inline u8 ata_dev_knobble(struct ata_port *ap)
    +{
    + return ((ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(ap->device)));
    +}
    +
    +/**
    + * ata_dev_config - Run device specific handlers and check for
    + * SATA->PATA bridges
    + * @ap: Bus
    + * @i: Device
    + *
    + * LOCKING:
    + */
    +
    +void ata_dev_config(struct ata_port *ap, unsigned int i)
    +{
    + /* limit bridge transfers to udma5, 200 sectors */
    + if (ata_dev_knobble(ap)) {
    + printk(KERN_INFO "ata%u(%u): applying bridge limits\n",
    + ap->id, ap->device->devno);
    + ap->udma_mask &= ATA_UDMA5;
    + ap->host->max_sectors = ATA_MAX_SECTORS;
    + ap->host->hostt->max_sectors = ATA_MAX_SECTORS;
    + ap->device->flags |= ATA_DFLAG_LOCK_SECTORS;
    + }
    +
    + if (ap->ops->dev_config)
    + ap->ops->dev_config(ap, &ap->device[i]);
    +}
    +
     /**
      * ata_bus_probe - Reset and probe ATA bus
      * @ap: Bus to probe
    @@ -1150,8 +1181,7 @@
                     ata_dev_identify(ap, i);
                     if (ata_dev_present(&ap->device[i])) {
                             found = 1;
    - if (ap->ops->dev_config)
    - ap->ops->dev_config(ap, &ap->device[i]);
    + ata_dev_config(ap,i);
                     }
             }
     
    @@ -1226,7 +1256,7 @@
                     ata_port_disable(ap);
                     return;
             }
    -
    + ap->cbl = ATA_CBL_SATA;
             ata_bus_reset(ap);
     }
     
    @@ -3567,3 +3597,4 @@
     EXPORT_SYMBOL_GPL(ata_scsi_release);
     EXPORT_SYMBOL_GPL(ata_host_intr);
     EXPORT_SYMBOL_GPL(ata_dev_id_string);
    +EXPORT_SYMBOL_GPL(ata_dev_config);
    nly in linux-2.6.9-rc1/include: config
    diff -ur orig/linux-2.6.0/include/linux/ata.h linux-2.6.9-rc1/include/linux/ata.h
    --- orig/linux-2.6.0/include/linux/ata.h 2004-08-30 20:48:35.000000000 +0400
    +++ linux-2.6.9-rc1/include/linux/ata.h 2004-08-30 18:42:41.000000000 +0400
    @@ -218,6 +218,7 @@
     };
     
     #define ata_id_is_ata(dev) (((dev)->id[0] & (1 << 15)) == 0)
    +#define ata_id_is_sata(dev) ((dev)->id[93] == 0)
     #define ata_id_rahead_enabled(dev) ((dev)->id[85] & (1 << 6))
     #define ata_id_wcache_enabled(dev) ((dev)->id[85] & (1 << 5))
     #define ata_id_has_flush(dev) ((dev)->id[83] & (1 << 12))
    diff -ur orig/linux-2.6.0/include/linux/libata.h linux-2.6.9-rc1/include/linux/libata.h
    --- orig/linux-2.6.0/include/linux/libata.h 2004-08-30 20:48:35.000000000 +0400
    +++ linux-2.6.9-rc1/include/linux/libata.h 2004-08-30 20:42:05.000000000 +0400
    @@ -400,6 +400,7 @@
                      unsigned int n_elem);
     extern void ata_dev_id_string(struct ata_device *dev, unsigned char *s,
                                   unsigned int ofs, unsigned int len);
    +extern void ata_dev_config(struct ata_port *ap, unsigned int i);
     extern void ata_bmdma_setup_mmio (struct ata_queued_cmd *qc);
     extern void ata_bmdma_start_mmio (struct ata_queued_cmd *qc);
     extern void ata_bmdma_setup_pio (struct ata_queued_cmd *qc);

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/


  • Next message: Francesco Biscani: "Re: System freeze: __iounmap: bad address dfd00000"

    Relevant Pages

    • Re: Hude read/write cache
      ... This a patch that defers disk writes, so that your disks can ... HDs have a VERY LIMITED amount of spinups/spindowns in them, about 50K for most desktop drives ... send the line "unsubscribe linux-kernel" in ...
      (Linux-Kernel)
    • Re: [PATCH] 2.6: ATAPI MO drive support
      ... > The below patch is needed to support ATAPI MO drives in 2.6. ... send the line "unsubscribe linux-kernel" in ...
      (Linux-Kernel)
    • Re: [parisc-linux] Re: [PATCH 3/9] mm: parisc pte atomicity
      ... using your own tmpalias area sounds much better than getting ... I've simply not wrapped my head around the races, ... it looks like we agree that my patch is necessary and valid as is; ... send the line "unsubscribe linux-kernel" in ...
      (Linux-Kernel)
    • Re: keyboard - was: Re: Linux 2.6.0-test4
      ... >> I was able to get the key unstuck by switching back and forth between ... I rebuild my kernel including your patch; ... I'll get back to you once I verify that the problem doesn't occur ... send the line "unsubscribe linux-kernel" in ...
      (Linux-Kernel)
    • Re: Packet writing problems
      ... >> I'm trying to do packet writing with my new DVD writer. ... The second problem is in the dvdrw-support patch in the -mm kernel. ... The problem is that some drives fail the "GET CONFIGURATION" command ... send the line "unsubscribe linux-kernel" in ...
      (Linux-Kernel)