Andre,
We spoke a while back about a GET/SET BUSSTATE API for IDE. Attached is my
(very simple) patch adding 2 ioctls, and obsoleting 1. I will send the
implementation of this for the HPT370 in a different message. Please let
me know if there are any problems with this preventing general inclusion.
This patch also includes support for a configurable 'max failures'
parameter, and one change for better DMA error reporting.
Tim
Andre Hedrick wrote:
>
> Bring it on! ;-)
>
> On Tue, 27 Mar 2001, Tim Hockin wrote:
>
> > Andre,
> >
> > I'm doing some work toward hotswap IDE, and I had a query for you. On
> > 2.2.x we added a HDIO_GET_BUSSTATE and HDIO_SET_BUSSTATE ioctl() pair. Now
> > I see in 2.4 that there is an HDIO_TRISTATE_HWIF ioctl(), but no way to
> > un-tristate or query the status.
> >
> > Are there plans to add the converse APIs? I see no one has yet implemented
> > the HWIF_TRISTATE_BUS ioctl() - would you accept my patch to
> > implement the HDIO_{GET,SET}_BUSSTATE, and implementation of it on the
> > HPT366 driver?
--
Tim Hockin
Systems Software Engineer
Sun Microsystems, Cobalt Server Appliances
[EMAIL PROTECTED]
diff -ruN dist-2.4.5/include/linux/hdreg.h cobalt-2.4.5/include/linux/hdreg.h
--- dist-2.4.5/include/linux/hdreg.h Fri May 25 18:01:27 2001
+++ cobalt-2.4.5/include/linux/hdreg.h Thu May 31 14:33:16 2001
@@ -181,9 +181,10 @@
#define HDIO_GET_DMA 0x030b /* get use-dma flag */
#define HDIO_GET_NICE 0x030c /* get nice flags */
#define HDIO_GET_IDENTITY 0x030d /* get IDE identification info */
+#define HDIO_GET_BUSSTATE 0x030e /* get the bus state of the hwif */
#define HDIO_DRIVE_RESET 0x031c /* execute a device reset */
-#define HDIO_TRISTATE_HWIF 0x031d /* execute a channel tristate */
+#define HDIO_TRISTATE_HWIF 0x031d /* OBSOLETE - use SET_BUSSTATE */
#define HDIO_DRIVE_TASK 0x031e /* execute task and special drive
command */
#define HDIO_DRIVE_CMD 0x031f /* execute a special drive command */
@@ -200,6 +201,14 @@
#define HDIO_SCAN_HWIF 0x0328 /* register and (re)scan interface */
#define HDIO_SET_NICE 0x0329 /* set nice flags */
#define HDIO_UNREGISTER_HWIF 0x032a /* unregister interface */
+#define HDIO_SET_BUSSTATE 0x032b /* set the bus state of the hwif */
+
+/* bus states */
+enum {
+ BUSSTATE_OFF = 0,
+ BUSSTATE_ON,
+ BUSSTATE_TRISTATE
+};
/* BIG GEOMETRY */
struct hd_big_geometry {
diff -ruN dist-2.4.5/include/linux/ide.h cobalt-2.4.5/include/linux/ide.h
--- dist-2.4.5/include/linux/ide.h Fri May 25 18:02:42 2001
+++ cobalt-2.4.5/include/linux/ide.h Thu May 31 14:33:16 2001
@@ -349,6 +350,8 @@
byte init_speed; /* transfer rate set at boot */
byte current_speed; /* current transfer rate set */
byte dn; /* now wide spread use */
+ unsigned int failures; /* current failure count */
+ unsigned int max_failures; /* maximum allowed failure count */
} ide_drive_t;
/*
@@ -397,6 +400,11 @@
typedef void (ide_rw_proc_t) (ide_drive_t *, ide_dma_action_t);
/*
+ * ide soft-power support
+ */
+typedef int (ide_busproc_t) (struct hwif_s *, int);
+
+/*
* hwif_chipset_t is used to keep track of the specific hardware
* chipset used by each IDE interface, if known.
*/
@@ -467,6 +475,8 @@
#endif
byte straight8; /* Alan's straight 8 check */
void *hwif_data; /* extra hwif data */
+ ide_busproc_t *busproc; /* driver soft-power interface */
+ byte bus_state; /* power state of the IDE bus */
} ide_hwif_t;
diff -ruN dist-2.4.5/drivers/ide/ide.c cobalt-2.4.5/drivers/ide/ide.c
--- dist-2.4.5/drivers/ide/ide.c Tue May 1 16:05:00 2001
+++ cobalt-2.4.5/drivers/ide/ide.c Thu May 31 14:32:16 2001
@@ -161,6 +161,9 @@
#include <linux/kmod.h>
#endif /* CONFIG_KMOD */
+/* default maximum number of failures */
+#define IDE_DEFAULT_MAX_FAILURES 1
+
static const byte ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR,
IDE3_MAJOR, IDE4_MAJOR, IDE5_MAJOR, IDE6_MAJOR, IDE7_MAJOR, IDE8_MAJOR, IDE9_MAJOR };
static int idebus_parameter; /* holds the "idebus=" parameter */
@@ -248,6 +251,7 @@
hwif->name[1] = 'd';
hwif->name[2] = 'e';
hwif->name[3] = '0' + index;
+ hwif->bus_state = BUSSTATE_ON;
for (unit = 0; unit < MAX_DRIVES; ++unit) {
ide_drive_t *drive = &hwif->drives[unit];
@@ -262,6 +266,7 @@
drive->name[0] = 'h';
drive->name[1] = 'd';
drive->name[2] = 'a' + (index * MAX_DRIVES) + unit;
+ drive->max_failures = IDE_DEFAULT_MAX_FAILURES;
init_waitqueue_head(&drive->wqueue);
}
}
@@ -636,11 +641,14 @@
return ide_started; /* continue polling */
}
printk("%s: reset timed-out, status=0x%02x\n", hwif->name, tmp);
+ drive->failures++;
} else {
printk("%s: reset: ", hwif->name);
- if ((tmp = GET_ERR()) == 1)
+ if ((tmp = GET_ERR()) == 1) {
printk("success\n");
- else {
+ drive->failures = 0;
+ } else {
+ drive->failures++;
#if FANCY_STATUS_DUMPS
printk("master: ");
switch (tmp & 0x7f) {
@@ -1048,6 +1056,12 @@
int i;
unsigned long flags;
+ /* bail early if we've exceeded max_failures */
+ if (drive->max_failures && (drive->failures > drive->max_failures)) {
+ *startstop = ide_stopped;
+ return 1;
+ }
+
udelay(1); /* spec allows drive 400ns to assert "BUSY" */
if ((stat = GET_STAT()) & BUSY_STAT) {
__save_flags(flags); /* local CPU only */
@@ -1144,6 +1158,11 @@
#ifdef DEBUG
printk("%s: start_request: current=0x%08lx\n", hwif->name, (unsigned long) rq);
#endif
+ /* bail early if we've exceeded max_failures */
+ if (drive->max_failures && (drive->failures > drive->max_failures)) {
+ goto kill_rq;
+ }
+
if (unit >= MAX_DRIVES) {
printk("%s: bad device number: %s\n", hwif->name,
kdevname(rq->rq_dev));
goto kill_rq;
@@ -2089,6 +2108,8 @@
hwif->quirkproc = old_hwif.quirkproc;
hwif->rwproc = old_hwif.rwproc;
hwif->dmaproc = old_hwif.dmaproc;
+ hwif->busproc = old_hwif.busproc;
+ hwif->bus_state = old_hwif.bus_state;
hwif->dma_base = old_hwif.dma_base;
hwif->dma_extra = old_hwif.dma_extra;
hwif->config_data = old_hwif.config_data;
@@ -2669,6 +2690,20 @@
case BLKELVGET:
case BLKELVSET:
return blk_ioctl(inode->i_rdev, cmd, arg);
+
+ case HDIO_GET_BUSSTATE:
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+ if (put_user(HWIF(drive)->bus_state, (long *)arg))
+ return -EFAULT;
+ return 0;
+
+ case HDIO_SET_BUSSTATE:
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+ if (HWIF(drive)->busproc)
+ HWIF(drive)->busproc(HWIF(drive), arg);
+ return 0;
default:
if (drive->driver != NULL)
diff -ruN dist-2.4.5/drivers/ide/ide-dma.c cobalt-2.4.5/drivers/ide/ide-dma.c
--- dist-2.4.5/drivers/ide/ide-dma.c Mon Jan 15 13:08:15 2001
+++ cobalt-2.4.5/drivers/ide/ide-dma.c Thu May 31 14:32:16 2001
@@ -206,7 +206,8 @@
}
return ide_stopped;
}
- printk("%s: dma_intr: bad DMA status\n", drive->name);
+ printk("%s: dma_intr: bad DMA status (dma_stat=%x)\n",
+ drive->name, dma_stat);
}
return ide_error(drive, "dma_intr", stat);
}
@@ -514,7 +515,7 @@
dma_stat = inb(dma_base+2); /* get DMA status */
outb(dma_stat|6, dma_base+2); /* clear the INTR & ERROR bits
*/
ide_destroy_dmatable(drive); /* purge DMA mappings */
- return (dma_stat & 7) != 4; /* verify good DMA status */
+ return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0; /*
+verify good DMA status */
case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */
dma_stat = inb(dma_base+2);
#if 0 /* do not set unless you know what you are doing */
diff -ruN dist-2.4.5/drivers/ide/ide-disk.c cobalt-2.4.5/drivers/ide/ide-disk.c
--- dist-2.4.5/drivers/ide/ide-disk.c Fri Feb 9 11:30:23 2001
+++ cobalt-2.4.5/drivers/ide/ide-disk.c Thu May 31 14:32:16 2001
@@ -692,6 +692,8 @@
ide_add_setting(drive, "file_readahead", SETTING_RW,
BLKFRAGET, BLKFRASET, TYPE_INTA, 0,
INT_MAX, 1, 1024, &max_readahead[major][minor],
NULL);
ide_add_setting(drive, "max_kb_per_request", SETTING_RW,
BLKSECTGET, BLKSECTSET, TYPE_INTA, 1,
255, 1, 2, &max_sectors[major][minor],
NULL);
ide_add_setting(drive, "lun", SETTING_RW,
-1, -1, TYPE_INT, 0,
7, 1, 1, &drive->lun,
NULL);
+ 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);
}
/*