Blame view

drivers/ide/ide-park.c 3.45 KB
4abdc6ee7   Elias Oltmanns   ide: Implement di...
1
  #include <linux/kernel.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
2
  #include <linux/gfp.h>
4abdc6ee7   Elias Oltmanns   ide: Implement di...
3
4
5
6
7
8
9
10
  #include <linux/ide.h>
  #include <linux/jiffies.h>
  #include <linux/blkdev.h>
  
  DECLARE_WAIT_QUEUE_HEAD(ide_park_wq);
  
  static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout)
  {
b65fac32c   Bartlomiej Zolnierkiewicz   ide: merge ide_hw...
11
  	ide_hwif_t *hwif = drive->hwif;
4abdc6ee7   Elias Oltmanns   ide: Implement di...
12
13
14
15
16
  	struct request_queue *q = drive->queue;
  	struct request *rq;
  	int rc;
  
  	timeout += jiffies;
b65fac32c   Bartlomiej Zolnierkiewicz   ide: merge ide_hw...
17
  	spin_lock_irq(&hwif->lock);
4abdc6ee7   Elias Oltmanns   ide: Implement di...
18
  	if (drive->dev_flags & IDE_DFLAG_PARKED) {
2a2ca6a96   Bartlomiej Zolnierkiewicz   ide: replace the ...
19
  		int reset_timer = time_before(timeout, drive->sleep);
201bffa46   Bartlomiej Zolnierkiewicz   ide: use per-devi...
20
  		int start_queue = 0;
4abdc6ee7   Elias Oltmanns   ide: Implement di...
21

4abdc6ee7   Elias Oltmanns   ide: Implement di...
22
23
  		drive->sleep = timeout;
  		wake_up_all(&ide_park_wq);
b65fac32c   Bartlomiej Zolnierkiewicz   ide: merge ide_hw...
24
  		if (reset_timer && del_timer(&hwif->timer))
201bffa46   Bartlomiej Zolnierkiewicz   ide: use per-devi...
25
  			start_queue = 1;
b65fac32c   Bartlomiej Zolnierkiewicz   ide: merge ide_hw...
26
  		spin_unlock_irq(&hwif->lock);
201bffa46   Bartlomiej Zolnierkiewicz   ide: use per-devi...
27

853280a4d   Tejun Heo   ide: use blk_run_...
28
29
  		if (start_queue)
  			blk_run_queue(q);
4abdc6ee7   Elias Oltmanns   ide: Implement di...
30
31
  		return;
  	}
b65fac32c   Bartlomiej Zolnierkiewicz   ide: merge ide_hw...
32
  	spin_unlock_irq(&hwif->lock);
4abdc6ee7   Elias Oltmanns   ide: Implement di...
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
  
  	rq = blk_get_request(q, READ, __GFP_WAIT);
  	rq->cmd[0] = REQ_PARK_HEADS;
  	rq->cmd_len = 1;
  	rq->cmd_type = REQ_TYPE_SPECIAL;
  	rq->special = &timeout;
  	rc = blk_execute_rq(q, NULL, rq, 1);
  	blk_put_request(rq);
  	if (rc)
  		goto out;
  
  	/*
  	 * Make sure that *some* command is sent to the drive after the
  	 * timeout has expired, so power management will be reenabled.
  	 */
  	rq = blk_get_request(q, READ, GFP_NOWAIT);
  	if (unlikely(!rq))
  		goto out;
  
  	rq->cmd[0] = REQ_UNPARK_HEADS;
  	rq->cmd_len = 1;
  	rq->cmd_type = REQ_TYPE_SPECIAL;
7eaceacca   Jens Axboe   block: remove per...
55
  	elv_add_request(q, rq, ELEVATOR_INSERT_FRONT);
4abdc6ee7   Elias Oltmanns   ide: Implement di...
56
57
58
59
  
  out:
  	return;
  }
c4e66c36c   Bartlomiej Zolnierkiewicz   ide: move ide_do_...
60
61
  ide_startstop_t ide_do_park_unpark(ide_drive_t *drive, struct request *rq)
  {
22aa4b32a   Bartlomiej Zolnierkiewicz   ide: remove ide_t...
62
63
  	struct ide_cmd cmd;
  	struct ide_taskfile *tf = &cmd.tf;
c4e66c36c   Bartlomiej Zolnierkiewicz   ide: move ide_do_...
64

22aa4b32a   Bartlomiej Zolnierkiewicz   ide: remove ide_t...
65
  	memset(&cmd, 0, sizeof(cmd));
c4e66c36c   Bartlomiej Zolnierkiewicz   ide: move ide_do_...
66
67
68
69
70
71
72
73
  	if (rq->cmd[0] == REQ_PARK_HEADS) {
  		drive->sleep = *(unsigned long *)rq->special;
  		drive->dev_flags |= IDE_DFLAG_SLEEPING;
  		tf->command = ATA_CMD_IDLEIMMEDIATE;
  		tf->feature = 0x44;
  		tf->lbal = 0x4c;
  		tf->lbam = 0x4e;
  		tf->lbah = 0x55;
60f85019c   Sergei Shtylyov   ide: replace IDE_...
74
75
  		cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
  		cmd.valid.in.tf  = IDE_VALID_IN_TF  | IDE_VALID_DEVICE;
c4e66c36c   Bartlomiej Zolnierkiewicz   ide: move ide_do_...
76
77
  	} else		/* cmd == REQ_UNPARK_HEADS */
  		tf->command = ATA_CMD_CHK_POWER;
d364c7f50   Bartlomiej Zolnierkiewicz   ide: use ide_comp...
78
  	cmd.tf_flags |= IDE_TFLAG_CUSTOM_HANDLER;
0dfb991c6   Bartlomiej Zolnierkiewicz   ide: use ata_tf_p...
79
  	cmd.protocol = ATA_PROT_NODATA;
22aa4b32a   Bartlomiej Zolnierkiewicz   ide: remove ide_t...
80
  	cmd.rq = rq;
22aa4b32a   Bartlomiej Zolnierkiewicz   ide: remove ide_t...
81
82
  
  	return do_rw_taskfile(drive, &cmd);
c4e66c36c   Bartlomiej Zolnierkiewicz   ide: move ide_do_...
83
  }
4abdc6ee7   Elias Oltmanns   ide: Implement di...
84
85
86
87
  ssize_t ide_park_show(struct device *dev, struct device_attribute *attr,
  		      char *buf)
  {
  	ide_drive_t *drive = to_ide_device(dev);
b65fac32c   Bartlomiej Zolnierkiewicz   ide: merge ide_hw...
88
  	ide_hwif_t *hwif = drive->hwif;
4abdc6ee7   Elias Oltmanns   ide: Implement di...
89
90
91
92
93
  	unsigned long now;
  	unsigned int msecs;
  
  	if (drive->dev_flags & IDE_DFLAG_NO_UNLOAD)
  		return -EOPNOTSUPP;
b65fac32c   Bartlomiej Zolnierkiewicz   ide: merge ide_hw...
94
  	spin_lock_irq(&hwif->lock);
4abdc6ee7   Elias Oltmanns   ide: Implement di...
95
96
97
98
99
100
  	now = jiffies;
  	if (drive->dev_flags & IDE_DFLAG_PARKED &&
  	    time_after(drive->sleep, now))
  		msecs = jiffies_to_msecs(drive->sleep - now);
  	else
  		msecs = 0;
b65fac32c   Bartlomiej Zolnierkiewicz   ide: merge ide_hw...
101
  	spin_unlock_irq(&hwif->lock);
4abdc6ee7   Elias Oltmanns   ide: Implement di...
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
  
  	return snprintf(buf, 20, "%u
  ", msecs);
  }
  
  ssize_t ide_park_store(struct device *dev, struct device_attribute *attr,
  		       const char *buf, size_t len)
  {
  #define MAX_PARK_TIMEOUT 30000
  	ide_drive_t *drive = to_ide_device(dev);
  	long int input;
  	int rc;
  
  	rc = strict_strtol(buf, 10, &input);
  	if (rc || input < -2)
  		return -EINVAL;
  	if (input > MAX_PARK_TIMEOUT) {
  		input = MAX_PARK_TIMEOUT;
  		rc = -EOVERFLOW;
  	}
  
  	mutex_lock(&ide_setting_mtx);
  	if (input >= 0) {
  		if (drive->dev_flags & IDE_DFLAG_NO_UNLOAD)
  			rc = -EOPNOTSUPP;
  		else if (input || drive->dev_flags & IDE_DFLAG_PARKED)
  			issue_park_cmd(drive, msecs_to_jiffies(input));
  	} else {
  		if (drive->media == ide_disk)
  			switch (input) {
  			case -1:
  				drive->dev_flags &= ~IDE_DFLAG_NO_UNLOAD;
  				break;
  			case -2:
  				drive->dev_flags |= IDE_DFLAG_NO_UNLOAD;
  				break;
  			}
  		else
  			rc = -EOPNOTSUPP;
  	}
  	mutex_unlock(&ide_setting_mtx);
  
  	return rc ? rc : len;
  }