[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

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: