Commit 49bbaa0c authored by Jens Axboe's avatar Jens Axboe

serverworks update

parent a21fb2ee
...@@ -36,23 +36,20 @@ ...@@ -36,23 +36,20 @@
#include <asm/io.h> #include <asm/io.h>
#include "ide_modes.h" #include "ide_modes.h"
#include "serverworks.h"
#define DISPLAY_SVWKS_TIMINGS 1 static u8 svwks_revision = 0;
#undef SVWKS_DEBUG_DRIVE_INFO static struct pci_dev *isa_dev;
#if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS) #if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
#include <linux/stat.h> #include <linux/stat.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
static u8 svwks_proc = 0;
#define SVWKS_MAX_DEVS 2 #define SVWKS_MAX_DEVS 2
static struct pci_dev *svwks_devs[SVWKS_MAX_DEVS]; static struct pci_dev *svwks_devs[SVWKS_MAX_DEVS];
static int n_svwks_devs; static int n_svwks_devs;
static byte svwks_revision = 0;
static int svwks_get_info(char *, char **, off_t, int);
extern int (*svwks_display_info)(char *, char **, off_t, int); /* ide-proc.c */
static int svwks_get_info (char *buffer, char **addr, off_t offset, int count) static int svwks_get_info (char *buffer, char **addr, off_t offset, int count)
{ {
char *p = buffer; char *p = buffer;
...@@ -81,28 +78,23 @@ static int svwks_get_info (char *buffer, char **addr, off_t offset, int count) ...@@ -81,28 +78,23 @@ static int svwks_get_info (char *buffer, char **addr, off_t offset, int count)
c0 = inb_p((unsigned short)bibma + 0x02); c0 = inb_p((unsigned short)bibma + 0x02);
c1 = inb_p((unsigned short)bibma + 0x0a); c1 = inb_p((unsigned short)bibma + 0x0a);
p += sprintf(p, "\n ServerWorks ");
switch(dev->device) { switch(dev->device) {
case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2:
case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE: case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE:
p += sprintf(p, "\n " p += sprintf(p, "CSB6 ");
"ServerWorks CSB6 Chipset (rev %02x)\n",
svwks_revision);
break; break;
case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE: case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
p += sprintf(p, "\n " p += sprintf(p, "CSB5 ");
"ServerWorks CSB5 Chipset (rev %02x)\n",
svwks_revision);
break; break;
case PCI_DEVICE_ID_SERVERWORKS_OSB4IDE: case PCI_DEVICE_ID_SERVERWORKS_OSB4IDE:
p += sprintf(p, "\n " p += sprintf(p, "OSB4 ");
"ServerWorks OSB4 Chipset (rev %02x)\n",
svwks_revision);
break; break;
default: default:
p += sprintf(p, "\n " p += sprintf(p, "%04x ", dev->device);
"ServerWorks %04x Chipset (rev %02x)\n",
dev->device, svwks_revision);
break; break;
} }
p += sprintf(p, "Chipset (rev %02x)\n", svwks_revision);
p += sprintf(p, "------------------------------- " p += sprintf(p, "------------------------------- "
"General Status " "General Status "
...@@ -110,7 +102,8 @@ static int svwks_get_info (char *buffer, char **addr, off_t offset, int count) ...@@ -110,7 +102,8 @@ static int svwks_get_info (char *buffer, char **addr, off_t offset, int count)
p += sprintf(p, "--------------- Primary Channel " p += sprintf(p, "--------------- Primary Channel "
"---------------- Secondary Channel " "---------------- Secondary Channel "
"-------------\n"); "-------------\n");
p += sprintf(p, " %sabled %sabled\n", p += sprintf(p, " %sabled"
" %sabled\n",
(c0&0x80) ? "dis" : " en", (c0&0x80) ? "dis" : " en",
(c1&0x80) ? "dis" : " en"); (c1&0x80) ? "dis" : " en");
p += sprintf(p, "--------------- drive0 --------- drive1 " p += sprintf(p, "--------------- drive0 --------- drive1 "
...@@ -202,113 +195,125 @@ static int svwks_get_info (char *buffer, char **addr, off_t offset, int count) ...@@ -202,113 +195,125 @@ static int svwks_get_info (char *buffer, char **addr, off_t offset, int count)
} }
#endif /* defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS) */ #endif /* defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS) */
#define SVWKS_CSB5_REVISION_NEW 0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */ static u8 svwks_ratemask (ide_drive_t *drive)
#define SVWKS_CSB6_REVISION 0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */
byte svwks_proc = 0;
static struct pci_dev *isa_dev;
static byte svwks_ratemask (ide_drive_t *drive)
{ {
struct pci_dev *dev = HWIF(drive)->pci_dev; struct pci_dev *dev = HWIF(drive)->pci_dev;
byte mode = 0; u8 mode;
if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) { if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
u32 reg = 0; u32 reg = 0;
mode &= ~0x01;
if (isa_dev) if (isa_dev)
pci_read_config_dword(isa_dev, 0x64, &reg); pci_read_config_dword(isa_dev, 0x64, &reg);
if ((reg & 0x00004000) == 0x00004000)
mode |= 0x01; /*
* Don't enable UDMA on disk devices for the moment
*/
if(drive->media == ide_disk)
return 0;
/* Check the OSB4 DMA33 enable bit */
return ((reg & 0x00004000) == 0x00004000) ? 1 : 0;
} else if (svwks_revision < SVWKS_CSB5_REVISION_NEW) { } else if (svwks_revision < SVWKS_CSB5_REVISION_NEW) {
mode |= 0x01; return 1;
} else if (svwks_revision >= SVWKS_CSB5_REVISION_NEW) { } else if (svwks_revision >= SVWKS_CSB5_REVISION_NEW) {
u8 btr =0; u8 btr = 0;
pci_read_config_byte(dev, 0x5A, &btr); pci_read_config_byte(dev, 0x5A, &btr);
mode |= btr; mode = btr;
if (!eighty_ninty_three(drive)) if (!eighty_ninty_three(drive))
mode &= ~0x02; mode = min(mode, (u8)1);
} }
if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) && if (((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
(dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) &&
(!(PCI_FUNC(dev->devfn) & 1))) (!(PCI_FUNC(dev->devfn) & 1)))
mode = 0x02; mode = 2;
mode &= ~0xFC; return mode;
return (mode);
} }
static byte svwks_ratefilter (ide_drive_t *drive, byte speed) static u8 svwks_csb_check (struct pci_dev *dev)
{
#ifdef CONFIG_BLK_DEV_IDEDMA
byte mode = svwks_ratemask(drive);
switch(mode) {
case 0x04: while (speed > XFER_UDMA_6) speed--; break;
case 0x03: while (speed > XFER_UDMA_5) speed--; break;
case 0x02: while (speed > XFER_UDMA_4) speed--; break;
case 0x01: while (speed > XFER_UDMA_2) speed--; break;
case 0x00:
default: while (speed > XFER_MW_DMA_2) speed--; break;
break;
}
#else
while (speed > XFER_PIO_4) speed--;
#endif /* CONFIG_BLK_DEV_IDEDMA */
// printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed);
return speed;
}
static byte svwks_csb_check (struct pci_dev *dev)
{ {
switch (dev->device) { switch (dev->device) {
case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE: case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE: case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE:
case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2:
return 1; return 1;
default: default:
break; break;
} }
return 0; return 0;
} }
static int svwks_tune_chipset (ide_drive_t *drive, byte xferspeed) static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed)
{ {
byte udma_modes[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 }; u8 udma_modes[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
byte dma_modes[] = { 0x77, 0x21, 0x20 }; u8 dma_modes[] = { 0x77, 0x21, 0x20 };
byte pio_modes[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 }; u8 pio_modes[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 };
u8 drive_pci[] = { 0x41, 0x40, 0x43, 0x42 };
u8 drive_pci2[] = { 0x45, 0x44, 0x47, 0x46 };
ide_hwif_t *hwif = HWIF(drive); ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev; struct pci_dev *dev = hwif->pci_dev;
byte unit = (drive->select.b.unit & 0x01); u8 speed = ide_rate_filter(svwks_ratemask(drive), xferspeed);
byte csb5 = svwks_csb_check(dev); u8 pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
u8 unit = (drive->select.b.unit & 0x01);
byte drive_pci = 0x00; u8 csb5 = svwks_csb_check(dev);
byte drive_pci2 = 0x00; u8 ultra_enable = 0, ultra_timing = 0;
byte drive_pci3 = hwif->channel ? 0x57 : 0x56; u8 dma_timing = 0, pio_timing = 0;
u16 csb5_pio = 0;
byte ultra_enable = 0x00;
byte ultra_timing = 0x00; pci_read_config_byte(dev, drive_pci[drive->dn], &pio_timing);
byte dma_timing = 0x00; pci_read_config_byte(dev, drive_pci2[drive->dn], &dma_timing);
byte pio_timing = 0x00; pci_read_config_byte(dev, (0x56|hwif->channel), &ultra_timing);
unsigned short csb5_pio = 0x00;
byte pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
byte speed = svwks_ratefilter(drive, xferspeed);
switch (drive->dn) {
case 0: drive_pci = 0x41; drive_pci2 = 0x45; break;
case 1: drive_pci = 0x40; drive_pci2 = 0x44; break;
case 2: drive_pci = 0x43; drive_pci2 = 0x47; break;
case 3: drive_pci = 0x42; drive_pci2 = 0x46; break;
default:
return -1;
}
pci_read_config_byte(dev, drive_pci, &pio_timing);
pci_read_config_byte(dev, drive_pci2, &dma_timing);
pci_read_config_byte(dev, drive_pci3, &ultra_timing);
pci_read_config_word(dev, 0x4A, &csb5_pio); pci_read_config_word(dev, 0x4A, &csb5_pio);
pci_read_config_byte(dev, 0x54, &ultra_enable); pci_read_config_byte(dev, 0x54, &ultra_enable);
/* Per Specified Design by OEM, and ASIC Architect */
if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
(dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) {
if (!drive->init_speed) {
u8 dma_stat = hwif->INB(hwif->dma_status);
dma_pio:
if (((ultra_enable << (7-drive->dn) & 0x80) == 0x80) &&
((dma_stat & (1<<(5+unit))) == (1<<(5+unit)))) {
drive->current_speed = drive->init_speed = XFER_UDMA_0 + udma_modes[(ultra_timing >> (4*unit)) & ~(0xF0)];
return 0;
} else if ((dma_timing) &&
((dma_stat&(1<<(5+unit)))==(1<<(5+unit)))) {
u8 dmaspeed = dma_timing;
dma_timing &= ~0xFF;
if ((dmaspeed & 0x20) == 0x20)
dmaspeed = XFER_MW_DMA_2;
else if ((dmaspeed & 0x21) == 0x21)
dmaspeed = XFER_MW_DMA_1;
else if ((dmaspeed & 0x77) == 0x77)
dmaspeed = XFER_MW_DMA_0;
else
goto dma_pio;
drive->current_speed = drive->init_speed = dmaspeed;
return 0;
} else if (pio_timing) {
u8 piospeed = pio_timing;
pio_timing &= ~0xFF;
if ((piospeed & 0x20) == 0x20)
piospeed = XFER_PIO_4;
else if ((piospeed & 0x22) == 0x22)
piospeed = XFER_PIO_3;
else if ((piospeed & 0x34) == 0x34)
piospeed = XFER_PIO_2;
else if ((piospeed & 0x47) == 0x47)
piospeed = XFER_PIO_1;
else if ((piospeed & 0x5d) == 0x5d)
piospeed = XFER_PIO_0;
else
goto oem_setup_failed;
drive->current_speed = drive->init_speed = piospeed;
return 0;
}
}
}
oem_setup_failed:
pio_timing &= ~0xFF; pio_timing &= ~0xFF;
dma_timing &= ~0xFF; dma_timing &= ~0xFF;
ultra_timing &= ~(0x0F << (4*unit)); ultra_timing &= ~(0x0F << (4*unit));
...@@ -350,13 +355,13 @@ static int svwks_tune_chipset (ide_drive_t *drive, byte xferspeed) ...@@ -350,13 +355,13 @@ static int svwks_tune_chipset (ide_drive_t *drive, byte xferspeed)
break; break;
} }
pci_write_config_byte(dev, drive_pci, pio_timing); pci_write_config_byte(dev, drive_pci[drive->dn], pio_timing);
if (csb5) if (csb5)
pci_write_config_word(dev, 0x4A, csb5_pio); pci_write_config_word(dev, 0x4A, csb5_pio);
#ifdef CONFIG_BLK_DEV_IDEDMA #ifdef CONFIG_BLK_DEV_IDEDMA
pci_write_config_byte(dev, drive_pci2, dma_timing); pci_write_config_byte(dev, drive_pci2[drive->dn], dma_timing);
pci_write_config_byte(dev, drive_pci3, ultra_timing); pci_write_config_byte(dev, (0x56|hwif->channel), ultra_timing);
pci_write_config_byte(dev, 0x54, ultra_enable); pci_write_config_byte(dev, 0x54, ultra_enable);
#endif /* CONFIG_BLK_DEV_IDEDMA */ #endif /* CONFIG_BLK_DEV_IDEDMA */
...@@ -365,13 +370,13 @@ static int svwks_tune_chipset (ide_drive_t *drive, byte xferspeed) ...@@ -365,13 +370,13 @@ static int svwks_tune_chipset (ide_drive_t *drive, byte xferspeed)
static void config_chipset_for_pio (ide_drive_t *drive) static void config_chipset_for_pio (ide_drive_t *drive)
{ {
unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90}; u16 eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
unsigned short xfer_pio = drive->id->eide_pio_modes; u16 xfer_pio = drive->id->eide_pio_modes;
byte timing, speed, pio; u8 timing, speed, pio;
pio = ide_get_best_pio_mode(drive, 255, 5, NULL); pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
if (xfer_pio> 4) if (xfer_pio > 4)
xfer_pio = 0; xfer_pio = 0;
if (drive->id->eide_pio_iordy > 0) if (drive->id->eide_pio_iordy > 0)
...@@ -401,181 +406,90 @@ static void config_chipset_for_pio (ide_drive_t *drive) ...@@ -401,181 +406,90 @@ static void config_chipset_for_pio (ide_drive_t *drive)
drive->current_speed = speed; drive->current_speed = speed;
} }
static void svwks_tune_drive (ide_drive_t *drive, byte pio) static void svwks_tune_drive (ide_drive_t *drive, u8 pio)
{ {
byte speed; (void) svwks_tune_chipset(drive, (XFER_PIO_0 + pio));
switch(pio) {
case 4: speed = XFER_PIO_4;break;
case 3: speed = XFER_PIO_3;break;
case 2: speed = XFER_PIO_2;break;
case 1: speed = XFER_PIO_1;break;
default: speed = XFER_PIO_0;break;
}
(void) svwks_tune_chipset(drive, speed);
} }
#ifdef CONFIG_BLK_DEV_IDEDMA #ifdef CONFIG_BLK_DEV_IDEDMA
static int config_chipset_for_dma (ide_drive_t *drive) static int config_chipset_for_dma (ide_drive_t *drive)
{ {
struct hd_driveid *id = drive->id; u8 speed = ide_dma_speed(drive, svwks_ratemask(drive));
byte mode = svwks_ratemask(drive);
byte speed, dma = 1;
if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE)
mode = 0;
switch(mode) {
case 0x04:
if (id->dma_ultra & 0x0040)
{ speed = XFER_UDMA_6; break; }
case 0x03:
if (id->dma_ultra & 0x0020)
{ speed = XFER_UDMA_5; break; }
case 0x02:
if (id->dma_ultra & 0x0010)
{ speed = XFER_UDMA_4; break; }
if (id->dma_ultra & 0x0008)
{ speed = XFER_UDMA_3; break; }
case 0x01:
if (id->dma_ultra & 0x0004)
{ speed = XFER_UDMA_2; break; }
if (id->dma_ultra & 0x0002)
{ speed = XFER_UDMA_1; break; }
if (id->dma_ultra & 0x0001)
{ speed = XFER_UDMA_0; break; }
if (id->dma_mword & 0x0004)
{ speed = XFER_MW_DMA_2; break; }
if (id->dma_mword & 0x0002)
{ speed = XFER_MW_DMA_1; break; }
if (id->dma_mword & 0x0001)
{ speed = XFER_MW_DMA_0; break; }
#if 0
if (id->dma_1word & 0x0004)
{ speed = XFER_SW_DMA_2; break; }
if (id->dma_1word & 0x0002)
{ speed = XFER_SW_DMA_1; break; }
if (id->dma_1word & 0x0001)
{ speed = XFER_SW_DMA_0; break; }
#endif
default:
speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
dma = 0;
break;
}
(void) svwks_tune_chipset(drive, speed); if (!(speed))
speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
// return ((int) (dma) ? ide_dma_on : ide_dma_off_quietly); (void) svwks_tune_chipset(drive, speed);
return ((int) ((id->dma_ultra >> 11) & 7) ? ide_dma_on : return ide_dma_enable(drive);
((id->dma_ultra >> 8) & 7) ? ide_dma_on :
((id->dma_mword >> 8) & 7) ? ide_dma_on :
((id->dma_1word >> 8) & 7) ? ide_dma_on :
ide_dma_off_quietly);
} }
static int config_drive_xfer_rate (ide_drive_t *drive) static int svwks_config_drive_xfer_rate (ide_drive_t *drive)
{ {
struct hd_driveid *id = drive->id; ide_hwif_t *hwif = HWIF(drive);
ide_dma_action_t dma_func = ide_dma_on; struct hd_driveid *id = drive->id;
drive->init_speed = 0; drive->init_speed = 0;
if (id && (id->capability & 1) && HWIF(drive)->autodma) { if (id && (id->capability & 1) && drive->autodma) {
/* Consult the list of known "bad" drives */ /* Consult the list of known "bad" drives */
if (ide_dmaproc(ide_dma_bad_drive, drive)) { if (hwif->ide_dma_bad_drive(drive))
dma_func = ide_dma_off;
goto fast_ata_pio; goto fast_ata_pio;
}
dma_func = ide_dma_off_quietly;
if (id->field_valid & 4) { if (id->field_valid & 4) {
if (id->dma_ultra & 0x003F) { if (id->dma_ultra & hwif->ultra_mask) {
/* Force if Capable UltraDMA */ /* Force if Capable UltraDMA */
dma_func = config_chipset_for_dma(drive); int dma = config_chipset_for_dma(drive);
if ((id->field_valid & 2) && if ((id->field_valid & 2) && !dma)
(dma_func != ide_dma_on))
goto try_dma_modes; goto try_dma_modes;
} }
} else if (id->field_valid & 2) { } else if (id->field_valid & 2) {
try_dma_modes: try_dma_modes:
if ((id->dma_mword & 0x0007) || if ((id->dma_mword & hwif->mwdma_mask) ||
(id->dma_1word & 0x007)) { (id->dma_1word & hwif->swdma_mask)) {
/* Force if Capable regular DMA modes */ /* Force if Capable regular DMA modes */
dma_func = config_chipset_for_dma(drive); if (!config_chipset_for_dma(drive))
if (dma_func != ide_dma_on)
goto no_dma_set; goto no_dma_set;
} }
} else if (ide_dmaproc(ide_dma_good_drive, drive)) { } else if (hwif->ide_dma_good_drive(drive) &&
if (id->eide_dma_time > 150) { (id->eide_dma_time < 150)) {
goto no_dma_set;
}
/* Consult the list of known "good" drives */ /* Consult the list of known "good" drives */
dma_func = config_chipset_for_dma(drive); if (!config_chipset_for_dma(drive))
if (dma_func != ide_dma_on)
goto no_dma_set; goto no_dma_set;
} else { } else {
goto fast_ata_pio; goto no_dma_set;
} }
} else if ((id->capability & 8) || (id->field_valid & 2)) { } else if ((id->capability & 8) || (id->field_valid & 2)) {
fast_ata_pio: fast_ata_pio:
dma_func = ide_dma_off_quietly;
no_dma_set: no_dma_set:
config_chipset_for_pio(drive); config_chipset_for_pio(drive);
// HWIF(drive)->tuneproc(drive, 5); // hwif->tuneproc(drive, 5);
return hwif->ide_dma_off_quietly(drive);
} }
return HWIF(drive)->dmaproc(dma_func, drive); return hwif->ide_dma_on(drive);
} }
static int svwks_dmaproc(ide_dma_action_t func, ide_drive_t *drive) static int svwks_ide_dma_end (ide_drive_t *drive)
{ {
switch (func) { ide_hwif_t *hwif = HWIF(drive);
case ide_dma_check: u8 dma_stat = hwif->INB(hwif->dma_status);
return config_drive_xfer_rate(drive);
case ide_dma_end: if ((dma_stat & 1) && drive->media == ide_disk)
{ {
ide_hwif_t *hwif = HWIF(drive); printk(KERN_CRIT "Serverworks OSB4 in impossible state.\n");
unsigned long dma_base = hwif->dma_base; printk(KERN_CRIT "Disable UDMA or if you are using Seagate then try switching disk types\n");
printk(KERN_CRIT "on this controller. Please report this event to osb4-bug@ide.cabal.tm\n");
if(IN_BYTE(dma_base+0x02)&1) /* Panic might sys_sync -> death by corrupt disk */
{ printk(KERN_CRIT "OSB4: continuing might cause disk corruption.\n");
#if 0 while(1)
int i; cpu_relax();
printk(KERN_ERR "Curious - OSB4 thinks the DMA is still running.\n");
for(i=0;i<10;i++)
{
if(!(IN_BYTE(dma_base+0x02)&1))
{
printk(KERN_ERR "OSB4 now finished.\n");
break;
}
udelay(5);
}
#endif
printk(KERN_CRIT "Serverworks OSB4 in impossible state.\n");
printk(KERN_CRIT "Disable UDMA or if you are using Seagate then try switching disk types\n");
printk(KERN_CRIT "on this controller. Please report this event to osb4-bug@ide.cabal.tm\n");
#if 0
/* Panic might sys_sync -> death by corrupt disk */
panic("OSB4: continuing might cause disk corruption.\n");
#else
printk(KERN_CRIT "OSB4: continuing might cause disk corruption.\n");
while(1)
cpu_relax();
#endif
}
/* and drop through */
}
default:
break;
} }
/* Other cases are done by generic IDE-DMA code. */ return __ide_dma_end(drive);
return ide_dmaproc(func, drive);
} }
#endif /* CONFIG_BLK_DEV_IDEDMA */ #endif /* CONFIG_BLK_DEV_IDEDMA */
unsigned int __init pci_init_svwks (struct pci_dev *dev, const char *name) static unsigned int __init init_chipset_svwks (struct pci_dev *dev, const char *name)
{ {
unsigned int reg; unsigned int reg;
byte btr; u8 btr;
/* save revision id to determine DMA capability */ /* save revision id to determine DMA capability */
pci_read_config_byte(dev, PCI_REVISION_ID, &svwks_revision); pci_read_config_byte(dev, PCI_REVISION_ID, &svwks_revision);
...@@ -590,6 +504,8 @@ unsigned int __init pci_init_svwks (struct pci_dev *dev, const char *name) ...@@ -590,6 +504,8 @@ unsigned int __init pci_init_svwks (struct pci_dev *dev, const char *name)
if (isa_dev) { if (isa_dev) {
pci_read_config_dword(isa_dev, 0x64, &reg); pci_read_config_dword(isa_dev, 0x64, &reg);
reg &= ~0x00002000; /* disable 600ns interrupt mask */ reg &= ~0x00002000; /* disable 600ns interrupt mask */
if(!(reg & 0x00004000))
printk(KERN_DEBUG "%s: UDMA not BIOS enabled.\n", name);
reg |= 0x00004000; /* enable UDMA/33 support */ reg |= 0x00004000; /* enable UDMA/33 support */
pci_write_config_dword(isa_dev, 0x64, reg); pci_write_config_dword(isa_dev, 0x64, reg);
} }
...@@ -597,12 +513,15 @@ unsigned int __init pci_init_svwks (struct pci_dev *dev, const char *name) ...@@ -597,12 +513,15 @@ unsigned int __init pci_init_svwks (struct pci_dev *dev, const char *name)
/* setup CSB5/CSB6 : South Bridge and IDE option RAID */ /* setup CSB5/CSB6 : South Bridge and IDE option RAID */
else if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) || else if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ||
(dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE)) { (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
(dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) {
// u32 pioreg = 0, dmareg = 0;
/* Third Channel Test */ /* Third Channel Test */
if (!(PCI_FUNC(dev->devfn) & 1)) { if (!(PCI_FUNC(dev->devfn) & 1)) {
#if 1 #if 1
struct pci_dev * findev = NULL; struct pci_dev * findev = NULL;
unsigned int reg4c = 0; u32 reg4c = 0;
findev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS, findev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
PCI_DEVICE_ID_SERVERWORKS_CSB5, NULL); PCI_DEVICE_ID_SERVERWORKS_CSB5, NULL);
if (findev) { if (findev) {
...@@ -615,13 +534,34 @@ unsigned int __init pci_init_svwks (struct pci_dev *dev, const char *name) ...@@ -615,13 +534,34 @@ unsigned int __init pci_init_svwks (struct pci_dev *dev, const char *name)
#endif #endif
outb_p(0x06, 0x0c00); outb_p(0x06, 0x0c00);
dev->irq = inb_p(0x0c01); dev->irq = inb_p(0x0c01);
#if 1 #if 0
/* WE need to figure out how to get the correct one */ /* WE need to figure out how to get the correct one */
printk("%s: interrupt %d\n", name, dev->irq); printk("%s: interrupt %d\n", name, dev->irq);
if (dev->irq != 0x0B) if (dev->irq != 0x0B)
dev->irq = 0x0B; dev->irq = 0x0B;
#endif
#if 0
printk("%s: device class (0x%04x)\n",
name, dev->class);
#else
if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
dev->class &= ~0x000F0F00;
// dev->class |= ~0x00000400;
dev->class |= ~0x00010100;
/**/
}
#endif #endif
} else { } else {
struct pci_dev * findev = NULL;
u8 reg41 = 0;
findev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
PCI_DEVICE_ID_SERVERWORKS_CSB6, NULL);
if (findev) {
pci_read_config_byte(findev, 0x41, &reg41);
reg41 &= ~0x40;
pci_write_config_byte(findev, 0x41, reg41);
}
/* /*
* This is a device pin issue on CSB6. * This is a device pin issue on CSB6.
* Since there will be a future raid mode, * Since there will be a future raid mode,
...@@ -631,8 +571,10 @@ unsigned int __init pci_init_svwks (struct pci_dev *dev, const char *name) ...@@ -631,8 +571,10 @@ unsigned int __init pci_init_svwks (struct pci_dev *dev, const char *name)
*/ */
dev->irq = 0; dev->irq = 0;
} }
pci_write_config_dword(dev, 0x40, 0x99999999); // pci_read_config_dword(dev, 0x40, &pioreg)
pci_write_config_dword(dev, 0x44, 0xFFFFFFFF); // pci_write_config_dword(dev, 0x40, 0x99999999);
// pci_read_config_dword(dev, 0x44, &dmareg);
// pci_write_config_dword(dev, 0x44, 0xFFFFFFFF);
/* setup the UDMA Control register /* setup the UDMA Control register
* *
* 1. clear bit 6 to enable DMA * 1. clear bit 6 to enable DMA
...@@ -651,12 +593,13 @@ unsigned int __init pci_init_svwks (struct pci_dev *dev, const char *name) ...@@ -651,12 +593,13 @@ unsigned int __init pci_init_svwks (struct pci_dev *dev, const char *name)
pci_write_config_byte(dev, 0x5A, btr); pci_write_config_byte(dev, 0x5A, btr);
} }
svwks_devs[n_svwks_devs++] = dev;
#if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS) #if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
svwks_devs[n_svwks_devs++] = dev;
if (!svwks_proc) { if (!svwks_proc) {
svwks_proc = 1; svwks_proc = 1;
svwks_display_info = &svwks_get_info; ide_pci_register_host_proc(&svwks_procs[0]);
} }
#endif /* DISPLAY_SVWKS_TIMINGS && CONFIG_PROC_FS */ #endif /* DISPLAY_SVWKS_TIMINGS && CONFIG_PROC_FS */
...@@ -706,10 +649,15 @@ static unsigned int __init ata66_svwks_cobalt (ide_hwif_t *hwif) ...@@ -706,10 +649,15 @@ static unsigned int __init ata66_svwks_cobalt (ide_hwif_t *hwif)
return 0; return 0;
} }
unsigned int __init ata66_svwks (ide_hwif_t *hwif) static unsigned int __init ata66_svwks (ide_hwif_t *hwif)
{ {
struct pci_dev *dev = hwif->pci_dev; struct pci_dev *dev = hwif->pci_dev;
/* Per Specified Design by OEM, and ASIC Architect */
if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
(dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2))
return 1;
/* Server Works */ /* Server Works */
if (dev->subsystem_vendor == PCI_VENDOR_ID_SERVERWORKS) if (dev->subsystem_vendor == PCI_VENDOR_ID_SERVERWORKS)
return ata66_svwks_svwks (hwif); return ata66_svwks_svwks (hwif);
...@@ -725,65 +673,114 @@ unsigned int __init ata66_svwks (ide_hwif_t *hwif) ...@@ -725,65 +673,114 @@ unsigned int __init ata66_svwks (ide_hwif_t *hwif)
return 0; return 0;
} }
void __init ide_init_svwks (ide_hwif_t *hwif) #undef CAN_SW_DMA
static void __init init_hwif_svwks (ide_hwif_t *hwif)
{ {
u8 dma_stat = 0;
if (!hwif->irq) if (!hwif->irq)
hwif->irq = hwif->channel ? 15 : 14; hwif->irq = hwif->channel ? 15 : 14;
hwif->tuneproc = &svwks_tune_drive; hwif->tuneproc = &svwks_tune_drive;
hwif->speedproc = &svwks_tune_chipset; hwif->speedproc = &svwks_tune_chipset;
hwif->drives[0].autotune = 1;
hwif->drives[1].autotune = 1; hwif->atapi_dma = 1;
if (hwif->pci_dev->device != PCI_DEVICE_ID_SERVERWORKS_OSB4IDE)
hwif->ultra_mask = 0x3f;
hwif->mwdma_mask = 0x07;
#ifdef CAN_SW_DMA
hwif->swdma_mask = 0x07;
#endif /* CAN_SW_DMA */
hwif->autodma = 0; hwif->autodma = 0;
if (!hwif->dma_base) if (!hwif->dma_base) {
hwif->drives[0].autotune = 1;
hwif->drives[1].autotune = 1;
return; return;
}
#ifdef CONFIG_BLK_DEV_IDEDMA #ifdef CONFIG_BLK_DEV_IDEDMA
hwif->dmaproc = &svwks_dmaproc; hwif->ide_dma_check = &svwks_config_drive_xfer_rate;
# ifdef CONFIG_IDEDMA_AUTO if (hwif->pci_dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE)
hwif->ide_dma_end = &svwks_ide_dma_end;
else if (!(hwif->udma_four))
hwif->udma_four = ata66_svwks(hwif);
if (!noautodma) if (!noautodma)
hwif->autodma = 1; hwif->autodma = 1;
# endif /* CONFIG_IDEDMA_AUTO */
dma_stat = hwif->INB(hwif->dma_status);
hwif->drives[0].autodma = (dma_stat & 0x20);
hwif->drives[1].autodma = (dma_stat & 0x40);
hwif->drives[0].autotune = (!(dma_stat & 0x20));
hwif->drives[1].autotune = (!(dma_stat & 0x40));
// hwif->drives[0].autodma = hwif->autodma;
// hwif->drives[1].autodma = hwif->autodma;
#endif /* !CONFIG_BLK_DEV_IDEDMA */ #endif /* !CONFIG_BLK_DEV_IDEDMA */
} }
/* /*
* We allow the BM-DMA driver to only work on enabled interfaces. * We allow the BM-DMA driver to only work on enabled interfaces.
*/ */
void __init ide_dmacapable_svwks (ide_hwif_t *hwif, unsigned long dmabase) static void __init init_dma_svwks (ide_hwif_t *hwif, unsigned long dmabase)
{ {
struct pci_dev *dev = hwif->pci_dev; struct pci_dev *dev = hwif->pci_dev;
if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) &&
if (((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
(dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) &&
(!(PCI_FUNC(dev->devfn) & 1)) && (hwif->channel)) (!(PCI_FUNC(dev->devfn) & 1)) && (hwif->channel))
return; return;
#if 0
if (svwks_revision == (SVWKS_CSB5_REVISION_NEW + 1)) {
if (hwif->mate && hwif->mate->dma_base) {
dmabase = hwif->mate->dma_base - (hwif->channel ? 0 : 8);
} else {
dmabase = pci_resource_start(dev, 4);
if (!dmabase) {
printk("%s: dma_base is invalid (0x%04lx)\n",
hwif->name, dmabase);
dmabase = 0;
}
}
}
#endif
ide_setup_dma(hwif, dmabase, 8); ide_setup_dma(hwif, dmabase, 8);
} }
extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d); extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
static void __init init_setup_svwks (struct pci_dev *dev, ide_pci_device_t *d)
{
ide_setup_pci_device(dev, d);
}
void __init fixup_device_csb6 (struct pci_dev *dev, ide_pci_device_t *d) static void __init init_setup_csb6 (struct pci_dev *dev, ide_pci_device_t *d)
{ {
if (!(PCI_FUNC(dev->devfn) & 1)) { if (!(PCI_FUNC(dev->devfn) & 1)) {
d->bootable = NEVER_BOARD; d->bootable = NEVER_BOARD;
if (dev->resource[0].start == 0x01f1)
d->bootable = ON_BOARD;
} else {
if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE)
return;
} }
#if 0
if ((IDE_PCI_DEVID_EQ(d->devid, DEVID_CSB6) &&
(!(PCI_FUNC(dev->devfn) & 1)))
d->autodma = AUTODMA;
#endif
d->channels = (((d->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
(d->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) &&
(!(PCI_FUNC(dev->devfn) & 1))) ? 1 : 2;
printk("%s: IDE controller on PCI bus %02x dev %02x\n",
d->name, dev->bus->number, dev->devfn);
ide_setup_pci_device(dev, d); ide_setup_pci_device(dev, d);
} }
int __init serverworks_scan_pcidev (struct pci_dev *dev)
{
ide_pci_device_t *d;
if (dev->vendor != PCI_VENDOR_ID_SERVERWORKS)
return 0;
for (d = serverworks_chipsets; d && d->vendor && d->device; ++d) {
if (((d->vendor == dev->vendor) &&
(d->device == dev->device)) &&
(d->init_setup)) {
d->init_setup(dev, d);
return 1;
}
}
return 0;
}
#ifndef SERVERWORKS_H
#define SERVERWORKS_H
#include <linux/config.h>
#include <linux/pci.h>
#include <linux/ide.h>
#undef SVWKS_DEBUG_DRIVE_INFO
#define SVWKS_CSB5_REVISION_NEW 0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */
#define SVWKS_CSB6_REVISION 0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */
#define DISPLAY_SVWKS_TIMINGS 1
#if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
#include <linux/stat.h>
#include <linux/proc_fs.h>
static u8 svwks_proc;
static int svwks_get_info(char *, char **, off_t, int);
static ide_pci_host_proc_t svwks_procs[] __initdata = {
{
name: "svwks",
set: 1,
get_info: svwks_get_info,
parent: NULL,
},
};
#endif /* defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS) */
static void init_setup_svwks(struct pci_dev *, ide_pci_device_t *);
static void init_setup_csb6(struct pci_dev *, ide_pci_device_t *);
static unsigned int init_chipset_svwks(struct pci_dev *, const char *);
static void init_hwif_svwks(ide_hwif_t *);
static void init_dma_svwks(ide_hwif_t *, unsigned long);
static ide_pci_device_t serverworks_chipsets[] __initdata = {
{
vendor: PCI_VENDOR_ID_SERVERWORKS,
device: PCI_DEVICE_ID_SERVERWORKS_OSB4IDE,
name: "SvrWks OSB4",
init_setup: init_setup_svwks,
init_chipset: init_chipset_svwks,
init_iops: NULL,
init_hwif: init_hwif_svwks,
init_dma: NULL,
channels: 2,
autodma: AUTODMA,
enablebits: {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
bootable: ON_BOARD,
extra: 0,
},{
vendor: PCI_VENDOR_ID_SERVERWORKS,
device: PCI_DEVICE_ID_SERVERWORKS_CSB5IDE,
name: "SvrWks CSB5",
init_setup: init_setup_svwks,
init_chipset: init_chipset_svwks,
init_iops: NULL,
init_hwif: init_hwif_svwks,
init_dma: init_dma_svwks,
channels: 2,
autodma: AUTODMA,
enablebits: {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
bootable: ON_BOARD,
extra: 0,
},{
vendor: PCI_VENDOR_ID_SERVERWORKS,
device: PCI_DEVICE_ID_SERVERWORKS_CSB6IDE,
name: "SvrWks CSB6",
init_setup: init_setup_csb6,
init_chipset: init_chipset_svwks,
init_iops: NULL,
init_hwif: init_hwif_svwks,
init_dma: init_dma_svwks,
channels: 2,
autodma: AUTODMA,
enablebits: {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
bootable: ON_BOARD,
extra: 0,
},{
vendor: PCI_VENDOR_ID_SERVERWORKS,
device: PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2,
name: "SvrWks CSB6",
init_setup: init_setup_csb6,
init_chipset: init_chipset_svwks,
init_iops: NULL,
init_hwif: init_hwif_svwks,
init_dma: init_dma_svwks,
channels: 1, /* 2 */
autodma: AUTODMA,
enablebits: {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
bootable: ON_BOARD,
extra: 0,
},{
vendor: 0,
device: 0,
channels: 0,
bootable: EOL,
}
};
#endif /* SERVERWORKS_H */
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