fedora-cvs-commits@redhat.com
[Top] [All Lists]

rpms/kernel/devel linux-2.6-libata-hpa.patch, NONE, 1.1 kernel-2.6.spec,

Subject: rpms/kernel/devel linux-2.6-libata-hpa.patch, NONE, 1.1 kernel-2.6.spec, 1.3078, 1.3079
From:
Date: Mon, 16 Apr 2007 18:27:55 -0400
Author: davej

Update of /cvs/dist/rpms/kernel/devel
In directory cvs.devel.redhat.com:/tmp/cvs-serv31576

Modified Files:
        kernel-2.6.spec 
Added Files:
        linux-2.6-libata-hpa.patch 
Log Message:
* Mon Apr 16 2007 Dave Jones <davej@xxxxxxxxxx>
- libata HPA support.


linux-2.6-libata-hpa.patch:
 drivers/ata/libata-core.c |  209 ++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/ata.h       |    2 
 include/linux/libata.h    |    1 
 3 files changed, 212 insertions(+)

--- NEW FILE linux-2.6-libata-hpa.patch ---

Signed-off-by: Alan Cox <alan@xxxxxxxxxx>

Add support for ignoring the BIOS HPA result (off by default) and setting
the disk to the full available size unless already frozen.

Tested with various platforms/disks and confirmed to work with the
Macintosh (which broke earlier) and ata_piix (breakage due to the LBA48
readback that Tejun fixed).

For normal users this brings us, I believe, to feature parity with old IDE
(and of course more featured in some areas too).

diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 735f0b0..e4fc33e 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -89,6 +89,10 @@ int libata_fua = 0;
 module_param_named(fua, libata_fua, int, 0444);
 MODULE_PARM_DESC(fua, "FUA support (0=off, 1=on)");
 
+static int ata_ignore_hpa = 0;
+module_param_named(ignore_hpa, ata_ignore_hpa, int, 0644);
+MODULE_PARM_DESC(ignore_hpa, "Ignore HPA (0=keep BIOS setting 1=ignore it)");
+
 static int ata_probe_timeout = ATA_TMOUT_INTERNAL / HZ;
 module_param(ata_probe_timeout, int, 0444);
 MODULE_PARM_DESC(ata_probe_timeout, "Set ATA probing timeout (seconds)");
@@ -808,6 +812,202 @@ void ata_id_c_string(const u16 *id, unsi
        *p = '\0';
 }
 
+static u64 ata_tf_to_lba48(struct ata_taskfile *tf)
+{
+       u64 sectors = 0;
+
+       sectors |= ((u64)(tf->hob_lbah & 0xff)) << 40;
+       sectors |= ((u64)(tf->hob_lbam & 0xff)) << 32;
+       sectors |= (tf->hob_lbal & 0xff) << 24;
+       sectors |= (tf->lbah & 0xff) << 16;
+       sectors |= (tf->lbam & 0xff) << 8;
+       sectors |= (tf->lbal & 0xff);
+
+       return ++sectors;
+}
+
+static u64 ata_tf_to_lba(struct ata_taskfile *tf)
+{
+       u64 sectors = 0;
+
+       sectors |= (tf->device & 0x0f) << 24;
+       sectors |= (tf->lbah & 0xff) << 16;
+       sectors |= (tf->lbam & 0xff) << 8;
+       sectors |= (tf->lbal & 0xff);
+
+       return ++sectors;
+}
+
+/**
+ *     ata_read_native_max_address_ext -       LBA48 native max query
+ *     @dev: Device to query
+ *
+ *     Perform an LBA48 size query upon the device in question. Return the
+ *     actual LBA48 size or zero if the command fails.
+ */
+
+static u64 ata_read_native_max_address_ext(struct ata_device *dev)
+{
+       unsigned int err;
+       struct ata_taskfile tf;
+
+       ata_tf_init(dev, &tf);
+
+       tf.command = ATA_CMD_READ_NATIVE_MAX_EXT;
+       tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 | ATA_TFLAG_ISADDR;
+       tf.protocol |= ATA_PROT_NODATA;
+       tf.device |= 0x40;
+
+       err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+       if (err)
+               return 0;
+
+       return ata_tf_to_lba48(&tf);
+}
+
+/**
+ *     ata_read_native_max_address     -       LBA28 native max query
+ *     @dev: Device to query
+ *
+ *     Performa an LBA28 size query upon the device in question. Return the
+ *     actual LBA28 size or zero if the command fails.
+ */
+
+static u64 ata_read_native_max_address(struct ata_device *dev)
+{
+       unsigned int err;
+       struct ata_taskfile tf;
+
+       ata_tf_init(dev, &tf);
+
+       tf.command = ATA_CMD_READ_NATIVE_MAX;
+       tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
+       tf.protocol |= ATA_PROT_NODATA;
+       tf.device |= 0x40;
+
+       err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+       if (err)
+               return 0;
+
+       return ata_tf_to_lba(&tf);
+}
+
+/**
+ *     ata_set_native_max_address_ext  -       LBA48 native max set
+ *     @dev: Device to query
+ *
+ *     Perform an LBA48 size set max upon the device in question. Return the
+ *     actual LBA48 size or zero if the command fails.
+ */
+
+static u64 ata_set_native_max_address_ext(struct ata_device *dev, u64 
new_sectors)
+{
+       unsigned int err;
+       struct ata_taskfile tf;
+
+       new_sectors--;
+
+       ata_tf_init(dev, &tf);
+
+       tf.command = ATA_CMD_SET_MAX_EXT;
+       tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 | ATA_TFLAG_ISADDR;
+       tf.protocol |= ATA_PROT_NODATA;
+       tf.device |= 0x40;
+
+       tf.lbal = (new_sectors >> 0) & 0xff;
+       tf.lbam = (new_sectors >> 8) & 0xff;
+       tf.lbah = (new_sectors >> 16) & 0xff;
+
+       tf.hob_lbal = (new_sectors >> 24) & 0xff;
+       tf.hob_lbam = (new_sectors >> 32) & 0xff;
+       tf.hob_lbah = (new_sectors >> 40) & 0xff;
+
+       err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+       if (err)
+               return 0;
+
+       return ata_tf_to_lba48(&tf);
+}
+
+/**
+ *     ata_set_native_max_address      -       LBA28 native max set
+ *     @dev: Device to query
+ *
+ *     Perform an LBA28 size set max upon the device in question. Return the
+ *     actual LBA28 size or zero if the command fails.
+ */
+
+static u64 ata_set_native_max_address(struct ata_device *dev, u64 new_sectors)
+{
+       unsigned int err;
+       struct ata_taskfile tf;
+
+       new_sectors--;
+
+       ata_tf_init(dev, &tf);
+
+       tf.command = ATA_CMD_SET_MAX;
+       tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
+       tf.protocol |= ATA_PROT_NODATA;
+
+       tf.lbal = (new_sectors >> 0) & 0xff;
+       tf.lbam = (new_sectors >> 8) & 0xff;
+       tf.lbah = (new_sectors >> 16) & 0xff;
+       tf.device |= ((new_sectors >> 24) & 0x0f) | 0x40;
+
+       err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+       if (err)
+               return 0;
+
+       return ata_tf_to_lba(&tf);
+}
+
+/**
+ *     ata_hpa_resize          -       Resize a device with an HPA set
+ *     @dev: Device to resize
+ *
+ *     Read the size of an LBA28 or LBA48 disk with HPA features and resize
+ *     it if required to the full size of the media. The caller must check
+ *     the drive has the HPA feature set enabled.
+ */
+
+static u64 ata_hpa_resize(struct ata_device *dev)
+{
+       u64 sectors = dev->n_sectors;
+       u64 hpa_sectors;
+       
+       if (ata_id_has_lba48(dev->id))
+               hpa_sectors = ata_read_native_max_address_ext(dev);
+       else
+               hpa_sectors = ata_read_native_max_address(dev);
+
+       /* if no hpa, both should be equal */
+       ata_dev_printk(dev, KERN_INFO, "%s 1: sectors = %lld, hpa_sectors = 
%lld\n",
+               __FUNCTION__, sectors, hpa_sectors);
+
+       if (hpa_sectors > sectors) {
+               ata_dev_printk(dev, KERN_INFO,
+                       "Host Protected Area detected:\n"
+                       "\tcurrent size: %lld sectors\n"
+                       "\tnative size: %lld sectors\n",
+                       sectors, hpa_sectors);
+
+               if (ata_ignore_hpa) {
+                       if (ata_id_has_lba48(dev->id))
+                               hpa_sectors = 
ata_set_native_max_address_ext(dev, hpa_sectors);
+                       else
+                               hpa_sectors = ata_set_native_max_address(dev, 
hpa_sectors);
+
+                       if (hpa_sectors) {
+                               ata_dev_printk(dev, KERN_INFO,
+                                       "native size increased to %lld 
sectors\n", hpa_sectors);
+                               return hpa_sectors;
+                       }
+               }
+       }
+       return sectors;
+}
+
 static u64 ata_id_n_sectors(const u16 *id)
 {
        if (ata_id_has_lba(id)) {
@@ -1658,6 +1858,7 @@ int ata_dev_configure(struct ata_device 
                        snprintf(revbuf, 7, "ATA-%d",  
ata_id_major_version(id));
 
                dev->n_sectors = ata_id_n_sectors(id);
+               dev->n_sectors_boot = dev->n_sectors;
 
                /* SCSI only uses 4-char revisions, dump full 8 chars from ATA 
*/
                ata_id_c_string(dev->id, fwrevbuf, ATA_ID_FW_REV,
@@ -1684,6 +1885,9 @@ int ata_dev_configure(struct ata_device 
                                        dev->flags |= ATA_DFLAG_FLUSH_EXT;
                        }
 
+                       if (ata_id_hpa_enabled(dev->id))
+                               dev->n_sectors = ata_hpa_resize(dev);
+
                        /* config NCQ */
                        ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc));
 
@@ -3341,6 +3545,11 @@ static int ata_dev_same_device(struct at
                               "%llu != %llu\n",
                               (unsigned long long)dev->n_sectors,
                               (unsigned long long)new_n_sectors);
+               /* Are we the boot time size - if so we appear to be the
+                  same disk at this point and our HPA got reapplied */
+               if (ata_ignore_hpa && dev->n_sectors_boot == new_n_sectors 
+                   && ata_id_hpa_enabled(new_id))
+                       return 1;
                return 0;
        }
 
diff --git a/include/linux/ata.h b/include/linux/ata.h
index ffb6cdc..f4dc8df 100644
--- a/include/linux/ata.h
+++ b/include/linux/ata.h
@@ -159,6 +159,8 @@ enum {
        ATA_CMD_INIT_DEV_PARAMS = 0x91,
        ATA_CMD_READ_NATIVE_MAX = 0xF8,
        ATA_CMD_READ_NATIVE_MAX_EXT = 0x27,
+       ATA_CMD_SET_MAX         = 0xF9,
+       ATA_CMD_SET_MAX_EXT     = 0x37,
        ATA_CMD_READ_LOG_EXT    = 0x2f,
 
        /* READ_LOG_EXT pages */
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 12237d4..b29850b 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -473,6 +473,7 @@ struct ata_device {
        struct scsi_device      *sdev;          /* attached SCSI device */
        /* n_sector is used as CLEAR_OFFSET, read comment above CLEAR_OFFSET */
        u64                     n_sectors;      /* size of device, if ATA */
+       u64                     n_sectors_boot; /* size of ATA device at 
startup */
        unsigned int            class;          /* ATA_DEV_xxx */
        u16                     id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */
        u8                      pio_mode;



Index: kernel-2.6.spec
===================================================================
RCS file: /cvs/dist/rpms/kernel/devel/kernel-2.6.spec,v
retrieving revision 1.3078
retrieving revision 1.3079
diff -u -r1.3078 -r1.3079
--- kernel-2.6.spec     16 Apr 2007 22:16:22 -0000      1.3078
+++ kernel-2.6.spec     16 Apr 2007 22:27:52 -0000      1.3079
@@ -585,6 +585,7 @@
 
 # SATA Bits
 Patch2200: linux-2.6-sata-promise-pata-ports.patch
+Patch2201: linux-2.6-libata-hpa.patch
 Patch2204: linux-2.6-ata-quirk.patch
 
 # ACPI bits
@@ -1307,6 +1308,8 @@
 
 # Enable PATA ports on Promise SATA.
 #%patch2200 -p1
+# HPA support for libata.
+%patch2201 -p1
 # libata: don't initialize sg in ata_exec_internal() if DMA_NONE
 # ia64 ata quirk
 %patch2204 -p1
@@ -2301,6 +2304,9 @@
 
 %changelog
 * Mon Apr 16 2007 Dave Jones <davej@xxxxxxxxxx>
+- libata HPA support.
+
+* Mon Apr 16 2007 Dave Jones <davej@xxxxxxxxxx>
 - Silence some more PM related noisy printk's.
 
 * Mon Apr 16 2007 Dave Jones <davej@xxxxxxxxxx>

-- 
fedora-cvs-commits mailing list
fedora-cvs-commits@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/fedora-cvs-commits

<Prev in Thread] Current Thread [Next in Thread>
  • rpms/kernel/devel linux-2.6-libata-hpa.patch, NONE, 1.1 kernel-2.6.spec, 1.3078, 1.3079, fedora-cvs-commits <=