Commit e00cb941 authored by Jens Axboe's avatar Jens Axboe

[PATCH] various ide fixes and cleanups

o Remove some ide compile warnings, old suspend stuff is not used at
  all, for instance.

o If elv_next_request() returns NULL, remember to clear hwgroup->busy
  if we don't have pending commands. This is important. If a queue
  prep function kills a request, we would before quit with hwgroup busy.
  This essentially froze the hwgroup.

o Don't do own list manipulation in ide_do_drive_cmd(). Use the new and
  great elv_add_request() functions

o Fix race on inspection of request after io completion by bumping the
  request reference count prior to ioscheduler insertion.

o Make ide-floppy understand a REQ_BLOCK_PC eject. More may follow, it's
  ATAPI after all.

o Clear hw before passing to ide_init_hwif_ports(). Fixes oops on
  non-pci controllers.
parent 278bdd1c
...@@ -1610,56 +1610,6 @@ static void idedisk_add_settings(ide_drive_t *drive) ...@@ -1610,56 +1610,6 @@ static void idedisk_add_settings(ide_drive_t *drive)
#endif #endif
} }
static int idedisk_suspend(struct device *dev, u32 state, u32 level)
{
ide_drive_t *drive = dev->driver_data;
printk("Suspending device %p\n", dev->driver_data);
/* I hope that every freeze operation from the upper levels have
* already been done...
*/
if (level != SUSPEND_SAVE_STATE)
return 0;
BUG_ON(in_interrupt());
printk("Waiting for commands to finish\n");
/* wait until all commands are finished */
/* FIXME: waiting for spinlocks should be done instead. */
if (!(HWGROUP(drive)))
printk("No hwgroup?\n");
while (HWGROUP(drive)->handler)
yield();
/* set the drive to standby */
printk(KERN_INFO "suspending: %s ", drive->name);
if (drive->driver) {
if (drive->driver->standby)
drive->driver->standby(drive);
}
drive->blocked = 1;
while (HWGROUP(drive)->handler)
yield();
return 0;
}
static int idedisk_resume(struct device *dev, u32 level)
{
ide_drive_t *drive = dev->driver_data;
if (level != RESUME_RESTORE_STATE)
return 0;
if (!drive->blocked)
panic("ide: Resume but not suspended?\n");
drive->blocked = 0;
return 0;
}
/* This is just a hook for the overall driver tree. /* This is just a hook for the overall driver tree.
*/ */
......
...@@ -1238,6 +1238,21 @@ static void idefloppy_create_rw_cmd (idefloppy_floppy_t *floppy, idefloppy_pc_t ...@@ -1238,6 +1238,21 @@ static void idefloppy_create_rw_cmd (idefloppy_floppy_t *floppy, idefloppy_pc_t
set_bit(PC_DMA_RECOMMENDED, &pc->flags); set_bit(PC_DMA_RECOMMENDED, &pc->flags);
} }
static int
idefloppy_blockpc_cmd(idefloppy_floppy_t *floppy, idefloppy_pc_t *pc, struct request *rq)
{
/*
* just support eject for now, it would not be hard to make the
* REQ_BLOCK_PC support fully-featured
*/
if (rq->cmd[0] != IDEFLOPPY_START_STOP_CMD)
return 1;
idefloppy_init_pc(pc);
memcpy(pc->c, rq->cmd, sizeof(pc->c));
return 0;
}
/* /*
* idefloppy_do_request is our request handling function. * idefloppy_do_request is our request handling function.
*/ */
...@@ -1280,6 +1295,12 @@ static ide_startstop_t idefloppy_do_request (ide_drive_t *drive, struct request ...@@ -1280,6 +1295,12 @@ static ide_startstop_t idefloppy_do_request (ide_drive_t *drive, struct request
idefloppy_create_rw_cmd(floppy, pc, rq, block); idefloppy_create_rw_cmd(floppy, pc, rq, block);
} else if (rq->flags & REQ_SPECIAL) { } else if (rq->flags & REQ_SPECIAL) {
pc = (idefloppy_pc_t *) rq->buffer; pc = (idefloppy_pc_t *) rq->buffer;
} else if (rq->flags & REQ_BLOCK_PC) {
pc = idefloppy_next_pc_storage(drive);
if (idefloppy_blockpc_cmd(floppy, pc, rq)) {
idefloppy_do_end_request(drive, 0, 0);
return ide_stopped;
}
} else { } else {
blk_dump_rq_flags(rq, blk_dump_rq_flags(rq,
"ide-floppy: unsupported command in queue"); "ide-floppy: unsupported command in queue");
......
...@@ -878,13 +878,12 @@ ide_startstop_t start_request (ide_drive_t *drive, struct request *rq) ...@@ -878,13 +878,12 @@ ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
{ {
ide_startstop_t startstop; ide_startstop_t startstop;
unsigned long block; unsigned long block;
ide_hwif_t *hwif = HWIF(drive);
BUG_ON(!(rq->flags & REQ_STARTED)); BUG_ON(!(rq->flags & REQ_STARTED));
#ifdef DEBUG #ifdef DEBUG
printk("%s: start_request: current=0x%08lx\n", printk("%s: start_request: current=0x%08lx\n",
hwif->name, (unsigned long) rq); HWIF(drive)->name, (unsigned long) rq);
#endif #endif
/* bail early if we've exceeded max_failures */ /* bail early if we've exceeded max_failures */
...@@ -910,7 +909,7 @@ ide_startstop_t start_request (ide_drive_t *drive, struct request *rq) ...@@ -910,7 +909,7 @@ ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
block = 1; /* redirect MBR access to EZ-Drive partn table */ block = 1; /* redirect MBR access to EZ-Drive partn table */
#if (DISK_RECOVERY_TIME > 0) #if (DISK_RECOVERY_TIME > 0)
while ((read_timer() - hwif->last_time) < DISK_RECOVERY_TIME); while ((read_timer() - HWIF(drive)->last_time) < DISK_RECOVERY_TIME);
#endif #endif
SELECT_DRIVE(drive); SELECT_DRIVE(drive);
...@@ -1128,9 +1127,15 @@ void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq) ...@@ -1128,9 +1127,15 @@ void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
break; break;
} }
/*
* we know that the queue isn't empty, but this can happen
* if the q->prep_rq_fn() decides to kill a request
*/
rq = elv_next_request(&drive->queue); rq = elv_next_request(&drive->queue);
if (!rq) if (!rq) {
hwgroup->busy = !!ata_pending_commands(drive);
break; break;
}
if (!rq->bio && ata_pending_commands(drive)) if (!rq->bio && ata_pending_commands(drive))
break; break;
...@@ -1515,10 +1520,8 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio ...@@ -1515,10 +1520,8 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio
{ {
unsigned long flags; unsigned long flags;
ide_hwgroup_t *hwgroup = HWGROUP(drive); ide_hwgroup_t *hwgroup = HWGROUP(drive);
unsigned int major = HWIF(drive)->major;
request_queue_t *q = &drive->queue;
struct list_head *queue_head = &q->queue_head;
DECLARE_COMPLETION(wait); DECLARE_COMPLETION(wait);
int insert_end = 1, err;
#ifdef CONFIG_BLK_DEV_PDC4030 #ifdef CONFIG_BLK_DEV_PDC4030
if (HWIF(drive)->chipset == ide_pdc4030 && rq->buffer != NULL) if (HWIF(drive)->chipset == ide_pdc4030 && rq->buffer != NULL)
...@@ -1540,29 +1543,35 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio ...@@ -1540,29 +1543,35 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio
} }
rq->rq_disk = drive->disk; rq->rq_disk = drive->disk;
if (action == ide_wait)
/*
* we need to hold an extra reference to request for safe inspection
* after completion
*/
if (action == ide_wait) {
rq->ref_count++;
rq->waiting = &wait; rq->waiting = &wait;
}
spin_lock_irqsave(&ide_lock, flags); spin_lock_irqsave(&ide_lock, flags);
if (blk_queue_empty(q) || action == ide_preempt) { if (action == ide_preempt) {
if (action == ide_preempt) hwgroup->rq = NULL;
hwgroup->rq = NULL; insert_end = 0;
} else {
if (action == ide_wait || action == ide_end) {
queue_head = queue_head->prev;
} else
queue_head = queue_head->next;
} }
q->elevator.elevator_add_req_fn(q, rq, queue_head); __elv_add_request(&drive->queue, rq, insert_end, 0);
ide_do_request(hwgroup, 0); ide_do_request(hwgroup, 0);
spin_unlock_irqrestore(&ide_lock, flags); spin_unlock_irqrestore(&ide_lock, flags);
err = 0;
if (action == ide_wait) { if (action == ide_wait) {
/* wait for it to be serviced */
wait_for_completion(&wait); wait_for_completion(&wait);
/* return -EIO if errors */ if (rq->errors)
return rq->errors ? -EIO : 0; err = -EIO;
blk_put_request(rq);
} }
return 0;
return err;
} }
EXPORT_SYMBOL(ide_do_drive_cmd); EXPORT_SYMBOL(ide_do_drive_cmd);
...@@ -3369,7 +3378,7 @@ int ide_register_driver(ide_driver_t *driver) ...@@ -3369,7 +3378,7 @@ int ide_register_driver(ide_driver_t *driver)
list_del_init(&drive->list); list_del_init(&drive->list);
ata_attach(drive); ata_attach(drive);
} }
driver->gen_driver.name = driver->name; driver->gen_driver.name = (char *) driver->name;
driver->gen_driver.bus = &ide_bus_type; driver->gen_driver.bus = &ide_bus_type;
driver->gen_driver.remove = ide_drive_remove; driver->gen_driver.remove = ide_drive_remove;
return driver_register(&driver->gen_driver); return driver_register(&driver->gen_driver);
......
...@@ -70,6 +70,7 @@ static __inline__ void ide_init_default_hwifs(void) ...@@ -70,6 +70,7 @@ static __inline__ void ide_init_default_hwifs(void)
int index; int index;
for(index = 0; index < MAX_HWIFS; index++) { for(index = 0; index < MAX_HWIFS; index++) {
memset(&hw, 0, sizeof hw);
ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL); ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL);
hw.irq = ide_default_irq(ide_default_io_base(index)); hw.irq = ide_default_irq(ide_default_io_base(index));
ide_register_hw(&hw, NULL); ide_register_hw(&hw, NULL);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment