Bug#377324: linux-2.6: HPA re-enabled after resume causes hard drive to be partially not accessible
Package: linux-2.6
Severity: normal
Tags: patch
Host protected area (sometimes called hidden protected area) is used to
have a hidden partition at the end of the harddrive.
The linux kernel disables HPA on boot and makes the whole harddrive
available to the kernel. I have a /home partition overlapping the host
protected area.
When doing a supend-to-ram and resume on my laptop, the Host protected
area is re-enabled causing the harddrive to appear smaller than it
actually is. After that, When I access data beyond the hpa limit,
the IO layer thinks I am accessing beyond the harddrive limit, catches
the error and remounts the /home partition read only.
The patch re-enables HPA on resume from ram and makes
suspend-to-ram/resume work on my laptop.
Regards,
--
Arnaud Cornet
-- System Information:
Debian Release: testing/unstable
APT prefers unstable
APT policy: (500, 'unstable')
Architecture: i386 (i686)
Shell: /bin/sh linked to /bin/bash
Kernel: Linux 2.6.17
Locale: LANG=fr_FR.UTF-8, LC_CTYPE=fr_FR.UTF-8 (charmap=UTF-8)
diff -ruN linux-2.6-2.6.17/drivers/ide/ide.c linux-2.6-2.6.17-resume-hpa/drivers/ide/ide.c
--- linux-2.6-2.6.17/drivers/ide/ide.c 2006-06-18 03:49:35.000000000 +0200
+++ linux-2.6-2.6.17-resume-hpa/drivers/ide/ide.c 2006-07-08 11:39:35.000000000 +0200
@@ -1238,6 +1238,7 @@
struct request rq;
struct request_pm_state rqpm;
ide_task_t args;
+ int ret;
memset(&rq, 0, sizeof(rq));
memset(&rqpm, 0, sizeof(rqpm));
@@ -1248,7 +1249,11 @@
rqpm.pm_step = ide_pm_state_start_resume;
rqpm.pm_state = PM_EVENT_ON;
- return ide_do_drive_cmd(drive, &rq, ide_head_wait);
+ ret = ide_do_drive_cmd(drive, &rq, ide_head_wait);
+
+ if (drive->has_hpa)
+ idedisk_disable_hpa(drive);
+ return ret;
}
int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device *bdev,
diff -ruN linux-2.6-2.6.17/drivers/ide/ide-disk.c linux-2.6-2.6.17-resume-hpa/drivers/ide/ide-disk.c
--- linux-2.6-2.6.17/drivers/ide/ide-disk.c 2006-06-18 03:49:35.000000000 +0200
+++ linux-2.6-2.6.17-resume-hpa/drivers/ide/ide-disk.c 2006-07-08 11:39:35.000000000 +0200
@@ -510,11 +510,29 @@
set_max = idedisk_set_max_address(drive, set_max);
if (set_max) {
drive->capacity64 = set_max;
+ drive->has_hpa = 1;
printk(KERN_INFO "%s: Host Protected Area disabled.\n",
drive->name);
}
}
+void idedisk_disable_hpa(ide_drive_t *drive)
+{
+ int lba48 = idedisk_supports_lba48(drive->id);
+
+ /* On my machine idedisk_set_max_address has no effect if
+ * idedisk_read_native_max_address is not called before */
+ if (lba48) {
+ idedisk_read_native_max_address_ext(drive);
+ idedisk_set_max_address_ext(drive, drive->capacity64);
+ } else {
+ idedisk_read_native_max_address(drive);
+ idedisk_set_max_address(drive, drive->capacity64);
+ }
+ printk(KERN_INFO "%s: Host Protected Area disabled.\n",
+ drive->name);
+}
+
/*
* Compute drive->capacity, the full capacity of the drive
* Called with drive->id != NULL.
diff -ruN linux-2.6-2.6.17/include/linux/ide.h linux-2.6-2.6.17-resume-hpa/include/linux/ide.h
--- linux-2.6-2.6.17/include/linux/ide.h 2006-06-18 03:49:35.000000000 +0200
+++ linux-2.6-2.6.17-resume-hpa/include/linux/ide.h 2006-07-08 11:39:36.000000000 +0200
@@ -602,6 +602,7 @@
unsigned scsi : 1; /* 0=default, 1=ide-scsi emulation */
unsigned sleeping : 1; /* 1=sleeping & sleep field valid */
unsigned post_reset : 1;
+ unsigned has_hpa : 1; /* host protected area detected */
u8 quirk_list; /* considered quirky, set for a specific host */
u8 init_speed; /* transfer rate set at boot */
Reply to: