Commit f7520fcf authored by Martin Dalecki's avatar Martin Dalecki Committed by Linus Torvalds

[PATCH] 2.5.11 IDE 47

- Rewrite choose_drive() to iterate explicitely over the channels and devices
    on them. It is not performance critical to iterate over this typically quite
    small array of disks and allows us to let them act on the natural entity,
    namely the channel as well as to remove the drive->next field from struct
    ata_device.  Make the device eviction code in ide_do_request() more
    intelliglible.  Add some comments explaining the reasoning behind the code
    there.

- Now finally since the code for choosing the drive which will be serviced next
    is intelliglibly it became obvious that the attempt to choose the next drive
    based on the duration of the last request was entierly bogous. (Because for
    example wakeups can take a long time, but this doesn't indicate that the
    drive is slow.) Remove this criterium and the corresponding accounting
    therefore. Threat all drives fairly right now.

Surprise surprise the overall system throughput increased :-).
parent 4a58bd1a
...@@ -438,10 +438,11 @@ static inline void probe_for_drive (ide_drive_t *drive) ...@@ -438,10 +438,11 @@ static inline void probe_for_drive (ide_drive_t *drive)
* This routine only knows how to look for drive units 0 and 1 * This routine only knows how to look for drive units 0 and 1
* on an interface, so any setting of MAX_DRIVES > 2 won't work here. * on an interface, so any setting of MAX_DRIVES > 2 won't work here.
*/ */
static void probe_hwif(struct ata_channel *ch) static void channel_probe(struct ata_channel *ch)
{ {
unsigned int unit; unsigned int unit;
unsigned long flags; unsigned long flags;
int error;
if (ch->noprobe) if (ch->noprobe)
return; return;
...@@ -454,96 +455,97 @@ static void probe_hwif(struct ata_channel *ch) ...@@ -454,96 +455,97 @@ static void probe_hwif(struct ata_channel *ch)
/* /*
* Check for the presence of a channel by probing for drives on it. * Check for the presence of a channel by probing for drives on it.
*/ */
for (unit = 0; unit < MAX_DRIVES; ++unit) { for (unit = 0; unit < MAX_DRIVES; ++unit) {
struct ata_device *drive = &ch->drives[unit]; struct ata_device *drive = &ch->drives[unit];
probe_for_drive(drive); probe_for_drive(drive);
if (drive->present && !ch->present) { /* drive found, there is a channel it is attached too. */
if (drive->present)
ch->present = 1; ch->present = 1;
}
} }
if (ch->present) { if (!ch->present)
int error = 0; goto not_found;
if (((unsigned long)ch->io_ports[IDE_DATA_OFFSET] | 7) == error = 0;
((unsigned long)ch->io_ports[IDE_STATUS_OFFSET])) {
error += !request_region(ch->io_ports[IDE_DATA_OFFSET], 8, ch->name);
ch->straight8 = 1;
} else {
if (ch->io_ports[IDE_DATA_OFFSET])
error += !request_region(ch->io_ports[IDE_DATA_OFFSET], 1, ch->name);
if (ch->io_ports[IDE_ERROR_OFFSET])
error += !request_region(ch->io_ports[IDE_ERROR_OFFSET], 1, ch->name);
if (ch->io_ports[IDE_NSECTOR_OFFSET])
error += !request_region(ch->io_ports[IDE_NSECTOR_OFFSET], 1, ch->name);
if (ch->io_ports[IDE_SECTOR_OFFSET])
error += !request_region(ch->io_ports[IDE_SECTOR_OFFSET], 1, ch->name);
if (ch->io_ports[IDE_LCYL_OFFSET])
error += !request_region(ch->io_ports[IDE_LCYL_OFFSET], 1, ch->name);
if (ch->io_ports[IDE_HCYL_OFFSET])
error += !request_region(ch->io_ports[IDE_HCYL_OFFSET], 1, ch->name);
if (ch->io_ports[IDE_SELECT_OFFSET])
error += !request_region(ch->io_ports[IDE_SELECT_OFFSET], 1, ch->name);
if (ch->io_ports[IDE_STATUS_OFFSET])
error += !request_region(ch->io_ports[IDE_STATUS_OFFSET], 1, ch->name);
} if (((unsigned long)ch->io_ports[IDE_DATA_OFFSET] | 7) ==
if (ch->io_ports[IDE_CONTROL_OFFSET]) ((unsigned long)ch->io_ports[IDE_STATUS_OFFSET])) {
error += !request_region(ch->io_ports[IDE_CONTROL_OFFSET], 1, ch->name); error += !request_region(ch->io_ports[IDE_DATA_OFFSET], 8, ch->name);
ch->straight8 = 1;
} else {
if (ch->io_ports[IDE_DATA_OFFSET])
error += !request_region(ch->io_ports[IDE_DATA_OFFSET], 1, ch->name);
if (ch->io_ports[IDE_ERROR_OFFSET])
error += !request_region(ch->io_ports[IDE_ERROR_OFFSET], 1, ch->name);
if (ch->io_ports[IDE_NSECTOR_OFFSET])
error += !request_region(ch->io_ports[IDE_NSECTOR_OFFSET], 1, ch->name);
if (ch->io_ports[IDE_SECTOR_OFFSET])
error += !request_region(ch->io_ports[IDE_SECTOR_OFFSET], 1, ch->name);
if (ch->io_ports[IDE_LCYL_OFFSET])
error += !request_region(ch->io_ports[IDE_LCYL_OFFSET], 1, ch->name);
if (ch->io_ports[IDE_HCYL_OFFSET])
error += !request_region(ch->io_ports[IDE_HCYL_OFFSET], 1, ch->name);
if (ch->io_ports[IDE_SELECT_OFFSET])
error += !request_region(ch->io_ports[IDE_SELECT_OFFSET], 1, ch->name);
if (ch->io_ports[IDE_STATUS_OFFSET])
error += !request_region(ch->io_ports[IDE_STATUS_OFFSET], 1, ch->name);
}
if (ch->io_ports[IDE_CONTROL_OFFSET])
error += !request_region(ch->io_ports[IDE_CONTROL_OFFSET], 1, ch->name);
#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC) #if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
if (ch->io_ports[IDE_IRQ_OFFSET]) if (ch->io_ports[IDE_IRQ_OFFSET])
error += !request_region(ch->io_ports[IDE_IRQ_OFFSET], 1, ch->name); error += !request_region(ch->io_ports[IDE_IRQ_OFFSET], 1, ch->name);
#endif #endif
/* Some neccessary register area was already used. Skip this /* Some neccessary register area was already used. Skip this device.
* device. */
*/
if ( if (
#if CONFIG_BLK_DEV_PDC4030 #if CONFIG_BLK_DEV_PDC4030
(ch->chipset != ide_pdc4030 || ch->unit == 0) && (ch->chipset != ide_pdc4030 || ch->unit == 0) &&
#endif #endif
error) { error) {
/* FIXME: We should be dealing properly with partial IO
* region allocations here.
*/
ch->present = 0;
printk("%s: error: ports already in use!\n", ch->name);
} /* FIXME: We should be dealing properly with partial IO region
* allocations here.
*/
ch->present = 0;
printk("%s: error: ports already in use!\n", ch->name);
} }
if (ch->present) { if (!ch->present)
/* Register this hardware interface within the global device tree. goto not_found;
*/
sprintf(ch->dev.bus_id, "%04x", ch->io_ports[IDE_DATA_OFFSET]); /* Register this hardware interface within the global device tree.
sprintf(ch->dev.name, "ide"); */
ch->dev.driver_data = ch; sprintf(ch->dev.bus_id, "%04x", ch->io_ports[IDE_DATA_OFFSET]);
sprintf(ch->dev.name, "ide");
ch->dev.driver_data = ch;
#ifdef CONFIG_BLK_DEV_IDEPCI #ifdef CONFIG_BLK_DEV_IDEPCI
if (ch->pci_dev) if (ch->pci_dev)
ch->dev.parent = &ch->pci_dev->dev; ch->dev.parent = &ch->pci_dev->dev;
else else
#endif #endif
ch->dev.parent = NULL; /* Would like to do = &device_legacy */ ch->dev.parent = NULL; /* Would like to do = &device_legacy */
device_register(&ch->dev); device_register(&ch->dev);
if (ch->io_ports[IDE_CONTROL_OFFSET] && ch->reset) { if (ch->io_ports[IDE_CONTROL_OFFSET] && ch->reset) {
unsigned long timeout = jiffies + WAIT_WORSTCASE; unsigned long timeout = jiffies + WAIT_WORSTCASE;
byte stat; byte stat;
printk("%s: reset\n", ch->name); printk("%s: reset\n", ch->name);
OUT_BYTE(12, ch->io_ports[IDE_CONTROL_OFFSET]); OUT_BYTE(12, ch->io_ports[IDE_CONTROL_OFFSET]);
udelay(10); udelay(10);
OUT_BYTE(8, ch->io_ports[IDE_CONTROL_OFFSET]); OUT_BYTE(8, ch->io_ports[IDE_CONTROL_OFFSET]);
do { do {
ide_delay_50ms(); ide_delay_50ms();
stat = IN_BYTE(ch->io_ports[IDE_STATUS_OFFSET]); stat = IN_BYTE(ch->io_ports[IDE_STATUS_OFFSET]);
} while ((stat & BUSY_STAT) && 0 < (signed long)(timeout - jiffies)); } while ((stat & BUSY_STAT) && 0 < (signed long)(timeout - jiffies));
}
} }
__restore_flags(flags); /* local CPU only */ __restore_flags(flags); /* local CPU only */
...@@ -551,16 +553,19 @@ static void probe_hwif(struct ata_channel *ch) ...@@ -551,16 +553,19 @@ static void probe_hwif(struct ata_channel *ch)
/* /*
* Now setup the PIO transfer modes of the drives on this channel. * Now setup the PIO transfer modes of the drives on this channel.
*/ */
if (ch->present) { for (unit = 0; unit < MAX_DRIVES; ++unit) {
for (unit = 0; unit < MAX_DRIVES; ++unit) { struct ata_device *drive = &ch->drives[unit];
struct ata_device *drive = &ch->drives[unit];
if (drive->present && (drive->autotune == 1)) { if (drive->present && (drive->autotune == 1)) {
if (drive->channel->tuneproc) if (drive->channel->tuneproc)
drive->channel->tuneproc(drive, 255); /* auto-tune PIO mode */ drive->channel->tuneproc(drive, 255); /* auto-tune PIO mode */
}
} }
} }
return;
not_found:
__restore_flags(flags);
} }
/* /*
...@@ -682,12 +687,7 @@ static int init_irq(struct ata_channel *ch) ...@@ -682,12 +687,7 @@ static int init_irq(struct ata_channel *ch)
spin_unlock_irqrestore(&ide_lock, flags); spin_unlock_irqrestore(&ide_lock, flags);
return 1; return 1;
} }
memset(hwgroup, 0, sizeof(ide_hwgroup_t)); memset(hwgroup, 0, sizeof(*hwgroup));
hwgroup->rq = NULL;
hwgroup->handler = NULL;
hwgroup->drive = NULL;
hwgroup->flags = 0;
init_timer(&hwgroup->timer); init_timer(&hwgroup->timer);
hwgroup->timer.function = &ide_timer_expiry; hwgroup->timer.function = &ide_timer_expiry;
hwgroup->timer.data = (unsigned long) hwgroup; hwgroup->timer.data = (unsigned long) hwgroup;
...@@ -716,21 +716,17 @@ static int init_irq(struct ata_channel *ch) ...@@ -716,21 +716,17 @@ static int init_irq(struct ata_channel *ch)
} }
/* /*
* Everything is okay. * Everything is okay. Tag us as member of this hardware group.
*/ */
ch->hwgroup = hwgroup; ch->hwgroup = hwgroup;
for (i = 0; i < MAX_DRIVES; ++i) { for (i = 0; i < MAX_DRIVES; ++i) {
struct ata_device *drive = &ch->drives[i]; struct ata_device *drive = &ch->drives[i];
if (!drive->present) if (!drive->present)
continue; continue;
if (!hwgroup->drive) if (!hwgroup->XXX_drive)
hwgroup->drive = drive; hwgroup->XXX_drive = drive;
drive->next = hwgroup->drive->next;
hwgroup->drive->next = drive;
init_device_queue(drive); init_device_queue(drive);
} }
...@@ -833,58 +829,65 @@ static void init_gendisk(struct ata_channel *hwif) ...@@ -833,58 +829,65 @@ static void init_gendisk(struct ata_channel *hwif)
return; return;
} }
static int hwif_init(struct ata_channel *hwif) static void channel_init(struct ata_channel *ch)
{ {
if (!hwif->present) if (!ch->present)
return 0; return;
if (!hwif->irq) {
if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET]))) /* we set it back to 1 if all is ok below */
{ ch->present = 0;
printk("%s: DISABLED, NO IRQ\n", hwif->name);
return (hwif->present = 0); if (!ch->irq) {
if (!(ch->irq = ide_default_irq(ch->io_ports[IDE_DATA_OFFSET]))) {
printk("%s: DISABLED, NO IRQ\n", ch->name);
return;
} }
} }
#ifdef CONFIG_BLK_DEV_HD #ifdef CONFIG_BLK_DEV_HD
if (hwif->irq == HD_IRQ && hwif->io_ports[IDE_DATA_OFFSET] != HD_DATA) { if (ch->irq == HD_IRQ && ch->io_ports[IDE_DATA_OFFSET] != HD_DATA) {
printk("%s: CANNOT SHARE IRQ WITH OLD HARDDISK DRIVER (hd.c)\n", hwif->name); printk("%s: CANNOT SHARE IRQ WITH OLD HARDDISK DRIVER (hd.c)\n", ch->name);
return (hwif->present = 0);
return;
} }
#endif #endif
hwif->present = 0; /* we set it back to 1 if all is ok below */ if (devfs_register_blkdev (ch->major, ch->name, ide_fops)) {
printk("%s: UNABLE TO GET MAJOR NUMBER %d\n", ch->name, ch->major);
if (devfs_register_blkdev (hwif->major, hwif->name, ide_fops)) { return;
printk("%s: UNABLE TO GET MAJOR NUMBER %d\n", hwif->name, hwif->major);
return (hwif->present = 0);
} }
if (init_irq(hwif)) { if (init_irq(ch)) {
int i = hwif->irq; int irq = ch->irq;
/* /*
* It failed to initialise. Find the default IRQ for * It failed to initialise. Find the default IRQ for
* this port and try that. * this port and try that.
*/ */
if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET]))) { if (!(ch->irq = ide_default_irq(ch->io_ports[IDE_DATA_OFFSET]))) {
printk("%s: Disabled unable to get IRQ %d.\n", hwif->name, i); printk(KERN_INFO "%s: disabled; unable to get IRQ %d.\n", ch->name, irq);
(void) unregister_blkdev (hwif->major, hwif->name); (void) unregister_blkdev (ch->major, ch->name);
return (hwif->present = 0);
return;
} }
if (init_irq(hwif)) { if (init_irq(ch)) {
printk("%s: probed IRQ %d and default IRQ %d failed.\n", printk(KERN_INFO "%s: probed IRQ %d and default IRQ %d failed.\n",
hwif->name, i, hwif->irq); ch->name, irq, ch->irq);
(void) unregister_blkdev (hwif->major, hwif->name); (void) unregister_blkdev(ch->major, ch->name);
return (hwif->present = 0);
return;
} }
printk("%s: probed IRQ %d failed, using default.\n", printk(KERN_INFO "%s: probed IRQ %d failed, using default.\n", ch->name, ch->irq);
hwif->name, hwif->irq);
} }
init_gendisk(hwif); init_gendisk(ch);
blk_dev[hwif->major].data = hwif; blk_dev[ch->major].data = ch;
blk_dev[hwif->major].queue = ide_get_queue; blk_dev[ch->major].queue = ide_get_queue;
hwif->present = 1; /* success */
return hwif->present; /* all went well, flag this channel entry as valid */
ch->present = 1;
return;
} }
int ideprobe_init (void) int ideprobe_init (void)
...@@ -901,9 +904,9 @@ int ideprobe_init (void) ...@@ -901,9 +904,9 @@ int ideprobe_init (void)
*/ */
for (index = 0; index < MAX_HWIFS; ++index) for (index = 0; index < MAX_HWIFS; ++index)
if (probe[index]) if (probe[index])
probe_hwif(&ide_hwifs[index]); channel_probe(&ide_hwifs[index]);
for (index = 0; index < MAX_HWIFS; ++index) for (index = 0; index < MAX_HWIFS; ++index)
if (probe[index]) if (probe[index])
hwif_init(&ide_hwifs[index]); channel_init(&ide_hwifs[index]);
return 0; return 0;
} }
...@@ -285,7 +285,7 @@ static void init_hwif_data(struct ata_channel *hwif, unsigned int index) ...@@ -285,7 +285,7 @@ static void init_hwif_data(struct ata_channel *hwif, unsigned int index)
hwif->bus_state = BUSSTATE_ON; hwif->bus_state = BUSSTATE_ON;
for (unit = 0; unit < MAX_DRIVES; ++unit) { for (unit = 0; unit < MAX_DRIVES; ++unit) {
ide_drive_t *drive = &hwif->drives[unit]; struct ata_device *drive = &hwif->drives[unit];
drive->type = ATA_DISK; drive->type = ATA_DISK;
drive->select.all = (unit<<4)|0xa0; drive->select.all = (unit<<4)|0xa0;
...@@ -507,19 +507,21 @@ extern struct block_device_operations ide_fops[]; ...@@ -507,19 +507,21 @@ extern struct block_device_operations ide_fops[];
/* /*
* This is called exactly *once* for each channel. * This is called exactly *once* for each channel.
*/ */
void ide_geninit(struct ata_channel *hwif) void ide_geninit(struct ata_channel *ch)
{ {
unsigned int unit; unsigned int unit;
struct gendisk *gd = hwif->gd; struct gendisk *gd = ch->gd;
for (unit = 0; unit < MAX_DRIVES; ++unit) { for (unit = 0; unit < MAX_DRIVES; ++unit) {
ide_drive_t *drive = &hwif->drives[unit]; struct ata_device *drive = &ch->drives[unit];
if (!drive->present) if (!drive->present)
continue; continue;
if (drive->type != ATA_DISK && drive->type != ATA_FLOPPY) if (drive->type != ATA_DISK && drive->type != ATA_FLOPPY)
continue; continue;
register_disk(gd,mk_kdev(hwif->major,unit<<PARTN_BITS),
register_disk(gd,mk_kdev(ch->major,unit<<PARTN_BITS),
#ifdef CONFIG_BLK_DEV_ISAPNP #ifdef CONFIG_BLK_DEV_ISAPNP
(drive->forced_geom && drive->noprobe) ? 1 : (drive->forced_geom && drive->noprobe) ? 1 :
#endif #endif
...@@ -1189,29 +1191,88 @@ void ide_stall_queue(ide_drive_t *drive, unsigned long timeout) ...@@ -1189,29 +1191,88 @@ void ide_stall_queue(ide_drive_t *drive, unsigned long timeout)
} }
/* /*
* Select the next drive which will be serviced. * Select the next device which will be serviced.
*/ */
static struct ata_device *choose_drive(struct ata_device *cur) static struct ata_device *choose_urgent_device(struct ata_channel *channel)
{ {
struct ata_device *drive = cur;
struct ata_device *best = NULL; struct ata_device *best = NULL;
int i;
do { for (i = 0; i < MAX_HWIFS; ++i) {
if (!list_empty(&drive->queue.queue_head) int unit;
&& (!drive->PADAM_sleep || time_after_eq(drive->PADAM_sleep, jiffies))) { struct ata_channel *ch = &ide_hwifs[i];
if (!best
|| (drive->PADAM_sleep && (!best->PADAM_sleep || time_after(best->PADAM_sleep, drive->PADAM_sleep))) if (!ch->present)
|| (!best->PADAM_sleep && time_after(best->PADAM_service_start + 2 * best->PADAM_service_time, drive->PADAM_service_start + 2 * drive->PADAM_service_time))) continue;
if (ch->hwgroup != channel->hwgroup)
continue;
for (unit = 0; unit < MAX_DRIVES; ++unit) {
struct ata_device *drive = &ch->drives[unit];
if (!drive->present)
continue;
/* There are no request pending for this device.
*/
if (list_empty(&drive->queue.queue_head))
continue;
/* This device still want's to remain idle.
*/
if (drive->PADAM_sleep && time_after(jiffies, drive->PADAM_sleep))
continue;
/* Take this device, if there is no device choosen thus far or
* it's more urgent.
*/
if (!best || (drive->PADAM_sleep && (!best->PADAM_sleep || time_after(best->PADAM_sleep, drive->PADAM_sleep))))
{ {
if (!blk_queue_plugged(&drive->queue)) if (!blk_queue_plugged(&drive->queue))
best = drive; best = drive;
} }
} }
drive = drive->next; }
} while (drive != cur);
return best; return best;
} }
/*
* Determine the longes sleep time for the devices in our hwgroup.
*/
static unsigned long longest_sleep(struct ata_channel *channel)
{
unsigned long sleep = 0;
int i;
for (i = 0; i < MAX_HWIFS; ++i) {
int unit;
struct ata_channel *ch = &ide_hwifs[i];
if (!ch->present)
continue;
if (ch->hwgroup != channel->hwgroup)
continue;
for (unit = 0; unit < MAX_DRIVES; ++unit) {
struct ata_device *drive = &ch->drives[unit];
if (!drive->present)
continue;
/* This device is sleeping and waiting to be serviced
* later than any other device we checked thus far.
*/
if (drive->PADAM_sleep && (!sleep || time_after(sleep, drive->PADAM_sleep)))
sleep = drive->PADAM_sleep;
}
}
return sleep;
}
/* /*
* Issue a new request to a drive from hwgroup. * Issue a new request to a drive from hwgroup.
* Caller must have already done spin_lock_irqsave(&ide_lock, ...) * Caller must have already done spin_lock_irqsave(&ide_lock, ...)
...@@ -1242,42 +1303,33 @@ static struct ata_device *choose_drive(struct ata_device *cur) ...@@ -1242,42 +1303,33 @@ static struct ata_device *choose_drive(struct ata_device *cur)
* will start the next request from the queue. If no more work remains, * will start the next request from the queue. If no more work remains,
* the driver will clear the hwgroup->flags IDE_BUSY flag and exit. * the driver will clear the hwgroup->flags IDE_BUSY flag and exit.
*/ */
static void ide_do_request(struct ata_channel *ch, int masked_irq) static void ide_do_request(struct ata_channel *channel, int masked_irq)
{ {
ide_hwgroup_t *hwgroup = ch->hwgroup; ide_hwgroup_t *hwgroup = channel->hwgroup;
struct ata_device *drive;
ide_startstop_t startstop;
struct request *rq;
ide_get_lock(&irq_lock, ata_irq_request, hwgroup);/* for atari only: POSSIBLY BROKEN HERE(?) */ ide_get_lock(&irq_lock, ata_irq_request, hwgroup);/* for atari only: POSSIBLY BROKEN HERE(?) */
__cli(); /* necessary paranoia: ensure IRQs are masked on local CPU */ __cli(); /* necessary paranoia: ensure IRQs are masked on local CPU */
while (!test_and_set_bit(IDE_BUSY, &hwgroup->flags)) { while (!test_and_set_bit(IDE_BUSY, &hwgroup->flags)) {
drive = choose_drive(hwgroup->drive); struct ata_channel *ch;
ide_startstop_t startstop;
struct ata_device *drive = choose_urgent_device(channel);
if (drive == NULL) { if (drive == NULL) {
unsigned long sleep = 0; unsigned long sleep = 0;
hwgroup->rq = NULL; hwgroup->rq = NULL;
sleep = longest_sleep(channel);
drive = hwgroup->drive;
do {
if (drive->PADAM_sleep && (!sleep || time_after(sleep, drive->PADAM_sleep)))
sleep = drive->PADAM_sleep;
drive = drive->next;
} while (drive!= hwgroup->drive);
if (sleep) { if (sleep) {
/* /*
* Take a short snooze, and then wake up this * Take a short snooze, and then wake up again.
* hwgroup again. This gives other hwgroups on * Just in case there are big differences in
* the same a chance to play fairly with us,
* just in case there are big differences in
* relative throughputs.. don't want to hog the * relative throughputs.. don't want to hog the
* cpu too much. * cpu too much.
*/ */
if (0 < (signed long)(jiffies + WAIT_MIN_SLEEP - sleep)) if (0 < (signed long)(jiffies + WAIT_MIN_SLEEP - sleep))
sleep = jiffies + WAIT_MIN_SLEEP; sleep = jiffies + WAIT_MIN_SLEEP;
#if 1 #if 1
...@@ -1293,29 +1345,35 @@ static void ide_do_request(struct ata_channel *ch, int masked_irq) ...@@ -1293,29 +1345,35 @@ static void ide_do_request(struct ata_channel *ch, int masked_irq)
ide_release_lock(&irq_lock);/* for atari only */ ide_release_lock(&irq_lock);/* for atari only */
clear_bit(IDE_BUSY, &hwgroup->flags); clear_bit(IDE_BUSY, &hwgroup->flags);
} }
return; /* no more work for this hwgroup (for now) */
return;
} }
ch = drive->channel; ch = drive->channel;
if (hwgroup->drive->channel->sharing_irq && ch != hwgroup->drive->channel && ch->io_ports[IDE_CONTROL_OFFSET]) { if (hwgroup->XXX_drive->channel->sharing_irq && ch != hwgroup->XXX_drive->channel && ch->io_ports[IDE_CONTROL_OFFSET]) {
/* set nIEN for previous channel */ /* set nIEN for previous channel */
/* FIXME: check this! It appears to act on the current channel! */
if (ch->intrproc) if (ch->intrproc)
ch->intrproc(drive); ch->intrproc(drive);
else else
OUT_BYTE((drive)->ctl|2, ch->io_ports[IDE_CONTROL_OFFSET]); OUT_BYTE((drive)->ctl|2, ch->io_ports[IDE_CONTROL_OFFSET]);
} }
hwgroup->drive = drive;
/* Remember the last drive we where acting on.
*/
hwgroup->XXX_drive = drive;
/* Reset wait timeout.
*/
drive->PADAM_sleep = 0; drive->PADAM_sleep = 0;
drive->PADAM_service_start = jiffies;
if (blk_queue_plugged(&drive->queue)) if (blk_queue_plugged(&drive->queue))
BUG(); BUG();
/* /* Just continuing an interrupted request maybe.
* just continuing an interrupted request maybe
*/ */
rq = hwgroup->rq = elv_next_request(&drive->queue); hwgroup->rq = elv_next_request(&drive->queue);
/* /*
* Some systems have trouble with IDE IRQs arriving while the * Some systems have trouble with IDE IRQs arriving while the
...@@ -1331,7 +1389,7 @@ static void ide_do_request(struct ata_channel *ch, int masked_irq) ...@@ -1331,7 +1389,7 @@ static void ide_do_request(struct ata_channel *ch, int masked_irq)
disable_irq_nosync(ch->irq); disable_irq_nosync(ch->irq);
spin_unlock(&ide_lock); spin_unlock(&ide_lock);
ide__sti(); /* allow other IRQs while we start this request */ ide__sti(); /* allow other IRQs while we start this request */
startstop = start_request(drive, rq); startstop = start_request(drive, hwgroup->rq);
spin_lock_irq(&ide_lock); spin_lock_irq(&ide_lock);
if (masked_irq && ch->irq != masked_irq) if (masked_irq && ch->irq != masked_irq)
enable_irq(ch->irq); enable_irq(ch->irq);
...@@ -1432,7 +1490,7 @@ void ide_timer_expiry(unsigned long data) ...@@ -1432,7 +1490,7 @@ void ide_timer_expiry(unsigned long data)
if (test_and_clear_bit(IDE_SLEEP, &hwgroup->flags)) if (test_and_clear_bit(IDE_SLEEP, &hwgroup->flags))
clear_bit(IDE_BUSY, &hwgroup->flags); clear_bit(IDE_BUSY, &hwgroup->flags);
} else { } else {
struct ata_device *drive = hwgroup->drive; struct ata_device *drive = hwgroup->XXX_drive;
if (!drive) { if (!drive) {
printk("ide_timer_expiry: hwgroup->drive was NULL\n"); printk("ide_timer_expiry: hwgroup->drive was NULL\n");
hwgroup->handler = NULL; hwgroup->handler = NULL;
...@@ -1483,7 +1541,6 @@ void ide_timer_expiry(unsigned long data) ...@@ -1483,7 +1541,6 @@ void ide_timer_expiry(unsigned long data)
startstop = ide_error(drive, "irq timeout", GET_STAT()); startstop = ide_error(drive, "irq timeout", GET_STAT());
} }
set_recovery_timer(ch); set_recovery_timer(ch);
drive->PADAM_service_time = jiffies - drive->PADAM_service_start;
enable_irq(ch->irq); enable_irq(ch->irq);
spin_lock_irq(&ide_lock); spin_lock_irq(&ide_lock);
if (startstop == ide_stopped) if (startstop == ide_stopped)
...@@ -1491,7 +1548,7 @@ void ide_timer_expiry(unsigned long data) ...@@ -1491,7 +1548,7 @@ void ide_timer_expiry(unsigned long data)
} }
} }
ide_do_request(hwgroup->drive->channel, 0); ide_do_request(hwgroup->XXX_drive->channel, 0);
spin_unlock_irqrestore(&ide_lock, flags); spin_unlock_irqrestore(&ide_lock, flags);
} }
...@@ -1525,15 +1582,15 @@ static void unexpected_irq(int irq) ...@@ -1525,15 +1582,15 @@ static void unexpected_irq(int irq)
for (i = 0; i < MAX_HWIFS; ++i) { for (i = 0; i < MAX_HWIFS; ++i) {
u8 stat; u8 stat;
struct ata_channel *tmp = &ide_hwifs[i]; struct ata_channel *ch = &ide_hwifs[i];
if (!tmp->present) if (!ch->present)
continue; continue;
if (tmp->irq != irq) if (ch->irq != irq)
continue; continue;
stat = IN_BYTE(tmp->io_ports[IDE_STATUS_OFFSET]); stat = IN_BYTE(ch->io_ports[IDE_STATUS_OFFSET]);
if (!OK_STAT(stat, READY_STAT, BAD_STAT)) { if (!OK_STAT(stat, READY_STAT, BAD_STAT)) {
/* Try to not flood the console with msgs */ /* Try to not flood the console with msgs */
static unsigned long last_msgtime; static unsigned long last_msgtime;
...@@ -1543,7 +1600,7 @@ static void unexpected_irq(int irq) ...@@ -1543,7 +1600,7 @@ static void unexpected_irq(int irq)
if (time_after(jiffies, last_msgtime + HZ)) { if (time_after(jiffies, last_msgtime + HZ)) {
last_msgtime = jiffies; last_msgtime = jiffies;
printk("%s: unexpected interrupt, status=0x%02x, count=%d\n", printk("%s: unexpected interrupt, status=0x%02x, count=%d\n",
tmp->name, stat, count); ch->name, stat, count);
} }
} }
} }
...@@ -1601,14 +1658,7 @@ void ata_irq_request(int irq, void *data, struct pt_regs *regs) ...@@ -1601,14 +1658,7 @@ void ata_irq_request(int irq, void *data, struct pt_regs *regs)
} }
goto out_lock; goto out_lock;
} }
drive = hwgroup->drive; drive = hwgroup->XXX_drive;
if (!drive) {
/*
* This should NEVER happen, and there isn't much we could do
* about it here.
*/
goto out_lock;
}
if (!drive_is_ready(drive)) { if (!drive_is_ready(drive)) {
/* /*
* This happens regularly when we share a PCI IRQ with another device. * This happens regularly when we share a PCI IRQ with another device.
...@@ -1640,7 +1690,6 @@ void ata_irq_request(int irq, void *data, struct pt_regs *regs) ...@@ -1640,7 +1690,6 @@ void ata_irq_request(int irq, void *data, struct pt_regs *regs)
* won't allow another of the same (on any CPU) until we return. * won't allow another of the same (on any CPU) until we return.
*/ */
set_recovery_timer(drive->channel); set_recovery_timer(drive->channel);
drive->PADAM_service_time = jiffies - drive->PADAM_service_start;
if (startstop == ide_stopped) { if (startstop == ide_stopped) {
if (hwgroup->handler == NULL) { /* paranoia */ if (hwgroup->handler == NULL) { /* paranoia */
clear_bit(IDE_BUSY, &hwgroup->flags); clear_bit(IDE_BUSY, &hwgroup->flags);
...@@ -1668,7 +1717,7 @@ ide_drive_t *get_info_ptr(kdev_t i_rdev) ...@@ -1668,7 +1717,7 @@ ide_drive_t *get_info_ptr(kdev_t i_rdev)
if (hwif->present && major == hwif->major) { if (hwif->present && major == hwif->major) {
int unit = DEVICE_NR(i_rdev); int unit = DEVICE_NR(i_rdev);
if (unit < MAX_DRIVES) { if (unit < MAX_DRIVES) {
ide_drive_t *drive = &hwif->drives[unit]; struct ata_device *drive = &hwif->drives[unit];
if (drive->present) if (drive->present)
return drive; return drive;
} }
...@@ -1800,46 +1849,44 @@ int ide_revalidate_disk (kdev_t i_rdev) ...@@ -1800,46 +1849,44 @@ int ide_revalidate_disk (kdev_t i_rdev)
*/ */
void revalidate_drives(void) void revalidate_drives(void)
{ {
struct ata_channel *hwif; int i;
ide_drive_t *drive;
int h;
for (h = 0; h < MAX_HWIFS; ++h) { for (i = 0; i < MAX_HWIFS; ++i) {
int unit; int unit;
hwif = &ide_hwifs[h]; struct ata_channel *ch = &ide_hwifs[i];
for (unit = 0; unit < MAX_DRIVES; ++unit) { for (unit = 0; unit < MAX_DRIVES; ++unit) {
drive = &ide_hwifs[h].drives[unit]; struct ata_device *drive = &ch->drives[unit];
if (drive->revalidate) { if (drive->revalidate) {
drive->revalidate = 0; drive->revalidate = 0;
if (!initializing) if (!initializing)
ide_revalidate_disk(mk_kdev(hwif->major, unit<<PARTN_BITS)); ide_revalidate_disk(mk_kdev(ch->major, unit<<PARTN_BITS));
} }
} }
} }
} }
static void ide_probe_module(void)
{
ideprobe_init();
revalidate_drives();
}
static void ide_driver_module (void) static void ide_driver_module (void)
{ {
int index; int i;
/* Don't reinit the probe if there is already one channel detected. */
for (index = 0; index < MAX_HWIFS; ++index) for (i = 0; i < MAX_HWIFS; ++i) {
if (ide_hwifs[index].present) if (ide_hwifs[i].present)
goto search; goto revalidate;
ide_probe_module(); }
search:
ideprobe_init();
revalidate:
revalidate_drives(); revalidate_drives();
} }
static int ide_open(struct inode * inode, struct file * filp) static int ide_open(struct inode * inode, struct file * filp)
{ {
ide_drive_t *drive; struct ata_device *drive;
if ((drive = get_info_ptr(inode->i_rdev)) == NULL) if ((drive = get_info_ptr(inode->i_rdev)) == NULL)
return -ENXIO; return -ENXIO;
...@@ -1901,7 +1948,7 @@ static int ide_open(struct inode * inode, struct file * filp) ...@@ -1901,7 +1948,7 @@ static int ide_open(struct inode * inode, struct file * filp)
*/ */
static int ide_release(struct inode * inode, struct file * file) static int ide_release(struct inode * inode, struct file * file)
{ {
ide_drive_t *drive; struct ata_device *drive;
if (!(drive = get_info_ptr(inode->i_rdev))) if (!(drive = get_info_ptr(inode->i_rdev)))
return 0; return 0;
...@@ -1977,7 +2024,7 @@ static void hwif_unregister(struct ata_channel *ch) ...@@ -1977,7 +2024,7 @@ static void hwif_unregister(struct ata_channel *ch)
void ide_unregister(struct ata_channel *ch) void ide_unregister(struct ata_channel *ch)
{ {
struct gendisk *gd; struct gendisk *gd;
ide_drive_t *drive, *d; struct ata_device *d;
ide_hwgroup_t *hwgroup; ide_hwgroup_t *hwgroup;
int unit, i; int unit, i;
unsigned long flags; unsigned long flags;
...@@ -1986,15 +2033,20 @@ void ide_unregister(struct ata_channel *ch) ...@@ -1986,15 +2033,20 @@ void ide_unregister(struct ata_channel *ch)
int n = 0; int n = 0;
spin_lock_irqsave(&ide_lock, flags); spin_lock_irqsave(&ide_lock, flags);
if (!ch->present) if (!ch->present)
goto abort; goto abort;
put_device(&ch->dev); put_device(&ch->dev);
for (unit = 0; unit < MAX_DRIVES; ++unit) { for (unit = 0; unit < MAX_DRIVES; ++unit) {
drive = &ch->drives[unit]; struct ata_device * drive = &ch->drives[unit];
if (!drive->present) if (!drive->present)
continue; continue;
if (drive->busy || drive->usage) if (drive->busy || drive->usage)
goto abort; goto abort;
if (ata_ops(drive)) { if (ata_ops(drive)) {
if (ata_ops(drive)->cleanup) { if (ata_ops(drive)->cleanup) {
if (ata_ops(drive)->cleanup(drive)) if (ata_ops(drive)->cleanup(drive))
...@@ -2010,9 +2062,11 @@ void ide_unregister(struct ata_channel *ch) ...@@ -2010,9 +2062,11 @@ void ide_unregister(struct ata_channel *ch)
*/ */
spin_unlock_irqrestore(&ide_lock, flags); spin_unlock_irqrestore(&ide_lock, flags);
for (unit = 0; unit < MAX_DRIVES; ++unit) { for (unit = 0; unit < MAX_DRIVES; ++unit) {
drive = &ch->drives[unit]; struct ata_device * drive = &ch->drives[unit];
if (!drive->present) if (!drive->present)
continue; continue;
minor = drive->select.b.unit << PARTN_BITS; minor = drive->select.b.unit << PARTN_BITS;
for (p = 0; p < (1<<PARTN_BITS); ++p) { for (p = 0; p < (1<<PARTN_BITS); ++p) {
if (drive->part[p].nr_sects > 0) { if (drive->part[p].nr_sects > 0) {
...@@ -2029,25 +2083,24 @@ void ide_unregister(struct ata_channel *ch) ...@@ -2029,25 +2083,24 @@ void ide_unregister(struct ata_channel *ch)
hwif_unregister(ch); hwif_unregister(ch);
/* /*
* Remove us from the hwgroup, and free the hwgroup if we were the only * Remove us from the hwgroup
* member.
*/ */
hwgroup = ch->hwgroup; hwgroup = ch->hwgroup;
d = hwgroup->drive; d = hwgroup->XXX_drive;
for (i = 0; i < MAX_DRIVES; ++i) { for (i = 0; i < MAX_DRIVES; ++i) {
drive = &ch->drives[i]; struct ata_device *drive = &ch->drives[i];
if (drive->de) { if (drive->de) {
devfs_unregister (drive->de); devfs_unregister (drive->de);
drive->de = NULL; drive->de = NULL;
} }
if (!drive->present) if (!drive->present)
continue; continue;
while (hwgroup->drive->next != drive)
hwgroup->drive = hwgroup->drive->next; if (hwgroup->XXX_drive == drive)
hwgroup->drive->next = drive->next; hwgroup->XXX_drive = NULL;
if (hwgroup->drive == drive)
hwgroup->drive = NULL;
if (drive->id != NULL) { if (drive->id != NULL) {
kfree(drive->id); kfree(drive->id);
drive->id = NULL; drive->id = NULL;
...@@ -2056,8 +2109,10 @@ void ide_unregister(struct ata_channel *ch) ...@@ -2056,8 +2109,10 @@ void ide_unregister(struct ata_channel *ch)
blk_cleanup_queue(&drive->queue); blk_cleanup_queue(&drive->queue);
} }
if (d->present) if (d->present)
hwgroup->drive = d; hwgroup->XXX_drive = d;
/* Free the hwgroup if we were the only member.
*/
n = 0; n = 0;
for (i = 0; i < MAX_HWIFS; ++i) { for (i = 0; i < MAX_HWIFS; ++i) {
struct ata_channel *tmp = &ide_hwifs[i]; struct ata_channel *tmp = &ide_hwifs[i];
...@@ -2215,10 +2270,12 @@ int ide_register_hw(hw_regs_t *hw, struct ata_channel **hwifp) ...@@ -2215,10 +2270,12 @@ int ide_register_hw(hw_regs_t *hw, struct ata_channel **hwifp)
hwif->chipset = hw->chipset; hwif->chipset = hw->chipset;
if (!initializing) { if (!initializing) {
ide_probe_module(); ideprobe_init();
revalidate_drives();
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
create_proc_ide_interfaces(); create_proc_ide_interfaces();
#endif #endif
/* FIXME: Do we really have to call it second time here?! */
ide_driver_module(); ide_driver_module();
} }
...@@ -3121,25 +3178,29 @@ int ide_end_request(struct ata_device *drive, struct request *rq, int uptodate) ...@@ -3121,25 +3178,29 @@ int ide_end_request(struct ata_device *drive, struct request *rq, int uptodate)
} }
/* /*
* Lookup IDE devices, which requested a particular driver * Lookup ATA devices, which requested a particular driver.
*/ */
ide_drive_t *ide_scan_devices(byte type, const char *name, struct ata_operations *driver, int n) ide_drive_t *ide_scan_devices(byte type, const char *name, struct ata_operations *driver, int n)
{ {
unsigned int unit, index, i; unsigned int unit, index, i;
for (index = 0, i = 0; index < MAX_HWIFS; ++index) { for (index = 0, i = 0; index < MAX_HWIFS; ++index) {
struct ata_channel *hwif = &ide_hwifs[index]; struct ata_channel *ch = &ide_hwifs[index];
if (!hwif->present)
if (!ch->present)
continue; continue;
for (unit = 0; unit < MAX_DRIVES; ++unit) { for (unit = 0; unit < MAX_DRIVES; ++unit) {
ide_drive_t *drive = &hwif->drives[unit]; struct ata_device *drive = &ch->drives[unit];
char *req = drive->driver_req; char *req = drive->driver_req;
if (*req && !strstr(name, req)) if (*req && !strstr(name, req))
continue; continue;
if (drive->present && drive->type == type && drive->driver == driver && ++i > n) if (drive->present && drive->type == type && drive->driver == driver && ++i > n)
return drive; return drive;
} }
} }
return NULL; return NULL;
} }
...@@ -3179,9 +3240,21 @@ int ide_register_subdriver(ide_drive_t *drive, struct ata_operations *driver) ...@@ -3179,9 +3240,21 @@ int ide_register_subdriver(ide_drive_t *drive, struct ata_operations *driver)
drive->channel->udma(ide_dma_off_quietly, drive, NULL); drive->channel->udma(ide_dma_off_quietly, drive, NULL);
drive->channel->udma(ide_dma_check, drive, NULL); drive->channel->udma(ide_dma_check, drive, NULL);
} }
/* Only CD-ROMs and tape drives support DSC overlap. */
drive->dsc_overlap = (drive->next != drive /* Only CD-ROMs and tape drives support DSC overlap. But only
&& (drive->type == ATA_ROM || drive->type == ATA_TAPE)); * if they are alone on a channel. */
if (drive->type == ATA_ROM || drive->type == ATA_TAPE) {
int single = 0;
int unit;
for (unit = 0; unit < MAX_DRIVES; ++unit)
if (drive->channel->drives[unit].present)
++single;
drive->dsc_overlap = (single == 1);
} else
drive->dsc_overlap = 0;
} }
drive->revalidate = 1; drive->revalidate = 1;
drive->suspend_reset = 0; drive->suspend_reset = 0;
...@@ -3319,9 +3392,7 @@ EXPORT_SYMBOL(get_info_ptr); ...@@ -3319,9 +3392,7 @@ EXPORT_SYMBOL(get_info_ptr);
static int ide_notify_reboot (struct notifier_block *this, unsigned long event, void *x) static int ide_notify_reboot (struct notifier_block *this, unsigned long event, void *x)
{ {
struct ata_channel *hwif; int i;
ide_drive_t *drive;
int i, unit;
switch (event) { switch (event) {
case SYS_HALT: case SYS_HALT:
...@@ -3335,12 +3406,15 @@ static int ide_notify_reboot (struct notifier_block *this, unsigned long event, ...@@ -3335,12 +3406,15 @@ static int ide_notify_reboot (struct notifier_block *this, unsigned long event,
printk("flushing ide devices: "); printk("flushing ide devices: ");
for (i = 0; i < MAX_HWIFS; i++) { for (i = 0; i < MAX_HWIFS; i++) {
hwif = &ide_hwifs[i]; int unit;
if (!hwif->present) struct ata_channel *ch = &ide_hwifs[i];
if (!ch->present)
continue; continue;
for (unit = 0; unit < MAX_DRIVES; ++unit) { for (unit = 0; unit < MAX_DRIVES; ++unit) {
drive = &hwif->drives[unit]; struct ata_device *drive = &ch->drives[unit];
if (!drive->present) if (!drive->present)
continue; continue;
......
...@@ -283,16 +283,10 @@ struct ata_device { ...@@ -283,16 +283,10 @@ struct ata_device {
*/ */
request_queue_t queue; /* per device request queue */ request_queue_t queue; /* per device request queue */
struct ata_device *next; /* circular list of hwgroup drives */
/* Those are directly injected jiffie values. They should go away and /* Those are directly injected jiffie values. They should go away and
* we should use generic timers instead!!! * we should use generic timers instead!!!
*/ */
unsigned long PADAM_sleep; /* sleep until this time */
unsigned long PADAM_sleep; /* sleep until this time */
unsigned long PADAM_service_start; /* time we started last request */
unsigned long PADAM_service_time; /* service time of last request */
unsigned long PADAM_timeout; /* max time to wait for irq */
/* Flags requesting/indicating one of the following special commands /* Flags requesting/indicating one of the following special commands
* executed on the request queue. * executed on the request queue.
...@@ -512,7 +506,7 @@ struct ata_taskfile; ...@@ -512,7 +506,7 @@ struct ata_taskfile;
typedef struct hwgroup_s { typedef struct hwgroup_s {
ide_startstop_t (*handler)(struct ata_device *, struct request *); /* irq handler, if active */ ide_startstop_t (*handler)(struct ata_device *, struct request *); /* irq handler, if active */
unsigned long flags; /* BUSY, SLEEPING */ unsigned long flags; /* BUSY, SLEEPING */
struct ata_device *drive; /* current drive */ struct ata_device *XXX_drive; /* current drive */
struct request *rq; /* current request */ struct request *rq; /* current request */
struct timer_list timer; /* failsafe timer */ struct timer_list timer; /* failsafe timer */
unsigned long poll_timeout; /* timeout value during long polls */ unsigned long poll_timeout; /* timeout value during long polls */
......
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