aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ide/ide-gd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ide/ide-gd.c')
-rw-r--r--drivers/ide/ide-gd.c296
1 files changed, 296 insertions, 0 deletions
diff --git a/drivers/ide/ide-gd.c b/drivers/ide/ide-gd.c
new file mode 100644
index 000000000000..84bbcfee9233
--- /dev/null
+++ b/drivers/ide/ide-gd.c
@@ -0,0 +1,296 @@
1#include <linux/module.h>
2#include <linux/types.h>
3#include <linux/string.h>
4#include <linux/kernel.h>
5#include <linux/errno.h>
6#include <linux/genhd.h>
7#include <linux/mutex.h>
8#include <linux/ide.h>
9#include <linux/hdreg.h>
10
11#if !defined(CONFIG_DEBUG_BLOCK_EXT_DEVT)
12#define IDE_DISK_MINORS (1 << PARTN_BITS)
13#else
14#define IDE_DISK_MINORS 0
15#endif
16
17#include "ide-disk.h"
18
19#define IDE_GD_VERSION "1.18"
20
21static DEFINE_MUTEX(ide_disk_ref_mutex);
22
23static void ide_disk_release(struct kref *);
24
25static struct ide_disk_obj *ide_disk_get(struct gendisk *disk)
26{
27 struct ide_disk_obj *idkp = NULL;
28
29 mutex_lock(&ide_disk_ref_mutex);
30 idkp = ide_drv_g(disk, ide_disk_obj);
31 if (idkp) {
32 if (ide_device_get(idkp->drive))
33 idkp = NULL;
34 else
35 kref_get(&idkp->kref);
36 }
37 mutex_unlock(&ide_disk_ref_mutex);
38 return idkp;
39}
40
41static void ide_disk_put(struct ide_disk_obj *idkp)
42{
43 ide_drive_t *drive = idkp->drive;
44
45 mutex_lock(&ide_disk_ref_mutex);
46 kref_put(&idkp->kref, ide_disk_release);
47 ide_device_put(drive);
48 mutex_unlock(&ide_disk_ref_mutex);
49}
50
51sector_t ide_gd_capacity(ide_drive_t *drive)
52{
53 return drive->capacity64;
54}
55
56static int ide_gd_probe(ide_drive_t *);
57
58static void ide_gd_remove(ide_drive_t *drive)
59{
60 struct ide_disk_obj *idkp = drive->driver_data;
61 struct gendisk *g = idkp->disk;
62
63 ide_proc_unregister_driver(drive, idkp->driver);
64
65 del_gendisk(g);
66
67 ide_disk_flush(drive);
68
69 ide_disk_put(idkp);
70}
71
72static void ide_disk_release(struct kref *kref)
73{
74 struct ide_disk_obj *idkp = to_ide_drv(kref, ide_disk_obj);
75 ide_drive_t *drive = idkp->drive;
76 struct gendisk *g = idkp->disk;
77
78 drive->driver_data = NULL;
79 g->private_data = NULL;
80 put_disk(g);
81 kfree(idkp);
82}
83
84/*
85 * On HPA drives the capacity needs to be
86 * reinitilized on resume otherwise the disk
87 * can not be used and a hard reset is required
88 */
89static void ide_gd_resume(ide_drive_t *drive)
90{
91 if (ata_id_hpa_enabled(drive->id))
92 ide_disk_init_capacity(drive);
93}
94
95static void ide_gd_shutdown(ide_drive_t *drive)
96{
97#ifdef CONFIG_ALPHA
98 /* On Alpha, halt(8) doesn't actually turn the machine off,
99 it puts you into the sort of firmware monitor. Typically,
100 it's used to boot another kernel image, so it's not much
101 different from reboot(8). Therefore, we don't need to
102 spin down the disk in this case, especially since Alpha
103 firmware doesn't handle disks in standby mode properly.
104 On the other hand, it's reasonably safe to turn the power
105 off when the shutdown process reaches the firmware prompt,
106 as the firmware initialization takes rather long time -
107 at least 10 seconds, which should be sufficient for
108 the disk to expire its write cache. */
109 if (system_state != SYSTEM_POWER_OFF) {
110#else
111 if (system_state == SYSTEM_RESTART) {
112#endif
113 ide_disk_flush(drive);
114 return;
115 }
116
117 printk(KERN_INFO "Shutdown: %s\n", drive->name);
118
119 drive->gendev.bus->suspend(&drive->gendev, PMSG_SUSPEND);
120}
121
122static ide_driver_t ide_gd_driver = {
123 .gen_driver = {
124 .owner = THIS_MODULE,
125 .name = "ide-disk",
126 .bus = &ide_bus_type,
127 },
128 .probe = ide_gd_probe,
129 .remove = ide_gd_remove,
130 .resume = ide_gd_resume,
131 .shutdown = ide_gd_shutdown,
132 .version = IDE_GD_VERSION,
133 .do_request = ide_do_rw_disk,
134 .end_request = ide_end_request,
135 .error = __ide_error,
136#ifdef CONFIG_IDE_PROC_FS
137 .proc = ide_disk_proc,
138 .settings = ide_disk_settings,
139#endif
140};
141
142static int ide_gd_open(struct inode *inode, struct file *filp)
143{
144 struct gendisk *disk = inode->i_bdev->bd_disk;
145 struct ide_disk_obj *idkp;
146 ide_drive_t *drive;
147
148 idkp = ide_disk_get(disk);
149 if (idkp == NULL)
150 return -ENXIO;
151
152 drive = idkp->drive;
153
154 idkp->openers++;
155
156 if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) {
157 /*
158 * Ignore the return code from door_lock,
159 * since the open() has already succeeded,
160 * and the door_lock is irrelevant at this point.
161 */
162 ide_disk_set_doorlock(drive, 1);
163 check_disk_change(inode->i_bdev);
164 }
165 return 0;
166}
167
168static int ide_gd_release(struct inode *inode, struct file *filp)
169{
170 struct gendisk *disk = inode->i_bdev->bd_disk;
171 struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj);
172 ide_drive_t *drive = idkp->drive;
173
174 if (idkp->openers == 1)
175 ide_disk_flush(drive);
176
177 if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1)
178 ide_disk_set_doorlock(drive, 0);
179
180 idkp->openers--;
181
182 ide_disk_put(idkp);
183
184 return 0;
185}
186
187static int ide_gd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
188{
189 struct ide_disk_obj *idkp = ide_drv_g(bdev->bd_disk, ide_disk_obj);
190 ide_drive_t *drive = idkp->drive;
191
192 geo->heads = drive->bios_head;
193 geo->sectors = drive->bios_sect;
194 geo->cylinders = (u16)drive->bios_cyl; /* truncate */
195 return 0;
196}
197
198static int ide_gd_media_changed(struct gendisk *disk)
199{
200 struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj);
201 ide_drive_t *drive = idkp->drive;
202
203 /* do not scan partitions twice if this is a removable device */
204 if (drive->dev_flags & IDE_DFLAG_ATTACH) {
205 drive->dev_flags &= ~IDE_DFLAG_ATTACH;
206 return 0;
207 }
208
209 /* if removable, always assume it was changed */
210 return !!(drive->dev_flags & IDE_DFLAG_REMOVABLE);
211}
212
213static int ide_gd_revalidate_disk(struct gendisk *disk)
214{
215 struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj);
216 set_capacity(disk, ide_gd_capacity(idkp->drive));
217 return 0;
218}
219
220static struct block_device_operations ide_gd_ops = {
221 .owner = THIS_MODULE,
222 .open = ide_gd_open,
223 .release = ide_gd_release,
224 .ioctl = ide_disk_ioctl,
225 .getgeo = ide_gd_getgeo,
226 .media_changed = ide_gd_media_changed,
227 .revalidate_disk = ide_gd_revalidate_disk
228};
229
230static int ide_gd_probe(ide_drive_t *drive)
231{
232 struct ide_disk_obj *idkp;
233 struct gendisk *g;
234
235 /* strstr("foo", "") is non-NULL */
236 if (!strstr("ide-disk", drive->driver_req))
237 goto failed;
238
239 if (drive->media != ide_disk)
240 goto failed;
241
242 idkp = kzalloc(sizeof(*idkp), GFP_KERNEL);
243 if (!idkp)
244 goto failed;
245
246 g = alloc_disk_node(IDE_DISK_MINORS, hwif_to_node(drive->hwif));
247 if (!g)
248 goto out_free_idkp;
249
250 ide_init_disk(g, drive);
251
252 kref_init(&idkp->kref);
253
254 idkp->drive = drive;
255 idkp->driver = &ide_gd_driver;
256 idkp->disk = g;
257
258 g->private_data = &idkp->driver;
259
260 drive->driver_data = idkp;
261
262 ide_disk_setup(drive);
263
264 set_capacity(g, ide_gd_capacity(drive));
265
266 g->minors = IDE_DISK_MINORS;
267 g->driverfs_dev = &drive->gendev;
268 g->flags |= GENHD_FL_EXT_DEVT;
269 if (drive->dev_flags & IDE_DFLAG_REMOVABLE)
270 g->flags = GENHD_FL_REMOVABLE;
271 g->fops = &ide_gd_ops;
272 add_disk(g);
273 return 0;
274
275out_free_idkp:
276 kfree(idkp);
277failed:
278 return -ENODEV;
279}
280
281static int __init ide_gd_init(void)
282{
283 return driver_register(&ide_gd_driver.gen_driver);
284}
285
286static void __exit ide_gd_exit(void)
287{
288 driver_unregister(&ide_gd_driver.gen_driver);
289}
290
291MODULE_ALIAS("ide:*m-disk*");
292MODULE_ALIAS("ide-disk");
293module_init(ide_gd_init);
294module_exit(ide_gd_exit);
295MODULE_LICENSE("GPL");
296MODULE_DESCRIPTION("ATA DISK Driver");