1 | /* |
2 | * Product specific probe and attach routines for: |
3 | * aic7901 and aic7902 SCSI controllers |
4 | * |
5 | * Copyright (c) 1994-2001 Justin T. Gibbs. |
6 | * Copyright (c) 2000-2002 Adaptec Inc. |
7 | * All rights reserved. |
8 | * |
9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions |
11 | * are met: |
12 | * 1. Redistributions of source code must retain the above copyright |
13 | * notice, this list of conditions, and the following disclaimer, |
14 | * without modification. |
15 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer |
16 | * substantially similar to the "NO WARRANTY" disclaimer below |
17 | * ("Disclaimer") and any redistribution must be conditioned upon |
18 | * including a substantially similar Disclaimer requirement for further |
19 | * binary redistribution. |
20 | * 3. Neither the names of the above-listed copyright holders nor the names |
21 | * of any contributors may be used to endorse or promote products derived |
22 | * from this software without specific prior written permission. |
23 | * |
24 | * Alternatively, this software may be distributed under the terms of the |
25 | * GNU General Public License ("GPL") version 2 as published by the Free |
26 | * Software Foundation. |
27 | * |
28 | * NO WARRANTY |
29 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
30 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
31 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
32 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
33 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
34 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
35 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
36 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
37 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
38 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
39 | * POSSIBILITY OF SUCH DAMAGES. |
40 | * |
41 | * $Id: //depot/aic7xxx/aic7xxx/aic79xx_pci.c#92 $ |
42 | */ |
43 | |
44 | #include "aic79xx_osm.h" |
45 | #include "aic79xx_inline.h" |
46 | #include "aic79xx_pci.h" |
47 | |
48 | static inline uint64_t |
49 | ahd_compose_id(u_int device, u_int vendor, u_int subdevice, u_int subvendor) |
50 | { |
51 | uint64_t id; |
52 | |
53 | id = subvendor |
54 | | (subdevice << 16) |
55 | | ((uint64_t)vendor << 32) |
56 | | ((uint64_t)device << 48); |
57 | |
58 | return (id); |
59 | } |
60 | |
61 | #define ID_AIC7902_PCI_REV_A4 0x3 |
62 | #define ID_AIC7902_PCI_REV_B0 0x10 |
63 | #define SUBID_HP 0x0E11 |
64 | |
65 | #define DEVID_9005_HOSTRAID(id) ((id) & 0x80) |
66 | |
67 | #define DEVID_9005_TYPE(id) ((id) & 0xF) |
68 | #define DEVID_9005_TYPE_HBA 0x0 /* Standard Card */ |
69 | #define DEVID_9005_TYPE_HBA_2EXT 0x1 /* 2 External Ports */ |
70 | #define DEVID_9005_TYPE_IROC 0x8 /* Raid(0,1,10) Card */ |
71 | #define DEVID_9005_TYPE_MB 0xF /* On Motherboard */ |
72 | |
73 | #define DEVID_9005_MFUNC(id) ((id) & 0x10) |
74 | |
75 | #define DEVID_9005_PACKETIZED(id) ((id) & 0x8000) |
76 | |
77 | #define SUBID_9005_TYPE(id) ((id) & 0xF) |
78 | #define SUBID_9005_TYPE_HBA 0x0 /* Standard Card */ |
79 | #define SUBID_9005_TYPE_MB 0xF /* On Motherboard */ |
80 | |
81 | #define SUBID_9005_AUTOTERM(id) (((id) & 0x10) == 0) |
82 | |
83 | #define SUBID_9005_LEGACYCONN_FUNC(id) ((id) & 0x20) |
84 | |
85 | #define SUBID_9005_SEEPTYPE(id) (((id) & 0x0C0) >> 6) |
86 | #define SUBID_9005_SEEPTYPE_NONE 0x0 |
87 | #define SUBID_9005_SEEPTYPE_4K 0x1 |
88 | |
89 | static ahd_device_setup_t ahd_aic7901_setup; |
90 | static ahd_device_setup_t ahd_aic7901A_setup; |
91 | static ahd_device_setup_t ahd_aic7902_setup; |
92 | static ahd_device_setup_t ahd_aic790X_setup; |
93 | |
94 | static const struct ahd_pci_identity ahd_pci_ident_table[] = |
95 | { |
96 | /* aic7901 based controllers */ |
97 | { |
98 | ID_AHA_29320A, |
99 | ID_ALL_MASK, |
100 | "Adaptec 29320A Ultra320 SCSI adapter" , |
101 | ahd_aic7901_setup |
102 | }, |
103 | { |
104 | ID_AHA_29320ALP, |
105 | ID_ALL_MASK, |
106 | "Adaptec 29320ALP PCIx Ultra320 SCSI adapter" , |
107 | ahd_aic7901_setup |
108 | }, |
109 | { |
110 | ID_AHA_29320LPE, |
111 | ID_ALL_MASK, |
112 | "Adaptec 29320LPE PCIe Ultra320 SCSI adapter" , |
113 | ahd_aic7901_setup |
114 | }, |
115 | /* aic7901A based controllers */ |
116 | { |
117 | ID_AHA_29320LP, |
118 | ID_ALL_MASK, |
119 | "Adaptec 29320LP Ultra320 SCSI adapter" , |
120 | ahd_aic7901A_setup |
121 | }, |
122 | /* aic7902 based controllers */ |
123 | { |
124 | ID_AHA_29320, |
125 | ID_ALL_MASK, |
126 | "Adaptec 29320 Ultra320 SCSI adapter" , |
127 | ahd_aic7902_setup |
128 | }, |
129 | { |
130 | ID_AHA_29320B, |
131 | ID_ALL_MASK, |
132 | "Adaptec 29320B Ultra320 SCSI adapter" , |
133 | ahd_aic7902_setup |
134 | }, |
135 | { |
136 | ID_AHA_39320, |
137 | ID_ALL_MASK, |
138 | "Adaptec 39320 Ultra320 SCSI adapter" , |
139 | ahd_aic7902_setup |
140 | }, |
141 | { |
142 | ID_AHA_39320_B, |
143 | ID_ALL_MASK, |
144 | "Adaptec 39320 Ultra320 SCSI adapter" , |
145 | ahd_aic7902_setup |
146 | }, |
147 | { |
148 | ID_AHA_39320_B_DELL, |
149 | ID_ALL_MASK, |
150 | "Adaptec (Dell OEM) 39320 Ultra320 SCSI adapter" , |
151 | ahd_aic7902_setup |
152 | }, |
153 | { |
154 | ID_AHA_39320A, |
155 | ID_ALL_MASK, |
156 | "Adaptec 39320A Ultra320 SCSI adapter" , |
157 | ahd_aic7902_setup |
158 | }, |
159 | { |
160 | ID_AHA_39320D, |
161 | ID_ALL_MASK, |
162 | "Adaptec 39320D Ultra320 SCSI adapter" , |
163 | ahd_aic7902_setup |
164 | }, |
165 | { |
166 | ID_AHA_39320D_HP, |
167 | ID_ALL_MASK, |
168 | "Adaptec (HP OEM) 39320D Ultra320 SCSI adapter" , |
169 | ahd_aic7902_setup |
170 | }, |
171 | { |
172 | ID_AHA_39320D_B, |
173 | ID_ALL_MASK, |
174 | "Adaptec 39320D Ultra320 SCSI adapter" , |
175 | ahd_aic7902_setup |
176 | }, |
177 | { |
178 | ID_AHA_39320D_B_HP, |
179 | ID_ALL_MASK, |
180 | "Adaptec (HP OEM) 39320D Ultra320 SCSI adapter" , |
181 | ahd_aic7902_setup |
182 | }, |
183 | /* Generic chip probes for devices we don't know 'exactly' */ |
184 | { |
185 | ID_AIC7901 & ID_9005_GENERIC_MASK, |
186 | ID_9005_GENERIC_MASK, |
187 | "Adaptec AIC7901 Ultra320 SCSI adapter" , |
188 | ahd_aic7901_setup |
189 | }, |
190 | { |
191 | ID_AIC7901A & ID_DEV_VENDOR_MASK, |
192 | ID_DEV_VENDOR_MASK, |
193 | "Adaptec AIC7901A Ultra320 SCSI adapter" , |
194 | ahd_aic7901A_setup |
195 | }, |
196 | { |
197 | ID_AIC7902 & ID_9005_GENERIC_MASK, |
198 | ID_9005_GENERIC_MASK, |
199 | "Adaptec AIC7902 Ultra320 SCSI adapter" , |
200 | ahd_aic7902_setup |
201 | } |
202 | }; |
203 | |
204 | static const u_int ahd_num_pci_devs = ARRAY_SIZE(ahd_pci_ident_table); |
205 | |
206 | #define DEVCONFIG 0x40 |
207 | #define PCIXINITPAT 0x0000E000ul |
208 | #define PCIXINIT_PCI33_66 0x0000E000ul |
209 | #define PCIXINIT_PCIX50_66 0x0000C000ul |
210 | #define PCIXINIT_PCIX66_100 0x0000A000ul |
211 | #define PCIXINIT_PCIX100_133 0x00008000ul |
212 | #define PCI_BUS_MODES_INDEX(devconfig) \ |
213 | (((devconfig) & PCIXINITPAT) >> 13) |
214 | static const char *pci_bus_modes[] = |
215 | { |
216 | "PCI bus mode unknown" , |
217 | "PCI bus mode unknown" , |
218 | "PCI bus mode unknown" , |
219 | "PCI bus mode unknown" , |
220 | "PCI-X 101-133MHz" , |
221 | "PCI-X 67-100MHz" , |
222 | "PCI-X 50-66MHz" , |
223 | "PCI 33 or 66MHz" |
224 | }; |
225 | |
226 | #define TESTMODE 0x00000800ul |
227 | #define IRDY_RST 0x00000200ul |
228 | #define FRAME_RST 0x00000100ul |
229 | #define PCI64BIT 0x00000080ul |
230 | #define MRDCEN 0x00000040ul |
231 | #define ENDIANSEL 0x00000020ul |
232 | #define MIXQWENDIANEN 0x00000008ul |
233 | #define DACEN 0x00000004ul |
234 | #define STPWLEVEL 0x00000002ul |
235 | #define QWENDIANSEL 0x00000001ul |
236 | |
237 | #define DEVCONFIG1 0x44 |
238 | #define PREQDIS 0x01 |
239 | |
240 | #define CSIZE_LATTIME 0x0c |
241 | #define CACHESIZE 0x000000fful |
242 | #define LATTIME 0x0000ff00ul |
243 | |
244 | static int ahd_check_extport(struct ahd_softc *ahd); |
245 | static void ahd_configure_termination(struct ahd_softc *ahd, |
246 | u_int adapter_control); |
247 | static void ahd_pci_split_intr(struct ahd_softc *ahd, u_int intstat); |
248 | static void ahd_pci_intr(struct ahd_softc *ahd); |
249 | |
250 | const struct ahd_pci_identity * |
251 | ahd_find_pci_device(ahd_dev_softc_t pci) |
252 | { |
253 | uint64_t full_id; |
254 | uint16_t device; |
255 | uint16_t vendor; |
256 | uint16_t subdevice; |
257 | uint16_t subvendor; |
258 | const struct ahd_pci_identity *entry; |
259 | u_int i; |
260 | |
261 | vendor = ahd_pci_read_config(pci, PCIR_DEVVENDOR, /*bytes*/width: 2); |
262 | device = ahd_pci_read_config(pci, PCIR_DEVICE, /*bytes*/width: 2); |
263 | subvendor = ahd_pci_read_config(pci, PCI_SUBSYSTEM_VENDOR_ID, /*bytes*/width: 2); |
264 | subdevice = ahd_pci_read_config(pci, PCI_SUBSYSTEM_ID, /*bytes*/width: 2); |
265 | full_id = ahd_compose_id(device, |
266 | vendor, |
267 | subdevice, |
268 | subvendor); |
269 | |
270 | /* |
271 | * Controllers, mask out the IROC/HostRAID bit |
272 | */ |
273 | |
274 | full_id &= ID_ALL_IROC_MASK; |
275 | |
276 | for (i = 0; i < ahd_num_pci_devs; i++) { |
277 | entry = &ahd_pci_ident_table[i]; |
278 | if (entry->full_id == (full_id & entry->id_mask)) { |
279 | /* Honor exclusion entries. */ |
280 | if (entry->name == NULL) |
281 | return (NULL); |
282 | return (entry); |
283 | } |
284 | } |
285 | return (NULL); |
286 | } |
287 | |
288 | int |
289 | ahd_pci_config(struct ahd_softc *ahd, const struct ahd_pci_identity *entry) |
290 | { |
291 | u_int command; |
292 | uint32_t devconfig; |
293 | uint16_t subvendor; |
294 | int error; |
295 | |
296 | ahd->description = entry->name; |
297 | /* |
298 | * Record if this is an HP board. |
299 | */ |
300 | subvendor = ahd_pci_read_config(pci: ahd->dev_softc, |
301 | PCI_SUBSYSTEM_VENDOR_ID, /*bytes*/width: 2); |
302 | if (subvendor == SUBID_HP) |
303 | ahd->flags |= AHD_HP_BOARD; |
304 | |
305 | error = entry->setup(ahd); |
306 | if (error != 0) |
307 | return (error); |
308 | |
309 | devconfig = ahd_pci_read_config(pci: ahd->dev_softc, DEVCONFIG, /*bytes*/width: 4); |
310 | if ((devconfig & PCIXINITPAT) == PCIXINIT_PCI33_66) { |
311 | ahd->chip |= AHD_PCI; |
312 | /* Disable PCIX workarounds when running in PCI mode. */ |
313 | ahd->bugs &= ~AHD_PCIX_BUG_MASK; |
314 | } else { |
315 | ahd->chip |= AHD_PCIX; |
316 | } |
317 | ahd->bus_description = pci_bus_modes[PCI_BUS_MODES_INDEX(devconfig)]; |
318 | |
319 | ahd_power_state_change(ahd, new_state: AHD_POWER_STATE_D0); |
320 | |
321 | error = ahd_pci_map_registers(ahd); |
322 | if (error != 0) |
323 | return (error); |
324 | |
325 | /* |
326 | * If we need to support high memory, enable dual |
327 | * address cycles. This bit must be set to enable |
328 | * high address bit generation even if we are on a |
329 | * 64bit bus (PCI64BIT set in devconfig). |
330 | */ |
331 | if ((ahd->flags & (AHD_39BIT_ADDRESSING|AHD_64BIT_ADDRESSING)) != 0) { |
332 | if (bootverbose) |
333 | printk("%s: Enabling 39Bit Addressing\n" , |
334 | ahd_name(ahd)); |
335 | devconfig = ahd_pci_read_config(pci: ahd->dev_softc, |
336 | DEVCONFIG, /*bytes*/width: 4); |
337 | devconfig |= DACEN; |
338 | ahd_pci_write_config(pci: ahd->dev_softc, DEVCONFIG, |
339 | value: devconfig, /*bytes*/width: 4); |
340 | } |
341 | |
342 | /* Ensure busmastering is enabled */ |
343 | command = ahd_pci_read_config(pci: ahd->dev_softc, PCIR_COMMAND, /*bytes*/width: 2); |
344 | command |= PCIM_CMD_BUSMASTEREN; |
345 | ahd_pci_write_config(pci: ahd->dev_softc, PCIR_COMMAND, value: command, /*bytes*/width: 2); |
346 | |
347 | error = ahd_softc_init(ahd); |
348 | if (error != 0) |
349 | return (error); |
350 | |
351 | ahd->bus_intr = ahd_pci_intr; |
352 | |
353 | error = ahd_reset(ahd, /*reinit*/FALSE); |
354 | if (error != 0) |
355 | return (ENXIO); |
356 | |
357 | ahd->pci_cachesize = |
358 | ahd_pci_read_config(pci: ahd->dev_softc, CSIZE_LATTIME, |
359 | /*bytes*/width: 1) & CACHESIZE; |
360 | ahd->pci_cachesize *= 4; |
361 | |
362 | ahd_set_modes(ahd, src: AHD_MODE_SCSI, dst: AHD_MODE_SCSI); |
363 | /* See if we have a SEEPROM and perform auto-term */ |
364 | error = ahd_check_extport(ahd); |
365 | if (error != 0) |
366 | return (error); |
367 | |
368 | /* Core initialization */ |
369 | error = ahd_init(ahd); |
370 | if (error != 0) |
371 | return (error); |
372 | ahd->init_level++; |
373 | |
374 | /* |
375 | * Allow interrupts now that we are completely setup. |
376 | */ |
377 | return ahd_pci_map_int(ahd); |
378 | } |
379 | |
380 | void __maybe_unused |
381 | ahd_pci_suspend(struct ahd_softc *ahd) |
382 | { |
383 | /* |
384 | * Save chip register configuration data for chip resets |
385 | * that occur during runtime and resume events. |
386 | */ |
387 | ahd->suspend_state.pci_state.devconfig = |
388 | ahd_pci_read_config(pci: ahd->dev_softc, DEVCONFIG, /*bytes*/width: 4); |
389 | ahd->suspend_state.pci_state.command = |
390 | ahd_pci_read_config(pci: ahd->dev_softc, PCIR_COMMAND, /*bytes*/width: 1); |
391 | ahd->suspend_state.pci_state.csize_lattime = |
392 | ahd_pci_read_config(pci: ahd->dev_softc, CSIZE_LATTIME, /*bytes*/width: 1); |
393 | |
394 | } |
395 | |
396 | void __maybe_unused |
397 | ahd_pci_resume(struct ahd_softc *ahd) |
398 | { |
399 | ahd_pci_write_config(pci: ahd->dev_softc, DEVCONFIG, |
400 | value: ahd->suspend_state.pci_state.devconfig, /*bytes*/width: 4); |
401 | ahd_pci_write_config(pci: ahd->dev_softc, PCIR_COMMAND, |
402 | value: ahd->suspend_state.pci_state.command, /*bytes*/width: 1); |
403 | ahd_pci_write_config(pci: ahd->dev_softc, CSIZE_LATTIME, |
404 | value: ahd->suspend_state.pci_state.csize_lattime, /*bytes*/width: 1); |
405 | } |
406 | |
407 | /* |
408 | * Perform some simple tests that should catch situations where |
409 | * our registers are invalidly mapped. |
410 | */ |
411 | int |
412 | ahd_pci_test_register_access(struct ahd_softc *ahd) |
413 | { |
414 | uint32_t cmd; |
415 | u_int targpcistat; |
416 | u_int pci_status1; |
417 | int error; |
418 | uint8_t hcntrl; |
419 | |
420 | error = EIO; |
421 | |
422 | /* |
423 | * Enable PCI error interrupt status, but suppress NMIs |
424 | * generated by SERR raised due to target aborts. |
425 | */ |
426 | cmd = ahd_pci_read_config(pci: ahd->dev_softc, PCIR_COMMAND, /*bytes*/width: 2); |
427 | ahd_pci_write_config(pci: ahd->dev_softc, PCIR_COMMAND, |
428 | value: cmd & ~PCIM_CMD_SERRESPEN, /*bytes*/width: 2); |
429 | |
430 | /* |
431 | * First a simple test to see if any |
432 | * registers can be read. Reading |
433 | * HCNTRL has no side effects and has |
434 | * at least one bit that is guaranteed to |
435 | * be zero so it is a good register to |
436 | * use for this test. |
437 | */ |
438 | hcntrl = ahd_inb(ahd, port: HCNTRL); |
439 | if (hcntrl == 0xFF) |
440 | goto fail; |
441 | |
442 | /* |
443 | * Next create a situation where write combining |
444 | * or read prefetching could be initiated by the |
445 | * CPU or host bridge. Our device does not support |
446 | * either, so look for data corruption and/or flaged |
447 | * PCI errors. First pause without causing another |
448 | * chip reset. |
449 | */ |
450 | hcntrl &= ~CHIPRST; |
451 | ahd_outb(ahd, port: HCNTRL, val: hcntrl|PAUSE); |
452 | while (ahd_is_paused(ahd) == 0) |
453 | ; |
454 | |
455 | /* Clear any PCI errors that occurred before our driver attached. */ |
456 | ahd_set_modes(ahd, src: AHD_MODE_CFG, dst: AHD_MODE_CFG); |
457 | targpcistat = ahd_inb(ahd, port: TARGPCISTAT); |
458 | ahd_outb(ahd, port: TARGPCISTAT, val: targpcistat); |
459 | pci_status1 = ahd_pci_read_config(pci: ahd->dev_softc, |
460 | PCIR_STATUS + 1, /*bytes*/width: 1); |
461 | ahd_pci_write_config(pci: ahd->dev_softc, PCIR_STATUS + 1, |
462 | value: pci_status1, /*bytes*/width: 1); |
463 | ahd_set_modes(ahd, src: AHD_MODE_SCSI, dst: AHD_MODE_SCSI); |
464 | ahd_outb(ahd, port: CLRINT, val: CLRPCIINT); |
465 | |
466 | ahd_outb(ahd, port: SEQCTL0, val: PERRORDIS); |
467 | ahd_outl(ahd, port: SRAM_BASE, value: 0x5aa555aa); |
468 | if (ahd_inl(ahd, port: SRAM_BASE) != 0x5aa555aa) |
469 | goto fail; |
470 | |
471 | if ((ahd_inb(ahd, INTSTAT) & PCIINT) != 0) { |
472 | ahd_set_modes(ahd, src: AHD_MODE_CFG, dst: AHD_MODE_CFG); |
473 | targpcistat = ahd_inb(ahd, port: TARGPCISTAT); |
474 | if ((targpcistat & STA) != 0) |
475 | goto fail; |
476 | } |
477 | |
478 | error = 0; |
479 | |
480 | fail: |
481 | if ((ahd_inb(ahd, INTSTAT) & PCIINT) != 0) { |
482 | |
483 | ahd_set_modes(ahd, src: AHD_MODE_CFG, dst: AHD_MODE_CFG); |
484 | targpcistat = ahd_inb(ahd, port: TARGPCISTAT); |
485 | |
486 | /* Silently clear any latched errors. */ |
487 | ahd_outb(ahd, port: TARGPCISTAT, val: targpcistat); |
488 | pci_status1 = ahd_pci_read_config(pci: ahd->dev_softc, |
489 | PCIR_STATUS + 1, /*bytes*/width: 1); |
490 | ahd_pci_write_config(pci: ahd->dev_softc, PCIR_STATUS + 1, |
491 | value: pci_status1, /*bytes*/width: 1); |
492 | ahd_outb(ahd, port: CLRINT, val: CLRPCIINT); |
493 | } |
494 | ahd_outb(ahd, port: SEQCTL0, val: PERRORDIS|FAILDIS); |
495 | ahd_pci_write_config(pci: ahd->dev_softc, PCIR_COMMAND, value: cmd, /*bytes*/width: 2); |
496 | return (error); |
497 | } |
498 | |
499 | /* |
500 | * Check the external port logic for a serial eeprom |
501 | * and termination/cable detection contrls. |
502 | */ |
503 | static int |
504 | ahd_check_extport(struct ahd_softc *ahd) |
505 | { |
506 | struct vpd_config vpd; |
507 | struct seeprom_config *sc; |
508 | u_int adapter_control; |
509 | int have_seeprom; |
510 | int error; |
511 | |
512 | sc = ahd->seep_config; |
513 | have_seeprom = ahd_acquire_seeprom(ahd); |
514 | if (have_seeprom) { |
515 | u_int start_addr; |
516 | |
517 | /* |
518 | * Fetch VPD for this function and parse it. |
519 | */ |
520 | if (bootverbose) |
521 | printk("%s: Reading VPD from SEEPROM..." , |
522 | ahd_name(ahd)); |
523 | |
524 | /* Address is always in units of 16bit words */ |
525 | start_addr = ((2 * sizeof(*sc)) |
526 | + (sizeof(vpd) * (ahd->channel - 'A'))) / 2; |
527 | |
528 | error = ahd_read_seeprom(ahd, buf: (uint16_t *)&vpd, |
529 | start_addr, count: sizeof(vpd)/2, |
530 | /*bytestream*/TRUE); |
531 | if (error == 0) |
532 | error = ahd_parse_vpddata(ahd, vpd: &vpd); |
533 | if (bootverbose) |
534 | printk("%s: VPD parsing %s\n" , |
535 | ahd_name(ahd), |
536 | error == 0 ? "successful" : "failed" ); |
537 | |
538 | if (bootverbose) |
539 | printk("%s: Reading SEEPROM..." , ahd_name(ahd)); |
540 | |
541 | /* Address is always in units of 16bit words */ |
542 | start_addr = (sizeof(*sc) / 2) * (ahd->channel - 'A'); |
543 | |
544 | error = ahd_read_seeprom(ahd, buf: (uint16_t *)sc, |
545 | start_addr, count: sizeof(*sc)/2, |
546 | /*bytestream*/FALSE); |
547 | |
548 | if (error != 0) { |
549 | printk("Unable to read SEEPROM\n" ); |
550 | have_seeprom = 0; |
551 | } else { |
552 | have_seeprom = ahd_verify_cksum(sc); |
553 | |
554 | if (bootverbose) { |
555 | if (have_seeprom == 0) |
556 | printk ("checksum error\n" ); |
557 | else |
558 | printk ("done.\n" ); |
559 | } |
560 | } |
561 | ahd_release_seeprom(ahd); |
562 | } |
563 | |
564 | if (!have_seeprom) { |
565 | u_int nvram_scb; |
566 | |
567 | /* |
568 | * Pull scratch ram settings and treat them as |
569 | * if they are the contents of an seeprom if |
570 | * the 'ADPT', 'BIOS', or 'ASPI' signature is found |
571 | * in SCB 0xFF. We manually compose the data as 16bit |
572 | * values to avoid endian issues. |
573 | */ |
574 | ahd_set_scbptr(ahd, scbptr: 0xFF); |
575 | nvram_scb = ahd_inb_scbram(ahd, offset: SCB_BASE + NVRAM_SCB_OFFSET); |
576 | if (nvram_scb != 0xFF |
577 | && ((ahd_inb_scbram(ahd, offset: SCB_BASE + 0) == 'A' |
578 | && ahd_inb_scbram(ahd, offset: SCB_BASE + 1) == 'D' |
579 | && ahd_inb_scbram(ahd, offset: SCB_BASE + 2) == 'P' |
580 | && ahd_inb_scbram(ahd, offset: SCB_BASE + 3) == 'T') |
581 | || (ahd_inb_scbram(ahd, offset: SCB_BASE + 0) == 'B' |
582 | && ahd_inb_scbram(ahd, offset: SCB_BASE + 1) == 'I' |
583 | && ahd_inb_scbram(ahd, offset: SCB_BASE + 2) == 'O' |
584 | && ahd_inb_scbram(ahd, offset: SCB_BASE + 3) == 'S') |
585 | || (ahd_inb_scbram(ahd, offset: SCB_BASE + 0) == 'A' |
586 | && ahd_inb_scbram(ahd, offset: SCB_BASE + 1) == 'S' |
587 | && ahd_inb_scbram(ahd, offset: SCB_BASE + 2) == 'P' |
588 | && ahd_inb_scbram(ahd, offset: SCB_BASE + 3) == 'I'))) { |
589 | uint16_t *sc_data; |
590 | int i; |
591 | |
592 | ahd_set_scbptr(ahd, scbptr: nvram_scb); |
593 | sc_data = (uint16_t *)sc; |
594 | for (i = 0; i < 64; i += 2) |
595 | *sc_data++ = ahd_inw_scbram(ahd, offset: SCB_BASE+i); |
596 | have_seeprom = ahd_verify_cksum(sc); |
597 | if (have_seeprom) |
598 | ahd->flags |= AHD_SCB_CONFIG_USED; |
599 | } |
600 | } |
601 | |
602 | #ifdef AHD_DEBUG |
603 | if (have_seeprom != 0 |
604 | && (ahd_debug & AHD_DUMP_SEEPROM) != 0) { |
605 | uint16_t *sc_data; |
606 | int i; |
607 | |
608 | printk("%s: Seeprom Contents:" , ahd_name(ahd)); |
609 | sc_data = (uint16_t *)sc; |
610 | for (i = 0; i < (sizeof(*sc)); i += 2) |
611 | printk("\n\t0x%.4x" , sc_data[i]); |
612 | printk("\n" ); |
613 | } |
614 | #endif |
615 | |
616 | if (!have_seeprom) { |
617 | if (bootverbose) |
618 | printk("%s: No SEEPROM available.\n" , ahd_name(ahd)); |
619 | ahd->flags |= AHD_USEDEFAULTS; |
620 | error = ahd_default_config(ahd); |
621 | adapter_control = CFAUTOTERM|CFSEAUTOTERM; |
622 | kfree(objp: ahd->seep_config); |
623 | ahd->seep_config = NULL; |
624 | } else { |
625 | error = ahd_parse_cfgdata(ahd, sc); |
626 | adapter_control = sc->adapter_control; |
627 | } |
628 | if (error != 0) |
629 | return (error); |
630 | |
631 | ahd_configure_termination(ahd, adapter_control); |
632 | |
633 | return (0); |
634 | } |
635 | |
636 | static void |
637 | ahd_configure_termination(struct ahd_softc *ahd, u_int adapter_control) |
638 | { |
639 | int error; |
640 | u_int sxfrctl1; |
641 | uint8_t termctl; |
642 | uint32_t devconfig; |
643 | |
644 | devconfig = ahd_pci_read_config(pci: ahd->dev_softc, DEVCONFIG, /*bytes*/width: 4); |
645 | devconfig &= ~STPWLEVEL; |
646 | if ((ahd->flags & AHD_STPWLEVEL_A) != 0) |
647 | devconfig |= STPWLEVEL; |
648 | if (bootverbose) |
649 | printk("%s: STPWLEVEL is %s\n" , |
650 | ahd_name(ahd), (devconfig & STPWLEVEL) ? "on" : "off" ); |
651 | ahd_pci_write_config(pci: ahd->dev_softc, DEVCONFIG, value: devconfig, /*bytes*/width: 4); |
652 | |
653 | /* Make sure current sensing is off. */ |
654 | if ((ahd->flags & AHD_CURRENT_SENSING) != 0) { |
655 | (void)ahd_write_flexport(ahd, FLXADDR_ROMSTAT_CURSENSECTL, value: 0); |
656 | } |
657 | |
658 | /* |
659 | * Read to sense. Write to set. |
660 | */ |
661 | error = ahd_read_flexport(ahd, FLXADDR_TERMCTL, value: &termctl); |
662 | if ((adapter_control & CFAUTOTERM) == 0) { |
663 | if (bootverbose) |
664 | printk("%s: Manual Primary Termination\n" , |
665 | ahd_name(ahd)); |
666 | termctl &= ~(FLX_TERMCTL_ENPRILOW|FLX_TERMCTL_ENPRIHIGH); |
667 | if ((adapter_control & CFSTERM) != 0) |
668 | termctl |= FLX_TERMCTL_ENPRILOW; |
669 | if ((adapter_control & CFWSTERM) != 0) |
670 | termctl |= FLX_TERMCTL_ENPRIHIGH; |
671 | } else if (error != 0) { |
672 | printk("%s: Primary Auto-Term Sensing failed! " |
673 | "Using Defaults.\n" , ahd_name(ahd)); |
674 | termctl = FLX_TERMCTL_ENPRILOW|FLX_TERMCTL_ENPRIHIGH; |
675 | } |
676 | |
677 | if ((adapter_control & CFSEAUTOTERM) == 0) { |
678 | if (bootverbose) |
679 | printk("%s: Manual Secondary Termination\n" , |
680 | ahd_name(ahd)); |
681 | termctl &= ~(FLX_TERMCTL_ENSECLOW|FLX_TERMCTL_ENSECHIGH); |
682 | if ((adapter_control & CFSELOWTERM) != 0) |
683 | termctl |= FLX_TERMCTL_ENSECLOW; |
684 | if ((adapter_control & CFSEHIGHTERM) != 0) |
685 | termctl |= FLX_TERMCTL_ENSECHIGH; |
686 | } else if (error != 0) { |
687 | printk("%s: Secondary Auto-Term Sensing failed! " |
688 | "Using Defaults.\n" , ahd_name(ahd)); |
689 | termctl |= FLX_TERMCTL_ENSECLOW|FLX_TERMCTL_ENSECHIGH; |
690 | } |
691 | |
692 | /* |
693 | * Now set the termination based on what we found. |
694 | */ |
695 | sxfrctl1 = ahd_inb(ahd, port: SXFRCTL1) & ~STPWEN; |
696 | ahd->flags &= ~AHD_TERM_ENB_A; |
697 | if ((termctl & FLX_TERMCTL_ENPRILOW) != 0) { |
698 | ahd->flags |= AHD_TERM_ENB_A; |
699 | sxfrctl1 |= STPWEN; |
700 | } |
701 | /* Must set the latch once in order to be effective. */ |
702 | ahd_outb(ahd, SXFRCTL1, sxfrctl1|STPWEN); |
703 | ahd_outb(ahd, SXFRCTL1, sxfrctl1); |
704 | |
705 | error = ahd_write_flexport(ahd, FLXADDR_TERMCTL, value: termctl); |
706 | if (error != 0) { |
707 | printk("%s: Unable to set termination settings!\n" , |
708 | ahd_name(ahd)); |
709 | } else if (bootverbose) { |
710 | printk("%s: Primary High byte termination %sabled\n" , |
711 | ahd_name(ahd), |
712 | (termctl & FLX_TERMCTL_ENPRIHIGH) ? "En" : "Dis" ); |
713 | |
714 | printk("%s: Primary Low byte termination %sabled\n" , |
715 | ahd_name(ahd), |
716 | (termctl & FLX_TERMCTL_ENPRILOW) ? "En" : "Dis" ); |
717 | |
718 | printk("%s: Secondary High byte termination %sabled\n" , |
719 | ahd_name(ahd), |
720 | (termctl & FLX_TERMCTL_ENSECHIGH) ? "En" : "Dis" ); |
721 | |
722 | printk("%s: Secondary Low byte termination %sabled\n" , |
723 | ahd_name(ahd), |
724 | (termctl & FLX_TERMCTL_ENSECLOW) ? "En" : "Dis" ); |
725 | } |
726 | return; |
727 | } |
728 | |
729 | #define DPE 0x80 |
730 | #define SSE 0x40 |
731 | #define RMA 0x20 |
732 | #define RTA 0x10 |
733 | #define STA 0x08 |
734 | #define DPR 0x01 |
735 | |
736 | static const char *split_status_source[] = |
737 | { |
738 | "DFF0" , |
739 | "DFF1" , |
740 | "OVLY" , |
741 | "CMC" , |
742 | }; |
743 | |
744 | static const char *pci_status_source[] = |
745 | { |
746 | "DFF0" , |
747 | "DFF1" , |
748 | "SG" , |
749 | "CMC" , |
750 | "OVLY" , |
751 | "NONE" , |
752 | "MSI" , |
753 | "TARG" |
754 | }; |
755 | |
756 | static const char *split_status_strings[] = |
757 | { |
758 | "%s: Received split response in %s.\n" , |
759 | "%s: Received split completion error message in %s\n" , |
760 | "%s: Receive overrun in %s\n" , |
761 | "%s: Count not complete in %s\n" , |
762 | "%s: Split completion data bucket in %s\n" , |
763 | "%s: Split completion address error in %s\n" , |
764 | "%s: Split completion byte count error in %s\n" , |
765 | "%s: Signaled Target-abort to early terminate a split in %s\n" |
766 | }; |
767 | |
768 | static const char *pci_status_strings[] = |
769 | { |
770 | "%s: Data Parity Error has been reported via PERR# in %s\n" , |
771 | "%s: Target initial wait state error in %s\n" , |
772 | "%s: Split completion read data parity error in %s\n" , |
773 | "%s: Split completion address attribute parity error in %s\n" , |
774 | "%s: Received a Target Abort in %s\n" , |
775 | "%s: Received a Master Abort in %s\n" , |
776 | "%s: Signal System Error Detected in %s\n" , |
777 | "%s: Address or Write Phase Parity Error Detected in %s.\n" |
778 | }; |
779 | |
780 | static void |
781 | ahd_pci_intr(struct ahd_softc *ahd) |
782 | { |
783 | uint8_t pci_status[8]; |
784 | ahd_mode_state saved_modes; |
785 | u_int pci_status1; |
786 | u_int intstat; |
787 | u_int i; |
788 | u_int reg; |
789 | |
790 | intstat = ahd_inb(ahd, INTSTAT); |
791 | |
792 | if ((intstat & SPLTINT) != 0) |
793 | ahd_pci_split_intr(ahd, intstat); |
794 | |
795 | if ((intstat & PCIINT) == 0) |
796 | return; |
797 | |
798 | printk("%s: PCI error Interrupt\n" , ahd_name(ahd)); |
799 | saved_modes = ahd_save_modes(ahd); |
800 | ahd_dump_card_state(ahd); |
801 | ahd_set_modes(ahd, src: AHD_MODE_CFG, dst: AHD_MODE_CFG); |
802 | for (i = 0, reg = DF0PCISTAT; i < 8; i++, reg++) { |
803 | |
804 | if (i == 5) |
805 | continue; |
806 | pci_status[i] = ahd_inb(ahd, port: reg); |
807 | /* Clear latched errors. So our interrupt deasserts. */ |
808 | ahd_outb(ahd, port: reg, val: pci_status[i]); |
809 | } |
810 | |
811 | for (i = 0; i < 8; i++) { |
812 | u_int bit; |
813 | |
814 | if (i == 5) |
815 | continue; |
816 | |
817 | for (bit = 0; bit < 8; bit++) { |
818 | |
819 | if ((pci_status[i] & (0x1 << bit)) != 0) { |
820 | const char *s; |
821 | |
822 | s = pci_status_strings[bit]; |
823 | if (i == 7/*TARG*/ && bit == 3) |
824 | s = "%s: Signaled Target Abort\n" ; |
825 | printk(s, ahd_name(ahd), pci_status_source[i]); |
826 | } |
827 | } |
828 | } |
829 | pci_status1 = ahd_pci_read_config(pci: ahd->dev_softc, |
830 | PCIR_STATUS + 1, /*bytes*/width: 1); |
831 | ahd_pci_write_config(pci: ahd->dev_softc, PCIR_STATUS + 1, |
832 | value: pci_status1, /*bytes*/width: 1); |
833 | ahd_restore_modes(ahd, state: saved_modes); |
834 | ahd_outb(ahd, CLRINT, CLRPCIINT); |
835 | ahd_unpause(ahd); |
836 | } |
837 | |
838 | static void |
839 | ahd_pci_split_intr(struct ahd_softc *ahd, u_int intstat) |
840 | { |
841 | uint8_t split_status[4]; |
842 | uint8_t split_status1[4]; |
843 | uint8_t sg_split_status[2]; |
844 | uint8_t sg_split_status1[2]; |
845 | ahd_mode_state saved_modes; |
846 | u_int i; |
847 | uint16_t pcix_status; |
848 | |
849 | /* |
850 | * Check for splits in all modes. Modes 0 and 1 |
851 | * additionally have SG engine splits to look at. |
852 | */ |
853 | pcix_status = ahd_pci_read_config(pci: ahd->dev_softc, PCIXR_STATUS, |
854 | /*bytes*/width: 2); |
855 | printk("%s: PCI Split Interrupt - PCI-X status = 0x%x\n" , |
856 | ahd_name(ahd), pcix_status); |
857 | saved_modes = ahd_save_modes(ahd); |
858 | for (i = 0; i < 4; i++) { |
859 | ahd_set_modes(ahd, src: i, dst: i); |
860 | |
861 | split_status[i] = ahd_inb(ahd, DCHSPLTSTAT0); |
862 | split_status1[i] = ahd_inb(ahd, DCHSPLTSTAT1); |
863 | /* Clear latched errors. So our interrupt deasserts. */ |
864 | ahd_outb(ahd, DCHSPLTSTAT0, split_status[i]); |
865 | ahd_outb(ahd, DCHSPLTSTAT1, split_status1[i]); |
866 | if (i > 1) |
867 | continue; |
868 | sg_split_status[i] = ahd_inb(ahd, SGSPLTSTAT0); |
869 | sg_split_status1[i] = ahd_inb(ahd, SGSPLTSTAT1); |
870 | /* Clear latched errors. So our interrupt deasserts. */ |
871 | ahd_outb(ahd, SGSPLTSTAT0, sg_split_status[i]); |
872 | ahd_outb(ahd, SGSPLTSTAT1, sg_split_status1[i]); |
873 | } |
874 | |
875 | for (i = 0; i < 4; i++) { |
876 | u_int bit; |
877 | |
878 | for (bit = 0; bit < 8; bit++) { |
879 | |
880 | if ((split_status[i] & (0x1 << bit)) != 0) |
881 | printk(split_status_strings[bit], ahd_name(ahd), |
882 | split_status_source[i]); |
883 | |
884 | if (i > 1) |
885 | continue; |
886 | |
887 | if ((sg_split_status[i] & (0x1 << bit)) != 0) |
888 | printk(split_status_strings[bit], ahd_name(ahd), "SG" ); |
889 | } |
890 | } |
891 | /* |
892 | * Clear PCI-X status bits. |
893 | */ |
894 | ahd_pci_write_config(pci: ahd->dev_softc, PCIXR_STATUS, |
895 | value: pcix_status, /*bytes*/width: 2); |
896 | ahd_outb(ahd, CLRINT, CLRSPLTINT); |
897 | ahd_restore_modes(ahd, state: saved_modes); |
898 | } |
899 | |
900 | static int |
901 | ahd_aic7901_setup(struct ahd_softc *ahd) |
902 | { |
903 | |
904 | ahd->chip = AHD_AIC7901; |
905 | ahd->features = AHD_AIC7901_FE; |
906 | return (ahd_aic790X_setup(ahd)); |
907 | } |
908 | |
909 | static int |
910 | ahd_aic7901A_setup(struct ahd_softc *ahd) |
911 | { |
912 | |
913 | ahd->chip = AHD_AIC7901A; |
914 | ahd->features = AHD_AIC7901A_FE; |
915 | return (ahd_aic790X_setup(ahd)); |
916 | } |
917 | |
918 | static int |
919 | ahd_aic7902_setup(struct ahd_softc *ahd) |
920 | { |
921 | ahd->chip = AHD_AIC7902; |
922 | ahd->features = AHD_AIC7902_FE; |
923 | return (ahd_aic790X_setup(ahd)); |
924 | } |
925 | |
926 | static int |
927 | ahd_aic790X_setup(struct ahd_softc *ahd) |
928 | { |
929 | ahd_dev_softc_t pci; |
930 | u_int rev; |
931 | |
932 | pci = ahd->dev_softc; |
933 | rev = ahd_pci_read_config(pci, PCIR_REVID, /*bytes*/width: 1); |
934 | if (rev < ID_AIC7902_PCI_REV_A4) { |
935 | printk("%s: Unable to attach to unsupported chip revision %d\n" , |
936 | ahd_name(ahd), rev); |
937 | ahd_pci_write_config(pci, PCIR_COMMAND, value: 0, /*bytes*/width: 2); |
938 | return (ENXIO); |
939 | } |
940 | ahd->channel = ahd_get_pci_function(pci) + 'A'; |
941 | if (rev < ID_AIC7902_PCI_REV_B0) { |
942 | /* |
943 | * Enable A series workarounds. |
944 | */ |
945 | ahd->bugs |= AHD_SENT_SCB_UPDATE_BUG|AHD_ABORT_LQI_BUG |
946 | | AHD_PKT_BITBUCKET_BUG|AHD_LONG_SETIMO_BUG |
947 | | AHD_NLQICRC_DELAYED_BUG|AHD_SCSIRST_BUG |
948 | | AHD_LQO_ATNO_BUG|AHD_AUTOFLUSH_BUG |
949 | | AHD_CLRLQO_AUTOCLR_BUG|AHD_PCIX_MMAPIO_BUG |
950 | | AHD_PCIX_CHIPRST_BUG|AHD_PCIX_SCBRAM_RD_BUG |
951 | | AHD_PKTIZED_STATUS_BUG|AHD_PKT_LUN_BUG |
952 | | AHD_MDFF_WSCBPTR_BUG|AHD_REG_SLOW_SETTLE_BUG |
953 | | AHD_SET_MODE_BUG|AHD_BUSFREEREV_BUG |
954 | | AHD_NONPACKFIFO_BUG|AHD_PACED_NEGTABLE_BUG |
955 | | AHD_FAINT_LED_BUG; |
956 | |
957 | /* |
958 | * IO Cell parameter setup. |
959 | */ |
960 | AHD_SET_PRECOMP(ahd, AHD_PRECOMP_CUTBACK_29); |
961 | |
962 | if ((ahd->flags & AHD_HP_BOARD) == 0) |
963 | AHD_SET_SLEWRATE(ahd, AHD_SLEWRATE_DEF_REVA); |
964 | } else { |
965 | /* This is revision B and newer. */ |
966 | extern uint32_t aic79xx_slowcrc; |
967 | u_int devconfig1; |
968 | |
969 | ahd->features |= AHD_RTI|AHD_NEW_IOCELL_OPTS |
970 | | AHD_NEW_DFCNTRL_OPTS|AHD_FAST_CDB_DELIVERY |
971 | | AHD_BUSFREEREV_BUG; |
972 | ahd->bugs |= AHD_LQOOVERRUN_BUG|AHD_EARLY_REQ_BUG; |
973 | |
974 | /* If the user requested that the SLOWCRC bit to be set. */ |
975 | if (aic79xx_slowcrc) |
976 | ahd->features |= AHD_AIC79XXB_SLOWCRC; |
977 | |
978 | /* |
979 | * Some issues have been resolved in the 7901B. |
980 | */ |
981 | if ((ahd->features & AHD_MULTI_FUNC) != 0) |
982 | ahd->bugs |= AHD_INTCOLLISION_BUG|AHD_ABORT_LQI_BUG; |
983 | |
984 | /* |
985 | * IO Cell parameter setup. |
986 | */ |
987 | AHD_SET_PRECOMP(ahd, AHD_PRECOMP_CUTBACK_29); |
988 | AHD_SET_SLEWRATE(ahd, AHD_SLEWRATE_DEF_REVB); |
989 | AHD_SET_AMPLITUDE(ahd, AHD_AMPLITUDE_DEF); |
990 | |
991 | /* |
992 | * Set the PREQDIS bit for H2B which disables some workaround |
993 | * that doesn't work on regular PCI busses. |
994 | * XXX - Find out exactly what this does from the hardware |
995 | * folks! |
996 | */ |
997 | devconfig1 = ahd_pci_read_config(pci, DEVCONFIG1, /*bytes*/width: 1); |
998 | ahd_pci_write_config(pci, DEVCONFIG1, |
999 | value: devconfig1|PREQDIS, /*bytes*/width: 1); |
1000 | devconfig1 = ahd_pci_read_config(pci, DEVCONFIG1, /*bytes*/width: 1); |
1001 | } |
1002 | |
1003 | return (0); |
1004 | } |
1005 | |