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 */