Blame view
drivers/ide/ide-gd.c
10.8 KB
5fef0e5c0 ide-disk: factor ... |
1 2 3 4 5 6 7 8 9 |
#include <linux/module.h> #include <linux/types.h> #include <linux/string.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/genhd.h> #include <linux/mutex.h> #include <linux/ide.h> #include <linux/hdreg.h> |
b0aedb04e ide: Stop disks o... |
10 |
#include <linux/dmi.h> |
5a0e3ad6a include cleanup: ... |
11 |
#include <linux/slab.h> |
5fef0e5c0 ide-disk: factor ... |
12 13 14 15 16 17 18 19 |
#if !defined(CONFIG_DEBUG_BLOCK_EXT_DEVT) #define IDE_DISK_MINORS (1 << PARTN_BITS) #else #define IDE_DISK_MINORS 0 #endif #include "ide-disk.h" |
806f80a6f ide: add generic ... |
20 |
#include "ide-floppy.h" |
5fef0e5c0 ide-disk: factor ... |
21 22 |
#define IDE_GD_VERSION "1.18" |
806f80a6f ide: add generic ... |
23 |
/* module parameters */ |
2a48fc0ab block: autoconver... |
24 |
static DEFINE_MUTEX(ide_gd_mutex); |
806f80a6f ide: add generic ... |
25 26 |
static unsigned long debug_mask; module_param(debug_mask, ulong, 0644); |
5fef0e5c0 ide-disk: factor ... |
27 |
static DEFINE_MUTEX(ide_disk_ref_mutex); |
8fed43684 ide: fix refcount... |
28 |
static void ide_disk_release(struct device *); |
5fef0e5c0 ide-disk: factor ... |
29 30 31 32 33 34 35 36 37 38 39 |
static struct ide_disk_obj *ide_disk_get(struct gendisk *disk) { struct ide_disk_obj *idkp = NULL; mutex_lock(&ide_disk_ref_mutex); idkp = ide_drv_g(disk, ide_disk_obj); if (idkp) { if (ide_device_get(idkp->drive)) idkp = NULL; else |
8fed43684 ide: fix refcount... |
40 |
get_device(&idkp->dev); |
5fef0e5c0 ide-disk: factor ... |
41 42 43 44 45 46 47 48 49 50 |
} mutex_unlock(&ide_disk_ref_mutex); return idkp; } static void ide_disk_put(struct ide_disk_obj *idkp) { ide_drive_t *drive = idkp->drive; mutex_lock(&ide_disk_ref_mutex); |
8fed43684 ide: fix refcount... |
51 |
put_device(&idkp->dev); |
5fef0e5c0 ide-disk: factor ... |
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
ide_device_put(drive); mutex_unlock(&ide_disk_ref_mutex); } sector_t ide_gd_capacity(ide_drive_t *drive) { return drive->capacity64; } static int ide_gd_probe(ide_drive_t *); static void ide_gd_remove(ide_drive_t *drive) { struct ide_disk_obj *idkp = drive->driver_data; struct gendisk *g = idkp->disk; ide_proc_unregister_driver(drive, idkp->driver); |
8fed43684 ide: fix refcount... |
69 |
device_del(&idkp->dev); |
5fef0e5c0 ide-disk: factor ... |
70 |
del_gendisk(g); |
806f80a6f ide: add generic ... |
71 |
drive->disk_ops->flush(drive); |
5fef0e5c0 ide-disk: factor ... |
72 |
|
8fed43684 ide: fix refcount... |
73 74 75 |
mutex_lock(&ide_disk_ref_mutex); put_device(&idkp->dev); mutex_unlock(&ide_disk_ref_mutex); |
5fef0e5c0 ide-disk: factor ... |
76 |
} |
8fed43684 ide: fix refcount... |
77 |
static void ide_disk_release(struct device *dev) |
5fef0e5c0 ide-disk: factor ... |
78 |
{ |
8fed43684 ide: fix refcount... |
79 |
struct ide_disk_obj *idkp = to_ide_drv(dev, ide_disk_obj); |
5fef0e5c0 ide-disk: factor ... |
80 81 |
ide_drive_t *drive = idkp->drive; struct gendisk *g = idkp->disk; |
806f80a6f ide: add generic ... |
82 |
drive->disk_ops = NULL; |
5fef0e5c0 ide-disk: factor ... |
83 84 85 86 87 88 89 90 |
drive->driver_data = NULL; g->private_data = NULL; put_disk(g); kfree(idkp); } /* * On HPA drives the capacity needs to be |
421f91d21 fix typos concern... |
91 |
* reinitialized on resume otherwise the disk |
5fef0e5c0 ide-disk: factor ... |
92 93 94 95 96 |
* can not be used and a hard reset is required */ static void ide_gd_resume(ide_drive_t *drive) { if (ata_id_hpa_enabled(drive->id)) |
806f80a6f ide: add generic ... |
97 |
(void)drive->disk_ops->get_capacity(drive); |
5fef0e5c0 ide-disk: factor ... |
98 |
} |
b0aedb04e ide: Stop disks o... |
99 100 101 102 103 104 105 106 107 108 109 110 |
static const struct dmi_system_id ide_coldreboot_table[] = { { /* Acer TravelMate 66x cuts power during reboot */ .ident = "Acer TravelMate 660", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 660"), }, }, { } /* terminate list */ }; |
5fef0e5c0 ide-disk: factor ... |
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
static void ide_gd_shutdown(ide_drive_t *drive) { #ifdef CONFIG_ALPHA /* On Alpha, halt(8) doesn't actually turn the machine off, it puts you into the sort of firmware monitor. Typically, it's used to boot another kernel image, so it's not much different from reboot(8). Therefore, we don't need to spin down the disk in this case, especially since Alpha firmware doesn't handle disks in standby mode properly. On the other hand, it's reasonably safe to turn the power off when the shutdown process reaches the firmware prompt, as the firmware initialization takes rather long time - at least 10 seconds, which should be sufficient for the disk to expire its write cache. */ if (system_state != SYSTEM_POWER_OFF) { #else |
b0aedb04e ide: Stop disks o... |
127 128 |
if (system_state == SYSTEM_RESTART && !dmi_check_system(ide_coldreboot_table)) { |
5fef0e5c0 ide-disk: factor ... |
129 |
#endif |
806f80a6f ide: add generic ... |
130 |
drive->disk_ops->flush(drive); |
5fef0e5c0 ide-disk: factor ... |
131 132 133 134 135 136 137 138 |
return; } printk(KERN_INFO "Shutdown: %s ", drive->name); drive->gendev.bus->suspend(&drive->gendev, PMSG_SUSPEND); } |
79cb38039 ide: allow device... |
139 140 141 |
#ifdef CONFIG_IDE_PROC_FS static ide_proc_entry_t *ide_disk_proc_entries(ide_drive_t *drive) { |
806f80a6f ide: add generic ... |
142 |
return (drive->media == ide_disk) ? ide_disk_proc : ide_floppy_proc; |
79cb38039 ide: allow device... |
143 144 145 146 |
} static const struct ide_proc_devset *ide_disk_proc_devsets(ide_drive_t *drive) { |
806f80a6f ide: add generic ... |
147 148 |
return (drive->media == ide_disk) ? ide_disk_settings : ide_floppy_settings; |
79cb38039 ide: allow device... |
149 150 |
} #endif |
806f80a6f ide: add generic ... |
151 152 153 154 155 |
static ide_startstop_t ide_gd_do_request(ide_drive_t *drive, struct request *rq, sector_t sector) { return drive->disk_ops->do_request(drive, rq, sector); } |
7f3c868ba ide: remove ide_d... |
156 |
static struct ide_driver ide_gd_driver = { |
5fef0e5c0 ide-disk: factor ... |
157 158 |
.gen_driver = { .owner = THIS_MODULE, |
806f80a6f ide: add generic ... |
159 |
.name = "ide-gd", |
5fef0e5c0 ide-disk: factor ... |
160 161 162 163 164 165 166 |
.bus = &ide_bus_type, }, .probe = ide_gd_probe, .remove = ide_gd_remove, .resume = ide_gd_resume, .shutdown = ide_gd_shutdown, .version = IDE_GD_VERSION, |
806f80a6f ide: add generic ... |
167 |
.do_request = ide_gd_do_request, |
5fef0e5c0 ide-disk: factor ... |
168 |
#ifdef CONFIG_IDE_PROC_FS |
79cb38039 ide: allow device... |
169 170 |
.proc_entries = ide_disk_proc_entries, .proc_devsets = ide_disk_proc_devsets, |
5fef0e5c0 ide-disk: factor ... |
171 172 |
#endif }; |
b2f21e057 [PATCH] switch id... |
173 |
static int ide_gd_open(struct block_device *bdev, fmode_t mode) |
5fef0e5c0 ide-disk: factor ... |
174 |
{ |
b2f21e057 [PATCH] switch id... |
175 |
struct gendisk *disk = bdev->bd_disk; |
5fef0e5c0 ide-disk: factor ... |
176 177 |
struct ide_disk_obj *idkp; ide_drive_t *drive; |
806f80a6f ide: add generic ... |
178 |
int ret = 0; |
5fef0e5c0 ide-disk: factor ... |
179 180 181 182 183 184 |
idkp = ide_disk_get(disk); if (idkp == NULL) return -ENXIO; drive = idkp->drive; |
088b1b886 ide: improve debu... |
185 |
ide_debug_log(IDE_DBG_FUNC, "enter"); |
806f80a6f ide: add generic ... |
186 |
|
5fef0e5c0 ide-disk: factor ... |
187 188 189 |
idkp->openers++; if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) { |
806f80a6f ide: add generic ... |
190 191 192 193 194 195 196 197 198 199 |
drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS; /* Just in case */ ret = drive->disk_ops->init_media(drive, disk); /* * Allow O_NDELAY to open a drive without a disk, or with an * unreadable disk, so that we can get the format capacity * of the drive or begin the format - Sam */ |
b2f21e057 [PATCH] switch id... |
200 |
if (ret && (mode & FMODE_NDELAY) == 0) { |
806f80a6f ide: add generic ... |
201 202 203 |
ret = -EIO; goto out_put_idkp; } |
b2f21e057 [PATCH] switch id... |
204 |
if ((drive->dev_flags & IDE_DFLAG_WP) && (mode & FMODE_WRITE)) { |
806f80a6f ide: add generic ... |
205 206 207 |
ret = -EROFS; goto out_put_idkp; } |
5fef0e5c0 ide-disk: factor ... |
208 209 210 211 212 |
/* * Ignore the return code from door_lock, * since the open() has already succeeded, * and the door_lock is irrelevant at this point. */ |
806f80a6f ide: add generic ... |
213 |
drive->disk_ops->set_doorlock(drive, disk, 1); |
cedd120ca ide-disk: use IDE... |
214 |
drive->dev_flags |= IDE_DFLAG_MEDIA_CHANGED; |
b2f21e057 [PATCH] switch id... |
215 |
check_disk_change(bdev); |
806f80a6f ide: add generic ... |
216 217 218 |
} else if (drive->dev_flags & IDE_DFLAG_FORMAT_IN_PROGRESS) { ret = -EBUSY; goto out_put_idkp; |
5fef0e5c0 ide-disk: factor ... |
219 220 |
} return 0; |
806f80a6f ide: add generic ... |
221 222 223 224 225 |
out_put_idkp: idkp->openers--; ide_disk_put(idkp); return ret; |
5fef0e5c0 ide-disk: factor ... |
226 |
} |
6e9624b8c block: push down ... |
227 228 229 |
static int ide_gd_unlocked_open(struct block_device *bdev, fmode_t mode) { int ret; |
2a48fc0ab block: autoconver... |
230 |
mutex_lock(&ide_gd_mutex); |
6e9624b8c block: push down ... |
231 |
ret = ide_gd_open(bdev, mode); |
2a48fc0ab block: autoconver... |
232 |
mutex_unlock(&ide_gd_mutex); |
6e9624b8c block: push down ... |
233 234 235 |
return ret; } |
b2f21e057 [PATCH] switch id... |
236 |
static int ide_gd_release(struct gendisk *disk, fmode_t mode) |
5fef0e5c0 ide-disk: factor ... |
237 |
{ |
5fef0e5c0 ide-disk: factor ... |
238 239 |
struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj); ide_drive_t *drive = idkp->drive; |
088b1b886 ide: improve debu... |
240 |
ide_debug_log(IDE_DBG_FUNC, "enter"); |
806f80a6f ide: add generic ... |
241 |
|
2a48fc0ab block: autoconver... |
242 |
mutex_lock(&ide_gd_mutex); |
5fef0e5c0 ide-disk: factor ... |
243 |
if (idkp->openers == 1) |
806f80a6f ide: add generic ... |
244 |
drive->disk_ops->flush(drive); |
5fef0e5c0 ide-disk: factor ... |
245 |
|
806f80a6f ide: add generic ... |
246 247 248 249 |
if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) { drive->disk_ops->set_doorlock(drive, disk, 0); drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS; } |
5fef0e5c0 ide-disk: factor ... |
250 251 252 253 |
idkp->openers--; ide_disk_put(idkp); |
2a48fc0ab block: autoconver... |
254 |
mutex_unlock(&ide_gd_mutex); |
5fef0e5c0 ide-disk: factor ... |
255 256 257 258 259 260 261 262 263 264 265 266 267 268 |
return 0; } static int ide_gd_getgeo(struct block_device *bdev, struct hd_geometry *geo) { struct ide_disk_obj *idkp = ide_drv_g(bdev->bd_disk, ide_disk_obj); ide_drive_t *drive = idkp->drive; geo->heads = drive->bios_head; geo->sectors = drive->bios_sect; geo->cylinders = (u16)drive->bios_cyl; /* truncate */ return 0; } |
5b03a1b14 ide: Convert to b... |
269 270 |
static unsigned int ide_gd_check_events(struct gendisk *disk, unsigned int clearing) |
5fef0e5c0 ide-disk: factor ... |
271 272 273 |
{ struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj); ide_drive_t *drive = idkp->drive; |
5b03a1b14 ide: Convert to b... |
274 |
bool ret; |
5fef0e5c0 ide-disk: factor ... |
275 276 277 278 279 280 |
/* do not scan partitions twice if this is a removable device */ if (drive->dev_flags & IDE_DFLAG_ATTACH) { drive->dev_flags &= ~IDE_DFLAG_ATTACH; return 0; } |
7eec77a18 ide: unexport DIS... |
281 282 283 284 285 286 |
/* * The following is used to force revalidation on the first open on * removeable devices, and never gets reported to userland as * genhd->events is 0. This is intended as removeable ide disk * can't really detect MEDIA_CHANGE events. */ |
5b03a1b14 ide: Convert to b... |
287 |
ret = drive->dev_flags & IDE_DFLAG_MEDIA_CHANGED; |
cedd120ca ide-disk: use IDE... |
288 |
drive->dev_flags &= ~IDE_DFLAG_MEDIA_CHANGED; |
5b03a1b14 ide: Convert to b... |
289 |
return ret ? DISK_EVENT_MEDIA_CHANGE : 0; |
5fef0e5c0 ide-disk: factor ... |
290 |
} |
c3e33e043 block,ide: simpli... |
291 |
static void ide_gd_unlock_native_capacity(struct gendisk *disk) |
e957b60d1 ide-gd: implement... |
292 293 294 295 |
{ struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj); ide_drive_t *drive = idkp->drive; const struct ide_disk_ops *disk_ops = drive->disk_ops; |
c3e33e043 block,ide: simpli... |
296 297 |
if (disk_ops->unlock_native_capacity) disk_ops->unlock_native_capacity(drive); |
e957b60d1 ide-gd: implement... |
298 |
} |
5fef0e5c0 ide-disk: factor ... |
299 300 301 |
static int ide_gd_revalidate_disk(struct gendisk *disk) { struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj); |
52ebb438e ide-gd: re-get ca... |
302 |
ide_drive_t *drive = idkp->drive; |
5b03a1b14 ide: Convert to b... |
303 |
if (ide_gd_check_events(disk, 0)) |
52ebb438e ide-gd: re-get ca... |
304 305 306 |
drive->disk_ops->get_capacity(drive); set_capacity(disk, ide_gd_capacity(drive)); |
5fef0e5c0 ide-disk: factor ... |
307 308 |
return 0; } |
b2f21e057 [PATCH] switch id... |
309 |
static int ide_gd_ioctl(struct block_device *bdev, fmode_t mode, |
806f80a6f ide: add generic ... |
310 311 |
unsigned int cmd, unsigned long arg) { |
806f80a6f ide: add generic ... |
312 313 |
struct ide_disk_obj *idkp = ide_drv_g(bdev->bd_disk, ide_disk_obj); ide_drive_t *drive = idkp->drive; |
b2f21e057 [PATCH] switch id... |
314 |
return drive->disk_ops->ioctl(drive, bdev, mode, cmd, arg); |
806f80a6f ide: add generic ... |
315 |
} |
83d5cde47 const: make block... |
316 |
static const struct block_device_operations ide_gd_ops = { |
5fef0e5c0 ide-disk: factor ... |
317 |
.owner = THIS_MODULE, |
6e9624b8c block: push down ... |
318 |
.open = ide_gd_unlocked_open, |
b2f21e057 [PATCH] switch id... |
319 |
.release = ide_gd_release, |
8a6cfeb6d block: push down ... |
320 |
.ioctl = ide_gd_ioctl, |
5fef0e5c0 ide-disk: factor ... |
321 |
.getgeo = ide_gd_getgeo, |
5b03a1b14 ide: Convert to b... |
322 |
.check_events = ide_gd_check_events, |
c3e33e043 block,ide: simpli... |
323 |
.unlock_native_capacity = ide_gd_unlock_native_capacity, |
5fef0e5c0 ide-disk: factor ... |
324 325 326 327 328 |
.revalidate_disk = ide_gd_revalidate_disk }; static int ide_gd_probe(ide_drive_t *drive) { |
806f80a6f ide: add generic ... |
329 |
const struct ide_disk_ops *disk_ops = NULL; |
5fef0e5c0 ide-disk: factor ... |
330 331 332 333 |
struct ide_disk_obj *idkp; struct gendisk *g; /* strstr("foo", "") is non-NULL */ |
806f80a6f ide: add generic ... |
334 335 336 337 338 339 340 341 342 343 344 345 |
if (!strstr("ide-gd", drive->driver_req)) goto failed; #ifdef CONFIG_IDE_GD_ATA if (drive->media == ide_disk) disk_ops = &ide_ata_disk_ops; #endif #ifdef CONFIG_IDE_GD_ATAPI if (drive->media == ide_floppy) disk_ops = &ide_atapi_disk_ops; #endif if (disk_ops == NULL) |
5fef0e5c0 ide-disk: factor ... |
346 |
goto failed; |
806f80a6f ide: add generic ... |
347 348 349 350 |
if (disk_ops->check(drive, DRV_NAME) == 0) { printk(KERN_ERR PFX "%s: not supported by this driver ", drive->name); |
5fef0e5c0 ide-disk: factor ... |
351 |
goto failed; |
806f80a6f ide: add generic ... |
352 |
} |
5fef0e5c0 ide-disk: factor ... |
353 354 |
idkp = kzalloc(sizeof(*idkp), GFP_KERNEL); |
806f80a6f ide: add generic ... |
355 356 357 358 |
if (!idkp) { printk(KERN_ERR PFX "%s: can't allocate a disk structure ", drive->name); |
5fef0e5c0 ide-disk: factor ... |
359 |
goto failed; |
806f80a6f ide: add generic ... |
360 |
} |
5fef0e5c0 ide-disk: factor ... |
361 362 363 364 365 366 |
g = alloc_disk_node(IDE_DISK_MINORS, hwif_to_node(drive->hwif)); if (!g) goto out_free_idkp; ide_init_disk(g, drive); |
8fed43684 ide: fix refcount... |
367 368 369 370 371 372 |
idkp->dev.parent = &drive->gendev; idkp->dev.release = ide_disk_release; dev_set_name(&idkp->dev, dev_name(&drive->gendev)); if (device_register(&idkp->dev)) goto out_free_disk; |
5fef0e5c0 ide-disk: factor ... |
373 374 375 376 377 378 379 380 |
idkp->drive = drive; idkp->driver = &ide_gd_driver; idkp->disk = g; g->private_data = &idkp->driver; drive->driver_data = idkp; |
806f80a6f ide: add generic ... |
381 382 |
drive->debug_mask = debug_mask; drive->disk_ops = disk_ops; |
5fef0e5c0 ide-disk: factor ... |
383 |
|
806f80a6f ide: add generic ... |
384 |
disk_ops->setup(drive); |
5fef0e5c0 ide-disk: factor ... |
385 386 387 388 389 390 391 392 393 394 395 |
set_capacity(g, ide_gd_capacity(drive)); g->minors = IDE_DISK_MINORS; g->driverfs_dev = &drive->gendev; g->flags |= GENHD_FL_EXT_DEVT; if (drive->dev_flags & IDE_DFLAG_REMOVABLE) g->flags = GENHD_FL_REMOVABLE; g->fops = &ide_gd_ops; add_disk(g); return 0; |
8fed43684 ide: fix refcount... |
396 397 |
out_free_disk: put_disk(g); |
5fef0e5c0 ide-disk: factor ... |
398 399 400 401 402 403 404 405 |
out_free_idkp: kfree(idkp); failed: return -ENODEV; } static int __init ide_gd_init(void) { |
806f80a6f ide: add generic ... |
406 407 |
printk(KERN_INFO DRV_NAME " driver " IDE_GD_VERSION " "); |
5fef0e5c0 ide-disk: factor ... |
408 409 410 411 412 413 414 415 416 417 |
return driver_register(&ide_gd_driver.gen_driver); } static void __exit ide_gd_exit(void) { driver_unregister(&ide_gd_driver.gen_driver); } MODULE_ALIAS("ide:*m-disk*"); MODULE_ALIAS("ide-disk"); |
806f80a6f ide: add generic ... |
418 419 |
MODULE_ALIAS("ide:*m-floppy*"); MODULE_ALIAS("ide-floppy"); |
5fef0e5c0 ide-disk: factor ... |
420 421 422 |
module_init(ide_gd_init); module_exit(ide_gd_exit); MODULE_LICENSE("GPL"); |
806f80a6f ide: add generic ... |
423 |
MODULE_DESCRIPTION("generic ATA/ATAPI disk driver"); |