aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ide/ide-io.c
diff options
context:
space:
mode:
authorElias Oltmanns <eo@nebensachen.de>2008-10-13 15:39:50 -0400
committerBartlomiej Zolnierkiewicz <bzolnier@gmail.com>2008-10-13 15:39:50 -0400
commit4abdc6ee7c47a1a6e12f95717e461baeebee5df7 (patch)
tree51cac3d66891d026483838563e35124467a8eb86 /drivers/ide/ide-io.c
parent08243ba731ee08ff42cf1589379c81567690218f (diff)
ide: Implement disk shock protection support (v4)
On user request (through sysfs), the IDLE IMMEDIATE command with UNLOAD FEATURE as specified in ATA-7 is issued to the device and processing of the request queue is stopped thereafter until the specified timeout expires or user space asks to resume normal operation. This is supposed to prevent the heads of a hard drive from accidentally crashing onto the platter when a heavy shock is anticipated (like a falling laptop expected to hit the floor). Port resets are deferred whenever a device on that port is in the parked state. v3: Elias Oltmanns <eo@nebensachen.de> wrote: [...] > >> 1. Make sure that no negative value is being passed to > >> jiffies_to_msecs() in ide_park_show(). > >> 2. Drop the superfluous variable hwif in ide_special_rq(). > >> 3. Skip initialisation of task and tf in ide_special_rq() if we are not > >> handling a (un)park request. > > > > Well, #3 should have been done differently because we donn't want to > > check for REQ_(UN)?PARK_HEADS more often than is necessary. > > While preparing the backport to 2.6.27, it has just occurred to me that > we need to clear the IDE_DFLAG_PARKED flag in ide_disk_pre_reset() > because this flag must not be set after *any* sort of access to the > device. v4: Fix a memory leak due to a missing blk_put_request() in issue_park_cmd(). Additionally, we should plug the queue when enqueueing the unpark request because there is no guarantee that the park timeout has not expired by then. Even though the chance for that to happen is very slim, the request might end up hanging in the queue until the next I/O operation is queued up. While at it, clean up the code a little: - make issue_park_cmd() a function of type void since nobody cares for the return value anyway; - use blk_start_queueing() instead of __blk_run_queue() since we don't have to worry about recursion; - remove a superfluous pointer deference in task_no_data_intr(). Signed-off-by: Elias Oltmanns <eo@nebensachen.de> Cc: Jeff Garzik <jeff@garzik.org>, Cc: Randy Dunlap <randy.dunlap@oracle.com> Cc: Tejun Heo <htejun@gmail.com> Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Diffstat (limited to 'drivers/ide/ide-io.c')
-rw-r--r--drivers/ide/ide-io.c29
1 files changed, 27 insertions, 2 deletions
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index e205f46c3c7a..77c6eaeacefa 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -672,7 +672,32 @@ EXPORT_SYMBOL_GPL(ide_devset_execute);
672 672
673static ide_startstop_t ide_special_rq(ide_drive_t *drive, struct request *rq) 673static ide_startstop_t ide_special_rq(ide_drive_t *drive, struct request *rq)
674{ 674{
675 switch (rq->cmd[0]) { 675 u8 cmd = rq->cmd[0];
676
677 if (cmd == REQ_PARK_HEADS || cmd == REQ_UNPARK_HEADS) {
678 ide_task_t task;
679 struct ide_taskfile *tf = &task.tf;
680
681 memset(&task, 0, sizeof(task));
682 if (cmd == REQ_PARK_HEADS) {
683 drive->sleep = *(unsigned long *)rq->special;
684 drive->dev_flags |= IDE_DFLAG_SLEEPING;
685 tf->command = ATA_CMD_IDLEIMMEDIATE;
686 tf->feature = 0x44;
687 tf->lbal = 0x4c;
688 tf->lbam = 0x4e;
689 tf->lbah = 0x55;
690 task.tf_flags |= IDE_TFLAG_CUSTOM_HANDLER;
691 } else /* cmd == REQ_UNPARK_HEADS */
692 tf->command = ATA_CMD_CHK_POWER;
693
694 task.tf_flags |= IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
695 task.rq = rq;
696 drive->hwif->data_phase = task.data_phase = TASKFILE_NO_DATA;
697 return do_rw_taskfile(drive, &task);
698 }
699
700 switch (cmd) {
676 case REQ_DEVSET_EXEC: 701 case REQ_DEVSET_EXEC:
677 { 702 {
678 int err, (*setfunc)(ide_drive_t *, int) = rq->special; 703 int err, (*setfunc)(ide_drive_t *, int) = rq->special;
@@ -1008,7 +1033,7 @@ static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
1008 } 1033 }
1009 hwgroup->hwif = hwif; 1034 hwgroup->hwif = hwif;
1010 hwgroup->drive = drive; 1035 hwgroup->drive = drive;
1011 drive->dev_flags &= ~IDE_DFLAG_SLEEPING; 1036 drive->dev_flags &= ~(IDE_DFLAG_SLEEPING | IDE_DFLAG_PARKED);
1012 drive->service_start = jiffies; 1037 drive->service_start = jiffies;
1013 1038
1014 if (blk_queue_plugged(drive->queue)) { 1039 if (blk_queue_plugged(drive->queue)) {