bk://bart.bkbits.net/ide-dev-2.6
bzolnier@trik.(none)|ChangeSet|20050211194118|09537 bzolnier

# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2005/03/07 15:21:07-08:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-ide-dev
# 
# include/linux/pci_ids.h
#   2005/03/07 15:21:00-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2005/03/06 19:52:56-08:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-ide-dev
# 
# include/linux/pci_ids.h
#   2005/03/06 19:52:52-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2005/03/04 22:24:46-08:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-ide-dev
# 
# include/linux/pci_ids.h
#   2005/03/04 22:24:42-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2005/03/01 23:32:11-08:00 akpm@bix.(none) 
#   Merge bk://bart.bkbits.net/ide-dev-2.6
#   into bix.(none):/usr/src/bk-ide-dev
# 
# include/linux/pci_ids.h
#   2005/03/01 23:32:07-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# include/linux/ide.h
#   2005/03/01 23:32:07-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# include/linux/ata.h
#   2005/03/01 23:32:07-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/ide/ide.c
#   2005/03/01 23:32:07-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/ide/ide-io.c
#   2005/03/01 23:32:07-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/ide/ide-disk.c
#   2005/03/01 23:32:07-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/ide/Kconfig
#   2005/03/01 23:32:07-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2005/02/11 20:41:18+01:00 bzolnier@trik.(none) 
#   [ide] fix io_32bit race in ide_taskfile_ioctl()
#   
#   In ide_taskfile_ioctl(), there was a race condition involving
#   drive->io_32bit.  It was cleared and restored during ioctl
#   requests but there was no synchronization with other requests.
#   So, other requests could execute with the altered io_32bit
#   setting or updated drive->io_32bit could be overwritten by
#   ide_taskfile_ioctl().
#   
#   This patch adds ATA_TFLAG_IO_16BIT flag to indicate to
#   ide_pio_datablock() that 16bit IO is needed regardless of
#   drive->io_32bit settting.
#   
#   Signed-off-by: Tejun Heo <htejun@gmail.com>
# 
# include/linux/ata.h
#   2005/02/11 20:41:06+01:00 bzolnier@trik.(none) +1 -0
#   [ide] fix io_32bit race in ide_taskfile_ioctl()
# 
# drivers/ide/ide-taskfile.c
#   2005/02/11 20:41:06+01:00 bzolnier@trik.(none) +12 -4
#   [ide] fix io_32bit race in ide_taskfile_ioctl()
# 
# ChangeSet
#   2005/02/11 19:47:30+01:00 bzolnier@trik.(none) 
#   [ide] fix unneeded LBA48 taskfile registers access
#   
#   This small patch fixes unneeded writes/reads to LBA48 taskfile registers
#   on LBA48 capable disks for following cases:
#   
#   * Power Management requests
#     (WIN_FLUSH_CACHE, WIN_STANDBYNOW1, WIN_IDLEIMMEDIATE commands)
#   * special commands (WIN_SPECIFY, WIN_RESTORE, WIN_SETMULT)
#   * Host Protected Area support (WIN_READ_NATIVE_MAX, WIN_SET_MAX)
#   * /proc/ide/ SMART support (WIN_SMART with SMART_ENABLE,
#     SMART_READ_VALUES and SMART_READ_THRESHOLDS subcommands)
#   * write cache enabling/disabling in ide-disk
#    (WIN_SETFEATURES with SETFEATURES_{EN,DIS}_WCACHE)
#   * write cache flushing in ide-disk (WIN_FLUSH_CACHE)
#   * acoustic management in ide-disk
#     (WIN_SETFEATURES with SETFEATURES_{EN,DIS}_AAM)
#   * door (un)locking in ide-disk (WIN_DOORLOCK, WIN_DOORUNLOCK)
#   * /proc/ide/hd?/identify support (WIN_IDENTIFY)
#   
#   Patch adds 'unsinged long flags' to ide_task_t and uses ATA_TFLAG_LBA48
#   flag (from <linux/ata.h>) to indicate need of access to LBA48 taskfile
#   registers.
# 
# include/linux/ide.h
#   2005/02/11 19:47:18+01:00 bzolnier@trik.(none) +1 -0
#   [ide] fix unneeded LBA48 taskfile registers access
# 
# drivers/ide/ide-taskfile.c
#   2005/02/11 19:47:18+01:00 bzolnier@trik.(none) +5 -2
#   [ide] fix unneeded LBA48 taskfile registers access
# 
# drivers/ide/ide-io.c
#   2005/02/11 19:47:18+01:00 bzolnier@trik.(none) +4 -3
#   [ide] fix unneeded LBA48 taskfile registers access
# 
# drivers/ide/ide-disk.c
#   2005/02/11 19:47:18+01:00 bzolnier@trik.(none) +9 -2
#   [ide] fix unneeded LBA48 taskfile registers access
# 
# ChangeSet
#   2005/02/11 19:31:17+01:00 bzolnier@trik.(none) 
#   [ide via82cxxx] add VIA VT6410 support
#   
#   From: Mathias Kretschmer <posting@blx4.net>
# 
# include/linux/pci_ids.h
#   2005/02/11 19:31:06+01:00 bzolnier@trik.(none) +1 -0
#   [ide via82cxxx] add VIA VT6410 support
# 
# drivers/ide/pci/via82cxxx.c
#   2005/02/11 19:31:06+01:00 bzolnier@trik.(none) +21 -9
#   [ide via82cxxx] add VIA VT6410 support
# 
# ChangeSet
#   2005/02/11 18:54:27+01:00 bzolnier@trik.(none) 
#   [ide] fix OOPS in task_end_request()
#   
#   Requests generated by /proc/ide/hd?/identify
#   and /proc/ide/hd?/smart_{thresholds,values}
#   don't have valid rq->rq_disk set.
#   
#   Use ide_end_request() instead of ->end_request().
# 
# drivers/ide/ide-taskfile.c
#   2005/02/11 18:54:16+01:00 bzolnier@trik.(none) +1 -4
#   [ide] fix OOPS in task_end_request()
# 
# ChangeSet
#   2005/02/06 21:08:16+01:00 bzolnier@trik.(none) 
#   [ide] fix ATAPI Power Management
#   
#   I've introduced bug in ATAPI Power Management handling,
#   idedisk_pm_idle shouldn't be done for ATAPI devices.
# 
# drivers/ide/ide-io.c
#   2005/02/05 01:44:33+01:00 bzolnier@trik.(none) +6 -0
#   [ide] fix ATAPI Power Management
# 
# ChangeSet
#   2005/02/06 21:07:35+01:00 bzolnier@trik.(none) 
#   [ide] fix pdc202xx_{new,old}.c after linux-2.6 merge
# 
# drivers/ide/pci/pdc202xx_old.c
#   2005/02/06 21:07:20+01:00 bzolnier@trik.(none) +0 -17
#   [ide] fix pdc202xx_{new,old}.c after linux-2.6 merge
# 
# drivers/ide/pci/pdc202xx_new.c
#   2005/02/06 21:07:20+01:00 bzolnier@trik.(none) +0 -6
#   [ide] fix pdc202xx_{new,old}.c after linux-2.6 merge
# 
# ChangeSet
#   2005/02/06 21:02:13+01:00 bzolnier@trik.(none) 
#   Merge trik.(none):/home/bzolnier/bk/linux-2.6
#   into trik.(none):/home/bzolnier/bk/ide-dev-2.6
# 
# BitKeeper/deleted/.del-pdc202xx_old.h~5487981ee32153be
#   2005/02/06 21:02:08+01:00 bzolnier@trik.(none) +0 -0
#   Auto merged
# 
# BitKeeper/deleted/.del-pdc202xx_new.h~2890994593a7ec02
#   2005/02/06 21:02:08+01:00 bzolnier@trik.(none) +0 -0
#   Auto merged
# 
# include/linux/ide.h
#   2005/02/06 21:02:08+01:00 bzolnier@trik.(none) +0 -0
#   Auto merged
# 
# drivers/ide/ide-probe.c
#   2005/02/06 21:02:08+01:00 bzolnier@trik.(none) +0 -0
#   Auto merged
# 
# BitKeeper/deleted/.del-pdc202xx_old.h~5487981ee32153be
#   2005/02/06 21:02:08+01:00 bzolnier@trik.(none) +0 -0
#   Merge rename: drivers/ide/pci/pdc202xx_old.h -> BitKeeper/deleted/.del-pdc202xx_old.h~5487981ee32153be
# 
# BitKeeper/deleted/.del-pdc202xx_new.h~2890994593a7ec02
#   2005/02/06 21:02:08+01:00 bzolnier@trik.(none) +0 -0
#   Merge rename: drivers/ide/pci/pdc202xx_new.h -> BitKeeper/deleted/.del-pdc202xx_new.h~2890994593a7ec02
# 
# ChangeSet
#   2005/02/04 00:40:24+01:00 bzolnier@trik.(none) 
#   [ide] kill ide-default
#   
#   * add ide_drives list to list devices without a driver
#   * add __ide_add_setting() and use it for adding no auto remove entries
#   * kill ide-default pseudo-driver
# 
# drivers/ide/ide.c
#   2005/01/25 02:40:20+01:00 bzolnier@trik.(none) +31 -28
#   [ide] kill ide-default
# 
# drivers/ide/ide-proc.c
#   2005/01/25 02:40:20+01:00 bzolnier@trik.(none) +5 -4
#   [ide] kill ide-default
# 
# drivers/ide/Makefile
#   2005/01/25 02:40:20+01:00 bzolnier@trik.(none) +1 -2
#   [ide] kill ide-default
# 
# BitKeeper/deleted/.del-ide-default.c~ad4e75ad8a193ed5
#   2005/02/04 00:40:13+01:00 bzolnier@trik.(none) +0 -0
#   [ide] kill ide-default
# 
# ChangeSet
#   2005/02/04 00:38:26+01:00 bzolnier@trik.(none) 
#   [ide] get driver from rq->rq_disk->private_data
#   
#   * add ide_driver_t * to device drivers objects
#   * set it to point at driver's ide_driver_t
#   * store address of this entry in disk->private_data
#   * fix ide_{cd,disk,floppy,tape,scsi}_g accordingly
#   * use rq->rq_disk->private_data instead of drive->driver
#     to obtain driver (this allows us to kill ide-default)
# 
# drivers/scsi/ide-scsi.c
#   2005/01/25 02:40:10+01:00 bzolnier@trik.(none) +13 -4
#   [ide] get driver from rq->rq_disk->private_data
# 
# drivers/ide/ide.c
#   2005/01/25 02:40:10+01:00 bzolnier@trik.(none) +3 -1
#   [ide] get driver from rq->rq_disk->private_data
# 
# drivers/ide/ide-taskfile.c
#   2005/01/25 02:40:10+01:00 bzolnier@trik.(none) +11 -3
#   [ide] get driver from rq->rq_disk->private_data
# 
# drivers/ide/ide-tape.c
#   2005/01/25 02:40:10+01:00 bzolnier@trik.(none) +6 -2
#   [ide] get driver from rq->rq_disk->private_data
# 
# drivers/ide/ide-io.c
#   2005/01/25 02:40:10+01:00 bzolnier@trik.(none) +36 -8
#   [ide] get driver from rq->rq_disk->private_data
# 
# drivers/ide/ide-floppy.c
#   2005/01/25 02:40:10+01:00 bzolnier@trik.(none) +6 -2
#   [ide] get driver from rq->rq_disk->private_data
# 
# drivers/ide/ide-dma.c
#   2005/01/25 02:40:10+01:00 bzolnier@trik.(none) +3 -1
#   [ide] get driver from rq->rq_disk->private_data
# 
# drivers/ide/ide-disk.c
#   2005/01/25 02:40:10+01:00 bzolnier@trik.(none) +6 -2
#   [ide] get driver from rq->rq_disk->private_data
# 
# drivers/ide/ide-cd.h
#   2005/01/25 02:40:10+01:00 bzolnier@trik.(none) +1 -0
#   [ide] get driver from rq->rq_disk->private_data
# 
# drivers/ide/ide-cd.c
#   2005/01/25 02:40:10+01:00 bzolnier@trik.(none) +5 -2
#   [ide] get driver from rq->rq_disk->private_data
# 
# ChangeSet
#   2005/02/04 00:35:41+01:00 bzolnier@trik.(none) 
#   [ide] kill ide_drive_t->disk
#   
#   * move ->disk from ide_drive_t to driver specific objects
#   * make drivers allocate struct gendisk and setup rq->rq_disk
#     (there is no need to do this for REQ_DRIVE_TASKFILE requests)
#   * add ide_init_disk() helper and kill alloc_disks() in ide-probe.c
#   * kill no longer needed ide_open() and ide_fops[] in ide.c
# 
# include/linux/ide.h
#   2005/01/25 02:39:59+01:00 bzolnier@trik.(none) +1 -2
#   [ide] kill ide_drive_t->disk
# 
# drivers/scsi/ide-scsi.c
#   2005/01/25 02:39:59+01:00 bzolnier@trik.(none) +18 -5
#   [ide] kill ide_drive_t->disk
# 
# drivers/ide/ide.c
#   2005/01/25 02:39:59+01:00 bzolnier@trik.(none) +0 -17
#   [ide] kill ide_drive_t->disk
# 
# drivers/ide/ide-tape.c
#   2005/01/25 02:39:59+01:00 bzolnier@trik.(none) +25 -6
#   [ide] kill ide_drive_t->disk
# 
# drivers/ide/ide-probe.c
#   2005/01/25 02:39:59+01:00 bzolnier@trik.(none) +13 -39
#   [ide] kill ide_drive_t->disk
# 
# drivers/ide/ide-io.c
#   2005/01/25 02:39:59+01:00 bzolnier@trik.(none) +0 -2
#   [ide] kill ide_drive_t->disk
# 
# drivers/ide/ide-floppy.c
#   2005/01/25 02:39:59+01:00 bzolnier@trik.(none) +30 -10
#   [ide] kill ide_drive_t->disk
# 
# drivers/ide/ide-disk.c
#   2005/01/25 02:39:59+01:00 bzolnier@trik.(none) +17 -5
#   [ide] kill ide_drive_t->disk
# 
# drivers/ide/ide-cd.h
#   2005/01/25 02:39:59+01:00 bzolnier@trik.(none) +1 -0
#   [ide] kill ide_drive_t->disk
# 
# drivers/ide/ide-cd.c
#   2005/01/25 02:39:59+01:00 bzolnier@trik.(none) +38 -22
#   [ide] kill ide_drive_t->disk
# 
# ChangeSet
#   2005/02/04 00:31:44+01:00 bzolnier@trik.(none) 
#   [ide] add ide_{un}register_region()
#   
#   Add ide_{un}register_region() and fix ide-{tape,scsi}.c to register
#   block device number ranges.  In ata_probe() only probe for modules.
#   
#   Behavior is unchanged because:
#   * if driver is already loaded and attached to drive ata_probe()
#     is not called et all
#   * if driver is loaded by ata_probe() it will register new number range
#     for a drive and this range will be found by kobj_lookup()
#   
#   If this is not clear please read http://lwn.net/Articles/25711/
#   and see drivers/base/map.c.
#   
#   This patch makes it possible to move drive->disk allocation from
#   ide-probe.c to device drivers.
# 
# include/linux/ide.h
#   2005/01/25 02:39:47+01:00 bzolnier@trik.(none) +3 -0
#   [ide] add ide_{un}register_region()
# 
# drivers/scsi/ide-scsi.c
#   2005/01/25 02:39:47+01:00 bzolnier@trik.(none) +4 -0
#   [ide] add ide_{un}register_region()
# 
# drivers/ide/ide-tape.c
#   2005/01/25 02:39:47+01:00 bzolnier@trik.(none) +3 -0
#   [ide] add ide_{un}register_region()
# 
# drivers/ide/ide-probe.c
#   2005/01/25 02:39:47+01:00 bzolnier@trik.(none) +44 -17
#   [ide] add ide_{un}register_region()
# 
# ChangeSet
#   2005/02/04 00:30:10+01:00 bzolnier@trik.(none) 
#   [ide] destroy_proc_ide_device() cleanup
#   
#   When this function is called device is already unbinded from a
#   driver so there are no driver /proc entries to remove.
# 
# drivers/ide/ide-proc.c
#   2005/01/25 02:39:35+01:00 bzolnier@trik.(none) +0 -3
#   [ide] destroy_proc_ide_device() cleanup
# 
# ChangeSet
#   2005/02/04 00:29:13+01:00 bzolnier@trik.(none) 
#   [ide] drive->dsc_overlap fix
#   
#   drive->dsc_overlap is supported only by ide-{cd,tape} drivers.
#   Add missing clearing of ->dsc_overlap to ide_{cd,tape}_release()
#   and move ->dsc_overlap setup from ide_register_subdriver() to
#   ide_cdrom_setup() (ide-tape enables it unconditionally).
# 
# drivers/ide/ide.c
#   2005/01/25 02:39:24+01:00 bzolnier@trik.(none) +0 -5
#   [ide] drive->dsc_overlap fix
# 
# drivers/ide/ide-tape.c
#   2005/01/25 02:39:24+01:00 bzolnier@trik.(none) +1 -0
#   [ide] drive->dsc_overlap fix
# 
# drivers/ide/ide-cd.c
#   2005/01/25 02:39:24+01:00 bzolnier@trik.(none) +4 -0
#   [ide] drive->dsc_overlap fix
# 
# ChangeSet
#   2005/02/04 00:28:20+01:00 bzolnier@trik.(none) 
#   [ide] drive->nice1 fix
#   
#   It is drive's property independent of the driver being used so move
#   drive->nice1 setup from ide_register_subdriver() to probe_hwif() in
#   ide-probe.c.  As a result changing a driver which controls the drive
#   no longer affects this flag.
# 
# drivers/ide/ide.c
#   2005/01/25 02:39:13+01:00 bzolnier@trik.(none) +0 -1
#   [ide] drive->nice1 fix
# 
# drivers/ide/ide-probe.c
#   2005/01/25 02:39:13+01:00 bzolnier@trik.(none) +8 -3
#   [ide] drive->nice1 fix
# 
# ChangeSet
#   2005/02/04 00:27:16+01:00 bzolnier@trik.(none) 
#   [ide] ide-tape: fix character device ->open() vs ->cleanup() race
#   
#   Similar to the same race but for the block device.
#   
#   * store pointer to struct ide_tape_obj in idetape_chrdevs[]
#   * rename idetape_chrdevs[] to idetape_devs[] and kill idetape_chrdev_t
#   * add ide_tape_chrdev_get() for getting reference to the tape
#   * store tape pointer in file->private_data and fix all users of it
#   * fix idetape_chrdev_{open,release}() to get/put reference to the tape
# 
# drivers/ide/ide-tape.c
#   2005/01/25 02:39:03+01:00 bzolnier@trik.(none) +51 -30
#   [ide] ide-tape: fix character device ->open() vs ->cleanup() race
# 
# ChangeSet
#   2005/02/03 21:47:18+01:00 bzolnier@trik.(none) 
#   [ide] fix via82cxxx resume failure
#   
#   With David Woodhouse <dwmw2@infradead.org>.
#   
#   On resume from sleep, via_set_speed() doesn't reinstate the correct
#   mode, because it thinks the drive is already configured correctly.
#   
#   Also kill redundant printk, ide_config_drive_speed() warns about errors.
# 
# drivers/ide/pci/via82cxxx.c
#   2005/02/03 21:47:05+01:00 bzolnier@trik.(none) +2 -5
#   [ide] fix via82cxxx resume failure
# 
# ChangeSet
#   2005/02/03 21:20:52+01:00 bzolnier@trik.(none) 
#   [ide] ide-scsi: add basic refcounting
#   
#   * pointers to a SCSI host and a drive are added to idescsi_scsi_t
#   * pointer to the SCSI host is stored in disk->private_data
#   * ide_scsi_{get,put}() is used to {get,put} reference to the SCSI host
# 
# drivers/scsi/ide-scsi.c
#   2005/01/21 23:41:42+01:00 bzolnier@trik.(none) +58 -11
#   [ide] ide-scsi: add basic refcounting
# 
# ChangeSet
#   2005/02/03 21:19:36+01:00 bzolnier@trik.(none) 
#   [ide] ide-tape: add basic refcounting
#   
#   Similar changes as for ide-cd.c.
# 
# drivers/ide/ide-tape.c
#   2005/01/21 23:41:25+01:00 bzolnier@trik.(none) +80 -14
#   [ide] ide-tape: add basic refcounting
# 
# ChangeSet
#   2005/02/03 21:18:37+01:00 bzolnier@trik.(none) 
#   [ide] ide-floppy: add basic refcounting
#   
#   Similar changes as for ide-cd.c.
# 
# drivers/ide/ide-floppy.c
#   2005/01/21 23:41:14+01:00 bzolnier@trik.(none) +90 -25
#   [ide] ide-floppy: add basic refcounting
# 
# ChangeSet
#   2005/02/03 21:17:26+01:00 bzolnier@trik.(none) 
#   [ide] ide-disk: add basic refcounting
#   
#   Similar changes as for ide-cd.c (except that struct ide_disk_obj is added).
# 
# drivers/ide/ide-disk.c
#   2005/01/21 23:41:03+01:00 bzolnier@trik.(none) +88 -9
#   [ide] ide-disk: add basic refcounting
# 
# ChangeSet
#   2005/02/03 21:15:21+01:00 bzolnier@trik.(none) 
#   [ide] ide-cd: add basic refcounting
#   
#   * based on reference counting in drivers/scsi/{sd,sr}.c
#   * fixes race between ->open() and ->cleanup() (ide_unregister_subdriver()
#     tests for drive->usage != 0 but there is no protection against new users)
#   * struct kref and pointer to a drive are added to struct ide_cdrom_info
#   * pointer to drive's struct ide_cdrom_info is stored in disk->private_data
#   * ide_cd_{get,put}() is used to {get,put} reference to struct ide_cdrom_info
#   * ide_cd_release() is a release method for struct ide_cdrom_info
# 
# drivers/ide/ide-cd.h
#   2005/01/21 23:40:52+01:00 bzolnier@trik.(none) +2 -0
#   [ide] ide-cd: add basic refcounting
# 
# drivers/ide/ide-cd.c
#   2005/01/21 23:40:52+01:00 bzolnier@trik.(none) +80 -19
#   [ide] ide-cd: add basic refcounting
# 
# ChangeSet
#   2005/02/03 21:13:29+01:00 bzolnier@trik.(none) 
#   [ide] make ide_generic_ioctl() take ide_drive_t * as an argument
#   
#   As a result disk->private_data can be used by device drivers now.
# 
# include/linux/ide.h
#   2005/01/21 22:30:19+01:00 bzolnier@trik.(none) +1 -1
#   [ide] make ide_generic_ioctl() take ide_drive_t * as an argument
# 
# drivers/scsi/ide-scsi.c
#   2005/01/21 22:30:19+01:00 bzolnier@trik.(none) +2 -1
#   [ide] make ide_generic_ioctl() take ide_drive_t * as an argument
# 
# drivers/ide/ide.c
#   2005/01/21 22:30:19+01:00 bzolnier@trik.(none) +1 -2
#   [ide] make ide_generic_ioctl() take ide_drive_t * as an argument
# 
# drivers/ide/ide-tape.c
#   2005/01/21 22:30:19+01:00 bzolnier@trik.(none) +1 -1
#   [ide] make ide_generic_ioctl() take ide_drive_t * as an argument
# 
# drivers/ide/ide-floppy.c
#   2005/01/21 22:30:19+01:00 bzolnier@trik.(none) +1 -1
#   [ide] make ide_generic_ioctl() take ide_drive_t * as an argument
# 
# drivers/ide/ide-disk.c
#   2005/01/21 22:30:19+01:00 bzolnier@trik.(none) +2 -1
#   [ide] make ide_generic_ioctl() take ide_drive_t * as an argument
# 
# drivers/ide/ide-cd.c
#   2005/01/21 22:30:19+01:00 bzolnier@trik.(none) +1 -1
#   [ide] make ide_generic_ioctl() take ide_drive_t * as an argument
# 
# ChangeSet
#   2005/02/03 21:08:15+01:00 bzolnier@trik.(none) 
#   [ide] kill setup_driver_defaults()
#   
#   * move default_do_request() to ide-default.c
#   * fix drivers to set ide_driver_t->{do_request,end_request,error,abort}
#   * kill setup_driver_defaults()
# 
# drivers/ide/ide.c
#   2005/01/21 22:27:18+01:00 bzolnier@trik.(none) +0 -37
#   [ide] kill setup_driver_defaults()
# 
# drivers/ide/ide-tape.c
#   2005/01/21 22:27:18+01:00 bzolnier@trik.(none) +2 -0
#   [ide] kill setup_driver_defaults()
# 
# drivers/ide/ide-io.c
#   2005/01/21 22:27:18+01:00 bzolnier@trik.(none) +4 -0
#   [ide] kill setup_driver_defaults()
# 
# drivers/ide/ide-floppy.c
#   2005/01/21 22:27:18+01:00 bzolnier@trik.(none) +2 -0
#   [ide] kill setup_driver_defaults()
# 
# drivers/ide/ide-disk.c
#   2005/01/21 22:27:18+01:00 bzolnier@trik.(none) +3 -0
#   [ide] kill setup_driver_defaults()
# 
# drivers/ide/ide-default.c
#   2005/01/21 22:27:18+01:00 bzolnier@trik.(none) +10 -0
#   [ide] kill setup_driver_defaults()
# 
# drivers/ide/ide-cd.c
#   2005/01/21 22:27:18+01:00 bzolnier@trik.(none) +3 -0
#   [ide] kill setup_driver_defaults()
# 
# ChangeSet
#   2005/02/03 21:04:06+01:00 bzolnier@trik.(none) 
#   [ide] kill ide_driver_t->capacity
#   
#   * add private /proc/ide/hd?/capacity handlers to ide-{cd,disk,floppy}.c
#   * use generic proc_ide_read_capacity() for ide-{scsi,tape}.c
#   * kill ->capacity, default_capacity() and generic_subdriver_entries[]
# 
# include/linux/ide.h
#   2005/01/21 22:23:17+01:00 bzolnier@trik.(none) +0 -1
#   [ide] kill ide_driver_t->capacity
# 
# drivers/scsi/ide-scsi.c
#   2005/01/21 22:23:17+01:00 bzolnier@trik.(none) +10 -0
#   [ide] kill ide_driver_t->capacity
# 
# drivers/ide/ide.c
#   2005/02/03 21:00:44+01:00 bzolnier@trik.(none) +1 -15
#   [ide] kill ide_driver_t->capacity
# 
# drivers/ide/ide-tape.c
#   2005/01/21 22:23:17+01:00 bzolnier@trik.(none) +1 -0
#   [ide] kill ide_driver_t->capacity
# 
# drivers/ide/ide-proc.c
#   2005/01/21 22:23:17+01:00 bzolnier@trik.(none) +3 -5
#   [ide] kill ide_driver_t->capacity
# 
# drivers/ide/ide-floppy.c
#   2005/01/21 22:23:17+01:00 bzolnier@trik.(none) +11 -1
#   [ide] kill ide_driver_t->capacity
# 
# drivers/ide/ide-disk.c
#   2005/01/21 22:23:17+01:00 bzolnier@trik.(none) +11 -1
#   [ide] kill ide_driver_t->capacity
# 
# drivers/ide/ide-cd.c
#   2005/01/21 22:23:17+01:00 bzolnier@trik.(none) +20 -1
#   [ide] kill ide_driver_t->capacity
# 
# ChangeSet
#   2005/02/03 20:44:44+01:00 bzolnier@trik.(none) 
#   Merge
# 
# include/linux/ide.h
#   2005/02/03 20:44:41+01:00 bzolnier@trik.(none) +0 -0
#   SCCS merged
# 
# drivers/ide/ide-iops.c
#   2005/02/03 20:44:41+01:00 bzolnier@trik.(none) +0 -0
#   SCCS merged
# 
# drivers/scsi/ide-scsi.c
#   2005/02/03 20:37:17+01:00 bzolnier@trik.(none) +0 -0
#   Auto merged
# 
# drivers/ide/ide.c
#   2005/02/03 20:37:17+01:00 bzolnier@trik.(none) +0 -0
#   Auto merged
# 
# drivers/ide/ide-taskfile.c
#   2005/02/03 20:37:17+01:00 bzolnier@trik.(none) +0 -0
#   Auto merged
# 
# drivers/ide/ide-tape.c
#   2005/02/03 20:37:17+01:00 bzolnier@trik.(none) +0 -0
#   Auto merged
# 
# drivers/ide/ide-probe.c
#   2005/02/03 20:37:17+01:00 bzolnier@trik.(none) +0 -0
#   Auto merged
# 
# drivers/ide/ide-io.c
#   2005/02/03 20:37:17+01:00 bzolnier@trik.(none) +0 -0
#   Auto merged
# 
# drivers/ide/ide-floppy.c
#   2005/02/03 20:37:17+01:00 bzolnier@trik.(none) +0 -0
#   Auto merged
# 
# drivers/ide/ide-disk.c
#   2005/02/03 20:37:17+01:00 bzolnier@trik.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2005/01/21 20:25:56+01:00 bzolnier@trik.(none) 
#   [ide] kill ide_driver_t->pre_reset
#   
#   Add ide_drive_t->post_reset flag and use it to signal post reset
#   condition to the ide-tape driver (the only user of ->pre_reset).
# 
# include/linux/ide.h
#   2005/01/21 20:13:35+01:00 bzolnier@trik.(none) +1 -1
#   [ide] kill ide_driver_t->pre_reset
# 
# drivers/ide/ide.c
#   2005/01/21 20:13:35+01:00 bzolnier@trik.(none) +0 -5
#   [ide] kill ide_driver_t->pre_reset
# 
# drivers/ide/ide-tape.c
#   2005/01/21 20:13:35+01:00 bzolnier@trik.(none) +5 -11
#   [ide] kill ide_driver_t->pre_reset
# 
# drivers/ide/ide-iops.c
#   2005/01/21 20:13:35+01:00 bzolnier@trik.(none) +1 -1
#   [ide] kill ide_driver_t->pre_reset
# 
# ChangeSet
#   2005/01/21 20:24:38+01:00 bzolnier@trik.(none) 
#   [ide] fix some rare ide-default vs ide-disk races
#   
#   Some rare races between ide-default and ide-disk are possible, i.e.:
#   * ide-default is used, I/O request is triggered (ie. /proc/ide/hd?/identify),
#     drive->special is cleared silently (so CHS is not initialized properly),
#     ide-disk is loaded and fails if drive uses CHS
#   * ide-disk is used, drive is resetted, ide-disk is unloaded, ide-default
#     takes control over drive and on the first I/O request silently clears
#    drive->special without restoring settings
#   
#   Fix them by moving idedisk_{special,pre_reset}() and company to IDE core.
# 
# include/linux/ide.h
#   2005/01/21 20:13:47+01:00 bzolnier@trik.(none) +0 -1
#   [ide] fix some rare ide-default vs ide-disk races
# 
# drivers/ide/ide.c
#   2005/01/21 20:13:47+01:00 bzolnier@trik.(none) +0 -10
#   [ide] fix some rare ide-default vs ide-disk races
# 
# drivers/ide/ide-taskfile.c
#   2005/01/21 20:13:47+01:00 bzolnier@trik.(none) +0 -6
#   [ide] fix some rare ide-default vs ide-disk races
# 
# drivers/ide/ide-probe.c
#   2005/01/21 20:13:47+01:00 bzolnier@trik.(none) +58 -2
#   [ide] fix some rare ide-default vs ide-disk races
# 
# drivers/ide/ide-iops.c
#   2005/01/21 20:13:47+01:00 bzolnier@trik.(none) +19 -1
#   [ide] fix some rare ide-default vs ide-disk races
# 
# drivers/ide/ide-io.c
#   2005/01/21 20:13:47+01:00 bzolnier@trik.(none) +66 -2
#   [ide] fix some rare ide-default vs ide-disk races
# 
# drivers/ide/ide-disk.c
#   2005/01/21 20:13:47+01:00 bzolnier@trik.(none) +0 -108
#   [ide] fix some rare ide-default vs ide-disk races
# 
# drivers/ide/Kconfig
#   2005/01/21 20:13:47+01:00 bzolnier@trik.(none) +0 -1
#   [ide] fix some rare ide-default vs ide-disk races
# 
# ChangeSet
#   2005/01/21 20:23:26+01:00 bzolnier@trik.(none) 
#   [ide] generic Power Management for IDE devices
#   
#   Move PM code from ide-cd.c and ide-disk.c to IDE core so:
#   * PM is supported for other ATAPI devices (floppy, tape)
#   * PM is supported even if specific driver is not loaded
# 
# include/linux/ide.h
#   2005/01/21 20:14:00+01:00 bzolnier@trik.(none) +0 -2
#   [ide] generic Power Management for IDE devices
# 
# drivers/ide/ide.c
#   2005/01/21 20:14:00+01:00 bzolnier@trik.(none) +0 -9
#   [ide] generic Power Management for IDE devices
# 
# drivers/ide/ide-io.c
#   2005/01/21 20:14:00+01:00 bzolnier@trik.(none) +89 -2
#   [ide] generic Power Management for IDE devices
# 
# drivers/ide/ide-disk.c
#   2005/01/21 20:14:00+01:00 bzolnier@trik.(none) +0 -86
#   [ide] generic Power Management for IDE devices
# 
# drivers/ide/ide-cd.c
#   2005/01/21 20:14:00+01:00 bzolnier@trik.(none) +0 -41
#   [ide] generic Power Management for IDE devices
# 
# ChangeSet
#   2005/01/21 20:21:54+01:00 bzolnier@trik.(none) 
#   [ide] fix drive->ready_stat for ATAPI
#   
#   ATAPI devices ignore DRDY bit so drive->ready_stat must be set to zero.
#   It is currently done by device drivers (including ide-default fake driver)
#   but for PMAC driver it is too late as wait_for_ready() may be called during
#   probe: probe_hwif()->pmac_ide_dma_check()->pmac_ide_{mdma,udma}_enable()->
#   ->pmac_ide_do_setfeature()->wait_for_ready().
#   
#   Fixup drive->ready_stat just after detecting ATAPI device.
# 
# drivers/scsi/ide-scsi.c
#   2005/01/21 20:14:18+01:00 bzolnier@trik.(none) +0 -1
#   [ide] fix drive->ready_stat for ATAPI
# 
# drivers/ide/ide.c
#   2005/01/21 20:14:18+01:00 bzolnier@trik.(none) +2 -0
#   [ide] fix drive->ready_stat for ATAPI
# 
# drivers/ide/ide-tape.c
#   2005/01/21 20:14:18+01:00 bzolnier@trik.(none) +0 -2
#   [ide] fix drive->ready_stat for ATAPI
# 
# drivers/ide/ide-probe.c
#   2005/01/21 20:14:18+01:00 bzolnier@trik.(none) +2 -0
#   [ide] fix drive->ready_stat for ATAPI
# 
# drivers/ide/ide-floppy.c
#   2005/01/21 20:14:18+01:00 bzolnier@trik.(none) +0 -1
#   [ide] fix drive->ready_stat for ATAPI
# 
# drivers/ide/ide-default.c
#   2005/01/21 20:14:18+01:00 bzolnier@trik.(none) +0 -7
#   [ide] fix drive->ready_stat for ATAPI
# 
# drivers/ide/ide-cd.c
#   2005/01/21 20:14:18+01:00 bzolnier@trik.(none) +0 -1
#   [ide] fix drive->ready_stat for ATAPI
# 
# ChangeSet
#   2005/01/21 20:20:25+01:00 bzolnier@trik.(none) 
#   [ide] ignore BIOS enable bits for Promise controllers
#   
#   Since there are no Promise binary drivers for 2.6.x kernels:
#   * ignore BIOS enable bits completely
#   * remove CONFIG_PDC202XX_FORCE
#   * kill IDEPCI_FLAG_FORCE_PDC hack
# 
# include/linux/ide.h
#   2005/01/21 20:14:29+01:00 bzolnier@trik.(none) +0 -1
#   [ide] ignore BIOS enable bits for Promise controllers
# 
# drivers/ide/setup-pci.c
#   2005/01/21 20:14:29+01:00 bzolnier@trik.(none) +1 -14
#   [ide] ignore BIOS enable bits for Promise controllers
# 
# drivers/ide/pci/pdc202xx_old.h
#   2005/01/21 20:14:29+01:00 bzolnier@trik.(none) +0 -17
#   [ide] ignore BIOS enable bits for Promise controllers
# 
# drivers/ide/pci/pdc202xx_new.h
#   2005/01/21 20:14:29+01:00 bzolnier@trik.(none) +0 -6
#   [ide] ignore BIOS enable bits for Promise controllers
# 
# drivers/ide/Kconfig
#   2005/01/21 20:14:29+01:00 bzolnier@trik.(none) +0 -7
#   [ide] ignore BIOS enable bits for Promise controllers
# 
diff -Nru a/drivers/ide/Kconfig b/drivers/ide/Kconfig
--- a/drivers/ide/Kconfig	2005-03-07 15:22:36 -08:00
+++ b/drivers/ide/Kconfig	2005-03-07 15:22:36 -08:00
@@ -150,7 +150,6 @@
 
 config IDEDISK_MULTI_MODE
 	bool "Use multi-mode by default"
-	depends on BLK_DEV_IDEDISK
 	help
 	  If you get this error, try to say Y here:
 
@@ -658,13 +657,6 @@
 
 config BLK_DEV_PDC202XX_NEW
 	tristate "PROMISE PDC202{68|69|70|71|75|76|77} support"
-
-# FIXME - probably wants to be one for old and for new
-config PDC202XX_FORCE
-	bool "Enable controller even if disabled by BIOS"
-	depends on BLK_DEV_PDC202XX_NEW
-	help
-	  Enable the PDC202xx controller even if it has been disabled in the BIOS setup.
 
 config BLK_DEV_SVWKS
 	tristate "ServerWorks OSB4/CSB5/CSB6 chipsets support"
diff -Nru a/drivers/ide/Makefile b/drivers/ide/Makefile
--- a/drivers/ide/Makefile	2005-03-07 15:22:36 -08:00
+++ b/drivers/ide/Makefile	2005-03-07 15:22:36 -08:00
@@ -13,8 +13,7 @@
 
 obj-$(CONFIG_BLK_DEV_IDE)		+= pci/
 
-ide-core-y += ide.o ide-default.o ide-io.o ide-iops.o ide-lib.o ide-probe.o \
-	ide-taskfile.o
+ide-core-y += ide.o ide-io.o ide-iops.o ide-lib.o ide-probe.o ide-taskfile.o
 
 ide-core-$(CONFIG_BLK_DEV_CMD640)	+= pci/cmd640.o
 
diff -Nru a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
--- a/drivers/ide/ide-cd.c	2005-03-07 15:22:36 -08:00
+++ b/drivers/ide/ide-cd.c	2005-03-07 15:22:36 -08:00
@@ -324,6 +324,34 @@
 
 #include "ide-cd.h"
 
+static DECLARE_MUTEX(idecd_ref_sem);
+
+#define to_ide_cd(obj) container_of(obj, struct cdrom_info, kref) 
+
+#define ide_cd_g(disk) \
+	container_of((disk)->private_data, struct cdrom_info, driver)
+
+static struct cdrom_info *ide_cd_get(struct gendisk *disk)
+{
+	struct cdrom_info *cd = NULL;
+
+	down(&idecd_ref_sem);
+	cd = ide_cd_g(disk);
+	if (cd)
+		kref_get(&cd->kref);
+	up(&idecd_ref_sem);
+	return cd;
+}
+
+static void ide_cd_release(struct kref *);
+
+static void ide_cd_put(struct cdrom_info *cd)
+{
+	down(&idecd_ref_sem);
+	kref_put(&cd->kref, ide_cd_release);
+	up(&idecd_ref_sem);
+}
+
 /****************************************************************************
  * Generic packet command support and error handling routines.
  */
@@ -529,10 +557,13 @@
 /*
  * Initialize a ide-cd packet command request
  */
-static void cdrom_prepare_request(struct request *rq)
+static void cdrom_prepare_request(ide_drive_t *drive, struct request *rq)
 {
+	struct cdrom_info *cd = drive->driver_data;
+
 	ide_init_drive_cmd(rq);
 	rq->flags = REQ_PC;
+	rq->rq_disk = cd->disk;
 }
 
 static void cdrom_queue_request_sense(ide_drive_t *drive, void *sense,
@@ -545,7 +576,7 @@
 		sense = &info->sense_data;
 
 	/* stuff the sense request in front of our current request */
-	cdrom_prepare_request(rq);
+	cdrom_prepare_request(drive, rq);
 
 	rq->data = sense;
 	rq->cmd[0] = GPCMD_REQUEST_SENSE;
@@ -1829,7 +1860,7 @@
 static ide_startstop_t cdrom_start_write(ide_drive_t *drive, struct request *rq)
 {
 	struct cdrom_info *info = drive->driver_data;
-	struct gendisk *g = drive->disk;
+	struct gendisk *g = info->disk;
 	unsigned short sectors_per_frame = queue_hardsect_size(drive->queue) >> SECTOR_BITS;
 
 	/*
@@ -2021,7 +2052,7 @@
 	struct cdrom_info *info = drive->driver_data;
 	struct cdrom_device_info *cdi = &info->devinfo;
 
-	cdrom_prepare_request(&req);
+	cdrom_prepare_request(drive, &req);
 
 	req.sense = sense;
 	req.cmd[0] = GPCMD_TEST_UNIT_READY;
@@ -2053,7 +2084,7 @@
 	if (CDROM_CONFIG_FLAGS(drive)->no_doorlock) {
 		stat = 0;
 	} else {
-		cdrom_prepare_request(&req);
+		cdrom_prepare_request(drive, &req);
 		req.sense = sense;
 		req.cmd[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
 		req.cmd[4] = lockflag ? 1 : 0;
@@ -2097,7 +2128,7 @@
 	if (CDROM_STATE_FLAGS(drive)->door_locked && ejectflag)
 		return 0;
 
-	cdrom_prepare_request(&req);
+	cdrom_prepare_request(drive, &req);
 
 	/* only tell drive to close tray if open, if it can do that */
 	if (ejectflag && !CDROM_CONFIG_FLAGS(drive)->close_tray)
@@ -2121,7 +2152,7 @@
 	int stat;
 	struct request req;
 
-	cdrom_prepare_request(&req);
+	cdrom_prepare_request(drive, &req);
 
 	req.sense = sense;
 	req.cmd[0] = GPCMD_READ_CDVD_CAPACITY;
@@ -2144,7 +2175,7 @@
 {
 	struct request req;
 
-	cdrom_prepare_request(&req);
+	cdrom_prepare_request(drive, &req);
 
 	req.sense = sense;
 	req.data =  buf;
@@ -2201,7 +2232,7 @@
 	if (stat)
 		toc->capacity = 0x1fffff;
 
-	set_capacity(drive->disk, toc->capacity * sectors_per_frame);
+	set_capacity(info->disk, toc->capacity * sectors_per_frame);
 	blk_queue_hardsect_size(drive->queue,
 				sectors_per_frame << SECTOR_BITS);
 
@@ -2321,7 +2352,7 @@
 	stat = cdrom_get_last_written(cdi, &last_written);
 	if (!stat && (last_written > toc->capacity)) {
 		toc->capacity = last_written;
-		set_capacity(drive->disk, toc->capacity * sectors_per_frame);
+		set_capacity(info->disk, toc->capacity * sectors_per_frame);
 	}
 
 	/* Remember that we've read this stuff. */
@@ -2336,7 +2367,7 @@
 {
 	struct request req;
 
-	cdrom_prepare_request(&req);
+	cdrom_prepare_request(drive, &req);
 
 	req.sense = sense;
 	req.data = buf;
@@ -2356,7 +2387,7 @@
 			      struct request_sense *sense)
 {
 	struct request req;
-	cdrom_prepare_request(&req);
+	cdrom_prepare_request(drive, &req);
 
 	req.sense = sense;
 	if (speed == 0)
@@ -2386,7 +2417,7 @@
 	struct request_sense sense;
 	struct request req;
 
-	cdrom_prepare_request(&req);
+	cdrom_prepare_request(drive, &req);
 
 	req.sense = &sense;
 	req.cmd[0] = GPCMD_PLAY_AUDIO_MSF;
@@ -2436,7 +2467,7 @@
 	/* here we queue the commands from the uniform CD-ROM
 	   layer. the packet must be complete, as we do not
 	   touch it at all. */
-	cdrom_prepare_request(&req);
+	cdrom_prepare_request(drive, &req);
 	memcpy(req.cmd, cgc->cmd, CDROM_PACKET_SIZE);
 	if (cgc->sense)
 		memset(cgc->sense, 0, sizeof(struct request_sense));
@@ -2586,7 +2617,7 @@
 	struct request req;
 	int ret;
 
-	cdrom_prepare_request(&req);
+	cdrom_prepare_request(drive, &req);
 	req.flags = REQ_SPECIAL | REQ_QUIET;
 	ret = ide_do_drive_cmd(drive, &req, ide_wait);
 
@@ -2830,7 +2861,7 @@
 	if (!CDROM_CONFIG_FLAGS(drive)->mo_drive)
 		devinfo->mask |= CDC_MO_DRIVE;
 
-	devinfo->disk = drive->disk;
+	devinfo->disk = info->disk;
 	return register_cdrom(devinfo);
 }
 
@@ -3088,7 +3119,6 @@
 		drive->queue->unplug_delay = 1;
 
 	drive->special.all	= 0;
-	drive->ready_stat	= 0;
 
 	CDROM_STATE_FLAGS(drive)->media_changed = 1;
 	CDROM_STATE_FLAGS(drive)->toc_valid     = 0;
@@ -3193,6 +3223,9 @@
 	 */
 	blk_queue_hardsect_size(drive->queue, CD_FRAMESIZE);
 
+	if (drive->autotune == IDE_TUNE_DEFAULT ||
+	    drive->autotune == IDE_TUNE_AUTO)
+		drive->dsc_overlap = (drive->next != drive);
 #if 0
 	drive->dsc_overlap = (HWIF(drive)->no_dsc) ? 0 : 1;
 	if (HWIF(drive)->no_dsc) {
@@ -3226,14 +3259,27 @@
 int ide_cdrom_cleanup(ide_drive_t *drive)
 {
 	struct cdrom_info *info = drive->driver_data;
-	struct cdrom_device_info *devinfo = &info->devinfo;
-	struct gendisk *g = drive->disk;
 
 	if (ide_unregister_subdriver(drive)) {
 		printk(KERN_ERR "%s: %s: failed to ide_unregister_subdriver\n",
 			__FUNCTION__, drive->name);
 		return 1;
 	}
+
+	del_gendisk(info->disk);
+
+	ide_cd_put(info);
+
+	return 0;
+}
+
+static void ide_cd_release(struct kref *kref)
+{
+	struct cdrom_info *info = to_ide_cd(kref);
+	struct cdrom_device_info *devinfo = &info->devinfo;
+	ide_drive_t *drive = info->drive;
+	struct gendisk *g = info->disk;
+
 	if (info->buffer != NULL)
 		kfree(info->buffer);
 	if (info->toc != NULL)
@@ -3241,56 +3287,37 @@
 	if (info->changer_info != NULL)
 		kfree(info->changer_info);
 	if (devinfo->handle == drive && unregister_cdrom(devinfo))
-		printk(KERN_ERR "%s: ide_cdrom_cleanup failed to unregister device from the cdrom driver.\n", drive->name);
-	kfree(info);
+		printk(KERN_ERR "%s: %s failed to unregister device from the cdrom "
+				"driver.\n", __FUNCTION__, drive->name);
+	drive->dsc_overlap = 0;
 	drive->driver_data = NULL;
 	blk_queue_prep_rq(drive->queue, NULL);
-	del_gendisk(g);
-	g->fops = ide_fops;
-	return 0;
+	g->private_data = NULL;
+	put_disk(g);
+	kfree(info);
 }
 
 static int ide_cdrom_attach (ide_drive_t *drive);
 
-/*
- * Power Management state machine.
- *
- * We don't do much for CDs right now.
- */
-
-static void ide_cdrom_complete_power_step (ide_drive_t *drive, struct request *rq, u8 stat, u8 error)
+#ifdef CONFIG_PROC_FS
+static int proc_idecd_read_capacity
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
-}
-
-static ide_startstop_t ide_cdrom_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 ide_pm_state_start_suspend:
-		break;
+	ide_drive_t*drive = (ide_drive_t *)data;
+	int len;
 
-	case ide_pm_state_start_resume:	/* Resume step 1 (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;
+	len = sprintf(page,"%llu\n", (long long)ide_cdrom_capacity(drive));
+	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
+static ide_proc_entry_t idecd_proc[] = {
+	{ "capacity", S_IFREG|S_IRUGO, proc_idecd_read_capacity, NULL },
+	{ NULL, 0, NULL, NULL }
+};
+#else
+# define idecd_proc	NULL
+#endif
+
 static ide_driver_t ide_cdrom_driver = {
 	.owner			= THIS_MODULE,
 	.name			= "ide-cdrom",
@@ -3300,18 +3327,26 @@
 	.supports_dsc_overlap	= 1,
 	.cleanup		= ide_cdrom_cleanup,
 	.do_request		= ide_do_rw_cdrom,
-	.capacity		= ide_cdrom_capacity,
+	.end_request		= ide_end_request,
+	.error			= __ide_error,
+	.abort			= __ide_abort,
+	.proc			= idecd_proc,
 	.attach			= ide_cdrom_attach,
 	.drives			= LIST_HEAD_INIT(ide_cdrom_driver.drives),
-	.start_power_step	= ide_cdrom_start_power_step,
-	.complete_power_step	= ide_cdrom_complete_power_step,
 };
 
 static int idecd_open(struct inode * inode, struct file * file)
 {
-	ide_drive_t *drive = inode->i_bdev->bd_disk->private_data;
-	struct cdrom_info *info = drive->driver_data;
+	struct gendisk *disk = inode->i_bdev->bd_disk;
+	struct cdrom_info *info;
+	ide_drive_t *drive;
 	int rc = -ENOMEM;
+
+	if (!(info = ide_cd_get(disk)))
+		return -ENXIO;
+
+	drive = info->drive;
+
 	drive->usage++;
 
 	if (!info->buffer)
@@ -3319,16 +3354,24 @@
 					GFP_KERNEL|__GFP_REPEAT);
         if (!info->buffer || (rc = cdrom_open(&info->devinfo, inode, file)))
 		drive->usage--;
+
+	if (rc < 0)
+		ide_cd_put(info);
+
 	return rc;
 }
 
 static int idecd_release(struct inode * inode, struct file * file)
 {
-	ide_drive_t *drive = inode->i_bdev->bd_disk->private_data;
-	struct cdrom_info *info = drive->driver_data;
+	struct gendisk *disk = inode->i_bdev->bd_disk;
+	struct cdrom_info *info = ide_cd_g(disk);
+	ide_drive_t *drive = info->drive;
 
 	cdrom_release (&info->devinfo, file);
 	drive->usage--;
+
+	ide_cd_put(info);
+
 	return 0;
 }
 
@@ -3336,27 +3379,27 @@
 			unsigned int cmd, unsigned long arg)
 {
 	struct block_device *bdev = inode->i_bdev;
-	ide_drive_t *drive = bdev->bd_disk->private_data;
-	int err = generic_ide_ioctl(file, bdev, cmd, arg);
-	if (err == -EINVAL) {
-		struct cdrom_info *info = drive->driver_data;
+	struct cdrom_info *info = ide_cd_g(bdev->bd_disk);
+	int err;
+
+	err  = generic_ide_ioctl(info->drive, file, bdev, cmd, arg);
+	if (err == -EINVAL)
 		err = cdrom_ioctl(file, &info->devinfo, inode, cmd, arg);
-	}
+
 	return err;
 }
 
 static int idecd_media_changed(struct gendisk *disk)
 {
-	ide_drive_t *drive = disk->private_data;
-	struct cdrom_info *info = drive->driver_data;
+	struct cdrom_info *info = ide_cd_g(disk);
 	return cdrom_media_changed(&info->devinfo);
 }
 
 static int idecd_revalidate_disk(struct gendisk *disk)
 {
-	ide_drive_t *drive = disk->private_data;
+	struct cdrom_info *info = ide_cd_g(disk);
 	struct request_sense sense;
-	cdrom_read_toc(drive, &sense);
+	cdrom_read_toc(info->drive, &sense);
 	return  0;
 }
 
@@ -3378,7 +3421,7 @@
 static int ide_cdrom_attach (ide_drive_t *drive)
 {
 	struct cdrom_info *info;
-	struct gendisk *g = drive->disk;
+	struct gendisk *g;
 	struct request_sense sense;
 
 	if (!strstr("ide-cdrom", drive->driver_req))
@@ -3403,14 +3446,30 @@
 		printk(KERN_ERR "%s: Can't allocate a cdrom structure\n", drive->name);
 		goto failed;
 	}
+
+	g = alloc_disk(1 << PARTN_BITS);
+	if (!g)
+		goto out_free_cd;
+
+	ide_init_disk(g, drive);
+
 	if (ide_register_subdriver(drive, &ide_cdrom_driver)) {
 		printk(KERN_ERR "%s: Failed to register the driver with ide.c\n",
 			drive->name);
-		kfree(info);
-		goto failed;
+		goto out_put_disk;
 	}
 	memset(info, 0, sizeof (struct cdrom_info));
+
+	kref_init(&info->kref);
+
+	info->drive = drive;
+	info->driver = &ide_cdrom_driver;
+	info->disk = g;
+
+	g->private_data = &info->driver;
+
 	drive->driver_data = info;
+
 	DRIVER(drive)->busy++;
 	g->minors = 1;
 	snprintf(g->devfs_name, sizeof(g->devfs_name),
@@ -3440,6 +3499,11 @@
 	g->flags |= GENHD_FL_REMOVABLE;
 	add_disk(g);
 	return 0;
+
+out_put_disk:
+	put_disk(g);
+out_free_cd:
+	kfree(info);
 failed:
 	return 1;
 }
diff -Nru a/drivers/ide/ide-cd.h b/drivers/ide/ide-cd.h
--- a/drivers/ide/ide-cd.h	2005-03-07 15:22:36 -08:00
+++ b/drivers/ide/ide-cd.h	2005-03-07 15:22:36 -08:00
@@ -460,6 +460,10 @@
 
 /* Extra per-device info for cdrom drives. */
 struct cdrom_info {
+	ide_drive_t	*drive;
+	ide_driver_t	*driver;
+	struct gendisk	*disk;
+	struct kref	kref;
 
 	/* Buffer for table of contents.  NULL if we haven't allocated
 	   a TOC buffer for this device yet. */
diff -Nru a/drivers/ide/ide-default.c b/drivers/ide/ide-default.c
--- a/drivers/ide/ide-default.c	2005-03-07 15:22:36 -08:00
+++ /dev/null	Wed Dec 31 16:00:00 196900
@@ -1,73 +0,0 @@
-/*
- *	ide-default		-	Driver for unbound ide devices
- *
- *	This provides a clean way to bind a device to default operations
- *	by having an actual driver class that rather than special casing
- *	"no driver" all over the IDE code
- *
- *	Copyright (C) 2003, Red Hat <alan@redhat.com>
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/genhd.h>
-#include <linux/slab.h>
-#include <linux/cdrom.h>
-#include <linux/ide.h>
-#include <linux/bitops.h>
-
-#include <asm/byteorder.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/unaligned.h>
-
-#define IDEDEFAULT_VERSION	"0.9.newide"
-/*
- *	Driver initialization.
- */
-
-static int idedefault_attach(ide_drive_t *drive);
-
-/*
- *	IDE subdriver functions, registered with ide.c
- */
-
-ide_driver_t idedefault_driver = {
-	.name		=	"ide-default",
-	.version	=	IDEDEFAULT_VERSION,
-	.attach		=	idedefault_attach,
-	.cleanup	=	ide_unregister_subdriver,
-	.drives		=	LIST_HEAD_INIT(idedefault_driver.drives)
-};
-
-static int idedefault_attach (ide_drive_t *drive)
-{
-	if (ide_register_subdriver(drive, &idedefault_driver)) {
-		printk(KERN_ERR "ide-default: %s: Failed to register the "
-			"driver with ide.c\n", drive->name);
-		return 1;
-	}
-	
-	/* For the sake of the request layer, we must make sure we have a
-	 * correct ready_stat value, that is 0 for ATAPI devices or we will
-	 * fail any request like Power Management
-	 */
-	if (drive->media != ide_disk)
-		drive->ready_stat = 0;
-
-	return 0;
-}
-
-MODULE_DESCRIPTION("IDE Default Driver");
-
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
--- a/drivers/ide/ide-disk.c	2005-03-07 15:22:36 -08:00
+++ b/drivers/ide/ide-disk.c	2005-03-07 15:22:36 -08:00
@@ -71,6 +71,41 @@
 #include <asm/io.h>
 #include <asm/div64.h>
 
+struct ide_disk_obj {
+	ide_drive_t	*drive;
+	ide_driver_t	*driver;
+	struct gendisk	*disk;
+	struct kref	kref;
+};
+
+static DECLARE_MUTEX(idedisk_ref_sem);
+
+#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;
+
+	down(&idedisk_ref_sem);
+	idkp = ide_disk_g(disk);
+	if (idkp)
+		kref_get(&idkp->kref);
+	up(&idedisk_ref_sem);
+	return idkp;
+}
+
+static void ide_disk_release(struct kref *);
+
+static void ide_disk_put(struct ide_disk_obj *idkp)
+{
+	down(&idedisk_ref_sem);
+	kref_put(&idkp->kref, ide_disk_release);
+	up(&idedisk_ref_sem);
+}
+
 /*
  * lba_capacity_is_ok() performs a sanity check on the claimed "lba_capacity"
  * value for this drive (from its reported identification information).
@@ -325,6 +360,9 @@
 	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_READ_NATIVE_MAX_EXT;
 	args.command_type			= IDE_DRIVE_TASK_NO_DATA;
 	args.handler				= &task_no_data_intr;
+
+	args.flags |= ATA_TFLAG_LBA48;
+
         /* submit command request */
         ide_raw_taskfile(drive, &args, NULL);
 
@@ -394,6 +432,9 @@
 	args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80);
 	args.command_type			= IDE_DRIVE_TASK_NO_DATA;
 	args.handler				= &task_no_data_intr;
+
+	args.flags |= ATA_TFLAG_LBA48;
+
 	/* submit command request */
 	ide_raw_taskfile(drive, &args, NULL);
 	/* if OK, compute maximum address value */
@@ -514,75 +555,6 @@
 	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 +618,16 @@
 	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 +668,7 @@
 
 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 },
@@ -790,9 +773,10 @@
 	ide_task_t args;
 
 	memset(&args, 0, sizeof(ide_task_t));
-	if (ide_id_has_flush_cache_ext(drive->id))
+	if (ide_id_has_flush_cache_ext(drive->id)) {
 		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_FLUSH_CACHE_EXT;
-	else
+		args.flags |= ATA_TFLAG_LBA48;
+	} else
 		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_FLUSH_CACHE;
 	args.command_type			= IDE_DRIVE_TASK_NO_DATA;
 	args.handler				= &task_no_data_intr;
@@ -852,90 +836,6 @@
  	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;
@@ -974,28 +874,6 @@
 
 	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,21 +937,6 @@
 		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? */
@@ -1117,16 +980,32 @@
 
 static int idedisk_cleanup (ide_drive_t *drive)
 {
-	struct gendisk *g = drive->disk;
+	struct ide_disk_obj *idkp = drive->driver_data;
+	struct gendisk *g = idkp->disk;
+
 	ide_cacheflush_p(drive);
 	if (ide_unregister_subdriver(drive))
 		return 1;
 	del_gendisk(g);
-	drive->devfs_name[0] = '\0';
-	g->fops = ide_fops;
+
+	ide_disk_put(idkp);
+
 	return 0;
 }
 
+static void ide_disk_release(struct kref *kref)
+{
+	struct ide_disk_obj *idkp = to_ide_disk(kref);
+	ide_drive_t *drive = idkp->drive;
+	struct gendisk *g = idkp->disk;
+
+	drive->driver_data = NULL;
+	drive->devfs_name[0] = '\0';
+	g->private_data = NULL;
+	put_disk(g);
+	kfree(idkp);
+}
+
 static int idedisk_attach(ide_drive_t *drive);
 
 static void ide_device_shutdown(struct device *dev)
@@ -1172,19 +1051,25 @@
 	.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 +1091,10 @@
 
 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 +1107,9 @@
 			drive->doorlocking = 0;
 	}
 	drive->usage--;
+
+	ide_disk_put(idkp);
+
 	return 0;
 }
 
@@ -1226,12 +1117,14 @@
 			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 +1137,8 @@
 
 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;
 }
 
@@ -1262,7 +1155,8 @@
 
 static int idedisk_attach(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,10 +1166,33 @@
 	if (drive->media != ide_disk)
 		goto failed;
 
+	idkp = kmalloc(sizeof(*idkp), GFP_KERNEL);
+	if (!idkp)
+		goto failed;
+
+	g = alloc_disk(1 << PARTN_BITS);
+	if (!g)
+		goto out_free_idkp;
+
+	ide_init_disk(g, drive);
+
 	if (ide_register_subdriver(drive, &idedisk_driver)) {
 		printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name);
-		goto failed;
+		goto out_put_disk;
 	}
+
+	memset(idkp, 0, sizeof(*idkp));
+
+	kref_init(&idkp->kref);
+
+	idkp->drive = drive;
+	idkp->driver = &idedisk_driver;
+	idkp->disk = g;
+
+	g->private_data = &idkp->driver;
+
+	drive->driver_data = idkp;
+
 	DRIVER(drive)->busy++;
 	idedisk_setup(drive);
 	if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
@@ -1293,6 +1210,11 @@
 	g->fops = &idedisk_ops;
 	add_disk(g);
 	return 0;
+
+out_put_disk:
+	put_disk(g);
+out_free_idkp:
+	kfree(idkp);
 failed:
 	return 1;
 }
diff -Nru a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
--- a/drivers/ide/ide-dma.c	2005-03-07 15:22:36 -08:00
+++ b/drivers/ide/ide-dma.c	2005-03-07 15:22:36 -08:00
@@ -175,8 +175,10 @@
 	if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
 		if (!dma_stat) {
 			struct request *rq = HWGROUP(drive)->rq;
+			ide_driver_t *drv;
 
-			DRIVER(drive)->end_request(drive, 1, rq->nr_sectors);
+			drv = *(ide_driver_t **)rq->rq_disk->private_data;;
+			drv->end_request(drive, 1, rq->nr_sectors);
 			return ide_stopped;
 		}
 		printk(KERN_ERR "%s: dma_intr: bad DMA status (dma_stat=%x)\n", 
diff -Nru a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
--- a/drivers/ide/ide-floppy.c	2005-03-07 15:22:36 -08:00
+++ b/drivers/ide/ide-floppy.c	2005-03-07 15:22:36 -08:00
@@ -274,8 +274,11 @@
  *	driver due to an interrupt or a timer event is stored in a variable
  *	of type idefloppy_floppy_t, defined below.
  */
-typedef struct {
-	ide_drive_t *drive;
+typedef struct ide_floppy_obj {
+	ide_drive_t	*drive;
+	ide_driver_t	*driver;
+	struct gendisk	*disk;
+	struct kref	kref;
 
 	/* Current packet command */
 	idefloppy_pc_t *pc;
@@ -514,6 +517,34 @@
 	u8		reserved[4];
 } idefloppy_mode_parameter_header_t;
 
+static DECLARE_MUTEX(idefloppy_ref_sem);
+
+#define to_ide_floppy(obj) container_of(obj, struct ide_floppy_obj, kref)
+
+#define ide_floppy_g(disk) \
+	container_of((disk)->private_data, struct ide_floppy_obj, driver)
+
+static struct ide_floppy_obj *ide_floppy_get(struct gendisk *disk)
+{
+	struct ide_floppy_obj *floppy = NULL;
+
+	down(&idefloppy_ref_sem);
+	floppy = ide_floppy_g(disk);
+	if (floppy)
+		kref_get(&floppy->kref);
+	up(&idefloppy_ref_sem);
+	return floppy;
+}
+
+static void ide_floppy_release(struct kref *);
+
+static void ide_floppy_put(struct ide_floppy_obj *floppy)
+{
+	down(&idefloppy_ref_sem);
+	kref_put(&floppy->kref, ide_floppy_release);
+	up(&idefloppy_ref_sem);
+}
+
 /*
  *	Too bad. The drive wants to send us data which we are not ready to accept.
  *	Just throw it away.
@@ -652,9 +683,12 @@
  */
 static void idefloppy_queue_pc_head (ide_drive_t *drive,idefloppy_pc_t *pc,struct request *rq)
 {
+	struct ide_floppy_obj *floppy = drive->driver_data;
+
 	ide_init_drive_cmd(rq);
 	rq->buffer = (char *) pc;
 	rq->flags = REQ_SPECIAL;	//rq->cmd = IDEFLOPPY_PC_RQ;
+	rq->rq_disk = floppy->disk;
 	(void) ide_do_drive_cmd(drive, rq, ide_preempt);
 }
 
@@ -1246,7 +1280,8 @@
 	unsigned long block = (unsigned long)block_s;
 
 	debug_log(KERN_INFO "rq_status: %d, dev: %s, flags: %lx, errors: %d\n",
-			rq->rq_status, rq->rq_disk->disk_name,
+			rq->rq_status,
+			rq->rq_disk ? rq->rq_disk->disk_name ? "?",
 			rq->flags, rq->errors);
 	debug_log(KERN_INFO "sector: %ld, nr_sectors: %ld, "
 			"current_nr_sectors: %d\n", (long)rq->sector,
@@ -1301,11 +1336,13 @@
  */
 static int idefloppy_queue_pc_tail (ide_drive_t *drive,idefloppy_pc_t *pc)
 {
+	struct ide_floppy_obj *floppy = drive->driver_data;
 	struct request rq;
 
 	ide_init_drive_cmd (&rq);
 	rq.buffer = (char *) pc;
 	rq.flags = REQ_SPECIAL;		//	rq.cmd = IDEFLOPPY_PC_RQ;
+	rq.rq_disk = floppy->disk;
 
 	return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
@@ -1330,7 +1367,7 @@
 	}
 	header = (idefloppy_mode_parameter_header_t *) pc.buffer;
 	floppy->wp = header->wp;
-	set_disk_ro(drive->disk, floppy->wp);
+	set_disk_ro(floppy->disk, floppy->wp);
 	page = (idefloppy_flexible_disk_page_t *) (header + 1);
 
 	page->transfer_rate = ntohs(page->transfer_rate);
@@ -1396,7 +1433,7 @@
 	drive->bios_cyl = 0;
 	drive->bios_head = drive->bios_sect = 0;
 	floppy->blocks = floppy->bs_factor = 0;
-	set_capacity(drive->disk, 0);
+	set_capacity(floppy->disk, 0);
 
 	idefloppy_create_read_capacity_cmd(&pc);
 	if (idefloppy_queue_pc_tail(drive, &pc)) {
@@ -1470,7 +1507,7 @@
 		(void) idefloppy_get_flexible_disk_page(drive);
 	}
 
-	set_capacity(drive->disk, floppy->blocks * floppy->bs_factor);
+	set_capacity(floppy->disk, floppy->blocks * floppy->bs_factor);
 	return rc;
 }
 
@@ -1792,10 +1829,6 @@
 	struct idefloppy_id_gcw gcw;
 
 	*((u16 *) &gcw) = drive->id->config;
-	drive->driver_data = floppy;
-	drive->ready_stat = 0;
-	memset(floppy, 0, sizeof(idefloppy_floppy_t));
-	floppy->drive = drive;
 	floppy->pc = floppy->pc_stack;
 	if (gcw.drq_type == 1)
 		set_bit(IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags);
@@ -1835,20 +1868,44 @@
 static int idefloppy_cleanup (ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
-	struct gendisk *g = drive->disk;
+	struct gendisk *g = floppy->disk;
 
 	if (ide_unregister_subdriver(drive))
 		return 1;
-	drive->driver_data = NULL;
-	kfree(floppy);
+
 	del_gendisk(g);
-	g->fops = ide_fops;
+
+	ide_floppy_put(floppy);
+
 	return 0;
 }
 
+static void ide_floppy_release(struct kref *kref)
+{
+	struct ide_floppy_obj *floppy = to_ide_floppy(kref);
+	ide_drive_t *drive = floppy->drive;
+	struct gendisk *g = floppy->disk;
+
+	drive->driver_data = NULL;
+	g->private_data = NULL;
+	put_disk(g);
+	kfree(floppy);
+}
+
 #ifdef CONFIG_PROC_FS
 
+static int proc_idefloppy_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)idefloppy_capacity(drive));
+	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
 static ide_proc_entry_t idefloppy_proc[] = {
+	{ "capacity",	S_IFREG|S_IRUGO,	proc_idefloppy_read_capacity, NULL },
 	{ "geometry",	S_IFREG|S_IRUGO,	proc_ide_read_geometry,	NULL },
 	{ NULL, 0, NULL, NULL }
 };
@@ -1874,7 +1931,8 @@
 	.cleanup		= idefloppy_cleanup,
 	.do_request		= idefloppy_do_request,
 	.end_request		= idefloppy_do_end_request,
-	.capacity		= idefloppy_capacity,
+	.error			= __ide_error,
+	.abort			= __ide_abort,
 	.proc			= idefloppy_proc,
 	.attach			= idefloppy_attach,
 	.drives			= LIST_HEAD_INIT(idefloppy_driver.drives),
@@ -1882,14 +1940,21 @@
 
 static int idefloppy_open(struct inode *inode, struct file *filp)
 {
-	ide_drive_t *drive = inode->i_bdev->bd_disk->private_data;
-	idefloppy_floppy_t *floppy = drive->driver_data;
+	struct gendisk *disk = inode->i_bdev->bd_disk;
+	struct ide_floppy_obj *floppy;
+	ide_drive_t *drive;
 	idefloppy_pc_t pc;
+	int ret = 0;
 
-	drive->usage++;
-	
 	debug_log(KERN_INFO "Reached idefloppy_open\n");
 
+	if (!(floppy = ide_floppy_get(disk)))
+		return -ENXIO;
+
+	drive = floppy->drive;
+
+	drive->usage++;
+
 	if (drive->usage == 1) {
 		clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags);
 		/* Just in case */
@@ -1909,13 +1974,15 @@
 		    */
 		    ) {
 			drive->usage--;
-			return -EIO;
+			ret = -EIO;
+			goto out_put_floppy;
 		}
 
 		if (floppy->wp && (filp->f_mode & 2)) {
 			drive->usage--;
-			return -EROFS;
-		}		
+			ret = -EROFS;
+			goto out_put_floppy;
+		}
 		set_bit(IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
 		/* IOMEGA Clik! drives do not support lock/unlock commands */
                 if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
@@ -1925,21 +1992,26 @@
 		check_disk_change(inode->i_bdev);
 	} else if (test_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags)) {
 		drive->usage--;
-		return -EBUSY;
+		ret = -EBUSY;
+		goto out_put_floppy;
 	}
 	return 0;
+
+out_put_floppy:
+	ide_floppy_put(floppy);
+	return ret;
 }
 
 static int idefloppy_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_floppy_obj *floppy = ide_floppy_g(disk);
+	ide_drive_t *drive = floppy->drive;
 	idefloppy_pc_t pc;
 	
 	debug_log(KERN_INFO "Reached idefloppy_release\n");
 
 	if (drive->usage == 1) {
-		idefloppy_floppy_t *floppy = drive->driver_data;
-
 		/* IOMEGA Clik! drives do not support lock/unlock commands */
                 if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
 			idefloppy_create_prevent_cmd(&pc, 0);
@@ -1949,6 +2021,9 @@
 		clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags);
 	}
 	drive->usage--;
+
+	ide_floppy_put(floppy);
+
 	return 0;
 }
 
@@ -1956,10 +2031,10 @@
 			unsigned int cmd, unsigned long arg)
 {
 	struct block_device *bdev = inode->i_bdev;
-	ide_drive_t *drive = bdev->bd_disk->private_data;
-	idefloppy_floppy_t *floppy = drive->driver_data;
+	struct ide_floppy_obj *floppy = ide_floppy_g(bdev->bd_disk);
+	ide_drive_t *drive = floppy->drive;
 	void __user *argp = (void __user *)arg;
-	int err = generic_ide_ioctl(file, bdev, cmd, arg);
+	int err = generic_ide_ioctl(drive, file, bdev, cmd, arg);
 	int prevent = (arg) ? 1 : 0;
 	idefloppy_pc_t pc;
 	if (err != -EINVAL)
@@ -2020,8 +2095,8 @@
 
 static int idefloppy_media_changed(struct gendisk *disk)
 {
-	ide_drive_t *drive = disk->private_data;
-	idefloppy_floppy_t *floppy = drive->driver_data;
+	struct ide_floppy_obj *floppy = ide_floppy_g(disk);
+	ide_drive_t *drive = floppy->drive;
 
 	/* do not scan partitions twice if this is a removable device */
 	if (drive->attach) {
@@ -2033,8 +2108,8 @@
 
 static int idefloppy_revalidate_disk(struct gendisk *disk)
 {
-	ide_drive_t *drive = disk->private_data;
-	set_capacity(disk, idefloppy_capacity(drive));
+	struct ide_floppy_obj *floppy = ide_floppy_g(disk);
+	set_capacity(disk, idefloppy_capacity(floppy->drive));
 	return 0;
 }
 
@@ -2050,7 +2125,8 @@
 static int idefloppy_attach (ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy;
-	struct gendisk *g = drive->disk;
+	struct gendisk *g;
+
 	if (!strstr("ide-floppy", drive->driver_req))
 		goto failed;
 	if (!drive->present)
@@ -2069,11 +2145,30 @@
 		printk (KERN_ERR "ide-floppy: %s: Can't allocate a floppy structure\n", drive->name);
 		goto failed;
 	}
+
+	g = alloc_disk(1 << PARTN_BITS);
+	if (!g)
+		goto out_free_floppy;
+
+	ide_init_disk(g, drive);
+
 	if (ide_register_subdriver(drive, &idefloppy_driver)) {
 		printk (KERN_ERR "ide-floppy: %s: Failed to register the driver with ide.c\n", drive->name);
-		kfree (floppy);
-		goto failed;
+		goto out_put_disk;
 	}
+
+	memset(floppy, 0, sizeof(*floppy));
+
+	kref_init(&floppy->kref);
+
+	floppy->drive = drive;
+	floppy->driver = &idefloppy_driver;
+	floppy->disk = g;
+
+	g->private_data = &floppy->driver;
+
+	drive->driver_data = floppy;
+
 	DRIVER(drive)->busy++;
 	idefloppy_setup (drive, floppy);
 	DRIVER(drive)->busy--;
@@ -2085,6 +2180,11 @@
 	drive->attach = 1;
 	add_disk(g);
 	return 0;
+
+out_put_disk:
+	put_disk(g);
+out_free_floppy:
+	kfree(floppy);
 failed:
 	return 1;
 }
diff -Nru a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
--- a/drivers/ide/ide-io.c	2005-03-07 15:22:36 -08:00
+++ b/drivers/ide/ide-io.c	2005-03-07 15:22:36 -08:00
@@ -189,6 +189,100 @@
 }
 EXPORT_SYMBOL(ide_end_request);
 
+/*
+ * 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 {
+	ide_pm_flush_cache	= ide_pm_state_start_suspend,
+	idedisk_pm_standby,
+
+	idedisk_pm_idle		= ide_pm_state_start_resume,
+	ide_pm_restore_dma,
+};
+
+static void ide_complete_power_step(ide_drive_t *drive, struct request *rq, u8 stat, u8 error)
+{
+	if (drive->media != ide_disk)
+		return;
+
+	switch (rq->pm->pm_step) {
+	case ide_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 = ide_pm_restore_dma;
+		break;
+	}
+}
+
+static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq)
+{
+	ide_task_t *args = rq->special;
+
+	memset(args, 0, sizeof(*args));
+
+	if (drive->media != ide_disk) {
+		/* skip idedisk_pm_idle for ATAPI devices */
+		if (rq->pm->pm_step == idedisk_pm_idle)
+			rq->pm->pm_step = ide_pm_restore_dma;
+	}
+
+	switch (rq->pm->pm_step) {
+	case ide_pm_flush_cache:	/* Suspend step 1 (flush cache) */
+		if (drive->media != ide_disk)
+			break;
+		/* Not supported? Switch to next step now. */
+		if (!drive->wcache || !ide_id_has_flush_cache(drive->id)) {
+			ide_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;
+			args->flags |= ATA_TFLAG_LBA48;
+		} 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 ide_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...
+		 */
+		if ((drive->id->capability & 1) == 0)
+			break;
+		if (drive->hwif->ide_dma_check == NULL)
+			break;
+		drive->hwif->ide_dma_check(drive);
+		break;
+	}
+	rq->pm->pm_step = ide_pm_state_completed;
+	return ide_stopped;
+}
+
 /**
  *	ide_complete_pm_request - end the current Power Management request
  *	@drive: target drive
@@ -395,7 +489,7 @@
 			args->tfRegister[IDE_SELECT_OFFSET]  = hwif->INB(IDE_SELECT_REG);
 			args->tfRegister[IDE_STATUS_OFFSET]  = stat;
 
-			if (drive->addressing == 1) {
+			if (args->flags & ATA_TFLAG_LBA48) {
 				hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG);
 				args->hobRegister[IDE_FEATURE_OFFSET]	= hwif->INB(IDE_FEATURE_REG);
 				args->hobRegister[IDE_NSECTOR_OFFSET]	= hwif->INB(IDE_NSECTOR_REG);
@@ -409,7 +503,7 @@
 		printk("%s: complete_power_step(step: %d, stat: %x, err: %x)\n",
 			drive->name, rq->pm->pm_step, stat, err);
 #endif
-		DRIVER(drive)->complete_power_step(drive, rq, stat, err);
+		ide_complete_power_step(drive, rq, stat, err);
 		if (rq->pm->pm_step == ide_pm_state_completed)
 			ide_complete_pm_request(drive, rq);
 		return;
@@ -453,6 +547,17 @@
 	}
 }
 
+static void ide_kill_rq(ide_drive_t *drive, struct request *rq)
+{
+	if (rq->rq_disk) {
+		ide_driver_t *drv;
+
+		drv = *(ide_driver_t **)rq->rq_disk->private_data;
+		drv->end_request(drive, 0, 0);
+	} else
+		ide_end_request(drive, 0, 0);
+}
+
 static ide_startstop_t ide_ata_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err)
 {
 	ide_hwif_t *hwif = drive->hwif;
@@ -487,7 +592,7 @@
 		hwif->OUTB(WIN_IDLEIMMEDIATE, IDE_COMMAND_REG);
 
 	if (rq->errors >= ERROR_MAX || blk_noretry_request(rq))
-		drive->driver->end_request(drive, 0, 0);
+		ide_kill_rq(drive, rq);
 	else {
 		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
 			++rq->errors;
@@ -516,7 +621,7 @@
 		hwif->OUTB(WIN_IDLEIMMEDIATE, IDE_COMMAND_REG);
 
 	if (rq->errors >= ERROR_MAX) {
-		drive->driver->end_request(drive, 0, 0);
+		ide_kill_rq(drive, rq);
 	} else {
 		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
 			++rq->errors;
@@ -536,6 +641,8 @@
 	return ide_atapi_error(drive, rq, stat, err);
 }
 
+EXPORT_SYMBOL_GPL(__ide_error);
+
 /**
  *	ide_error	-	handle an error on the IDE
  *	@drive: drive the error occurred on
@@ -566,7 +673,13 @@
 		return ide_stopped;
 	}
 
-	return drive->driver->error(drive, rq, stat, err);
+	if (rq->rq_disk) {
+		ide_driver_t *drv;
+
+		drv = *(ide_driver_t **)rq->rq_disk->private_data;
+		return drv->error(drive, rq, stat, err);
+	} else
+		return __ide_error(drive, rq, stat, err);
 }
 
 EXPORT_SYMBOL_GPL(ide_error);
@@ -576,10 +689,13 @@
 	if (drive->media != ide_disk)
 		rq->errors |= ERROR_RESET;
 
-	DRIVER(drive)->end_request(drive, 0, 0);
+	ide_kill_rq(drive, rq);
+
 	return ide_stopped;
 }
 
+EXPORT_SYMBOL_GPL(__ide_abort);
+
 /**
  *	ide_abort	-	abort pending IDE operatins
  *	@drive: drive the error occurred on
@@ -608,7 +724,13 @@
 		return ide_stopped;
 	}
 
-	return drive->driver->abort(drive, rq);
+	if (rq->rq_disk) {
+		ide_driver_t *drv;
+
+		drv = *(ide_driver_t **)rq->rq_disk->private_data;
+		return drv->abort(drive, rq);
+	} else
+		return __ide_abort(drive, rq);
 }
 
 /**
@@ -661,13 +783,72 @@
 			udelay(100);
 	}
 
-	if (!OK_STAT(stat, READY_STAT, BAD_STAT) && DRIVER(drive) != NULL)
+	if (!OK_STAT(stat, READY_STAT, BAD_STAT))
 		return ide_error(drive, "drive_cmd", stat);
 		/* calls ide_end_drive_cmd */
 	ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG));
 	return ide_stopped;
 }
 
+static void ide_init_specify_cmd(ide_drive_t *drive, ide_task_t *task)
+{
+	task->tfRegister[IDE_NSECTOR_OFFSET] = drive->sect;
+	task->tfRegister[IDE_SECTOR_OFFSET]  = drive->sect;
+	task->tfRegister[IDE_LCYL_OFFSET]    = drive->cyl;
+	task->tfRegister[IDE_HCYL_OFFSET]    = drive->cyl>>8;
+	task->tfRegister[IDE_SELECT_OFFSET]  = ((drive->head-1)|drive->select.all)&0xBF;
+	task->tfRegister[IDE_COMMAND_OFFSET] = WIN_SPECIFY;
+
+	task->handler = &set_geometry_intr;
+}
+
+static void ide_init_restore_cmd(ide_drive_t *drive, ide_task_t *task)
+{
+	task->tfRegister[IDE_NSECTOR_OFFSET] = drive->sect;
+	task->tfRegister[IDE_COMMAND_OFFSET] = WIN_RESTORE;
+
+	task->handler = &recal_intr;
+}
+
+static void ide_init_setmult_cmd(ide_drive_t *drive, ide_task_t *task)
+{
+	task->tfRegister[IDE_NSECTOR_OFFSET] = drive->mult_req;
+	task->tfRegister[IDE_COMMAND_OFFSET] = WIN_SETMULT;
+
+	task->handler = &set_multmode_intr;
+}
+
+static ide_startstop_t ide_disk_special(ide_drive_t *drive)
+{
+	special_t *s = &drive->special;
+	ide_task_t args;
+
+	memset(&args, 0, sizeof(ide_task_t));
+	args.command_type = IDE_DRIVE_TASK_NO_DATA;
+
+	if (s->b.set_geometry) {
+		s->b.set_geometry = 0;
+		ide_init_specify_cmd(drive, &args);
+	} else if (s->b.recalibrate) {
+		s->b.recalibrate = 0;
+		ide_init_restore_cmd(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;
+		ide_init_setmult_cmd(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;
+	}
+
+	do_rw_taskfile(drive, &args);
+
+	return ide_started;
+}
+
 /**
  *	do_special		-	issue some special commands
  *	@drive: drive the command is for
@@ -689,9 +870,14 @@
 		if (HWIF(drive)->tuneproc != NULL)
 			HWIF(drive)->tuneproc(drive, drive->tune_req);
 		return ide_stopped;
+	} else {
+		if (drive->media == ide_disk)
+			return ide_disk_special(drive);
+
+		s->all = 0;
+		drive->mult_req = 0;
+		return ide_stopped;
 	}
-	else
-		return DRIVER(drive)->special(drive);
 }
 
 void ide_map_sg(ide_drive_t *drive, struct request *rq)
@@ -897,6 +1083,8 @@
 		return startstop;
 	}
 	if (!drive->special.all) {
+		ide_driver_t *drv;
+
 		if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK))
 			return execute_drive_cmd(drive, rq);
 		else if (rq->flags & REQ_DRIVE_TASKFILE)
@@ -906,17 +1094,19 @@
 			printk("%s: start_power_step(step: %d)\n",
 				drive->name, rq->pm->pm_step);
 #endif
-			startstop = DRIVER(drive)->start_power_step(drive, rq);
+			startstop = ide_start_power_step(drive, rq);
 			if (startstop == ide_stopped &&
 			    rq->pm->pm_step == ide_pm_state_completed)
 				ide_complete_pm_request(drive, rq);
 			return startstop;
 		}
-		return (DRIVER(drive)->do_request(drive, rq, block));
+
+		drv = *(ide_driver_t **)rq->rq_disk->private_data;
+		return drv->do_request(drive, rq, block);
 	}
 	return do_special(drive);
 kill_rq:
-	DRIVER(drive)->end_request(drive, 0, 0);
+	ide_kill_rq(drive, rq);
 	return ide_stopped;
 }
 
@@ -1597,8 +1787,6 @@
 
 	rq->errors = 0;
 	rq->rq_status = RQ_ACTIVE;
-
-	rq->rq_disk = drive->disk;
 
 	/*
 	 * we need to hold an extra reference to request for safe inspection
diff -Nru a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
--- a/drivers/ide/ide-iops.c	2005-03-07 15:22:36 -08:00
+++ b/drivers/ide/ide-iops.c	2005-03-07 15:22:36 -08:00
@@ -1107,9 +1107,27 @@
 #endif
 }
 
+static void ide_disk_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;
+}
+
 static void pre_reset(ide_drive_t *drive)
 {
-	DRIVER(drive)->pre_reset(drive);
+	if (drive->media == ide_disk)
+		ide_disk_pre_reset(drive);
+	else
+		drive->post_reset = 1;
 
 	if (!drive->keep_settings) {
 		if (drive->using_dma) {
diff -Nru a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
--- a/drivers/ide/ide-probe.c	2005-03-07 15:22:36 -08:00
+++ b/drivers/ide/ide-probe.c	2005-03-07 15:22:36 -08:00
@@ -74,7 +74,55 @@
 	drive->id->cur_heads = drive->head;
 	drive->id->cur_sectors = drive->sect;
 }
-		
+
+static void ide_disk_init_chs(ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+
+	/* 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;
+	}
+}
+
+static void ide_disk_init_mult_count(ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+
+	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
+	}
+}
+
 /**
  *	drive_is_flashcard	-	check for compact flash
  *	@drive: drive to check
@@ -221,6 +269,8 @@
 		}
 		printk (" drive\n");
 		drive->media = type;
+		/* an ATAPI device ignores DRDY */
+		drive->ready_stat = 0;
 		return;
 	}
 
@@ -588,8 +638,16 @@
 	if(!drive->present)
 		return 0;
 	/* The drive wasn't being helpful. Add generic info only */
-	if(!drive->id_read)
+	if (drive->id_read == 0) {
 		generic_id(drive);
+		return 1;
+	}
+
+	if (drive->media == ide_disk) {
+		ide_disk_init_chs(drive);
+		ide_disk_init_mult_count(drive);
+	}
+
 	return drive->present;
 }
 
@@ -804,6 +862,13 @@
 				drive->autotune == IDE_TUNE_AUTO)
 				/* auto-tune PIO mode */
 				hwif->tuneproc(drive, 255);
+
+			if (drive->autotune != IDE_TUNE_DEFAULT &&
+			    drive->autotune != IDE_TUNE_AUTO)
+				continue;
+
+			drive->nice1 = 1;
+
 			/*
 			 * MAJOR HACK BARF :-/
 			 *
@@ -813,9 +878,7 @@
 			 * Move here to prevent module loading clashing.
 			 */
 	//		drive->autodma = hwif->autodma;
-			if ((hwif->ide_dma_check) &&
-				((drive->autotune == IDE_TUNE_DEFAULT) ||
-				(drive->autotune == IDE_TUNE_AUTO))) {
+			if (hwif->ide_dma_check) {
 				/*
 				 * Force DMAing for the beginning of the check.
 				 * Some chipsets appear to do interesting
@@ -948,10 +1011,8 @@
 	blk_queue_max_hw_segments(q, max_sg_entries);
 	blk_queue_max_phys_segments(q, max_sg_entries);
 
-	/* assign drive and gendisk queue */
+	/* assign drive queue */
 	drive->queue = q;
-	if (drive->disk)
-		drive->disk->queue = drive->queue;
 
 	/* needs drive->queue to be set */
 	ide_toggle_bounce(drive, 1);
@@ -1151,8 +1212,6 @@
 	return 0;
 }
 
-extern ide_driver_t idedefault_driver;
-
 static struct kobject *ata_probe(dev_t dev, int *part, void *data)
 {
 	ide_hwif_t *hwif = data;
@@ -1160,52 +1219,66 @@
 	ide_drive_t *drive = &hwif->drives[unit];
 	if (!drive->present)
 		return NULL;
-	if (drive->driver == &idedefault_driver) {
-		if (drive->media == ide_disk)
-			(void) request_module("ide-disk");
-		if (drive->scsi)
-			(void) request_module("ide-scsi");
-		if (drive->media == ide_cdrom || drive->media == ide_optical)
-			(void) request_module("ide-cd");
-		if (drive->media == ide_tape)
-			(void) request_module("ide-tape");
-		if (drive->media == ide_floppy)
-			(void) request_module("ide-floppy");
-	}
-	if (drive->driver == &idedefault_driver)
-		return NULL;
+
+	if (drive->media == ide_disk)
+		request_module("ide-disk");
+	if (drive->scsi)
+		request_module("ide-scsi");
+	if (drive->media == ide_cdrom || drive->media == ide_optical)
+		request_module("ide-cd");
+	if (drive->media == ide_tape)
+		request_module("ide-tape");
+	if (drive->media == ide_floppy)
+		request_module("ide-floppy");
+
+	return NULL;
+}
+
+static struct kobject *exact_match(dev_t dev, int *part, void *data)
+{
+	struct gendisk *p = data;
 	*part &= (1 << PARTN_BITS) - 1;
-	return get_disk(drive->disk);
+	return &p->kobj;
 }
 
-static int alloc_disks(ide_hwif_t *hwif)
+static int exact_lock(dev_t dev, void *data)
 {
-	unsigned int unit;
-	struct gendisk *disks[MAX_DRIVES];
+	struct gendisk *p = data;
 
-	for (unit = 0; unit < MAX_DRIVES; unit++) {
-		disks[unit] = alloc_disk(1 << PARTN_BITS);
-		if (!disks[unit])
-			goto Enomem;
-	}
-	for (unit = 0; unit < MAX_DRIVES; ++unit) {
-		ide_drive_t *drive = &hwif->drives[unit];
-		struct gendisk *disk = disks[unit];
-		disk->major  = hwif->major;
-		disk->first_minor = unit << PARTN_BITS;
-		sprintf(disk->disk_name,"hd%c",'a'+hwif->index*MAX_DRIVES+unit);
-		disk->fops = ide_fops;
-		disk->private_data = drive;
-		drive->disk = disk;
-	}
+	if (!get_disk(p))
+		return -1;
 	return 0;
-Enomem:
-	printk(KERN_WARNING "(ide::init_gendisk) Out of memory\n");
-	while (unit--)
-		put_disk(disks[unit]);
-	return -ENOMEM;
 }
 
+void ide_register_region(struct gendisk *disk)
+{
+	blk_register_region(MKDEV(disk->major, disk->first_minor),
+			    disk->minors, NULL, exact_match, exact_lock, disk);
+}
+
+EXPORT_SYMBOL_GPL(ide_register_region);
+
+void ide_unregister_region(struct gendisk *disk)
+{
+	blk_unregister_region(MKDEV(disk->major, disk->first_minor),
+			      disk->minors);
+}
+
+EXPORT_SYMBOL_GPL(ide_unregister_region);
+
+void ide_init_disk(struct gendisk *disk, ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = drive->hwif;
+	unsigned int unit = drive->select.all & (1 << 4);
+
+	disk->major = hwif->major;
+	disk->first_minor = unit << PARTN_BITS;
+	sprintf(disk->disk_name, "hd%c", 'a' + hwif->index * MAX_DRIVES + unit);
+	disk->queue = drive->queue;
+}
+
+EXPORT_SYMBOL_GPL(ide_init_disk);
+
 static void drive_release_dev (struct device *dev)
 {
 	ide_drive_t *drive = container_of(dev, ide_drive_t, gendev);
@@ -1246,7 +1319,7 @@
 
 static int hwif_init(ide_hwif_t *hwif)
 {
-	int old_irq, unit;
+	int old_irq;
 
 	/* Return success if no device is connected */
 	if (!hwif->present)
@@ -1282,9 +1355,6 @@
 		printk(KERN_ERR "%s: unable to allocate SG table.\n", hwif->name);
 		goto out;
 	}
-
-	if (alloc_disks(hwif) < 0)
-		goto out;
 	
 	if (init_irq(hwif) == 0)
 		goto done;
@@ -1297,12 +1367,12 @@
 	if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET]))) {
 		printk("%s: Disabled unable to get IRQ %d.\n",
 			hwif->name, old_irq);
-		goto out_disks;
+		goto out;
 	}
 	if (init_irq(hwif)) {
 		printk("%s: probed IRQ %d and default IRQ %d failed.\n",
 			hwif->name, old_irq, hwif->irq);
-		goto out_disks;
+		goto out;
 	}
 	printk("%s: probed IRQ %d failed, using default.\n",
 		hwif->name, hwif->irq);
@@ -1312,12 +1382,6 @@
 	hwif->present = 1;	/* success */
 	return 1;
 
-out_disks:
-	for (unit = 0; unit < MAX_DRIVES; unit++) {
-		struct gendisk *disk = hwif->drives[unit].disk;
-		hwif->drives[unit].disk = NULL;
-		put_disk(disk);
-	}
 out:
 	unregister_blkdev(hwif->major, hwif->name);
 	return 0;
diff -Nru a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
--- a/drivers/ide/ide-proc.c	2005-03-07 15:22:36 -08:00
+++ b/drivers/ide/ide-proc.c	2005-03-07 15:22:36 -08:00
@@ -107,8 +107,6 @@
 	if (drive) {
 		unsigned short *val = (unsigned short *) page;
 
-		BUG_ON(!drive->driver);
-
 		err = taskfile_lib_get_identify(drive, page);
 		if (!err) {
 			char *out = ((char *)page) + (SECTOR_WORDS * 4);
@@ -269,14 +267,12 @@
 int proc_ide_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) (DRIVER(drive)->capacity(drive)));
+	int len = sprintf(page,"%llu\n", (long long)0x7fffffff);
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
+EXPORT_SYMBOL_GPL(proc_ide_read_capacity);
+
 int proc_ide_read_geometry
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
@@ -314,8 +310,11 @@
 	ide_driver_t	*driver = drive->driver;
 	int		len;
 
-	len = sprintf(page, "%s version %s\n",
-			driver->name, driver->version);
+	if (driver) {
+		len = sprintf(page, "%s version %s\n",
+				driver->name, driver->version);
+	} else
+		len = sprintf(page, "ide-default version 0.9.newide\n");
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
@@ -423,10 +422,7 @@
 
 static void destroy_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive)
 {
-	ide_driver_t *driver = drive->driver;
-
 	if (drive->proc) {
-		ide_remove_proc_entries(drive->proc, driver->proc);
 		ide_remove_proc_entries(drive->proc, generic_drive_entries);
 		remove_proc_entry(drive->name, proc_ide_root);
 		remove_proc_entry(drive->name, hwif->proc);
diff -Nru a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
--- a/drivers/ide/ide-tape.c	2005-03-07 15:22:36 -08:00
+++ b/drivers/ide/ide-tape.c	2005-03-07 15:22:36 -08:00
@@ -781,8 +781,12 @@
  *	driver due to an interrupt or a timer event is stored in a variable
  *	of type idetape_tape_t, defined below.
  */
-typedef struct {
-	ide_drive_t *drive;
+typedef struct ide_tape_obj {
+	ide_drive_t	*drive;
+	ide_driver_t	*driver;
+	struct gendisk	*disk;
+	struct kref	kref;
+
 	/*
 	 *	Since a typical character device operation requires more
 	 *	than one packet command, we provide here enough memory
@@ -1007,6 +1011,34 @@
          int debug_level; 
 } idetape_tape_t;
 
+static DECLARE_MUTEX(idetape_ref_sem);
+
+#define to_ide_tape(obj) container_of(obj, struct ide_tape_obj, kref)
+
+#define ide_tape_g(disk) \
+	container_of((disk)->private_data, struct ide_tape_obj, driver)
+
+static struct ide_tape_obj *ide_tape_get(struct gendisk *disk)
+{
+	struct ide_tape_obj *tape = NULL;
+
+	down(&idetape_ref_sem);
+	tape = ide_tape_g(disk);
+	if (tape)
+		kref_get(&tape->kref);
+	up(&idetape_ref_sem);
+	return tape;
+}
+
+static void ide_tape_release(struct kref *);
+
+static void ide_tape_put(struct ide_tape_obj *tape)
+{
+	down(&idetape_ref_sem);
+	kref_put(&tape->kref, ide_tape_release);
+	up(&idetape_ref_sem);
+}
+
 /*
  *	Tape door status
  */
@@ -1093,15 +1125,6 @@
 #define	IDETAPE_ERROR_EOD		103
 
 /*
- *	idetape_chrdev_t provides the link between out character device
- *	interface and our block device interface and the corresponding
- *	ide_drive_t structure.
- */
-typedef struct {
-	ide_drive_t *drive;
-} idetape_chrdev_t;
-
-/*
  *	The following is used to format the general configuration word of
  *	the ATAPI IDENTIFY DEVICE command.
  */
@@ -1257,7 +1280,21 @@
  *	The variables below are used for the character device interface.
  *	Additional state variables are defined in our ide_drive_t structure.
  */
-static idetape_chrdev_t idetape_chrdevs[MAX_HWIFS * MAX_DRIVES];
+static struct ide_tape_obj * idetape_devs[MAX_HWIFS * MAX_DRIVES];
+
+#define ide_tape_f(file) ((file)->private_data)
+
+static struct ide_tape_obj *ide_tape_chrdev_get(unsigned int i)
+{
+	struct ide_tape_obj *tape = NULL;
+
+	down(&idetape_ref_sem);
+	tape = idetape_devs[i];
+	if (tape)
+		kref_get(&tape->kref);
+	up(&idetape_ref_sem);
+	return tape;
+}
 
 /*
  *      Function declarations
@@ -1509,6 +1546,7 @@
 	}
 #endif /* IDETAPE_DEBUG_BUGS */	
 
+	rq->rq_disk = tape->disk;
 	rq->buffer = NULL;
 	rq->special = (void *)stage->bh;
 	tape->active_data_request = rq;
@@ -1761,8 +1799,11 @@
  */
 static void idetape_queue_pc_head (ide_drive_t *drive, idetape_pc_t *pc,struct request *rq)
 {
+	struct ide_tape_obj *tape = drive->driver_data;
+
 	idetape_init_rq(rq, REQ_IDETAPE_PC1);
 	rq->buffer = (char *) pc;
+	rq->rq_disk = tape->disk;
 	(void) ide_do_drive_cmd(drive, rq, ide_preempt);
 }
 
@@ -2428,6 +2469,11 @@
 	if (!drive->dsc_overlap && !(rq->cmd[0] & REQ_IDETAPE_PC2))
 		set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
 
+	if (drive->post_reset == 1) {
+		set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
+		drive->post_reset = 0;
+	}
+
 	if (tape->tape_still_time > 100 && tape->tape_still_time < 200)
 		tape->measure_insert_time = 1;
 	if (time_after(jiffies, tape->insert_time))
@@ -2812,10 +2858,12 @@
  */
 static int __idetape_queue_pc_tail (ide_drive_t *drive, idetape_pc_t *pc)
 {
+	struct ide_tape_obj *tape = drive->driver_data;
 	struct request rq;
 
 	idetape_init_rq(&rq, REQ_IDETAPE_PC1);
 	rq.buffer = (char *) pc;
+	rq.rq_disk = tape->disk;
 	return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
 
@@ -3039,6 +3087,7 @@
 #endif /* IDETAPE_DEBUG_BUGS */	
 
 	idetape_init_rq(&rq, cmd);
+	rq.rq_disk = tape->disk;
 	rq.special = (void *)bh;
 	rq.sector = tape->first_frame_position;
 	rq.nr_sectors = rq.current_nr_sectors = blocks;
@@ -3558,16 +3607,6 @@
 }
 
 /*
- *	idetape_pre_reset is called before an ATAPI/ATA software reset.
- */
-static void idetape_pre_reset (ide_drive_t *drive)
-{
-	idetape_tape_t *tape = drive->driver_data;
-	if (tape != NULL)
-		set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
-}
-
-/*
  *	idetape_space_over_filemarks is now a bit more complicated than just
  *	passing the command to the tape since we may have crossed some
  *	filemarks during our pipelined read-ahead mode.
@@ -3673,8 +3712,8 @@
 static ssize_t idetape_chrdev_read (struct file *file, char __user *buf,
 				    size_t count, loff_t *ppos)
 {
-	ide_drive_t *drive = file->private_data;
-	idetape_tape_t *tape = drive->driver_data;
+	struct ide_tape_obj *tape = ide_tape_f(file);
+	ide_drive_t *drive = tape->drive;
 	ssize_t bytes_read,temp, actually_read = 0, rc;
 
 #if IDETAPE_DEBUG_LOG
@@ -3732,8 +3771,8 @@
 static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf,
 				     size_t count, loff_t *ppos)
 {
-	ide_drive_t *drive = file->private_data;
-	idetape_tape_t *tape = drive->driver_data;
+	struct ide_tape_obj *tape = ide_tape_f(file);
+	ide_drive_t *drive = tape->drive;
 	ssize_t retval, actually_written = 0;
 
 	/* The drive is write protected. */
@@ -4035,8 +4074,8 @@
  */
 static int idetape_chrdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
-	ide_drive_t *drive = file->private_data;
-	idetape_tape_t *tape = drive->driver_data;
+	struct ide_tape_obj *tape = ide_tape_f(file);
+	ide_drive_t *drive = tape->drive;
 	struct mtop mtop;
 	struct mtget mtget;
 	struct mtpos mtpos;
@@ -4107,17 +4146,24 @@
 	
 	if (i >= MAX_HWIFS * MAX_DRIVES)
 		return -ENXIO;
-	drive = idetape_chrdevs[i].drive;
-	tape = drive->driver_data;
-	filp->private_data = drive;
 
-	if (test_and_set_bit(IDETAPE_BUSY, &tape->flags))
-		return -EBUSY;
+	if (!(tape = ide_tape_chrdev_get(i)))
+		return -ENXIO;
+
+	drive = tape->drive;
+
+	filp->private_data = tape;
+
+	if (test_and_set_bit(IDETAPE_BUSY, &tape->flags)) {
+		retval = -EBUSY;
+		goto out_put_tape;
+	}
+
 	retval = idetape_wait_ready(drive, 60 * HZ);
 	if (retval) {
 		clear_bit(IDETAPE_BUSY, &tape->flags);
 		printk(KERN_ERR "ide-tape: %s: drive not ready\n", tape->name);
-		return retval;
+		goto out_put_tape;
 	}
 
 	idetape_read_position(drive);
@@ -4141,7 +4187,8 @@
 		if ((filp->f_flags & O_ACCMODE) == O_WRONLY ||
 		    (filp->f_flags & O_ACCMODE) == O_RDWR) {
 			clear_bit(IDETAPE_BUSY, &tape->flags);
-			return -EROFS;
+			retval = -EROFS;
+			goto out_put_tape;
 		}
 	}
 
@@ -4159,6 +4206,10 @@
 	idetape_restart_speed_control(drive);
 	tape->restart_speed_control_req = 0;
 	return 0;
+
+out_put_tape:
+	ide_tape_put(tape);
+	return retval;
 }
 
 static void idetape_write_release (ide_drive_t *drive, unsigned int minor)
@@ -4182,8 +4233,8 @@
  */
 static int idetape_chrdev_release (struct inode *inode, struct file *filp)
 {
-	ide_drive_t *drive = filp->private_data;
-	idetape_tape_t *tape;
+	struct ide_tape_obj *tape = ide_tape_f(filp);
+	ide_drive_t *drive = tape->drive;
 	idetape_pc_t pc;
 	unsigned int minor = iminor(inode);
 
@@ -4217,6 +4268,7 @@
 		}
 	}
 	clear_bit(IDETAPE_BUSY, &tape->flags);
+	ide_tape_put(tape);
 	unlock_kernel();
 	return 0;
 }
@@ -4527,11 +4579,7 @@
 	int stage_size;
 	struct sysinfo si;
 
-	memset(tape, 0, sizeof (idetape_tape_t));
 	spin_lock_init(&tape->spinlock);
-	drive->driver_data = tape;
-	/* An ATAPI device ignores DRDY */
-	drive->ready_stat = 0;
 	drive->dsc_overlap = 1;
 #ifdef CONFIG_BLK_DEV_IDEPCI
 	if (HWIF(drive)->pci_dev != NULL) {
@@ -4549,7 +4597,6 @@
 	/* Seagate Travan drives do not support DSC overlap. */
 	if (strstr(drive->id->model, "Seagate STT3401"))
 		drive->dsc_overlap = 0;
-	tape->drive = drive;
 	tape->minor = minor;
 	tape->name[0] = 'h';
 	tape->name[1] = 't';
@@ -4630,7 +4677,6 @@
 static int idetape_cleanup (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
-	int minor = tape->minor;
 	unsigned long flags;
 
 	spin_lock_irqsave(&ide_lock, flags);
@@ -4639,17 +4685,33 @@
 		spin_unlock_irqrestore(&ide_lock, flags);
 		return 1;
 	}
-	idetape_chrdevs[minor].drive = NULL;
+
 	spin_unlock_irqrestore(&ide_lock, flags);
 	DRIVER(drive)->busy = 0;
 	(void) ide_unregister_subdriver(drive);
+
+	ide_unregister_region(tape->disk);
+
+	ide_tape_put(tape);
+
+	return 0;
+}
+
+static void ide_tape_release(struct kref *kref)
+{
+	struct ide_tape_obj *tape = to_ide_tape(kref);
+	ide_drive_t *drive = tape->drive;
+	struct gendisk *g = tape->disk;
+
+	drive->dsc_overlap = 0;
 	drive->driver_data = NULL;
 	devfs_remove("%s/mt", drive->devfs_name);
 	devfs_remove("%s/mtn", drive->devfs_name);
-	devfs_unregister_tape(drive->disk->number);
-	kfree (tape);
-	drive->disk->fops = ide_fops;
-	return 0;
+	devfs_unregister_tape(g->number);
+	idetape_devs[tape->minor] = NULL;
+	g->private_data = NULL;
+	put_disk(g);
+	kfree(tape);
 }
 
 #ifdef CONFIG_PROC_FS
@@ -4667,6 +4729,7 @@
 }
 
 static ide_proc_entry_t idetape_proc[] = {
+	{ "capacity",	S_IFREG|S_IRUGO,	proc_ide_read_capacity, NULL },
 	{ "name",	S_IFREG|S_IRUGO,	proc_idetape_read_name,	NULL },
 	{ NULL, 0, NULL, NULL }
 };
@@ -4692,7 +4755,8 @@
 	.cleanup		= idetape_cleanup,
 	.do_request		= idetape_do_request,
 	.end_request		= idetape_end_request,
-	.pre_reset		= idetape_pre_reset,
+	.error			= __ide_error,
+	.abort			= __ide_abort,
 	.proc			= idetape_proc,
 	.attach			= idetape_attach,
 	.drives			= LIST_HEAD_INIT(idetape_driver.drives),
@@ -4712,15 +4776,30 @@
 
 static int idetape_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_tape_obj *tape;
+	ide_drive_t *drive;
+
+	if (!(tape = ide_tape_get(disk)))
+		return -ENXIO;
+
+	drive = tape->drive;
+
 	drive->usage++;
+
 	return 0;
 }
 
 static int idetape_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_tape_obj *tape = ide_tape_g(disk);
+	ide_drive_t *drive = tape->drive;
+
 	drive->usage--;
+
+	ide_tape_put(tape);
+
 	return 0;
 }
 
@@ -4728,8 +4807,9 @@
 			unsigned int cmd, unsigned long arg)
 {
 	struct block_device *bdev = inode->i_bdev;
-	ide_drive_t *drive = bdev->bd_disk->private_data;
-	int err = generic_ide_ioctl(file, bdev, cmd, arg);
+	struct ide_tape_obj *tape = ide_tape_g(bdev->bd_disk);
+	ide_drive_t *drive = tape->drive;
+	int err = generic_ide_ioctl(drive, file, bdev, cmd, arg);
 	if (err == -EINVAL)
 		err = idetape_blkdev_ioctl(drive, cmd, arg);
 	return err;
@@ -4745,6 +4825,7 @@
 static int idetape_attach (ide_drive_t *drive)
 {
 	idetape_tape_t *tape;
+	struct gendisk *g;
 	int minor;
 
 	if (!strstr("ide-tape", drive->driver_req))
@@ -4770,15 +4851,37 @@
 		printk(KERN_ERR "ide-tape: %s: Can't allocate a tape structure\n", drive->name);
 		goto failed;
 	}
+
+	g = alloc_disk(1 << PARTN_BITS);
+	if (!g)
+		goto out_free_tape;
+
+	ide_init_disk(g, drive);
+
 	if (ide_register_subdriver(drive, &idetape_driver)) {
 		printk(KERN_ERR "ide-tape: %s: Failed to register the driver with ide.c\n", drive->name);
-		kfree(tape);
-		goto failed;
+		goto out_put_disk;
 	}
-	for (minor = 0; idetape_chrdevs[minor].drive != NULL; minor++)
+
+	memset(tape, 0, sizeof(*tape));
+
+	kref_init(&tape->kref);
+
+	tape->drive = drive;
+	tape->driver = &idetape_driver;
+	tape->disk = g;
+
+	g->private_data = &tape->driver;
+
+	drive->driver_data = tape;
+
+	down(&idetape_ref_sem);
+	for (minor = 0; idetape_devs[minor]; minor++)
 		;
+	idetape_devs[minor] = tape;
+	up(&idetape_ref_sem);
+
 	idetape_setup(drive, tape, minor);
-	idetape_chrdevs[minor].drive = drive;
 
 	devfs_mk_cdev(MKDEV(HWIF(drive)->major, minor),
 			S_IFCHR | S_IRUGO | S_IWUGO,
@@ -4787,9 +4890,15 @@
 			S_IFCHR | S_IRUGO | S_IWUGO,
 			"%s/mtn", drive->devfs_name);
 
-	drive->disk->number = devfs_register_tape(drive->devfs_name);
-	drive->disk->fops = &idetape_block_ops;
+	g->number = devfs_register_tape(drive->devfs_name);
+	g->fops = &idetape_block_ops;
+	ide_register_region(g);
+
 	return 0;
+out_put_disk:
+	put_disk(g);
+out_free_tape:
+	kfree(tape);
 failed:
 	return 1;
 }
diff -Nru a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
--- a/drivers/ide/ide-taskfile.c	2005-03-07 15:22:36 -08:00
+++ b/drivers/ide/ide-taskfile.c	2005-03-07 15:22:36 -08:00
@@ -101,7 +101,7 @@
 	ide_hwif_t *hwif	= HWIF(drive);
 	task_struct_t *taskfile	= (task_struct_t *) task->tfRegister;
 	hob_struct_t *hobfile	= (hob_struct_t *) task->hobRegister;
-	u8 HIHI			= (drive->addressing == 1) ? 0xE0 : 0xEF;
+	u8 HIHI			= (task->flags & ATA_TFLAG_LBA48) ? 0xE0 : 0xEF;
 
 	/* ALL Command Block Executions SHALL clear nIEN, unless otherwise */
 	if (IDE_CONTROL_REG) {
@@ -110,7 +110,7 @@
 	}
 	SELECT_MASK(drive, 0);
 
-	if (drive->addressing == 1) {
+	if (task->flags & ATA_TFLAG_LBA48) {
 		hwif->OUTB(hobfile->feature, IDE_FEATURE_REG);
 		hwif->OUTB(hobfile->sector_count, IDE_NSECTOR_REG);
 		hwif->OUTB(hobfile->sector_number, IDE_SECTOR_REG);
@@ -181,8 +181,6 @@
 	return ide_stopped;
 }
 
-EXPORT_SYMBOL(set_multmode_intr);
-
 /*
  * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd.
  */
@@ -207,8 +205,6 @@
 	return ide_started;
 }
 
-EXPORT_SYMBOL(set_geometry_intr);
-
 /*
  * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
  */
@@ -222,8 +218,6 @@
 	return ide_stopped;
 }
 
-EXPORT_SYMBOL(recal_intr);
-
 /*
  * Handler for commands without a data phase
  */
@@ -321,9 +315,18 @@
 static inline void ide_pio_datablock(ide_drive_t *drive, struct request *rq,
 				     unsigned int write)
 {
+	u8 saved_io_32bit = drive->io_32bit;
+
 	if (rq->bio)	/* fs request */
 		rq->errors = 0;
 
+	if (rq->flags & REQ_DRIVE_TASKFILE) {
+		ide_task_t *task = rq->special;
+
+		if (task->flags & ATA_TFLAG_IO_16BIT)
+			drive->io_32bit = 0;
+	}
+
 	switch (drive->hwif->data_phase) {
 	case TASKFILE_MULTI_IN:
 	case TASKFILE_MULTI_OUT:
@@ -333,6 +336,8 @@
 		ide_pio_sector(drive, write);
 		break;
 	}
+
+	drive->io_32bit = saved_io_32bit;
 }
 
 static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq,
@@ -360,8 +365,12 @@
 			break;
 		}
 
-		if (sectors > 0)
-			drive->driver->end_request(drive, 1, sectors);
+		if (sectors > 0) {
+			ide_driver_t *drv;
+
+			drv = *(ide_driver_t **)rq->rq_disk->private_data;
+			drv->end_request(drive, 1, sectors);
+		}
 	}
 	return ide_error(drive, s, stat);
 }
@@ -377,7 +386,8 @@
 			return;
 		}
 	}
-	drive->driver->end_request(drive, 1, rq->hard_nr_sectors);
+
+	ide_end_request(drive, 1, rq->hard_nr_sectors);
 }
 
 /*
@@ -523,7 +533,6 @@
 	int tasksize		= sizeof(struct ide_task_request_s);
 	int taskin		= 0;
 	int taskout		= 0;
-	u8 io_32bit		= drive->io_32bit;
 	char __user *buf = (char __user *)arg;
 
 //	printk("IDE Taskfile ...\n");
@@ -576,7 +585,10 @@
 	args.data_phase   = req_task->data_phase;
 	args.command_type = req_task->req_cmd;
 
-	drive->io_32bit = 0;
+	args.flags = ATA_TFLAG_IO_16BIT;
+	if (drive->addressing == 1)
+		args.flags |= ATA_TFLAG_LBA48;
+
 	switch(req_task->data_phase) {
 		case TASKFILE_OUT_DMAQ:
 		case TASKFILE_OUT_DMA:
@@ -655,8 +667,6 @@
 		kfree(inbuf);
 
 //	printk("IDE Taskfile ioctl ended. rc = %i\n", err);
-
-	drive->io_32bit = io_32bit;
 
 	return err;
 }
diff -Nru a/drivers/ide/ide.c b/drivers/ide/ide.c
--- a/drivers/ide/ide.c	2005-03-07 15:22:36 -08:00
+++ b/drivers/ide/ide.c	2005-03-07 15:22:36 -08:00
@@ -196,8 +196,7 @@
 
 EXPORT_SYMBOL(ide_hwifs);
 
-extern ide_driver_t idedefault_driver;
-static void setup_driver_defaults(ide_driver_t *driver);
+static struct list_head ide_drives = LIST_HEAD_INIT(ide_drives);
 
 /*
  * Do not even *think* about calling this!
@@ -246,7 +245,6 @@
 		drive->max_failures		= IDE_DEFAULT_MAX_FAILURES;
 		drive->using_dma		= 0;
 		drive->is_flash			= 0;
-		drive->driver			= &idedefault_driver;
 		drive->vdma			= 0;
 		INIT_LIST_HEAD(&drive->list);
 		sema_init(&drive->gendev_rel_sem, 0);
@@ -301,8 +299,6 @@
 		return;		/* already initialized */
 	magic_cookie = 0;
 
-	setup_driver_defaults(&idedefault_driver);
-
 	/* Initialise all interface structures */
 	for (index = 0; index < MAX_HWIFS; ++index) {
 		hwif = &ide_hwifs[index];
@@ -362,11 +358,6 @@
 	return system_bus_speed;
 }
 
-static int ide_open (struct inode * inode, struct file * filp)
-{
-	return -ENXIO;
-}
-
 /*
  *	drives_lock protects the list of drives, drivers_lock the
  *	list of drivers.  Currently nobody takes both at once.
@@ -417,11 +408,6 @@
 
 #ifdef CONFIG_PROC_FS
 struct proc_dir_entry *proc_ide_root;
-
-static ide_proc_entry_t generic_subdriver_entries[] = {
-	{ "capacity",	S_IFREG|S_IRUGO,	proc_ide_read_capacity,	NULL },
-	{ NULL, 0, NULL, NULL }
-};
 #endif
 
 static struct resource* hwif_request_region(ide_hwif_t *hwif,
@@ -771,11 +757,6 @@
 	 * Remove us from the kernel's knowledge
 	 */
 	blk_unregister_region(MKDEV(hwif->major, 0), MAX_DRIVES<<PARTN_BITS);
-	for (i = 0; i < MAX_DRIVES; i++) {
-		struct gendisk *disk = hwif->drives[i].disk;
-		hwif->drives[i].disk = NULL;
-		put_disk(disk);
-	}
 	kfree(hwif->sg_table);
 	unregister_blkdev(hwif->major, hwif->name);
 	spin_lock_irq(&ide_lock);
@@ -939,7 +920,7 @@
 DECLARE_MUTEX(ide_setting_sem);
 
 /**
- *	ide_add_setting	-	add an ide setting option
+ *	__ide_add_setting	-	add an ide setting option
  *	@drive: drive to use
  *	@name: setting name
  *	@rw: true if the function is read write
@@ -952,6 +933,7 @@
  *	@div_factor: divison scale
  *	@data: private data field
  *	@set: setting
+ *	@auto_remove: setting auto removal flag
  *
  *	Removes the setting named from the device if it is present.
  *	The function takes the settings_lock to protect against 
@@ -963,8 +945,8 @@
  *	a driver is attached we assume the driver settings are auto
  *	remove.
  */
- 
-int ide_add_setting (ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set)
+
+static int __ide_add_setting(ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set, int auto_remove)
 {
 	ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL;
 
@@ -989,7 +971,7 @@
 	setting->set = set;
 	
 	setting->next = *p;
-	if (drive->driver != &idedefault_driver)
+	if (auto_remove)
 		setting->auto_remove = 1;
 	*p = setting;
 	up(&ide_setting_sem);
@@ -1001,6 +983,11 @@
 	return -1;
 }
 
+int ide_add_setting(ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set)
+{
+	return __ide_add_setting(drive, name, rw, read_ioctl, write_ioctl, data_type, min, max, mul_factor, div_factor, data, set, 1);
+}
+
 EXPORT_SYMBOL(ide_add_setting);
 
 /**
@@ -1290,17 +1277,17 @@
 void ide_add_generic_settings (ide_drive_t *drive)
 {
 /*
- *			drive	setting name		read/write access				read ioctl		write ioctl		data type	min	max				mul_factor	div_factor	data pointer			set function
+ *			  drive		setting name		read/write access				read ioctl		write ioctl		data type	min	max				mul_factor	div_factor	data pointer			set function
  */
-	ide_add_setting(drive,	"io_32bit",		drive->no_io_32bit ? SETTING_READ : SETTING_RW,	HDIO_GET_32BIT,		HDIO_SET_32BIT,		TYPE_BYTE,	0,	1 + (SUPPORT_VLB_SYNC << 1),	1,		1,		&drive->io_32bit,		set_io_32bit);
-	ide_add_setting(drive,	"keepsettings",		SETTING_RW,					HDIO_GET_KEEPSETTINGS,	HDIO_SET_KEEPSETTINGS,	TYPE_BYTE,	0,	1,				1,		1,		&drive->keep_settings,		NULL);
-	ide_add_setting(drive,	"nice1",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	1,				1,		1,		&drive->nice1,			NULL);
-	ide_add_setting(drive,	"pio_mode",		SETTING_WRITE,					-1,			HDIO_SET_PIO_MODE,	TYPE_BYTE,	0,	255,				1,		1,		NULL,				set_pio_mode);
-	ide_add_setting(drive,	"unmaskirq",		drive->no_unmask ? SETTING_READ : SETTING_RW,	HDIO_GET_UNMASKINTR,	HDIO_SET_UNMASKINTR,	TYPE_BYTE,	0,	1,				1,		1,		&drive->unmask,			NULL);
-	ide_add_setting(drive,	"using_dma",		SETTING_RW,					HDIO_GET_DMA,		HDIO_SET_DMA,		TYPE_BYTE,	0,	1,				1,		1,		&drive->using_dma,		set_using_dma);
-	ide_add_setting(drive,	"init_speed",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	70,				1,		1,		&drive->init_speed,		NULL);
-	ide_add_setting(drive,	"current_speed",	SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	70,				1,		1,		&drive->current_speed,		set_xfer_rate);
-	ide_add_setting(drive,	"number",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	3,				1,		1,		&drive->dn,			NULL);
+	__ide_add_setting(drive,	"io_32bit",		drive->no_io_32bit ? SETTING_READ : SETTING_RW,	HDIO_GET_32BIT,		HDIO_SET_32BIT,		TYPE_BYTE,	0,	1 + (SUPPORT_VLB_SYNC << 1),	1,		1,		&drive->io_32bit,		set_io_32bit,	0);
+	__ide_add_setting(drive,	"keepsettings",		SETTING_RW,					HDIO_GET_KEEPSETTINGS,	HDIO_SET_KEEPSETTINGS,	TYPE_BYTE,	0,	1,				1,		1,		&drive->keep_settings,		NULL,		0);
+	__ide_add_setting(drive,	"nice1",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	1,				1,		1,		&drive->nice1,			NULL,		0);
+	__ide_add_setting(drive,	"pio_mode",		SETTING_WRITE,					-1,			HDIO_SET_PIO_MODE,	TYPE_BYTE,	0,	255,				1,		1,		NULL,				set_pio_mode,	0);
+	__ide_add_setting(drive,	"unmaskirq",		drive->no_unmask ? SETTING_READ : SETTING_RW,	HDIO_GET_UNMASKINTR,	HDIO_SET_UNMASKINTR,	TYPE_BYTE,	0,	1,				1,		1,		&drive->unmask,			NULL,		0);
+	__ide_add_setting(drive,	"using_dma",		SETTING_RW,					HDIO_GET_DMA,		HDIO_SET_DMA,		TYPE_BYTE,	0,	1,				1,		1,		&drive->using_dma,		set_using_dma,	0);
+	__ide_add_setting(drive,	"init_speed",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	70,				1,		1,		&drive->init_speed,		NULL,		0);
+	__ide_add_setting(drive,	"current_speed",	SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	70,				1,		1,		&drive->current_speed,		set_xfer_rate,	0);
+	__ide_add_setting(drive,	"number",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	3,				1,		1,		&drive->dn,			NULL,		0);
 }
 
 /**
@@ -1338,7 +1325,7 @@
 	} else {
 		drive->driver_req[0] = 0;
 	}
-	if (DRIVER(drive)!= &idedefault_driver && !strcmp(DRIVER(drive)->name, driver))
+	if (drive->driver && !strcmp(drive->driver->name, driver))
 		return 0;
 abort:
 	return 1;
@@ -1377,9 +1364,9 @@
 		spin_lock(&drivers_lock);
 		module_put(driver->owner);
 	}
-	drive->gendev.driver = &idedefault_driver.gen_driver;
+	drive->gendev.driver = NULL;
 	spin_unlock(&drivers_lock);
-	if(idedefault_driver.attach(drive) != 0)
+	if (ide_register_subdriver(drive, NULL))
 		panic("ide: default attach failed");
 	return 1;
 }
@@ -1422,11 +1409,11 @@
 	return ide_do_drive_cmd(drive, &rq, ide_head_wait);
 }
 
-int generic_ide_ioctl(struct file *file, struct block_device *bdev,
+int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device *bdev,
 			unsigned int cmd, unsigned long arg)
 {
-	ide_drive_t *drive = bdev->bd_disk->private_data;
 	ide_settings_t *setting;
+	ide_driver_t *drv;
 	int err = 0;
 	void __user *p = (void __user *)arg;
 
@@ -1526,7 +1513,8 @@
 			if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP) | (1 << IDE_NICE_1))))
 				return -EPERM;
 			drive->dsc_overlap = (arg >> IDE_NICE_DSC_OVERLAP) & 1;
-			if (drive->dsc_overlap && !DRIVER(drive)->supports_dsc_overlap) {
+			drv = *(ide_driver_t **)bdev->bd_disk->private_data;
+			if (drive->dsc_overlap && !drv->supports_dsc_overlap) {
 				drive->dsc_overlap = 0;
 				return -EPERM;
 			}
@@ -1751,6 +1739,8 @@
 			case -4: /* "cdrom" */
 				drive->present = 1;
 				drive->media = ide_cdrom;
+				/* an ATAPI device ignores DRDY */
+				drive->ready_stat = 0;
 				hwif->noprobe = 0;
 				goto done;
 			case -5: /* "serialize" */
@@ -2022,76 +2012,12 @@
 #endif
 }
 
-static ide_startstop_t default_do_request (ide_drive_t *drive, struct request *rq, sector_t block)
-{
-	ide_end_request(drive, 0, 0);
-	return ide_stopped;
-}
-
-static int default_end_request (ide_drive_t *drive, int uptodate, int nr_sects)
-{
-	return ide_end_request(drive, uptodate, nr_sects);
-}
-
-static ide_startstop_t
-default_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err)
-{
-	return __ide_error(drive, rq, stat, err);
-}
-
-static void default_pre_reset (ide_drive_t *drive)
-{
-}
-
-static sector_t default_capacity (ide_drive_t *drive)
-{
-	return 0x7fffffff;
-}
-
-static ide_startstop_t default_special (ide_drive_t *drive)
-{
-	special_t *s = &drive->special;
-
-	s->all = 0;
-	drive->mult_req = 0;
-	return ide_stopped;
-}
-
-static ide_startstop_t default_abort(ide_drive_t *drive, struct request *rq)
-{
-	return __ide_abort(drive, rq);
-}
-
-static ide_startstop_t default_start_power_step(ide_drive_t *drive,
-						struct request *rq)
-{
-	rq->pm->pm_step = ide_pm_state_completed;
-	return ide_stopped;
-}
-
-static void setup_driver_defaults (ide_driver_t *d)
-{
-	BUG_ON(d->attach == NULL || d->cleanup == NULL);
-
-	if (d->do_request == NULL)	d->do_request = default_do_request;
-	if (d->end_request == NULL)	d->end_request = default_end_request;
-	if (d->error == NULL)		d->error = default_error;
-	if (d->abort == NULL)		d->abort = default_abort;
-	if (d->pre_reset == NULL)	d->pre_reset = default_pre_reset;
-	if (d->capacity == NULL)	d->capacity = default_capacity;
-	if (d->special == NULL)		d->special = default_special;
-	if (d->start_power_step == NULL)
-		d->start_power_step = default_start_power_step;
-}
-
 int ide_register_subdriver(ide_drive_t *drive, ide_driver_t *driver)
 {
 	unsigned long flags;
 
-	BUG_ON(!drive->driver);
-
 	spin_lock_irqsave(&ide_lock, flags);
-	if (!drive->present || drive->driver != &idedefault_driver ||
+	if (!drive->present || drive->driver != NULL ||
 	    drive->usage || drive->dead) {
 		spin_unlock_irqrestore(&ide_lock, flags);
 		return 1;
@@ -2099,20 +2025,12 @@
 	drive->driver = driver;
 	spin_unlock_irqrestore(&ide_lock, flags);
 	spin_lock(&drives_lock);
-	list_add_tail(&drive->list, &driver->drives);
+	list_add_tail(&drive->list, driver ? &driver->drives : &ide_drives);
 	spin_unlock(&drives_lock);
 //	printk(KERN_INFO "%s: attached %s driver.\n", drive->name, driver->name);
-	if ((drive->autotune == IDE_TUNE_DEFAULT) ||
-		(drive->autotune == IDE_TUNE_AUTO)) {
-		/* DMA timings and setup moved to ide-probe.c */
-		drive->dsc_overlap = (drive->next != drive && driver->supports_dsc_overlap);
-		drive->nice1 = 1;
-	}
 #ifdef CONFIG_PROC_FS
-	if (drive->driver != &idedefault_driver) {
-		ide_add_proc_entries(drive->proc, generic_subdriver_entries, drive);
+	if (driver)
 		ide_add_proc_entries(drive->proc, driver->proc, drive);
-	}
 #endif
 	return 0;
 }
@@ -2139,23 +2057,22 @@
 	
 	down(&ide_setting_sem);
 	spin_lock_irqsave(&ide_lock, flags);
-	if (drive->usage || drive->driver == &idedefault_driver || DRIVER(drive)->busy) {
+	if (drive->usage || drive->driver == NULL || DRIVER(drive)->busy) {
 		spin_unlock_irqrestore(&ide_lock, flags);
 		up(&ide_setting_sem);
 		return 1;
 	}
 #ifdef CONFIG_PROC_FS
 	ide_remove_proc_entries(drive->proc, DRIVER(drive)->proc);
-	ide_remove_proc_entries(drive->proc, generic_subdriver_entries);
 #endif
 	auto_remove_settings(drive);
-	drive->driver = &idedefault_driver;
+	drive->driver = NULL;
 	spin_unlock_irqrestore(&ide_lock, flags);
 	up(&ide_setting_sem);
 	spin_lock(&drives_lock);
 	list_del_init(&drive->list);
 	spin_unlock(&drives_lock);
-	/* drive will be added to &idedefault_driver->drives in ata_attach() */
+	/* drive will be added to &ide_drives in ata_attach() */
 	return 0;
 }
 
@@ -2185,15 +2102,13 @@
 	struct list_head *list_loop;
 	struct list_head *tmp_storage;
 
-	setup_driver_defaults(driver);
-
 	spin_lock(&drivers_lock);
 	list_add(&driver->drivers, &drivers);
 	spin_unlock(&drivers_lock);
 
 	INIT_LIST_HEAD(&list);
 	spin_lock(&drives_lock);
-	list_splice_init(&idedefault_driver.drives, &list);
+	list_splice_init(&ide_drives, &list);
 	spin_unlock(&drives_lock);
 
 	list_for_each_safe(list_loop, tmp_storage, &list) {
@@ -2242,13 +2157,6 @@
 }
 
 EXPORT_SYMBOL(ide_unregister_driver);
-
-struct block_device_operations ide_fops[] = {{
-	.owner		= THIS_MODULE,
-	.open		= ide_open,
-}};
-
-EXPORT_SYMBOL(ide_fops);
 
 /*
  * Probe module
diff -Nru a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c
--- a/drivers/ide/pci/pdc202xx_new.c	2005-03-07 15:22:36 -08:00
+++ b/drivers/ide/pci/pdc202xx_new.c	2005-03-07 15:22:36 -08:00
@@ -420,9 +420,6 @@
 		.init_hwif	= init_hwif_pdc202new,
 		.channels	= 2,
 		.autodma	= AUTODMA,
-#ifndef CONFIG_PDC202XX_FORCE
-		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
-#endif
 		.bootable	= OFF_BOARD,
 	},{	/* 3 */
 		.name		= "PDC20271",
@@ -447,9 +444,6 @@
 		.init_hwif	= init_hwif_pdc202new,
 		.channels	= 2,
 		.autodma	= AUTODMA,
-#ifndef CONFIG_PDC202XX_FORCE
-		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
-#endif
 		.bootable	= OFF_BOARD,
 	},{	/* 6 */
 		.name		= "PDC20277",
diff -Nru a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c
--- a/drivers/ide/pci/pdc202xx_old.c	2005-03-07 15:22:36 -08:00
+++ b/drivers/ide/pci/pdc202xx_old.c	2005-03-07 15:22:36 -08:00
@@ -786,9 +786,6 @@
 		.init_dma	= init_dma_pdc202xx,
 		.channels	= 2,
 		.autodma	= AUTODMA,
-#ifndef CONFIG_PDC202XX_FORCE
-		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
-#endif
 		.bootable	= OFF_BOARD,
 		.extra		= 16,
 	},{	/* 1 */
@@ -799,12 +796,8 @@
 		.init_dma	= init_dma_pdc202xx,
 		.channels	= 2,
 		.autodma	= AUTODMA,
-#ifndef CONFIG_PDC202XX_FORCE
-		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
-#endif
 		.bootable	= OFF_BOARD,
 		.extra		= 48,
-		.flags		= IDEPCI_FLAG_FORCE_PDC,
 	},{	/* 2 */
 		.name		= "PDC20263",
 		.init_setup	= init_setup_pdc202ata4,
@@ -813,9 +806,6 @@
 		.init_dma	= init_dma_pdc202xx,
 		.channels	= 2,
 		.autodma	= AUTODMA,
-#ifndef CONFIG_PDC202XX_FORCE
-		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
-#endif
 		.bootable	= OFF_BOARD,
 		.extra		= 48,
 	},{	/* 3 */
@@ -826,12 +816,8 @@
 		.init_dma	= init_dma_pdc202xx,
 		.channels	= 2,
 		.autodma	= AUTODMA,
-#ifndef CONFIG_PDC202XX_FORCE
-		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
-#endif
 		.bootable	= OFF_BOARD,
 		.extra		= 48,
-		.flags		= IDEPCI_FLAG_FORCE_PDC,
 	},{	/* 4 */
 		.name		= "PDC20267",
 		.init_setup	= init_setup_pdc202xx,
@@ -840,9 +826,6 @@
 		.init_dma	= init_dma_pdc202xx,
 		.channels	= 2,
 		.autodma	= AUTODMA,
-#ifndef CONFIG_PDC202XX_FORCE
-		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
-#endif
 		.bootable	= OFF_BOARD,
 		.extra		= 48,
 	}
diff -Nru a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c
--- a/drivers/ide/pci/via82cxxx.c	2005-03-07 15:22:36 -08:00
+++ b/drivers/ide/pci/via82cxxx.c	2005-03-07 15:22:36 -08:00
@@ -79,6 +79,7 @@
 	u8 rev_max;
 	u16 flags;
 } via_isa_bridges[] = {
+	{ "vt6410",	PCI_DEVICE_ID_VIA_6410,     0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
 	{ "vt8237",	PCI_DEVICE_ID_VIA_8237,     0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
 	{ "vt8235",	PCI_DEVICE_ID_VIA_8235,     0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
 	{ "vt8233a",	PCI_DEVICE_ID_VIA_8233A,    0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
@@ -332,11 +333,8 @@
 	struct ide_timing t, p;
 	unsigned int T, UT;
 
-	if (speed != XFER_PIO_SLOW && speed != drive->current_speed)
-		if (ide_config_drive_speed(drive, speed))
-			printk(KERN_WARNING "ide%d: Drive %d didn't "
-				"accept speed setting. Oh, well.\n",
-				drive->dn >> 1, drive->dn & 1);
+	if (speed != XFER_PIO_SLOW)
+		ide_config_drive_speed(drive, speed);
 
 	T = 1000000000 / via_clock;
 
@@ -619,24 +617,35 @@
 	hwif->drives[1].autodma = hwif->autodma;
 }
 
-static ide_pci_device_t via82cxxx_chipset __devinitdata = {
-	.name		= "VP_IDE",
-	.init_chipset	= init_chipset_via82cxxx,
-	.init_hwif	= init_hwif_via82cxxx,
-	.channels	= 2,
-	.autodma	= NOAUTODMA,
-	.enablebits	= {{0x40,0x02,0x02}, {0x40,0x01,0x01}},
-	.bootable	= ON_BOARD,
+static ide_pci_device_t via82cxxx_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.name		= "VP_IDE",
+		.init_chipset	= init_chipset_via82cxxx,
+		.init_hwif	= init_hwif_via82cxxx,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.enablebits	= {{0x40,0x02,0x02}, {0x40,0x01,0x01}},
+		.bootable	= ON_BOARD
+	},{	/* 1 */
+		.name		= "VP_IDE",
+		.init_chipset	= init_chipset_via82cxxx,
+		.init_hwif	= init_hwif_via82cxxx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+	}
 };
 
 static int __devinit via_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
-	return ide_setup_pci_device(dev, &via82cxxx_chipset);
+	return ide_setup_pci_device(dev, &via82cxxx_chipsets[id->driver_data]);
 }
 
 static struct pci_device_id via_pci_tbl[] = {
 	{ PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{ PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_6410,     PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
 	{ 0, },
 };
 MODULE_DEVICE_TABLE(pci, via_pci_tbl);
diff -Nru a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c
--- a/drivers/ide/setup-pci.c	2005-03-07 15:22:36 -08:00
+++ b/drivers/ide/setup-pci.c	2005-03-07 15:22:36 -08:00
@@ -579,7 +579,6 @@
 	int port;
 	int at_least_one_hwif_enabled = 0;
 	ide_hwif_t *hwif, *mate = NULL;
-	static int secondpdc = 0;
 	u8 tmp;
 
 	index->all = 0xf0f0;
@@ -590,22 +589,10 @@
 	 
 	for (port = 0; port <= 1; ++port) {
 		ide_pci_enablebit_t *e = &(d->enablebits[port]);
-	
-		/* 
-		 * If this is a Promise FakeRaid controller,
-		 * the 2nd controller will be marked as 
-		 * disabled while it is actually there and enabled
-		 * by the bios for raid purposes. 
-		 * Skip the normal "is it enabled" test for those.
-		 */
-		if ((d->flags & IDEPCI_FLAG_FORCE_PDC) &&
-		    (secondpdc++==1) && (port==1))
-			goto controller_ok;
-			
+
 		if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) ||
 		    (tmp & e->mask) != e->val))
 			continue;	/* port not enabled */
-controller_ok:
 
 		if (d->channels	<= port)
 			break;
diff -Nru a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
--- a/drivers/scsi/ide-scsi.c	2005-03-07 15:22:36 -08:00
+++ b/drivers/scsi/ide-scsi.c	2005-03-07 15:22:36 -08:00
@@ -96,14 +96,42 @@
  */
 #define IDESCSI_LOG_CMD			0	/* Log SCSI commands */
 
-typedef struct {
-	ide_drive_t *drive;
+typedef struct ide_scsi_obj {
+	ide_drive_t		*drive;
+	ide_driver_t		*driver;
+	struct gendisk		*disk;
+	struct Scsi_Host	*host;
+
 	idescsi_pc_t *pc;			/* Current packet command */
 	unsigned long flags;			/* Status/Action flags */
 	unsigned long transform;		/* SCSI cmd translation layer */
 	unsigned long log;			/* log flags */
 } idescsi_scsi_t;
 
+static DECLARE_MUTEX(idescsi_ref_sem);
+
+#define ide_scsi_g(disk) \
+	container_of((disk)->private_data, struct ide_scsi_obj, driver)
+
+static struct ide_scsi_obj *ide_scsi_get(struct gendisk *disk)
+{
+	struct ide_scsi_obj *scsi = NULL;
+
+	down(&idescsi_ref_sem);
+	scsi = ide_scsi_g(disk);
+	if (scsi)
+		scsi_host_get(scsi->host);
+	up(&idescsi_ref_sem);
+	return scsi;
+}
+
+static void ide_scsi_put(struct ide_scsi_obj *scsi)
+{
+	down(&idescsi_ref_sem);
+	scsi_host_put(scsi->host);
+	up(&idescsi_ref_sem);
+}
+
 static inline idescsi_scsi_t *scsihost_to_idescsi(struct Scsi_Host *host)
 {
 	return (idescsi_scsi_t*) (&host[1]);
@@ -298,9 +326,12 @@
 		printk ("ide-scsi: %s: queue cmd = ", drive->name);
 		hexdump(pc->c, 6);
 	}
+	rq->rq_disk = scsi->disk;
 	return ide_do_drive_cmd(drive, rq, ide_preempt);
 }
 
+static int idescsi_end_request(ide_drive_t *, int, int);
+
 static ide_startstop_t
 idescsi_atapi_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err)
 {
@@ -309,7 +340,9 @@
 		HWIF(drive)->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);
 
 	rq->errors++;
-	DRIVER(drive)->end_request(drive, 0, 0);
+
+	idescsi_end_request(drive, 0, 0);
+
 	return ide_stopped;
 }
 
@@ -321,7 +354,9 @@
 			((idescsi_pc_t *) rq->special)->scsi_cmd->serial_number);
 #endif
 	rq->errors |= ERROR_MAX;
-	DRIVER(drive)->end_request(drive, 0, 0);
+
+	idescsi_end_request(drive, 0, 0);
+
 	return ide_stopped;
 }
 
@@ -679,7 +714,6 @@
 static void idescsi_setup (ide_drive_t *drive, idescsi_scsi_t *scsi)
 {
 	DRIVER(drive)->busy++;
-	drive->ready_stat = 0;
 	if (drive->id && (drive->id->config & 0x0060) == 0x20)
 		set_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags);
 	set_bit(IDESCSI_TRANSFORM, &scsi->transform);
@@ -694,21 +728,37 @@
 static int idescsi_cleanup (ide_drive_t *drive)
 {
 	struct Scsi_Host *scsihost = drive->driver_data;
+	struct ide_scsi_obj *scsi = scsihost_to_idescsi(scsihost);
+	struct gendisk *g = scsi->disk;
 
 	if (ide_unregister_subdriver(drive))
 		return 1;
-	
-	/* FIXME?: Are these two statements necessary? */
+
+	ide_unregister_region(g);
+
+	/* FIXME: drive->driver_data shouldn't be used */
 	drive->driver_data = NULL;
-	drive->disk->fops = ide_fops;
+	/* FIXME: add driver's private struct gendisk */
+	g->private_data = NULL;
+	put_disk(g);
 
 	scsi_remove_host(scsihost);
-	scsi_host_put(scsihost);
+	ide_scsi_put(scsi);
+
 	return 0;
 }
 
 static int idescsi_attach(ide_drive_t *drive);
 
+#ifdef CONFIG_PROC_FS
+static ide_proc_entry_t idescsi_proc[] = {
+	{ "capacity", S_IFREG|S_IRUGO, proc_ide_read_capacity, NULL },
+	{ NULL, 0, NULL, NULL }
+};
+#else
+# define idescsi_proc	NULL
+#endif
+
 /*
  *	IDE subdriver functions, registered with ide.c
  */
@@ -719,6 +769,7 @@
 	.media			= ide_scsi,
 	.busy			= 0,
 	.supports_dsc_overlap	= 0,
+	.proc			= idescsi_proc,
 	.attach			= idescsi_attach,
 	.cleanup		= idescsi_cleanup,
 	.do_request		= idescsi_do_request,
@@ -730,15 +781,30 @@
 
 static int idescsi_ide_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_scsi_obj *scsi;
+	ide_drive_t *drive;
+
+	if (!(scsi = ide_scsi_get(disk)))
+		return -ENXIO;
+
+	drive = scsi->drive;
+
 	drive->usage++;
+
 	return 0;
 }
 
 static int idescsi_ide_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_scsi_obj *scsi = ide_scsi_g(disk);
+	ide_drive_t *drive = scsi->drive;
+
 	drive->usage--;
+
+	ide_scsi_put(scsi);
+
 	return 0;
 }
 
@@ -746,7 +812,8 @@
 			unsigned int cmd, unsigned long arg)
 {
 	struct block_device *bdev = inode->i_bdev;
-	return generic_ide_ioctl(file, bdev, cmd, arg);
+	struct ide_scsi_obj *scsi = ide_scsi_g(bdev->bd_disk);
+	return generic_ide_ioctl(scsi->drive, file, bdev, cmd, arg);
 }
 
 static struct block_device_operations idescsi_ops = {
@@ -858,6 +925,7 @@
 	rq->special = (char *) pc;
 	rq->flags = REQ_SPECIAL;
 	spin_unlock_irq(host->host_lock);
+	rq->rq_disk = scsi->disk;
 	(void) ide_do_drive_cmd (drive, rq, ide_end);
 	spin_lock_irq(host->host_lock);
 	return 0;
@@ -1033,8 +1101,9 @@
 {
 	idescsi_scsi_t *idescsi;
 	struct Scsi_Host *host;
+	struct gendisk *g;
 	static int warned;
-	int err;
+	int err = -ENOMEM;
 
 	if (!warned && drive->media == ide_cdrom) {
 		printk(KERN_WARNING "ide-scsi is deprecated for cd burning! Use ide-cd and give dev=/dev/hdX as device\n");
@@ -1047,6 +1116,12 @@
 	    !(host = scsi_host_alloc(&idescsi_template,sizeof(idescsi_scsi_t))))
 		return 1;
 
+	g = alloc_disk(1 << PARTN_BITS);
+	if (!g)
+		goto out_host_put;
+
+	ide_init_disk(g, drive);
+
 	host->max_id = 1;
 
 #if IDESCSI_DEBUG_LOG
@@ -1061,19 +1136,27 @@
 	drive->driver_data = host;
 	idescsi = scsihost_to_idescsi(host);
 	idescsi->drive = drive;
+	idescsi->driver = &idescsi_driver;
+	idescsi->host = host;
+	idescsi->disk = g;
+	g->private_data = &idescsi->driver;
 	err = ide_register_subdriver(drive, &idescsi_driver);
 	if (!err) {
 		idescsi_setup (drive, idescsi);
-		drive->disk->fops = &idescsi_ops;
+		g->fops = &idescsi_ops;
+		ide_register_region(g);
 		err = scsi_add_host(host, &drive->gendev);
 		if (!err) {
 			scsi_scan_host(host);
 			return 0;
 		}
 		/* fall through on error */
+		ide_unregister_region(g);
 		ide_unregister_subdriver(drive);
 	}
 
+	put_disk(g);
+out_host_put:
 	scsi_host_put(host);
 	return err;
 }
diff -Nru a/include/linux/ata.h b/include/linux/ata.h
--- a/include/linux/ata.h	2005-03-07 15:22:36 -08:00
+++ b/include/linux/ata.h	2005-03-07 15:22:36 -08:00
@@ -174,6 +174,7 @@
 	ATA_TFLAG_ISADDR	= (1 << 1), /* enable r/w to nsect/lba regs */
 	ATA_TFLAG_DEVICE	= (1 << 2), /* enable r/w to device reg */
 	ATA_TFLAG_WRITE		= (1 << 3), /* data dir: host->dev==1 (write) */
+	ATA_TFLAG_IO_16BIT	= (1 << 4), /* force 16bit pio */
 };
 
 enum ata_tf_protocols {
diff -Nru a/include/linux/ide.h b/include/linux/ide.h
--- a/include/linux/ide.h	2005-03-07 15:22:36 -08:00
+++ b/include/linux/ide.h	2005-03-07 15:22:36 -08:00
@@ -718,6 +718,7 @@
 					 */
 	unsigned scsi		: 1;	/* 0=default, 1=ide-scsi emulation */
 	unsigned sleeping	: 1;	/* 1=sleeping & sleep field valid */
+	unsigned post_reset	: 1;
 
         u8	quirk_list;	/* considered quirky, set for a specific host */
         u8	init_speed;	/* transfer rate set at boot */
@@ -756,7 +757,6 @@
 	struct list_head list;
 	struct device	gendev;
 	struct semaphore gendev_rel_sem;	/* to deal with device release() */
-	struct gendisk *disk;
 } ide_drive_t;
 
 #define IDE_CHIPSET_PCI_MASK	\
@@ -1098,15 +1098,10 @@
 	ide_startstop_t	(*error)(ide_drive_t *, struct request *rq, u8, u8);
 	ide_startstop_t	(*abort)(ide_drive_t *, struct request *rq);
 	int		(*ioctl)(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
-	void		(*pre_reset)(ide_drive_t *);
-	sector_t	(*capacity)(ide_drive_t *);
-	ide_startstop_t	(*special)(ide_drive_t *);
 	ide_proc_entry_t	*proc;
 	int		(*attach)(ide_drive_t *);
 	void		(*ata_prebuilder)(ide_drive_t *);
 	void		(*atapi_prebuilder)(ide_drive_t *);
-	ide_startstop_t	(*start_power_step)(ide_drive_t *, struct request *);
-	void		(*complete_power_step)(ide_drive_t *, struct request *, u8, u8);
 	struct device_driver	gen_driver;
 	struct list_head drives;
 	struct list_head drivers;
@@ -1114,7 +1109,7 @@
 
 #define DRIVER(drive)		((drive)->driver)
 
-extern int generic_ide_ioctl(struct file *, struct block_device *, unsigned, unsigned long);
+int generic_ide_ioctl(ide_drive_t *, struct file *, struct block_device *, unsigned, unsigned long);
 
 /*
  * ide_hwifs[] is the master data structure used to keep track
@@ -1263,6 +1258,7 @@
  *	struct hd_drive_hob_hdr		hobf;
  *	hob_struct_t		hobf;
  */
+	unsigned long		flags;		/* ATA_TFLAG_xxx */
 	task_ioreg_t		tfRegister[8];
 	task_ioreg_t		hobRegister[8];
 	ide_reg_valid_t		tf_out_flags;
@@ -1331,7 +1327,7 @@
 extern void do_ide_request(request_queue_t *);
 extern void ide_init_subdrivers(void);
 
-extern struct block_device_operations ide_fops[];
+void ide_init_disk(struct gendisk *, ide_drive_t *);
 
 extern int ata_attach(ide_drive_t *);
 
@@ -1375,7 +1371,6 @@
 enum {
 	/* Uses ISA control ports not PCI ones. */
 	IDEPCI_FLAG_ISA_PORTS		= (1 << 0),
-	IDEPCI_FLAG_FORCE_PDC		= (1 << 1),
 };
 
 typedef struct ide_pci_device_s {
@@ -1445,6 +1440,9 @@
 extern int ide_hwif_request_regions(ide_hwif_t *hwif);
 extern void ide_hwif_release_regions(ide_hwif_t* hwif);
 extern void ide_unregister (unsigned int index);
+
+void ide_register_region(struct gendisk *);
+void ide_unregister_region(struct gendisk *);
 
 void ide_undecoded_slave(ide_hwif_t *);
 
diff -Nru a/include/linux/pci_ids.h b/include/linux/pci_ids.h
--- a/include/linux/pci_ids.h	2005-03-07 15:22:36 -08:00
+++ b/include/linux/pci_ids.h	2005-03-07 15:22:36 -08:00
@@ -1295,6 +1295,7 @@
 #define PCI_DEVICE_ID_VIA_8703_51_0	0x3148
 #define PCI_DEVICE_ID_VIA_8237_SATA	0x3149
 #define PCI_DEVICE_ID_VIA_XN266		0x3156
+#define PCI_DEVICE_ID_VIA_6410		0x3164
 #define PCI_DEVICE_ID_VIA_8754C_0	0x3168
 #define PCI_DEVICE_ID_VIA_8235		0x3177
 #define PCI_DEVICE_ID_VIA_P4N333	0x3178
