blob: 4b6b71e2cdf5b6cc3f1fe1288e0f99408d5a3742 [file] [log] [blame]
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +02001#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>
Bruno Prémontb0aedb02009-04-22 20:33:41 +020010#include <linux/dmi.h>
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +020011
12#if !defined(CONFIG_DEBUG_BLOCK_EXT_DEVT)
13#define IDE_DISK_MINORS (1 << PARTN_BITS)
14#else
15#define IDE_DISK_MINORS 0
16#endif
17
18#include "ide-disk.h"
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +020019#include "ide-floppy.h"
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +020020
21#define IDE_GD_VERSION "1.18"
22
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +020023/* module parameters */
24static unsigned long debug_mask;
25module_param(debug_mask, ulong, 0644);
26
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +020027static DEFINE_MUTEX(ide_disk_ref_mutex);
28
Bartlomiej Zolnierkiewicz8fed4362009-02-25 20:28:24 +010029static void ide_disk_release(struct device *);
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +020030
31static struct ide_disk_obj *ide_disk_get(struct gendisk *disk)
32{
33 struct ide_disk_obj *idkp = NULL;
34
35 mutex_lock(&ide_disk_ref_mutex);
36 idkp = ide_drv_g(disk, ide_disk_obj);
37 if (idkp) {
38 if (ide_device_get(idkp->drive))
39 idkp = NULL;
40 else
Bartlomiej Zolnierkiewicz8fed4362009-02-25 20:28:24 +010041 get_device(&idkp->dev);
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +020042 }
43 mutex_unlock(&ide_disk_ref_mutex);
44 return idkp;
45}
46
47static void ide_disk_put(struct ide_disk_obj *idkp)
48{
49 ide_drive_t *drive = idkp->drive;
50
51 mutex_lock(&ide_disk_ref_mutex);
Bartlomiej Zolnierkiewicz8fed4362009-02-25 20:28:24 +010052 put_device(&idkp->dev);
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +020053 ide_device_put(drive);
54 mutex_unlock(&ide_disk_ref_mutex);
55}
56
57sector_t ide_gd_capacity(ide_drive_t *drive)
58{
59 return drive->capacity64;
60}
61
62static int ide_gd_probe(ide_drive_t *);
63
64static void ide_gd_remove(ide_drive_t *drive)
65{
66 struct ide_disk_obj *idkp = drive->driver_data;
67 struct gendisk *g = idkp->disk;
68
69 ide_proc_unregister_driver(drive, idkp->driver);
Bartlomiej Zolnierkiewicz8fed4362009-02-25 20:28:24 +010070 device_del(&idkp->dev);
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +020071 del_gendisk(g);
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +020072 drive->disk_ops->flush(drive);
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +020073
Bartlomiej Zolnierkiewicz8fed4362009-02-25 20:28:24 +010074 mutex_lock(&ide_disk_ref_mutex);
75 put_device(&idkp->dev);
76 mutex_unlock(&ide_disk_ref_mutex);
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +020077}
78
Bartlomiej Zolnierkiewicz8fed4362009-02-25 20:28:24 +010079static void ide_disk_release(struct device *dev)
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +020080{
Bartlomiej Zolnierkiewicz8fed4362009-02-25 20:28:24 +010081 struct ide_disk_obj *idkp = to_ide_drv(dev, ide_disk_obj);
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +020082 ide_drive_t *drive = idkp->drive;
83 struct gendisk *g = idkp->disk;
84
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +020085 drive->disk_ops = NULL;
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +020086 drive->driver_data = NULL;
87 g->private_data = NULL;
88 put_disk(g);
89 kfree(idkp);
90}
91
92/*
93 * On HPA drives the capacity needs to be
94 * reinitilized on resume otherwise the disk
95 * can not be used and a hard reset is required
96 */
97static void ide_gd_resume(ide_drive_t *drive)
98{
99 if (ata_id_hpa_enabled(drive->id))
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200100 (void)drive->disk_ops->get_capacity(drive);
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200101}
102
Bruno Prémontb0aedb02009-04-22 20:33:41 +0200103static const struct dmi_system_id ide_coldreboot_table[] = {
104 {
105 /* Acer TravelMate 66x cuts power during reboot */
106 .ident = "Acer TravelMate 660",
107 .matches = {
108 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
109 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 660"),
110 },
111 },
112
113 { } /* terminate list */
114};
115
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200116static void ide_gd_shutdown(ide_drive_t *drive)
117{
118#ifdef CONFIG_ALPHA
119 /* On Alpha, halt(8) doesn't actually turn the machine off,
120 it puts you into the sort of firmware monitor. Typically,
121 it's used to boot another kernel image, so it's not much
122 different from reboot(8). Therefore, we don't need to
123 spin down the disk in this case, especially since Alpha
124 firmware doesn't handle disks in standby mode properly.
125 On the other hand, it's reasonably safe to turn the power
126 off when the shutdown process reaches the firmware prompt,
127 as the firmware initialization takes rather long time -
128 at least 10 seconds, which should be sufficient for
129 the disk to expire its write cache. */
130 if (system_state != SYSTEM_POWER_OFF) {
131#else
Bruno Prémontb0aedb02009-04-22 20:33:41 +0200132 if (system_state == SYSTEM_RESTART &&
133 !dmi_check_system(ide_coldreboot_table)) {
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200134#endif
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200135 drive->disk_ops->flush(drive);
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200136 return;
137 }
138
139 printk(KERN_INFO "Shutdown: %s\n", drive->name);
140
141 drive->gendev.bus->suspend(&drive->gendev, PMSG_SUSPEND);
142}
143
Bartlomiej Zolnierkiewicz79cb3802008-10-17 18:09:13 +0200144#ifdef CONFIG_IDE_PROC_FS
145static ide_proc_entry_t *ide_disk_proc_entries(ide_drive_t *drive)
146{
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200147 return (drive->media == ide_disk) ? ide_disk_proc : ide_floppy_proc;
Bartlomiej Zolnierkiewicz79cb3802008-10-17 18:09:13 +0200148}
149
150static const struct ide_proc_devset *ide_disk_proc_devsets(ide_drive_t *drive)
151{
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200152 return (drive->media == ide_disk) ? ide_disk_settings
153 : ide_floppy_settings;
Bartlomiej Zolnierkiewicz79cb3802008-10-17 18:09:13 +0200154}
155#endif
156
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200157static ide_startstop_t ide_gd_do_request(ide_drive_t *drive,
158 struct request *rq, sector_t sector)
159{
160 return drive->disk_ops->do_request(drive, rq, sector);
161}
162
Bartlomiej Zolnierkiewicz7f3c8682009-01-06 17:20:53 +0100163static struct ide_driver ide_gd_driver = {
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200164 .gen_driver = {
165 .owner = THIS_MODULE,
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200166 .name = "ide-gd",
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200167 .bus = &ide_bus_type,
168 },
169 .probe = ide_gd_probe,
170 .remove = ide_gd_remove,
171 .resume = ide_gd_resume,
172 .shutdown = ide_gd_shutdown,
173 .version = IDE_GD_VERSION,
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200174 .do_request = ide_gd_do_request,
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200175#ifdef CONFIG_IDE_PROC_FS
Bartlomiej Zolnierkiewicz79cb3802008-10-17 18:09:13 +0200176 .proc_entries = ide_disk_proc_entries,
177 .proc_devsets = ide_disk_proc_devsets,
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200178#endif
179};
180
Al Virob2f21e02008-10-16 10:34:00 -0400181static int ide_gd_open(struct block_device *bdev, fmode_t mode)
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200182{
Al Virob2f21e02008-10-16 10:34:00 -0400183 struct gendisk *disk = bdev->bd_disk;
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200184 struct ide_disk_obj *idkp;
185 ide_drive_t *drive;
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200186 int ret = 0;
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200187
188 idkp = ide_disk_get(disk);
189 if (idkp == NULL)
190 return -ENXIO;
191
192 drive = idkp->drive;
193
Borislav Petkov088b1b82009-01-02 13:34:47 +0100194 ide_debug_log(IDE_DBG_FUNC, "enter");
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200195
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200196 idkp->openers++;
197
198 if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) {
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200199 drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS;
200 /* Just in case */
201
202 ret = drive->disk_ops->init_media(drive, disk);
203
204 /*
205 * Allow O_NDELAY to open a drive without a disk, or with an
206 * unreadable disk, so that we can get the format capacity
207 * of the drive or begin the format - Sam
208 */
Al Virob2f21e02008-10-16 10:34:00 -0400209 if (ret && (mode & FMODE_NDELAY) == 0) {
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200210 ret = -EIO;
211 goto out_put_idkp;
212 }
213
Al Virob2f21e02008-10-16 10:34:00 -0400214 if ((drive->dev_flags & IDE_DFLAG_WP) && (mode & FMODE_WRITE)) {
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200215 ret = -EROFS;
216 goto out_put_idkp;
217 }
218
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200219 /*
220 * Ignore the return code from door_lock,
221 * since the open() has already succeeded,
222 * and the door_lock is irrelevant at this point.
223 */
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200224 drive->disk_ops->set_doorlock(drive, disk, 1);
Bartlomiej Zolnierkiewiczcedd1202008-10-17 18:09:12 +0200225 drive->dev_flags |= IDE_DFLAG_MEDIA_CHANGED;
Al Virob2f21e02008-10-16 10:34:00 -0400226 check_disk_change(bdev);
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200227 } else if (drive->dev_flags & IDE_DFLAG_FORMAT_IN_PROGRESS) {
228 ret = -EBUSY;
229 goto out_put_idkp;
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200230 }
231 return 0;
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200232
233out_put_idkp:
234 idkp->openers--;
235 ide_disk_put(idkp);
236 return ret;
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200237}
238
Al Virob2f21e02008-10-16 10:34:00 -0400239static int ide_gd_release(struct gendisk *disk, fmode_t mode)
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200240{
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200241 struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj);
242 ide_drive_t *drive = idkp->drive;
243
Borislav Petkov088b1b82009-01-02 13:34:47 +0100244 ide_debug_log(IDE_DBG_FUNC, "enter");
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200245
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200246 if (idkp->openers == 1)
247 drive->disk_ops->flush(drive);
248
249 if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) {
250 drive->disk_ops->set_doorlock(drive, disk, 0);
251 drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS;
252 }
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200253
254 idkp->openers--;
255
256 ide_disk_put(idkp);
257
258 return 0;
259}
260
261static int ide_gd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
262{
263 struct ide_disk_obj *idkp = ide_drv_g(bdev->bd_disk, ide_disk_obj);
264 ide_drive_t *drive = idkp->drive;
265
266 geo->heads = drive->bios_head;
267 geo->sectors = drive->bios_sect;
268 geo->cylinders = (u16)drive->bios_cyl; /* truncate */
269 return 0;
270}
271
272static int ide_gd_media_changed(struct gendisk *disk)
273{
274 struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj);
275 ide_drive_t *drive = idkp->drive;
Bartlomiej Zolnierkiewiczcedd1202008-10-17 18:09:12 +0200276 int ret;
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200277
278 /* do not scan partitions twice if this is a removable device */
279 if (drive->dev_flags & IDE_DFLAG_ATTACH) {
280 drive->dev_flags &= ~IDE_DFLAG_ATTACH;
281 return 0;
282 }
283
Bartlomiej Zolnierkiewiczcedd1202008-10-17 18:09:12 +0200284 ret = !!(drive->dev_flags & IDE_DFLAG_MEDIA_CHANGED);
285 drive->dev_flags &= ~IDE_DFLAG_MEDIA_CHANGED;
286
287 return ret;
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200288}
289
290static int ide_gd_revalidate_disk(struct gendisk *disk)
291{
292 struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj);
Borislav Petkov52ebb432008-11-02 21:40:10 +0100293 ide_drive_t *drive = idkp->drive;
294
295 if (ide_gd_media_changed(disk))
296 drive->disk_ops->get_capacity(drive);
297
298 set_capacity(disk, ide_gd_capacity(drive));
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200299 return 0;
300}
301
Al Virob2f21e02008-10-16 10:34:00 -0400302static int ide_gd_ioctl(struct block_device *bdev, fmode_t mode,
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200303 unsigned int cmd, unsigned long arg)
304{
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200305 struct ide_disk_obj *idkp = ide_drv_g(bdev->bd_disk, ide_disk_obj);
306 ide_drive_t *drive = idkp->drive;
307
Al Virob2f21e02008-10-16 10:34:00 -0400308 return drive->disk_ops->ioctl(drive, bdev, mode, cmd, arg);
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200309}
310
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200311static struct block_device_operations ide_gd_ops = {
312 .owner = THIS_MODULE,
Al Virob2f21e02008-10-16 10:34:00 -0400313 .open = ide_gd_open,
314 .release = ide_gd_release,
315 .locked_ioctl = ide_gd_ioctl,
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200316 .getgeo = ide_gd_getgeo,
317 .media_changed = ide_gd_media_changed,
318 .revalidate_disk = ide_gd_revalidate_disk
319};
320
321static int ide_gd_probe(ide_drive_t *drive)
322{
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200323 const struct ide_disk_ops *disk_ops = NULL;
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200324 struct ide_disk_obj *idkp;
325 struct gendisk *g;
326
327 /* strstr("foo", "") is non-NULL */
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200328 if (!strstr("ide-gd", drive->driver_req))
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200329 goto failed;
330
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200331#ifdef CONFIG_IDE_GD_ATA
332 if (drive->media == ide_disk)
333 disk_ops = &ide_ata_disk_ops;
334#endif
335#ifdef CONFIG_IDE_GD_ATAPI
336 if (drive->media == ide_floppy)
337 disk_ops = &ide_atapi_disk_ops;
338#endif
339 if (disk_ops == NULL)
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200340 goto failed;
341
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200342 if (disk_ops->check(drive, DRV_NAME) == 0) {
343 printk(KERN_ERR PFX "%s: not supported by this driver\n",
344 drive->name);
345 goto failed;
346 }
347
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200348 idkp = kzalloc(sizeof(*idkp), GFP_KERNEL);
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200349 if (!idkp) {
350 printk(KERN_ERR PFX "%s: can't allocate a disk structure\n",
351 drive->name);
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200352 goto failed;
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200353 }
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200354
355 g = alloc_disk_node(IDE_DISK_MINORS, hwif_to_node(drive->hwif));
356 if (!g)
357 goto out_free_idkp;
358
359 ide_init_disk(g, drive);
360
Bartlomiej Zolnierkiewicz8fed4362009-02-25 20:28:24 +0100361 idkp->dev.parent = &drive->gendev;
362 idkp->dev.release = ide_disk_release;
363 dev_set_name(&idkp->dev, dev_name(&drive->gendev));
364
365 if (device_register(&idkp->dev))
366 goto out_free_disk;
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200367
368 idkp->drive = drive;
369 idkp->driver = &ide_gd_driver;
370 idkp->disk = g;
371
372 g->private_data = &idkp->driver;
373
374 drive->driver_data = idkp;
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200375 drive->debug_mask = debug_mask;
376 drive->disk_ops = disk_ops;
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200377
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200378 disk_ops->setup(drive);
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200379
380 set_capacity(g, ide_gd_capacity(drive));
381
382 g->minors = IDE_DISK_MINORS;
383 g->driverfs_dev = &drive->gendev;
384 g->flags |= GENHD_FL_EXT_DEVT;
385 if (drive->dev_flags & IDE_DFLAG_REMOVABLE)
386 g->flags = GENHD_FL_REMOVABLE;
387 g->fops = &ide_gd_ops;
388 add_disk(g);
389 return 0;
390
Bartlomiej Zolnierkiewicz8fed4362009-02-25 20:28:24 +0100391out_free_disk:
392 put_disk(g);
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200393out_free_idkp:
394 kfree(idkp);
395failed:
396 return -ENODEV;
397}
398
399static int __init ide_gd_init(void)
400{
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200401 printk(KERN_INFO DRV_NAME " driver " IDE_GD_VERSION "\n");
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200402 return driver_register(&ide_gd_driver.gen_driver);
403}
404
405static void __exit ide_gd_exit(void)
406{
407 driver_unregister(&ide_gd_driver.gen_driver);
408}
409
410MODULE_ALIAS("ide:*m-disk*");
411MODULE_ALIAS("ide-disk");
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200412MODULE_ALIAS("ide:*m-floppy*");
413MODULE_ALIAS("ide-floppy");
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200414module_init(ide_gd_init);
415module_exit(ide_gd_exit);
416MODULE_LICENSE("GPL");
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200417MODULE_DESCRIPTION("generic ATA/ATAPI disk driver");