ide_startstop_t __ide_do_rw_disk (ide_drive_t *drive, struct request *rq, sector_t block)
{
ide_hwif_t *hwif = HWIF(drive);
+ unsigned int dma = drive->using_dma;
u8 lba48 = (drive->addressing == 1) ? 1 : 0;
task_ioreg_t command = WIN_NOP;
ata_nsector_t nsectors;
nsectors.all = (u16) rq->nr_sectors;
+ if (hwif->no_lba48_dma && lba48 && dma) {
+ if (rq->sector + rq->nr_sectors > 1ULL << 28)
+ dma = 0;
+ }
+
if (IDE_CONTROL_REG)
hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
}
if (rq_data_dir(rq) == READ) {
- if (drive->using_dma && !hwif->ide_dma_read(drive))
+ if (dma && !hwif->ide_dma_read(drive))
return ide_started;
command = ((drive->mult_count) ?
} else {
ide_startstop_t startstop;
- if (drive->using_dma && !(HWIF(drive)->ide_dma_write(drive)))
+ if (dma && !hwif->ide_dma_write(drive))
return ide_started;
command = ((drive->mult_count) ?
}
EXPORT_SYMBOL_GPL(__ide_do_rw_disk);
-static u8 get_command(ide_drive_t *drive, int cmd, ide_task_t *task)
+static u8 get_command(ide_drive_t *drive, struct request *rq, ide_task_t *task)
{
unsigned int lba48 = (drive->addressing == 1) ? 1 : 0;
+ unsigned int dma = drive->using_dma;
+
+ if (drive->hwif->no_lba48_dma && lba48 && dma) {
+ if (rq->sector + rq->nr_sectors > 1ULL << 28)
+ dma = 0;
+ }
- if (cmd == READ) {
+ if (rq_data_dir(rq) == READ) {
task->command_type = IDE_DRIVE_TASK_IN;
- if (drive->using_dma)
+ if (dma)
return lba48 ? WIN_READDMA_EXT : WIN_READDMA;
+ task->handler = &task_in_intr;
if (drive->mult_count) {
- task->handler = &task_mulin_intr;
+ task->data_phase = TASKFILE_MULTI_IN;
return lba48 ? WIN_MULTREAD_EXT : WIN_MULTREAD;
}
- task->handler = &task_in_intr;
+ task->data_phase = TASKFILE_IN;
return lba48 ? WIN_READ_EXT : WIN_READ;
} else {
task->command_type = IDE_DRIVE_TASK_RAW_WRITE;
- if (drive->using_dma)
+ if (dma)
return lba48 ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
+ task->prehandler = &pre_task_out_intr;
+ task->handler = &task_out_intr;
if (drive->mult_count) {
- task->prehandler = &pre_task_mulout_intr;
- task->handler = &task_mulout_intr;
+ task->data_phase = TASKFILE_MULTI_OUT;
return lba48 ? WIN_MULTWRITE_EXT : WIN_MULTWRITE;
}
- task->prehandler = &pre_task_out_intr;
- task->handler = &task_out_intr;
+ task->data_phase = TASKFILE_OUT;
return lba48 ? WIN_WRITE_EXT : WIN_WRITE;
}
}
args.tfRegister[IDE_HCYL_OFFSET] = (cyl>>8);
args.tfRegister[IDE_SELECT_OFFSET] = head;
args.tfRegister[IDE_SELECT_OFFSET] |= drive->select.all;
- args.tfRegister[IDE_COMMAND_OFFSET] = get_command(drive, rq_data_dir(rq), &args);
+ args.tfRegister[IDE_COMMAND_OFFSET] = get_command(drive, rq, &args);
args.rq = (struct request *) rq;
rq->special = (ide_task_t *)&args;
+ drive->hwif->data_phase = args.data_phase;
return do_rw_taskfile(drive, &args);
}
args.tfRegister[IDE_HCYL_OFFSET] = (block>>=8);
args.tfRegister[IDE_SELECT_OFFSET] = ((block>>8)&0x0f);
args.tfRegister[IDE_SELECT_OFFSET] |= drive->select.all;
- args.tfRegister[IDE_COMMAND_OFFSET] = get_command(drive, rq_data_dir(rq), &args);
+ args.tfRegister[IDE_COMMAND_OFFSET] = get_command(drive, rq, &args);
args.rq = (struct request *) rq;
rq->special = (ide_task_t *)&args;
+ drive->hwif->data_phase = args.data_phase;
return do_rw_taskfile(drive, &args);
}
args.tfRegister[IDE_LCYL_OFFSET] = (block>>=8); /* mid lba */
args.tfRegister[IDE_HCYL_OFFSET] = (block>>=8); /* hi lba */
args.tfRegister[IDE_SELECT_OFFSET] = drive->select.all;
- args.tfRegister[IDE_COMMAND_OFFSET] = get_command(drive, rq_data_dir(rq), &args);
+ args.tfRegister[IDE_COMMAND_OFFSET] = get_command(drive, rq, &args);
args.hobRegister[IDE_SECTOR_OFFSET] = (block>>=8); /* low lba */
args.hobRegister[IDE_LCYL_OFFSET] = (block>>=8); /* mid lba */
args.hobRegister[IDE_HCYL_OFFSET] = (block>>=8); /* hi lba */
args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80);
args.rq = (struct request *) rq;
rq->special = (ide_task_t *)&args;
+ drive->hwif->data_phase = args.data_phase;
return do_rw_taskfile(drive, &args);
}
local_irq_set(flags);
printk("%s: %s: status=0x%02x", drive->name, msg, stat);
-#if FANCY_STATUS_DUMPS
printk(" { ");
if (stat & BUSY_STAT)
printk("Busy ");
if (stat & ERR_STAT) printk("Error ");
}
printk("}");
-#endif /* FANCY_STATUS_DUMPS */
printk("\n");
if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
err = hwif->INB(IDE_ERROR_REG);
printk("%s: %s: error=0x%02x", drive->name, msg, err);
-#if FANCY_STATUS_DUMPS
printk(" { ");
if (err & ABRT_ERR) printk("DriveStatusError ");
if (err & ICRC_ERR)
(unsigned long long)HWGROUP(drive)->rq->sector);
}
}
-#endif /* FANCY_STATUS_DUMPS */
printk("\n");
+ {
+ struct request *rq;
+ unsigned char opcode = 0;
+ int found = 0;
+
+ spin_lock(&ide_lock);
+ rq = HWGROUP(drive)->rq;
+ spin_unlock(&ide_lock);
+ if (!rq)
+ goto out;
+ if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK)) {
+ char *args = rq->buffer;
+ if (args) {
+ opcode = args[0];
+ found = 1;
+ }
+ } else if (rq->flags & REQ_DRIVE_TASKFILE) {
+ ide_task_t *args = rq->special;
+ if (args) {
+ task_struct_t *tf = (task_struct_t *) args->tfRegister;
+ opcode = tf->command;
+ found = 1;
+ }
+ }
+ printk("ide: failed opcode was: ");
+ if (!found)
+ printk("unknown\n");
+ else
+ printk("0x%02x\n", opcode);
+ }
+out:
local_irq_restore(flags);
return err;
}
args.tfRegister[IDE_HCYL_OFFSET] = SMART_HCYL_PASS;
args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SMART;
args.command_type = IDE_DRIVE_TASK_IN;
+ args.data_phase = TASKFILE_IN;
args.handler = &task_in_intr;
(void) smart_enable(drive);
return ide_raw_taskfile(drive, &args, buf);
#endif /* CONFIG_PROC_FS */
+static int idedisk_issue_flush(request_queue_t *q, struct gendisk *disk,
+ sector_t *error_sector)
+{
+ ide_drive_t *drive = q->queuedata;
+ struct request *rq;
+ int ret;
+
+ if (!drive->wcache)
+ return 0;
+
+ rq = blk_get_request(q, WRITE, __GFP_WAIT);
+
+ memset(rq->cmd, 0, sizeof(rq->cmd));
+
+ if (ide_id_has_flush_cache_ext(drive->id) &&
+ (drive->capacity64 >= (1UL << 28)))
+ rq->cmd[0] = WIN_FLUSH_CACHE_EXT;
+ else
+ rq->cmd[0] = WIN_FLUSH_CACHE;
+
+
+ rq->flags |= REQ_DRIVE_TASK | REQ_SOFTBARRIER;
+ rq->buffer = rq->cmd;
+
+ ret = blk_execute_rq(q, disk, rq);
+
+ /*
+ * if we failed and caller wants error offset, get it
+ */
+ if (ret && error_sector)
+ *error_sector = ide_get_error_location(drive, rq->cmd);
+
+ blk_put_request(rq);
+ return ret;
+}
+
/*
* This is tightly woven into the driver->do_special can not touch.
* DON'T do it again until a total personality rewrite is committed.
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)
+static int write_cache(ide_drive_t *drive, int arg)
{
ide_task_t args;
+ int err;
if (!ide_id_has_flush_cache(drive->id))
return 1;
args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SETFEATURES;
args.command_type = IDE_DRIVE_TASK_NO_DATA;
args.handler = &task_no_data_intr;
- (void) ide_raw_taskfile(drive, &args, NULL);
+
+ err = ide_raw_taskfile(drive, &args, NULL);
+ if (err)
+ return err;
drive->wcache = arg;
return 0;
{
struct hd_driveid *id = drive->id;
unsigned long long capacity;
+ int barrier;
idedisk_add_settings(drive);
blk_queue_max_sectors(drive->queue, max_s);
}
- printk("%s: max request size: %dKiB\n", drive->name, drive->queue->max_sectors / 2);
+ 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) {
/* limit drive capacity to 137GB if LBA48 cannot be used */
if (drive->addressing == 0 && drive->capacity64 > 1ULL << 28) {
- printk("%s: cannot use LBA48 - full capacity "
+ printk(KERN_WARNING "%s: cannot use LBA48 - full capacity "
"%llu sectors (%llu MB)\n",
drive->name, (unsigned long long)drive->capacity64,
sectors_to_MB(drive->capacity64));
drive->capacity64 = 1ULL << 28;
}
+ if (drive->hwif->no_lba48_dma && drive->addressing) {
+ if (drive->capacity64 > 1ULL << 28) {
+ printk(KERN_INFO "%s: cannot use LBA48 DMA - PIO mode will"
+ " be used for accessing sectors > %u\n",
+ drive->name, 1 << 28);
+ } else
+ drive->addressing = 0;
+ }
+
/*
* if possible, give fdisk access to more of the drive,
* by correcting bios_cyls:
drive->wcache = 1;
write_cache(drive, 1);
+
+ /*
+ * We must avoid issuing commands a drive does not understand
+ * or we may crash it. We check flush cache is supported. We also
+ * check we have the LBA48 flush cache if the drive capacity is
+ * too large. By this time we have trimmed the drive capacity if
+ * LBA48 is not available so we don't need to recheck that.
+ */
+ barrier = 0;
+ if (ide_id_has_flush_cache(id))
+ barrier = 1;
+ if (drive->addressing == 1) {
+ /* Can't issue the correct flush ? */
+ if (capacity > (1ULL << 28) && !ide_id_has_flush_cache_ext(id))
+ barrier = 0;
+ }
+
+ printk(KERN_DEBUG "%s: cache flushes %ssupported\n",
+ drive->name, barrier ? "" : "not ");
+ if (barrier) {
+ blk_queue_ordered(drive->queue, 1);
+ blk_queue_issue_flush_fn(drive->queue, idedisk_issue_flush);
+ }
}
static void ide_cacheflush_p(ide_drive_t *drive)
if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n",
drive->name, drive->head);
- ide_cacheflush_p(drive);
- ide_unregister_subdriver(drive);
- DRIVER(drive)->busy--;
- goto failed;
- }
+ drive->attach = 0;
+ } else
+ drive->attach = 1;
DRIVER(drive)->busy--;
g->minors = 1 << PARTN_BITS;
strcpy(g->devfs_name, drive->devfs_name);
g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0;
set_capacity(g, current_capacity(drive));
g->fops = &idedisk_ops;
- drive->attach = 1;
add_disk(g);
return 0;
failed: