| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 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> | 
| Bruno Prémont | b0aedb0 | 2009-04-22 20:33:41 +0200 | [diff] [blame] | 10 | #include <linux/dmi.h> | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 11 |  | 
|  | 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 Zolnierkiewicz | 806f80a | 2008-10-17 18:09:14 +0200 | [diff] [blame] | 19 | #include "ide-floppy.h" | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 20 |  | 
|  | 21 | #define IDE_GD_VERSION	"1.18" | 
|  | 22 |  | 
| Bartlomiej Zolnierkiewicz | 806f80a | 2008-10-17 18:09:14 +0200 | [diff] [blame] | 23 | /* module parameters */ | 
|  | 24 | static unsigned long debug_mask; | 
|  | 25 | module_param(debug_mask, ulong, 0644); | 
|  | 26 |  | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 27 | static DEFINE_MUTEX(ide_disk_ref_mutex); | 
|  | 28 |  | 
| Bartlomiej Zolnierkiewicz | 8fed436 | 2009-02-25 20:28:24 +0100 | [diff] [blame] | 29 | static void ide_disk_release(struct device *); | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 30 |  | 
|  | 31 | static 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 Zolnierkiewicz | 8fed436 | 2009-02-25 20:28:24 +0100 | [diff] [blame] | 41 | get_device(&idkp->dev); | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 42 | } | 
|  | 43 | mutex_unlock(&ide_disk_ref_mutex); | 
|  | 44 | return idkp; | 
|  | 45 | } | 
|  | 46 |  | 
|  | 47 | static 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 Zolnierkiewicz | 8fed436 | 2009-02-25 20:28:24 +0100 | [diff] [blame] | 52 | put_device(&idkp->dev); | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 53 | ide_device_put(drive); | 
|  | 54 | mutex_unlock(&ide_disk_ref_mutex); | 
|  | 55 | } | 
|  | 56 |  | 
|  | 57 | sector_t ide_gd_capacity(ide_drive_t *drive) | 
|  | 58 | { | 
|  | 59 | return drive->capacity64; | 
|  | 60 | } | 
|  | 61 |  | 
|  | 62 | static int ide_gd_probe(ide_drive_t *); | 
|  | 63 |  | 
|  | 64 | static 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 Zolnierkiewicz | 8fed436 | 2009-02-25 20:28:24 +0100 | [diff] [blame] | 70 | device_del(&idkp->dev); | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 71 | del_gendisk(g); | 
| Bartlomiej Zolnierkiewicz | 806f80a | 2008-10-17 18:09:14 +0200 | [diff] [blame] | 72 | drive->disk_ops->flush(drive); | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 73 |  | 
| Bartlomiej Zolnierkiewicz | 8fed436 | 2009-02-25 20:28:24 +0100 | [diff] [blame] | 74 | mutex_lock(&ide_disk_ref_mutex); | 
|  | 75 | put_device(&idkp->dev); | 
|  | 76 | mutex_unlock(&ide_disk_ref_mutex); | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 77 | } | 
|  | 78 |  | 
| Bartlomiej Zolnierkiewicz | 8fed436 | 2009-02-25 20:28:24 +0100 | [diff] [blame] | 79 | static void ide_disk_release(struct device *dev) | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 80 | { | 
| Bartlomiej Zolnierkiewicz | 8fed436 | 2009-02-25 20:28:24 +0100 | [diff] [blame] | 81 | struct ide_disk_obj *idkp = to_ide_drv(dev, ide_disk_obj); | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 82 | ide_drive_t *drive = idkp->drive; | 
|  | 83 | struct gendisk *g = idkp->disk; | 
|  | 84 |  | 
| Bartlomiej Zolnierkiewicz | 806f80a | 2008-10-17 18:09:14 +0200 | [diff] [blame] | 85 | drive->disk_ops = NULL; | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 86 | 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 | */ | 
|  | 97 | static void ide_gd_resume(ide_drive_t *drive) | 
|  | 98 | { | 
|  | 99 | if (ata_id_hpa_enabled(drive->id)) | 
| Bartlomiej Zolnierkiewicz | 806f80a | 2008-10-17 18:09:14 +0200 | [diff] [blame] | 100 | (void)drive->disk_ops->get_capacity(drive); | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 101 | } | 
|  | 102 |  | 
| Bruno Prémont | b0aedb0 | 2009-04-22 20:33:41 +0200 | [diff] [blame] | 103 | static 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 Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 116 | static 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émont | b0aedb0 | 2009-04-22 20:33:41 +0200 | [diff] [blame] | 132 | if (system_state == SYSTEM_RESTART && | 
|  | 133 | !dmi_check_system(ide_coldreboot_table)) { | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 134 | #endif | 
| Bartlomiej Zolnierkiewicz | 806f80a | 2008-10-17 18:09:14 +0200 | [diff] [blame] | 135 | drive->disk_ops->flush(drive); | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 136 | 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 Zolnierkiewicz | 79cb380 | 2008-10-17 18:09:13 +0200 | [diff] [blame] | 144 | #ifdef CONFIG_IDE_PROC_FS | 
|  | 145 | static ide_proc_entry_t *ide_disk_proc_entries(ide_drive_t *drive) | 
|  | 146 | { | 
| Bartlomiej Zolnierkiewicz | 806f80a | 2008-10-17 18:09:14 +0200 | [diff] [blame] | 147 | return (drive->media == ide_disk) ? ide_disk_proc : ide_floppy_proc; | 
| Bartlomiej Zolnierkiewicz | 79cb380 | 2008-10-17 18:09:13 +0200 | [diff] [blame] | 148 | } | 
|  | 149 |  | 
|  | 150 | static const struct ide_proc_devset *ide_disk_proc_devsets(ide_drive_t *drive) | 
|  | 151 | { | 
| Bartlomiej Zolnierkiewicz | 806f80a | 2008-10-17 18:09:14 +0200 | [diff] [blame] | 152 | return (drive->media == ide_disk) ? ide_disk_settings | 
|  | 153 | : ide_floppy_settings; | 
| Bartlomiej Zolnierkiewicz | 79cb380 | 2008-10-17 18:09:13 +0200 | [diff] [blame] | 154 | } | 
|  | 155 | #endif | 
|  | 156 |  | 
| Bartlomiej Zolnierkiewicz | 806f80a | 2008-10-17 18:09:14 +0200 | [diff] [blame] | 157 | static 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 Zolnierkiewicz | 7f3c868 | 2009-01-06 17:20:53 +0100 | [diff] [blame] | 163 | static struct ide_driver ide_gd_driver = { | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 164 | .gen_driver = { | 
|  | 165 | .owner		= THIS_MODULE, | 
| Bartlomiej Zolnierkiewicz | 806f80a | 2008-10-17 18:09:14 +0200 | [diff] [blame] | 166 | .name		= "ide-gd", | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 167 | .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 Zolnierkiewicz | 806f80a | 2008-10-17 18:09:14 +0200 | [diff] [blame] | 174 | .do_request		= ide_gd_do_request, | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 175 | #ifdef CONFIG_IDE_PROC_FS | 
| Bartlomiej Zolnierkiewicz | 79cb380 | 2008-10-17 18:09:13 +0200 | [diff] [blame] | 176 | .proc_entries		= ide_disk_proc_entries, | 
|  | 177 | .proc_devsets		= ide_disk_proc_devsets, | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 178 | #endif | 
|  | 179 | }; | 
|  | 180 |  | 
| Al Viro | b2f21e0 | 2008-10-16 10:34:00 -0400 | [diff] [blame] | 181 | static int ide_gd_open(struct block_device *bdev, fmode_t mode) | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 182 | { | 
| Al Viro | b2f21e0 | 2008-10-16 10:34:00 -0400 | [diff] [blame] | 183 | struct gendisk *disk = bdev->bd_disk; | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 184 | struct ide_disk_obj *idkp; | 
|  | 185 | ide_drive_t *drive; | 
| Bartlomiej Zolnierkiewicz | 806f80a | 2008-10-17 18:09:14 +0200 | [diff] [blame] | 186 | int ret = 0; | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 187 |  | 
|  | 188 | idkp = ide_disk_get(disk); | 
|  | 189 | if (idkp == NULL) | 
|  | 190 | return -ENXIO; | 
|  | 191 |  | 
|  | 192 | drive = idkp->drive; | 
|  | 193 |  | 
| Borislav Petkov | 088b1b8 | 2009-01-02 13:34:47 +0100 | [diff] [blame] | 194 | ide_debug_log(IDE_DBG_FUNC, "enter"); | 
| Bartlomiej Zolnierkiewicz | 806f80a | 2008-10-17 18:09:14 +0200 | [diff] [blame] | 195 |  | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 196 | idkp->openers++; | 
|  | 197 |  | 
|  | 198 | if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) { | 
| Bartlomiej Zolnierkiewicz | 806f80a | 2008-10-17 18:09:14 +0200 | [diff] [blame] | 199 | 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 Viro | b2f21e0 | 2008-10-16 10:34:00 -0400 | [diff] [blame] | 209 | if (ret && (mode & FMODE_NDELAY) == 0) { | 
| Bartlomiej Zolnierkiewicz | 806f80a | 2008-10-17 18:09:14 +0200 | [diff] [blame] | 210 | ret = -EIO; | 
|  | 211 | goto out_put_idkp; | 
|  | 212 | } | 
|  | 213 |  | 
| Al Viro | b2f21e0 | 2008-10-16 10:34:00 -0400 | [diff] [blame] | 214 | if ((drive->dev_flags & IDE_DFLAG_WP) && (mode & FMODE_WRITE)) { | 
| Bartlomiej Zolnierkiewicz | 806f80a | 2008-10-17 18:09:14 +0200 | [diff] [blame] | 215 | ret = -EROFS; | 
|  | 216 | goto out_put_idkp; | 
|  | 217 | } | 
|  | 218 |  | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 219 | /* | 
|  | 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 Zolnierkiewicz | 806f80a | 2008-10-17 18:09:14 +0200 | [diff] [blame] | 224 | drive->disk_ops->set_doorlock(drive, disk, 1); | 
| Bartlomiej Zolnierkiewicz | cedd120 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 225 | drive->dev_flags |= IDE_DFLAG_MEDIA_CHANGED; | 
| Al Viro | b2f21e0 | 2008-10-16 10:34:00 -0400 | [diff] [blame] | 226 | check_disk_change(bdev); | 
| Bartlomiej Zolnierkiewicz | 806f80a | 2008-10-17 18:09:14 +0200 | [diff] [blame] | 227 | } else if (drive->dev_flags & IDE_DFLAG_FORMAT_IN_PROGRESS) { | 
|  | 228 | ret = -EBUSY; | 
|  | 229 | goto out_put_idkp; | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 230 | } | 
|  | 231 | return 0; | 
| Bartlomiej Zolnierkiewicz | 806f80a | 2008-10-17 18:09:14 +0200 | [diff] [blame] | 232 |  | 
|  | 233 | out_put_idkp: | 
|  | 234 | idkp->openers--; | 
|  | 235 | ide_disk_put(idkp); | 
|  | 236 | return ret; | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 237 | } | 
|  | 238 |  | 
| Al Viro | b2f21e0 | 2008-10-16 10:34:00 -0400 | [diff] [blame] | 239 | static int ide_gd_release(struct gendisk *disk, fmode_t mode) | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 240 | { | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 241 | struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj); | 
|  | 242 | ide_drive_t *drive = idkp->drive; | 
|  | 243 |  | 
| Borislav Petkov | 088b1b8 | 2009-01-02 13:34:47 +0100 | [diff] [blame] | 244 | ide_debug_log(IDE_DBG_FUNC, "enter"); | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 245 |  | 
| Bartlomiej Zolnierkiewicz | 806f80a | 2008-10-17 18:09:14 +0200 | [diff] [blame] | 246 | 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 Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 253 |  | 
|  | 254 | idkp->openers--; | 
|  | 255 |  | 
|  | 256 | ide_disk_put(idkp); | 
|  | 257 |  | 
|  | 258 | return 0; | 
|  | 259 | } | 
|  | 260 |  | 
|  | 261 | static 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 |  | 
|  | 272 | static 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 Zolnierkiewicz | cedd120 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 276 | int ret; | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 277 |  | 
|  | 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 Zolnierkiewicz | cedd120 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 284 | ret = !!(drive->dev_flags & IDE_DFLAG_MEDIA_CHANGED); | 
|  | 285 | drive->dev_flags &= ~IDE_DFLAG_MEDIA_CHANGED; | 
|  | 286 |  | 
|  | 287 | return ret; | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 288 | } | 
|  | 289 |  | 
| Bartlomiej Zolnierkiewicz | e957b60 | 2009-06-07 13:52:52 +0200 | [diff] [blame] | 290 | static unsigned long long ide_gd_set_capacity(struct gendisk *disk, | 
|  | 291 | unsigned long long capacity) | 
|  | 292 | { | 
|  | 293 | struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj); | 
|  | 294 | ide_drive_t *drive = idkp->drive; | 
|  | 295 | const struct ide_disk_ops *disk_ops = drive->disk_ops; | 
|  | 296 |  | 
|  | 297 | if (disk_ops->set_capacity) | 
|  | 298 | return disk_ops->set_capacity(drive, capacity); | 
|  | 299 |  | 
|  | 300 | return drive->capacity64; | 
|  | 301 | } | 
|  | 302 |  | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 303 | static int ide_gd_revalidate_disk(struct gendisk *disk) | 
|  | 304 | { | 
|  | 305 | struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj); | 
| Borislav Petkov | 52ebb43 | 2008-11-02 21:40:10 +0100 | [diff] [blame] | 306 | ide_drive_t *drive = idkp->drive; | 
|  | 307 |  | 
|  | 308 | if (ide_gd_media_changed(disk)) | 
|  | 309 | drive->disk_ops->get_capacity(drive); | 
|  | 310 |  | 
|  | 311 | set_capacity(disk, ide_gd_capacity(drive)); | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 312 | return 0; | 
|  | 313 | } | 
|  | 314 |  | 
| Al Viro | b2f21e0 | 2008-10-16 10:34:00 -0400 | [diff] [blame] | 315 | static int ide_gd_ioctl(struct block_device *bdev, fmode_t mode, | 
| Bartlomiej Zolnierkiewicz | 806f80a | 2008-10-17 18:09:14 +0200 | [diff] [blame] | 316 | unsigned int cmd, unsigned long arg) | 
|  | 317 | { | 
| Bartlomiej Zolnierkiewicz | 806f80a | 2008-10-17 18:09:14 +0200 | [diff] [blame] | 318 | struct ide_disk_obj *idkp = ide_drv_g(bdev->bd_disk, ide_disk_obj); | 
|  | 319 | ide_drive_t *drive = idkp->drive; | 
|  | 320 |  | 
| Al Viro | b2f21e0 | 2008-10-16 10:34:00 -0400 | [diff] [blame] | 321 | return drive->disk_ops->ioctl(drive, bdev, mode, cmd, arg); | 
| Bartlomiej Zolnierkiewicz | 806f80a | 2008-10-17 18:09:14 +0200 | [diff] [blame] | 322 | } | 
|  | 323 |  | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 324 | static struct block_device_operations ide_gd_ops = { | 
|  | 325 | .owner			= THIS_MODULE, | 
| Al Viro | b2f21e0 | 2008-10-16 10:34:00 -0400 | [diff] [blame] | 326 | .open			= ide_gd_open, | 
|  | 327 | .release		= ide_gd_release, | 
|  | 328 | .locked_ioctl		= ide_gd_ioctl, | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 329 | .getgeo			= ide_gd_getgeo, | 
|  | 330 | .media_changed		= ide_gd_media_changed, | 
| Bartlomiej Zolnierkiewicz | e957b60 | 2009-06-07 13:52:52 +0200 | [diff] [blame] | 331 | .set_capacity		= ide_gd_set_capacity, | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 332 | .revalidate_disk	= ide_gd_revalidate_disk | 
|  | 333 | }; | 
|  | 334 |  | 
|  | 335 | static int ide_gd_probe(ide_drive_t *drive) | 
|  | 336 | { | 
| Bartlomiej Zolnierkiewicz | 806f80a | 2008-10-17 18:09:14 +0200 | [diff] [blame] | 337 | const struct ide_disk_ops *disk_ops = NULL; | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 338 | struct ide_disk_obj *idkp; | 
|  | 339 | struct gendisk *g; | 
|  | 340 |  | 
|  | 341 | /* strstr("foo", "") is non-NULL */ | 
| Bartlomiej Zolnierkiewicz | 806f80a | 2008-10-17 18:09:14 +0200 | [diff] [blame] | 342 | if (!strstr("ide-gd", drive->driver_req)) | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 343 | goto failed; | 
|  | 344 |  | 
| Bartlomiej Zolnierkiewicz | 806f80a | 2008-10-17 18:09:14 +0200 | [diff] [blame] | 345 | #ifdef CONFIG_IDE_GD_ATA | 
|  | 346 | if (drive->media == ide_disk) | 
|  | 347 | disk_ops = &ide_ata_disk_ops; | 
|  | 348 | #endif | 
|  | 349 | #ifdef CONFIG_IDE_GD_ATAPI | 
|  | 350 | if (drive->media == ide_floppy) | 
|  | 351 | disk_ops = &ide_atapi_disk_ops; | 
|  | 352 | #endif | 
|  | 353 | if (disk_ops == NULL) | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 354 | goto failed; | 
|  | 355 |  | 
| Bartlomiej Zolnierkiewicz | 806f80a | 2008-10-17 18:09:14 +0200 | [diff] [blame] | 356 | if (disk_ops->check(drive, DRV_NAME) == 0) { | 
|  | 357 | printk(KERN_ERR PFX "%s: not supported by this driver\n", | 
|  | 358 | drive->name); | 
|  | 359 | goto failed; | 
|  | 360 | } | 
|  | 361 |  | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 362 | idkp = kzalloc(sizeof(*idkp), GFP_KERNEL); | 
| Bartlomiej Zolnierkiewicz | 806f80a | 2008-10-17 18:09:14 +0200 | [diff] [blame] | 363 | if (!idkp) { | 
|  | 364 | printk(KERN_ERR PFX "%s: can't allocate a disk structure\n", | 
|  | 365 | drive->name); | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 366 | goto failed; | 
| Bartlomiej Zolnierkiewicz | 806f80a | 2008-10-17 18:09:14 +0200 | [diff] [blame] | 367 | } | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 368 |  | 
|  | 369 | g = alloc_disk_node(IDE_DISK_MINORS, hwif_to_node(drive->hwif)); | 
|  | 370 | if (!g) | 
|  | 371 | goto out_free_idkp; | 
|  | 372 |  | 
|  | 373 | ide_init_disk(g, drive); | 
|  | 374 |  | 
| Bartlomiej Zolnierkiewicz | 8fed436 | 2009-02-25 20:28:24 +0100 | [diff] [blame] | 375 | idkp->dev.parent = &drive->gendev; | 
|  | 376 | idkp->dev.release = ide_disk_release; | 
|  | 377 | dev_set_name(&idkp->dev, dev_name(&drive->gendev)); | 
|  | 378 |  | 
|  | 379 | if (device_register(&idkp->dev)) | 
|  | 380 | goto out_free_disk; | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 381 |  | 
|  | 382 | idkp->drive = drive; | 
|  | 383 | idkp->driver = &ide_gd_driver; | 
|  | 384 | idkp->disk = g; | 
|  | 385 |  | 
|  | 386 | g->private_data = &idkp->driver; | 
|  | 387 |  | 
|  | 388 | drive->driver_data = idkp; | 
| Bartlomiej Zolnierkiewicz | 806f80a | 2008-10-17 18:09:14 +0200 | [diff] [blame] | 389 | drive->debug_mask = debug_mask; | 
|  | 390 | drive->disk_ops = disk_ops; | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 391 |  | 
| Bartlomiej Zolnierkiewicz | 806f80a | 2008-10-17 18:09:14 +0200 | [diff] [blame] | 392 | disk_ops->setup(drive); | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 393 |  | 
|  | 394 | set_capacity(g, ide_gd_capacity(drive)); | 
|  | 395 |  | 
|  | 396 | g->minors = IDE_DISK_MINORS; | 
|  | 397 | g->driverfs_dev = &drive->gendev; | 
|  | 398 | g->flags |= GENHD_FL_EXT_DEVT; | 
|  | 399 | if (drive->dev_flags & IDE_DFLAG_REMOVABLE) | 
|  | 400 | g->flags = GENHD_FL_REMOVABLE; | 
|  | 401 | g->fops = &ide_gd_ops; | 
|  | 402 | add_disk(g); | 
|  | 403 | return 0; | 
|  | 404 |  | 
| Bartlomiej Zolnierkiewicz | 8fed436 | 2009-02-25 20:28:24 +0100 | [diff] [blame] | 405 | out_free_disk: | 
|  | 406 | put_disk(g); | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 407 | out_free_idkp: | 
|  | 408 | kfree(idkp); | 
|  | 409 | failed: | 
|  | 410 | return -ENODEV; | 
|  | 411 | } | 
|  | 412 |  | 
|  | 413 | static int __init ide_gd_init(void) | 
|  | 414 | { | 
| Bartlomiej Zolnierkiewicz | 806f80a | 2008-10-17 18:09:14 +0200 | [diff] [blame] | 415 | printk(KERN_INFO DRV_NAME " driver " IDE_GD_VERSION "\n"); | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 416 | return driver_register(&ide_gd_driver.gen_driver); | 
|  | 417 | } | 
|  | 418 |  | 
|  | 419 | static void __exit ide_gd_exit(void) | 
|  | 420 | { | 
|  | 421 | driver_unregister(&ide_gd_driver.gen_driver); | 
|  | 422 | } | 
|  | 423 |  | 
|  | 424 | MODULE_ALIAS("ide:*m-disk*"); | 
|  | 425 | MODULE_ALIAS("ide-disk"); | 
| Bartlomiej Zolnierkiewicz | 806f80a | 2008-10-17 18:09:14 +0200 | [diff] [blame] | 426 | MODULE_ALIAS("ide:*m-floppy*"); | 
|  | 427 | MODULE_ALIAS("ide-floppy"); | 
| Bartlomiej Zolnierkiewicz | 5fef0e5 | 2008-10-17 18:09:12 +0200 | [diff] [blame] | 428 | module_init(ide_gd_init); | 
|  | 429 | module_exit(ide_gd_exit); | 
|  | 430 | MODULE_LICENSE("GPL"); | 
| Bartlomiej Zolnierkiewicz | 806f80a | 2008-10-17 18:09:14 +0200 | [diff] [blame] | 431 | MODULE_DESCRIPTION("generic ATA/ATAPI disk driver"); |