X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fide%2Fide-disk.c;h=0a05a377d66ac54a77056fd67cf484cf5bdf8fec;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=db55f241f76ffa6c440c3bdd048b6cfccf153358;hpb=6a77f38946aaee1cd85eeec6cf4229b204c15071;p=linux-2.6.git diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index db55f241f..0a05a377d 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -37,7 +37,7 @@ * Version 1.15 convert all calls to ide_raw_taskfile * since args will return register content. * Version 1.16 added suspend-resume-checkpower - * Version 1.17 do flush on standy, do flush on ATA < ATA6 + * Version 1.17 do flush on standby, do flush on ATA < ATA6 * fix wcache setup. */ @@ -47,7 +47,6 @@ //#define DEBUG -#include #include #include #include @@ -60,6 +59,8 @@ #include #include #include +#include +#include #define _IDE_DISK @@ -71,6 +72,41 @@ #include #include +struct ide_disk_obj { + ide_drive_t *drive; + ide_driver_t *driver; + struct gendisk *disk; + struct kref kref; +}; + +static DEFINE_MUTEX(idedisk_ref_mutex); + +#define to_ide_disk(obj) container_of(obj, struct ide_disk_obj, kref) + +#define ide_disk_g(disk) \ + container_of((disk)->private_data, struct ide_disk_obj, driver) + +static struct ide_disk_obj *ide_disk_get(struct gendisk *disk) +{ + struct ide_disk_obj *idkp = NULL; + + mutex_lock(&idedisk_ref_mutex); + idkp = ide_disk_g(disk); + if (idkp) + kref_get(&idkp->kref); + mutex_unlock(&idedisk_ref_mutex); + return idkp; +} + +static void ide_disk_release(struct kref *); + +static void ide_disk_put(struct ide_disk_obj *idkp) +{ + mutex_lock(&idedisk_ref_mutex); + kref_put(&idkp->kref, ide_disk_release); + mutex_unlock(&idedisk_ref_mutex); +} + /* * lba_capacity_is_ok() performs a sanity check on the claimed "lba_capacity" * value for this drive (from its reported identification information). @@ -84,6 +120,10 @@ static int lba_capacity_is_ok (struct hd_driveid *id) { unsigned long lba_sects, chs_sects, head, tail; + /* No non-LBA info .. so valid! */ + if (id->cyls == 0) + return 1; + /* * The ATA spec tells large drives to return * C/H/S = 16383/16/63 independent of their size. @@ -133,6 +173,8 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq, if (hwif->no_lba48_dma && lba48 && dma) { if (block + rq->nr_sectors > 1ULL << 28) dma = 0; + else + lba48 = 0; } if (!dma) { @@ -146,10 +188,11 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq, /* FIXME: SELECT_MASK(drive, 0) ? */ if (drive->select.b.lba) { - if (drive->addressing == 1) { + if (lba48) { task_ioreg_t tasklets[10]; - pr_debug("%s: LBA=0x%012llx\n", drive->name, block); + pr_debug("%s: LBA=0x%012llx\n", drive->name, + (unsigned long long)block); tasklets[0] = 0; tasklets[1] = 0; @@ -274,9 +317,12 @@ static ide_startstop_t ide_do_rw_disk (ide_drive_t *drive, struct request *rq, s return ide_stopped; } + ledtrig_ide_activity(); + pr_debug("%s: %sing: block=%llu, sectors=%lu, buffer=0x%08lx\n", drive->name, rq_data_dir(rq) == READ ? "read" : "writ", - block, rq->nr_sectors, (unsigned long)rq->buffer); + (unsigned long long)block, rq->nr_sectors, + (unsigned long)rq->buffer); if (hwif->rw_disk) hwif->rw_disk(drive, rq); @@ -436,7 +482,7 @@ static inline int idedisk_supports_lba48(const struct hd_driveid *id) && id->lba_capacity_2; } -static inline void idedisk_check_hpa(ide_drive_t *drive) +static void idedisk_check_hpa(ide_drive_t *drive) { unsigned long long capacity, set_max; int lba48 = idedisk_supports_lba48(drive->id); @@ -514,75 +560,6 @@ static sector_t idedisk_capacity (ide_drive_t *drive) return drive->capacity64 - drive->sect0; } -#define IS_PDC4030_DRIVE 0 - -static ide_startstop_t idedisk_special (ide_drive_t *drive) -{ - special_t *s = &drive->special; - - if (s->b.set_geometry) { - s->b.set_geometry = 0; - if (!IS_PDC4030_DRIVE) { - ide_task_t args; - memset(&args, 0, sizeof(ide_task_t)); - args.tfRegister[IDE_NSECTOR_OFFSET] = drive->sect; - args.tfRegister[IDE_SECTOR_OFFSET] = drive->sect; - args.tfRegister[IDE_LCYL_OFFSET] = drive->cyl; - args.tfRegister[IDE_HCYL_OFFSET] = drive->cyl>>8; - args.tfRegister[IDE_SELECT_OFFSET] = ((drive->head-1)|drive->select.all)&0xBF; - args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SPECIFY; - args.command_type = IDE_DRIVE_TASK_NO_DATA; - args.handler = &set_geometry_intr; - do_rw_taskfile(drive, &args); - } - } else if (s->b.recalibrate) { - s->b.recalibrate = 0; - if (!IS_PDC4030_DRIVE) { - ide_task_t args; - memset(&args, 0, sizeof(ide_task_t)); - args.tfRegister[IDE_NSECTOR_OFFSET] = drive->sect; - args.tfRegister[IDE_COMMAND_OFFSET] = WIN_RESTORE; - args.command_type = IDE_DRIVE_TASK_NO_DATA; - args.handler = &recal_intr; - do_rw_taskfile(drive, &args); - } - } else if (s->b.set_multmode) { - s->b.set_multmode = 0; - if (drive->mult_req > drive->id->max_multsect) - drive->mult_req = drive->id->max_multsect; - if (!IS_PDC4030_DRIVE) { - ide_task_t args; - memset(&args, 0, sizeof(ide_task_t)); - args.tfRegister[IDE_NSECTOR_OFFSET] = drive->mult_req; - args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SETMULT; - args.command_type = IDE_DRIVE_TASK_NO_DATA; - args.handler = &set_multmode_intr; - do_rw_taskfile(drive, &args); - } - } else if (s->all) { - int special = s->all; - s->all = 0; - printk(KERN_ERR "%s: bad special flag: 0x%02x\n", drive->name, special); - return ide_stopped; - } - return IS_PDC4030_DRIVE ? ide_stopped : ide_started; -} - -static void idedisk_pre_reset (ide_drive_t *drive) -{ - int legacy = (drive->id->cfs_enable_2 & 0x0400) ? 0 : 1; - - drive->special.all = 0; - drive->special.b.set_geometry = legacy; - drive->special.b.recalibrate = legacy; - if (OK_TO_RESET_CONTROLLER) - drive->mult_count = 0; - if (!drive->keep_settings && !drive->using_dma) - drive->mult_req = 0; - if (drive->mult_req != drive->mult_count) - drive->special.b.set_multmode = 1; -} - #ifdef CONFIG_PROC_FS static int smart_enable(ide_drive_t *drive) @@ -646,6 +623,16 @@ static int proc_idedisk_read_cache PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } +static int proc_idedisk_read_capacity + (char *page, char **start, off_t off, int count, int *eof, void *data) +{ + ide_drive_t*drive = (ide_drive_t *)data; + int len; + + len = sprintf(page,"%llu\n", (long long)idedisk_capacity(drive)); + PROC_IDE_READ_RETURN(page,start,off,count,eof,len); +} + static int proc_idedisk_read_smart_thresholds (char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -686,6 +673,7 @@ static int proc_idedisk_read_smart_values static ide_proc_entry_t idedisk_proc[] = { { "cache", S_IFREG|S_IRUGO, proc_idedisk_read_cache, NULL }, + { "capacity", S_IFREG|S_IRUGO, proc_idedisk_read_capacity, NULL }, { "geometry", S_IFREG|S_IRUGO, proc_ide_read_geometry, NULL }, { "smart_values", S_IFREG|S_IRUSR, proc_idedisk_read_smart_values, NULL }, { "smart_thresholds", S_IFREG|S_IRUSR, proc_idedisk_read_smart_thresholds, NULL }, @@ -698,17 +686,9 @@ static ide_proc_entry_t idedisk_proc[] = { #endif /* CONFIG_PROC_FS */ -static int idedisk_issue_flush(request_queue_t *q, struct gendisk *disk, - sector_t *error_sector) +static void idedisk_prepare_flush(request_queue_t *q, struct request *rq) { ide_drive_t *drive = q->queuedata; - struct request *rq; - int ret; - - if (!drive->wcache) - return 0; - - rq = blk_get_request(q, WRITE, __GFP_WAIT); memset(rq->cmd, 0, sizeof(rq->cmd)); @@ -719,10 +699,26 @@ static int idedisk_issue_flush(request_queue_t *q, struct gendisk *disk, rq->cmd[0] = WIN_FLUSH_CACHE; - rq->flags |= REQ_DRIVE_TASK | REQ_SOFTBARRIER; + rq->cmd_type = REQ_TYPE_ATA_TASK; + rq->cmd_flags |= REQ_SOFTBARRIER; rq->buffer = rq->cmd; +} + +static int idedisk_issue_flush(request_queue_t *q, struct gendisk *disk, + sector_t *error_sector) +{ + ide_drive_t *drive = q->queuedata; + struct request *rq; + int ret; + + if (!drive->wcache) + return 0; + + rq = blk_get_request(q, WRITE, __GFP_WAIT); + + idedisk_prepare_flush(q, rq); - ret = blk_execute_rq(q, disk, rq); + ret = blk_execute_rq(q, disk, rq, 0); /* * if we failed and caller wants error offset, get it @@ -745,7 +741,7 @@ static int set_multcount(ide_drive_t *drive, int arg) if (drive->special.b.set_multmode) return -EBUSY; ide_init_drive_cmd (&rq); - rq.flags = REQ_DRIVE_CMD; + rq.cmd_type = REQ_TYPE_ATA_CMD; drive->mult_req = arg; drive->special.b.set_multmode = 1; (void) ide_do_drive_cmd (drive, &rq, ide_wait); @@ -762,27 +758,64 @@ static int set_nowerr(ide_drive_t *drive, int arg) return 0; } +static void update_ordered(ide_drive_t *drive) +{ + struct hd_driveid *id = drive->id; + unsigned ordered = QUEUE_ORDERED_NONE; + prepare_flush_fn *prep_fn = NULL; + issue_flush_fn *issue_fn = NULL; + + if (drive->wcache) { + unsigned long long capacity; + int barrier; + /* + * We must avoid issuing commands a drive does not + * understand or we may crash it. We check flush cache + * is supported. We also check we have the LBA48 flush + * cache if the drive capacity is too large. By this + * time we have trimmed the drive capacity if LBA48 is + * not available so we don't need to recheck that. + */ + capacity = idedisk_capacity(drive); + barrier = ide_id_has_flush_cache(id) && !drive->noflush && + (drive->addressing == 0 || capacity <= (1ULL << 28) || + ide_id_has_flush_cache_ext(id)); + + printk(KERN_INFO "%s: cache flushes %ssupported\n", + drive->name, barrier ? "" : "not "); + + if (barrier) { + ordered = QUEUE_ORDERED_DRAIN_FLUSH; + prep_fn = idedisk_prepare_flush; + issue_fn = idedisk_issue_flush; + } + } else + ordered = QUEUE_ORDERED_DRAIN; + + blk_queue_ordered(drive->queue, ordered, prep_fn); + blk_queue_issue_flush_fn(drive->queue, issue_fn); +} + static int write_cache(ide_drive_t *drive, int arg) { ide_task_t args; - int err; - - if (!ide_id_has_flush_cache(drive->id)) - return 1; + int err = 1; - memset(&args, 0, sizeof(ide_task_t)); - args.tfRegister[IDE_FEATURE_OFFSET] = (arg) ? + if (ide_id_has_flush_cache(drive->id)) { + memset(&args, 0, sizeof(ide_task_t)); + args.tfRegister[IDE_FEATURE_OFFSET] = (arg) ? SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE; - args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SETFEATURES; - args.command_type = IDE_DRIVE_TASK_NO_DATA; - args.handler = &task_no_data_intr; + args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SETFEATURES; + args.command_type = IDE_DRIVE_TASK_NO_DATA; + args.handler = &task_no_data_intr; + err = ide_raw_taskfile(drive, &args, NULL); + if (err == 0) + drive->wcache = arg; + } - err = ide_raw_taskfile(drive, &args, NULL); - if (err) - return err; + update_ordered(drive); - drive->wcache = arg; - return 0; + return err; } static int do_idedisk_flushcache (ide_drive_t *drive) @@ -852,106 +885,17 @@ static void idedisk_add_settings(ide_drive_t *drive) ide_add_setting(drive, "max_failures", SETTING_RW, -1, -1, TYPE_INT, 0, 65535, 1, 1, &drive->max_failures, NULL); } -/* - * Power Management state machine. This one is rather trivial for now, - * we should probably add more, like switching back to PIO on suspend - * to help some BIOSes, re-do the door locking on resume, etc... - */ - -enum { - idedisk_pm_flush_cache = ide_pm_state_start_suspend, - idedisk_pm_standby, - - idedisk_pm_idle = ide_pm_state_start_resume, - idedisk_pm_restore_dma, -}; - -static void idedisk_complete_power_step (ide_drive_t *drive, struct request *rq, u8 stat, u8 error) -{ - switch (rq->pm->pm_step) { - case idedisk_pm_flush_cache: /* Suspend step 1 (flush cache) complete */ - if (rq->pm->pm_state == 4) - rq->pm->pm_step = ide_pm_state_completed; - else - rq->pm->pm_step = idedisk_pm_standby; - break; - case idedisk_pm_standby: /* Suspend step 2 (standby) complete */ - rq->pm->pm_step = ide_pm_state_completed; - break; - case idedisk_pm_idle: /* Resume step 1 (idle) complete */ - rq->pm->pm_step = idedisk_pm_restore_dma; - break; - } -} - -static ide_startstop_t idedisk_start_power_step (ide_drive_t *drive, struct request *rq) -{ - ide_task_t *args = rq->special; - - memset(args, 0, sizeof(*args)); - - switch (rq->pm->pm_step) { - case idedisk_pm_flush_cache: /* Suspend step 1 (flush cache) */ - /* Not supported? Switch to next step now. */ - if (!drive->wcache || !ide_id_has_flush_cache(drive->id)) { - idedisk_complete_power_step(drive, rq, 0, 0); - return ide_stopped; - } - if (ide_id_has_flush_cache_ext(drive->id)) - args->tfRegister[IDE_COMMAND_OFFSET] = WIN_FLUSH_CACHE_EXT; - else - args->tfRegister[IDE_COMMAND_OFFSET] = WIN_FLUSH_CACHE; - args->command_type = IDE_DRIVE_TASK_NO_DATA; - args->handler = &task_no_data_intr; - return do_rw_taskfile(drive, args); - - case idedisk_pm_standby: /* Suspend step 2 (standby) */ - args->tfRegister[IDE_COMMAND_OFFSET] = WIN_STANDBYNOW1; - args->command_type = IDE_DRIVE_TASK_NO_DATA; - args->handler = &task_no_data_intr; - return do_rw_taskfile(drive, args); - - case idedisk_pm_idle: /* Resume step 1 (idle) */ - args->tfRegister[IDE_COMMAND_OFFSET] = WIN_IDLEIMMEDIATE; - args->command_type = IDE_DRIVE_TASK_NO_DATA; - args->handler = task_no_data_intr; - return do_rw_taskfile(drive, args); - - case idedisk_pm_restore_dma: /* Resume step 2 (restore DMA) */ - /* - * Right now, all we do is call hwif->ide_dma_check(drive), - * we could be smarter and check for current xfer_speed - * in struct drive etc... - * Also, this step could be implemented as a generic helper - * as most subdrivers will use it - */ - if ((drive->id->capability & 1) == 0) - break; - if (HWIF(drive)->ide_dma_check == NULL) - break; - HWIF(drive)->ide_dma_check(drive); - break; - } - rq->pm->pm_step = ide_pm_state_completed; - return ide_stopped; -} - static void idedisk_setup (ide_drive_t *drive) { struct hd_driveid *id = drive->id; unsigned long long capacity; - int barrier; idedisk_add_settings(drive); if (drive->id_read == 0) return; - /* - * CompactFlash cards and their brethern look just like hard drives - * to us, but they are removable and don't have a doorlock mechanism. - */ - if (drive->removable && !(drive->is_flash)) { + if (drive->removable) { /* * Removable disks (eg. SYQUEST); ignore 'WD' drives */ @@ -974,28 +918,6 @@ static void idedisk_setup (ide_drive_t *drive) printk(KERN_INFO "%s: max request size: %dKiB\n", drive->name, drive->queue->max_sectors / 2); - /* Extract geometry if we did not already have one for the drive */ - if (!drive->cyl || !drive->head || !drive->sect) { - drive->cyl = drive->bios_cyl = id->cyls; - drive->head = drive->bios_head = id->heads; - drive->sect = drive->bios_sect = id->sectors; - } - - /* Handle logical geometry translation by the drive */ - if ((id->field_valid & 1) && id->cur_cyls && - id->cur_heads && (id->cur_heads <= 16) && id->cur_sectors) { - drive->cyl = id->cur_cyls; - drive->head = id->cur_heads; - drive->sect = id->cur_sectors; - } - - /* Use physical geometry if what we have still makes no sense */ - if (drive->head > 16 && id->heads && id->heads <= 16) { - drive->cyl = id->cyls; - drive->head = id->heads; - drive->sect = id->sectors; - } - /* calculate drive capacity, and select LBA if possible */ init_idedisk_capacity (drive); @@ -1059,51 +981,11 @@ static void idedisk_setup (ide_drive_t *drive) ide_dma_verbose(drive); printk("\n"); - drive->mult_count = 0; - if (id->max_multsect) { -#ifdef CONFIG_IDEDISK_MULTI_MODE - id->multsect = ((id->max_multsect/2) > 1) ? id->max_multsect : 0; - id->multsect_valid = id->multsect ? 1 : 0; - drive->mult_req = id->multsect_valid ? id->max_multsect : INITIAL_MULT_COUNT; - drive->special.b.set_multmode = drive->mult_req ? 1 : 0; -#else /* original, pre IDE-NFG, per request of AC */ - drive->mult_req = INITIAL_MULT_COUNT; - if (drive->mult_req > id->max_multsect) - drive->mult_req = id->max_multsect; - if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect)) - drive->special.b.set_multmode = 1; -#endif /* CONFIG_IDEDISK_MULTI_MODE */ - } - drive->no_io_32bit = id->dword_io ? 1 : 0; - /* write cache enabled? */ if ((id->csfo & 1) || (id->cfs_enable_1 & (1 << 5))) drive->wcache = 1; write_cache(drive, 1); - - /* - * We must avoid issuing commands a drive does not understand - * or we may crash it. We check flush cache is supported. We also - * check we have the LBA48 flush cache if the drive capacity is - * too large. By this time we have trimmed the drive capacity if - * LBA48 is not available so we don't need to recheck that. - */ - barrier = 0; - if (ide_id_has_flush_cache(id)) - barrier = 1; - if (drive->addressing == 1) { - /* Can't issue the correct flush ? */ - if (capacity > (1ULL << 28) && !ide_id_has_flush_cache_ext(id)) - barrier = 0; - } - - printk(KERN_DEBUG "%s: cache flushes %ssupported\n", - drive->name, barrier ? "" : "not "); - if (barrier) { - blk_queue_ordered(drive->queue, 1); - blk_queue_issue_flush_fn(drive->queue, idedisk_issue_flush); - } } static void ide_cacheflush_p(ide_drive_t *drive) @@ -1115,24 +997,36 @@ static void ide_cacheflush_p(ide_drive_t *drive) printk(KERN_INFO "%s: wcache flush failed!\n", drive->name); } -static int idedisk_cleanup (ide_drive_t *drive) +static void ide_disk_remove(ide_drive_t *drive) { - struct gendisk *g = drive->disk; - ide_cacheflush_p(drive); - if (ide_unregister_subdriver(drive)) - return 1; + struct ide_disk_obj *idkp = drive->driver_data; + struct gendisk *g = idkp->disk; + + ide_unregister_subdriver(drive, idkp->driver); + del_gendisk(g); - drive->devfs_name[0] = '\0'; - g->fops = ide_fops; - return 0; -} -static int idedisk_attach(ide_drive_t *drive); + ide_cacheflush_p(drive); + + ide_disk_put(idkp); +} -static void ide_device_shutdown(struct device *dev) +static void ide_disk_release(struct kref *kref) { - ide_drive_t *drive = container_of(dev, ide_drive_t, gendev); + struct ide_disk_obj *idkp = to_ide_disk(kref); + ide_drive_t *drive = idkp->drive; + struct gendisk *g = idkp->disk; + + drive->driver_data = NULL; + g->private_data = NULL; + put_disk(g); + kfree(idkp); +} + +static int ide_disk_probe(ide_drive_t *drive); +static void ide_device_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, @@ -1154,37 +1048,39 @@ static void ide_device_shutdown(struct device *dev) } printk("Shutdown: %s\n", drive->name); - dev->bus->suspend(dev, PM_SUSPEND_STANDBY); + drive->gendev.bus->suspend(&drive->gendev, PMSG_SUSPEND); } -/* - * IDE subdriver functions, registered with ide.c - */ static ide_driver_t idedisk_driver = { - .owner = THIS_MODULE, .gen_driver = { - .shutdown = ide_device_shutdown, + .owner = THIS_MODULE, + .name = "ide-disk", + .bus = &ide_bus_type, }, - .name = "ide-disk", + .probe = ide_disk_probe, + .remove = ide_disk_remove, + .shutdown = ide_device_shutdown, .version = IDEDISK_VERSION, .media = ide_disk, - .busy = 0, .supports_dsc_overlap = 0, - .cleanup = idedisk_cleanup, .do_request = ide_do_rw_disk, - .pre_reset = idedisk_pre_reset, - .capacity = idedisk_capacity, - .special = idedisk_special, + .end_request = ide_end_request, + .error = __ide_error, + .abort = __ide_abort, .proc = idedisk_proc, - .attach = idedisk_attach, - .drives = LIST_HEAD_INIT(idedisk_driver.drives), - .start_power_step = idedisk_start_power_step, - .complete_power_step = idedisk_complete_power_step, }; static int idedisk_open(struct inode *inode, struct file *filp) { - ide_drive_t *drive = inode->i_bdev->bd_disk->private_data; + struct gendisk *disk = inode->i_bdev->bd_disk; + struct ide_disk_obj *idkp; + ide_drive_t *drive; + + if (!(idkp = ide_disk_get(disk))) + return -ENXIO; + + drive = idkp->drive; + drive->usage++; if (drive->removable && drive->usage == 1) { ide_task_t args; @@ -1206,7 +1102,10 @@ static int idedisk_open(struct inode *inode, struct file *filp) static int idedisk_release(struct inode *inode, struct file *filp) { - ide_drive_t *drive = inode->i_bdev->bd_disk->private_data; + struct gendisk *disk = inode->i_bdev->bd_disk; + struct ide_disk_obj *idkp = ide_disk_g(disk); + ide_drive_t *drive = idkp->drive; + if (drive->usage == 1) ide_cacheflush_p(drive); if (drive->removable && drive->usage == 1) { @@ -1219,6 +1118,20 @@ static int idedisk_release(struct inode *inode, struct file *filp) drive->doorlocking = 0; } drive->usage--; + + ide_disk_put(idkp); + + return 0; +} + +static int idedisk_getgeo(struct block_device *bdev, struct hd_geometry *geo) +{ + struct ide_disk_obj *idkp = ide_disk_g(bdev->bd_disk); + 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; } @@ -1226,12 +1139,14 @@ static int idedisk_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct block_device *bdev = inode->i_bdev; - return generic_ide_ioctl(file, bdev, cmd, arg); + struct ide_disk_obj *idkp = ide_disk_g(bdev->bd_disk); + return generic_ide_ioctl(idkp->drive, file, bdev, cmd, arg); } static int idedisk_media_changed(struct gendisk *disk) { - ide_drive_t *drive = disk->private_data; + struct ide_disk_obj *idkp = ide_disk_g(disk); + ide_drive_t *drive = idkp->drive; /* do not scan partitions twice if this is a removable device */ if (drive->attach) { @@ -1244,8 +1159,8 @@ static int idedisk_media_changed(struct gendisk *disk) static int idedisk_revalidate_disk(struct gendisk *disk) { - ide_drive_t *drive = disk->private_data; - set_capacity(disk, idedisk_capacity(drive)); + struct ide_disk_obj *idkp = ide_disk_g(disk); + set_capacity(disk, idedisk_capacity(idkp->drive)); return 0; } @@ -1254,15 +1169,17 @@ static struct block_device_operations idedisk_ops = { .open = idedisk_open, .release = idedisk_release, .ioctl = idedisk_ioctl, + .getgeo = idedisk_getgeo, .media_changed = idedisk_media_changed, .revalidate_disk= idedisk_revalidate_disk }; MODULE_DESCRIPTION("ATA DISK Driver"); -static int idedisk_attach(ide_drive_t *drive) +static int ide_disk_probe(ide_drive_t *drive) { - struct gendisk *g = drive->disk; + struct ide_disk_obj *idkp; + struct gendisk *g; /* strstr("foo", "") is non-NULL */ if (!strstr("ide-disk", drive->driver_req)) @@ -1272,11 +1189,29 @@ static int idedisk_attach(ide_drive_t *drive) if (drive->media != ide_disk) goto failed; - if (ide_register_subdriver(drive, &idedisk_driver)) { - printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name); + idkp = kzalloc(sizeof(*idkp), GFP_KERNEL); + if (!idkp) goto failed; - } - DRIVER(drive)->busy++; + + g = alloc_disk_node(1 << PARTN_BITS, + hwif_to_node(drive->hwif)); + if (!g) + goto out_free_idkp; + + ide_init_disk(g, drive); + + ide_register_subdriver(drive, &idedisk_driver); + + kref_init(&idkp->kref); + + idkp->drive = drive; + idkp->driver = &idedisk_driver; + idkp->disk = g; + + g->private_data = &idkp->driver; + + drive->driver_data = idkp; + idedisk_setup(drive); if ((!drive->head || drive->head > 16) && !drive->select.b.lba) { printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", @@ -1284,29 +1219,32 @@ static int idedisk_attach(ide_drive_t *drive) drive->attach = 0; } else drive->attach = 1; - DRIVER(drive)->busy--; + g->minors = 1 << PARTN_BITS; - strcpy(g->devfs_name, drive->devfs_name); g->driverfs_dev = &drive->gendev; g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0; set_capacity(g, idedisk_capacity(drive)); g->fops = &idedisk_ops; add_disk(g); return 0; + +out_free_idkp: + kfree(idkp); failed: - return 1; + return -ENODEV; } static void __exit idedisk_exit (void) { - ide_unregister_driver(&idedisk_driver); + driver_unregister(&idedisk_driver.gen_driver); } -static int idedisk_init (void) +static int __init idedisk_init(void) { - return ide_register_driver(&idedisk_driver); + return driver_register(&idedisk_driver.gen_driver); } +MODULE_ALIAS("ide:*m-disk*"); module_init(idedisk_init); module_exit(idedisk_exit); MODULE_LICENSE("GPL");