#undef REALLY_SLOW_IO /* most systems can safely undef this */
+//#define DEBUG
+
#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
return 0; /* lba_capacity value may be bad */
}
-static int idedisk_start_tag(ide_drive_t *drive, struct request *rq)
-{
- unsigned long flags;
- int ret = 1;
-
- spin_lock_irqsave(&ide_lock, flags);
-
- if (ata_pending_commands(drive) < drive->queue_depth)
- ret = blk_queue_start_tag(drive->queue, rq);
-
- spin_unlock_irqrestore(&ide_lock, flags);
- return ret;
-}
-
#ifndef CONFIG_IDE_TASKFILE_IO
/*
nsectors.all = (u16) rq->nr_sectors;
- if (drive->using_tcq && idedisk_start_tag(drive, rq)) {
- if (!ata_pending_commands(drive))
- BUG();
-
- return ide_started;
- }
-
if (IDE_CONTROL_REG)
hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
if (drive->addressing == 1) {
task_ioreg_t tasklets[10];
- if (blk_rq_tagged(rq)) {
- tasklets[0] = nsectors.b.low;
- tasklets[1] = nsectors.b.high;
- tasklets[2] = rq->tag << 3;
- tasklets[3] = 0;
- } else {
- tasklets[0] = 0;
- tasklets[1] = 0;
- tasklets[2] = nsectors.b.low;
- tasklets[3] = nsectors.b.high;
- }
+ pr_debug("%s: LBA=0x%012llx\n", drive->name, block);
+ tasklets[0] = 0;
+ tasklets[1] = 0;
+ tasklets[2] = nsectors.b.low;
+ tasklets[3] = nsectors.b.high;
tasklets[4] = (task_ioreg_t) block;
tasklets[5] = (task_ioreg_t) (block>>8);
tasklets[6] = (task_ioreg_t) (block>>16);
tasklets[9] = (task_ioreg_t)((u64)block >> 40);
}
#ifdef DEBUG
- printk("%s: %sing: LBAsect=%lu, sectors=%ld, "
- "buffer=0x%08lx, LBAsect=0x%012lx\n",
- drive->name,
- rq_data_dir(rq)==READ?"read":"writ",
- block,
- rq->nr_sectors,
- (unsigned long) rq->buffer,
- block);
printk("%s: 0x%02x%02x 0x%02x%02x%02x%02x%02x%02x\n",
drive->name, tasklets[3], tasklets[2],
tasklets[9], tasklets[8], tasklets[7],
hwif->OUTB(tasklets[6], IDE_HCYL_REG);
hwif->OUTB(0x00|drive->select.all,IDE_SELECT_REG);
} else {
-#ifdef DEBUG
- printk("%s: %sing: LBAsect=%llu, sectors=%ld, "
- "buffer=0x%08lx\n",
- drive->name,
- rq_data_dir(rq)==READ?"read":"writ",
- (unsigned long long)block, rq->nr_sectors,
- (unsigned long) rq->buffer);
-#endif
- if (blk_rq_tagged(rq)) {
- hwif->OUTB(nsectors.b.low, IDE_FEATURE_REG);
- hwif->OUTB(rq->tag << 3, IDE_NSECTOR_REG);
- } else {
- hwif->OUTB(0x00, IDE_FEATURE_REG);
- hwif->OUTB(nsectors.b.low, IDE_NSECTOR_REG);
- }
-
+ hwif->OUTB(0x00, IDE_FEATURE_REG);
+ hwif->OUTB(nsectors.b.low, IDE_NSECTOR_REG);
hwif->OUTB(block, IDE_SECTOR_REG);
hwif->OUTB(block>>=8, IDE_LCYL_REG);
hwif->OUTB(block>>=8, IDE_HCYL_REG);
head = track % drive->head;
cyl = track / drive->head;
- if (blk_rq_tagged(rq)) {
- hwif->OUTB(nsectors.b.low, IDE_FEATURE_REG);
- hwif->OUTB(rq->tag << 3, IDE_NSECTOR_REG);
- } else {
- hwif->OUTB(0x00, IDE_FEATURE_REG);
- hwif->OUTB(nsectors.b.low, IDE_NSECTOR_REG);
- }
+ pr_debug("%s: CHS=%u/%u/%u\n", drive->name, cyl, head, sect);
+ hwif->OUTB(0x00, IDE_FEATURE_REG);
+ hwif->OUTB(nsectors.b.low, IDE_NSECTOR_REG);
hwif->OUTB(cyl, IDE_LCYL_REG);
hwif->OUTB(cyl>>8, IDE_HCYL_REG);
hwif->OUTB(head|drive->select.all,IDE_SELECT_REG);
-#ifdef DEBUG
- printk("%s: %sing: CHS=%d/%d/%d, sectors=%ld, buffer=0x%08lx\n",
- drive->name, rq_data_dir(rq)==READ?"read":"writ", cyl,
- head, sect, rq->nr_sectors, (unsigned long) rq->buffer);
-#endif
}
if (rq_data_dir(rq) == READ) {
-#ifdef CONFIG_BLK_DEV_IDE_TCQ
- if (blk_rq_tagged(rq))
- return __ide_dma_queued_read(drive);
-#endif
if (drive->using_dma && !hwif->ide_dma_read(drive))
return ide_started;
((lba48) ? WIN_READ_EXT : WIN_READ));
ide_execute_command(drive, command, &read_intr, WAIT_CMD, NULL);
return ide_started;
- } else if (rq_data_dir(rq) == WRITE) {
+ } else {
ide_startstop_t startstop;
-#ifdef CONFIG_BLK_DEV_IDE_TCQ
- if (blk_rq_tagged(rq))
- return __ide_dma_queued_write(drive);
-#endif
+
if (drive->using_dma && !(HWIF(drive)->ide_dma_write(drive)))
return ide_started;
}
return ide_started;
}
- blk_dump_rq_flags(rq, "__ide_do_rw_disk - bad command");
- ide_end_request(drive, 0, 0);
- return ide_stopped;
}
EXPORT_SYMBOL_GPL(__ide_do_rw_disk);
*/
ide_startstop_t __ide_do_rw_disk (ide_drive_t *drive, struct request *rq, sector_t block)
{
- BUG_ON(drive->blocked);
- if (!blk_fs_request(rq)) {
- blk_dump_rq_flags(rq, "__ide_do_rw_disk - bad command");
- ide_end_request(drive, 0, 0);
- return ide_stopped;
- }
-
/*
* 268435455 == 137439 MB or 28bit limit
*
* need to add split taskfile operations based on 28bit threshold.
*/
-
- if (drive->using_tcq && idedisk_start_tag(drive, rq)) {
- if (!ata_pending_commands(drive))
- BUG();
-
- return ide_started;
- }
-
if (drive->addressing == 1) /* 48-bit LBA */
return lba_48_rw_disk(drive, rq, (unsigned long long) block);
if (drive->select.b.lba) /* 28-bit LBA */
if (cmd == READ) {
task->command_type = IDE_DRIVE_TASK_IN;
- if (drive->using_tcq)
- return lba48 ? WIN_READDMA_QUEUED_EXT : WIN_READDMA_QUEUED;
if (drive->using_dma)
return lba48 ? WIN_READDMA_EXT : WIN_READDMA;
if (drive->mult_count) {
return lba48 ? WIN_READ_EXT : WIN_READ;
} else {
task->command_type = IDE_DRIVE_TASK_RAW_WRITE;
- if (drive->using_tcq)
- return lba48 ? WIN_WRITEDMA_QUEUED_EXT : WIN_WRITEDMA_QUEUED;
if (drive->using_dma)
return lba48 ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
if (drive->mult_count) {
nsectors.all = (u16) rq->nr_sectors;
-#ifdef DEBUG
- printk("%s: %sing: ", drive->name, (rq_data_dir(rq)==READ) ? "read" : "writ");
- printk("CHS=%d/%d/%d, ", cyl, head, sect);
- printk("sectors=%ld, ", rq->nr_sectors);
- printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
-#endif
+ pr_debug("%s: CHS=%u/%u/%u\n", drive->name, cyl, head, sect);
memset(&args, 0, sizeof(ide_task_t));
sectors = (rq->nr_sectors == 256) ? 0x00 : rq->nr_sectors;
- if (blk_rq_tagged(rq)) {
- args.tfRegister[IDE_FEATURE_OFFSET] = sectors;
- args.tfRegister[IDE_NSECTOR_OFFSET] = rq->tag << 3;
- } else
- args.tfRegister[IDE_NSECTOR_OFFSET] = sectors;
-
+ args.tfRegister[IDE_NSECTOR_OFFSET] = sectors;
args.tfRegister[IDE_SECTOR_OFFSET] = sect;
args.tfRegister[IDE_LCYL_OFFSET] = cyl;
args.tfRegister[IDE_HCYL_OFFSET] = (cyl>>8);
nsectors.all = (u16) rq->nr_sectors;
-#ifdef DEBUG
- printk("%s: %sing: ", drive->name, (rq_data_dir(rq)==READ) ? "read" : "writ");
- printk("LBAsect=%lld, ", block);
- printk("sectors=%ld, ", rq->nr_sectors);
- printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
-#endif
-
memset(&args, 0, sizeof(ide_task_t));
sectors = (rq->nr_sectors == 256) ? 0x00 : rq->nr_sectors;
- if (blk_rq_tagged(rq)) {
- args.tfRegister[IDE_FEATURE_OFFSET] = sectors;
- args.tfRegister[IDE_NSECTOR_OFFSET] = rq->tag << 3;
- } else
- args.tfRegister[IDE_NSECTOR_OFFSET] = sectors;
-
+ args.tfRegister[IDE_NSECTOR_OFFSET] = sectors;
args.tfRegister[IDE_SECTOR_OFFSET] = block;
args.tfRegister[IDE_LCYL_OFFSET] = (block>>=8);
args.tfRegister[IDE_HCYL_OFFSET] = (block>>=8);
nsectors.all = (u16) rq->nr_sectors;
-#ifdef DEBUG
- printk("%s: %sing: ", drive->name, (rq_data_dir(rq)==READ) ? "read" : "writ");
- printk("LBAsect=%lld, ", block);
- printk("sectors=%ld, ", rq->nr_sectors);
- printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
-#endif
-
memset(&args, 0, sizeof(ide_task_t));
sectors = (rq->nr_sectors == 65536) ? 0 : rq->nr_sectors;
- if (blk_rq_tagged(rq)) {
- args.tfRegister[IDE_FEATURE_OFFSET] = sectors;
- args.tfRegister[IDE_NSECTOR_OFFSET] = rq->tag << 3;
- args.hobRegister[IDE_FEATURE_OFFSET] = sectors >> 8;
- args.hobRegister[IDE_NSECTOR_OFFSET] = 0;
- } else {
- args.tfRegister[IDE_NSECTOR_OFFSET] = sectors;
- args.hobRegister[IDE_NSECTOR_OFFSET] = sectors >> 8;
- }
-
+ args.tfRegister[IDE_NSECTOR_OFFSET] = sectors;
+ args.hobRegister[IDE_NSECTOR_OFFSET] = sectors >> 8;
args.tfRegister[IDE_SECTOR_OFFSET] = block; /* low lba */
args.tfRegister[IDE_LCYL_OFFSET] = (block>>=8); /* mid lba */
args.tfRegister[IDE_HCYL_OFFSET] = (block>>=8); /* hi lba */
{
ide_hwif_t *hwif = HWIF(drive);
+ BUG_ON(drive->blocked);
+
+ if (!blk_fs_request(rq)) {
+ blk_dump_rq_flags(rq, "ide_do_rw_disk - bad command");
+ ide_end_request(drive, 0, 0);
+ return ide_stopped;
+ }
+
+ pr_debug("%s: %sing: block=%llu, sectors=%lu, buffer=0x%08lx\n",
+ drive->name, rq_data_dir(rq) == READ ? "read" : "writ",
+ block, rq->nr_sectors, (unsigned long)rq->buffer);
+
if (hwif->rw_disk)
return hwif->rw_disk(drive, rq, block);
else
return __ide_do_rw_disk(drive, rq, block);
}
-static int do_idedisk_flushcache(ide_drive_t *drive);
-
static u8 idedisk_dump_status (ide_drive_t *drive, const char *msg, u8 stat)
{
ide_hwif_t *hwif = HWIF(drive);
ide_hwif_t *hwif;
struct request *rq;
u8 err;
- int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS;
err = idedisk_dump_status(drive, msg, stat);
rq->errors |= ERROR_RECAL;
}
}
- if ((stat & DRQ_STAT) && rq_data_dir(rq) == READ) {
- /*
- * try_to_flush_leftover_data() is invoked in response to
- * a drive unexpectedly having its DRQ_STAT bit set. As
- * an alternative to resetting the drive, this routine
- * tries to clear the condition by read a sector's worth
- * of data from the drive. Of course, this may not help
- * if the drive is *waiting* for data from *us*.
- */
- while (i > 0) {
- u32 buffer[16];
- unsigned int wcount = (i > 16) ? 16 : i;
- i -= wcount;
- taskfile_input_data(drive, buffer, wcount);
- }
- }
+ if ((stat & DRQ_STAT) && rq_data_dir(rq) == READ)
+ try_to_flush_leftover_data(drive);
if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT)) {
/* force an abort */
hwif->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);
return addr;
}
-#ifdef CONFIG_IDEDISK_STROKE
/*
* Sets maximum virtual LBA address of the drive.
* Returns new maximum virtual LBA address (> 0) or 0 on failure.
return addr_set;
}
-#endif /* CONFIG_IDEDISK_STROKE */
-
static unsigned long long sectors_to_MB(unsigned long long n)
{
n <<= 9; /* make it bytes */
drive->name,
capacity, sectors_to_MB(capacity),
set_max, sectors_to_MB(set_max));
-#ifdef CONFIG_IDEDISK_STROKE
+
+ if (!drive->stroke)
+ return;
+
if (lba48)
set_max = idedisk_set_max_address_ext(drive, set_max);
else
printk(KERN_INFO "%s: Host Protected Area disabled.\n",
drive->name);
}
-#endif
}
/*
return 0;
}
+/* check if CACHE FLUSH (EXT) command is supported (bits defined in ATA-6) */
+#define ide_id_has_flush_cache(id) ((id)->cfs_enable_2 & 0x3000)
+
+/* some Maxtor disks have bit 13 defined incorrectly so check bit 10 too */
+#define ide_id_has_flush_cache_ext(id) \
+ (((id)->cfs_enable_2 & 0x2400) == 0x2400)
+
static int write_cache (ide_drive_t *drive, int arg)
{
ide_task_t args;
- if (!(drive->id->cfs_enable_2 & 0x3000))
+ if (!ide_id_has_flush_cache(drive->id))
return 1;
memset(&args, 0, sizeof(ide_task_t));
ide_task_t args;
memset(&args, 0, sizeof(ide_task_t));
- if (drive->id->cfs_enable_2 & 0x2400)
+ 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;
return 0;
}
-#ifdef CONFIG_BLK_DEV_IDE_TCQ
-static int set_using_tcq(ide_drive_t *drive, int arg)
-{
- int ret;
-
- if (!drive->driver)
- return -EPERM;
- if (arg == drive->queue_depth && drive->using_tcq)
- return 0;
-
- /*
- * set depth, but check also id for max supported depth
- */
- drive->queue_depth = arg ? arg : 1;
- if (drive->id) {
- if (drive->queue_depth > drive->id->queue_depth + 1)
- drive->queue_depth = drive->id->queue_depth + 1;
- }
-
- if (arg)
- ret = __ide_dma_queued_on(drive);
- else
- ret = __ide_dma_queued_off(drive);
-
- return ret ? -EIO : 0;
-}
-#endif
-
/*
* drive->addressing:
* 0: 28-bit
ide_add_setting(drive, "acoustic", SETTING_RW, HDIO_GET_ACOUSTIC, HDIO_SET_ACOUSTIC, TYPE_BYTE, 0, 254, 1, 1, &drive->acoustic, set_acoustic);
ide_add_setting(drive, "failures", SETTING_RW, -1, -1, TYPE_INT, 0, 65535, 1, 1, &drive->failures, NULL);
ide_add_setting(drive, "max_failures", SETTING_RW, -1, -1, TYPE_INT, 0, 65535, 1, 1, &drive->max_failures, NULL);
-#ifdef CONFIG_BLK_DEV_IDE_TCQ
- ide_add_setting(drive, "using_tcq", SETTING_RW, HDIO_GET_QDMA, HDIO_SET_QDMA, TYPE_BYTE, 0, IDE_MAX_TAG, 1, 1, &drive->using_tcq, set_using_tcq);
-#endif
}
/*
idedisk_pm_flush_cache = ide_pm_state_start_suspend,
idedisk_pm_standby,
- idedisk_pm_restore_dma = ide_pm_state_start_resume,
+ 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)
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;
}
}
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) {
+ if (!drive->wcache || !ide_id_has_flush_cache(drive->id)) {
idedisk_complete_power_step(drive, rq, 0, 0);
return ide_stopped;
}
- if (drive->id->cfs_enable_2 & 0x2400)
+ 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_restore_dma: /* Resume step 1 (restore DMA) */
+ 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
#endif /* CONFIG_IDEDISK_MULTI_MODE */
}
drive->no_io_32bit = id->dword_io ? 1 : 0;
- if (drive->id->cfs_enable_2 & 0x3000)
- write_cache(drive, (id->cfs_enable_2 & 0x3000));
-#ifdef CONFIG_BLK_DEV_IDE_TCQ_DEFAULT
- if (drive->using_dma)
- __ide_dma_queued_on(drive);
-#endif
+ /* write cache enabled? */
+ if ((id->csfo & 1) || (id->cfs_enable_1 & (1 << 5)))
+ drive->wcache = 1;
+
+ write_cache(drive, 1);
+}
+
+static void ide_cacheflush_p(ide_drive_t *drive)
+{
+ if (!drive->wcache || !ide_id_has_flush_cache(drive->id))
+ return;
+
+ if (do_idedisk_flushcache(drive))
+ printk(KERN_INFO "%s: wcache flush failed!\n", drive->name);
}
static int idedisk_cleanup (ide_drive_t *drive)
{
- static int ide_cacheflush_p(ide_drive_t *drive);
struct gendisk *g = drive->disk;
ide_cacheflush_p(drive);
if (ide_unregister_subdriver(drive))
{
ide_drive_t *drive = container_of(dev, ide_drive_t, gendev);
+#ifdef CONFIG_ALPHA
+ /* On Alpha, halt(8) doesn't actually turn the machine off,
+ it puts you into the sort of firmware monitor. Typically,
+ it's used to boot another kernel image, so it's not much
+ different from reboot(8). Therefore, we don't need to
+ spin down the disk in this case, especially since Alpha
+ firmware doesn't handle disks in standby mode properly.
+ On the other hand, it's reasonably safe to turn the power
+ off when the shutdown process reaches the firmware prompt,
+ as the firmware initialization takes rather long time -
+ at least 10 seconds, which should be sufficient for
+ the disk to expire its write cache. */
+ if (system_state != SYSTEM_POWER_OFF) {
+#else
+ if (system_state == SYSTEM_RESTART) {
+#endif
+ ide_cacheflush_p(drive);
+ return;
+ }
+
printk("Shutdown: %s\n", drive->name);
dev->bus->suspend(dev, PM_SUSPEND_STANDBY);
}
static int idedisk_open(struct inode *inode, struct file *filp)
{
- u8 cf;
ide_drive_t *drive = inode->i_bdev->bd_disk->private_data;
drive->usage++;
if (drive->removable && drive->usage == 1) {
if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL))
drive->doorlocking = 0;
}
- drive->wcache = 0;
- /* Cache enabled? */
- if (drive->id->csfo & 1)
- drive->wcache = 1;
- /* Cache command set available? */
- if (drive->id->cfs_enable_1 & (1 << 5))
- drive->wcache = 1;
- /* ATA6 cache extended commands */
- cf = drive->id->command_set_2 >> 24;
- if ((cf & 0xC0) == 0x40 && (cf & 0x30) != 0)
- drive->wcache = 1;
- return 0;
-}
-
-static int ide_cacheflush_p(ide_drive_t *drive)
-{
- if (!(drive->id->cfs_enable_2 & 0x3000))
- return 0;
-
- if(drive->wcache)
- {
- if (do_idedisk_flushcache(drive))
- {
- printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n",
- drive->name);
- return -EIO;
- }
- return 1;
- }
return 0;
}
unsigned int cmd, unsigned long arg)
{
struct block_device *bdev = inode->i_bdev;
- return generic_ide_ioctl(bdev, cmd, arg);
+ return generic_ide_ioctl(file, bdev, cmd, arg);
}
static int idedisk_media_changed(struct gendisk *disk)
if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n",
drive->name, drive->head);
- if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache)
- if (do_idedisk_flushcache(drive))
- printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n",
- drive->name);
+ ide_cacheflush_p(drive);
ide_unregister_subdriver(drive);
DRIVER(drive)->busy--;
goto failed;