patch-2.3.23 linux/drivers/block/ide.c
Next file: linux/drivers/block/ll_rw_blk.c
Previous file: linux/drivers/block/ide-tape.c
Back to the patch index
Back to the overall index
- Lines: 373
- Date:
Tue Oct 19 13:47:40 1999
- Orig file:
v2.3.22/linux/drivers/block/ide.c
- Orig date:
Mon Oct 11 15:38:14 1999
diff -u --recursive --new-file v2.3.22/linux/drivers/block/ide.c linux/drivers/block/ide.c
@@ -149,9 +149,9 @@
#include <linux/kmod.h>
#endif /* CONFIG_KMOD */
-#ifdef CONFIG_BLK_DEV_VIA82C586
-extern byte fifoconfig; /* defined in via82c586.c used by ide_setup()*/
-#endif
+#ifdef CONFIG_BLK_DEV_VIA82CXXX
+extern byte fifoconfig; /* defined in via82cxxx.c used by ide_setup() */
+#endif /* CONFIG_BLK_DEV_VIA82CXXX */
static const byte ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR,
IDE2_MAJOR, IDE3_MAJOR,
@@ -498,13 +498,25 @@
}
/*
+ * The below two are helpers used when modifying the drive timeout.
+ */
+static inline unsigned long set_timeout(ide_drive_t *drive, unsigned long timeout)
+{
+ unsigned long foo = drive->timeout;
+ drive->timeout = timeout;
+ return foo;
+}
+
+#define restore_timeout(drive, old) (drive->timeout = old)
+
+/*
* This should get invoked any time we exit the driver to
* wait for an interrupt response from a drive. handler() points
* at the appropriate code to handle the next interrupt, and a
* timer is started to prevent us from waiting forever in case
* something goes wrong (see the ide_timer_expiry() handler later on).
*/
-void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout)
+void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler)
{
unsigned long flags;
ide_hwgroup_t *hwgroup = HWGROUP(drive);
@@ -517,8 +529,11 @@
}
#endif
hwgroup->handler = handler;
- hwgroup->timer.expires = jiffies + timeout;
- add_timer(&(hwgroup->timer));
+ /* 0 means don't timeout */
+ if (drive->timeout && !timer_pending(&hwgroup->timer)) {
+ hwgroup->timer.expires = jiffies + drive->timeout;
+ add_timer(&(hwgroup->timer));
+ }
spin_unlock_irqrestore(&hwgroup->spinlock, flags);
}
@@ -565,6 +580,7 @@
static void atapi_reset_pollfunc (ide_drive_t *drive)
{
ide_hwgroup_t *hwgroup = HWGROUP(drive);
+ unsigned long old_timeout;
byte stat;
SELECT_DRIVE(HWIF(drive),drive);
@@ -574,7 +590,9 @@
printk("%s: ATAPI reset complete\n", drive->name);
} else {
if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {
- ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20);
+ old_timeout = set_timeout(drive, HZ / 20);
+ ide_set_handler (drive, &atapi_reset_pollfunc);
+ restore_timeout(drive, old_timeout);
return; /* continue polling */
}
hwgroup->poll_timeout = 0; /* end of polling */
@@ -595,11 +613,14 @@
{
ide_hwgroup_t *hwgroup = HWGROUP(drive);
ide_hwif_t *hwif = HWIF(drive);
+ unsigned long old_timeout;
byte tmp;
if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) {
if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {
- ide_set_handler (drive, &reset_pollfunc, HZ/20);
+ old_timeout = set_timeout(drive, HZ / 20);
+ ide_set_handler (drive, &reset_pollfunc);
+ restore_timeout(drive, old_timeout);
return; /* continue polling */
}
printk("%s: reset timed-out, status=0x%02x\n", hwif->name, tmp);
@@ -667,6 +688,7 @@
unsigned long flags;
ide_hwif_t *hwif = HWIF(drive);
ide_hwgroup_t *hwgroup = HWGROUP(drive);
+ unsigned long old_timeout;
__save_flags(flags); /* local CPU only */
__cli(); /* local CPU only */
@@ -678,7 +700,9 @@
udelay (20);
OUT_BYTE (WIN_SRST, IDE_COMMAND_REG);
hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
- ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20);
+ old_timeout = set_timeout(drive, HZ / 20);
+ ide_set_handler (drive, &atapi_reset_pollfunc);
+ restore_timeout(drive, old_timeout);
__restore_flags (flags); /* local CPU only */
return;
}
@@ -708,7 +732,18 @@
OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG); /* clear SRST, leave nIEN */
udelay(10); /* more than enough time */
hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
- ide_set_handler (drive, &reset_pollfunc, HZ/20);
+ old_timeout = set_timeout(drive, HZ / 20);
+ ide_set_handler (drive, &reset_pollfunc);
+ restore_timeout(drive, old_timeout);
+
+ /*
+ * Some weird controller like resetting themselves to a strange
+ * state when the disks are reset this way. At least, the Winbond
+ * 553 documentation says that
+ */
+ if (hwif->resetproc != NULL)
+ hwif->resetproc(drive);
+
#endif /* OK_TO_RESET_CONTROLLER */
__restore_flags (flags); /* local CPU only */
@@ -899,7 +934,7 @@
*/
void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler)
{
- ide_set_handler (drive, handler, WAIT_CMD);
+ ide_set_handler (drive, handler);
if (IDE_CONTROL_REG)
OUT_BYTE(drive->ctl,IDE_CONTROL_REG); /* clear nIEN */
OUT_BYTE(nsect,IDE_NSECTOR_REG);
@@ -1018,6 +1053,10 @@
if (args[0] == WIN_SMART) {
OUT_BYTE(0x4f, IDE_LCYL_REG);
OUT_BYTE(0xc2, IDE_HCYL_REG);
+ OUT_BYTE(args[2],IDE_FEATURE_REG);
+ OUT_BYTE(args[1],IDE_SECTOR_REG);
+ ide_cmd(drive, args[0], args[3], &drive_cmd_intr);
+ return;
}
OUT_BYTE(args[2],IDE_FEATURE_REG);
ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
@@ -1218,13 +1257,37 @@
bdev->current_request = hwgroup->rq = drive->queue;
spin_unlock_irqrestore(&io_request_lock, io_flags);
+#if 0
if (hwif->irq != masked_irq)
- disable_irq(hwif->irq);
+ disable_irq_nosync(hwif->irq);
spin_unlock_irqrestore(&hwgroup->spinlock, *hwgroup_flags);
start_request(drive);
spin_lock_irqsave(&hwgroup->spinlock, *hwgroup_flags);
if (hwif->irq != masked_irq)
enable_irq(hwif->irq);
+#else
+
+ if (masked_irq && hwif->irq != masked_irq) {
+ printk("%s: (disable_irq) %smasked_irq %d\n",
+ drive->name,
+ masked_irq ? "" : "un_", hwif->irq);
+
+#if 0
+ disable_irq(hwif->irq);
+#else
+ disable_irq_nosync(hwif->irq);
+#endif
+ }
+ spin_unlock_irqrestore(&hwgroup->spinlock, *hwgroup_flags);
+ start_request(drive);
+ spin_lock_irqsave(&hwgroup->spinlock, *hwgroup_flags);
+ if (masked_irq && hwif->irq != masked_irq) {
+ printk("%s: (enable_irq) %smasked_irq %d\n",
+ drive->name,
+ masked_irq ? "" : "un_", hwif->irq);
+ enable_irq(hwif->irq);
+ }
+#endif
}
}
@@ -1373,8 +1436,8 @@
}
hwgroup->busy = 1; /* should already be "1" */
hwgroup->handler = NULL;
- del_timer(&hwgroup->timer); /* Is this needed?? */
- if (hwgroup->poll_timeout != 0) { /* polling in progress? */
+ /* polling in progress or just don't timeout */
+ if (hwgroup->poll_timeout != 0) {
spin_unlock_irqrestore(&hwgroup->spinlock, flags);
handler(drive);
} else if (drive_is_ready(drive)) {
@@ -1612,8 +1675,10 @@
}
spin_unlock_irqrestore(&io_request_lock, flags);
do_hwgroup_request(hwgroup);
- if (action == ide_wait && rq->rq_status != RQ_INACTIVE)
+ if (action == ide_wait) {
down(&sem); /* wait for it to be serviced */
+ rq->sem = NULL;
+ }
return rq->errors ? -EIO : 0; /* return -EIO if errors */
}
@@ -2270,8 +2335,13 @@
int ide_config_drive_speed (ide_drive_t *drive, byte speed)
{
+ struct hd_driveid *id = drive->id;
+ unsigned long flags;
int err;
+ __save_flags(flags); /* local CPU only */
+ __cli(); /* local CPU only */
+
/*
* Don't use ide_wait_cmd here - it will
* attempt to set_geometry and recalibrate,
@@ -2287,6 +2357,109 @@
err = ide_wait_stat(drive, DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT, WAIT_CMD);
+#if 0
+ if (IDE_CONTROL_REG)
+ OUT_BYTE(drive->ctl, IDE_CONTROL_REG);
+#endif
+
+ __restore_flags(flags); /* local CPU only */
+
+ switch(speed) {
+ case XFER_UDMA_4:
+ if (!((id->dma_ultra >> 8) & 16)) {
+ drive->id->dma_ultra &= ~0xFF00;
+ drive->id->dma_ultra |= 0x1010;
+ }
+ drive->id->dma_mword &= ~0x0F00;
+ drive->id->dma_1word &= ~0x0F00;
+ break;
+ case XFER_UDMA_3:
+ if (!((id->dma_ultra >> 8) & 8)) {
+ drive->id->dma_ultra &= ~0xFF00;
+ drive->id->dma_ultra |= 0x0808;
+ }
+ drive->id->dma_mword &= ~0x0F00;
+ drive->id->dma_1word &= ~0x0F00;
+ break;
+ case XFER_UDMA_2:
+ if (!((id->dma_ultra >> 8) & 4)) {
+ drive->id->dma_ultra &= ~0xFF00;
+ drive->id->dma_ultra |= 0x0404;
+ }
+ drive->id->dma_mword &= ~0x0F00;
+ drive->id->dma_1word &= ~0x0F00;
+ break;
+ case XFER_UDMA_1:
+ if (!((id->dma_ultra >> 8) & 2)) {
+ drive->id->dma_ultra &= ~0xFF00;
+ drive->id->dma_ultra |= 0x0202;
+ }
+ drive->id->dma_mword &= ~0x0F00;
+ drive->id->dma_1word &= ~0x0F00;
+ break;
+ case XFER_UDMA_0:
+ if (!((id->dma_ultra >> 8) & 1)) {
+ drive->id->dma_ultra &= ~0xFF00;
+ drive->id->dma_ultra |= 0x0101;
+ }
+ drive->id->dma_mword &= ~0x0F00;
+ drive->id->dma_1word &= ~0x0F00;
+ break;
+ case XFER_MW_DMA_2:
+ drive->id->dma_ultra &= ~0xFF00;
+ if (!((id->dma_mword >> 8) & 4)) {
+ drive->id->dma_mword &= ~0x0F00;
+ drive->id->dma_mword |= 0x0404;
+ }
+ drive->id->dma_1word &= ~0x0F00;
+ break;
+ case XFER_MW_DMA_1:
+ drive->id->dma_ultra &= ~0xFF00;
+ if (!((id->dma_mword >> 8) & 2)) {
+ drive->id->dma_mword &= ~0x0F00;
+ drive->id->dma_mword |= 0x0202;
+ }
+ drive->id->dma_1word &= ~0x0F00;
+ break;
+ case XFER_MW_DMA_0:
+ drive->id->dma_ultra &= ~0xFF00;
+ if (!((id->dma_mword >> 8) & 1)) {
+ drive->id->dma_mword &= ~0x0F00;
+ drive->id->dma_mword |= 0x0101;
+ }
+ drive->id->dma_1word &= ~0x0F00;
+ break;
+ case XFER_SW_DMA_2:
+ drive->id->dma_ultra &= ~0xFF00;
+ drive->id->dma_mword &= ~0x0F00;
+ if (!((id->dma_1word >> 8) & 4)) {
+ drive->id->dma_1word &= ~0x0F00;
+ drive->id->dma_1word |= 0x0404;
+ }
+ break;
+ case XFER_SW_DMA_1:
+ drive->id->dma_ultra &= ~0xFF00;
+ drive->id->dma_mword &= ~0x0F00;
+ if (!((id->dma_1word >> 8) & 2)) {
+ drive->id->dma_1word &= ~0x0F00;
+ drive->id->dma_1word |= 0x0202;
+ }
+ break;
+ case XFER_SW_DMA_0:
+ drive->id->dma_ultra &= ~0xFF00;
+ drive->id->dma_mword &= ~0x0F00;
+ if (!((id->dma_1word >> 8) & 1)) {
+ drive->id->dma_1word &= ~0x0F00;
+ drive->id->dma_1word |= 0x0101;
+ }
+ break;
+ default:
+ drive->id->dma_ultra &= ~0xFF00;
+ drive->id->dma_mword &= ~0x0F00;
+ drive->id->dma_1word &= ~0x0F00;
+ break;
+ }
+
return(err);
}
@@ -2803,7 +2976,7 @@
}
}
-#if defined(CONFIG_BLK_DEV_VIA82C586)
+#if defined(CONFIG_BLK_DEV_VIA82CXXX)
/*
* Look for drive option "splitfifo=..."
*/
@@ -2853,7 +3026,7 @@
fifoconfig = tmp;
goto done;
}
-#endif /* defined(CONFIG_BLK_DEV_VIA82C586) */
+#endif /* defined(CONFIG_BLK_DEV_VIA82CXXX) */
if (s[0] != 'i' || s[1] != 'd' || s[2] != 'e')
goto bad_option;
@@ -3393,6 +3566,7 @@
EXPORT_SYMBOL(ide_scan_devices);
EXPORT_SYMBOL(ide_register_subdriver);
EXPORT_SYMBOL(ide_unregister_subdriver);
+EXPORT_SYMBOL(ide_replace_subdriver);
EXPORT_SYMBOL(ide_input_data);
EXPORT_SYMBOL(ide_output_data);
EXPORT_SYMBOL(atapi_input_bytes);
@@ -3464,7 +3638,11 @@
while ((line = next) != NULL) {
if ((next = strchr(line,' ')) != NULL)
*next++ = 0;
- if (!strncmp(line,"ide",3) || (!strncmp(line,"hd",2) && line[2] != '='))
+ if (!strncmp(line,"ide",3) ||
+#ifdef CONFIG_BLK_DEV_VIA82CXXX
+ !strncmp(line,"splitfifo",9) ||
+#endif /* CONFIG_BLK_DEV_VIA82CXXX */
+ (!strncmp(line,"hd",2) && line[2] != '='))
ide_setup(line);
}
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)