| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2 | * Copyright (C) 1998-2000 Michel Aubry | 
|  | 3 | * Copyright (C) 1998-2000 Andrzej Krzysztofowicz | 
|  | 4 | * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org> | 
| Bartlomiej Zolnierkiewicz | 9445de7 | 2007-05-16 00:51:42 +0200 | [diff] [blame] | 5 | * Copyright (C)      2007 Bartlomiej Zolnierkiewicz | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6 | * Portions copyright (c) 2001 Sun Microsystems | 
|  | 7 | * | 
|  | 8 | * | 
|  | 9 | * RCC/ServerWorks IDE driver for Linux | 
|  | 10 | * | 
|  | 11 | *   OSB4: `Open South Bridge' IDE Interface (fn 1) | 
|  | 12 | *         supports UDMA mode 2 (33 MB/s) | 
|  | 13 | * | 
|  | 14 | *   CSB5: `Champion South Bridge' IDE Interface (fn 1) | 
|  | 15 | *         all revisions support UDMA mode 4 (66 MB/s) | 
|  | 16 | *         revision A2.0 and up support UDMA mode 5 (100 MB/s) | 
|  | 17 | * | 
|  | 18 | *         *** The CSB5 does not provide ANY register *** | 
|  | 19 | *         *** to detect 80-conductor cable presence. *** | 
|  | 20 | * | 
|  | 21 | *   CSB6: `Champion South Bridge' IDE Interface (optional: third channel) | 
|  | 22 | * | 
| Narendra Sankar | 84f57fb | 2005-08-18 22:30:35 +0200 | [diff] [blame] | 23 | *   HT1000: AKA BCM5785 - Hypertransport Southbridge for Opteron systems. IDE | 
|  | 24 | *   controller same as the CSB6. Single channel ATA100 only. | 
|  | 25 | * | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 26 | * Documentation: | 
|  | 27 | *	Available under NDA only. Errata info very hard to get. | 
|  | 28 | * | 
|  | 29 | */ | 
|  | 30 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 31 | #include <linux/types.h> | 
|  | 32 | #include <linux/module.h> | 
|  | 33 | #include <linux/kernel.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 34 | #include <linux/pci.h> | 
|  | 35 | #include <linux/hdreg.h> | 
|  | 36 | #include <linux/ide.h> | 
|  | 37 | #include <linux/init.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 38 |  | 
|  | 39 | #include <asm/io.h> | 
|  | 40 |  | 
|  | 41 | #define SVWKS_CSB5_REVISION_NEW	0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */ | 
|  | 42 | #define SVWKS_CSB6_REVISION	0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */ | 
|  | 43 |  | 
|  | 44 | /* Seagate Barracuda ATA IV Family drives in UDMA mode 5 | 
|  | 45 | * can overrun their FIFOs when used with the CSB5 */ | 
|  | 46 | static const char *svwks_bad_ata100[] = { | 
|  | 47 | "ST320011A", | 
|  | 48 | "ST340016A", | 
|  | 49 | "ST360021A", | 
|  | 50 | "ST380021A", | 
|  | 51 | NULL | 
|  | 52 | }; | 
|  | 53 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 54 | static struct pci_dev *isa_dev; | 
|  | 55 |  | 
|  | 56 | static int check_in_drive_lists (ide_drive_t *drive, const char **list) | 
|  | 57 | { | 
|  | 58 | while (*list) | 
|  | 59 | if (!strcmp(*list++, drive->id->model)) | 
|  | 60 | return 1; | 
|  | 61 | return 0; | 
|  | 62 | } | 
|  | 63 |  | 
| Bartlomiej Zolnierkiewicz | 2d5eaa6 | 2007-05-10 00:01:08 +0200 | [diff] [blame] | 64 | static u8 svwks_udma_filter(ide_drive_t *drive) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 65 | { | 
| Bartlomiej Zolnierkiewicz | 3650165 | 2008-02-01 23:09:31 +0100 | [diff] [blame] | 66 | struct pci_dev *dev = to_pci_dev(drive->hwif->dev); | 
| Bartlomiej Zolnierkiewicz | 2d5eaa6 | 2007-05-10 00:01:08 +0200 | [diff] [blame] | 67 | u8 mask = 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 68 |  | 
| Narendra Sankar | 84f57fb | 2005-08-18 22:30:35 +0200 | [diff] [blame] | 69 | if (dev->device == PCI_DEVICE_ID_SERVERWORKS_HT1000IDE) | 
| Bartlomiej Zolnierkiewicz | 2d5eaa6 | 2007-05-10 00:01:08 +0200 | [diff] [blame] | 70 | return 0x1f; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 71 | if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) { | 
|  | 72 | u32 reg = 0; | 
|  | 73 | if (isa_dev) | 
|  | 74 | pci_read_config_dword(isa_dev, 0x64, ®); | 
|  | 75 |  | 
|  | 76 | /* | 
|  | 77 | *	Don't enable UDMA on disk devices for the moment | 
|  | 78 | */ | 
|  | 79 | if(drive->media == ide_disk) | 
|  | 80 | return 0; | 
|  | 81 | /* Check the OSB4 DMA33 enable bit */ | 
| Bartlomiej Zolnierkiewicz | 2d5eaa6 | 2007-05-10 00:01:08 +0200 | [diff] [blame] | 82 | return ((reg & 0x00004000) == 0x00004000) ? 0x07 : 0; | 
| Auke Kok | 44c1013 | 2007-06-08 15:46:36 -0700 | [diff] [blame] | 83 | } else if (dev->revision < SVWKS_CSB5_REVISION_NEW) { | 
| Bartlomiej Zolnierkiewicz | 2d5eaa6 | 2007-05-10 00:01:08 +0200 | [diff] [blame] | 84 | return 0x07; | 
| Auke Kok | 44c1013 | 2007-06-08 15:46:36 -0700 | [diff] [blame] | 85 | } else if (dev->revision >= SVWKS_CSB5_REVISION_NEW) { | 
| Bartlomiej Zolnierkiewicz | 2d5eaa6 | 2007-05-10 00:01:08 +0200 | [diff] [blame] | 86 | u8 btr = 0, mode; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 87 | pci_read_config_byte(dev, 0x5A, &btr); | 
|  | 88 | mode = btr & 0x3; | 
| Bartlomiej Zolnierkiewicz | 2d5eaa6 | 2007-05-10 00:01:08 +0200 | [diff] [blame] | 89 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 90 | /* If someone decides to do UDMA133 on CSB5 the same | 
|  | 91 | issue will bite so be inclusive */ | 
|  | 92 | if (mode > 2 && check_in_drive_lists(drive, svwks_bad_ata100)) | 
|  | 93 | mode = 2; | 
| Bartlomiej Zolnierkiewicz | 2d5eaa6 | 2007-05-10 00:01:08 +0200 | [diff] [blame] | 94 |  | 
|  | 95 | switch(mode) { | 
| Tony Battersby | 0c824b5 | 2007-10-16 22:29:52 +0200 | [diff] [blame] | 96 | case 3:	 mask = 0x3f; break; | 
| Bartlomiej Zolnierkiewicz | 2d5eaa6 | 2007-05-10 00:01:08 +0200 | [diff] [blame] | 97 | case 2:	 mask = 0x1f; break; | 
|  | 98 | case 1:	 mask = 0x07; break; | 
|  | 99 | default: mask = 0x00; break; | 
|  | 100 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 101 | } | 
|  | 102 | if (((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) || | 
|  | 103 | (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) && | 
|  | 104 | (!(PCI_FUNC(dev->devfn) & 1))) | 
| Bartlomiej Zolnierkiewicz | 2d5eaa6 | 2007-05-10 00:01:08 +0200 | [diff] [blame] | 105 | mask = 0x1f; | 
|  | 106 |  | 
|  | 107 | return mask; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 108 | } | 
|  | 109 |  | 
|  | 110 | static u8 svwks_csb_check (struct pci_dev *dev) | 
|  | 111 | { | 
|  | 112 | switch (dev->device) { | 
|  | 113 | case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE: | 
|  | 114 | case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE: | 
|  | 115 | case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2: | 
| Narendra Sankar | 84f57fb | 2005-08-18 22:30:35 +0200 | [diff] [blame] | 116 | case PCI_DEVICE_ID_SERVERWORKS_HT1000IDE: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 117 | return 1; | 
|  | 118 | default: | 
|  | 119 | break; | 
|  | 120 | } | 
|  | 121 | return 0; | 
|  | 122 | } | 
| Bartlomiej Zolnierkiewicz | 1880a8d | 2007-07-20 01:11:56 +0200 | [diff] [blame] | 123 |  | 
| Bartlomiej Zolnierkiewicz | 88b2b32 | 2007-10-13 17:47:51 +0200 | [diff] [blame] | 124 | static void svwks_set_pio_mode(ide_drive_t *drive, const u8 pio) | 
| Bartlomiej Zolnierkiewicz | 1880a8d | 2007-07-20 01:11:56 +0200 | [diff] [blame] | 125 | { | 
|  | 126 | static const u8 pio_modes[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 }; | 
|  | 127 | static const u8 drive_pci[] = { 0x41, 0x40, 0x43, 0x42 }; | 
|  | 128 |  | 
| Bartlomiej Zolnierkiewicz | 3650165 | 2008-02-01 23:09:31 +0100 | [diff] [blame] | 129 | struct pci_dev *dev = to_pci_dev(drive->hwif->dev); | 
| Bartlomiej Zolnierkiewicz | 1880a8d | 2007-07-20 01:11:56 +0200 | [diff] [blame] | 130 |  | 
|  | 131 | pci_write_config_byte(dev, drive_pci[drive->dn], pio_modes[pio]); | 
|  | 132 |  | 
|  | 133 | if (svwks_csb_check(dev)) { | 
|  | 134 | u16 csb_pio = 0; | 
|  | 135 |  | 
|  | 136 | pci_read_config_word(dev, 0x4a, &csb_pio); | 
|  | 137 |  | 
|  | 138 | csb_pio &= ~(0x0f << (4 * drive->dn)); | 
|  | 139 | csb_pio |= (pio << (4 * drive->dn)); | 
|  | 140 |  | 
|  | 141 | pci_write_config_word(dev, 0x4a, csb_pio); | 
|  | 142 | } | 
|  | 143 | } | 
|  | 144 |  | 
| Bartlomiej Zolnierkiewicz | 88b2b32 | 2007-10-13 17:47:51 +0200 | [diff] [blame] | 145 | static void svwks_set_dma_mode(ide_drive_t *drive, const u8 speed) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 146 | { | 
| Alan Cox | f201f50 | 2006-06-28 04:27:02 -0700 | [diff] [blame] | 147 | static const u8 udma_modes[]		= { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 }; | 
|  | 148 | static const u8 dma_modes[]		= { 0x77, 0x21, 0x20 }; | 
| Alan Cox | f201f50 | 2006-06-28 04:27:02 -0700 | [diff] [blame] | 149 | static const u8 drive_pci2[]		= { 0x45, 0x44, 0x47, 0x46 }; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 150 |  | 
|  | 151 | ide_hwif_t *hwif	= HWIF(drive); | 
| Bartlomiej Zolnierkiewicz | 3650165 | 2008-02-01 23:09:31 +0100 | [diff] [blame] | 152 | struct pci_dev *dev	= to_pci_dev(hwif->dev); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 153 | u8 unit			= (drive->select.b.unit & 0x01); | 
| Bartlomiej Zolnierkiewicz | 1880a8d | 2007-07-20 01:11:56 +0200 | [diff] [blame] | 154 |  | 
|  | 155 | u8 ultra_enable	 = 0, ultra_timing = 0, dma_timing = 0; | 
|  | 156 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 157 | pci_read_config_byte(dev, (0x56|hwif->channel), &ultra_timing); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 158 | pci_read_config_byte(dev, 0x54, &ultra_enable); | 
|  | 159 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 160 | ultra_timing	&= ~(0x0F << (4*unit)); | 
|  | 161 | ultra_enable	&= ~(0x01 << drive->dn); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 162 |  | 
| Bartlomiej Zolnierkiewicz | 7b971df | 2008-01-26 20:12:59 +0100 | [diff] [blame] | 163 | if (speed >= XFER_UDMA_0) { | 
|  | 164 | dma_timing   |= dma_modes[2]; | 
|  | 165 | ultra_timing |= (udma_modes[speed - XFER_UDMA_0] << (4 * unit)); | 
|  | 166 | ultra_enable |= (0x01 << drive->dn); | 
|  | 167 | } else if (speed >= XFER_MW_DMA_0) | 
|  | 168 | dma_timing   |= dma_modes[speed - XFER_MW_DMA_0]; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 169 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 170 | pci_write_config_byte(dev, drive_pci2[drive->dn], dma_timing); | 
|  | 171 | pci_write_config_byte(dev, (0x56|hwif->channel), ultra_timing); | 
|  | 172 | pci_write_config_byte(dev, 0x54, ultra_enable); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 173 | } | 
|  | 174 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 175 | static unsigned int __devinit init_chipset_svwks (struct pci_dev *dev, const char *name) | 
|  | 176 | { | 
|  | 177 | unsigned int reg; | 
|  | 178 | u8 btr; | 
|  | 179 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 180 | /* force Master Latency Timer value to 64 PCICLKs */ | 
|  | 181 | pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40); | 
|  | 182 |  | 
|  | 183 | /* OSB4 : South Bridge and IDE */ | 
|  | 184 | if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) { | 
| Alan Cox | 970a613 | 2006-09-30 23:27:29 -0700 | [diff] [blame] | 185 | isa_dev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 186 | PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL); | 
|  | 187 | if (isa_dev) { | 
|  | 188 | pci_read_config_dword(isa_dev, 0x64, ®); | 
|  | 189 | reg &= ~0x00002000; /* disable 600ns interrupt mask */ | 
|  | 190 | if(!(reg & 0x00004000)) | 
|  | 191 | printk(KERN_DEBUG "%s: UDMA not BIOS enabled.\n", name); | 
|  | 192 | reg |=  0x00004000; /* enable UDMA/33 support */ | 
|  | 193 | pci_write_config_dword(isa_dev, 0x64, reg); | 
|  | 194 | } | 
|  | 195 | } | 
|  | 196 |  | 
|  | 197 | /* setup CSB5/CSB6 : South Bridge and IDE option RAID */ | 
|  | 198 | else if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) || | 
|  | 199 | (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) || | 
|  | 200 | (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) { | 
|  | 201 |  | 
|  | 202 | /* Third Channel Test */ | 
|  | 203 | if (!(PCI_FUNC(dev->devfn) & 1)) { | 
|  | 204 | struct pci_dev * findev = NULL; | 
|  | 205 | u32 reg4c = 0; | 
| Alan Cox | 970a613 | 2006-09-30 23:27:29 -0700 | [diff] [blame] | 206 | findev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 207 | PCI_DEVICE_ID_SERVERWORKS_CSB5, NULL); | 
|  | 208 | if (findev) { | 
|  | 209 | pci_read_config_dword(findev, 0x4C, ®4c); | 
|  | 210 | reg4c &= ~0x000007FF; | 
|  | 211 | reg4c |=  0x00000040; | 
|  | 212 | reg4c |=  0x00000020; | 
|  | 213 | pci_write_config_dword(findev, 0x4C, reg4c); | 
| Alan Cox | 970a613 | 2006-09-30 23:27:29 -0700 | [diff] [blame] | 214 | pci_dev_put(findev); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 215 | } | 
|  | 216 | outb_p(0x06, 0x0c00); | 
|  | 217 | dev->irq = inb_p(0x0c01); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 218 | } else { | 
|  | 219 | struct pci_dev * findev = NULL; | 
|  | 220 | u8 reg41 = 0; | 
|  | 221 |  | 
| Alan Cox | 970a613 | 2006-09-30 23:27:29 -0700 | [diff] [blame] | 222 | findev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 223 | PCI_DEVICE_ID_SERVERWORKS_CSB6, NULL); | 
|  | 224 | if (findev) { | 
|  | 225 | pci_read_config_byte(findev, 0x41, ®41); | 
|  | 226 | reg41 &= ~0x40; | 
|  | 227 | pci_write_config_byte(findev, 0x41, reg41); | 
| Alan Cox | 970a613 | 2006-09-30 23:27:29 -0700 | [diff] [blame] | 228 | pci_dev_put(findev); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 229 | } | 
|  | 230 | /* | 
|  | 231 | * This is a device pin issue on CSB6. | 
|  | 232 | * Since there will be a future raid mode, | 
|  | 233 | * early versions of the chipset require the | 
|  | 234 | * interrupt pin to be set, and it is a compatibility | 
|  | 235 | * mode issue. | 
|  | 236 | */ | 
|  | 237 | if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE) | 
|  | 238 | dev->irq = 0; | 
|  | 239 | } | 
|  | 240 | //		pci_read_config_dword(dev, 0x40, &pioreg) | 
|  | 241 | //		pci_write_config_dword(dev, 0x40, 0x99999999); | 
|  | 242 | //		pci_read_config_dword(dev, 0x44, &dmareg); | 
|  | 243 | //		pci_write_config_dword(dev, 0x44, 0xFFFFFFFF); | 
|  | 244 | /* setup the UDMA Control register | 
|  | 245 | * | 
|  | 246 | * 1. clear bit 6 to enable DMA | 
|  | 247 | * 2. enable DMA modes with bits 0-1 | 
|  | 248 | * 	00 : legacy | 
|  | 249 | * 	01 : udma2 | 
|  | 250 | * 	10 : udma2/udma4 | 
|  | 251 | * 	11 : udma2/udma4/udma5 | 
|  | 252 | */ | 
|  | 253 | pci_read_config_byte(dev, 0x5A, &btr); | 
|  | 254 | btr &= ~0x40; | 
|  | 255 | if (!(PCI_FUNC(dev->devfn) & 1)) | 
|  | 256 | btr |= 0x2; | 
|  | 257 | else | 
| Auke Kok | 44c1013 | 2007-06-08 15:46:36 -0700 | [diff] [blame] | 258 | btr |= (dev->revision >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 259 | pci_write_config_byte(dev, 0x5A, btr); | 
|  | 260 | } | 
| Narendra Sankar | 84f57fb | 2005-08-18 22:30:35 +0200 | [diff] [blame] | 261 | /* Setup HT1000 SouthBridge Controller - Single Channel Only */ | 
|  | 262 | else if (dev->device == PCI_DEVICE_ID_SERVERWORKS_HT1000IDE) { | 
|  | 263 | pci_read_config_byte(dev, 0x5A, &btr); | 
|  | 264 | btr &= ~0x40; | 
|  | 265 | btr |= 0x3; | 
|  | 266 | pci_write_config_byte(dev, 0x5A, btr); | 
|  | 267 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 268 |  | 
| Alan Cox | f201f50 | 2006-06-28 04:27:02 -0700 | [diff] [blame] | 269 | return dev->irq; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 270 | } | 
|  | 271 |  | 
| Bartlomiej Zolnierkiewicz | 49521f9 | 2007-07-09 23:17:58 +0200 | [diff] [blame] | 272 | static u8 __devinit ata66_svwks_svwks(ide_hwif_t *hwif) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 273 | { | 
| Bartlomiej Zolnierkiewicz | 49521f9 | 2007-07-09 23:17:58 +0200 | [diff] [blame] | 274 | return ATA_CBL_PATA80; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 275 | } | 
|  | 276 |  | 
|  | 277 | /* On Dell PowerEdge servers with a CSB5/CSB6, the top two bits | 
|  | 278 | * of the subsystem device ID indicate presence of an 80-pin cable. | 
|  | 279 | * Bit 15 clear = secondary IDE channel does not have 80-pin cable. | 
|  | 280 | * Bit 15 set   = secondary IDE channel has 80-pin cable. | 
|  | 281 | * Bit 14 clear = primary IDE channel does not have 80-pin cable. | 
|  | 282 | * Bit 14 set   = primary IDE channel has 80-pin cable. | 
|  | 283 | */ | 
| Bartlomiej Zolnierkiewicz | 49521f9 | 2007-07-09 23:17:58 +0200 | [diff] [blame] | 284 | static u8 __devinit ata66_svwks_dell(ide_hwif_t *hwif) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 285 | { | 
| Bartlomiej Zolnierkiewicz | 3650165 | 2008-02-01 23:09:31 +0100 | [diff] [blame] | 286 | struct pci_dev *dev = to_pci_dev(hwif->dev); | 
|  | 287 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 288 | if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL && | 
|  | 289 | dev->vendor	== PCI_VENDOR_ID_SERVERWORKS && | 
|  | 290 | (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE || | 
|  | 291 | dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE)) | 
|  | 292 | return ((1 << (hwif->channel + 14)) & | 
| Bartlomiej Zolnierkiewicz | 49521f9 | 2007-07-09 23:17:58 +0200 | [diff] [blame] | 293 | dev->subsystem_device) ? ATA_CBL_PATA80 : ATA_CBL_PATA40; | 
|  | 294 | return ATA_CBL_PATA40; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 295 | } | 
|  | 296 |  | 
|  | 297 | /* Sun Cobalt Alpine hardware avoids the 80-pin cable | 
|  | 298 | * detect issue by attaching the drives directly to the board. | 
|  | 299 | * This check follows the Dell precedent (how scary is that?!) | 
|  | 300 | * | 
|  | 301 | * WARNING: this only works on Alpine hardware! | 
|  | 302 | */ | 
| Bartlomiej Zolnierkiewicz | 49521f9 | 2007-07-09 23:17:58 +0200 | [diff] [blame] | 303 | static u8 __devinit ata66_svwks_cobalt(ide_hwif_t *hwif) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 304 | { | 
| Bartlomiej Zolnierkiewicz | 3650165 | 2008-02-01 23:09:31 +0100 | [diff] [blame] | 305 | struct pci_dev *dev = to_pci_dev(hwif->dev); | 
|  | 306 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 307 | if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN && | 
|  | 308 | dev->vendor	== PCI_VENDOR_ID_SERVERWORKS && | 
|  | 309 | dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) | 
|  | 310 | return ((1 << (hwif->channel + 14)) & | 
| Bartlomiej Zolnierkiewicz | 49521f9 | 2007-07-09 23:17:58 +0200 | [diff] [blame] | 311 | dev->subsystem_device) ? ATA_CBL_PATA80 : ATA_CBL_PATA40; | 
|  | 312 | return ATA_CBL_PATA40; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 313 | } | 
|  | 314 |  | 
| Bartlomiej Zolnierkiewicz | 49521f9 | 2007-07-09 23:17:58 +0200 | [diff] [blame] | 315 | static u8 __devinit ata66_svwks(ide_hwif_t *hwif) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 316 | { | 
| Bartlomiej Zolnierkiewicz | 3650165 | 2008-02-01 23:09:31 +0100 | [diff] [blame] | 317 | struct pci_dev *dev = to_pci_dev(hwif->dev); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 318 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 319 | /* Server Works */ | 
|  | 320 | if (dev->subsystem_vendor == PCI_VENDOR_ID_SERVERWORKS) | 
|  | 321 | return ata66_svwks_svwks (hwif); | 
|  | 322 |  | 
|  | 323 | /* Dell PowerEdge */ | 
|  | 324 | if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL) | 
|  | 325 | return ata66_svwks_dell (hwif); | 
|  | 326 |  | 
|  | 327 | /* Cobalt Alpine */ | 
|  | 328 | if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN) | 
|  | 329 | return ata66_svwks_cobalt (hwif); | 
|  | 330 |  | 
| Alan Cox | f201f50 | 2006-06-28 04:27:02 -0700 | [diff] [blame] | 331 | /* Per Specified Design by OEM, and ASIC Architect */ | 
|  | 332 | if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) || | 
|  | 333 | (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) | 
| Bartlomiej Zolnierkiewicz | 49521f9 | 2007-07-09 23:17:58 +0200 | [diff] [blame] | 334 | return ATA_CBL_PATA80; | 
| Alan Cox | f201f50 | 2006-06-28 04:27:02 -0700 | [diff] [blame] | 335 |  | 
| Bartlomiej Zolnierkiewicz | 49521f9 | 2007-07-09 23:17:58 +0200 | [diff] [blame] | 336 | return ATA_CBL_PATA40; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 337 | } | 
|  | 338 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 339 | static void __devinit init_hwif_svwks (ide_hwif_t *hwif) | 
|  | 340 | { | 
| Bartlomiej Zolnierkiewicz | 3650165 | 2008-02-01 23:09:31 +0100 | [diff] [blame] | 341 | struct pci_dev *dev = to_pci_dev(hwif->dev); | 
|  | 342 |  | 
| Bartlomiej Zolnierkiewicz | 26bcb87 | 2007-10-11 23:54:00 +0200 | [diff] [blame] | 343 | hwif->set_pio_mode = &svwks_set_pio_mode; | 
| Bartlomiej Zolnierkiewicz | 88b2b32 | 2007-10-13 17:47:51 +0200 | [diff] [blame] | 344 | hwif->set_dma_mode = &svwks_set_dma_mode; | 
| Bartlomiej Zolnierkiewicz | 2d5eaa6 | 2007-05-10 00:01:08 +0200 | [diff] [blame] | 345 | hwif->udma_filter = &svwks_udma_filter; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 346 |  | 
| Bartlomiej Zolnierkiewicz | bfa14b4 | 2008-02-02 19:56:31 +0100 | [diff] [blame] | 347 | if (dev->device != PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) | 
|  | 348 | hwif->cable_detect = ata66_svwks; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 349 | } | 
|  | 350 |  | 
| Bartlomiej Zolnierkiewicz | 4db90a1 | 2008-01-25 22:17:18 +0100 | [diff] [blame] | 351 | #define IDE_HFLAGS_SVWKS \ | 
|  | 352 | (IDE_HFLAG_LEGACY_IRQS | \ | 
|  | 353 | IDE_HFLAG_ABUSE_SET_DMA_MODE | \ | 
|  | 354 | IDE_HFLAG_BOOTABLE) | 
|  | 355 |  | 
| Bartlomiej Zolnierkiewicz | 8562043 | 2007-10-20 00:32:34 +0200 | [diff] [blame] | 356 | static const struct ide_port_info serverworks_chipsets[] __devinitdata = { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 357 | {	/* 0 */ | 
|  | 358 | .name		= "SvrWks OSB4", | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 359 | .init_chipset	= init_chipset_svwks, | 
|  | 360 | .init_hwif	= init_hwif_svwks, | 
| Bartlomiej Zolnierkiewicz | 4db90a1 | 2008-01-25 22:17:18 +0100 | [diff] [blame] | 361 | .host_flags	= IDE_HFLAGS_SVWKS, | 
| Bartlomiej Zolnierkiewicz | 4099d14 | 2007-07-20 01:11:59 +0200 | [diff] [blame] | 362 | .pio_mask	= ATA_PIO4, | 
| Bartlomiej Zolnierkiewicz | 5f8b6c3 | 2007-10-19 00:30:07 +0200 | [diff] [blame] | 363 | .mwdma_mask	= ATA_MWDMA2, | 
|  | 364 | .udma_mask	= 0x00, /* UDMA is problematic on OSB4 */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 365 | },{	/* 1 */ | 
|  | 366 | .name		= "SvrWks CSB5", | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 367 | .init_chipset	= init_chipset_svwks, | 
|  | 368 | .init_hwif	= init_hwif_svwks, | 
| Bartlomiej Zolnierkiewicz | 4db90a1 | 2008-01-25 22:17:18 +0100 | [diff] [blame] | 369 | .host_flags	= IDE_HFLAGS_SVWKS, | 
| Bartlomiej Zolnierkiewicz | 4099d14 | 2007-07-20 01:11:59 +0200 | [diff] [blame] | 370 | .pio_mask	= ATA_PIO4, | 
| Bartlomiej Zolnierkiewicz | 5f8b6c3 | 2007-10-19 00:30:07 +0200 | [diff] [blame] | 371 | .mwdma_mask	= ATA_MWDMA2, | 
|  | 372 | .udma_mask	= ATA_UDMA5, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 373 | },{	/* 2 */ | 
|  | 374 | .name		= "SvrWks CSB6", | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 375 | .init_chipset	= init_chipset_svwks, | 
|  | 376 | .init_hwif	= init_hwif_svwks, | 
| Bartlomiej Zolnierkiewicz | 4db90a1 | 2008-01-25 22:17:18 +0100 | [diff] [blame] | 377 | .host_flags	= IDE_HFLAGS_SVWKS, | 
| Bartlomiej Zolnierkiewicz | 4099d14 | 2007-07-20 01:11:59 +0200 | [diff] [blame] | 378 | .pio_mask	= ATA_PIO4, | 
| Bartlomiej Zolnierkiewicz | 5f8b6c3 | 2007-10-19 00:30:07 +0200 | [diff] [blame] | 379 | .mwdma_mask	= ATA_MWDMA2, | 
|  | 380 | .udma_mask	= ATA_UDMA5, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 381 | },{	/* 3 */ | 
|  | 382 | .name		= "SvrWks CSB6", | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 383 | .init_chipset	= init_chipset_svwks, | 
|  | 384 | .init_hwif	= init_hwif_svwks, | 
| Bartlomiej Zolnierkiewicz | 4db90a1 | 2008-01-25 22:17:18 +0100 | [diff] [blame] | 385 | .host_flags	= IDE_HFLAGS_SVWKS | IDE_HFLAG_SINGLE, | 
| Bartlomiej Zolnierkiewicz | 4099d14 | 2007-07-20 01:11:59 +0200 | [diff] [blame] | 386 | .pio_mask	= ATA_PIO4, | 
| Bartlomiej Zolnierkiewicz | 5f8b6c3 | 2007-10-19 00:30:07 +0200 | [diff] [blame] | 387 | .mwdma_mask	= ATA_MWDMA2, | 
|  | 388 | .udma_mask	= ATA_UDMA5, | 
| Narendra Sankar | 84f57fb | 2005-08-18 22:30:35 +0200 | [diff] [blame] | 389 | },{	/* 4 */ | 
|  | 390 | .name		= "SvrWks HT1000", | 
| Narendra Sankar | 84f57fb | 2005-08-18 22:30:35 +0200 | [diff] [blame] | 391 | .init_chipset	= init_chipset_svwks, | 
|  | 392 | .init_hwif	= init_hwif_svwks, | 
| Bartlomiej Zolnierkiewicz | 4db90a1 | 2008-01-25 22:17:18 +0100 | [diff] [blame] | 393 | .host_flags	= IDE_HFLAGS_SVWKS | IDE_HFLAG_SINGLE, | 
| Bartlomiej Zolnierkiewicz | 4099d14 | 2007-07-20 01:11:59 +0200 | [diff] [blame] | 394 | .pio_mask	= ATA_PIO4, | 
| Bartlomiej Zolnierkiewicz | 5f8b6c3 | 2007-10-19 00:30:07 +0200 | [diff] [blame] | 395 | .mwdma_mask	= ATA_MWDMA2, | 
|  | 396 | .udma_mask	= ATA_UDMA5, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 397 | } | 
|  | 398 | }; | 
|  | 399 |  | 
|  | 400 | /** | 
|  | 401 | *	svwks_init_one	-	called when a OSB/CSB is found | 
|  | 402 | *	@dev: the svwks device | 
|  | 403 | *	@id: the matching pci id | 
|  | 404 | * | 
|  | 405 | *	Called when the PCI registration layer (or the IDE initialization) | 
|  | 406 | *	finds a device matching our IDE device tables. | 
|  | 407 | */ | 
|  | 408 |  | 
|  | 409 | static int __devinit svwks_init_one(struct pci_dev *dev, const struct pci_device_id *id) | 
|  | 410 | { | 
| Bartlomiej Zolnierkiewicz | 039788e | 2007-10-20 00:32:34 +0200 | [diff] [blame] | 411 | struct ide_port_info d; | 
| Bartlomiej Zolnierkiewicz | 7ed5829 | 2007-10-19 00:30:09 +0200 | [diff] [blame] | 412 | u8 idx = id->driver_data; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 413 |  | 
| Bartlomiej Zolnierkiewicz | 7ed5829 | 2007-10-19 00:30:09 +0200 | [diff] [blame] | 414 | d = serverworks_chipsets[idx]; | 
|  | 415 |  | 
| Bartlomiej Zolnierkiewicz | 8ac2b42 | 2008-02-01 23:09:30 +0100 | [diff] [blame] | 416 | if (idx == 1) | 
|  | 417 | d.host_flags |= IDE_HFLAG_CLEAR_SIMPLEX; | 
|  | 418 | else if (idx == 2 || idx == 3) { | 
| Bartlomiej Zolnierkiewicz | 7ed5829 | 2007-10-19 00:30:09 +0200 | [diff] [blame] | 419 | if ((PCI_FUNC(dev->devfn) & 1) == 0) { | 
|  | 420 | if (pci_resource_start(dev, 0) != 0x01f1) | 
|  | 421 | d.host_flags &= ~IDE_HFLAG_BOOTABLE; | 
|  | 422 | d.host_flags |= IDE_HFLAG_SINGLE; | 
|  | 423 | } else | 
|  | 424 | d.host_flags &= ~IDE_HFLAG_SINGLE; | 
|  | 425 | } | 
|  | 426 |  | 
|  | 427 | return ide_setup_pci_device(dev, &d); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 428 | } | 
|  | 429 |  | 
| Bartlomiej Zolnierkiewicz | 9cbcc5e | 2007-10-16 22:29:56 +0200 | [diff] [blame] | 430 | static const struct pci_device_id svwks_pci_tbl[] = { | 
|  | 431 | { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE),   0 }, | 
|  | 432 | { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE),   1 }, | 
|  | 433 | { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE),   2 }, | 
|  | 434 | { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2),  3 }, | 
|  | 435 | { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000IDE), 4 }, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 436 | { 0, }, | 
|  | 437 | }; | 
|  | 438 | MODULE_DEVICE_TABLE(pci, svwks_pci_tbl); | 
|  | 439 |  | 
|  | 440 | static struct pci_driver driver = { | 
|  | 441 | .name		= "Serverworks_IDE", | 
|  | 442 | .id_table	= svwks_pci_tbl, | 
|  | 443 | .probe		= svwks_init_one, | 
|  | 444 | }; | 
|  | 445 |  | 
| Bartlomiej Zolnierkiewicz | 82ab1ee | 2007-01-27 13:46:56 +0100 | [diff] [blame] | 446 | static int __init svwks_ide_init(void) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 447 | { | 
|  | 448 | return ide_pci_register_driver(&driver); | 
|  | 449 | } | 
|  | 450 |  | 
|  | 451 | module_init(svwks_ide_init); | 
|  | 452 |  | 
|  | 453 | MODULE_AUTHOR("Michael Aubry. Andrzej Krzysztofowicz, Andre Hedrick"); | 
|  | 454 | MODULE_DESCRIPTION("PCI driver module for Serverworks OSB4/CSB5/CSB6 IDE"); | 
|  | 455 | MODULE_LICENSE("GPL"); |