diff options
author | Jeff Garzik <jeff@garzik.org> | 2006-08-29 18:12:40 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-08-29 18:12:40 -0400 |
commit | 669a5db411d85a14f86cd92bc16bf7ab5b8aa235 (patch) | |
tree | 8d4f9d63e18185695a4d97e1a3fa4e18b61c7345 /drivers/ata/pata_serverworks.c | |
parent | b01e86fee6c821e4e003fd4e9f65453ac478a58e (diff) |
[libata] Add a bunch of PATA drivers.
The vast majority of drivers and changes are from Alan Cox. Albert Lee
contributed and maintains pata_pdc2027x. Adrian Bunk, Andrew Morton,
and Tejun Heo contributed various minor fixes and updates.
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/ata/pata_serverworks.c')
-rw-r--r-- | drivers/ata/pata_serverworks.c | 587 |
1 files changed, 587 insertions, 0 deletions
diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c new file mode 100644 index 000000000000..3ec30036c978 --- /dev/null +++ b/drivers/ata/pata_serverworks.c | |||
@@ -0,0 +1,587 @@ | |||
1 | /* | ||
2 | * ata-serverworks.c - Serverworks PATA for new ATA layer | ||
3 | * (C) 2005 Red Hat Inc | ||
4 | * Alan Cox <alan@redhat.com> | ||
5 | * | ||
6 | * based upon | ||
7 | * | ||
8 | * serverworks.c | ||
9 | * | ||
10 | * Copyright (C) 1998-2000 Michel Aubry | ||
11 | * Copyright (C) 1998-2000 Andrzej Krzysztofowicz | ||
12 | * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org> | ||
13 | * Portions copyright (c) 2001 Sun Microsystems | ||
14 | * | ||
15 | * | ||
16 | * RCC/ServerWorks IDE driver for Linux | ||
17 | * | ||
18 | * OSB4: `Open South Bridge' IDE Interface (fn 1) | ||
19 | * supports UDMA mode 2 (33 MB/s) | ||
20 | * | ||
21 | * CSB5: `Champion South Bridge' IDE Interface (fn 1) | ||
22 | * all revisions support UDMA mode 4 (66 MB/s) | ||
23 | * revision A2.0 and up support UDMA mode 5 (100 MB/s) | ||
24 | * | ||
25 | * *** The CSB5 does not provide ANY register *** | ||
26 | * *** to detect 80-conductor cable presence. *** | ||
27 | * | ||
28 | * CSB6: `Champion South Bridge' IDE Interface (optional: third channel) | ||
29 | * | ||
30 | * Documentation: | ||
31 | * Available under NDA only. Errata info very hard to get. | ||
32 | */ | ||
33 | |||
34 | #include <linux/kernel.h> | ||
35 | #include <linux/module.h> | ||
36 | #include <linux/pci.h> | ||
37 | #include <linux/init.h> | ||
38 | #include <linux/blkdev.h> | ||
39 | #include <linux/delay.h> | ||
40 | #include <scsi/scsi_host.h> | ||
41 | #include <linux/libata.h> | ||
42 | |||
43 | #define DRV_NAME "pata_serverworks" | ||
44 | #define DRV_VERSION "0.3.6" | ||
45 | |||
46 | #define SVWKS_CSB5_REVISION_NEW 0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */ | ||
47 | #define SVWKS_CSB6_REVISION 0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */ | ||
48 | |||
49 | /* Seagate Barracuda ATA IV Family drives in UDMA mode 5 | ||
50 | * can overrun their FIFOs when used with the CSB5 */ | ||
51 | |||
52 | static const char *csb_bad_ata100[] = { | ||
53 | "ST320011A", | ||
54 | "ST340016A", | ||
55 | "ST360021A", | ||
56 | "ST380021A", | ||
57 | NULL | ||
58 | }; | ||
59 | |||
60 | /** | ||
61 | * dell_cable - Dell serverworks cable detection | ||
62 | * @ap: ATA port to do cable detect | ||
63 | * | ||
64 | * Dell hide the 40/80 pin select for their interfaces in the top two | ||
65 | * bits of the subsystem ID. | ||
66 | */ | ||
67 | |||
68 | static int dell_cable(struct ata_port *ap) { | ||
69 | struct pci_dev *pdev = to_pci_dev(ap->host->dev); | ||
70 | |||
71 | if (pdev->subsystem_device & (1 << (ap->port_no + 14))) | ||
72 | return ATA_CBL_PATA80; | ||
73 | return ATA_CBL_PATA40; | ||
74 | } | ||
75 | |||
76 | /** | ||
77 | * sun_cable - Sun Cobalt 'Alpine' cable detection | ||
78 | * @ap: ATA port to do cable select | ||
79 | * | ||
80 | * Cobalt CSB5 IDE hides the 40/80pin in the top two bits of the | ||
81 | * subsystem ID the same as dell. We could use one function but we may | ||
82 | * need to extend the Dell one in future | ||
83 | */ | ||
84 | |||
85 | static int sun_cable(struct ata_port *ap) { | ||
86 | struct pci_dev *pdev = to_pci_dev(ap->host->dev); | ||
87 | |||
88 | if (pdev->subsystem_device & (1 << (ap->port_no + 14))) | ||
89 | return ATA_CBL_PATA80; | ||
90 | return ATA_CBL_PATA40; | ||
91 | } | ||
92 | |||
93 | /** | ||
94 | * osb4_cable - OSB4 cable detect | ||
95 | * @ap: ATA port to check | ||
96 | * | ||
97 | * The OSB4 isn't UDMA66 capable so this is easy | ||
98 | */ | ||
99 | |||
100 | static int osb4_cable(struct ata_port *ap) { | ||
101 | return ATA_CBL_PATA40; | ||
102 | } | ||
103 | |||
104 | /** | ||
105 | * csb4_cable - CSB5/6 cable detect | ||
106 | * @ap: ATA port to check | ||
107 | * | ||
108 | * Serverworks default arrangement is to use the drive side detection | ||
109 | * only. | ||
110 | */ | ||
111 | |||
112 | static int csb_cable(struct ata_port *ap) { | ||
113 | return ATA_CBL_PATA80; | ||
114 | } | ||
115 | |||
116 | struct sv_cable_table { | ||
117 | int device; | ||
118 | int subvendor; | ||
119 | int (*cable_detect)(struct ata_port *ap); | ||
120 | }; | ||
121 | |||
122 | /* | ||
123 | * Note that we don't copy the old serverworks code because the old | ||
124 | * code contains obvious mistakes | ||
125 | */ | ||
126 | |||
127 | static struct sv_cable_table cable_detect[] = { | ||
128 | { PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_VENDOR_ID_DELL, dell_cable }, | ||
129 | { PCI_DEVICE_ID_SERVERWORKS_CSB6IDE, PCI_VENDOR_ID_DELL, dell_cable }, | ||
130 | { PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_VENDOR_ID_SUN, sun_cable }, | ||
131 | { PCI_DEVICE_ID_SERVERWORKS_OSB4, PCI_ANY_ID, osb4_cable }, | ||
132 | { PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_ANY_ID, csb_cable }, | ||
133 | { PCI_DEVICE_ID_SERVERWORKS_CSB6IDE, PCI_ANY_ID, csb_cable }, | ||
134 | { PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2, PCI_ANY_ID, csb_cable }, | ||
135 | { PCI_DEVICE_ID_SERVERWORKS_HT1000IDE, PCI_ANY_ID, csb_cable }, | ||
136 | { } | ||
137 | }; | ||
138 | |||
139 | /** | ||
140 | * serverworks_pre_reset - cable detection | ||
141 | * @ap: ATA port | ||
142 | * | ||
143 | * Perform cable detection according to the device and subvendor | ||
144 | * identifications | ||
145 | */ | ||
146 | |||
147 | static int serverworks_pre_reset(struct ata_port *ap) { | ||
148 | struct pci_dev *pdev = to_pci_dev(ap->host->dev); | ||
149 | struct sv_cable_table *cb = cable_detect; | ||
150 | |||
151 | while(cb->device) { | ||
152 | if (cb->device == pdev->device && | ||
153 | (cb->subvendor == pdev->subsystem_vendor || | ||
154 | cb->subvendor == PCI_ANY_ID)) { | ||
155 | ap->cbl = cb->cable_detect(ap); | ||
156 | return ata_std_prereset(ap); | ||
157 | } | ||
158 | cb++; | ||
159 | } | ||
160 | |||
161 | BUG(); | ||
162 | return -1; /* kill compiler warning */ | ||
163 | } | ||
164 | |||
165 | static void serverworks_error_handler(struct ata_port *ap) | ||
166 | { | ||
167 | return ata_bmdma_drive_eh(ap, serverworks_pre_reset, ata_std_softreset, NULL, ata_std_postreset); | ||
168 | } | ||
169 | |||
170 | /** | ||
171 | * serverworks_is_csb - Check for CSB or OSB | ||
172 | * @pdev: PCI device to check | ||
173 | * | ||
174 | * Returns true if the device being checked is known to be a CSB | ||
175 | * series device. | ||
176 | */ | ||
177 | |||
178 | static u8 serverworks_is_csb(struct pci_dev *pdev) | ||
179 | { | ||
180 | switch (pdev->device) { | ||
181 | case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE: | ||
182 | case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE: | ||
183 | case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2: | ||
184 | case PCI_DEVICE_ID_SERVERWORKS_HT1000IDE: | ||
185 | return 1; | ||
186 | default: | ||
187 | break; | ||
188 | } | ||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | /** | ||
193 | * serverworks_osb4_filter - mode selection filter | ||
194 | * @ap: ATA interface | ||
195 | * @adev: ATA device | ||
196 | * | ||
197 | * Filter the offered modes for the device to apply controller | ||
198 | * specific rules. OSB4 requires no UDMA for disks due to a FIFO | ||
199 | * bug we hit. | ||
200 | */ | ||
201 | |||
202 | static unsigned long serverworks_osb4_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask) | ||
203 | { | ||
204 | if (adev->class == ATA_DEV_ATA) | ||
205 | mask &= ~ATA_MASK_UDMA; | ||
206 | return ata_pci_default_filter(ap, adev, mask); | ||
207 | } | ||
208 | |||
209 | |||
210 | /** | ||
211 | * serverworks_csb_filter - mode selection filter | ||
212 | * @ap: ATA interface | ||
213 | * @adev: ATA device | ||
214 | * | ||
215 | * Check the blacklist and disable UDMA5 if matched | ||
216 | */ | ||
217 | |||
218 | static unsigned long serverworks_csb_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask) | ||
219 | { | ||
220 | const char *p; | ||
221 | char model_num[40]; | ||
222 | int len, i; | ||
223 | |||
224 | /* Disk, UDMA */ | ||
225 | if (adev->class != ATA_DEV_ATA) | ||
226 | return ata_pci_default_filter(ap, adev, mask); | ||
227 | |||
228 | /* Actually do need to check */ | ||
229 | ata_id_string(adev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num)); | ||
230 | /* Precuationary - why not do this in the libata core ?? */ | ||
231 | |||
232 | len = strlen(model_num); | ||
233 | while ((len > 0) && (model_num[len - 1] == ' ')) { | ||
234 | len--; | ||
235 | model_num[len] = 0; | ||
236 | } | ||
237 | |||
238 | for(i = 0; (p = csb_bad_ata100[i]) != NULL; i++) { | ||
239 | if (!strncmp(p, model_num, len)) | ||
240 | mask &= ~(0x1F << ATA_SHIFT_UDMA); | ||
241 | } | ||
242 | return ata_pci_default_filter(ap, adev, mask); | ||
243 | } | ||
244 | |||
245 | |||
246 | /** | ||
247 | * serverworks_set_piomode - set initial PIO mode data | ||
248 | * @ap: ATA interface | ||
249 | * @adev: ATA device | ||
250 | * | ||
251 | * Program the OSB4/CSB5 timing registers for PIO. The PIO register | ||
252 | * load is done as a simple lookup. | ||
253 | */ | ||
254 | static void serverworks_set_piomode(struct ata_port *ap, struct ata_device *adev) | ||
255 | { | ||
256 | static const u8 pio_mode[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 }; | ||
257 | int offset = 1 + (2 * ap->port_no) - adev->devno; | ||
258 | int devbits = (2 * ap->port_no + adev->devno) * 4; | ||
259 | u16 csb5_pio; | ||
260 | struct pci_dev *pdev = to_pci_dev(ap->host->dev); | ||
261 | int pio = adev->pio_mode - XFER_PIO_0; | ||
262 | |||
263 | pci_write_config_byte(pdev, 0x40 + offset, pio_mode[pio]); | ||
264 | |||
265 | /* The OSB4 just requires the timing but the CSB series want the | ||
266 | mode number as well */ | ||
267 | if (serverworks_is_csb(pdev)) { | ||
268 | pci_read_config_word(pdev, 0x4A, &csb5_pio); | ||
269 | csb5_pio &= ~(0x0F << devbits); | ||
270 | pci_write_config_byte(pdev, 0x4A, csb5_pio | (pio << devbits)); | ||
271 | } | ||
272 | } | ||
273 | |||
274 | /** | ||
275 | * serverworks_set_dmamode - set initial DMA mode data | ||
276 | * @ap: ATA interface | ||
277 | * @adev: ATA device | ||
278 | * | ||
279 | * Program the MWDMA/UDMA modes for the serverworks OSB4/CSB5 | ||
280 | * chipset. The MWDMA mode values are pulled from a lookup table | ||
281 | * while the chipset uses mode number for UDMA. | ||
282 | */ | ||
283 | |||
284 | static void serverworks_set_dmamode(struct ata_port *ap, struct ata_device *adev) | ||
285 | { | ||
286 | static const u8 dma_mode[] = { 0x77, 0x21, 0x20 }; | ||
287 | int offset = 1 + 2 * ap->port_no - adev->devno; | ||
288 | int devbits = (2 * ap->port_no + adev->devno); | ||
289 | u8 ultra; | ||
290 | u8 ultra_cfg; | ||
291 | struct pci_dev *pdev = to_pci_dev(ap->host->dev); | ||
292 | |||
293 | pci_read_config_byte(pdev, 0x54, &ultra_cfg); | ||
294 | |||
295 | if (adev->dma_mode >= XFER_UDMA_0) { | ||
296 | pci_write_config_byte(pdev, 0x44 + offset, 0x20); | ||
297 | |||
298 | pci_read_config_byte(pdev, 0x56 + ap->port_no, &ultra); | ||
299 | ultra &= ~(0x0F << (ap->port_no * 4)); | ||
300 | ultra |= (adev->dma_mode - XFER_UDMA_0) | ||
301 | << (ap->port_no * 4); | ||
302 | pci_write_config_byte(pdev, 0x56 + ap->port_no, ultra); | ||
303 | |||
304 | ultra_cfg |= (1 << devbits); | ||
305 | } else { | ||
306 | pci_write_config_byte(pdev, 0x44 + offset, | ||
307 | dma_mode[adev->dma_mode - XFER_MW_DMA_0]); | ||
308 | ultra_cfg &= ~(1 << devbits); | ||
309 | } | ||
310 | pci_write_config_byte(pdev, 0x54, ultra_cfg); | ||
311 | } | ||
312 | |||
313 | static struct scsi_host_template serverworks_sht = { | ||
314 | .module = THIS_MODULE, | ||
315 | .name = DRV_NAME, | ||
316 | .ioctl = ata_scsi_ioctl, | ||
317 | .queuecommand = ata_scsi_queuecmd, | ||
318 | .can_queue = ATA_DEF_QUEUE, | ||
319 | .this_id = ATA_SHT_THIS_ID, | ||
320 | .sg_tablesize = LIBATA_MAX_PRD, | ||
321 | .max_sectors = ATA_MAX_SECTORS, | ||
322 | .cmd_per_lun = ATA_SHT_CMD_PER_LUN, | ||
323 | .emulated = ATA_SHT_EMULATED, | ||
324 | .use_clustering = ATA_SHT_USE_CLUSTERING, | ||
325 | .proc_name = DRV_NAME, | ||
326 | .dma_boundary = ATA_DMA_BOUNDARY, | ||
327 | .slave_configure = ata_scsi_slave_config, | ||
328 | .bios_param = ata_std_bios_param, | ||
329 | }; | ||
330 | |||
331 | static struct ata_port_operations serverworks_osb4_port_ops = { | ||
332 | .port_disable = ata_port_disable, | ||
333 | .set_piomode = serverworks_set_piomode, | ||
334 | .set_dmamode = serverworks_set_dmamode, | ||
335 | .mode_filter = serverworks_osb4_filter, | ||
336 | |||
337 | .tf_load = ata_tf_load, | ||
338 | .tf_read = ata_tf_read, | ||
339 | .check_status = ata_check_status, | ||
340 | .exec_command = ata_exec_command, | ||
341 | .dev_select = ata_std_dev_select, | ||
342 | |||
343 | .freeze = ata_bmdma_freeze, | ||
344 | .thaw = ata_bmdma_thaw, | ||
345 | .error_handler = serverworks_error_handler, | ||
346 | .post_internal_cmd = ata_bmdma_post_internal_cmd, | ||
347 | |||
348 | .bmdma_setup = ata_bmdma_setup, | ||
349 | .bmdma_start = ata_bmdma_start, | ||
350 | .bmdma_stop = ata_bmdma_stop, | ||
351 | .bmdma_status = ata_bmdma_status, | ||
352 | |||
353 | .qc_prep = ata_qc_prep, | ||
354 | .qc_issue = ata_qc_issue_prot, | ||
355 | .eng_timeout = ata_eng_timeout, | ||
356 | .data_xfer = ata_pio_data_xfer, | ||
357 | |||
358 | .irq_handler = ata_interrupt, | ||
359 | .port_start = ata_port_start, | ||
360 | .port_stop = ata_port_stop, | ||
361 | .host_stop = ata_host_stop | ||
362 | }; | ||
363 | |||
364 | static struct ata_port_operations serverworks_csb_port_ops = { | ||
365 | .port_disable = ata_port_disable, | ||
366 | .set_piomode = serverworks_set_piomode, | ||
367 | .set_dmamode = serverworks_set_dmamode, | ||
368 | .mode_filter = serverworks_csb_filter, | ||
369 | |||
370 | .tf_load = ata_tf_load, | ||
371 | .tf_read = ata_tf_read, | ||
372 | .check_status = ata_check_status, | ||
373 | .exec_command = ata_exec_command, | ||
374 | .dev_select = ata_std_dev_select, | ||
375 | |||
376 | .freeze = ata_bmdma_freeze, | ||
377 | .thaw = ata_bmdma_thaw, | ||
378 | .error_handler = serverworks_error_handler, | ||
379 | .post_internal_cmd = ata_bmdma_post_internal_cmd, | ||
380 | |||
381 | .bmdma_setup = ata_bmdma_setup, | ||
382 | .bmdma_start = ata_bmdma_start, | ||
383 | .bmdma_stop = ata_bmdma_stop, | ||
384 | .bmdma_status = ata_bmdma_status, | ||
385 | |||
386 | .qc_prep = ata_qc_prep, | ||
387 | .qc_issue = ata_qc_issue_prot, | ||
388 | .eng_timeout = ata_eng_timeout, | ||
389 | .data_xfer = ata_pio_data_xfer, | ||
390 | |||
391 | .irq_handler = ata_interrupt, | ||
392 | .port_start = ata_port_start, | ||
393 | .port_stop = ata_port_stop, | ||
394 | .host_stop = ata_host_stop | ||
395 | }; | ||
396 | |||
397 | static int serverworks_fixup_osb4(struct pci_dev *pdev) | ||
398 | { | ||
399 | u32 reg; | ||
400 | struct pci_dev *isa_dev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS, | ||
401 | PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL); | ||
402 | if (isa_dev) { | ||
403 | pci_read_config_dword(isa_dev, 0x64, ®); | ||
404 | reg &= ~0x00002000; /* disable 600ns interrupt mask */ | ||
405 | if (!(reg & 0x00004000)) | ||
406 | printk(KERN_DEBUG DRV_NAME ": UDMA not BIOS enabled.\n"); | ||
407 | reg |= 0x00004000; /* enable UDMA/33 support */ | ||
408 | pci_write_config_dword(isa_dev, 0x64, reg); | ||
409 | pci_dev_put(isa_dev); | ||
410 | return 0; | ||
411 | } | ||
412 | printk(KERN_WARNING "ata_serverworks: Unable to find bridge.\n"); | ||
413 | return -ENODEV; | ||
414 | } | ||
415 | |||
416 | static int serverworks_fixup_csb(struct pci_dev *pdev) | ||
417 | { | ||
418 | u8 rev; | ||
419 | u8 btr; | ||
420 | |||
421 | pci_read_config_byte(pdev, PCI_REVISION_ID, &rev); | ||
422 | |||
423 | /* Third Channel Test */ | ||
424 | if (!(PCI_FUNC(pdev->devfn) & 1)) { | ||
425 | struct pci_dev * findev = NULL; | ||
426 | u32 reg4c = 0; | ||
427 | findev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS, | ||
428 | PCI_DEVICE_ID_SERVERWORKS_CSB5, NULL); | ||
429 | if (findev) { | ||
430 | pci_read_config_dword(findev, 0x4C, ®4c); | ||
431 | reg4c &= ~0x000007FF; | ||
432 | reg4c |= 0x00000040; | ||
433 | reg4c |= 0x00000020; | ||
434 | pci_write_config_dword(findev, 0x4C, reg4c); | ||
435 | pci_dev_put(findev); | ||
436 | } | ||
437 | } else { | ||
438 | struct pci_dev * findev = NULL; | ||
439 | u8 reg41 = 0; | ||
440 | |||
441 | findev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS, | ||
442 | PCI_DEVICE_ID_SERVERWORKS_CSB6, NULL); | ||
443 | if (findev) { | ||
444 | pci_read_config_byte(findev, 0x41, ®41); | ||
445 | reg41 &= ~0x40; | ||
446 | pci_write_config_byte(findev, 0x41, reg41); | ||
447 | pci_dev_put(findev); | ||
448 | } | ||
449 | } | ||
450 | /* setup the UDMA Control register | ||
451 | * | ||
452 | * 1. clear bit 6 to enable DMA | ||
453 | * 2. enable DMA modes with bits 0-1 | ||
454 | * 00 : legacy | ||
455 | * 01 : udma2 | ||
456 | * 10 : udma2/udma4 | ||
457 | * 11 : udma2/udma4/udma5 | ||
458 | */ | ||
459 | pci_read_config_byte(pdev, 0x5A, &btr); | ||
460 | btr &= ~0x40; | ||
461 | if (!(PCI_FUNC(pdev->devfn) & 1)) | ||
462 | btr |= 0x2; | ||
463 | else | ||
464 | btr |= (rev >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2; | ||
465 | pci_write_config_byte(pdev, 0x5A, btr); | ||
466 | |||
467 | return btr; | ||
468 | } | ||
469 | |||
470 | static void serverworks_fixup_ht1000(struct pci_dev *pdev) | ||
471 | { | ||
472 | u8 btr; | ||
473 | /* Setup HT1000 SouthBridge Controller - Single Channel Only */ | ||
474 | pci_read_config_byte(pdev, 0x5A, &btr); | ||
475 | btr &= ~0x40; | ||
476 | btr |= 0x3; | ||
477 | pci_write_config_byte(pdev, 0x5A, btr); | ||
478 | } | ||
479 | |||
480 | |||
481 | static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id *id) | ||
482 | { | ||
483 | int ports = 2; | ||
484 | static struct ata_port_info info[4] = { | ||
485 | { /* OSB4 */ | ||
486 | .sht = &serverworks_sht, | ||
487 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | ||
488 | .pio_mask = 0x1f, | ||
489 | .mwdma_mask = 0x07, | ||
490 | .udma_mask = 0x07, | ||
491 | .port_ops = &serverworks_osb4_port_ops | ||
492 | }, { /* OSB4 no UDMA */ | ||
493 | .sht = &serverworks_sht, | ||
494 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | ||
495 | .pio_mask = 0x1f, | ||
496 | .mwdma_mask = 0x07, | ||
497 | .udma_mask = 0x00, | ||
498 | .port_ops = &serverworks_osb4_port_ops | ||
499 | }, { /* CSB5 */ | ||
500 | .sht = &serverworks_sht, | ||
501 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | ||
502 | .pio_mask = 0x1f, | ||
503 | .mwdma_mask = 0x07, | ||
504 | .udma_mask = 0x1f, | ||
505 | .port_ops = &serverworks_csb_port_ops | ||
506 | }, { /* CSB5 - later revisions*/ | ||
507 | .sht = &serverworks_sht, | ||
508 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | ||
509 | .pio_mask = 0x1f, | ||
510 | .mwdma_mask = 0x07, | ||
511 | .udma_mask = 0x3f, | ||
512 | .port_ops = &serverworks_csb_port_ops | ||
513 | } | ||
514 | }; | ||
515 | static struct ata_port_info *port_info[2]; | ||
516 | struct ata_port_info *devinfo = &info[id->driver_data]; | ||
517 | |||
518 | /* Force master latency timer to 64 PCI clocks */ | ||
519 | pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x40); | ||
520 | |||
521 | /* OSB4 : South Bridge and IDE */ | ||
522 | if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) { | ||
523 | /* Select non UDMA capable OSB4 if we can't do fixups */ | ||
524 | if ( serverworks_fixup_osb4(pdev) < 0) | ||
525 | devinfo = &info[1]; | ||
526 | } | ||
527 | /* setup CSB5/CSB6 : South Bridge and IDE option RAID */ | ||
528 | else if ((pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) || | ||
529 | (pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) || | ||
530 | (pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) { | ||
531 | |||
532 | /* If the returned btr is the newer revision then | ||
533 | select the right info block */ | ||
534 | if (serverworks_fixup_csb(pdev) == 3) | ||
535 | devinfo = &info[3]; | ||
536 | |||
537 | /* Is this the 3rd channel CSB6 IDE ? */ | ||
538 | if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2) | ||
539 | ports = 1; | ||
540 | } | ||
541 | /* setup HT1000E */ | ||
542 | else if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_HT1000IDE) | ||
543 | serverworks_fixup_ht1000(pdev); | ||
544 | |||
545 | if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) | ||
546 | ata_pci_clear_simplex(pdev); | ||
547 | |||
548 | port_info[0] = port_info[1] = devinfo; | ||
549 | return ata_pci_init_one(pdev, port_info, ports); | ||
550 | } | ||
551 | |||
552 | static struct pci_device_id serverworks[] = { | ||
553 | { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE), 0}, | ||
554 | { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE), 2}, | ||
555 | { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE), 2}, | ||
556 | { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2), 2}, | ||
557 | { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000IDE), 2}, | ||
558 | { 0, }, | ||
559 | }; | ||
560 | |||
561 | static struct pci_driver serverworks_pci_driver = { | ||
562 | .name = DRV_NAME, | ||
563 | .id_table = serverworks, | ||
564 | .probe = serverworks_init_one, | ||
565 | .remove = ata_pci_remove_one | ||
566 | }; | ||
567 | |||
568 | static int __init serverworks_init(void) | ||
569 | { | ||
570 | return pci_register_driver(&serverworks_pci_driver); | ||
571 | } | ||
572 | |||
573 | |||
574 | static void __exit serverworks_exit(void) | ||
575 | { | ||
576 | pci_unregister_driver(&serverworks_pci_driver); | ||
577 | } | ||
578 | |||
579 | |||
580 | MODULE_AUTHOR("Alan Cox"); | ||
581 | MODULE_DESCRIPTION("low-level driver for Serverworks OSB4/CSB5/CSB6"); | ||
582 | MODULE_LICENSE("GPL"); | ||
583 | MODULE_DEVICE_TABLE(pci, serverworks); | ||
584 | MODULE_VERSION(DRV_VERSION); | ||
585 | |||
586 | module_init(serverworks_init); | ||
587 | module_exit(serverworks_exit); | ||