ide: allow device drivers to specify per-device type /proc settings
[deliverable/linux.git] / drivers / ide / ide-gd.c
CommitLineData
5fef0e5c
BZ
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
79cb3803
BZ
122#ifdef CONFIG_IDE_PROC_FS
123static ide_proc_entry_t *ide_disk_proc_entries(ide_drive_t *drive)
124{
125 return ide_disk_proc;
126}
127
128static const struct ide_proc_devset *ide_disk_proc_devsets(ide_drive_t *drive)
129{
130 return ide_disk_settings;
131}
132#endif
133
5fef0e5c
BZ
134static ide_driver_t ide_gd_driver = {
135 .gen_driver = {
136 .owner = THIS_MODULE,
137 .name = "ide-disk",
138 .bus = &ide_bus_type,
139 },
140 .probe = ide_gd_probe,
141 .remove = ide_gd_remove,
142 .resume = ide_gd_resume,
143 .shutdown = ide_gd_shutdown,
144 .version = IDE_GD_VERSION,
145 .do_request = ide_do_rw_disk,
146 .end_request = ide_end_request,
147 .error = __ide_error,
148#ifdef CONFIG_IDE_PROC_FS
79cb3803
BZ
149 .proc_entries = ide_disk_proc_entries,
150 .proc_devsets = ide_disk_proc_devsets,
5fef0e5c
BZ
151#endif
152};
153
154static int ide_gd_open(struct inode *inode, struct file *filp)
155{
156 struct gendisk *disk = inode->i_bdev->bd_disk;
157 struct ide_disk_obj *idkp;
158 ide_drive_t *drive;
159
160 idkp = ide_disk_get(disk);
161 if (idkp == NULL)
162 return -ENXIO;
163
164 drive = idkp->drive;
165
166 idkp->openers++;
167
168 if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) {
169 /*
170 * Ignore the return code from door_lock,
171 * since the open() has already succeeded,
172 * and the door_lock is irrelevant at this point.
173 */
174 ide_disk_set_doorlock(drive, 1);
cedd120c 175 drive->dev_flags |= IDE_DFLAG_MEDIA_CHANGED;
5fef0e5c
BZ
176 check_disk_change(inode->i_bdev);
177 }
178 return 0;
179}
180
181static int ide_gd_release(struct inode *inode, struct file *filp)
182{
183 struct gendisk *disk = inode->i_bdev->bd_disk;
184 struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj);
185 ide_drive_t *drive = idkp->drive;
186
187 if (idkp->openers == 1)
188 ide_disk_flush(drive);
189
190 if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1)
191 ide_disk_set_doorlock(drive, 0);
192
193 idkp->openers--;
194
195 ide_disk_put(idkp);
196
197 return 0;
198}
199
200static int ide_gd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
201{
202 struct ide_disk_obj *idkp = ide_drv_g(bdev->bd_disk, ide_disk_obj);
203 ide_drive_t *drive = idkp->drive;
204
205 geo->heads = drive->bios_head;
206 geo->sectors = drive->bios_sect;
207 geo->cylinders = (u16)drive->bios_cyl; /* truncate */
208 return 0;
209}
210
211static int ide_gd_media_changed(struct gendisk *disk)
212{
213 struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj);
214 ide_drive_t *drive = idkp->drive;
cedd120c 215 int ret;
5fef0e5c
BZ
216
217 /* do not scan partitions twice if this is a removable device */
218 if (drive->dev_flags & IDE_DFLAG_ATTACH) {
219 drive->dev_flags &= ~IDE_DFLAG_ATTACH;
220 return 0;
221 }
222
cedd120c
BZ
223 ret = !!(drive->dev_flags & IDE_DFLAG_MEDIA_CHANGED);
224 drive->dev_flags &= ~IDE_DFLAG_MEDIA_CHANGED;
225
226 return ret;
5fef0e5c
BZ
227}
228
229static int ide_gd_revalidate_disk(struct gendisk *disk)
230{
231 struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj);
232 set_capacity(disk, ide_gd_capacity(idkp->drive));
233 return 0;
234}
235
236static struct block_device_operations ide_gd_ops = {
237 .owner = THIS_MODULE,
238 .open = ide_gd_open,
239 .release = ide_gd_release,
240 .ioctl = ide_disk_ioctl,
241 .getgeo = ide_gd_getgeo,
242 .media_changed = ide_gd_media_changed,
243 .revalidate_disk = ide_gd_revalidate_disk
244};
245
246static int ide_gd_probe(ide_drive_t *drive)
247{
248 struct ide_disk_obj *idkp;
249 struct gendisk *g;
250
251 /* strstr("foo", "") is non-NULL */
252 if (!strstr("ide-disk", drive->driver_req))
253 goto failed;
254
255 if (drive->media != ide_disk)
256 goto failed;
257
258 idkp = kzalloc(sizeof(*idkp), GFP_KERNEL);
259 if (!idkp)
260 goto failed;
261
262 g = alloc_disk_node(IDE_DISK_MINORS, hwif_to_node(drive->hwif));
263 if (!g)
264 goto out_free_idkp;
265
266 ide_init_disk(g, drive);
267
268 kref_init(&idkp->kref);
269
270 idkp->drive = drive;
271 idkp->driver = &ide_gd_driver;
272 idkp->disk = g;
273
274 g->private_data = &idkp->driver;
275
276 drive->driver_data = idkp;
277
278 ide_disk_setup(drive);
279
280 set_capacity(g, ide_gd_capacity(drive));
281
282 g->minors = IDE_DISK_MINORS;
283 g->driverfs_dev = &drive->gendev;
284 g->flags |= GENHD_FL_EXT_DEVT;
285 if (drive->dev_flags & IDE_DFLAG_REMOVABLE)
286 g->flags = GENHD_FL_REMOVABLE;
287 g->fops = &ide_gd_ops;
288 add_disk(g);
289 return 0;
290
291out_free_idkp:
292 kfree(idkp);
293failed:
294 return -ENODEV;
295}
296
297static int __init ide_gd_init(void)
298{
299 return driver_register(&ide_gd_driver.gen_driver);
300}
301
302static void __exit ide_gd_exit(void)
303{
304 driver_unregister(&ide_gd_driver.gen_driver);
305}
306
307MODULE_ALIAS("ide:*m-disk*");
308MODULE_ALIAS("ide-disk");
309module_init(ide_gd_init);
310module_exit(ide_gd_exit);
311MODULE_LICENSE("GPL");
312MODULE_DESCRIPTION("ATA DISK Driver");
This page took 0.040304 seconds and 5 git commands to generate.