Re: problem with a cobalt RaQ550 system and DMA (Serverworks OSB4 in impossible state)

Duncan Laurie
2003-04-23T23:48:58Z

[-- Attachment #1: Type: text/plain, Size: 1084 bytes --]

Olivier Bornet wrote:
> Hello,
>
> I'm trying to install Debian on 4 RaQ550 with each 2 80GB disks. All
> seems OK with 3 of RaQ, but with one, it crash when I put the two disks
> in a RAID1 meta device. In fact, it as crash at about 6% before the 70GB
> partition is fully synchronized.
>

Hi Olivier,

There is an interaction problem between the Serverworks IDE controller
and some Seagate BlockPoint drives. They aren't handling the bus
throttling correctly on ATA bus writes and are sometimes overflowing
their FIFOs.

The CSB5 in UDMA mode 5 sends 3 words after the drive de-asserts
DDMARDY- (per ATA spec section 9.14.3.2) but these drives sometimes
have problems when the three extra words are sent and overflows its
FIFO. Other IDE controllers only send 2 extra words and don't cause
this to happen.

The only work around we have found is to limit these drives to ATA
mode 4. Supposedly newer Seagate firmware for these drives will report
only UDMA mode 4 capable, but for earlier drives (like those probably
found in your raq550) try this patch against 2.4.20.

-duncan

[-- Attachment #2: serverworks.c.diff --]
[-- Type: text/plain, Size: 1205 bytes --]

--- serverworks.c 2002-08-02 17:39:44.000000000 -0700
+++ /home/duncan/cvs/linux-2.4/drivers/ide/serverworks.c 2003-04-23 16:37:45.000000000 -0700
@@ -100,6 +100,12 @@
#include <linux/stat.h>
#include <linux/proc_fs.h>

+const char *bad_ata100[] = {
+ "ST340016A",
+ "ST380021A",
+ NULL
+};
+
static struct pci_dev *bmide_dev;
static byte svwks_revision = 0;

@@ -107,6 +113,14 @@
extern int (*svwks_display_info)(char *, char **, off_t, int); /* ide-proc.c */
extern char *ide_media_verbose(ide_drive_t *);

+static int check_in_drive_lists (ide_drive_t *drive, const char **list)
+{
+ while (*list)
+ if (!strcmp(*list++, drive->id->model))
+ return 1;
+ return 0;
+}
+
static int svwks_get_info (char *buffer, char **addr, off_t offset, int count)
{
char *p = buffer;
@@ -420,7 +434,8 @@
int ultra100 = (ultra66 && svwks_revision >= SVWKS_CSB5_REVISION_NEW) ? 1 : 0;
byte speed;

- if ((id->dma_ultra & 0x0020) && (udma_66) && (ultra100)) {
+ if ((id->dma_ultra & 0x0020) && (udma_66) && (ultra100) &&
+ !check_in_drive_lists(drive, bad_ata100)) {
speed = XFER_UDMA_5;
} else if (id->dma_ultra & 0x0010) {
speed = ((udma_66) && (ultra66)) ? XFER_UDMA_4 : XFER_UDMA_2;