blob: 79c0b6e37a3b92abe629101857f0364a046acfd6 [file] [log] [blame]
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001#define ASC_VERSION "3.3K" /* AdvanSys Driver Version */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002
3/*
4 * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
5 *
6 * Copyright (c) 1995-2000 Advanced System Products, Inc.
7 * Copyright (c) 2000-2001 ConnectCom Solutions, Inc.
8 * All Rights Reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that redistributions of source
12 * code retain the above copyright notice and this comment without
13 * modification.
14 *
15 * As of March 8, 2000 Advanced System Products, Inc. (AdvanSys)
16 * changed its name to ConnectCom Solutions, Inc.
17 *
18 */
19
20/*
21
22 Documentation for the AdvanSys Driver
23
24 A. Linux Kernels Supported by this Driver
25 B. Adapters Supported by this Driver
26 C. Linux source files modified by AdvanSys Driver
27 D. Source Comments
28 E. Driver Compile Time Options and Debugging
29 F. Driver LILO Option
30 G. Tests to run before releasing new driver
31 H. Release History
32 I. Known Problems/Fix List
33 J. Credits (Chronological Order)
34
35 A. Linux Kernels Supported by this Driver
36
37 This driver has been tested in the following Linux kernels: v2.2.18
38 v2.4.0. The driver is supported on v2.2 and v2.4 kernels and on x86,
39 alpha, and PowerPC platforms.
40
41 B. Adapters Supported by this Driver
42
43 AdvanSys (Advanced System Products, Inc.) manufactures the following
44 RISC-based, Bus-Mastering, Fast (10 Mhz) and Ultra (20 Mhz) Narrow
45 (8-bit transfer) SCSI Host Adapters for the ISA, EISA, VL, and PCI
46 buses and RISC-based, Bus-Mastering, Ultra (20 Mhz) Wide (16-bit
47 transfer) SCSI Host Adapters for the PCI bus.
48
49 The CDB counts below indicate the number of SCSI CDB (Command
50 Descriptor Block) requests that can be stored in the RISC chip
51 cache and board LRAM. A CDB is a single SCSI command. The driver
52 detect routine will display the number of CDBs available for each
53 adapter detected. The number of CDBs used by the driver can be
54 lowered in the BIOS by changing the 'Host Queue Size' adapter setting.
55
56 Laptop Products:
57 ABP-480 - Bus-Master CardBus (16 CDB) (2.4 kernel and greater)
58
59 Connectivity Products:
60 ABP510/5150 - Bus-Master ISA (240 CDB)
61 ABP5140 - Bus-Master ISA PnP (16 CDB)
62 ABP5142 - Bus-Master ISA PnP with floppy (16 CDB)
63 ABP902/3902 - Bus-Master PCI (16 CDB)
64 ABP3905 - Bus-Master PCI (16 CDB)
65 ABP915 - Bus-Master PCI (16 CDB)
66 ABP920 - Bus-Master PCI (16 CDB)
67 ABP3922 - Bus-Master PCI (16 CDB)
68 ABP3925 - Bus-Master PCI (16 CDB)
69 ABP930 - Bus-Master PCI (16 CDB)
70 ABP930U - Bus-Master PCI Ultra (16 CDB)
71 ABP930UA - Bus-Master PCI Ultra (16 CDB)
72 ABP960 - Bus-Master PCI MAC/PC (16 CDB)
73 ABP960U - Bus-Master PCI MAC/PC Ultra (16 CDB)
74
75 Single Channel Products:
76 ABP542 - Bus-Master ISA with floppy (240 CDB)
77 ABP742 - Bus-Master EISA (240 CDB)
78 ABP842 - Bus-Master VL (240 CDB)
79 ABP940 - Bus-Master PCI (240 CDB)
80 ABP940U - Bus-Master PCI Ultra (240 CDB)
81 ABP940UA/3940UA - Bus-Master PCI Ultra (240 CDB)
82 ABP970 - Bus-Master PCI MAC/PC (240 CDB)
83 ABP970U - Bus-Master PCI MAC/PC Ultra (240 CDB)
84 ABP3960UA - Bus-Master PCI MAC/PC Ultra (240 CDB)
85 ABP940UW/3940UW - Bus-Master PCI Ultra-Wide (253 CDB)
86 ABP970UW - Bus-Master PCI MAC/PC Ultra-Wide (253 CDB)
87 ABP3940U2W - Bus-Master PCI LVD/Ultra2-Wide (253 CDB)
88
89 Multi-Channel Products:
90 ABP752 - Dual Channel Bus-Master EISA (240 CDB Per Channel)
91 ABP852 - Dual Channel Bus-Master VL (240 CDB Per Channel)
92 ABP950 - Dual Channel Bus-Master PCI (240 CDB Per Channel)
93 ABP950UW - Dual Channel Bus-Master PCI Ultra-Wide (253 CDB Per Channel)
94 ABP980 - Four Channel Bus-Master PCI (240 CDB Per Channel)
95 ABP980U - Four Channel Bus-Master PCI Ultra (240 CDB Per Channel)
96 ABP980UA/3980UA - Four Channel Bus-Master PCI Ultra (16 CDB Per Chan.)
97 ABP3950U2W - Bus-Master PCI LVD/Ultra2-Wide and Ultra-Wide (253 CDB)
98 ABP3950U3W - Bus-Master PCI Dual LVD2/Ultra3-Wide (253 CDB)
99
100 C. Linux source files modified by AdvanSys Driver
101
102 This section for historical purposes documents the changes
103 originally made to the Linux kernel source to add the advansys
104 driver. As Linux has changed some of these files have also
105 been modified.
106
107 1. linux/arch/i386/config.in:
108
109 bool 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS y
110
111 2. linux/drivers/scsi/hosts.c:
112
113 #ifdef CONFIG_SCSI_ADVANSYS
114 #include "advansys.h"
115 #endif
116
Christoph Hellwigd0be4a7d2005-10-31 18:31:40 +0100117 and after "static struct scsi_host_template builtin_scsi_hosts[] =":
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118
119 #ifdef CONFIG_SCSI_ADVANSYS
120 ADVANSYS,
121 #endif
122
123 3. linux/drivers/scsi/Makefile:
124
125 ifdef CONFIG_SCSI_ADVANSYS
126 SCSI_SRCS := $(SCSI_SRCS) advansys.c
127 SCSI_OBJS := $(SCSI_OBJS) advansys.o
128 else
129 SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) advansys.o
130 endif
131
132 4. linux/init/main.c:
133
134 extern void advansys_setup(char *str, int *ints);
135
136 and add the following lines to the bootsetups[] array.
137
138 #ifdef CONFIG_SCSI_ADVANSYS
139 { "advansys=", advansys_setup },
140 #endif
141
142 D. Source Comments
143
144 1. Use tab stops set to 4 for the source files. For vi use 'se tabstops=4'.
145
146 2. This driver should be maintained in multiple files. But to make
147 it easier to include with Linux and to follow Linux conventions,
148 the whole driver is maintained in the source files advansys.h and
149 advansys.c. In this file logical sections of the driver begin with
150 a comment that contains '---'. The following are the logical sections
151 of the driver below.
152
153 --- Linux Version
154 --- Linux Include File
155 --- Driver Options
156 --- Debugging Header
157 --- Asc Library Constants and Macros
158 --- Adv Library Constants and Macros
159 --- Driver Constants and Macros
160 --- Driver Structures
161 --- Driver Data
162 --- Driver Function Prototypes
Christoph Hellwigd0be4a7d2005-10-31 18:31:40 +0100163 --- Linux 'struct scsi_host_template' and advansys_setup() Functions
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 --- Loadable Driver Support
165 --- Miscellaneous Driver Functions
166 --- Functions Required by the Asc Library
167 --- Functions Required by the Adv Library
168 --- Tracing and Debugging Functions
169 --- Asc Library Functions
170 --- Adv Library Functions
171
172 3. The string 'XXX' is used to flag code that needs to be re-written
173 or that contains a problem that needs to be addressed.
174
175 4. I have stripped comments from and reformatted the source for the
176 Asc Library and Adv Library to reduce the size of this file. This
177 source can be found under the following headings. The Asc Library
178 is used to support Narrow Boards. The Adv Library is used to
179 support Wide Boards.
180
181 --- Asc Library Constants and Macros
182 --- Adv Library Constants and Macros
183 --- Asc Library Functions
184 --- Adv Library Functions
185
186 E. Driver Compile Time Options and Debugging
187
188 In this source file the following constants can be defined. They are
189 defined in the source below. Both of these options are enabled by
190 default.
191
192 1. ADVANSYS_ASSERT - Enable driver assertions (Def: Enabled)
193
194 Enabling this option adds assertion logic statements to the
195 driver. If an assertion fails a message will be displayed to
196 the console, but the system will continue to operate. Any
197 assertions encountered should be reported to the person
198 responsible for the driver. Assertion statements may proactively
199 detect problems with the driver and facilitate fixing these
200 problems. Enabling assertions will add a small overhead to the
201 execution of the driver.
202
203 2. ADVANSYS_DEBUG - Enable driver debugging (Def: Disabled)
204
205 Enabling this option adds tracing functions to the driver and
206 the ability to set a driver tracing level at boot time. This
207 option will also export symbols not required outside the driver to
208 the kernel name space. This option is very useful for debugging
209 the driver, but it will add to the size of the driver execution
210 image and add overhead to the execution of the driver.
211
212 The amount of debugging output can be controlled with the global
213 variable 'asc_dbglvl'. The higher the number the more output. By
214 default the debug level is 0.
215
216 If the driver is loaded at boot time and the LILO Driver Option
217 is included in the system, the debug level can be changed by
218 specifying a 5th (ASC_NUM_IOPORT_PROBE + 1) I/O Port. The
219 first three hex digits of the pseudo I/O Port must be set to
220 'deb' and the fourth hex digit specifies the debug level: 0 - F.
221 The following command line will look for an adapter at 0x330
222 and set the debug level to 2.
223
224 linux advansys=0x330,0,0,0,0xdeb2
225
226 If the driver is built as a loadable module this variable can be
227 defined when the driver is loaded. The following insmod command
228 will set the debug level to one.
229
230 insmod advansys.o asc_dbglvl=1
231
232 Debugging Message Levels:
233 0: Errors Only
234 1: High-Level Tracing
235 2-N: Verbose Tracing
236
237 To enable debug output to console, please make sure that:
238
239 a. System and kernel logging is enabled (syslogd, klogd running).
240 b. Kernel messages are routed to console output. Check
241 /etc/syslog.conf for an entry similar to this:
242
243 kern.* /dev/console
244
245 c. klogd is started with the appropriate -c parameter
246 (e.g. klogd -c 8)
247
248 This will cause printk() messages to be be displayed on the
249 current console. Refer to the klogd(8) and syslogd(8) man pages
250 for details.
251
252 Alternatively you can enable printk() to console with this
253 program. However, this is not the 'official' way to do this.
254 Debug output is logged in /var/log/messages.
255
256 main()
257 {
258 syscall(103, 7, 0, 0);
259 }
260
261 Increasing LOG_BUF_LEN in kernel/printk.c to something like
262 40960 allows more debug messages to be buffered in the kernel
263 and written to the console or log file.
264
265 3. ADVANSYS_STATS - Enable statistics (Def: Enabled >= v1.3.0)
266
267 Enabling this option adds statistics collection and display
268 through /proc to the driver. The information is useful for
269 monitoring driver and device performance. It will add to the
270 size of the driver execution image and add minor overhead to
271 the execution of the driver.
272
273 Statistics are maintained on a per adapter basis. Driver entry
274 point call counts and transfer size counts are maintained.
275 Statistics are only available for kernels greater than or equal
276 to v1.3.0 with the CONFIG_PROC_FS (/proc) file system configured.
277
278 AdvanSys SCSI adapter files have the following path name format:
279
280 /proc/scsi/advansys/[0-(ASC_NUM_BOARD_SUPPORTED-1)]
281
282 This information can be displayed with cat. For example:
283
284 cat /proc/scsi/advansys/0
285
286 When ADVANSYS_STATS is not defined the AdvanSys /proc files only
287 contain adapter and device configuration information.
288
289 F. Driver LILO Option
290
291 If init/main.c is modified as described in the 'Directions for Adding
292 the AdvanSys Driver to Linux' section (B.4.) above, the driver will
293 recognize the 'advansys' LILO command line and /etc/lilo.conf option.
294 This option can be used to either disable I/O port scanning or to limit
295 scanning to 1 - 4 I/O ports. Regardless of the option setting EISA and
296 PCI boards will still be searched for and detected. This option only
297 affects searching for ISA and VL boards.
298
299 Examples:
300 1. Eliminate I/O port scanning:
301 boot: linux advansys=
302 or
303 boot: linux advansys=0x0
304 2. Limit I/O port scanning to one I/O port:
305 boot: linux advansys=0x110
306 3. Limit I/O port scanning to four I/O ports:
307 boot: linux advansys=0x110,0x210,0x230,0x330
308
309 For a loadable module the same effect can be achieved by setting
310 the 'asc_iopflag' variable and 'asc_ioport' array when loading
311 the driver, e.g.
312
313 insmod advansys.o asc_iopflag=1 asc_ioport=0x110,0x330
314
315 If ADVANSYS_DEBUG is defined a 5th (ASC_NUM_IOPORT_PROBE + 1)
316 I/O Port may be added to specify the driver debug level. Refer to
317 the 'Driver Compile Time Options and Debugging' section above for
318 more information.
319
320 G. Tests to run before releasing new driver
321
322 1. In the supported kernels verify there are no warning or compile
323 errors when the kernel is built as both a driver and as a module
324 and with the following options:
325
326 ADVANSYS_DEBUG - enabled and disabled
327 CONFIG_SMP - enabled and disabled
328 CONFIG_PROC_FS - enabled and disabled
329
330 2. Run tests on an x86, alpha, and PowerPC with at least one narrow
331 card and one wide card attached to a hard disk and CD-ROM drive:
332 fdisk, mkfs, fsck, bonnie, copy/compare test from the
333 CD-ROM to the hard drive.
334
335 H. Release History
336
337 BETA-1.0 (12/23/95):
338 First Release
339
340 BETA-1.1 (12/28/95):
341 1. Prevent advansys_detect() from being called twice.
342 2. Add LILO 0xdeb[0-f] option to set 'asc_dbglvl'.
343
344 1.2 (1/12/96):
345 1. Prevent re-entrancy in the interrupt handler which
346 resulted in the driver hanging Linux.
347 2. Fix problem that prevented ABP-940 cards from being
348 recognized on some PCI motherboards.
349 3. Add support for the ABP-5140 PnP ISA card.
350 4. Fix check condition return status.
351 5. Add conditionally compiled code for Linux v1.3.X.
352
353 1.3 (2/23/96):
354 1. Fix problem in advansys_biosparam() that resulted in the
355 wrong drive geometry being returned for drives > 1GB with
356 extended translation enabled.
357 2. Add additional tracing during device initialization.
358 3. Change code that only applies to ISA PnP adapter.
359 4. Eliminate 'make dep' warning.
360 5. Try to fix problem with handling resets by increasing their
361 timeout value.
362
363 1.4 (5/8/96):
364 1. Change definitions to eliminate conflicts with other subsystems.
365 2. Add versioning code for the shared interrupt changes.
366 3. Eliminate problem in asc_rmqueue() with iterating after removing
367 a request.
368 4. Remove reset request loop problem from the "Known Problems or
369 Issues" section. This problem was isolated and fixed in the
370 mid-level SCSI driver.
371
372 1.5 (8/8/96):
373 1. Add support for ABP-940U (PCI Ultra) adapter.
Thomas Gleixner1d6f3592006-07-01 19:29:42 -0700374 2. Add support for IRQ sharing by setting the IRQF_SHARED flag for
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 request_irq and supplying a dev_id pointer to both request_irq()
376 and free_irq().
377 3. In AscSearchIOPortAddr11() restore a call to check_region() which
378 should be used before I/O port probing.
379 4. Fix bug in asc_prt_hex() which resulted in the displaying
380 the wrong data.
381 5. Incorporate miscellaneous Asc Library bug fixes and new microcode.
382 6. Change driver versioning to be specific to each Linux sub-level.
383 7. Change statistics gathering to be per adapter instead of global
384 to the driver.
385 8. Add more information and statistics to the adapter /proc file:
386 /proc/scsi/advansys[0...].
387 9. Remove 'cmd_per_lun' from the "Known Problems or Issues" list.
388 This problem has been addressed with the SCSI mid-level changes
389 made in v1.3.89. The advansys_select_queue_depths() function
390 was added for the v1.3.89 changes.
391
392 1.6 (9/10/96):
393 1. Incorporate miscellaneous Asc Library bug fixes and new microcode.
394
395 1.7 (9/25/96):
396 1. Enable clustering and optimize the setting of the maximum number
397 of scatter gather elements for any particular board. Clustering
398 increases CPU utilization, but results in a relatively larger
399 increase in I/O throughput.
400 2. Improve the performance of the request queuing functions by
401 adding a last pointer to the queue structure.
402 3. Correct problems with reset and abort request handling that
403 could have hung or crashed Linux.
404 4. Add more information to the adapter /proc file:
405 /proc/scsi/advansys[0...].
406 5. Remove the request timeout issue form the driver issues list.
407 6. Miscellaneous documentation additions and changes.
408
409 1.8 (10/4/96):
410 1. Make changes to handle the new v2.1.0 kernel memory mapping
411 in which a kernel virtual address may not be equivalent to its
412 bus or DMA memory address.
413 2. Change abort and reset request handling to make it yet even
414 more robust.
415 3. Try to mitigate request starvation by sending ordered requests
416 to heavily loaded, tag queuing enabled devices.
417 4. Maintain statistics on request response time.
418 5. Add request response time statistics and other information to
419 the adapter /proc file: /proc/scsi/advansys[0...].
420
421 1.9 (10/21/96):
422 1. Add conditionally compiled code (ASC_QUEUE_FLOW_CONTROL) to
423 make use of mid-level SCSI driver device queue depth flow
424 control mechanism. This will eliminate aborts caused by a
425 device being unable to keep up with requests and eliminate
426 repeat busy or QUEUE FULL status returned by a device.
427 2. Incorporate miscellaneous Asc Library bug fixes.
428 3. To allow the driver to work in kernels with broken module
429 support set 'cmd_per_lun' if the driver is compiled as a
430 module. This change affects kernels v1.3.89 to present.
431 4. Remove PCI BIOS address from the driver banner. The PCI BIOS
432 is relocated by the motherboard BIOS and its new address can
433 not be determined by the driver.
434 5. Add mid-level SCSI queue depth information to the adapter
435 /proc file: /proc/scsi/advansys[0...].
436
437 2.0 (11/14/96):
438 1. Change allocation of global structures used for device
439 initialization to guarantee they are in DMA-able memory.
440 Previously when the driver was loaded as a module these
441 structures might not have been in DMA-able memory, causing
442 device initialization to fail.
443
444 2.1 (12/30/96):
445 1. In advansys_reset(), if the request is a synchronous reset
446 request, even if the request serial number has changed, then
447 complete the request.
448 2. Add Asc Library bug fixes including new microcode.
449 3. Clear inquiry buffer before using it.
450 4. Correct ifdef typo.
451
452 2.2 (1/15/97):
453 1. Add Asc Library bug fixes including new microcode.
454 2. Add synchronous data transfer rate information to the
455 adapter /proc file: /proc/scsi/advansys[0...].
456 3. Change ADVANSYS_DEBUG to be disabled by default. This
457 will reduce the size of the driver image, eliminate execution
458 overhead, and remove unneeded symbols from the kernel symbol
459 space that were previously added by the driver.
460 4. Add new compile-time option ADVANSYS_ASSERT for assertion
461 code that used to be defined within ADVANSYS_DEBUG. This
462 option is enabled by default.
463
464 2.8 (5/26/97):
465 1. Change version number to 2.8 to synchronize the Linux driver
466 version numbering with other AdvanSys drivers.
467 2. Reformat source files without tabs to present the same view
468 of the file to everyone regardless of the editor tab setting
469 being used.
470 3. Add Asc Library bug fixes.
471
472 3.1A (1/8/98):
473 1. Change version number to 3.1 to indicate that support for
474 Ultra-Wide adapters (ABP-940UW) is included in this release.
475 2. Add Asc Library (Narrow Board) bug fixes.
476 3. Report an underrun condition with the host status byte set
477 to DID_UNDERRUN. Currently DID_UNDERRUN is defined to 0 which
478 causes the underrun condition to be ignored. When Linux defines
479 its own DID_UNDERRUN the constant defined in this file can be
480 removed.
481 4. Add patch to AscWaitTixISRDone().
482 5. Add support for up to 16 different AdvanSys host adapter SCSI
483 channels in one system. This allows four cards with four channels
484 to be used in one system.
485
486 3.1B (1/9/98):
487 1. Handle that PCI register base addresses are not always page
488 aligned even though ioremap() requires that the address argument
489 be page aligned.
490
491 3.1C (1/10/98):
492 1. Update latest BIOS version checked for from the /proc file.
493 2. Don't set microcode SDTR variable at initialization. Instead
494 wait until device capabilities have been detected from an Inquiry
495 command.
496
497 3.1D (1/21/98):
498 1. Improve performance when the driver is compiled as module by
499 allowing up to 64 scatter-gather elements instead of 8.
500
501 3.1E (5/1/98):
502 1. Set time delay in AscWaitTixISRDone() to 1000 ms.
503 2. Include SMP locking changes.
504 3. For v2.1.93 and newer kernels use CONFIG_PCI and new PCI BIOS
505 access functions.
506 4. Update board serial number printing.
Thomas Gleixner1d6f3592006-07-01 19:29:42 -0700507 5. Try allocating an IRQ both with and without the IRQF_DISABLED
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 flag set to allow IRQ sharing with drivers that do not set
Thomas Gleixner1d6f3592006-07-01 19:29:42 -0700509 the IRQF_DISABLED flag. Also display a more descriptive error
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 message if request_irq() fails.
511 6. Update to latest Asc and Adv Libraries.
512
513 3.2A (7/22/99):
514 1. Update Adv Library to 4.16 which includes support for
515 the ASC38C0800 (Ultra2/LVD) IC.
516
517 3.2B (8/23/99):
518 1. Correct PCI compile time option for v2.1.93 and greater
519 kernels, advansys_info() string, and debug compile time
520 option.
521 2. Correct DvcSleepMilliSecond() for v2.1.0 and greater
522 kernels. This caused an LVD detection/BIST problem problem
523 among other things.
524 3. Sort PCI cards by PCI Bus, Slot, Function ascending order
525 to be consistent with the BIOS.
526 4. Update to Asc Library S121 and Adv Library 5.2.
527
528 3.2C (8/24/99):
529 1. Correct PCI card detection bug introduced in 3.2B that
530 prevented PCI cards from being detected in kernels older
531 than v2.1.93.
532
533 3.2D (8/26/99):
534 1. Correct /proc device synchronous speed information display.
535 Also when re-negotiation is pending for a target device
536 note this condition with an * and footnote.
537 2. Correct initialization problem with Ultra-Wide cards that
538 have a pre-3.2 BIOS. A microcode variable changed locations
539 in 3.2 and greater BIOSes which caused WDTR to be attempted
540 erroneously with drives that don't support WDTR.
541
542 3.2E (8/30/99):
543 1. Fix compile error caused by v2.3.13 PCI structure change.
544 2. Remove field from ASCEEP_CONFIG that resulted in an EEPROM
545 checksum error for ISA cards.
546 3. Remove ASC_QUEUE_FLOW_CONTROL conditional code. The mid-level
547 SCSI changes that it depended on were never included in Linux.
548
549 3.2F (9/3/99):
550 1. Handle new initial function code added in v2.3.16 for all
551 driver versions.
552
553 3.2G (9/8/99):
554 1. Fix PCI board detection in v2.3.13 and greater kernels.
555 2. Fix comiple errors in v2.3.X with debugging enabled.
556
557 3.2H (9/13/99):
558 1. Add 64-bit address, long support for Alpha and UltraSPARC.
559 The driver has been verified to work on an Alpha system.
560 2. Add partial byte order handling support for Power PC and
561 other big-endian platforms. This support has not yet been
562 completed or verified.
563 3. For wide boards replace block zeroing of request and
564 scatter-gather structures with individual field initialization
565 to improve performance.
566 4. Correct and clarify ROM BIOS version detection.
567
568 3.2I (10/8/99):
569 1. Update to Adv Library 5.4.
570 2. Add v2.3.19 underrun reporting to asc_isr_callback() and
571 adv_isr_callback(). Remove DID_UNDERRUN constant and other
572 no longer needed code that previously documented the lack
573 of underrun handling.
574
575 3.2J (10/14/99):
576 1. Eliminate compile errors for v2.0 and earlier kernels.
577
578 3.2K (11/15/99):
579 1. Correct debug compile error in asc_prt_adv_scsi_req_q().
580 2. Update Adv Library to 5.5.
581 3. Add ifdef handling for /proc changes added in v2.3.28.
582 4. Increase Wide board scatter-gather list maximum length to
583 255 when the driver is compiled into the kernel.
584
585 3.2L (11/18/99):
586 1. Fix bug in adv_get_sglist() that caused an assertion failure
587 at line 7475. The reqp->sgblkp pointer must be initialized
588 to NULL in adv_get_sglist().
589
590 3.2M (11/29/99):
591 1. Really fix bug in adv_get_sglist().
592 2. Incorporate v2.3.29 changes into driver.
593
594 3.2N (4/1/00):
595 1. Add CONFIG_ISA ifdef code.
596 2. Include advansys_interrupts_enabled name change patch.
597 3. For >= v2.3.28 use new SCSI error handling with new function
598 advansys_eh_bus_reset(). Don't include an abort function
599 because of base library limitations.
600 4. For >= v2.3.28 use per board lock instead of io_request_lock.
601 5. For >= v2.3.28 eliminate advansys_command() and
602 advansys_command_done().
603 6. Add some changes for PowerPC (Big Endian) support, but it isn't
604 working yet.
605 7. Fix "nonexistent resource free" problem that occurred on a module
606 unload for boards with an I/O space >= 255. The 'n_io_port' field
607 is only one byte and can not be used to hold an ioport length more
608 than 255.
609
610 3.3A (4/4/00):
611 1. Update to Adv Library 5.8.
612 2. For wide cards add support for CDBs up to 16 bytes.
613 3. Eliminate warnings when CONFIG_PROC_FS is not defined.
614
615 3.3B (5/1/00):
616 1. Support for PowerPC (Big Endian) wide cards. Narrow cards
617 still need work.
618 2. Change bitfields to shift and mask access for endian
619 portability.
620
621 3.3C (10/13/00):
622 1. Update for latest 2.4 kernel.
623 2. Test ABP-480 CardBus support in 2.4 kernel - works!
624 3. Update to Asc Library S123.
625 4. Update to Adv Library 5.12.
626
627 3.3D (11/22/00):
628 1. Update for latest 2.4 kernel.
629 2. Create patches for 2.2 and 2.4 kernels.
630
631 3.3E (1/9/01):
632 1. Now that 2.4 is released remove ifdef code for kernel versions
633 less than 2.2. The driver is now only supported in kernels 2.2,
634 2.4, and greater.
635 2. Add code to release and acquire the io_request_lock in
636 the driver entrypoint functions: advansys_detect and
637 advansys_queuecommand. In kernel 2.4 the SCSI mid-level driver
638 still holds the io_request_lock on entry to SCSI low-level drivers.
639 This was supposed to be removed before 2.4 was released but never
640 happened. When the mid-level SCSI driver is changed all references
641 to the io_request_lock should be removed from the driver.
642 3. Simplify error handling by removing advansys_abort(),
643 AscAbortSRB(), AscResetDevice(). SCSI bus reset requests are
644 now handled by resetting the SCSI bus and fully re-initializing
645 the chip. This simple method of error recovery has proven to work
646 most reliably after attempts at different methods. Also now only
647 support the "new" error handling method and remove the obsolete
648 error handling interface.
649 4. Fix debug build errors.
650
651 3.3F (1/24/01):
652 1. Merge with ConnectCom version from Andy Kellner which
653 updates Adv Library to 5.14.
654 2. Make PowerPC (Big Endian) work for narrow cards and
655 fix problems writing EEPROM for wide cards.
656 3. Remove interrupts_enabled assertion function.
657
658 3.3G (2/16/01):
659 1. Return an error from narrow boards if passed a 16 byte
660 CDB. The wide board can already handle 16 byte CDBs.
661
662 3.3GJ (4/15/02):
663 1. hacks for lk 2.5 series (D. Gilbert)
664
665 3.3GJD (10/14/02):
666 1. change select_queue_depths to slave_configure
667 2. make cmd_per_lun be sane again
668
669 3.3K [2004/06/24]:
670 1. continuing cleanup for lk 2.6 series
671 2. Fix problem in lk 2.6.7-bk2 that broke PCI wide cards
672 3. Fix problem that oopsed ISA cards
673
674 I. Known Problems/Fix List (XXX)
675
676 1. Need to add memory mapping workaround. Test the memory mapping.
677 If it doesn't work revert to I/O port access. Can a test be done
678 safely?
679 2. Handle an interrupt not working. Keep an interrupt counter in
680 the interrupt handler. In the timeout function if the interrupt
681 has not occurred then print a message and run in polled mode.
682 3. Allow bus type scanning order to be changed.
683 4. Need to add support for target mode commands, cf. CAM XPT.
684
685 J. Credits (Chronological Order)
686
687 Bob Frey <bfrey@turbolinux.com.cn> wrote the AdvanSys SCSI driver
688 and maintained it up to 3.3F. He continues to answer questions
689 and help maintain the driver.
690
691 Nathan Hartwell <mage@cdc3.cdc.net> provided the directions and
692 basis for the Linux v1.3.X changes which were included in the
693 1.2 release.
694
695 Thomas E Zerucha <zerucha@shell.portal.com> pointed out a bug
696 in advansys_biosparam() which was fixed in the 1.3 release.
697
698 Erik Ratcliffe <erik@caldera.com> has done testing of the
699 AdvanSys driver in the Caldera releases.
700
701 Rik van Riel <H.H.vanRiel@fys.ruu.nl> provided a patch to
702 AscWaitTixISRDone() which he found necessary to make the
703 driver work with a SCSI-1 disk.
704
705 Mark Moran <mmoran@mmoran.com> has helped test Ultra-Wide
706 support in the 3.1A driver.
707
708 Doug Gilbert <dgilbert@interlog.com> has made changes and
709 suggestions to improve the driver and done a lot of testing.
710
711 Ken Mort <ken@mort.net> reported a DEBUG compile bug fixed
712 in 3.2K.
713
714 Tom Rini <trini@kernel.crashing.org> provided the CONFIG_ISA
715 patch and helped with PowerPC wide and narrow board support.
716
717 Philip Blundell <philb@gnu.org> provided an
718 advansys_interrupts_enabled patch.
719
720 Dave Jones <dave@denial.force9.co.uk> reported the compiler
721 warnings generated when CONFIG_PROC_FS was not defined in
722 the 3.2M driver.
723
724 Jerry Quinn <jlquinn@us.ibm.com> fixed PowerPC support (endian
725 problems) for wide cards.
726
727 Bryan Henderson <bryanh@giraffe-data.com> helped debug narrow
728 card error handling.
729
730 Manuel Veloso <veloso@pobox.com> worked hard on PowerPC narrow
731 board support and fixed a bug in AscGetEEPConfig().
732
733 Arnaldo Carvalho de Melo <acme@conectiva.com.br> made
734 save_flags/restore_flags changes.
735
736 Andy Kellner <AKellner@connectcom.net> continues the Advansys SCSI
737 driver development for ConnectCom (Version > 3.3F).
738
739 K. ConnectCom (AdvanSys) Contact Information
740
741 Mail: ConnectCom Solutions, Inc.
742 1150 Ringwood Court
743 San Jose, CA 95131
744 Operator/Sales: 1-408-383-9400
745 FAX: 1-408-383-9612
746 Tech Support: 1-408-467-2930
747 Tech Support E-Mail: linux@connectcom.net
748 FTP Site: ftp.connectcom.net (login: anonymous)
749 Web Site: http://www.connectcom.net
750
751*/
752
753/*
754 * --- Linux Include Files
755 */
756
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757#include <linux/module.h>
758
759#if defined(CONFIG_X86) && !defined(CONFIG_ISA)
760#define CONFIG_ISA
761#endif /* CONFIG_X86 && !CONFIG_ISA */
762
763#include <linux/string.h>
764#include <linux/kernel.h>
765#include <linux/types.h>
766#include <linux/ioport.h>
767#include <linux/interrupt.h>
768#include <linux/delay.h>
769#include <linux/slab.h>
770#include <linux/mm.h>
771#include <linux/proc_fs.h>
772#include <linux/init.h>
773#include <linux/blkdev.h>
774#include <linux/stat.h>
775#include <linux/spinlock.h>
776#include <linux/dma-mapping.h>
777
778#include <asm/io.h>
779#include <asm/system.h>
780#include <asm/dma.h>
781
782/* FIXME: (by jejb@steeleye.com) This warning is present for two
783 * reasons:
784 *
785 * 1) This driver badly needs converting to the correct driver model
786 * probing API
787 *
788 * 2) Although all of the necessary command mapping places have the
789 * appropriate dma_map.. APIs, the driver still processes its internal
790 * queue using bus_to_virt() and virt_to_bus() which are illegal under
791 * the API. The entire queue processing structure will need to be
792 * altered to fix this.
793 */
794#warning this driver is still not properly converted to the DMA API
795
796#include <scsi/scsi_cmnd.h>
797#include <scsi/scsi_device.h>
798#include <scsi/scsi_tcq.h>
799#include <scsi/scsi.h>
800#include <scsi/scsi_host.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801#ifdef CONFIG_PCI
802#include <linux/pci.h>
803#endif /* CONFIG_PCI */
804
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805/*
806 * --- Driver Options
807 */
808
809/* Enable driver assertions. */
810#define ADVANSYS_ASSERT
811
812/* Enable driver /proc statistics. */
813#define ADVANSYS_STATS
814
815/* Enable driver tracing. */
816/* #define ADVANSYS_DEBUG */
817
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818/*
819 * --- Asc Library Constants and Macros
820 */
821
822#define ASC_LIB_VERSION_MAJOR 1
823#define ASC_LIB_VERSION_MINOR 24
824#define ASC_LIB_SERIAL_NUMBER 123
825
826/*
827 * Portable Data Types
828 *
829 * Any instance where a 32-bit long or pointer type is assumed
830 * for precision or HW defined structures, the following define
831 * types must be used. In Linux the char, short, and int types
832 * are all consistent at 8, 16, and 32 bits respectively. Pointers
833 * and long types are 64 bits on Alpha and UltraSPARC.
834 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400835#define ASC_PADDR __u32 /* Physical/Bus address data type. */
836#define ASC_VADDR __u32 /* Virtual address data type. */
837#define ASC_DCNT __u32 /* Unsigned Data count type. */
838#define ASC_SDCNT __s32 /* Signed Data count type. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839
840/*
841 * These macros are used to convert a virtual address to a
842 * 32-bit value. This currently can be used on Linux Alpha
843 * which uses 64-bit virtual address but a 32-bit bus address.
844 * This is likely to break in the future, but doing this now
845 * will give us time to change the HW and FW to handle 64-bit
846 * addresses.
847 */
848#define ASC_VADDR_TO_U32 virt_to_bus
849#define ASC_U32_TO_VADDR bus_to_virt
850
851typedef unsigned char uchar;
852
853#ifndef TRUE
854#define TRUE (1)
855#endif
856#ifndef FALSE
857#define FALSE (0)
858#endif
859
860#define EOF (-1)
861#define ERR (-1)
862#define UW_ERR (uint)(0xFFFF)
863#define isodd_word(val) ((((uint)val) & (uint)0x0001) != 0)
864#define AscPCIConfigVendorIDRegister 0x0000
865#define AscPCIConfigDeviceIDRegister 0x0002
866#define AscPCIConfigCommandRegister 0x0004
867#define AscPCIConfigStatusRegister 0x0006
868#define AscPCIConfigRevisionIDRegister 0x0008
869#define AscPCIConfigCacheSize 0x000C
870#define AscPCIConfigLatencyTimer 0x000D
871#define AscPCIIOBaseRegister 0x0010
872#define AscPCICmdRegBits_IOMemBusMaster 0x0007
873#define ASC_PCI_ID2BUS(id) ((id) & 0xFF)
874#define ASC_PCI_ID2DEV(id) (((id) >> 11) & 0x1F)
875#define ASC_PCI_ID2FUNC(id) (((id) >> 8) & 0x7)
876#define ASC_PCI_MKID(bus, dev, func) ((((dev) & 0x1F) << 11) | (((func) & 0x7) << 8) | ((bus) & 0xFF))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877#define ASC_PCI_REVISION_3150 0x02
878#define ASC_PCI_REVISION_3050 0x03
879
880#define ASC_DVCLIB_CALL_DONE (1)
881#define ASC_DVCLIB_CALL_FAILED (0)
882#define ASC_DVCLIB_CALL_ERROR (-1)
883
Dave Jones2672ea82006-08-02 17:11:49 -0400884#define PCI_VENDOR_ID_ASP 0x10cd
885#define PCI_DEVICE_ID_ASP_1200A 0x1100
886#define PCI_DEVICE_ID_ASP_ABP940 0x1200
887#define PCI_DEVICE_ID_ASP_ABP940U 0x1300
888#define PCI_DEVICE_ID_ASP_ABP940UW 0x2300
889#define PCI_DEVICE_ID_38C0800_REV1 0x2500
890#define PCI_DEVICE_ID_38C1600_REV1 0x2700
891
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892/*
893 * Enable CC_VERY_LONG_SG_LIST to support up to 64K element SG lists.
894 * The SRB structure will have to be changed and the ASC_SRB2SCSIQ()
895 * macro re-defined to be able to obtain a ASC_SCSI_Q pointer from the
896 * SRB structure.
897 */
898#define CC_VERY_LONG_SG_LIST 0
899#define ASC_SRB2SCSIQ(srb_ptr) (srb_ptr)
900
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400901#define PortAddr unsigned short /* port address size */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902#define inp(port) inb(port)
903#define outp(port, byte) outb((byte), (port))
904
905#define inpw(port) inw(port)
906#define outpw(port, word) outw((word), (port))
907
908#define ASC_MAX_SG_QUEUE 7
909#define ASC_MAX_SG_LIST 255
910
911#define ASC_CS_TYPE unsigned short
912
913#define ASC_IS_ISA (0x0001)
914#define ASC_IS_ISAPNP (0x0081)
915#define ASC_IS_EISA (0x0002)
916#define ASC_IS_PCI (0x0004)
917#define ASC_IS_PCI_ULTRA (0x0104)
918#define ASC_IS_PCMCIA (0x0008)
919#define ASC_IS_MCA (0x0020)
920#define ASC_IS_VL (0x0040)
921#define ASC_ISA_PNP_PORT_ADDR (0x279)
922#define ASC_ISA_PNP_PORT_WRITE (ASC_ISA_PNP_PORT_ADDR+0x800)
923#define ASC_IS_WIDESCSI_16 (0x0100)
924#define ASC_IS_WIDESCSI_32 (0x0200)
925#define ASC_IS_BIG_ENDIAN (0x8000)
926#define ASC_CHIP_MIN_VER_VL (0x01)
927#define ASC_CHIP_MAX_VER_VL (0x07)
928#define ASC_CHIP_MIN_VER_PCI (0x09)
929#define ASC_CHIP_MAX_VER_PCI (0x0F)
930#define ASC_CHIP_VER_PCI_BIT (0x08)
931#define ASC_CHIP_MIN_VER_ISA (0x11)
932#define ASC_CHIP_MIN_VER_ISA_PNP (0x21)
933#define ASC_CHIP_MAX_VER_ISA (0x27)
934#define ASC_CHIP_VER_ISA_BIT (0x30)
935#define ASC_CHIP_VER_ISAPNP_BIT (0x20)
936#define ASC_CHIP_VER_ASYN_BUG (0x21)
937#define ASC_CHIP_VER_PCI 0x08
938#define ASC_CHIP_VER_PCI_ULTRA_3150 (ASC_CHIP_VER_PCI | 0x02)
939#define ASC_CHIP_VER_PCI_ULTRA_3050 (ASC_CHIP_VER_PCI | 0x03)
940#define ASC_CHIP_MIN_VER_EISA (0x41)
941#define ASC_CHIP_MAX_VER_EISA (0x47)
942#define ASC_CHIP_VER_EISA_BIT (0x40)
943#define ASC_CHIP_LATEST_VER_EISA ((ASC_CHIP_MIN_VER_EISA - 1) + 3)
944#define ASC_MAX_LIB_SUPPORTED_ISA_CHIP_VER 0x21
945#define ASC_MAX_LIB_SUPPORTED_PCI_CHIP_VER 0x0A
946#define ASC_MAX_VL_DMA_ADDR (0x07FFFFFFL)
947#define ASC_MAX_VL_DMA_COUNT (0x07FFFFFFL)
948#define ASC_MAX_PCI_DMA_ADDR (0xFFFFFFFFL)
949#define ASC_MAX_PCI_DMA_COUNT (0xFFFFFFFFL)
950#define ASC_MAX_ISA_DMA_ADDR (0x00FFFFFFL)
951#define ASC_MAX_ISA_DMA_COUNT (0x00FFFFFFL)
952#define ASC_MAX_EISA_DMA_ADDR (0x07FFFFFFL)
953#define ASC_MAX_EISA_DMA_COUNT (0x07FFFFFFL)
954
955#define ASC_SCSI_ID_BITS 3
956#define ASC_SCSI_TIX_TYPE uchar
957#define ASC_ALL_DEVICE_BIT_SET 0xFF
958#define ASC_SCSI_BIT_ID_TYPE uchar
959#define ASC_MAX_TID 7
960#define ASC_MAX_LUN 7
961#define ASC_SCSI_WIDTH_BIT_SET 0xFF
962#define ASC_MAX_SENSE_LEN 32
963#define ASC_MIN_SENSE_LEN 14
964#define ASC_MAX_CDB_LEN 12
965#define ASC_SCSI_RESET_HOLD_TIME_US 60
966
967#define ADV_INQ_CLOCKING_ST_ONLY 0x0
968#define ADV_INQ_CLOCKING_DT_ONLY 0x1
969#define ADV_INQ_CLOCKING_ST_AND_DT 0x3
970
971/*
972 * Inquiry SPC-2 SPI Byte 1 EVPD (Enable Vital Product Data)
973 * and CmdDt (Command Support Data) field bit definitions.
974 */
975#define ADV_INQ_RTN_VPD_AND_CMDDT 0x3
976#define ADV_INQ_RTN_CMDDT_FOR_OP_CODE 0x2
977#define ADV_INQ_RTN_VPD_FOR_PG_CODE 0x1
978#define ADV_INQ_RTN_STD_INQUIRY_DATA 0x0
979
980#define ASC_SCSIDIR_NOCHK 0x00
981#define ASC_SCSIDIR_T2H 0x08
982#define ASC_SCSIDIR_H2T 0x10
983#define ASC_SCSIDIR_NODATA 0x18
984#define SCSI_ASC_NOMEDIA 0x3A
985#define ASC_SRB_HOST(x) ((uchar)((uchar)(x) >> 4))
986#define ASC_SRB_TID(x) ((uchar)((uchar)(x) & (uchar)0x0F))
987#define ASC_SRB_LUN(x) ((uchar)((uint)(x) >> 13))
988#define PUT_CDB1(x) ((uchar)((uint)(x) >> 8))
989#define MS_CMD_DONE 0x00
990#define MS_EXTEND 0x01
991#define MS_SDTR_LEN 0x03
992#define MS_SDTR_CODE 0x01
993#define MS_WDTR_LEN 0x02
994#define MS_WDTR_CODE 0x03
995#define MS_MDP_LEN 0x05
996#define MS_MDP_CODE 0x00
997
998/*
999 * Inquiry data structure and bitfield macros
1000 *
1001 * Only quantities of more than 1 bit are shifted, since the others are
1002 * just tested for true or false. C bitfields aren't portable between big
1003 * and little-endian platforms so they are not used.
1004 */
1005
1006#define ASC_INQ_DVC_TYPE(inq) ((inq)->periph & 0x1f)
1007#define ASC_INQ_QUALIFIER(inq) (((inq)->periph & 0xe0) >> 5)
1008#define ASC_INQ_DVC_TYPE_MOD(inq) ((inq)->devtype & 0x7f)
1009#define ASC_INQ_REMOVABLE(inq) ((inq)->devtype & 0x80)
1010#define ASC_INQ_ANSI_VER(inq) ((inq)->ver & 0x07)
1011#define ASC_INQ_ECMA_VER(inq) (((inq)->ver & 0x38) >> 3)
1012#define ASC_INQ_ISO_VER(inq) (((inq)->ver & 0xc0) >> 6)
1013#define ASC_INQ_RESPONSE_FMT(inq) ((inq)->byte3 & 0x0f)
1014#define ASC_INQ_TERM_IO(inq) ((inq)->byte3 & 0x40)
1015#define ASC_INQ_ASYNC_NOTIF(inq) ((inq)->byte3 & 0x80)
1016#define ASC_INQ_SOFT_RESET(inq) ((inq)->flags & 0x01)
1017#define ASC_INQ_CMD_QUEUE(inq) ((inq)->flags & 0x02)
1018#define ASC_INQ_LINK_CMD(inq) ((inq)->flags & 0x08)
1019#define ASC_INQ_SYNC(inq) ((inq)->flags & 0x10)
1020#define ASC_INQ_WIDE16(inq) ((inq)->flags & 0x20)
1021#define ASC_INQ_WIDE32(inq) ((inq)->flags & 0x40)
1022#define ASC_INQ_REL_ADDR(inq) ((inq)->flags & 0x80)
1023#define ASC_INQ_INFO_UNIT(inq) ((inq)->info & 0x01)
1024#define ASC_INQ_QUICK_ARB(inq) ((inq)->info & 0x02)
1025#define ASC_INQ_CLOCKING(inq) (((inq)->info & 0x0c) >> 2)
1026
1027typedef struct {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001028 uchar periph;
1029 uchar devtype;
1030 uchar ver;
1031 uchar byte3;
1032 uchar add_len;
1033 uchar res1;
1034 uchar res2;
1035 uchar flags;
1036 uchar vendor_id[8];
1037 uchar product_id[16];
1038 uchar product_rev_level[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039} ASC_SCSI_INQUIRY;
1040
1041#define ASC_SG_LIST_PER_Q 7
1042#define QS_FREE 0x00
1043#define QS_READY 0x01
1044#define QS_DISC1 0x02
1045#define QS_DISC2 0x04
1046#define QS_BUSY 0x08
1047#define QS_ABORTED 0x40
1048#define QS_DONE 0x80
1049#define QC_NO_CALLBACK 0x01
1050#define QC_SG_SWAP_QUEUE 0x02
1051#define QC_SG_HEAD 0x04
1052#define QC_DATA_IN 0x08
1053#define QC_DATA_OUT 0x10
1054#define QC_URGENT 0x20
1055#define QC_MSG_OUT 0x40
1056#define QC_REQ_SENSE 0x80
1057#define QCSG_SG_XFER_LIST 0x02
1058#define QCSG_SG_XFER_MORE 0x04
1059#define QCSG_SG_XFER_END 0x08
1060#define QD_IN_PROGRESS 0x00
1061#define QD_NO_ERROR 0x01
1062#define QD_ABORTED_BY_HOST 0x02
1063#define QD_WITH_ERROR 0x04
1064#define QD_INVALID_REQUEST 0x80
1065#define QD_INVALID_HOST_NUM 0x81
1066#define QD_INVALID_DEVICE 0x82
1067#define QD_ERR_INTERNAL 0xFF
1068#define QHSTA_NO_ERROR 0x00
1069#define QHSTA_M_SEL_TIMEOUT 0x11
1070#define QHSTA_M_DATA_OVER_RUN 0x12
1071#define QHSTA_M_DATA_UNDER_RUN 0x12
1072#define QHSTA_M_UNEXPECTED_BUS_FREE 0x13
1073#define QHSTA_M_BAD_BUS_PHASE_SEQ 0x14
1074#define QHSTA_D_QDONE_SG_LIST_CORRUPTED 0x21
1075#define QHSTA_D_ASC_DVC_ERROR_CODE_SET 0x22
1076#define QHSTA_D_HOST_ABORT_FAILED 0x23
1077#define QHSTA_D_EXE_SCSI_Q_FAILED 0x24
1078#define QHSTA_D_EXE_SCSI_Q_BUSY_TIMEOUT 0x25
1079#define QHSTA_D_ASPI_NO_BUF_POOL 0x26
1080#define QHSTA_M_WTM_TIMEOUT 0x41
1081#define QHSTA_M_BAD_CMPL_STATUS_IN 0x42
1082#define QHSTA_M_NO_AUTO_REQ_SENSE 0x43
1083#define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44
1084#define QHSTA_M_TARGET_STATUS_BUSY 0x45
1085#define QHSTA_M_BAD_TAG_CODE 0x46
1086#define QHSTA_M_BAD_QUEUE_FULL_OR_BUSY 0x47
1087#define QHSTA_M_HUNG_REQ_SCSI_BUS_RESET 0x48
1088#define QHSTA_D_LRAM_CMP_ERROR 0x81
1089#define QHSTA_M_MICRO_CODE_ERROR_HALT 0xA1
1090#define ASC_FLAG_SCSIQ_REQ 0x01
1091#define ASC_FLAG_BIOS_SCSIQ_REQ 0x02
1092#define ASC_FLAG_BIOS_ASYNC_IO 0x04
1093#define ASC_FLAG_SRB_LINEAR_ADDR 0x08
1094#define ASC_FLAG_WIN16 0x10
1095#define ASC_FLAG_WIN32 0x20
1096#define ASC_FLAG_ISA_OVER_16MB 0x40
1097#define ASC_FLAG_DOS_VM_CALLBACK 0x80
1098#define ASC_TAG_FLAG_EXTRA_BYTES 0x10
1099#define ASC_TAG_FLAG_DISABLE_DISCONNECT 0x04
1100#define ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX 0x08
1101#define ASC_TAG_FLAG_DISABLE_CHK_COND_INT_HOST 0x40
1102#define ASC_SCSIQ_CPY_BEG 4
1103#define ASC_SCSIQ_SGHD_CPY_BEG 2
1104#define ASC_SCSIQ_B_FWD 0
1105#define ASC_SCSIQ_B_BWD 1
1106#define ASC_SCSIQ_B_STATUS 2
1107#define ASC_SCSIQ_B_QNO 3
1108#define ASC_SCSIQ_B_CNTL 4
1109#define ASC_SCSIQ_B_SG_QUEUE_CNT 5
1110#define ASC_SCSIQ_D_DATA_ADDR 8
1111#define ASC_SCSIQ_D_DATA_CNT 12
1112#define ASC_SCSIQ_B_SENSE_LEN 20
1113#define ASC_SCSIQ_DONE_INFO_BEG 22
1114#define ASC_SCSIQ_D_SRBPTR 22
1115#define ASC_SCSIQ_B_TARGET_IX 26
1116#define ASC_SCSIQ_B_CDB_LEN 28
1117#define ASC_SCSIQ_B_TAG_CODE 29
1118#define ASC_SCSIQ_W_VM_ID 30
1119#define ASC_SCSIQ_DONE_STATUS 32
1120#define ASC_SCSIQ_HOST_STATUS 33
1121#define ASC_SCSIQ_SCSI_STATUS 34
1122#define ASC_SCSIQ_CDB_BEG 36
1123#define ASC_SCSIQ_DW_REMAIN_XFER_ADDR 56
1124#define ASC_SCSIQ_DW_REMAIN_XFER_CNT 60
1125#define ASC_SCSIQ_B_FIRST_SG_WK_QP 48
1126#define ASC_SCSIQ_B_SG_WK_QP 49
1127#define ASC_SCSIQ_B_SG_WK_IX 50
1128#define ASC_SCSIQ_W_ALT_DC1 52
1129#define ASC_SCSIQ_B_LIST_CNT 6
1130#define ASC_SCSIQ_B_CUR_LIST_CNT 7
1131#define ASC_SGQ_B_SG_CNTL 4
1132#define ASC_SGQ_B_SG_HEAD_QP 5
1133#define ASC_SGQ_B_SG_LIST_CNT 6
1134#define ASC_SGQ_B_SG_CUR_LIST_CNT 7
1135#define ASC_SGQ_LIST_BEG 8
1136#define ASC_DEF_SCSI1_QNG 4
1137#define ASC_MAX_SCSI1_QNG 4
1138#define ASC_DEF_SCSI2_QNG 16
1139#define ASC_MAX_SCSI2_QNG 32
1140#define ASC_TAG_CODE_MASK 0x23
1141#define ASC_STOP_REQ_RISC_STOP 0x01
1142#define ASC_STOP_ACK_RISC_STOP 0x03
1143#define ASC_STOP_CLEAN_UP_BUSY_Q 0x10
1144#define ASC_STOP_CLEAN_UP_DISC_Q 0x20
1145#define ASC_STOP_HOST_REQ_RISC_HALT 0x40
1146#define ASC_TIDLUN_TO_IX(tid, lun) (ASC_SCSI_TIX_TYPE)((tid) + ((lun)<<ASC_SCSI_ID_BITS))
1147#define ASC_TID_TO_TARGET_ID(tid) (ASC_SCSI_BIT_ID_TYPE)(0x01 << (tid))
1148#define ASC_TIX_TO_TARGET_ID(tix) (0x01 << ((tix) & ASC_MAX_TID))
1149#define ASC_TIX_TO_TID(tix) ((tix) & ASC_MAX_TID)
1150#define ASC_TID_TO_TIX(tid) ((tid) & ASC_MAX_TID)
1151#define ASC_TIX_TO_LUN(tix) (((tix) >> ASC_SCSI_ID_BITS) & ASC_MAX_LUN)
1152#define ASC_QNO_TO_QADDR(q_no) ((ASC_QADR_BEG)+((int)(q_no) << 6))
1153
1154typedef struct asc_scsiq_1 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001155 uchar status;
1156 uchar q_no;
1157 uchar cntl;
1158 uchar sg_queue_cnt;
1159 uchar target_id;
1160 uchar target_lun;
1161 ASC_PADDR data_addr;
1162 ASC_DCNT data_cnt;
1163 ASC_PADDR sense_addr;
1164 uchar sense_len;
1165 uchar extra_bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166} ASC_SCSIQ_1;
1167
1168typedef struct asc_scsiq_2 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001169 ASC_VADDR srb_ptr;
1170 uchar target_ix;
1171 uchar flag;
1172 uchar cdb_len;
1173 uchar tag_code;
1174 ushort vm_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175} ASC_SCSIQ_2;
1176
1177typedef struct asc_scsiq_3 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001178 uchar done_stat;
1179 uchar host_stat;
1180 uchar scsi_stat;
1181 uchar scsi_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182} ASC_SCSIQ_3;
1183
1184typedef struct asc_scsiq_4 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001185 uchar cdb[ASC_MAX_CDB_LEN];
1186 uchar y_first_sg_list_qp;
1187 uchar y_working_sg_qp;
1188 uchar y_working_sg_ix;
1189 uchar y_res;
1190 ushort x_req_count;
1191 ushort x_reconnect_rtn;
1192 ASC_PADDR x_saved_data_addr;
1193 ASC_DCNT x_saved_data_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194} ASC_SCSIQ_4;
1195
1196typedef struct asc_q_done_info {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001197 ASC_SCSIQ_2 d2;
1198 ASC_SCSIQ_3 d3;
1199 uchar q_status;
1200 uchar q_no;
1201 uchar cntl;
1202 uchar sense_len;
1203 uchar extra_bytes;
1204 uchar res;
1205 ASC_DCNT remain_bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206} ASC_QDONE_INFO;
1207
1208typedef struct asc_sg_list {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001209 ASC_PADDR addr;
1210 ASC_DCNT bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211} ASC_SG_LIST;
1212
1213typedef struct asc_sg_head {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001214 ushort entry_cnt;
1215 ushort queue_cnt;
1216 ushort entry_to_copy;
1217 ushort res;
1218 ASC_SG_LIST sg_list[ASC_MAX_SG_LIST];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219} ASC_SG_HEAD;
1220
1221#define ASC_MIN_SG_LIST 2
1222
1223typedef struct asc_min_sg_head {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001224 ushort entry_cnt;
1225 ushort queue_cnt;
1226 ushort entry_to_copy;
1227 ushort res;
1228 ASC_SG_LIST sg_list[ASC_MIN_SG_LIST];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229} ASC_MIN_SG_HEAD;
1230
1231#define QCX_SORT (0x0001)
1232#define QCX_COALEASE (0x0002)
1233
1234typedef struct asc_scsi_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001235 ASC_SCSIQ_1 q1;
1236 ASC_SCSIQ_2 q2;
1237 uchar *cdbptr;
1238 ASC_SG_HEAD *sg_head;
1239 ushort remain_sg_entry_cnt;
1240 ushort next_sg_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241} ASC_SCSI_Q;
1242
1243typedef struct asc_scsi_req_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001244 ASC_SCSIQ_1 r1;
1245 ASC_SCSIQ_2 r2;
1246 uchar *cdbptr;
1247 ASC_SG_HEAD *sg_head;
1248 uchar *sense_ptr;
1249 ASC_SCSIQ_3 r3;
1250 uchar cdb[ASC_MAX_CDB_LEN];
1251 uchar sense[ASC_MIN_SENSE_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252} ASC_SCSI_REQ_Q;
1253
1254typedef struct asc_scsi_bios_req_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001255 ASC_SCSIQ_1 r1;
1256 ASC_SCSIQ_2 r2;
1257 uchar *cdbptr;
1258 ASC_SG_HEAD *sg_head;
1259 uchar *sense_ptr;
1260 ASC_SCSIQ_3 r3;
1261 uchar cdb[ASC_MAX_CDB_LEN];
1262 uchar sense[ASC_MIN_SENSE_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263} ASC_SCSI_BIOS_REQ_Q;
1264
1265typedef struct asc_risc_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001266 uchar fwd;
1267 uchar bwd;
1268 ASC_SCSIQ_1 i1;
1269 ASC_SCSIQ_2 i2;
1270 ASC_SCSIQ_3 i3;
1271 ASC_SCSIQ_4 i4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272} ASC_RISC_Q;
1273
1274typedef struct asc_sg_list_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001275 uchar seq_no;
1276 uchar q_no;
1277 uchar cntl;
1278 uchar sg_head_qp;
1279 uchar sg_list_cnt;
1280 uchar sg_cur_list_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281} ASC_SG_LIST_Q;
1282
1283typedef struct asc_risc_sg_list_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001284 uchar fwd;
1285 uchar bwd;
1286 ASC_SG_LIST_Q sg;
1287 ASC_SG_LIST sg_list[7];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288} ASC_RISC_SG_LIST_Q;
1289
1290#define ASC_EXE_SCSI_IO_MAX_IDLE_LOOP 0x1000000UL
1291#define ASC_EXE_SCSI_IO_MAX_WAIT_LOOP 1024
1292#define ASCQ_ERR_NO_ERROR 0
1293#define ASCQ_ERR_IO_NOT_FOUND 1
1294#define ASCQ_ERR_LOCAL_MEM 2
1295#define ASCQ_ERR_CHKSUM 3
1296#define ASCQ_ERR_START_CHIP 4
1297#define ASCQ_ERR_INT_TARGET_ID 5
1298#define ASCQ_ERR_INT_LOCAL_MEM 6
1299#define ASCQ_ERR_HALT_RISC 7
1300#define ASCQ_ERR_GET_ASPI_ENTRY 8
1301#define ASCQ_ERR_CLOSE_ASPI 9
1302#define ASCQ_ERR_HOST_INQUIRY 0x0A
1303#define ASCQ_ERR_SAVED_SRB_BAD 0x0B
1304#define ASCQ_ERR_QCNTL_SG_LIST 0x0C
1305#define ASCQ_ERR_Q_STATUS 0x0D
1306#define ASCQ_ERR_WR_SCSIQ 0x0E
1307#define ASCQ_ERR_PC_ADDR 0x0F
1308#define ASCQ_ERR_SYN_OFFSET 0x10
1309#define ASCQ_ERR_SYN_XFER_TIME 0x11
1310#define ASCQ_ERR_LOCK_DMA 0x12
1311#define ASCQ_ERR_UNLOCK_DMA 0x13
1312#define ASCQ_ERR_VDS_CHK_INSTALL 0x14
1313#define ASCQ_ERR_MICRO_CODE_HALT 0x15
1314#define ASCQ_ERR_SET_LRAM_ADDR 0x16
1315#define ASCQ_ERR_CUR_QNG 0x17
1316#define ASCQ_ERR_SG_Q_LINKS 0x18
1317#define ASCQ_ERR_SCSIQ_PTR 0x19
1318#define ASCQ_ERR_ISR_RE_ENTRY 0x1A
1319#define ASCQ_ERR_CRITICAL_RE_ENTRY 0x1B
1320#define ASCQ_ERR_ISR_ON_CRITICAL 0x1C
1321#define ASCQ_ERR_SG_LIST_ODD_ADDRESS 0x1D
1322#define ASCQ_ERR_XFER_ADDRESS_TOO_BIG 0x1E
1323#define ASCQ_ERR_SCSIQ_NULL_PTR 0x1F
1324#define ASCQ_ERR_SCSIQ_BAD_NEXT_PTR 0x20
1325#define ASCQ_ERR_GET_NUM_OF_FREE_Q 0x21
1326#define ASCQ_ERR_SEND_SCSI_Q 0x22
1327#define ASCQ_ERR_HOST_REQ_RISC_HALT 0x23
1328#define ASCQ_ERR_RESET_SDTR 0x24
1329
1330/*
1331 * Warning code values are set in ASC_DVC_VAR 'warn_code'.
1332 */
1333#define ASC_WARN_NO_ERROR 0x0000
1334#define ASC_WARN_IO_PORT_ROTATE 0x0001
1335#define ASC_WARN_EEPROM_CHKSUM 0x0002
1336#define ASC_WARN_IRQ_MODIFIED 0x0004
1337#define ASC_WARN_AUTO_CONFIG 0x0008
1338#define ASC_WARN_CMD_QNG_CONFLICT 0x0010
1339#define ASC_WARN_EEPROM_RECOVER 0x0020
1340#define ASC_WARN_CFG_MSW_RECOVER 0x0040
1341#define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080
1342
1343/*
1344 * Error code values are set in ASC_DVC_VAR 'err_code'.
1345 */
1346#define ASC_IERR_WRITE_EEPROM 0x0001
1347#define ASC_IERR_MCODE_CHKSUM 0x0002
1348#define ASC_IERR_SET_PC_ADDR 0x0004
1349#define ASC_IERR_START_STOP_CHIP 0x0008
1350#define ASC_IERR_IRQ_NO 0x0010
1351#define ASC_IERR_SET_IRQ_NO 0x0020
1352#define ASC_IERR_CHIP_VERSION 0x0040
1353#define ASC_IERR_SET_SCSI_ID 0x0080
1354#define ASC_IERR_GET_PHY_ADDR 0x0100
1355#define ASC_IERR_BAD_SIGNATURE 0x0200
1356#define ASC_IERR_NO_BUS_TYPE 0x0400
1357#define ASC_IERR_SCAM 0x0800
1358#define ASC_IERR_SET_SDTR 0x1000
1359#define ASC_IERR_RW_LRAM 0x8000
1360
1361#define ASC_DEF_IRQ_NO 10
1362#define ASC_MAX_IRQ_NO 15
1363#define ASC_MIN_IRQ_NO 10
1364#define ASC_MIN_REMAIN_Q (0x02)
1365#define ASC_DEF_MAX_TOTAL_QNG (0xF0)
1366#define ASC_MIN_TAG_Q_PER_DVC (0x04)
1367#define ASC_DEF_TAG_Q_PER_DVC (0x04)
1368#define ASC_MIN_FREE_Q ASC_MIN_REMAIN_Q
1369#define ASC_MIN_TOTAL_QNG ((ASC_MAX_SG_QUEUE)+(ASC_MIN_FREE_Q))
1370#define ASC_MAX_TOTAL_QNG 240
1371#define ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG 16
1372#define ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG 8
1373#define ASC_MAX_PCI_INRAM_TOTAL_QNG 20
1374#define ASC_MAX_INRAM_TAG_QNG 16
1375#define ASC_IOADR_TABLE_MAX_IX 11
1376#define ASC_IOADR_GAP 0x10
1377#define ASC_SEARCH_IOP_GAP 0x10
1378#define ASC_MIN_IOP_ADDR (PortAddr)0x0100
1379#define ASC_MAX_IOP_ADDR (PortAddr)0x3F0
1380#define ASC_IOADR_1 (PortAddr)0x0110
1381#define ASC_IOADR_2 (PortAddr)0x0130
1382#define ASC_IOADR_3 (PortAddr)0x0150
1383#define ASC_IOADR_4 (PortAddr)0x0190
1384#define ASC_IOADR_5 (PortAddr)0x0210
1385#define ASC_IOADR_6 (PortAddr)0x0230
1386#define ASC_IOADR_7 (PortAddr)0x0250
1387#define ASC_IOADR_8 (PortAddr)0x0330
1388#define ASC_IOADR_DEF ASC_IOADR_8
1389#define ASC_LIB_SCSIQ_WK_SP 256
1390#define ASC_MAX_SYN_XFER_NO 16
1391#define ASC_SYN_MAX_OFFSET 0x0F
1392#define ASC_DEF_SDTR_OFFSET 0x0F
1393#define ASC_DEF_SDTR_INDEX 0x00
1394#define ASC_SDTR_ULTRA_PCI_10MB_INDEX 0x02
1395#define SYN_XFER_NS_0 25
1396#define SYN_XFER_NS_1 30
1397#define SYN_XFER_NS_2 35
1398#define SYN_XFER_NS_3 40
1399#define SYN_XFER_NS_4 50
1400#define SYN_XFER_NS_5 60
1401#define SYN_XFER_NS_6 70
1402#define SYN_XFER_NS_7 85
1403#define SYN_ULTRA_XFER_NS_0 12
1404#define SYN_ULTRA_XFER_NS_1 19
1405#define SYN_ULTRA_XFER_NS_2 25
1406#define SYN_ULTRA_XFER_NS_3 32
1407#define SYN_ULTRA_XFER_NS_4 38
1408#define SYN_ULTRA_XFER_NS_5 44
1409#define SYN_ULTRA_XFER_NS_6 50
1410#define SYN_ULTRA_XFER_NS_7 57
1411#define SYN_ULTRA_XFER_NS_8 63
1412#define SYN_ULTRA_XFER_NS_9 69
1413#define SYN_ULTRA_XFER_NS_10 75
1414#define SYN_ULTRA_XFER_NS_11 82
1415#define SYN_ULTRA_XFER_NS_12 88
1416#define SYN_ULTRA_XFER_NS_13 94
1417#define SYN_ULTRA_XFER_NS_14 100
1418#define SYN_ULTRA_XFER_NS_15 107
1419
1420typedef struct ext_msg {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001421 uchar msg_type;
1422 uchar msg_len;
1423 uchar msg_req;
1424 union {
1425 struct {
1426 uchar sdtr_xfer_period;
1427 uchar sdtr_req_ack_offset;
1428 } sdtr;
1429 struct {
1430 uchar wdtr_width;
1431 } wdtr;
1432 struct {
1433 uchar mdp_b3;
1434 uchar mdp_b2;
1435 uchar mdp_b1;
1436 uchar mdp_b0;
1437 } mdp;
1438 } u_ext_msg;
1439 uchar res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440} EXT_MSG;
1441
1442#define xfer_period u_ext_msg.sdtr.sdtr_xfer_period
1443#define req_ack_offset u_ext_msg.sdtr.sdtr_req_ack_offset
1444#define wdtr_width u_ext_msg.wdtr.wdtr_width
1445#define mdp_b3 u_ext_msg.mdp_b3
1446#define mdp_b2 u_ext_msg.mdp_b2
1447#define mdp_b1 u_ext_msg.mdp_b1
1448#define mdp_b0 u_ext_msg.mdp_b0
1449
1450typedef struct asc_dvc_cfg {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001451 ASC_SCSI_BIT_ID_TYPE can_tagged_qng;
1452 ASC_SCSI_BIT_ID_TYPE cmd_qng_enabled;
1453 ASC_SCSI_BIT_ID_TYPE disc_enable;
1454 ASC_SCSI_BIT_ID_TYPE sdtr_enable;
1455 uchar chip_scsi_id;
1456 uchar isa_dma_speed;
1457 uchar isa_dma_channel;
1458 uchar chip_version;
1459 ushort lib_serial_no;
1460 ushort lib_version;
1461 ushort mcode_date;
1462 ushort mcode_version;
1463 uchar max_tag_qng[ASC_MAX_TID + 1];
1464 uchar *overrun_buf;
1465 uchar sdtr_period_offset[ASC_MAX_TID + 1];
1466 ushort pci_slot_info;
1467 uchar adapter_info[6];
1468 struct device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469} ASC_DVC_CFG;
1470
1471#define ASC_DEF_DVC_CNTL 0xFFFF
1472#define ASC_DEF_CHIP_SCSI_ID 7
1473#define ASC_DEF_ISA_DMA_SPEED 4
1474#define ASC_INIT_STATE_NULL 0x0000
1475#define ASC_INIT_STATE_BEG_GET_CFG 0x0001
1476#define ASC_INIT_STATE_END_GET_CFG 0x0002
1477#define ASC_INIT_STATE_BEG_SET_CFG 0x0004
1478#define ASC_INIT_STATE_END_SET_CFG 0x0008
1479#define ASC_INIT_STATE_BEG_LOAD_MC 0x0010
1480#define ASC_INIT_STATE_END_LOAD_MC 0x0020
1481#define ASC_INIT_STATE_BEG_INQUIRY 0x0040
1482#define ASC_INIT_STATE_END_INQUIRY 0x0080
1483#define ASC_INIT_RESET_SCSI_DONE 0x0100
1484#define ASC_INIT_STATE_WITHOUT_EEP 0x8000
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485#define ASC_BUG_FIX_IF_NOT_DWB 0x0001
1486#define ASC_BUG_FIX_ASYN_USE_SYN 0x0002
1487#define ASYN_SDTR_DATA_FIX_PCI_REV_AB 0x41
1488#define ASC_MIN_TAGGED_CMD 7
1489#define ASC_MAX_SCSI_RESET_WAIT 30
1490
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001491struct asc_dvc_var; /* Forward Declaration. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001493typedef void (*ASC_ISR_CALLBACK) (struct asc_dvc_var *, ASC_QDONE_INFO *);
1494typedef int (*ASC_EXE_CALLBACK) (struct asc_dvc_var *, ASC_SCSI_Q *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495
1496typedef struct asc_dvc_var {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001497 PortAddr iop_base;
1498 ushort err_code;
1499 ushort dvc_cntl;
1500 ushort bug_fix_cntl;
1501 ushort bus_type;
1502 ASC_ISR_CALLBACK isr_callback;
1503 ASC_EXE_CALLBACK exe_callback;
1504 ASC_SCSI_BIT_ID_TYPE init_sdtr;
1505 ASC_SCSI_BIT_ID_TYPE sdtr_done;
1506 ASC_SCSI_BIT_ID_TYPE use_tagged_qng;
1507 ASC_SCSI_BIT_ID_TYPE unit_not_ready;
1508 ASC_SCSI_BIT_ID_TYPE queue_full_or_busy;
1509 ASC_SCSI_BIT_ID_TYPE start_motor;
1510 uchar scsi_reset_wait;
1511 uchar chip_no;
1512 char is_in_int;
1513 uchar max_total_qng;
1514 uchar cur_total_qng;
1515 uchar in_critical_cnt;
1516 uchar irq_no;
1517 uchar last_q_shortage;
1518 ushort init_state;
1519 uchar cur_dvc_qng[ASC_MAX_TID + 1];
1520 uchar max_dvc_qng[ASC_MAX_TID + 1];
1521 ASC_SCSI_Q *scsiq_busy_head[ASC_MAX_TID + 1];
1522 ASC_SCSI_Q *scsiq_busy_tail[ASC_MAX_TID + 1];
1523 uchar sdtr_period_tbl[ASC_MAX_SYN_XFER_NO];
1524 ASC_DVC_CFG *cfg;
1525 ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer_always;
1526 char redo_scam;
1527 ushort res2;
1528 uchar dos_int13_table[ASC_MAX_TID + 1];
1529 ASC_DCNT max_dma_count;
1530 ASC_SCSI_BIT_ID_TYPE no_scam;
1531 ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer;
1532 uchar max_sdtr_index;
1533 uchar host_init_sdtr_index;
1534 struct asc_board *drv_ptr;
1535 ASC_DCNT uc_break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536} ASC_DVC_VAR;
1537
1538typedef struct asc_dvc_inq_info {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001539 uchar type[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540} ASC_DVC_INQ_INFO;
1541
1542typedef struct asc_cap_info {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001543 ASC_DCNT lba;
1544 ASC_DCNT blk_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545} ASC_CAP_INFO;
1546
1547typedef struct asc_cap_info_array {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001548 ASC_CAP_INFO cap_info[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549} ASC_CAP_INFO_ARRAY;
1550
1551#define ASC_MCNTL_NO_SEL_TIMEOUT (ushort)0x0001
1552#define ASC_MCNTL_NULL_TARGET (ushort)0x0002
1553#define ASC_CNTL_INITIATOR (ushort)0x0001
1554#define ASC_CNTL_BIOS_GT_1GB (ushort)0x0002
1555#define ASC_CNTL_BIOS_GT_2_DISK (ushort)0x0004
1556#define ASC_CNTL_BIOS_REMOVABLE (ushort)0x0008
1557#define ASC_CNTL_NO_SCAM (ushort)0x0010
1558#define ASC_CNTL_INT_MULTI_Q (ushort)0x0080
1559#define ASC_CNTL_NO_LUN_SUPPORT (ushort)0x0040
1560#define ASC_CNTL_NO_VERIFY_COPY (ushort)0x0100
1561#define ASC_CNTL_RESET_SCSI (ushort)0x0200
1562#define ASC_CNTL_INIT_INQUIRY (ushort)0x0400
1563#define ASC_CNTL_INIT_VERBOSE (ushort)0x0800
1564#define ASC_CNTL_SCSI_PARITY (ushort)0x1000
1565#define ASC_CNTL_BURST_MODE (ushort)0x2000
1566#define ASC_CNTL_SDTR_ENABLE_ULTRA (ushort)0x4000
1567#define ASC_EEP_DVC_CFG_BEG_VL 2
1568#define ASC_EEP_MAX_DVC_ADDR_VL 15
1569#define ASC_EEP_DVC_CFG_BEG 32
1570#define ASC_EEP_MAX_DVC_ADDR 45
1571#define ASC_EEP_DEFINED_WORDS 10
1572#define ASC_EEP_MAX_ADDR 63
1573#define ASC_EEP_RES_WORDS 0
1574#define ASC_EEP_MAX_RETRY 20
1575#define ASC_MAX_INIT_BUSY_RETRY 8
1576#define ASC_EEP_ISA_PNP_WSIZE 16
1577
1578/*
1579 * These macros keep the chip SCSI id and ISA DMA speed
1580 * bitfields in board order. C bitfields aren't portable
1581 * between big and little-endian platforms so they are
1582 * not used.
1583 */
1584
1585#define ASC_EEP_GET_CHIP_ID(cfg) ((cfg)->id_speed & 0x0f)
1586#define ASC_EEP_GET_DMA_SPD(cfg) (((cfg)->id_speed & 0xf0) >> 4)
1587#define ASC_EEP_SET_CHIP_ID(cfg, sid) \
1588 ((cfg)->id_speed = ((cfg)->id_speed & 0xf0) | ((sid) & ASC_MAX_TID))
1589#define ASC_EEP_SET_DMA_SPD(cfg, spd) \
1590 ((cfg)->id_speed = ((cfg)->id_speed & 0x0f) | ((spd) & 0x0f) << 4)
1591
1592typedef struct asceep_config {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001593 ushort cfg_lsw;
1594 ushort cfg_msw;
1595 uchar init_sdtr;
1596 uchar disc_enable;
1597 uchar use_cmd_qng;
1598 uchar start_motor;
1599 uchar max_total_qng;
1600 uchar max_tag_qng;
1601 uchar bios_scan;
1602 uchar power_up_wait;
1603 uchar no_scam;
1604 uchar id_speed; /* low order 4 bits is chip scsi id */
1605 /* high order 4 bits is isa dma speed */
1606 uchar dos_int13_table[ASC_MAX_TID + 1];
1607 uchar adapter_info[6];
1608 ushort cntl;
1609 ushort chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610} ASCEEP_CONFIG;
1611
1612#define ASC_PCI_CFG_LSW_SCSI_PARITY 0x0800
1613#define ASC_PCI_CFG_LSW_BURST_MODE 0x0080
1614#define ASC_PCI_CFG_LSW_INTR_ABLE 0x0020
1615
1616#define ASC_EEP_CMD_READ 0x80
1617#define ASC_EEP_CMD_WRITE 0x40
1618#define ASC_EEP_CMD_WRITE_ABLE 0x30
1619#define ASC_EEP_CMD_WRITE_DISABLE 0x00
1620#define ASC_OVERRUN_BSIZE 0x00000048UL
1621#define ASC_CTRL_BREAK_ONCE 0x0001
1622#define ASC_CTRL_BREAK_STAY_IDLE 0x0002
1623#define ASCV_MSGOUT_BEG 0x0000
1624#define ASCV_MSGOUT_SDTR_PERIOD (ASCV_MSGOUT_BEG+3)
1625#define ASCV_MSGOUT_SDTR_OFFSET (ASCV_MSGOUT_BEG+4)
1626#define ASCV_BREAK_SAVED_CODE (ushort)0x0006
1627#define ASCV_MSGIN_BEG (ASCV_MSGOUT_BEG+8)
1628#define ASCV_MSGIN_SDTR_PERIOD (ASCV_MSGIN_BEG+3)
1629#define ASCV_MSGIN_SDTR_OFFSET (ASCV_MSGIN_BEG+4)
1630#define ASCV_SDTR_DATA_BEG (ASCV_MSGIN_BEG+8)
1631#define ASCV_SDTR_DONE_BEG (ASCV_SDTR_DATA_BEG+8)
1632#define ASCV_MAX_DVC_QNG_BEG (ushort)0x0020
1633#define ASCV_BREAK_ADDR (ushort)0x0028
1634#define ASCV_BREAK_NOTIFY_COUNT (ushort)0x002A
1635#define ASCV_BREAK_CONTROL (ushort)0x002C
1636#define ASCV_BREAK_HIT_COUNT (ushort)0x002E
1637
1638#define ASCV_ASCDVC_ERR_CODE_W (ushort)0x0030
1639#define ASCV_MCODE_CHKSUM_W (ushort)0x0032
1640#define ASCV_MCODE_SIZE_W (ushort)0x0034
1641#define ASCV_STOP_CODE_B (ushort)0x0036
1642#define ASCV_DVC_ERR_CODE_B (ushort)0x0037
1643#define ASCV_OVERRUN_PADDR_D (ushort)0x0038
1644#define ASCV_OVERRUN_BSIZE_D (ushort)0x003C
1645#define ASCV_HALTCODE_W (ushort)0x0040
1646#define ASCV_CHKSUM_W (ushort)0x0042
1647#define ASCV_MC_DATE_W (ushort)0x0044
1648#define ASCV_MC_VER_W (ushort)0x0046
1649#define ASCV_NEXTRDY_B (ushort)0x0048
1650#define ASCV_DONENEXT_B (ushort)0x0049
1651#define ASCV_USE_TAGGED_QNG_B (ushort)0x004A
1652#define ASCV_SCSIBUSY_B (ushort)0x004B
1653#define ASCV_Q_DONE_IN_PROGRESS_B (ushort)0x004C
1654#define ASCV_CURCDB_B (ushort)0x004D
1655#define ASCV_RCLUN_B (ushort)0x004E
1656#define ASCV_BUSY_QHEAD_B (ushort)0x004F
1657#define ASCV_DISC1_QHEAD_B (ushort)0x0050
1658#define ASCV_DISC_ENABLE_B (ushort)0x0052
1659#define ASCV_CAN_TAGGED_QNG_B (ushort)0x0053
1660#define ASCV_HOSTSCSI_ID_B (ushort)0x0055
1661#define ASCV_MCODE_CNTL_B (ushort)0x0056
1662#define ASCV_NULL_TARGET_B (ushort)0x0057
1663#define ASCV_FREE_Q_HEAD_W (ushort)0x0058
1664#define ASCV_DONE_Q_TAIL_W (ushort)0x005A
1665#define ASCV_FREE_Q_HEAD_B (ushort)(ASCV_FREE_Q_HEAD_W+1)
1666#define ASCV_DONE_Q_TAIL_B (ushort)(ASCV_DONE_Q_TAIL_W+1)
1667#define ASCV_HOST_FLAG_B (ushort)0x005D
1668#define ASCV_TOTAL_READY_Q_B (ushort)0x0064
1669#define ASCV_VER_SERIAL_B (ushort)0x0065
1670#define ASCV_HALTCODE_SAVED_W (ushort)0x0066
1671#define ASCV_WTM_FLAG_B (ushort)0x0068
1672#define ASCV_RISC_FLAG_B (ushort)0x006A
1673#define ASCV_REQ_SG_LIST_QP (ushort)0x006B
1674#define ASC_HOST_FLAG_IN_ISR 0x01
1675#define ASC_HOST_FLAG_ACK_INT 0x02
1676#define ASC_RISC_FLAG_GEN_INT 0x01
1677#define ASC_RISC_FLAG_REQ_SG_LIST 0x02
1678#define IOP_CTRL (0x0F)
1679#define IOP_STATUS (0x0E)
1680#define IOP_INT_ACK IOP_STATUS
1681#define IOP_REG_IFC (0x0D)
1682#define IOP_SYN_OFFSET (0x0B)
1683#define IOP_EXTRA_CONTROL (0x0D)
1684#define IOP_REG_PC (0x0C)
1685#define IOP_RAM_ADDR (0x0A)
1686#define IOP_RAM_DATA (0x08)
1687#define IOP_EEP_DATA (0x06)
1688#define IOP_EEP_CMD (0x07)
1689#define IOP_VERSION (0x03)
1690#define IOP_CONFIG_HIGH (0x04)
1691#define IOP_CONFIG_LOW (0x02)
1692#define IOP_SIG_BYTE (0x01)
1693#define IOP_SIG_WORD (0x00)
1694#define IOP_REG_DC1 (0x0E)
1695#define IOP_REG_DC0 (0x0C)
1696#define IOP_REG_SB (0x0B)
1697#define IOP_REG_DA1 (0x0A)
1698#define IOP_REG_DA0 (0x08)
1699#define IOP_REG_SC (0x09)
1700#define IOP_DMA_SPEED (0x07)
1701#define IOP_REG_FLAG (0x07)
1702#define IOP_FIFO_H (0x06)
1703#define IOP_FIFO_L (0x04)
1704#define IOP_REG_ID (0x05)
1705#define IOP_REG_QP (0x03)
1706#define IOP_REG_IH (0x02)
1707#define IOP_REG_IX (0x01)
1708#define IOP_REG_AX (0x00)
1709#define IFC_REG_LOCK (0x00)
1710#define IFC_REG_UNLOCK (0x09)
1711#define IFC_WR_EN_FILTER (0x10)
1712#define IFC_RD_NO_EEPROM (0x10)
1713#define IFC_SLEW_RATE (0x20)
1714#define IFC_ACT_NEG (0x40)
1715#define IFC_INP_FILTER (0x80)
1716#define IFC_INIT_DEFAULT (IFC_ACT_NEG | IFC_REG_UNLOCK)
1717#define SC_SEL (uchar)(0x80)
1718#define SC_BSY (uchar)(0x40)
1719#define SC_ACK (uchar)(0x20)
1720#define SC_REQ (uchar)(0x10)
1721#define SC_ATN (uchar)(0x08)
1722#define SC_IO (uchar)(0x04)
1723#define SC_CD (uchar)(0x02)
1724#define SC_MSG (uchar)(0x01)
1725#define SEC_SCSI_CTL (uchar)(0x80)
1726#define SEC_ACTIVE_NEGATE (uchar)(0x40)
1727#define SEC_SLEW_RATE (uchar)(0x20)
1728#define SEC_ENABLE_FILTER (uchar)(0x10)
1729#define ASC_HALT_EXTMSG_IN (ushort)0x8000
1730#define ASC_HALT_CHK_CONDITION (ushort)0x8100
1731#define ASC_HALT_SS_QUEUE_FULL (ushort)0x8200
1732#define ASC_HALT_DISABLE_ASYN_USE_SYN_FIX (ushort)0x8300
1733#define ASC_HALT_ENABLE_ASYN_USE_SYN_FIX (ushort)0x8400
1734#define ASC_HALT_SDTR_REJECTED (ushort)0x4000
1735#define ASC_HALT_HOST_COPY_SG_LIST_TO_RISC ( ushort )0x2000
1736#define ASC_MAX_QNO 0xF8
1737#define ASC_DATA_SEC_BEG (ushort)0x0080
1738#define ASC_DATA_SEC_END (ushort)0x0080
1739#define ASC_CODE_SEC_BEG (ushort)0x0080
1740#define ASC_CODE_SEC_END (ushort)0x0080
1741#define ASC_QADR_BEG (0x4000)
1742#define ASC_QADR_USED (ushort)(ASC_MAX_QNO * 64)
1743#define ASC_QADR_END (ushort)0x7FFF
1744#define ASC_QLAST_ADR (ushort)0x7FC0
1745#define ASC_QBLK_SIZE 0x40
1746#define ASC_BIOS_DATA_QBEG 0xF8
1747#define ASC_MIN_ACTIVE_QNO 0x01
1748#define ASC_QLINK_END 0xFF
1749#define ASC_EEPROM_WORDS 0x10
1750#define ASC_MAX_MGS_LEN 0x10
1751#define ASC_BIOS_ADDR_DEF 0xDC00
1752#define ASC_BIOS_SIZE 0x3800
1753#define ASC_BIOS_RAM_OFF 0x3800
1754#define ASC_BIOS_RAM_SIZE 0x800
1755#define ASC_BIOS_MIN_ADDR 0xC000
1756#define ASC_BIOS_MAX_ADDR 0xEC00
1757#define ASC_BIOS_BANK_SIZE 0x0400
1758#define ASC_MCODE_START_ADDR 0x0080
1759#define ASC_CFG0_HOST_INT_ON 0x0020
1760#define ASC_CFG0_BIOS_ON 0x0040
1761#define ASC_CFG0_VERA_BURST_ON 0x0080
1762#define ASC_CFG0_SCSI_PARITY_ON 0x0800
1763#define ASC_CFG1_SCSI_TARGET_ON 0x0080
1764#define ASC_CFG1_LRAM_8BITS_ON 0x0800
1765#define ASC_CFG_MSW_CLR_MASK 0x3080
1766#define CSW_TEST1 (ASC_CS_TYPE)0x8000
1767#define CSW_AUTO_CONFIG (ASC_CS_TYPE)0x4000
1768#define CSW_RESERVED1 (ASC_CS_TYPE)0x2000
1769#define CSW_IRQ_WRITTEN (ASC_CS_TYPE)0x1000
1770#define CSW_33MHZ_SELECTED (ASC_CS_TYPE)0x0800
1771#define CSW_TEST2 (ASC_CS_TYPE)0x0400
1772#define CSW_TEST3 (ASC_CS_TYPE)0x0200
1773#define CSW_RESERVED2 (ASC_CS_TYPE)0x0100
1774#define CSW_DMA_DONE (ASC_CS_TYPE)0x0080
1775#define CSW_FIFO_RDY (ASC_CS_TYPE)0x0040
1776#define CSW_EEP_READ_DONE (ASC_CS_TYPE)0x0020
1777#define CSW_HALTED (ASC_CS_TYPE)0x0010
1778#define CSW_SCSI_RESET_ACTIVE (ASC_CS_TYPE)0x0008
1779#define CSW_PARITY_ERR (ASC_CS_TYPE)0x0004
1780#define CSW_SCSI_RESET_LATCH (ASC_CS_TYPE)0x0002
1781#define CSW_INT_PENDING (ASC_CS_TYPE)0x0001
1782#define CIW_CLR_SCSI_RESET_INT (ASC_CS_TYPE)0x1000
1783#define CIW_INT_ACK (ASC_CS_TYPE)0x0100
1784#define CIW_TEST1 (ASC_CS_TYPE)0x0200
1785#define CIW_TEST2 (ASC_CS_TYPE)0x0400
1786#define CIW_SEL_33MHZ (ASC_CS_TYPE)0x0800
1787#define CIW_IRQ_ACT (ASC_CS_TYPE)0x1000
1788#define CC_CHIP_RESET (uchar)0x80
1789#define CC_SCSI_RESET (uchar)0x40
1790#define CC_HALT (uchar)0x20
1791#define CC_SINGLE_STEP (uchar)0x10
1792#define CC_DMA_ABLE (uchar)0x08
1793#define CC_TEST (uchar)0x04
1794#define CC_BANK_ONE (uchar)0x02
1795#define CC_DIAG (uchar)0x01
1796#define ASC_1000_ID0W 0x04C1
1797#define ASC_1000_ID0W_FIX 0x00C1
1798#define ASC_1000_ID1B 0x25
1799#define ASC_EISA_BIG_IOP_GAP (0x1C30-0x0C50)
1800#define ASC_EISA_SMALL_IOP_GAP (0x0020)
1801#define ASC_EISA_MIN_IOP_ADDR (0x0C30)
1802#define ASC_EISA_MAX_IOP_ADDR (0xFC50)
1803#define ASC_EISA_REV_IOP_MASK (0x0C83)
1804#define ASC_EISA_PID_IOP_MASK (0x0C80)
1805#define ASC_EISA_CFG_IOP_MASK (0x0C86)
1806#define ASC_GET_EISA_SLOT(iop) (PortAddr)((iop) & 0xF000)
1807#define ASC_EISA_ID_740 0x01745004UL
1808#define ASC_EISA_ID_750 0x01755004UL
1809#define INS_HALTINT (ushort)0x6281
1810#define INS_HALT (ushort)0x6280
1811#define INS_SINT (ushort)0x6200
1812#define INS_RFLAG_WTM (ushort)0x7380
1813#define ASC_MC_SAVE_CODE_WSIZE 0x500
1814#define ASC_MC_SAVE_DATA_WSIZE 0x40
1815
1816typedef struct asc_mc_saved {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001817 ushort data[ASC_MC_SAVE_DATA_WSIZE];
1818 ushort code[ASC_MC_SAVE_CODE_WSIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819} ASC_MC_SAVED;
1820
1821#define AscGetQDoneInProgress(port) AscReadLramByte((port), ASCV_Q_DONE_IN_PROGRESS_B)
1822#define AscPutQDoneInProgress(port, val) AscWriteLramByte((port), ASCV_Q_DONE_IN_PROGRESS_B, val)
1823#define AscGetVarFreeQHead(port) AscReadLramWord((port), ASCV_FREE_Q_HEAD_W)
1824#define AscGetVarDoneQTail(port) AscReadLramWord((port), ASCV_DONE_Q_TAIL_W)
1825#define AscPutVarFreeQHead(port, val) AscWriteLramWord((port), ASCV_FREE_Q_HEAD_W, val)
1826#define AscPutVarDoneQTail(port, val) AscWriteLramWord((port), ASCV_DONE_Q_TAIL_W, val)
1827#define AscGetRiscVarFreeQHead(port) AscReadLramByte((port), ASCV_NEXTRDY_B)
1828#define AscGetRiscVarDoneQTail(port) AscReadLramByte((port), ASCV_DONENEXT_B)
1829#define AscPutRiscVarFreeQHead(port, val) AscWriteLramByte((port), ASCV_NEXTRDY_B, val)
1830#define AscPutRiscVarDoneQTail(port, val) AscWriteLramByte((port), ASCV_DONENEXT_B, val)
1831#define AscPutMCodeSDTRDoneAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id), (data));
1832#define AscGetMCodeSDTRDoneAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id));
1833#define AscPutMCodeInitSDTRAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id), data);
1834#define AscGetMCodeInitSDTRAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id));
1835#define AscSynIndexToPeriod(index) (uchar)(asc_dvc->sdtr_period_tbl[ (index) ])
1836#define AscGetChipSignatureByte(port) (uchar)inp((port)+IOP_SIG_BYTE)
1837#define AscGetChipSignatureWord(port) (ushort)inpw((port)+IOP_SIG_WORD)
1838#define AscGetChipVerNo(port) (uchar)inp((port)+IOP_VERSION)
1839#define AscGetChipCfgLsw(port) (ushort)inpw((port)+IOP_CONFIG_LOW)
1840#define AscGetChipCfgMsw(port) (ushort)inpw((port)+IOP_CONFIG_HIGH)
1841#define AscSetChipCfgLsw(port, data) outpw((port)+IOP_CONFIG_LOW, data)
1842#define AscSetChipCfgMsw(port, data) outpw((port)+IOP_CONFIG_HIGH, data)
1843#define AscGetChipEEPCmd(port) (uchar)inp((port)+IOP_EEP_CMD)
1844#define AscSetChipEEPCmd(port, data) outp((port)+IOP_EEP_CMD, data)
1845#define AscGetChipEEPData(port) (ushort)inpw((port)+IOP_EEP_DATA)
1846#define AscSetChipEEPData(port, data) outpw((port)+IOP_EEP_DATA, data)
1847#define AscGetChipLramAddr(port) (ushort)inpw((PortAddr)((port)+IOP_RAM_ADDR))
1848#define AscSetChipLramAddr(port, addr) outpw((PortAddr)((port)+IOP_RAM_ADDR), addr)
1849#define AscGetChipLramData(port) (ushort)inpw((port)+IOP_RAM_DATA)
1850#define AscSetChipLramData(port, data) outpw((port)+IOP_RAM_DATA, data)
1851#define AscGetChipIFC(port) (uchar)inp((port)+IOP_REG_IFC)
1852#define AscSetChipIFC(port, data) outp((port)+IOP_REG_IFC, data)
1853#define AscGetChipStatus(port) (ASC_CS_TYPE)inpw((port)+IOP_STATUS)
1854#define AscSetChipStatus(port, cs_val) outpw((port)+IOP_STATUS, cs_val)
1855#define AscGetChipControl(port) (uchar)inp((port)+IOP_CTRL)
1856#define AscSetChipControl(port, cc_val) outp((port)+IOP_CTRL, cc_val)
1857#define AscGetChipSyn(port) (uchar)inp((port)+IOP_SYN_OFFSET)
1858#define AscSetChipSyn(port, data) outp((port)+IOP_SYN_OFFSET, data)
1859#define AscSetPCAddr(port, data) outpw((port)+IOP_REG_PC, data)
1860#define AscGetPCAddr(port) (ushort)inpw((port)+IOP_REG_PC)
1861#define AscIsIntPending(port) (AscGetChipStatus(port) & (CSW_INT_PENDING | CSW_SCSI_RESET_LATCH))
1862#define AscGetChipScsiID(port) ((AscGetChipCfgLsw(port) >> 8) & ASC_MAX_TID)
1863#define AscGetExtraControl(port) (uchar)inp((port)+IOP_EXTRA_CONTROL)
1864#define AscSetExtraControl(port, data) outp((port)+IOP_EXTRA_CONTROL, data)
1865#define AscReadChipAX(port) (ushort)inpw((port)+IOP_REG_AX)
1866#define AscWriteChipAX(port, data) outpw((port)+IOP_REG_AX, data)
1867#define AscReadChipIX(port) (uchar)inp((port)+IOP_REG_IX)
1868#define AscWriteChipIX(port, data) outp((port)+IOP_REG_IX, data)
1869#define AscReadChipIH(port) (ushort)inpw((port)+IOP_REG_IH)
1870#define AscWriteChipIH(port, data) outpw((port)+IOP_REG_IH, data)
1871#define AscReadChipQP(port) (uchar)inp((port)+IOP_REG_QP)
1872#define AscWriteChipQP(port, data) outp((port)+IOP_REG_QP, data)
1873#define AscReadChipFIFO_L(port) (ushort)inpw((port)+IOP_REG_FIFO_L)
1874#define AscWriteChipFIFO_L(port, data) outpw((port)+IOP_REG_FIFO_L, data)
1875#define AscReadChipFIFO_H(port) (ushort)inpw((port)+IOP_REG_FIFO_H)
1876#define AscWriteChipFIFO_H(port, data) outpw((port)+IOP_REG_FIFO_H, data)
1877#define AscReadChipDmaSpeed(port) (uchar)inp((port)+IOP_DMA_SPEED)
1878#define AscWriteChipDmaSpeed(port, data) outp((port)+IOP_DMA_SPEED, data)
1879#define AscReadChipDA0(port) (ushort)inpw((port)+IOP_REG_DA0)
1880#define AscWriteChipDA0(port) outpw((port)+IOP_REG_DA0, data)
1881#define AscReadChipDA1(port) (ushort)inpw((port)+IOP_REG_DA1)
1882#define AscWriteChipDA1(port) outpw((port)+IOP_REG_DA1, data)
1883#define AscReadChipDC0(port) (ushort)inpw((port)+IOP_REG_DC0)
1884#define AscWriteChipDC0(port) outpw((port)+IOP_REG_DC0, data)
1885#define AscReadChipDC1(port) (ushort)inpw((port)+IOP_REG_DC1)
1886#define AscWriteChipDC1(port) outpw((port)+IOP_REG_DC1, data)
1887#define AscReadChipDvcID(port) (uchar)inp((port)+IOP_REG_ID)
1888#define AscWriteChipDvcID(port, data) outp((port)+IOP_REG_ID, data)
1889
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001890static int AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg);
1891static int AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg);
1892static void AscWaitEEPRead(void);
1893static void AscWaitEEPWrite(void);
1894static ushort AscReadEEPWord(PortAddr, uchar);
1895static ushort AscWriteEEPWord(PortAddr, uchar, ushort);
1896static ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
1897static int AscSetEEPConfigOnce(PortAddr, ASCEEP_CONFIG *, ushort);
1898static int AscSetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
1899static int AscStartChip(PortAddr);
1900static int AscStopChip(PortAddr);
1901static void AscSetChipIH(PortAddr, ushort);
1902static int AscIsChipHalted(PortAddr);
1903static void AscAckInterrupt(PortAddr);
1904static void AscDisableInterrupt(PortAddr);
1905static void AscEnableInterrupt(PortAddr);
1906static void AscSetBank(PortAddr, uchar);
1907static int AscResetChipAndScsiBus(ASC_DVC_VAR *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001909static ushort AscGetIsaDmaChannel(PortAddr);
1910static ushort AscSetIsaDmaChannel(PortAddr, ushort);
1911static uchar AscSetIsaDmaSpeed(PortAddr, uchar);
1912static uchar AscGetIsaDmaSpeed(PortAddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001914static uchar AscReadLramByte(PortAddr, ushort);
1915static ushort AscReadLramWord(PortAddr, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001917static ASC_DCNT AscReadLramDWord(PortAddr, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001919static void AscWriteLramWord(PortAddr, ushort, ushort);
1920static void AscWriteLramByte(PortAddr, ushort, uchar);
1921static ASC_DCNT AscMemSumLramWord(PortAddr, ushort, int);
1922static void AscMemWordSetLram(PortAddr, ushort, ushort, int);
1923static void AscMemWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
1924static void AscMemDWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
1925static void AscMemWordCopyPtrFromLram(PortAddr, ushort, uchar *, int);
1926static ushort AscInitAscDvcVar(ASC_DVC_VAR *);
1927static ushort AscInitFromEEP(ASC_DVC_VAR *);
1928static ushort AscInitFromAscDvcVar(ASC_DVC_VAR *);
1929static ushort AscInitMicroCodeVar(ASC_DVC_VAR *);
1930static int AscTestExternalLram(ASC_DVC_VAR *);
1931static uchar AscMsgOutSDTR(ASC_DVC_VAR *, uchar, uchar);
1932static uchar AscCalSDTRData(ASC_DVC_VAR *, uchar, uchar);
1933static void AscSetChipSDTR(PortAddr, uchar, uchar);
1934static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *, uchar);
1935static uchar AscAllocFreeQueue(PortAddr, uchar);
1936static uchar AscAllocMultipleFreeQueue(PortAddr, uchar, uchar);
1937static int AscHostReqRiscHalt(PortAddr);
1938static int AscStopQueueExe(PortAddr);
1939static int AscSendScsiQueue(ASC_DVC_VAR *,
1940 ASC_SCSI_Q *scsiq, uchar n_q_required);
1941static int AscPutReadyQueue(ASC_DVC_VAR *, ASC_SCSI_Q *, uchar);
1942static int AscPutReadySgListQueue(ASC_DVC_VAR *, ASC_SCSI_Q *, uchar);
1943static int AscSetChipSynRegAtID(PortAddr, uchar, uchar);
1944static int AscSetRunChipSynRegAtID(PortAddr, uchar, uchar);
1945static ushort AscInitLram(ASC_DVC_VAR *);
1946static ushort AscInitQLinkVar(ASC_DVC_VAR *);
1947static int AscSetLibErrorCode(ASC_DVC_VAR *, ushort);
1948static int AscIsrChipHalted(ASC_DVC_VAR *);
1949static uchar _AscCopyLramScsiDoneQ(PortAddr, ushort,
1950 ASC_QDONE_INFO *, ASC_DCNT);
1951static int AscIsrQDone(ASC_DVC_VAR *);
1952static int AscCompareString(uchar *, uchar *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001954static ushort AscGetEisaChipCfg(PortAddr);
1955static ASC_DCNT AscGetEisaProductID(PortAddr);
1956static PortAddr AscSearchIOPortAddrEISA(PortAddr);
1957static PortAddr AscSearchIOPortAddr11(PortAddr);
1958static PortAddr AscSearchIOPortAddr(PortAddr, ushort);
1959static void AscSetISAPNPWaitForKey(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001961static uchar AscGetChipScsiCtrl(PortAddr);
1962static uchar AscSetChipScsiID(PortAddr, uchar);
1963static uchar AscGetChipVersion(PortAddr, ushort);
1964static ushort AscGetChipBusType(PortAddr);
1965static ASC_DCNT AscLoadMicroCode(PortAddr, ushort, uchar *, ushort);
1966static int AscFindSignature(PortAddr);
1967static void AscToggleIRQAct(PortAddr);
1968static uchar AscGetChipIRQ(PortAddr, ushort);
1969static uchar AscSetChipIRQ(PortAddr, uchar, ushort);
1970static ushort AscGetChipBiosAddress(PortAddr, ushort);
1971static inline ulong DvcEnterCritical(void);
1972static inline void DvcLeaveCritical(ulong);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001974static uchar DvcReadPCIConfigByte(ASC_DVC_VAR *, ushort);
1975static void DvcWritePCIConfigByte(ASC_DVC_VAR *, ushort, uchar);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976#endif /* CONFIG_PCI */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001977static ushort AscGetChipBiosAddress(PortAddr, ushort);
1978static void DvcSleepMilliSecond(ASC_DCNT);
1979static void DvcDelayNanoSecond(ASC_DVC_VAR *, ASC_DCNT);
1980static void DvcPutScsiQ(PortAddr, ushort, uchar *, int);
1981static void DvcGetQinfo(PortAddr, ushort, uchar *, int);
1982static ushort AscInitGetConfig(ASC_DVC_VAR *);
1983static ushort AscInitSetConfig(ASC_DVC_VAR *);
1984static ushort AscInitAsc1000Driver(ASC_DVC_VAR *);
1985static void AscAsyncFix(ASC_DVC_VAR *, uchar, ASC_SCSI_INQUIRY *);
1986static int AscTagQueuingSafe(ASC_SCSI_INQUIRY *);
1987static void AscInquiryHandling(ASC_DVC_VAR *, uchar, ASC_SCSI_INQUIRY *);
1988static int AscExeScsiQueue(ASC_DVC_VAR *, ASC_SCSI_Q *);
1989static int AscISR(ASC_DVC_VAR *);
1990static uint AscGetNumOfFreeQueue(ASC_DVC_VAR *, uchar, uchar);
1991static int AscSgListToQueue(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001993static void AscEnableIsaDma(uchar);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001995static ASC_DCNT AscGetMaxDmaCount(ushort);
1996static const char *advansys_info(struct Scsi_Host *shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997
1998/*
1999 * --- Adv Library Constants and Macros
2000 */
2001
2002#define ADV_LIB_VERSION_MAJOR 5
2003#define ADV_LIB_VERSION_MINOR 14
2004
2005/*
2006 * Define Adv Library required special types.
2007 */
2008
2009/*
2010 * Portable Data Types
2011 *
2012 * Any instance where a 32-bit long or pointer type is assumed
2013 * for precision or HW defined structures, the following define
2014 * types must be used. In Linux the char, short, and int types
2015 * are all consistent at 8, 16, and 32 bits respectively. Pointers
2016 * and long types are 64 bits on Alpha and UltraSPARC.
2017 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002018#define ADV_PADDR __u32 /* Physical address data type. */
2019#define ADV_VADDR __u32 /* Virtual address data type. */
2020#define ADV_DCNT __u32 /* Unsigned Data count type. */
2021#define ADV_SDCNT __s32 /* Signed Data count type. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022
2023/*
2024 * These macros are used to convert a virtual address to a
2025 * 32-bit value. This currently can be used on Linux Alpha
2026 * which uses 64-bit virtual address but a 32-bit bus address.
2027 * This is likely to break in the future, but doing this now
2028 * will give us time to change the HW and FW to handle 64-bit
2029 * addresses.
2030 */
2031#define ADV_VADDR_TO_U32 virt_to_bus
2032#define ADV_U32_TO_VADDR bus_to_virt
2033
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002034#define AdvPortAddr void __iomem * /* Virtual memory address size */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035
2036/*
2037 * Define Adv Library required memory access macros.
2038 */
2039#define ADV_MEM_READB(addr) readb(addr)
2040#define ADV_MEM_READW(addr) readw(addr)
2041#define ADV_MEM_WRITEB(addr, byte) writeb(byte, addr)
2042#define ADV_MEM_WRITEW(addr, word) writew(word, addr)
2043#define ADV_MEM_WRITEDW(addr, dword) writel(dword, addr)
2044
2045#define ADV_CARRIER_COUNT (ASC_DEF_MAX_HOST_QNG + 15)
2046
2047/*
2048 * For wide boards a CDB length maximum of 16 bytes
2049 * is supported.
2050 */
2051#define ADV_MAX_CDB_LEN 16
2052
2053/*
2054 * Define total number of simultaneous maximum element scatter-gather
2055 * request blocks per wide adapter. ASC_DEF_MAX_HOST_QNG (253) is the
2056 * maximum number of outstanding commands per wide host adapter. Each
2057 * command uses one or more ADV_SG_BLOCK each with 15 scatter-gather
2058 * elements. Allow each command to have at least one ADV_SG_BLOCK structure.
2059 * This allows about 15 commands to have the maximum 17 ADV_SG_BLOCK
2060 * structures or 255 scatter-gather elements.
2061 *
2062 */
2063#define ADV_TOT_SG_BLOCK ASC_DEF_MAX_HOST_QNG
2064
2065/*
2066 * Define Adv Library required maximum number of scatter-gather
2067 * elements per request.
2068 */
2069#define ADV_MAX_SG_LIST 255
2070
2071/* Number of SG blocks needed. */
2072#define ADV_NUM_SG_BLOCK \
2073 ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK)
2074
2075/* Total contiguous memory needed for SG blocks. */
2076#define ADV_SG_TOTAL_MEM_SIZE \
2077 (sizeof(ADV_SG_BLOCK) * ADV_NUM_SG_BLOCK)
2078
2079#define ADV_PAGE_SIZE PAGE_SIZE
2080
2081#define ADV_NUM_PAGE_CROSSING \
2082 ((ADV_SG_TOTAL_MEM_SIZE + (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
2083
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084#define ADV_EEP_DVC_CFG_BEGIN (0x00)
2085#define ADV_EEP_DVC_CFG_END (0x15)
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002086#define ADV_EEP_DVC_CTL_BEGIN (0x16) /* location of OEM name */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087#define ADV_EEP_MAX_WORD_ADDR (0x1E)
2088
2089#define ADV_EEP_DELAY_MS 100
2090
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002091#define ADV_EEPROM_BIG_ENDIAN 0x8000 /* EEPROM Bit 15 */
2092#define ADV_EEPROM_BIOS_ENABLE 0x4000 /* EEPROM Bit 14 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093/*
2094 * For the ASC3550 Bit 13 is Termination Polarity control bit.
2095 * For later ICs Bit 13 controls whether the CIS (Card Information
2096 * Service Section) is loaded from EEPROM.
2097 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002098#define ADV_EEPROM_TERM_POL 0x2000 /* EEPROM Bit 13 */
2099#define ADV_EEPROM_CIS_LD 0x2000 /* EEPROM Bit 13 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100/*
2101 * ASC38C1600 Bit 11
2102 *
2103 * If EEPROM Bit 11 is 0 for Function 0, then Function 0 will specify
2104 * INT A in the PCI Configuration Space Int Pin field. If it is 1, then
2105 * Function 0 will specify INT B.
2106 *
2107 * If EEPROM Bit 11 is 0 for Function 1, then Function 1 will specify
2108 * INT B in the PCI Configuration Space Int Pin field. If it is 1, then
2109 * Function 1 will specify INT A.
2110 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002111#define ADV_EEPROM_INTAB 0x0800 /* EEPROM Bit 11 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002113typedef struct adveep_3550_config {
2114 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002116 ushort cfg_lsw; /* 00 power up initialization */
2117 /* bit 13 set - Term Polarity Control */
2118 /* bit 14 set - BIOS Enable */
2119 /* bit 15 set - Big Endian Mode */
2120 ushort cfg_msw; /* 01 unused */
2121 ushort disc_enable; /* 02 disconnect enable */
2122 ushort wdtr_able; /* 03 Wide DTR able */
2123 ushort sdtr_able; /* 04 Synchronous DTR able */
2124 ushort start_motor; /* 05 send start up motor */
2125 ushort tagqng_able; /* 06 tag queuing able */
2126 ushort bios_scan; /* 07 BIOS device control */
2127 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002129 uchar adapter_scsi_id; /* 09 Host Adapter ID */
2130 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002132 uchar scsi_reset_delay; /* 10 reset delay */
2133 uchar bios_id_lun; /* first boot device scsi id & lun */
2134 /* high nibble is lun */
2135 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002136
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002137 uchar termination; /* 11 0 - automatic */
2138 /* 1 - low off / high off */
2139 /* 2 - low off / high on */
2140 /* 3 - low on / high on */
2141 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002143 uchar reserved1; /* reserved byte (not used) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002145 ushort bios_ctrl; /* 12 BIOS control bits */
2146 /* bit 0 BIOS don't act as initiator. */
2147 /* bit 1 BIOS > 1 GB support */
2148 /* bit 2 BIOS > 2 Disk Support */
2149 /* bit 3 BIOS don't support removables */
2150 /* bit 4 BIOS support bootable CD */
2151 /* bit 5 BIOS scan enabled */
2152 /* bit 6 BIOS support multiple LUNs */
2153 /* bit 7 BIOS display of message */
2154 /* bit 8 SCAM disabled */
2155 /* bit 9 Reset SCSI bus during init. */
2156 /* bit 10 */
2157 /* bit 11 No verbose initialization. */
2158 /* bit 12 SCSI parity enabled */
2159 /* bit 13 */
2160 /* bit 14 */
2161 /* bit 15 */
2162 ushort ultra_able; /* 13 ULTRA speed able */
2163 ushort reserved2; /* 14 reserved */
2164 uchar max_host_qng; /* 15 maximum host queuing */
2165 uchar max_dvc_qng; /* maximum per device queuing */
2166 ushort dvc_cntl; /* 16 control bit for driver */
2167 ushort bug_fix; /* 17 control bit for bug fix */
2168 ushort serial_number_word1; /* 18 Board serial number word 1 */
2169 ushort serial_number_word2; /* 19 Board serial number word 2 */
2170 ushort serial_number_word3; /* 20 Board serial number word 3 */
2171 ushort check_sum; /* 21 EEP check sum */
2172 uchar oem_name[16]; /* 22 OEM name */
2173 ushort dvc_err_code; /* 30 last device driver error code */
2174 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
2175 ushort adv_err_addr; /* 32 last uc error address */
2176 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
2177 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
2178 ushort saved_adv_err_addr; /* 35 saved last uc error address */
2179 ushort num_of_err; /* 36 number of error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180} ADVEEP_3550_CONFIG;
2181
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002182typedef struct adveep_38C0800_config {
2183 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002185 ushort cfg_lsw; /* 00 power up initialization */
2186 /* bit 13 set - Load CIS */
2187 /* bit 14 set - BIOS Enable */
2188 /* bit 15 set - Big Endian Mode */
2189 ushort cfg_msw; /* 01 unused */
2190 ushort disc_enable; /* 02 disconnect enable */
2191 ushort wdtr_able; /* 03 Wide DTR able */
2192 ushort sdtr_speed1; /* 04 SDTR Speed TID 0-3 */
2193 ushort start_motor; /* 05 send start up motor */
2194 ushort tagqng_able; /* 06 tag queuing able */
2195 ushort bios_scan; /* 07 BIOS device control */
2196 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002198 uchar adapter_scsi_id; /* 09 Host Adapter ID */
2199 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002201 uchar scsi_reset_delay; /* 10 reset delay */
2202 uchar bios_id_lun; /* first boot device scsi id & lun */
2203 /* high nibble is lun */
2204 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002206 uchar termination_se; /* 11 0 - automatic */
2207 /* 1 - low off / high off */
2208 /* 2 - low off / high on */
2209 /* 3 - low on / high on */
2210 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002212 uchar termination_lvd; /* 11 0 - automatic */
2213 /* 1 - low off / high off */
2214 /* 2 - low off / high on */
2215 /* 3 - low on / high on */
2216 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002218 ushort bios_ctrl; /* 12 BIOS control bits */
2219 /* bit 0 BIOS don't act as initiator. */
2220 /* bit 1 BIOS > 1 GB support */
2221 /* bit 2 BIOS > 2 Disk Support */
2222 /* bit 3 BIOS don't support removables */
2223 /* bit 4 BIOS support bootable CD */
2224 /* bit 5 BIOS scan enabled */
2225 /* bit 6 BIOS support multiple LUNs */
2226 /* bit 7 BIOS display of message */
2227 /* bit 8 SCAM disabled */
2228 /* bit 9 Reset SCSI bus during init. */
2229 /* bit 10 */
2230 /* bit 11 No verbose initialization. */
2231 /* bit 12 SCSI parity enabled */
2232 /* bit 13 */
2233 /* bit 14 */
2234 /* bit 15 */
2235 ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */
2236 ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */
2237 uchar max_host_qng; /* 15 maximum host queueing */
2238 uchar max_dvc_qng; /* maximum per device queuing */
2239 ushort dvc_cntl; /* 16 control bit for driver */
2240 ushort sdtr_speed4; /* 17 SDTR speed 4 TID 12-15 */
2241 ushort serial_number_word1; /* 18 Board serial number word 1 */
2242 ushort serial_number_word2; /* 19 Board serial number word 2 */
2243 ushort serial_number_word3; /* 20 Board serial number word 3 */
2244 ushort check_sum; /* 21 EEP check sum */
2245 uchar oem_name[16]; /* 22 OEM name */
2246 ushort dvc_err_code; /* 30 last device driver error code */
2247 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
2248 ushort adv_err_addr; /* 32 last uc error address */
2249 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
2250 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
2251 ushort saved_adv_err_addr; /* 35 saved last uc error address */
2252 ushort reserved36; /* 36 reserved */
2253 ushort reserved37; /* 37 reserved */
2254 ushort reserved38; /* 38 reserved */
2255 ushort reserved39; /* 39 reserved */
2256 ushort reserved40; /* 40 reserved */
2257 ushort reserved41; /* 41 reserved */
2258 ushort reserved42; /* 42 reserved */
2259 ushort reserved43; /* 43 reserved */
2260 ushort reserved44; /* 44 reserved */
2261 ushort reserved45; /* 45 reserved */
2262 ushort reserved46; /* 46 reserved */
2263 ushort reserved47; /* 47 reserved */
2264 ushort reserved48; /* 48 reserved */
2265 ushort reserved49; /* 49 reserved */
2266 ushort reserved50; /* 50 reserved */
2267 ushort reserved51; /* 51 reserved */
2268 ushort reserved52; /* 52 reserved */
2269 ushort reserved53; /* 53 reserved */
2270 ushort reserved54; /* 54 reserved */
2271 ushort reserved55; /* 55 reserved */
2272 ushort cisptr_lsw; /* 56 CIS PTR LSW */
2273 ushort cisprt_msw; /* 57 CIS PTR MSW */
2274 ushort subsysvid; /* 58 SubSystem Vendor ID */
2275 ushort subsysid; /* 59 SubSystem ID */
2276 ushort reserved60; /* 60 reserved */
2277 ushort reserved61; /* 61 reserved */
2278 ushort reserved62; /* 62 reserved */
2279 ushort reserved63; /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280} ADVEEP_38C0800_CONFIG;
2281
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002282typedef struct adveep_38C1600_config {
2283 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002285 ushort cfg_lsw; /* 00 power up initialization */
2286 /* bit 11 set - Func. 0 INTB, Func. 1 INTA */
2287 /* clear - Func. 0 INTA, Func. 1 INTB */
2288 /* bit 13 set - Load CIS */
2289 /* bit 14 set - BIOS Enable */
2290 /* bit 15 set - Big Endian Mode */
2291 ushort cfg_msw; /* 01 unused */
2292 ushort disc_enable; /* 02 disconnect enable */
2293 ushort wdtr_able; /* 03 Wide DTR able */
2294 ushort sdtr_speed1; /* 04 SDTR Speed TID 0-3 */
2295 ushort start_motor; /* 05 send start up motor */
2296 ushort tagqng_able; /* 06 tag queuing able */
2297 ushort bios_scan; /* 07 BIOS device control */
2298 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002300 uchar adapter_scsi_id; /* 09 Host Adapter ID */
2301 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002303 uchar scsi_reset_delay; /* 10 reset delay */
2304 uchar bios_id_lun; /* first boot device scsi id & lun */
2305 /* high nibble is lun */
2306 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002308 uchar termination_se; /* 11 0 - automatic */
2309 /* 1 - low off / high off */
2310 /* 2 - low off / high on */
2311 /* 3 - low on / high on */
2312 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002314 uchar termination_lvd; /* 11 0 - automatic */
2315 /* 1 - low off / high off */
2316 /* 2 - low off / high on */
2317 /* 3 - low on / high on */
2318 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002320 ushort bios_ctrl; /* 12 BIOS control bits */
2321 /* bit 0 BIOS don't act as initiator. */
2322 /* bit 1 BIOS > 1 GB support */
2323 /* bit 2 BIOS > 2 Disk Support */
2324 /* bit 3 BIOS don't support removables */
2325 /* bit 4 BIOS support bootable CD */
2326 /* bit 5 BIOS scan enabled */
2327 /* bit 6 BIOS support multiple LUNs */
2328 /* bit 7 BIOS display of message */
2329 /* bit 8 SCAM disabled */
2330 /* bit 9 Reset SCSI bus during init. */
2331 /* bit 10 Basic Integrity Checking disabled */
2332 /* bit 11 No verbose initialization. */
2333 /* bit 12 SCSI parity enabled */
2334 /* bit 13 AIPP (Asyn. Info. Ph. Prot.) dis. */
2335 /* bit 14 */
2336 /* bit 15 */
2337 ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */
2338 ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */
2339 uchar max_host_qng; /* 15 maximum host queueing */
2340 uchar max_dvc_qng; /* maximum per device queuing */
2341 ushort dvc_cntl; /* 16 control bit for driver */
2342 ushort sdtr_speed4; /* 17 SDTR speed 4 TID 12-15 */
2343 ushort serial_number_word1; /* 18 Board serial number word 1 */
2344 ushort serial_number_word2; /* 19 Board serial number word 2 */
2345 ushort serial_number_word3; /* 20 Board serial number word 3 */
2346 ushort check_sum; /* 21 EEP check sum */
2347 uchar oem_name[16]; /* 22 OEM name */
2348 ushort dvc_err_code; /* 30 last device driver error code */
2349 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
2350 ushort adv_err_addr; /* 32 last uc error address */
2351 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
2352 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
2353 ushort saved_adv_err_addr; /* 35 saved last uc error address */
2354 ushort reserved36; /* 36 reserved */
2355 ushort reserved37; /* 37 reserved */
2356 ushort reserved38; /* 38 reserved */
2357 ushort reserved39; /* 39 reserved */
2358 ushort reserved40; /* 40 reserved */
2359 ushort reserved41; /* 41 reserved */
2360 ushort reserved42; /* 42 reserved */
2361 ushort reserved43; /* 43 reserved */
2362 ushort reserved44; /* 44 reserved */
2363 ushort reserved45; /* 45 reserved */
2364 ushort reserved46; /* 46 reserved */
2365 ushort reserved47; /* 47 reserved */
2366 ushort reserved48; /* 48 reserved */
2367 ushort reserved49; /* 49 reserved */
2368 ushort reserved50; /* 50 reserved */
2369 ushort reserved51; /* 51 reserved */
2370 ushort reserved52; /* 52 reserved */
2371 ushort reserved53; /* 53 reserved */
2372 ushort reserved54; /* 54 reserved */
2373 ushort reserved55; /* 55 reserved */
2374 ushort cisptr_lsw; /* 56 CIS PTR LSW */
2375 ushort cisprt_msw; /* 57 CIS PTR MSW */
2376 ushort subsysvid; /* 58 SubSystem Vendor ID */
2377 ushort subsysid; /* 59 SubSystem ID */
2378 ushort reserved60; /* 60 reserved */
2379 ushort reserved61; /* 61 reserved */
2380 ushort reserved62; /* 62 reserved */
2381 ushort reserved63; /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382} ADVEEP_38C1600_CONFIG;
2383
2384/*
2385 * EEPROM Commands
2386 */
2387#define ASC_EEP_CMD_DONE 0x0200
2388#define ASC_EEP_CMD_DONE_ERR 0x0001
2389
2390/* cfg_word */
2391#define EEP_CFG_WORD_BIG_ENDIAN 0x8000
2392
2393/* bios_ctrl */
2394#define BIOS_CTRL_BIOS 0x0001
2395#define BIOS_CTRL_EXTENDED_XLAT 0x0002
2396#define BIOS_CTRL_GT_2_DISK 0x0004
2397#define BIOS_CTRL_BIOS_REMOVABLE 0x0008
2398#define BIOS_CTRL_BOOTABLE_CD 0x0010
2399#define BIOS_CTRL_MULTIPLE_LUN 0x0040
2400#define BIOS_CTRL_DISPLAY_MSG 0x0080
2401#define BIOS_CTRL_NO_SCAM 0x0100
2402#define BIOS_CTRL_RESET_SCSI_BUS 0x0200
2403#define BIOS_CTRL_INIT_VERBOSE 0x0800
2404#define BIOS_CTRL_SCSI_PARITY 0x1000
2405#define BIOS_CTRL_AIPP_DIS 0x2000
2406
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002407#define ADV_3550_MEMSIZE 0x2000 /* 8 KB Internal Memory */
2408#define ADV_3550_IOLEN 0x40 /* I/O Port Range in bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002410#define ADV_38C0800_MEMSIZE 0x4000 /* 16 KB Internal Memory */
2411#define ADV_38C0800_IOLEN 0x100 /* I/O Port Range in bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412
2413/*
2414 * XXX - Since ASC38C1600 Rev.3 has a local RAM failure issue, there is
2415 * a special 16K Adv Library and Microcode version. After the issue is
2416 * resolved, should restore 32K support.
2417 *
2418 * #define ADV_38C1600_MEMSIZE 0x8000L * 32 KB Internal Memory *
2419 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002420#define ADV_38C1600_MEMSIZE 0x4000 /* 16 KB Internal Memory */
2421#define ADV_38C1600_IOLEN 0x100 /* I/O Port Range 256 bytes */
2422#define ADV_38C1600_MEMLEN 0x1000 /* Memory Range 4KB bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423
2424/*
2425 * Byte I/O register address from base of 'iop_base'.
2426 */
2427#define IOPB_INTR_STATUS_REG 0x00
2428#define IOPB_CHIP_ID_1 0x01
2429#define IOPB_INTR_ENABLES 0x02
2430#define IOPB_CHIP_TYPE_REV 0x03
2431#define IOPB_RES_ADDR_4 0x04
2432#define IOPB_RES_ADDR_5 0x05
2433#define IOPB_RAM_DATA 0x06
2434#define IOPB_RES_ADDR_7 0x07
2435#define IOPB_FLAG_REG 0x08
2436#define IOPB_RES_ADDR_9 0x09
2437#define IOPB_RISC_CSR 0x0A
2438#define IOPB_RES_ADDR_B 0x0B
2439#define IOPB_RES_ADDR_C 0x0C
2440#define IOPB_RES_ADDR_D 0x0D
2441#define IOPB_SOFT_OVER_WR 0x0E
2442#define IOPB_RES_ADDR_F 0x0F
2443#define IOPB_MEM_CFG 0x10
2444#define IOPB_RES_ADDR_11 0x11
2445#define IOPB_GPIO_DATA 0x12
2446#define IOPB_RES_ADDR_13 0x13
2447#define IOPB_FLASH_PAGE 0x14
2448#define IOPB_RES_ADDR_15 0x15
2449#define IOPB_GPIO_CNTL 0x16
2450#define IOPB_RES_ADDR_17 0x17
2451#define IOPB_FLASH_DATA 0x18
2452#define IOPB_RES_ADDR_19 0x19
2453#define IOPB_RES_ADDR_1A 0x1A
2454#define IOPB_RES_ADDR_1B 0x1B
2455#define IOPB_RES_ADDR_1C 0x1C
2456#define IOPB_RES_ADDR_1D 0x1D
2457#define IOPB_RES_ADDR_1E 0x1E
2458#define IOPB_RES_ADDR_1F 0x1F
2459#define IOPB_DMA_CFG0 0x20
2460#define IOPB_DMA_CFG1 0x21
2461#define IOPB_TICKLE 0x22
2462#define IOPB_DMA_REG_WR 0x23
2463#define IOPB_SDMA_STATUS 0x24
2464#define IOPB_SCSI_BYTE_CNT 0x25
2465#define IOPB_HOST_BYTE_CNT 0x26
2466#define IOPB_BYTE_LEFT_TO_XFER 0x27
2467#define IOPB_BYTE_TO_XFER_0 0x28
2468#define IOPB_BYTE_TO_XFER_1 0x29
2469#define IOPB_BYTE_TO_XFER_2 0x2A
2470#define IOPB_BYTE_TO_XFER_3 0x2B
2471#define IOPB_ACC_GRP 0x2C
2472#define IOPB_RES_ADDR_2D 0x2D
2473#define IOPB_DEV_ID 0x2E
2474#define IOPB_RES_ADDR_2F 0x2F
2475#define IOPB_SCSI_DATA 0x30
2476#define IOPB_RES_ADDR_31 0x31
2477#define IOPB_RES_ADDR_32 0x32
2478#define IOPB_SCSI_DATA_HSHK 0x33
2479#define IOPB_SCSI_CTRL 0x34
2480#define IOPB_RES_ADDR_35 0x35
2481#define IOPB_RES_ADDR_36 0x36
2482#define IOPB_RES_ADDR_37 0x37
2483#define IOPB_RAM_BIST 0x38
2484#define IOPB_PLL_TEST 0x39
2485#define IOPB_PCI_INT_CFG 0x3A
2486#define IOPB_RES_ADDR_3B 0x3B
2487#define IOPB_RFIFO_CNT 0x3C
2488#define IOPB_RES_ADDR_3D 0x3D
2489#define IOPB_RES_ADDR_3E 0x3E
2490#define IOPB_RES_ADDR_3F 0x3F
2491
2492/*
2493 * Word I/O register address from base of 'iop_base'.
2494 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002495#define IOPW_CHIP_ID_0 0x00 /* CID0 */
2496#define IOPW_CTRL_REG 0x02 /* CC */
2497#define IOPW_RAM_ADDR 0x04 /* LA */
2498#define IOPW_RAM_DATA 0x06 /* LD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499#define IOPW_RES_ADDR_08 0x08
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002500#define IOPW_RISC_CSR 0x0A /* CSR */
2501#define IOPW_SCSI_CFG0 0x0C /* CFG0 */
2502#define IOPW_SCSI_CFG1 0x0E /* CFG1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503#define IOPW_RES_ADDR_10 0x10
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002504#define IOPW_SEL_MASK 0x12 /* SM */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505#define IOPW_RES_ADDR_14 0x14
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002506#define IOPW_FLASH_ADDR 0x16 /* FA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507#define IOPW_RES_ADDR_18 0x18
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002508#define IOPW_EE_CMD 0x1A /* EC */
2509#define IOPW_EE_DATA 0x1C /* ED */
2510#define IOPW_SFIFO_CNT 0x1E /* SFC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511#define IOPW_RES_ADDR_20 0x20
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002512#define IOPW_Q_BASE 0x22 /* QB */
2513#define IOPW_QP 0x24 /* QP */
2514#define IOPW_IX 0x26 /* IX */
2515#define IOPW_SP 0x28 /* SP */
2516#define IOPW_PC 0x2A /* PC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517#define IOPW_RES_ADDR_2C 0x2C
2518#define IOPW_RES_ADDR_2E 0x2E
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002519#define IOPW_SCSI_DATA 0x30 /* SD */
2520#define IOPW_SCSI_DATA_HSHK 0x32 /* SDH */
2521#define IOPW_SCSI_CTRL 0x34 /* SC */
2522#define IOPW_HSHK_CFG 0x36 /* HCFG */
2523#define IOPW_SXFR_STATUS 0x36 /* SXS */
2524#define IOPW_SXFR_CNTL 0x38 /* SXL */
2525#define IOPW_SXFR_CNTH 0x3A /* SXH */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526#define IOPW_RES_ADDR_3C 0x3C
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002527#define IOPW_RFIFO_DATA 0x3E /* RFD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528
2529/*
2530 * Doubleword I/O register address from base of 'iop_base'.
2531 */
2532#define IOPDW_RES_ADDR_0 0x00
2533#define IOPDW_RAM_DATA 0x04
2534#define IOPDW_RES_ADDR_8 0x08
2535#define IOPDW_RES_ADDR_C 0x0C
2536#define IOPDW_RES_ADDR_10 0x10
2537#define IOPDW_COMMA 0x14
2538#define IOPDW_COMMB 0x18
2539#define IOPDW_RES_ADDR_1C 0x1C
2540#define IOPDW_SDMA_ADDR0 0x20
2541#define IOPDW_SDMA_ADDR1 0x24
2542#define IOPDW_SDMA_COUNT 0x28
2543#define IOPDW_SDMA_ERROR 0x2C
2544#define IOPDW_RDMA_ADDR0 0x30
2545#define IOPDW_RDMA_ADDR1 0x34
2546#define IOPDW_RDMA_COUNT 0x38
2547#define IOPDW_RDMA_ERROR 0x3C
2548
2549#define ADV_CHIP_ID_BYTE 0x25
2550#define ADV_CHIP_ID_WORD 0x04C1
2551
2552#define ADV_SC_SCSI_BUS_RESET 0x2000
2553
2554#define ADV_INTR_ENABLE_HOST_INTR 0x01
2555#define ADV_INTR_ENABLE_SEL_INTR 0x02
2556#define ADV_INTR_ENABLE_DPR_INTR 0x04
2557#define ADV_INTR_ENABLE_RTA_INTR 0x08
2558#define ADV_INTR_ENABLE_RMA_INTR 0x10
2559#define ADV_INTR_ENABLE_RST_INTR 0x20
2560#define ADV_INTR_ENABLE_DPE_INTR 0x40
2561#define ADV_INTR_ENABLE_GLOBAL_INTR 0x80
2562
2563#define ADV_INTR_STATUS_INTRA 0x01
2564#define ADV_INTR_STATUS_INTRB 0x02
2565#define ADV_INTR_STATUS_INTRC 0x04
2566
2567#define ADV_RISC_CSR_STOP (0x0000)
2568#define ADV_RISC_TEST_COND (0x2000)
2569#define ADV_RISC_CSR_RUN (0x4000)
2570#define ADV_RISC_CSR_SINGLE_STEP (0x8000)
2571
2572#define ADV_CTRL_REG_HOST_INTR 0x0100
2573#define ADV_CTRL_REG_SEL_INTR 0x0200
2574#define ADV_CTRL_REG_DPR_INTR 0x0400
2575#define ADV_CTRL_REG_RTA_INTR 0x0800
2576#define ADV_CTRL_REG_RMA_INTR 0x1000
2577#define ADV_CTRL_REG_RES_BIT14 0x2000
2578#define ADV_CTRL_REG_DPE_INTR 0x4000
2579#define ADV_CTRL_REG_POWER_DONE 0x8000
2580#define ADV_CTRL_REG_ANY_INTR 0xFF00
2581
2582#define ADV_CTRL_REG_CMD_RESET 0x00C6
2583#define ADV_CTRL_REG_CMD_WR_IO_REG 0x00C5
2584#define ADV_CTRL_REG_CMD_RD_IO_REG 0x00C4
2585#define ADV_CTRL_REG_CMD_WR_PCI_CFG_SPACE 0x00C3
2586#define ADV_CTRL_REG_CMD_RD_PCI_CFG_SPACE 0x00C2
2587
2588#define ADV_TICKLE_NOP 0x00
2589#define ADV_TICKLE_A 0x01
2590#define ADV_TICKLE_B 0x02
2591#define ADV_TICKLE_C 0x03
2592
2593#define ADV_SCSI_CTRL_RSTOUT 0x2000
2594
2595#define AdvIsIntPending(port) \
2596 (AdvReadWordRegister(port, IOPW_CTRL_REG) & ADV_CTRL_REG_HOST_INTR)
2597
2598/*
2599 * SCSI_CFG0 Register bit definitions
2600 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002601#define TIMER_MODEAB 0xC000 /* Watchdog, Second, and Select. Timer Ctrl. */
2602#define PARITY_EN 0x2000 /* Enable SCSI Parity Error detection */
2603#define EVEN_PARITY 0x1000 /* Select Even Parity */
2604#define WD_LONG 0x0800 /* Watchdog Interval, 1: 57 min, 0: 13 sec */
2605#define QUEUE_128 0x0400 /* Queue Size, 1: 128 byte, 0: 64 byte */
2606#define PRIM_MODE 0x0100 /* Primitive SCSI mode */
2607#define SCAM_EN 0x0080 /* Enable SCAM selection */
2608#define SEL_TMO_LONG 0x0040 /* Sel/Resel Timeout, 1: 400 ms, 0: 1.6 ms */
2609#define CFRM_ID 0x0020 /* SCAM id sel. confirm., 1: fast, 0: 6.4 ms */
2610#define OUR_ID_EN 0x0010 /* Enable OUR_ID bits */
2611#define OUR_ID 0x000F /* SCSI ID */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612
2613/*
2614 * SCSI_CFG1 Register bit definitions
2615 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002616#define BIG_ENDIAN 0x8000 /* Enable Big Endian Mode MIO:15, EEP:15 */
2617#define TERM_POL 0x2000 /* Terminator Polarity Ctrl. MIO:13, EEP:13 */
2618#define SLEW_RATE 0x1000 /* SCSI output buffer slew rate */
2619#define FILTER_SEL 0x0C00 /* Filter Period Selection */
2620#define FLTR_DISABLE 0x0000 /* Input Filtering Disabled */
2621#define FLTR_11_TO_20NS 0x0800 /* Input Filtering 11ns to 20ns */
2622#define FLTR_21_TO_39NS 0x0C00 /* Input Filtering 21ns to 39ns */
2623#define ACTIVE_DBL 0x0200 /* Disable Active Negation */
2624#define DIFF_MODE 0x0100 /* SCSI differential Mode (Read-Only) */
2625#define DIFF_SENSE 0x0080 /* 1: No SE cables, 0: SE cable (Read-Only) */
2626#define TERM_CTL_SEL 0x0040 /* Enable TERM_CTL_H and TERM_CTL_L */
2627#define TERM_CTL 0x0030 /* External SCSI Termination Bits */
2628#define TERM_CTL_H 0x0020 /* Enable External SCSI Upper Termination */
2629#define TERM_CTL_L 0x0010 /* Enable External SCSI Lower Termination */
2630#define CABLE_DETECT 0x000F /* External SCSI Cable Connection Status */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631
2632/*
2633 * Addendum for ASC-38C0800 Chip
2634 *
2635 * The ASC-38C1600 Chip uses the same definitions except that the
2636 * bus mode override bits [12:10] have been moved to byte register
2637 * offset 0xE (IOPB_SOFT_OVER_WR) bits [12:10]. The [12:10] bits in
2638 * SCSI_CFG1 are read-only and always available. Bit 14 (DIS_TERM_DRV)
2639 * is not needed. The [12:10] bits in IOPB_SOFT_OVER_WR are write-only.
2640 * Also each ASC-38C1600 function or channel uses only cable bits [5:4]
2641 * and [1:0]. Bits [14], [7:6], [3:2] are unused.
2642 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002643#define DIS_TERM_DRV 0x4000 /* 1: Read c_det[3:0], 0: cannot read */
2644#define HVD_LVD_SE 0x1C00 /* Device Detect Bits */
2645#define HVD 0x1000 /* HVD Device Detect */
2646#define LVD 0x0800 /* LVD Device Detect */
2647#define SE 0x0400 /* SE Device Detect */
2648#define TERM_LVD 0x00C0 /* LVD Termination Bits */
2649#define TERM_LVD_HI 0x0080 /* Enable LVD Upper Termination */
2650#define TERM_LVD_LO 0x0040 /* Enable LVD Lower Termination */
2651#define TERM_SE 0x0030 /* SE Termination Bits */
2652#define TERM_SE_HI 0x0020 /* Enable SE Upper Termination */
2653#define TERM_SE_LO 0x0010 /* Enable SE Lower Termination */
2654#define C_DET_LVD 0x000C /* LVD Cable Detect Bits */
2655#define C_DET3 0x0008 /* Cable Detect for LVD External Wide */
2656#define C_DET2 0x0004 /* Cable Detect for LVD Internal Wide */
2657#define C_DET_SE 0x0003 /* SE Cable Detect Bits */
2658#define C_DET1 0x0002 /* Cable Detect for SE Internal Wide */
2659#define C_DET0 0x0001 /* Cable Detect for SE Internal Narrow */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660
2661#define CABLE_ILLEGAL_A 0x7
2662 /* x 0 0 0 | on on | Illegal (all 3 connectors are used) */
2663
2664#define CABLE_ILLEGAL_B 0xB
2665 /* 0 x 0 0 | on on | Illegal (all 3 connectors are used) */
2666
2667/*
2668 * MEM_CFG Register bit definitions
2669 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002670#define BIOS_EN 0x40 /* BIOS Enable MIO:14,EEP:14 */
2671#define FAST_EE_CLK 0x20 /* Diagnostic Bit */
2672#define RAM_SZ 0x1C /* Specify size of RAM to RISC */
2673#define RAM_SZ_2KB 0x00 /* 2 KB */
2674#define RAM_SZ_4KB 0x04 /* 4 KB */
2675#define RAM_SZ_8KB 0x08 /* 8 KB */
2676#define RAM_SZ_16KB 0x0C /* 16 KB */
2677#define RAM_SZ_32KB 0x10 /* 32 KB */
2678#define RAM_SZ_64KB 0x14 /* 64 KB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679
2680/*
2681 * DMA_CFG0 Register bit definitions
2682 *
2683 * This register is only accessible to the host.
2684 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002685#define BC_THRESH_ENB 0x80 /* PCI DMA Start Conditions */
2686#define FIFO_THRESH 0x70 /* PCI DMA FIFO Threshold */
2687#define FIFO_THRESH_16B 0x00 /* 16 bytes */
2688#define FIFO_THRESH_32B 0x20 /* 32 bytes */
2689#define FIFO_THRESH_48B 0x30 /* 48 bytes */
2690#define FIFO_THRESH_64B 0x40 /* 64 bytes */
2691#define FIFO_THRESH_80B 0x50 /* 80 bytes (default) */
2692#define FIFO_THRESH_96B 0x60 /* 96 bytes */
2693#define FIFO_THRESH_112B 0x70 /* 112 bytes */
2694#define START_CTL 0x0C /* DMA start conditions */
2695#define START_CTL_TH 0x00 /* Wait threshold level (default) */
2696#define START_CTL_ID 0x04 /* Wait SDMA/SBUS idle */
2697#define START_CTL_THID 0x08 /* Wait threshold and SDMA/SBUS idle */
2698#define START_CTL_EMFU 0x0C /* Wait SDMA FIFO empty/full */
2699#define READ_CMD 0x03 /* Memory Read Method */
2700#define READ_CMD_MR 0x00 /* Memory Read */
2701#define READ_CMD_MRL 0x02 /* Memory Read Long */
2702#define READ_CMD_MRM 0x03 /* Memory Read Multiple (default) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703
2704/*
2705 * ASC-38C0800 RAM BIST Register bit definitions
2706 */
2707#define RAM_TEST_MODE 0x80
2708#define PRE_TEST_MODE 0x40
2709#define NORMAL_MODE 0x00
2710#define RAM_TEST_DONE 0x10
2711#define RAM_TEST_STATUS 0x0F
2712#define RAM_TEST_HOST_ERROR 0x08
2713#define RAM_TEST_INTRAM_ERROR 0x04
2714#define RAM_TEST_RISC_ERROR 0x02
2715#define RAM_TEST_SCSI_ERROR 0x01
2716#define RAM_TEST_SUCCESS 0x00
2717#define PRE_TEST_VALUE 0x05
2718#define NORMAL_VALUE 0x00
2719
2720/*
2721 * ASC38C1600 Definitions
2722 *
2723 * IOPB_PCI_INT_CFG Bit Field Definitions
2724 */
2725
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002726#define INTAB_LD 0x80 /* Value loaded from EEPROM Bit 11. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727
2728/*
2729 * Bit 1 can be set to change the interrupt for the Function to operate in
2730 * Totem Pole mode. By default Bit 1 is 0 and the interrupt operates in
2731 * Open Drain mode. Both functions of the ASC38C1600 must be set to the same
2732 * mode, otherwise the operating mode is undefined.
2733 */
2734#define TOTEMPOLE 0x02
2735
2736/*
2737 * Bit 0 can be used to change the Int Pin for the Function. The value is
2738 * 0 by default for both Functions with Function 0 using INT A and Function
2739 * B using INT B. For Function 0 if set, INT B is used. For Function 1 if set,
2740 * INT A is used.
2741 *
2742 * EEPROM Word 0 Bit 11 for each Function may change the initial Int Pin
2743 * value specified in the PCI Configuration Space.
2744 */
2745#define INTAB 0x01
2746
2747/* a_advlib.h */
2748
2749/*
2750 * Adv Library Status Definitions
2751 */
2752#define ADV_TRUE 1
2753#define ADV_FALSE 0
2754#define ADV_NOERROR 1
2755#define ADV_SUCCESS 1
2756#define ADV_BUSY 0
2757#define ADV_ERROR (-1)
2758
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759/*
2760 * ADV_DVC_VAR 'warn_code' values
2761 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002762#define ASC_WARN_BUSRESET_ERROR 0x0001 /* SCSI Bus Reset error */
2763#define ASC_WARN_EEPROM_CHKSUM 0x0002 /* EEP check sum error */
2764#define ASC_WARN_EEPROM_TERMINATION 0x0004 /* EEP termination bad field */
2765#define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080 /* PCI config space set error */
2766#define ASC_WARN_ERROR 0xFFFF /* ADV_ERROR return */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002768#define ADV_MAX_TID 15 /* max. target identifier */
2769#define ADV_MAX_LUN 7 /* max. logical unit number */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770
2771/*
2772 * Error code values are set in ADV_DVC_VAR 'err_code'.
2773 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002774#define ASC_IERR_WRITE_EEPROM 0x0001 /* write EEPROM error */
2775#define ASC_IERR_MCODE_CHKSUM 0x0002 /* micro code check sum error */
2776#define ASC_IERR_NO_CARRIER 0x0004 /* No more carrier memory. */
2777#define ASC_IERR_START_STOP_CHIP 0x0008 /* start/stop chip failed */
2778#define ASC_IERR_CHIP_VERSION 0x0040 /* wrong chip version */
2779#define ASC_IERR_SET_SCSI_ID 0x0080 /* set SCSI ID failed */
2780#define ASC_IERR_HVD_DEVICE 0x0100 /* HVD attached to LVD connector. */
2781#define ASC_IERR_BAD_SIGNATURE 0x0200 /* signature not found */
2782#define ASC_IERR_ILLEGAL_CONNECTION 0x0400 /* Illegal cable connection */
2783#define ASC_IERR_SINGLE_END_DEVICE 0x0800 /* Single-end used w/differential */
2784#define ASC_IERR_REVERSED_CABLE 0x1000 /* Narrow flat cable reversed */
2785#define ASC_IERR_BIST_PRE_TEST 0x2000 /* BIST pre-test error */
2786#define ASC_IERR_BIST_RAM_TEST 0x4000 /* BIST RAM test error */
2787#define ASC_IERR_BAD_CHIPTYPE 0x8000 /* Invalid 'chip_type' setting. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788
2789/*
2790 * Fixed locations of microcode operating variables.
2791 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002792#define ASC_MC_CODE_BEGIN_ADDR 0x0028 /* microcode start address */
2793#define ASC_MC_CODE_END_ADDR 0x002A /* microcode end address */
2794#define ASC_MC_CODE_CHK_SUM 0x002C /* microcode code checksum */
2795#define ASC_MC_VERSION_DATE 0x0038 /* microcode version */
2796#define ASC_MC_VERSION_NUM 0x003A /* microcode number */
2797#define ASC_MC_BIOSMEM 0x0040 /* BIOS RISC Memory Start */
2798#define ASC_MC_BIOSLEN 0x0050 /* BIOS RISC Memory Length */
2799#define ASC_MC_BIOS_SIGNATURE 0x0058 /* BIOS Signature 0x55AA */
2800#define ASC_MC_BIOS_VERSION 0x005A /* BIOS Version (2 bytes) */
2801#define ASC_MC_SDTR_SPEED1 0x0090 /* SDTR Speed for TID 0-3 */
2802#define ASC_MC_SDTR_SPEED2 0x0092 /* SDTR Speed for TID 4-7 */
2803#define ASC_MC_SDTR_SPEED3 0x0094 /* SDTR Speed for TID 8-11 */
2804#define ASC_MC_SDTR_SPEED4 0x0096 /* SDTR Speed for TID 12-15 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002805#define ASC_MC_CHIP_TYPE 0x009A
2806#define ASC_MC_INTRB_CODE 0x009B
2807#define ASC_MC_WDTR_ABLE 0x009C
2808#define ASC_MC_SDTR_ABLE 0x009E
2809#define ASC_MC_TAGQNG_ABLE 0x00A0
2810#define ASC_MC_DISC_ENABLE 0x00A2
2811#define ASC_MC_IDLE_CMD_STATUS 0x00A4
2812#define ASC_MC_IDLE_CMD 0x00A6
2813#define ASC_MC_IDLE_CMD_PARAMETER 0x00A8
2814#define ASC_MC_DEFAULT_SCSI_CFG0 0x00AC
2815#define ASC_MC_DEFAULT_SCSI_CFG1 0x00AE
2816#define ASC_MC_DEFAULT_MEM_CFG 0x00B0
2817#define ASC_MC_DEFAULT_SEL_MASK 0x00B2
2818#define ASC_MC_SDTR_DONE 0x00B6
2819#define ASC_MC_NUMBER_OF_QUEUED_CMD 0x00C0
2820#define ASC_MC_NUMBER_OF_MAX_CMD 0x00D0
2821#define ASC_MC_DEVICE_HSHK_CFG_TABLE 0x0100
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002822#define ASC_MC_CONTROL_FLAG 0x0122 /* Microcode control flag. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823#define ASC_MC_WDTR_DONE 0x0124
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002824#define ASC_MC_CAM_MODE_MASK 0x015E /* CAM mode TID bitmask. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825#define ASC_MC_ICQ 0x0160
2826#define ASC_MC_IRQ 0x0164
2827#define ASC_MC_PPR_ABLE 0x017A
2828
2829/*
2830 * BIOS LRAM variable absolute offsets.
2831 */
2832#define BIOS_CODESEG 0x54
2833#define BIOS_CODELEN 0x56
2834#define BIOS_SIGNATURE 0x58
2835#define BIOS_VERSION 0x5A
2836
2837/*
2838 * Microcode Control Flags
2839 *
2840 * Flags set by the Adv Library in RISC variable 'control_flag' (0x122)
2841 * and handled by the microcode.
2842 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002843#define CONTROL_FLAG_IGNORE_PERR 0x0001 /* Ignore DMA Parity Errors */
2844#define CONTROL_FLAG_ENABLE_AIPP 0x0002 /* Enabled AIPP checking. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845
2846/*
2847 * ASC_MC_DEVICE_HSHK_CFG_TABLE microcode table or HSHK_CFG register format
2848 */
2849#define HSHK_CFG_WIDE_XFR 0x8000
2850#define HSHK_CFG_RATE 0x0F00
2851#define HSHK_CFG_OFFSET 0x001F
2852
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002853#define ASC_DEF_MAX_HOST_QNG 0xFD /* Max. number of host commands (253) */
2854#define ASC_DEF_MIN_HOST_QNG 0x10 /* Min. number of host commands (16) */
2855#define ASC_DEF_MAX_DVC_QNG 0x3F /* Max. number commands per device (63) */
2856#define ASC_DEF_MIN_DVC_QNG 0x04 /* Min. number commands per device (4) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002858#define ASC_QC_DATA_CHECK 0x01 /* Require ASC_QC_DATA_OUT set or clear. */
2859#define ASC_QC_DATA_OUT 0x02 /* Data out DMA transfer. */
2860#define ASC_QC_START_MOTOR 0x04 /* Send auto-start motor before request. */
2861#define ASC_QC_NO_OVERRUN 0x08 /* Don't report overrun. */
2862#define ASC_QC_FREEZE_TIDQ 0x10 /* Freeze TID queue after request. XXX TBD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002864#define ASC_QSC_NO_DISC 0x01 /* Don't allow disconnect for request. */
2865#define ASC_QSC_NO_TAGMSG 0x02 /* Don't allow tag queuing for request. */
2866#define ASC_QSC_NO_SYNC 0x04 /* Don't use Synch. transfer on request. */
2867#define ASC_QSC_NO_WIDE 0x08 /* Don't use Wide transfer on request. */
2868#define ASC_QSC_REDO_DTR 0x10 /* Renegotiate WDTR/SDTR before request. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869/*
2870 * Note: If a Tag Message is to be sent and neither ASC_QSC_HEAD_TAG or
2871 * ASC_QSC_ORDERED_TAG is set, then a Simple Tag Message (0x20) is used.
2872 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002873#define ASC_QSC_HEAD_TAG 0x40 /* Use Head Tag Message (0x21). */
2874#define ASC_QSC_ORDERED_TAG 0x80 /* Use Ordered Tag Message (0x22). */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875
2876/*
2877 * All fields here are accessed by the board microcode and need to be
2878 * little-endian.
2879 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002880typedef struct adv_carr_t {
2881 ADV_VADDR carr_va; /* Carrier Virtual Address */
2882 ADV_PADDR carr_pa; /* Carrier Physical Address */
2883 ADV_VADDR areq_vpa; /* ASC_SCSI_REQ_Q Virtual or Physical Address */
2884 /*
2885 * next_vpa [31:4] Carrier Virtual or Physical Next Pointer
2886 *
2887 * next_vpa [3:1] Reserved Bits
2888 * next_vpa [0] Done Flag set in Response Queue.
2889 */
2890 ADV_VADDR next_vpa;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891} ADV_CARR_T;
2892
2893/*
2894 * Mask used to eliminate low 4 bits of carrier 'next_vpa' field.
2895 */
2896#define ASC_NEXT_VPA_MASK 0xFFFFFFF0
2897
2898#define ASC_RQ_DONE 0x00000001
2899#define ASC_RQ_GOOD 0x00000002
2900#define ASC_CQ_STOPPER 0x00000000
2901
2902#define ASC_GET_CARRP(carrp) ((carrp) & ASC_NEXT_VPA_MASK)
2903
2904#define ADV_CARRIER_NUM_PAGE_CROSSING \
2905 (((ADV_CARRIER_COUNT * sizeof(ADV_CARR_T)) + \
2906 (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
2907
2908#define ADV_CARRIER_BUFSIZE \
2909 ((ADV_CARRIER_COUNT + ADV_CARRIER_NUM_PAGE_CROSSING) * sizeof(ADV_CARR_T))
2910
2911/*
2912 * ASC_SCSI_REQ_Q 'a_flag' definitions
2913 *
2914 * The Adv Library should limit use to the lower nibble (4 bits) of
2915 * a_flag. Drivers are free to use the upper nibble (4 bits) of a_flag.
2916 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002917#define ADV_POLL_REQUEST 0x01 /* poll for request completion */
2918#define ADV_SCSIQ_DONE 0x02 /* request done */
2919#define ADV_DONT_RETRY 0x08 /* don't do retry */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002921#define ADV_CHIP_ASC3550 0x01 /* Ultra-Wide IC */
2922#define ADV_CHIP_ASC38C0800 0x02 /* Ultra2-Wide/LVD IC */
2923#define ADV_CHIP_ASC38C1600 0x03 /* Ultra3-Wide/LVD2 IC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924
2925/*
2926 * Adapter temporary configuration structure
2927 *
2928 * This structure can be discarded after initialization. Don't add
2929 * fields here needed after initialization.
2930 *
2931 * Field naming convention:
2932 *
2933 * *_enable indicates the field enables or disables a feature. The
2934 * value of the field is never reset.
2935 */
2936typedef struct adv_dvc_cfg {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002937 ushort disc_enable; /* enable disconnection */
2938 uchar chip_version; /* chip version */
2939 uchar termination; /* Term. Ctrl. bits 6-5 of SCSI_CFG1 register */
2940 ushort lib_version; /* Adv Library version number */
2941 ushort control_flag; /* Microcode Control Flag */
2942 ushort mcode_date; /* Microcode date */
2943 ushort mcode_version; /* Microcode version */
2944 ushort pci_slot_info; /* high byte device/function number */
2945 /* bits 7-3 device num., bits 2-0 function num. */
2946 /* low byte bus num. */
2947 ushort serial1; /* EEPROM serial number word 1 */
2948 ushort serial2; /* EEPROM serial number word 2 */
2949 ushort serial3; /* EEPROM serial number word 3 */
2950 struct device *dev; /* pointer to the pci dev structure for this board */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951} ADV_DVC_CFG;
2952
2953struct adv_dvc_var;
2954struct adv_scsi_req_q;
2955
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002956typedef void (*ADV_ISR_CALLBACK)
2957 (struct adv_dvc_var *, struct adv_scsi_req_q *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002959typedef void (*ADV_ASYNC_CALLBACK)
2960 (struct adv_dvc_var *, uchar);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961
2962/*
2963 * Adapter operation variable structure.
2964 *
2965 * One structure is required per host adapter.
2966 *
2967 * Field naming convention:
2968 *
2969 * *_able indicates both whether a feature should be enabled or disabled
2970 * and whether a device isi capable of the feature. At initialization
2971 * this field may be set, but later if a device is found to be incapable
2972 * of the feature, the field is cleared.
2973 */
2974typedef struct adv_dvc_var {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002975 AdvPortAddr iop_base; /* I/O port address */
2976 ushort err_code; /* fatal error code */
2977 ushort bios_ctrl; /* BIOS control word, EEPROM word 12 */
2978 ADV_ISR_CALLBACK isr_callback;
2979 ADV_ASYNC_CALLBACK async_callback;
2980 ushort wdtr_able; /* try WDTR for a device */
2981 ushort sdtr_able; /* try SDTR for a device */
2982 ushort ultra_able; /* try SDTR Ultra speed for a device */
2983 ushort sdtr_speed1; /* EEPROM SDTR Speed for TID 0-3 */
2984 ushort sdtr_speed2; /* EEPROM SDTR Speed for TID 4-7 */
2985 ushort sdtr_speed3; /* EEPROM SDTR Speed for TID 8-11 */
2986 ushort sdtr_speed4; /* EEPROM SDTR Speed for TID 12-15 */
2987 ushort tagqng_able; /* try tagged queuing with a device */
2988 ushort ppr_able; /* PPR message capable per TID bitmask. */
2989 uchar max_dvc_qng; /* maximum number of tagged commands per device */
2990 ushort start_motor; /* start motor command allowed */
2991 uchar scsi_reset_wait; /* delay in seconds after scsi bus reset */
2992 uchar chip_no; /* should be assigned by caller */
2993 uchar max_host_qng; /* maximum number of Q'ed command allowed */
2994 uchar irq_no; /* IRQ number */
2995 ushort no_scam; /* scam_tolerant of EEPROM */
2996 struct asc_board *drv_ptr; /* driver pointer to private structure */
2997 uchar chip_scsi_id; /* chip SCSI target ID */
2998 uchar chip_type;
2999 uchar bist_err_code;
3000 ADV_CARR_T *carrier_buf;
3001 ADV_CARR_T *carr_freelist; /* Carrier free list. */
3002 ADV_CARR_T *icq_sp; /* Initiator command queue stopper pointer. */
3003 ADV_CARR_T *irq_sp; /* Initiator response queue stopper pointer. */
3004 ushort carr_pending_cnt; /* Count of pending carriers. */
3005 /*
3006 * Note: The following fields will not be used after initialization. The
3007 * driver may discard the buffer after initialization is done.
3008 */
3009 ADV_DVC_CFG *cfg; /* temporary configuration structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010} ADV_DVC_VAR;
3011
3012#define NO_OF_SG_PER_BLOCK 15
3013
3014typedef struct asc_sg_block {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003015 uchar reserved1;
3016 uchar reserved2;
3017 uchar reserved3;
3018 uchar sg_cnt; /* Valid entries in block. */
3019 ADV_PADDR sg_ptr; /* Pointer to next sg block. */
3020 struct {
3021 ADV_PADDR sg_addr; /* SG element address. */
3022 ADV_DCNT sg_count; /* SG element count. */
3023 } sg_list[NO_OF_SG_PER_BLOCK];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024} ADV_SG_BLOCK;
3025
3026/*
3027 * ADV_SCSI_REQ_Q - microcode request structure
3028 *
3029 * All fields in this structure up to byte 60 are used by the microcode.
3030 * The microcode makes assumptions about the size and ordering of fields
3031 * in this structure. Do not change the structure definition here without
3032 * coordinating the change with the microcode.
3033 *
3034 * All fields accessed by microcode must be maintained in little_endian
3035 * order.
3036 */
3037typedef struct adv_scsi_req_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003038 uchar cntl; /* Ucode flags and state (ASC_MC_QC_*). */
3039 uchar target_cmd;
3040 uchar target_id; /* Device target identifier. */
3041 uchar target_lun; /* Device target logical unit number. */
3042 ADV_PADDR data_addr; /* Data buffer physical address. */
3043 ADV_DCNT data_cnt; /* Data count. Ucode sets to residual. */
3044 ADV_PADDR sense_addr;
3045 ADV_PADDR carr_pa;
3046 uchar mflag;
3047 uchar sense_len;
3048 uchar cdb_len; /* SCSI CDB length. Must <= 16 bytes. */
3049 uchar scsi_cntl;
3050 uchar done_status; /* Completion status. */
3051 uchar scsi_status; /* SCSI status byte. */
3052 uchar host_status; /* Ucode host status. */
3053 uchar sg_working_ix;
3054 uchar cdb[12]; /* SCSI CDB bytes 0-11. */
3055 ADV_PADDR sg_real_addr; /* SG list physical address. */
3056 ADV_PADDR scsiq_rptr;
3057 uchar cdb16[4]; /* SCSI CDB bytes 12-15. */
3058 ADV_VADDR scsiq_ptr;
3059 ADV_VADDR carr_va;
3060 /*
3061 * End of microcode structure - 60 bytes. The rest of the structure
3062 * is used by the Adv Library and ignored by the microcode.
3063 */
3064 ADV_VADDR srb_ptr;
3065 ADV_SG_BLOCK *sg_list_ptr; /* SG list virtual address. */
3066 char *vdata_addr; /* Data buffer virtual address. */
3067 uchar a_flag;
3068 uchar pad[2]; /* Pad out to a word boundary. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069} ADV_SCSI_REQ_Q;
3070
3071/*
3072 * Microcode idle loop commands
3073 */
3074#define IDLE_CMD_COMPLETED 0
3075#define IDLE_CMD_STOP_CHIP 0x0001
3076#define IDLE_CMD_STOP_CHIP_SEND_INT 0x0002
3077#define IDLE_CMD_SEND_INT 0x0004
3078#define IDLE_CMD_ABORT 0x0008
3079#define IDLE_CMD_DEVICE_RESET 0x0010
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003080#define IDLE_CMD_SCSI_RESET_START 0x0020 /* Assert SCSI Bus Reset */
3081#define IDLE_CMD_SCSI_RESET_END 0x0040 /* Deassert SCSI Bus Reset */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003082#define IDLE_CMD_SCSIREQ 0x0080
3083
3084#define IDLE_CMD_STATUS_SUCCESS 0x0001
3085#define IDLE_CMD_STATUS_FAILURE 0x0002
3086
3087/*
3088 * AdvSendIdleCmd() flag definitions.
3089 */
3090#define ADV_NOWAIT 0x01
3091
3092/*
3093 * Wait loop time out values.
3094 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003095#define SCSI_WAIT_10_SEC 10UL /* 10 seconds */
3096#define SCSI_WAIT_100_MSEC 100UL /* 100 milliseconds */
3097#define SCSI_US_PER_MSEC 1000 /* microseconds per millisecond */
3098#define SCSI_MS_PER_SEC 1000UL /* milliseconds per second */
3099#define SCSI_MAX_RETRY 10 /* retry count */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003101#define ADV_ASYNC_RDMA_FAILURE 0x01 /* Fatal RDMA failure. */
3102#define ADV_ASYNC_SCSI_BUS_RESET_DET 0x02 /* Detected SCSI Bus Reset. */
3103#define ADV_ASYNC_CARRIER_READY_FAILURE 0x03 /* Carrier Ready failure. */
3104#define ADV_RDMA_IN_CARR_AND_Q_INVALID 0x04 /* RDMAed-in data invalid. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003106#define ADV_HOST_SCSI_BUS_RESET 0x80 /* Host Initiated SCSI Bus Reset. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003107
3108/*
3109 * Device drivers must define the following functions.
3110 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003111static inline ulong DvcEnterCritical(void);
3112static inline void DvcLeaveCritical(ulong);
3113static void DvcSleepMilliSecond(ADV_DCNT);
3114static uchar DvcAdvReadPCIConfigByte(ADV_DVC_VAR *, ushort);
3115static void DvcAdvWritePCIConfigByte(ADV_DVC_VAR *, ushort, uchar);
3116static ADV_PADDR DvcGetPhyAddr(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *,
3117 uchar *, ASC_SDCNT *, int);
3118static void DvcDelayMicroSecond(ADV_DVC_VAR *, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003119
3120/*
3121 * Adv Library functions available to drivers.
3122 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003123static int AdvExeScsiQueue(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
3124static int AdvISR(ADV_DVC_VAR *);
3125static int AdvInitGetConfig(ADV_DVC_VAR *);
3126static int AdvInitAsc3550Driver(ADV_DVC_VAR *);
3127static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *);
3128static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *);
3129static int AdvResetChipAndSB(ADV_DVC_VAR *);
3130static int AdvResetSB(ADV_DVC_VAR *asc_dvc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003131
3132/*
3133 * Internal Adv Library functions.
3134 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003135static int AdvSendIdleCmd(ADV_DVC_VAR *, ushort, ADV_DCNT);
3136static void AdvInquiryHandling(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
3137static int AdvInitFrom3550EEP(ADV_DVC_VAR *);
3138static int AdvInitFrom38C0800EEP(ADV_DVC_VAR *);
3139static int AdvInitFrom38C1600EEP(ADV_DVC_VAR *);
3140static ushort AdvGet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
3141static void AdvSet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
3142static ushort AdvGet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
3143static void AdvSet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
3144static ushort AdvGet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
3145static void AdvSet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
3146static void AdvWaitEEPCmd(AdvPortAddr);
3147static ushort AdvReadEEPWord(AdvPortAddr, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003148
3149/*
3150 * PCI Bus Definitions
3151 */
3152#define AscPCICmdRegBits_BusMastering 0x0007
3153#define AscPCICmdRegBits_ParErrRespCtrl 0x0040
3154
3155/* Read byte from a register. */
3156#define AdvReadByteRegister(iop_base, reg_off) \
3157 (ADV_MEM_READB((iop_base) + (reg_off)))
3158
3159/* Write byte to a register. */
3160#define AdvWriteByteRegister(iop_base, reg_off, byte) \
3161 (ADV_MEM_WRITEB((iop_base) + (reg_off), (byte)))
3162
3163/* Read word (2 bytes) from a register. */
3164#define AdvReadWordRegister(iop_base, reg_off) \
3165 (ADV_MEM_READW((iop_base) + (reg_off)))
3166
3167/* Write word (2 bytes) to a register. */
3168#define AdvWriteWordRegister(iop_base, reg_off, word) \
3169 (ADV_MEM_WRITEW((iop_base) + (reg_off), (word)))
3170
3171/* Write dword (4 bytes) to a register. */
3172#define AdvWriteDWordRegister(iop_base, reg_off, dword) \
3173 (ADV_MEM_WRITEDW((iop_base) + (reg_off), (dword)))
3174
3175/* Read byte from LRAM. */
3176#define AdvReadByteLram(iop_base, addr, byte) \
3177do { \
3178 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \
3179 (byte) = ADV_MEM_READB((iop_base) + IOPB_RAM_DATA); \
3180} while (0)
3181
3182/* Write byte to LRAM. */
3183#define AdvWriteByteLram(iop_base, addr, byte) \
3184 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
3185 ADV_MEM_WRITEB((iop_base) + IOPB_RAM_DATA, (byte)))
3186
3187/* Read word (2 bytes) from LRAM. */
3188#define AdvReadWordLram(iop_base, addr, word) \
3189do { \
3190 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \
3191 (word) = (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA)); \
3192} while (0)
3193
3194/* Write word (2 bytes) to LRAM. */
3195#define AdvWriteWordLram(iop_base, addr, word) \
3196 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
3197 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
3198
3199/* Write little-endian double word (4 bytes) to LRAM */
3200/* Because of unspecified C language ordering don't use auto-increment. */
3201#define AdvWriteDWordLramNoSwap(iop_base, addr, dword) \
3202 ((ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
3203 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
3204 cpu_to_le16((ushort) ((dword) & 0xFFFF)))), \
3205 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr) + 2), \
3206 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
3207 cpu_to_le16((ushort) ((dword >> 16) & 0xFFFF)))))
3208
3209/* Read word (2 bytes) from LRAM assuming that the address is already set. */
3210#define AdvReadWordAutoIncLram(iop_base) \
3211 (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA))
3212
3213/* Write word (2 bytes) to LRAM assuming that the address is already set. */
3214#define AdvWriteWordAutoIncLram(iop_base, word) \
3215 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
3216
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217/*
3218 * Define macro to check for Condor signature.
3219 *
3220 * Evaluate to ADV_TRUE if a Condor chip is found the specified port
3221 * address 'iop_base'. Otherwise evalue to ADV_FALSE.
3222 */
3223#define AdvFindSignature(iop_base) \
3224 (((AdvReadByteRegister((iop_base), IOPB_CHIP_ID_1) == \
3225 ADV_CHIP_ID_BYTE) && \
3226 (AdvReadWordRegister((iop_base), IOPW_CHIP_ID_0) == \
3227 ADV_CHIP_ID_WORD)) ? ADV_TRUE : ADV_FALSE)
3228
3229/*
3230 * Define macro to Return the version number of the chip at 'iop_base'.
3231 *
3232 * The second parameter 'bus_type' is currently unused.
3233 */
3234#define AdvGetChipVersion(iop_base, bus_type) \
3235 AdvReadByteRegister((iop_base), IOPB_CHIP_TYPE_REV)
3236
3237/*
3238 * Abort an SRB in the chip's RISC Memory. The 'srb_ptr' argument must
3239 * match the ASC_SCSI_REQ_Q 'srb_ptr' field.
3240 *
3241 * If the request has not yet been sent to the device it will simply be
3242 * aborted from RISC memory. If the request is disconnected it will be
3243 * aborted on reselection by sending an Abort Message to the target ID.
3244 *
3245 * Return value:
3246 * ADV_TRUE(1) - Queue was successfully aborted.
3247 * ADV_FALSE(0) - Queue was not found on the active queue list.
3248 */
3249#define AdvAbortQueue(asc_dvc, scsiq) \
3250 AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_ABORT, \
3251 (ADV_DCNT) (scsiq))
3252
3253/*
3254 * Send a Bus Device Reset Message to the specified target ID.
3255 *
3256 * All outstanding commands will be purged if sending the
3257 * Bus Device Reset Message is successful.
3258 *
3259 * Return Value:
3260 * ADV_TRUE(1) - All requests on the target are purged.
3261 * ADV_FALSE(0) - Couldn't issue Bus Device Reset Message; Requests
3262 * are not purged.
3263 */
3264#define AdvResetDevice(asc_dvc, target_id) \
3265 AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_DEVICE_RESET, \
3266 (ADV_DCNT) (target_id))
3267
3268/*
3269 * SCSI Wide Type definition.
3270 */
3271#define ADV_SCSI_BIT_ID_TYPE ushort
3272
3273/*
3274 * AdvInitScsiTarget() 'cntl_flag' options.
3275 */
3276#define ADV_SCAN_LUN 0x01
3277#define ADV_CAPINFO_NOLUN 0x02
3278
3279/*
3280 * Convert target id to target id bit mask.
3281 */
3282#define ADV_TID_TO_TIDMASK(tid) (0x01 << ((tid) & ADV_MAX_TID))
3283
3284/*
3285 * ASC_SCSI_REQ_Q 'done_status' and 'host_status' return values.
3286 */
3287
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003288#define QD_NO_STATUS 0x00 /* Request not completed yet. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003289#define QD_NO_ERROR 0x01
3290#define QD_ABORTED_BY_HOST 0x02
3291#define QD_WITH_ERROR 0x04
3292
3293#define QHSTA_NO_ERROR 0x00
3294#define QHSTA_M_SEL_TIMEOUT 0x11
3295#define QHSTA_M_DATA_OVER_RUN 0x12
3296#define QHSTA_M_UNEXPECTED_BUS_FREE 0x13
3297#define QHSTA_M_QUEUE_ABORTED 0x15
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003298#define QHSTA_M_SXFR_SDMA_ERR 0x16 /* SXFR_STATUS SCSI DMA Error */
3299#define QHSTA_M_SXFR_SXFR_PERR 0x17 /* SXFR_STATUS SCSI Bus Parity Error */
3300#define QHSTA_M_RDMA_PERR 0x18 /* RISC PCI DMA parity error */
3301#define QHSTA_M_SXFR_OFF_UFLW 0x19 /* SXFR_STATUS Offset Underflow */
3302#define QHSTA_M_SXFR_OFF_OFLW 0x20 /* SXFR_STATUS Offset Overflow */
3303#define QHSTA_M_SXFR_WD_TMO 0x21 /* SXFR_STATUS Watchdog Timeout */
3304#define QHSTA_M_SXFR_DESELECTED 0x22 /* SXFR_STATUS Deselected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003305/* Note: QHSTA_M_SXFR_XFR_OFLW is identical to QHSTA_M_DATA_OVER_RUN. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003306#define QHSTA_M_SXFR_XFR_OFLW 0x12 /* SXFR_STATUS Transfer Overflow */
3307#define QHSTA_M_SXFR_XFR_PH_ERR 0x24 /* SXFR_STATUS Transfer Phase Error */
3308#define QHSTA_M_SXFR_UNKNOWN_ERROR 0x25 /* SXFR_STATUS Unknown Error */
3309#define QHSTA_M_SCSI_BUS_RESET 0x30 /* Request aborted from SBR */
3310#define QHSTA_M_SCSI_BUS_RESET_UNSOL 0x31 /* Request aborted from unsol. SBR */
3311#define QHSTA_M_BUS_DEVICE_RESET 0x32 /* Request aborted from BDR */
3312#define QHSTA_M_DIRECTION_ERR 0x35 /* Data Phase mismatch */
3313#define QHSTA_M_DIRECTION_ERR_HUNG 0x36 /* Data Phase mismatch and bus hang */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314#define QHSTA_M_WTM_TIMEOUT 0x41
3315#define QHSTA_M_BAD_CMPL_STATUS_IN 0x42
3316#define QHSTA_M_NO_AUTO_REQ_SENSE 0x43
3317#define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003318#define QHSTA_M_INVALID_DEVICE 0x45 /* Bad target ID */
3319#define QHSTA_M_FROZEN_TIDQ 0x46 /* TID Queue frozen. */
3320#define QHSTA_M_SGBACKUP_ERROR 0x47 /* Scatter-Gather backup error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321
3322/*
3323 * Default EEPROM Configuration structure defined in a_init.c.
3324 */
3325static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config;
3326static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config;
3327static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config;
3328
3329/*
3330 * DvcGetPhyAddr() flag arguments
3331 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003332#define ADV_IS_SCSIQ_FLAG 0x01 /* 'addr' is ASC_SCSI_REQ_Q pointer */
3333#define ADV_ASCGETSGLIST_VADDR 0x02 /* 'addr' is AscGetSGList() virtual addr */
3334#define ADV_IS_SENSE_FLAG 0x04 /* 'addr' is sense virtual pointer */
3335#define ADV_IS_DATA_FLAG 0x08 /* 'addr' is data virtual pointer */
3336#define ADV_IS_SGLIST_FLAG 0x10 /* 'addr' is sglist virtual pointer */
3337#define ADV_IS_CARRIER_FLAG 0x20 /* 'addr' is ADV_CARR_T pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338
3339/* Return the address that is aligned at the next doubleword >= to 'addr'. */
3340#define ADV_8BALIGN(addr) (((ulong) (addr) + 0x7) & ~0x7)
3341#define ADV_16BALIGN(addr) (((ulong) (addr) + 0xF) & ~0xF)
3342#define ADV_32BALIGN(addr) (((ulong) (addr) + 0x1F) & ~0x1F)
3343
3344/*
3345 * Total contiguous memory needed for driver SG blocks.
3346 *
3347 * ADV_MAX_SG_LIST must be defined by a driver. It is the maximum
3348 * number of scatter-gather elements the driver supports in a
3349 * single request.
3350 */
3351
3352#define ADV_SG_LIST_MAX_BYTE_SIZE \
3353 (sizeof(ADV_SG_BLOCK) * \
3354 ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK))
3355
3356/*
3357 * Inquiry data structure and bitfield macros
3358 *
3359 * Using bitfields to access the subchar data isn't portable across
3360 * endianness, so instead mask and shift. Only quantities of more
3361 * than 1 bit are shifted, since the others are just tested for true
3362 * or false.
3363 */
3364
3365#define ADV_INQ_DVC_TYPE(inq) ((inq)->periph & 0x1f)
3366#define ADV_INQ_QUALIFIER(inq) (((inq)->periph & 0xe0) >> 5)
3367#define ADV_INQ_DVC_TYPE_MOD(inq) ((inq)->devtype & 0x7f)
3368#define ADV_INQ_REMOVABLE(inq) ((inq)->devtype & 0x80)
3369#define ADV_INQ_ANSI_VER(inq) ((inq)->ver & 0x07)
3370#define ADV_INQ_ECMA_VER(inq) (((inq)->ver & 0x38) >> 3)
3371#define ADV_INQ_ISO_VER(inq) (((inq)->ver & 0xc0) >> 6)
3372#define ADV_INQ_RESPONSE_FMT(inq) ((inq)->byte3 & 0x0f)
3373#define ADV_INQ_TERM_IO(inq) ((inq)->byte3 & 0x40)
3374#define ADV_INQ_ASYNC_NOTIF(inq) ((inq)->byte3 & 0x80)
3375#define ADV_INQ_SOFT_RESET(inq) ((inq)->flags & 0x01)
3376#define ADV_INQ_CMD_QUEUE(inq) ((inq)->flags & 0x02)
3377#define ADV_INQ_LINK_CMD(inq) ((inq)->flags & 0x08)
3378#define ADV_INQ_SYNC(inq) ((inq)->flags & 0x10)
3379#define ADV_INQ_WIDE16(inq) ((inq)->flags & 0x20)
3380#define ADV_INQ_WIDE32(inq) ((inq)->flags & 0x40)
3381#define ADV_INQ_REL_ADDR(inq) ((inq)->flags & 0x80)
3382#define ADV_INQ_INFO_UNIT(inq) ((inq)->info & 0x01)
3383#define ADV_INQ_QUICK_ARB(inq) ((inq)->info & 0x02)
3384#define ADV_INQ_CLOCKING(inq) (((inq)->info & 0x0c) >> 2)
3385
3386typedef struct {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003387 uchar periph; /* peripheral device type [0:4] */
3388 /* peripheral qualifier [5:7] */
3389 uchar devtype; /* device type modifier (for SCSI I) [0:6] */
3390 /* RMB - removable medium bit [7] */
3391 uchar ver; /* ANSI approved version [0:2] */
3392 /* ECMA version [3:5] */
3393 /* ISO version [6:7] */
3394 uchar byte3; /* response data format [0:3] */
3395 /* 0 SCSI 1 */
3396 /* 1 CCS */
3397 /* 2 SCSI-2 */
3398 /* 3-F reserved */
3399 /* reserved [4:5] */
3400 /* terminate I/O process bit (see 5.6.22) [6] */
3401 /* asynch. event notification (processor) [7] */
3402 uchar add_len; /* additional length */
3403 uchar res1; /* reserved */
3404 uchar res2; /* reserved */
3405 uchar flags; /* soft reset implemented [0] */
3406 /* command queuing [1] */
3407 /* reserved [2] */
3408 /* linked command for this logical unit [3] */
3409 /* synchronous data transfer [4] */
3410 /* wide bus 16 bit data transfer [5] */
3411 /* wide bus 32 bit data transfer [6] */
3412 /* relative addressing mode [7] */
3413 uchar vendor_id[8]; /* vendor identification */
3414 uchar product_id[16]; /* product identification */
3415 uchar product_rev_level[4]; /* product revision level */
3416 uchar vendor_specific[20]; /* vendor specific */
3417 uchar info; /* information unit supported [0] */
3418 /* quick arbitrate supported [1] */
3419 /* clocking field [2:3] */
3420 /* reserved [4:7] */
3421 uchar res3; /* reserved */
3422} ADV_SCSI_INQUIRY; /* 58 bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423
3424/*
3425 * --- Driver Constants and Macros
3426 */
3427
3428#define ASC_NUM_BOARD_SUPPORTED 16
3429#define ASC_NUM_IOPORT_PROBE 4
3430#define ASC_NUM_BUS 4
3431
3432/* Reference Scsi_Host hostdata */
3433#define ASC_BOARDP(host) ((asc_board_t *) &((host)->hostdata))
3434
3435/* asc_board_t flags */
3436#define ASC_HOST_IN_RESET 0x01
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003437#define ASC_IS_WIDE_BOARD 0x04 /* AdvanSys Wide Board */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003438#define ASC_SELECT_QUEUE_DEPTHS 0x08
3439
3440#define ASC_NARROW_BOARD(boardp) (((boardp)->flags & ASC_IS_WIDE_BOARD) == 0)
3441#define ASC_WIDE_BOARD(boardp) ((boardp)->flags & ASC_IS_WIDE_BOARD)
3442
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003443#define NO_ISA_DMA 0xff /* No ISA DMA Channel Used */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003445#define ASC_INFO_SIZE 128 /* advansys_info() line size */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446
3447#ifdef CONFIG_PROC_FS
3448/* /proc/scsi/advansys/[0...] related definitions */
3449#define ASC_PRTBUF_SIZE 2048
3450#define ASC_PRTLINE_SIZE 160
3451
3452#define ASC_PRT_NEXT() \
3453 if (cp) { \
3454 totlen += len; \
3455 leftlen -= len; \
3456 if (leftlen == 0) { \
3457 return totlen; \
3458 } \
3459 cp += len; \
3460 }
3461#endif /* CONFIG_PROC_FS */
3462
3463/* Asc Library return codes */
3464#define ASC_TRUE 1
3465#define ASC_FALSE 0
3466#define ASC_NOERROR 1
3467#define ASC_BUSY 0
3468#define ASC_ERROR (-1)
3469
3470/* struct scsi_cmnd function return codes */
3471#define STATUS_BYTE(byte) (byte)
3472#define MSG_BYTE(byte) ((byte) << 8)
3473#define HOST_BYTE(byte) ((byte) << 16)
3474#define DRIVER_BYTE(byte) ((byte) << 24)
3475
3476/*
3477 * The following definitions and macros are OS independent interfaces to
3478 * the queue functions:
3479 * REQ - SCSI request structure
3480 * REQP - pointer to SCSI request structure
3481 * REQPTID(reqp) - reqp's target id
3482 * REQPNEXT(reqp) - reqp's next pointer
3483 * REQPNEXTP(reqp) - pointer to reqp's next pointer
3484 * REQPTIME(reqp) - reqp's time stamp value
3485 * REQTIMESTAMP() - system time stamp value
3486 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003487typedef struct scsi_cmnd REQ, *REQP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003488#define REQPNEXT(reqp) ((REQP) ((reqp)->host_scribble))
3489#define REQPNEXTP(reqp) ((REQP *) &((reqp)->host_scribble))
3490#define REQPTID(reqp) ((reqp)->device->id)
3491#define REQPTIME(reqp) ((reqp)->SCp.this_residual)
3492#define REQTIMESTAMP() (jiffies)
3493
3494#define REQTIMESTAT(function, ascq, reqp, tid) \
3495{ \
3496 /*
3497 * If the request time stamp is less than the system time stamp, then \
3498 * maybe the system time stamp wrapped. Set the request time to zero.\
3499 */ \
3500 if (REQPTIME(reqp) <= REQTIMESTAMP()) { \
3501 REQPTIME(reqp) = REQTIMESTAMP() - REQPTIME(reqp); \
3502 } else { \
3503 /* Indicate an error occurred with the assertion. */ \
3504 ASC_ASSERT(REQPTIME(reqp) <= REQTIMESTAMP()); \
3505 REQPTIME(reqp) = 0; \
3506 } \
3507 /* Handle first minimum time case without external initialization. */ \
3508 if (((ascq)->q_tot_cnt[tid] == 1) || \
3509 (REQPTIME(reqp) < (ascq)->q_min_tim[tid])) { \
3510 (ascq)->q_min_tim[tid] = REQPTIME(reqp); \
3511 ASC_DBG3(1, "%s: new q_min_tim[%d] %u\n", \
3512 (function), (tid), (ascq)->q_min_tim[tid]); \
3513 } \
3514 if (REQPTIME(reqp) > (ascq)->q_max_tim[tid]) { \
3515 (ascq)->q_max_tim[tid] = REQPTIME(reqp); \
3516 ASC_DBG3(1, "%s: new q_max_tim[%d] %u\n", \
3517 (function), tid, (ascq)->q_max_tim[tid]); \
3518 } \
3519 (ascq)->q_tot_tim[tid] += REQPTIME(reqp); \
3520 /* Reset the time stamp field. */ \
3521 REQPTIME(reqp) = 0; \
3522}
3523
3524/* asc_enqueue() flags */
3525#define ASC_FRONT 1
3526#define ASC_BACK 2
3527
3528/* asc_dequeue_list() argument */
3529#define ASC_TID_ALL (-1)
3530
3531/* Return non-zero, if the queue is empty. */
3532#define ASC_QUEUE_EMPTY(ascq) ((ascq)->q_tidmask == 0)
3533
3534#define PCI_MAX_SLOT 0x1F
3535#define PCI_MAX_BUS 0xFF
3536#define PCI_IOADDRESS_MASK 0xFFFE
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003537#define ASC_PCI_DEVICE_ID_CNT 6 /* PCI Device ID count. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003538
3539#ifndef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003540#define ASC_STATS(shost, counter)
3541#define ASC_STATS_ADD(shost, counter, count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542#else /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003543#define ASC_STATS(shost, counter) \
3544 (ASC_BOARDP(shost)->asc_stats.counter++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003545
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003546#define ASC_STATS_ADD(shost, counter, count) \
3547 (ASC_BOARDP(shost)->asc_stats.counter += (count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003548#endif /* ADVANSYS_STATS */
3549
3550#define ASC_CEILING(val, unit) (((val) + ((unit) - 1))/(unit))
3551
3552/* If the result wraps when calculating tenths, return 0. */
3553#define ASC_TENTHS(num, den) \
3554 (((10 * ((num)/(den))) > (((num) * 10)/(den))) ? \
3555 0 : ((((num) * 10)/(den)) - (10 * ((num)/(den)))))
3556
3557/*
3558 * Display a message to the console.
3559 */
3560#define ASC_PRINT(s) \
3561 { \
3562 printk("advansys: "); \
3563 printk(s); \
3564 }
3565
3566#define ASC_PRINT1(s, a1) \
3567 { \
3568 printk("advansys: "); \
3569 printk((s), (a1)); \
3570 }
3571
3572#define ASC_PRINT2(s, a1, a2) \
3573 { \
3574 printk("advansys: "); \
3575 printk((s), (a1), (a2)); \
3576 }
3577
3578#define ASC_PRINT3(s, a1, a2, a3) \
3579 { \
3580 printk("advansys: "); \
3581 printk((s), (a1), (a2), (a3)); \
3582 }
3583
3584#define ASC_PRINT4(s, a1, a2, a3, a4) \
3585 { \
3586 printk("advansys: "); \
3587 printk((s), (a1), (a2), (a3), (a4)); \
3588 }
3589
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590#ifndef ADVANSYS_DEBUG
3591
3592#define ASC_DBG(lvl, s)
3593#define ASC_DBG1(lvl, s, a1)
3594#define ASC_DBG2(lvl, s, a1, a2)
3595#define ASC_DBG3(lvl, s, a1, a2, a3)
3596#define ASC_DBG4(lvl, s, a1, a2, a3, a4)
3597#define ASC_DBG_PRT_SCSI_HOST(lvl, s)
3598#define ASC_DBG_PRT_SCSI_CMND(lvl, s)
3599#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp)
3600#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
3601#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone)
3602#define ADV_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
3603#define ASC_DBG_PRT_HEX(lvl, name, start, length)
3604#define ASC_DBG_PRT_CDB(lvl, cdb, len)
3605#define ASC_DBG_PRT_SENSE(lvl, sense, len)
3606#define ASC_DBG_PRT_INQUIRY(lvl, inq, len)
3607
3608#else /* ADVANSYS_DEBUG */
3609
3610/*
3611 * Debugging Message Levels:
3612 * 0: Errors Only
3613 * 1: High-Level Tracing
3614 * 2-N: Verbose Tracing
3615 */
3616
3617#define ASC_DBG(lvl, s) \
3618 { \
3619 if (asc_dbglvl >= (lvl)) { \
3620 printk(s); \
3621 } \
3622 }
3623
3624#define ASC_DBG1(lvl, s, a1) \
3625 { \
3626 if (asc_dbglvl >= (lvl)) { \
3627 printk((s), (a1)); \
3628 } \
3629 }
3630
3631#define ASC_DBG2(lvl, s, a1, a2) \
3632 { \
3633 if (asc_dbglvl >= (lvl)) { \
3634 printk((s), (a1), (a2)); \
3635 } \
3636 }
3637
3638#define ASC_DBG3(lvl, s, a1, a2, a3) \
3639 { \
3640 if (asc_dbglvl >= (lvl)) { \
3641 printk((s), (a1), (a2), (a3)); \
3642 } \
3643 }
3644
3645#define ASC_DBG4(lvl, s, a1, a2, a3, a4) \
3646 { \
3647 if (asc_dbglvl >= (lvl)) { \
3648 printk((s), (a1), (a2), (a3), (a4)); \
3649 } \
3650 }
3651
3652#define ASC_DBG_PRT_SCSI_HOST(lvl, s) \
3653 { \
3654 if (asc_dbglvl >= (lvl)) { \
3655 asc_prt_scsi_host(s); \
3656 } \
3657 }
3658
3659#define ASC_DBG_PRT_SCSI_CMND(lvl, s) \
3660 { \
3661 if (asc_dbglvl >= (lvl)) { \
3662 asc_prt_scsi_cmnd(s); \
3663 } \
3664 }
3665
3666#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp) \
3667 { \
3668 if (asc_dbglvl >= (lvl)) { \
3669 asc_prt_asc_scsi_q(scsiqp); \
3670 } \
3671 }
3672
3673#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone) \
3674 { \
3675 if (asc_dbglvl >= (lvl)) { \
3676 asc_prt_asc_qdone_info(qdone); \
3677 } \
3678 }
3679
3680#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp) \
3681 { \
3682 if (asc_dbglvl >= (lvl)) { \
3683 asc_prt_adv_scsi_req_q(scsiqp); \
3684 } \
3685 }
3686
3687#define ASC_DBG_PRT_HEX(lvl, name, start, length) \
3688 { \
3689 if (asc_dbglvl >= (lvl)) { \
3690 asc_prt_hex((name), (start), (length)); \
3691 } \
3692 }
3693
3694#define ASC_DBG_PRT_CDB(lvl, cdb, len) \
3695 ASC_DBG_PRT_HEX((lvl), "CDB", (uchar *) (cdb), (len));
3696
3697#define ASC_DBG_PRT_SENSE(lvl, sense, len) \
3698 ASC_DBG_PRT_HEX((lvl), "SENSE", (uchar *) (sense), (len));
3699
3700#define ASC_DBG_PRT_INQUIRY(lvl, inq, len) \
3701 ASC_DBG_PRT_HEX((lvl), "INQUIRY", (uchar *) (inq), (len));
3702#endif /* ADVANSYS_DEBUG */
3703
3704#ifndef ADVANSYS_ASSERT
3705#define ASC_ASSERT(a)
3706#else /* ADVANSYS_ASSERT */
3707
3708#define ASC_ASSERT(a) \
3709 { \
3710 if (!(a)) { \
3711 printk("ASC_ASSERT() Failure: file %s, line %d\n", \
3712 __FILE__, __LINE__); \
3713 } \
3714 }
3715
3716#endif /* ADVANSYS_ASSERT */
3717
Linus Torvalds1da177e2005-04-16 15:20:36 -07003718/*
3719 * --- Driver Structures
3720 */
3721
3722#ifdef ADVANSYS_STATS
3723
3724/* Per board statistics structure */
3725struct asc_stats {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003726 /* Driver Entrypoint Statistics */
3727 ADV_DCNT queuecommand; /* # calls to advansys_queuecommand() */
3728 ADV_DCNT reset; /* # calls to advansys_eh_bus_reset() */
3729 ADV_DCNT biosparam; /* # calls to advansys_biosparam() */
3730 ADV_DCNT interrupt; /* # advansys_interrupt() calls */
3731 ADV_DCNT callback; /* # calls to asc/adv_isr_callback() */
3732 ADV_DCNT done; /* # calls to request's scsi_done function */
3733 ADV_DCNT build_error; /* # asc/adv_build_req() ASC_ERROR returns. */
3734 ADV_DCNT adv_build_noreq; /* # adv_build_req() adv_req_t alloc. fail. */
3735 ADV_DCNT adv_build_nosg; /* # adv_build_req() adv_sgblk_t alloc. fail. */
3736 /* AscExeScsiQueue()/AdvExeScsiQueue() Statistics */
3737 ADV_DCNT exe_noerror; /* # ASC_NOERROR returns. */
3738 ADV_DCNT exe_busy; /* # ASC_BUSY returns. */
3739 ADV_DCNT exe_error; /* # ASC_ERROR returns. */
3740 ADV_DCNT exe_unknown; /* # unknown returns. */
3741 /* Data Transfer Statistics */
3742 ADV_DCNT cont_cnt; /* # non-scatter-gather I/O requests received */
3743 ADV_DCNT cont_xfer; /* # contiguous transfer 512-bytes */
3744 ADV_DCNT sg_cnt; /* # scatter-gather I/O requests received */
3745 ADV_DCNT sg_elem; /* # scatter-gather elements */
3746 ADV_DCNT sg_xfer; /* # scatter-gather transfer 512-bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003747};
3748#endif /* ADVANSYS_STATS */
3749
3750/*
3751 * Request queuing structure
3752 */
3753typedef struct asc_queue {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003754 ADV_SCSI_BIT_ID_TYPE q_tidmask; /* queue mask */
3755 REQP q_first[ADV_MAX_TID + 1]; /* first queued request */
3756 REQP q_last[ADV_MAX_TID + 1]; /* last queued request */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003757#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003758 short q_cur_cnt[ADV_MAX_TID + 1]; /* current queue count */
3759 short q_max_cnt[ADV_MAX_TID + 1]; /* maximum queue count */
3760 ADV_DCNT q_tot_cnt[ADV_MAX_TID + 1]; /* total enqueue count */
3761 ADV_DCNT q_tot_tim[ADV_MAX_TID + 1]; /* total time queued */
3762 ushort q_max_tim[ADV_MAX_TID + 1]; /* maximum time queued */
3763 ushort q_min_tim[ADV_MAX_TID + 1]; /* minimum time queued */
3764#endif /* ADVANSYS_STATS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003765} asc_queue_t;
3766
3767/*
3768 * Adv Library Request Structures
3769 *
3770 * The following two structures are used to process Wide Board requests.
3771 *
3772 * The ADV_SCSI_REQ_Q structure in adv_req_t is passed to the Adv Library
3773 * and microcode with the ADV_SCSI_REQ_Q field 'srb_ptr' pointing to the
3774 * adv_req_t. The adv_req_t structure 'cmndp' field in turn points to the
3775 * Mid-Level SCSI request structure.
3776 *
3777 * Zero or more ADV_SG_BLOCK are used with each ADV_SCSI_REQ_Q. Each
3778 * ADV_SG_BLOCK structure holds 15 scatter-gather elements. Under Linux
3779 * up to 255 scatter-gather elements may be used per request or
3780 * ADV_SCSI_REQ_Q.
3781 *
3782 * Both structures must be 32 byte aligned.
3783 */
3784typedef struct adv_sgblk {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003785 ADV_SG_BLOCK sg_block; /* Sgblock structure. */
3786 uchar align[32]; /* Sgblock structure padding. */
3787 struct adv_sgblk *next_sgblkp; /* Next scatter-gather structure. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003788} adv_sgblk_t;
3789
3790typedef struct adv_req {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003791 ADV_SCSI_REQ_Q scsi_req_q; /* Adv Library request structure. */
3792 uchar align[32]; /* Request structure padding. */
3793 struct scsi_cmnd *cmndp; /* Mid-Level SCSI command pointer. */
3794 adv_sgblk_t *sgblkp; /* Adv Library scatter-gather pointer. */
3795 struct adv_req *next_reqp; /* Next Request Structure. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003796} adv_req_t;
3797
3798/*
3799 * Structure allocated for each board.
3800 *
3801 * This structure is allocated by scsi_register() at the end
3802 * of the 'Scsi_Host' structure starting at the 'hostdata'
3803 * field. It is guaranteed to be allocated from DMA-able memory.
3804 */
3805typedef struct asc_board {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003806 int id; /* Board Id */
3807 uint flags; /* Board flags */
3808 union {
3809 ASC_DVC_VAR asc_dvc_var; /* Narrow board */
3810 ADV_DVC_VAR adv_dvc_var; /* Wide board */
3811 } dvc_var;
3812 union {
3813 ASC_DVC_CFG asc_dvc_cfg; /* Narrow board */
3814 ADV_DVC_CFG adv_dvc_cfg; /* Wide board */
3815 } dvc_cfg;
3816 ushort asc_n_io_port; /* Number I/O ports. */
3817 asc_queue_t active; /* Active command queue */
3818 asc_queue_t waiting; /* Waiting command queue */
3819 asc_queue_t done; /* Done command queue */
3820 ADV_SCSI_BIT_ID_TYPE init_tidmask; /* Target init./valid mask */
3821 struct scsi_device *device[ADV_MAX_TID + 1]; /* Mid-Level Scsi Device */
3822 ushort reqcnt[ADV_MAX_TID + 1]; /* Starvation request count */
3823 ADV_SCSI_BIT_ID_TYPE queue_full; /* Queue full mask */
3824 ushort queue_full_cnt[ADV_MAX_TID + 1]; /* Queue full count */
3825 union {
3826 ASCEEP_CONFIG asc_eep; /* Narrow EEPROM config. */
3827 ADVEEP_3550_CONFIG adv_3550_eep; /* 3550 EEPROM config. */
3828 ADVEEP_38C0800_CONFIG adv_38C0800_eep; /* 38C0800 EEPROM config. */
3829 ADVEEP_38C1600_CONFIG adv_38C1600_eep; /* 38C1600 EEPROM config. */
3830 } eep_config;
3831 ulong last_reset; /* Saved last reset time */
3832 spinlock_t lock; /* Board spinlock */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003834 /* /proc/scsi/advansys/[0...] */
3835 char *prtbuf; /* /proc print buffer */
3836#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003837#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003838 struct asc_stats asc_stats; /* Board statistics */
3839#endif /* ADVANSYS_STATS */
3840 /*
3841 * The following fields are used only for Narrow Boards.
3842 */
3843 /* The following three structures must be in DMA-able memory. */
3844 ASC_SCSI_REQ_Q scsireqq;
3845 ASC_CAP_INFO cap_info;
3846 ASC_SCSI_INQUIRY inquiry;
3847 uchar sdtr_data[ASC_MAX_TID + 1]; /* SDTR information */
3848 /*
3849 * The following fields are used only for Wide Boards.
3850 */
3851 void __iomem *ioremap_addr; /* I/O Memory remap address. */
3852 ushort ioport; /* I/O Port address. */
3853 ADV_CARR_T *orig_carrp; /* ADV_CARR_T memory block. */
3854 adv_req_t *orig_reqp; /* adv_req_t memory block. */
3855 adv_req_t *adv_reqp; /* Request structures. */
3856 adv_sgblk_t *adv_sgblkp; /* Scatter-gather structures. */
3857 ushort bios_signature; /* BIOS Signature. */
3858 ushort bios_version; /* BIOS Version. */
3859 ushort bios_codeseg; /* BIOS Code Segment. */
3860 ushort bios_codelen; /* BIOS Code Segment Length. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003861} asc_board_t;
3862
3863/*
3864 * PCI configuration structures
3865 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003866typedef struct _PCI_DATA_ {
3867 uchar type;
3868 uchar bus;
3869 uchar slot;
3870 uchar func;
3871 uchar offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003872} PCI_DATA;
3873
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003874typedef struct _PCI_DEVICE_ {
3875 ushort vendorID;
3876 ushort deviceID;
3877 ushort slotNumber;
3878 ushort slotFound;
3879 uchar busNumber;
3880 uchar maxBusNumber;
3881 uchar devFunc;
3882 ushort startSlot;
3883 ushort endSlot;
3884 uchar bridge;
3885 uchar type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003886} PCI_DEVICE;
3887
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003888typedef struct _PCI_CONFIG_SPACE_ {
3889 ushort vendorID;
3890 ushort deviceID;
3891 ushort command;
3892 ushort status;
3893 uchar revision;
3894 uchar classCode[3];
3895 uchar cacheSize;
3896 uchar latencyTimer;
3897 uchar headerType;
3898 uchar bist;
3899 ADV_PADDR baseAddress[6];
3900 ushort reserved[4];
3901 ADV_PADDR optionRomAddr;
3902 ushort reserved2[4];
3903 uchar irqLine;
3904 uchar irqPin;
3905 uchar minGnt;
3906 uchar maxLatency;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907} PCI_CONFIG_SPACE;
3908
Linus Torvalds1da177e2005-04-16 15:20:36 -07003909/*
3910 * --- Driver Data
3911 */
3912
3913/* Note: All driver global data should be initialized. */
3914
3915/* Number of boards detected in system. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003916static int asc_board_count = 0;
3917static struct Scsi_Host *asc_host[ASC_NUM_BOARD_SUPPORTED] = { NULL };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003918
3919/* Overrun buffer used by all narrow boards. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003920static uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003921
3922/*
3923 * Global structures required to issue a command.
3924 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003925static ASC_SCSI_Q asc_scsi_q = { {0} };
3926static ASC_SG_HEAD asc_sg_head = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003927
3928/* List of supported bus types. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003929static ushort asc_bus[ASC_NUM_BUS] __initdata = {
3930 ASC_IS_ISA,
3931 ASC_IS_VL,
3932 ASC_IS_EISA,
3933 ASC_IS_PCI,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003934};
3935
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003936static int asc_iopflag = ASC_FALSE;
3937static int asc_ioport[ASC_NUM_IOPORT_PROBE] = { 0, 0, 0, 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003938
3939#ifdef ADVANSYS_DEBUG
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003940static char *asc_bus_name[ASC_NUM_BUS] = {
3941 "ASC_IS_ISA",
3942 "ASC_IS_VL",
3943 "ASC_IS_EISA",
3944 "ASC_IS_PCI",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003945};
3946
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003947static int asc_dbglvl = 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003948#endif /* ADVANSYS_DEBUG */
3949
3950/* Declaration for Asc Library internal data referenced by driver. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003951static PortAddr _asc_def_iop_base[];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003952
3953/*
3954 * --- Driver Function Prototypes
3955 *
3956 * advansys.h contains function prototypes for functions global to Linux.
3957 */
3958
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003959static irqreturn_t advansys_interrupt(int, void *);
3960static int advansys_slave_configure(struct scsi_device *);
3961static void asc_scsi_done_list(struct scsi_cmnd *);
3962static int asc_execute_scsi_cmnd(struct scsi_cmnd *);
3963static int asc_build_req(asc_board_t *, struct scsi_cmnd *);
3964static int adv_build_req(asc_board_t *, struct scsi_cmnd *, ADV_SCSI_REQ_Q **);
3965static int adv_get_sglist(asc_board_t *, adv_req_t *, struct scsi_cmnd *, int);
3966static void asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *);
3967static void adv_isr_callback(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
3968static void adv_async_callback(ADV_DVC_VAR *, uchar);
3969static void asc_enqueue(asc_queue_t *, REQP, int);
3970static REQP asc_dequeue(asc_queue_t *, int);
3971static REQP asc_dequeue_list(asc_queue_t *, REQP *, int);
3972static int asc_rmqueue(asc_queue_t *, REQP);
3973static void asc_execute_queue(asc_queue_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003974#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003975static int asc_proc_copy(off_t, off_t, char *, int, char *, int);
3976static int asc_prt_board_devices(struct Scsi_Host *, char *, int);
3977static int asc_prt_adv_bios(struct Scsi_Host *, char *, int);
3978static int asc_get_eeprom_string(ushort *serialnum, uchar *cp);
3979static int asc_prt_asc_board_eeprom(struct Scsi_Host *, char *, int);
3980static int asc_prt_adv_board_eeprom(struct Scsi_Host *, char *, int);
3981static int asc_prt_driver_conf(struct Scsi_Host *, char *, int);
3982static int asc_prt_asc_board_info(struct Scsi_Host *, char *, int);
3983static int asc_prt_adv_board_info(struct Scsi_Host *, char *, int);
3984static int asc_prt_line(char *, int, char *fmt, ...);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003985#endif /* CONFIG_PROC_FS */
3986
3987/* Declaration for Asc Library internal functions referenced by driver. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003988static int AscFindSignature(PortAddr);
3989static ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003990
3991/* Statistics function prototypes. */
3992#ifdef ADVANSYS_STATS
3993#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003994static int asc_prt_board_stats(struct Scsi_Host *, char *, int);
3995static int asc_prt_target_stats(struct Scsi_Host *, int, char *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003996#endif /* CONFIG_PROC_FS */
3997#endif /* ADVANSYS_STATS */
3998
3999/* Debug function prototypes. */
4000#ifdef ADVANSYS_DEBUG
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004001static void asc_prt_scsi_host(struct Scsi_Host *);
4002static void asc_prt_scsi_cmnd(struct scsi_cmnd *);
4003static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *);
4004static void asc_prt_asc_dvc_var(ASC_DVC_VAR *);
4005static void asc_prt_asc_scsi_q(ASC_SCSI_Q *);
4006static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *);
4007static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *);
4008static void asc_prt_adv_dvc_var(ADV_DVC_VAR *);
4009static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *);
4010static void asc_prt_adv_sgblock(int, ADV_SG_BLOCK *);
4011static void asc_prt_hex(char *f, uchar *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004012#endif /* ADVANSYS_DEBUG */
4013
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014#ifdef CONFIG_PROC_FS
4015/*
4016 * advansys_proc_info() - /proc/scsi/advansys/[0-(ASC_NUM_BOARD_SUPPORTED-1)]
4017 *
4018 * *buffer: I/O buffer
4019 * **start: if inout == FALSE pointer into buffer where user read should start
4020 * offset: current offset into a /proc/scsi/advansys/[0...] file
4021 * length: length of buffer
4022 * hostno: Scsi_Host host_no
4023 * inout: TRUE - user is writing; FALSE - user is reading
4024 *
4025 * Return the number of bytes read from or written to a
4026 * /proc/scsi/advansys/[0...] file.
4027 *
4028 * Note: This function uses the per board buffer 'prtbuf' which is
4029 * allocated when the board is initialized in advansys_detect(). The
4030 * buffer is ASC_PRTBUF_SIZE bytes. The function asc_proc_copy() is
4031 * used to write to the buffer. The way asc_proc_copy() is written
4032 * if 'prtbuf' is too small it will not be overwritten. Instead the
4033 * user just won't get all the available statistics.
4034 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07004035static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07004036advansys_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004037 off_t offset, int length, int inout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004038{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004039 struct Scsi_Host *shp;
4040 asc_board_t *boardp;
4041 int i;
4042 char *cp;
4043 int cplen;
4044 int cnt;
4045 int totcnt;
4046 int leftlen;
4047 char *curbuf;
4048 off_t advoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004050 int tgt_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004051#endif /* ADVANSYS_STATS */
4052
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004053 ASC_DBG(1, "advansys_proc_info: begin\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004055 /*
4056 * User write not supported.
4057 */
4058 if (inout == TRUE) {
4059 return (-ENOSYS);
4060 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004061
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004062 /*
4063 * User read of /proc/scsi/advansys/[0...] file.
4064 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004065
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004066 /* Find the specified board. */
4067 for (i = 0; i < asc_board_count; i++) {
4068 if (asc_host[i]->host_no == shost->host_no) {
4069 break;
4070 }
4071 }
4072 if (i == asc_board_count) {
4073 return (-ENOENT);
4074 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004075
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004076 shp = asc_host[i];
4077 boardp = ASC_BOARDP(shp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004078
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004079 /* Copy read data starting at the beginning of the buffer. */
4080 *start = buffer;
4081 curbuf = buffer;
4082 advoffset = 0;
4083 totcnt = 0;
4084 leftlen = length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004085
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004086 /*
4087 * Get board configuration information.
4088 *
4089 * advansys_info() returns the board string from its own static buffer.
4090 */
4091 cp = (char *)advansys_info(shp);
4092 strcat(cp, "\n");
4093 cplen = strlen(cp);
4094 /* Copy board information. */
4095 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
4096 totcnt += cnt;
4097 leftlen -= cnt;
4098 if (leftlen == 0) {
4099 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4100 return totcnt;
4101 }
4102 advoffset += cplen;
4103 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004104
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004105 /*
4106 * Display Wide Board BIOS Information.
4107 */
4108 if (ASC_WIDE_BOARD(boardp)) {
4109 cp = boardp->prtbuf;
4110 cplen = asc_prt_adv_bios(shp, cp, ASC_PRTBUF_SIZE);
4111 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
4112 cnt =
4113 asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
4114 cplen);
4115 totcnt += cnt;
4116 leftlen -= cnt;
4117 if (leftlen == 0) {
4118 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4119 return totcnt;
4120 }
4121 advoffset += cplen;
4122 curbuf += cnt;
4123 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004124
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004125 /*
4126 * Display driver information for each device attached to the board.
4127 */
4128 cp = boardp->prtbuf;
4129 cplen = asc_prt_board_devices(shp, cp, ASC_PRTBUF_SIZE);
4130 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
4131 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
4132 totcnt += cnt;
4133 leftlen -= cnt;
4134 if (leftlen == 0) {
4135 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4136 return totcnt;
4137 }
4138 advoffset += cplen;
4139 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004140
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004141 /*
4142 * Display EEPROM configuration for the board.
4143 */
4144 cp = boardp->prtbuf;
4145 if (ASC_NARROW_BOARD(boardp)) {
4146 cplen = asc_prt_asc_board_eeprom(shp, cp, ASC_PRTBUF_SIZE);
4147 } else {
4148 cplen = asc_prt_adv_board_eeprom(shp, cp, ASC_PRTBUF_SIZE);
4149 }
4150 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
4151 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
4152 totcnt += cnt;
4153 leftlen -= cnt;
4154 if (leftlen == 0) {
4155 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4156 return totcnt;
4157 }
4158 advoffset += cplen;
4159 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004160
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004161 /*
4162 * Display driver configuration and information for the board.
4163 */
4164 cp = boardp->prtbuf;
4165 cplen = asc_prt_driver_conf(shp, cp, ASC_PRTBUF_SIZE);
4166 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
4167 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
4168 totcnt += cnt;
4169 leftlen -= cnt;
4170 if (leftlen == 0) {
4171 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4172 return totcnt;
4173 }
4174 advoffset += cplen;
4175 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176
4177#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004178 /*
4179 * Display driver statistics for the board.
4180 */
4181 cp = boardp->prtbuf;
4182 cplen = asc_prt_board_stats(shp, cp, ASC_PRTBUF_SIZE);
4183 ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
4184 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
4185 totcnt += cnt;
4186 leftlen -= cnt;
4187 if (leftlen == 0) {
4188 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4189 return totcnt;
4190 }
4191 advoffset += cplen;
4192 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004193
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004194 /*
4195 * Display driver statistics for each target.
4196 */
4197 for (tgt_id = 0; tgt_id <= ADV_MAX_TID; tgt_id++) {
4198 cp = boardp->prtbuf;
4199 cplen = asc_prt_target_stats(shp, tgt_id, cp, ASC_PRTBUF_SIZE);
4200 ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
4201 cnt =
4202 asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
4203 cplen);
4204 totcnt += cnt;
4205 leftlen -= cnt;
4206 if (leftlen == 0) {
4207 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4208 return totcnt;
4209 }
4210 advoffset += cplen;
4211 curbuf += cnt;
4212 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213#endif /* ADVANSYS_STATS */
4214
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004215 /*
4216 * Display Asc Library dynamic configuration information
4217 * for the board.
4218 */
4219 cp = boardp->prtbuf;
4220 if (ASC_NARROW_BOARD(boardp)) {
4221 cplen = asc_prt_asc_board_info(shp, cp, ASC_PRTBUF_SIZE);
4222 } else {
4223 cplen = asc_prt_adv_board_info(shp, cp, ASC_PRTBUF_SIZE);
4224 }
4225 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
4226 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
4227 totcnt += cnt;
4228 leftlen -= cnt;
4229 if (leftlen == 0) {
4230 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4231 return totcnt;
4232 }
4233 advoffset += cplen;
4234 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004235
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004236 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004237
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004238 return totcnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004239}
4240#endif /* CONFIG_PROC_FS */
4241
4242/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07004243 * advansys_info()
4244 *
4245 * Return suitable for printing on the console with the argument
4246 * adapter's configuration information.
4247 *
4248 * Note: The information line should not exceed ASC_INFO_SIZE bytes,
4249 * otherwise the static 'info' array will be overrun.
4250 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004251static const char *advansys_info(struct Scsi_Host *shost)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004252{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004253 static char info[ASC_INFO_SIZE];
4254 asc_board_t *boardp;
4255 ASC_DVC_VAR *asc_dvc_varp;
4256 ADV_DVC_VAR *adv_dvc_varp;
4257 char *busname;
4258 int iolen;
4259 char *widename = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004261 boardp = ASC_BOARDP(shost);
4262 if (ASC_NARROW_BOARD(boardp)) {
4263 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
4264 ASC_DBG(1, "advansys_info: begin\n");
4265 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
4266 if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) ==
4267 ASC_IS_ISAPNP) {
4268 busname = "ISA PnP";
4269 } else {
4270 busname = "ISA";
4271 }
4272 /* Don't reference 'shost->n_io_port'; It may be truncated. */
4273 sprintf(info,
4274 "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X, DMA 0x%X",
4275 ASC_VERSION, busname,
4276 (ulong)shost->io_port,
4277 (ulong)shost->io_port + boardp->asc_n_io_port -
4278 1, shost->irq, shost->dma_channel);
4279 } else {
4280 if (asc_dvc_varp->bus_type & ASC_IS_VL) {
4281 busname = "VL";
4282 } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) {
4283 busname = "EISA";
4284 } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
4285 if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
4286 == ASC_IS_PCI_ULTRA) {
4287 busname = "PCI Ultra";
4288 } else {
4289 busname = "PCI";
4290 }
4291 } else {
4292 busname = "?";
4293 ASC_PRINT2
4294 ("advansys_info: board %d: unknown bus type %d\n",
4295 boardp->id, asc_dvc_varp->bus_type);
4296 }
4297 /* Don't reference 'shost->n_io_port'; It may be truncated. */
4298 sprintf(info,
4299 "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X",
4300 ASC_VERSION, busname,
4301 (ulong)shost->io_port,
4302 (ulong)shost->io_port + boardp->asc_n_io_port -
4303 1, shost->irq);
4304 }
4305 } else {
4306 /*
4307 * Wide Adapter Information
4308 *
4309 * Memory-mapped I/O is used instead of I/O space to access
4310 * the adapter, but display the I/O Port range. The Memory
4311 * I/O address is displayed through the driver /proc file.
4312 */
4313 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
4314 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
4315 iolen = ADV_3550_IOLEN;
4316 widename = "Ultra-Wide";
4317 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
4318 iolen = ADV_38C0800_IOLEN;
4319 widename = "Ultra2-Wide";
4320 } else {
4321 iolen = ADV_38C1600_IOLEN;
4322 widename = "Ultra3-Wide";
4323 }
4324 sprintf(info,
4325 "AdvanSys SCSI %s: PCI %s: PCIMEM 0x%lX-0x%lX, IRQ 0x%X",
4326 ASC_VERSION, widename, (ulong)adv_dvc_varp->iop_base,
4327 (ulong)adv_dvc_varp->iop_base + iolen - 1, shost->irq);
4328 }
4329 ASC_ASSERT(strlen(info) < ASC_INFO_SIZE);
4330 ASC_DBG(1, "advansys_info: end\n");
4331 return info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004332}
4333
4334/*
4335 * advansys_queuecommand() - interrupt-driven I/O entrypoint.
4336 *
4337 * This function always returns 0. Command return status is saved
4338 * in the 'scp' result field.
4339 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07004340static int
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004341advansys_queuecommand(struct scsi_cmnd *scp, void (*done) (struct scsi_cmnd *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004342{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004343 struct Scsi_Host *shost;
4344 asc_board_t *boardp;
4345 ulong flags;
4346 struct scsi_cmnd *done_scp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004347
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004348 shost = scp->device->host;
4349 boardp = ASC_BOARDP(shost);
4350 ASC_STATS(shost, queuecommand);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004351
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004352 /* host_lock taken by mid-level prior to call but need to protect */
4353 /* against own ISR */
4354 spin_lock_irqsave(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004355
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004356 /*
4357 * Block new commands while handling a reset or abort request.
4358 */
4359 if (boardp->flags & ASC_HOST_IN_RESET) {
4360 ASC_DBG1(1,
4361 "advansys_queuecommand: scp 0x%lx blocked for reset request\n",
4362 (ulong)scp);
4363 scp->result = HOST_BYTE(DID_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004364
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004365 /*
4366 * Add blocked requests to the board's 'done' queue. The queued
4367 * requests will be completed at the end of the abort or reset
4368 * handling.
4369 */
4370 asc_enqueue(&boardp->done, scp, ASC_BACK);
4371 spin_unlock_irqrestore(&boardp->lock, flags);
4372 return 0;
4373 }
4374
4375 /*
4376 * Attempt to execute any waiting commands for the board.
4377 */
4378 if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
4379 ASC_DBG(1,
4380 "advansys_queuecommand: before asc_execute_queue() waiting\n");
4381 asc_execute_queue(&boardp->waiting);
4382 }
4383
4384 /*
4385 * Save the function pointer to Linux mid-level 'done' function
4386 * and attempt to execute the command.
4387 *
4388 * If ASC_NOERROR is returned the request has been added to the
4389 * board's 'active' queue and will be completed by the interrupt
4390 * handler.
4391 *
4392 * If ASC_BUSY is returned add the request to the board's per
4393 * target waiting list. This is the first time the request has
4394 * been tried. Add it to the back of the waiting list. It will be
4395 * retried later.
4396 *
4397 * If an error occurred, the request will have been placed on the
4398 * board's 'done' queue and must be completed before returning.
4399 */
4400 scp->scsi_done = done;
4401 switch (asc_execute_scsi_cmnd(scp)) {
4402 case ASC_NOERROR:
4403 break;
4404 case ASC_BUSY:
4405 asc_enqueue(&boardp->waiting, scp, ASC_BACK);
4406 break;
4407 case ASC_ERROR:
4408 default:
4409 done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
4410 /* Interrupts could be enabled here. */
4411 asc_scsi_done_list(done_scp);
4412 break;
4413 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004414 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004415
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004416 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417}
4418
4419/*
4420 * advansys_reset()
4421 *
4422 * Reset the bus associated with the command 'scp'.
4423 *
4424 * This function runs its own thread. Interrupts must be blocked but
4425 * sleeping is allowed and no locking other than for host structures is
4426 * required. Returns SUCCESS or FAILED.
4427 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004428static int advansys_reset(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004429{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004430 struct Scsi_Host *shost;
4431 asc_board_t *boardp;
4432 ASC_DVC_VAR *asc_dvc_varp;
4433 ADV_DVC_VAR *adv_dvc_varp;
4434 ulong flags;
4435 struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
4436 struct scsi_cmnd *tscp, *new_last_scp;
4437 int status;
4438 int ret = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004439
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004440 ASC_DBG1(1, "advansys_reset: 0x%lx\n", (ulong)scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004441
4442#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004443 if (scp->device->host != NULL) {
4444 ASC_STATS(scp->device->host, reset);
4445 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004446#endif /* ADVANSYS_STATS */
4447
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004448 if ((shost = scp->device->host) == NULL) {
4449 scp->result = HOST_BYTE(DID_ERROR);
4450 return FAILED;
4451 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004452
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004453 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004454
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004455 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset started...\n",
4456 boardp->id);
4457 /*
4458 * Check for re-entrancy.
4459 */
4460 spin_lock_irqsave(&boardp->lock, flags);
4461 if (boardp->flags & ASC_HOST_IN_RESET) {
4462 spin_unlock_irqrestore(&boardp->lock, flags);
4463 return FAILED;
4464 }
4465 boardp->flags |= ASC_HOST_IN_RESET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004466 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004467
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004468 if (ASC_NARROW_BOARD(boardp)) {
4469 /*
4470 * Narrow Board
4471 */
4472 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004473
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004474 /*
4475 * Reset the chip and SCSI bus.
4476 */
4477 ASC_DBG(1, "advansys_reset: before AscInitAsc1000Driver()\n");
4478 status = AscInitAsc1000Driver(asc_dvc_varp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004479
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004480 /* Refer to ASC_IERR_* defintions for meaning of 'err_code'. */
4481 if (asc_dvc_varp->err_code) {
4482 ASC_PRINT2
4483 ("advansys_reset: board %d: SCSI bus reset error: 0x%x\n",
4484 boardp->id, asc_dvc_varp->err_code);
4485 ret = FAILED;
4486 } else if (status) {
4487 ASC_PRINT2
4488 ("advansys_reset: board %d: SCSI bus reset warning: 0x%x\n",
4489 boardp->id, status);
4490 } else {
4491 ASC_PRINT1
4492 ("advansys_reset: board %d: SCSI bus reset successful.\n",
4493 boardp->id);
4494 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004495
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004496 ASC_DBG(1, "advansys_reset: after AscInitAsc1000Driver()\n");
4497 spin_lock_irqsave(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004498
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004499 } else {
4500 /*
4501 * Wide Board
4502 *
4503 * If the suggest reset bus flags are set, then reset the bus.
4504 * Otherwise only reset the device.
4505 */
4506 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004507
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004508 /*
4509 * Reset the target's SCSI bus.
4510 */
4511 ASC_DBG(1, "advansys_reset: before AdvResetChipAndSB()\n");
4512 switch (AdvResetChipAndSB(adv_dvc_varp)) {
4513 case ASC_TRUE:
4514 ASC_PRINT1
4515 ("advansys_reset: board %d: SCSI bus reset successful.\n",
4516 boardp->id);
4517 break;
4518 case ASC_FALSE:
4519 default:
4520 ASC_PRINT1
4521 ("advansys_reset: board %d: SCSI bus reset error.\n",
4522 boardp->id);
4523 ret = FAILED;
4524 break;
4525 }
4526 spin_lock_irqsave(&boardp->lock, flags);
4527 (void)AdvISR(adv_dvc_varp);
4528 }
4529 /* Board lock is held. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004530
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004531 /*
4532 * Dequeue all board 'done' requests. A pointer to the last request
4533 * is returned in 'last_scp'.
4534 */
4535 done_scp = asc_dequeue_list(&boardp->done, &last_scp, ASC_TID_ALL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004536
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004537 /*
4538 * Dequeue all board 'active' requests for all devices and set
4539 * the request status to DID_RESET. A pointer to the last request
4540 * is returned in 'last_scp'.
4541 */
4542 if (done_scp == NULL) {
4543 done_scp =
4544 asc_dequeue_list(&boardp->active, &last_scp, ASC_TID_ALL);
4545 for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
4546 tscp->result = HOST_BYTE(DID_RESET);
4547 }
4548 } else {
4549 /* Append to 'done_scp' at the end with 'last_scp'. */
4550 ASC_ASSERT(last_scp != NULL);
4551 last_scp->host_scribble =
4552 (unsigned char *)asc_dequeue_list(&boardp->active,
4553 &new_last_scp,
4554 ASC_TID_ALL);
4555 if (new_last_scp != NULL) {
4556 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
4557 for (tscp = REQPNEXT(last_scp); tscp;
4558 tscp = REQPNEXT(tscp)) {
4559 tscp->result = HOST_BYTE(DID_RESET);
4560 }
4561 last_scp = new_last_scp;
4562 }
4563 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004565 /*
4566 * Dequeue all 'waiting' requests and set the request status
4567 * to DID_RESET.
4568 */
4569 if (done_scp == NULL) {
4570 done_scp =
4571 asc_dequeue_list(&boardp->waiting, &last_scp, ASC_TID_ALL);
4572 for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
4573 tscp->result = HOST_BYTE(DID_RESET);
4574 }
4575 } else {
4576 /* Append to 'done_scp' at the end with 'last_scp'. */
4577 ASC_ASSERT(last_scp != NULL);
4578 last_scp->host_scribble =
4579 (unsigned char *)asc_dequeue_list(&boardp->waiting,
4580 &new_last_scp,
4581 ASC_TID_ALL);
4582 if (new_last_scp != NULL) {
4583 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
4584 for (tscp = REQPNEXT(last_scp); tscp;
4585 tscp = REQPNEXT(tscp)) {
4586 tscp->result = HOST_BYTE(DID_RESET);
4587 }
4588 last_scp = new_last_scp;
4589 }
4590 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004591
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004592 /* Save the time of the most recently completed reset. */
4593 boardp->last_reset = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004594
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004595 /* Clear reset flag. */
4596 boardp->flags &= ~ASC_HOST_IN_RESET;
4597 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004598
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004599 /*
4600 * Complete all the 'done_scp' requests.
4601 */
4602 if (done_scp != NULL) {
4603 asc_scsi_done_list(done_scp);
4604 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004605
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004606 ASC_DBG1(1, "advansys_reset: ret %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004607
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004608 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004609}
4610
4611/*
4612 * advansys_biosparam()
4613 *
4614 * Translate disk drive geometry if the "BIOS greater than 1 GB"
4615 * support is enabled for a drive.
4616 *
4617 * ip (information pointer) is an int array with the following definition:
4618 * ip[0]: heads
4619 * ip[1]: sectors
4620 * ip[2]: cylinders
4621 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07004622static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623advansys_biosparam(struct scsi_device *sdev, struct block_device *bdev,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004624 sector_t capacity, int ip[])
Linus Torvalds1da177e2005-04-16 15:20:36 -07004625{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004626 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004627
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004628 ASC_DBG(1, "advansys_biosparam: begin\n");
4629 ASC_STATS(sdev->host, biosparam);
4630 boardp = ASC_BOARDP(sdev->host);
4631 if (ASC_NARROW_BOARD(boardp)) {
4632 if ((boardp->dvc_var.asc_dvc_var.dvc_cntl &
4633 ASC_CNTL_BIOS_GT_1GB) && capacity > 0x200000) {
4634 ip[0] = 255;
4635 ip[1] = 63;
4636 } else {
4637 ip[0] = 64;
4638 ip[1] = 32;
4639 }
4640 } else {
4641 if ((boardp->dvc_var.adv_dvc_var.bios_ctrl &
4642 BIOS_CTRL_EXTENDED_XLAT) && capacity > 0x200000) {
4643 ip[0] = 255;
4644 ip[1] = 63;
4645 } else {
4646 ip[0] = 64;
4647 ip[1] = 32;
4648 }
4649 }
4650 ip[2] = (unsigned long)capacity / (ip[0] * ip[1]);
4651 ASC_DBG(1, "advansys_biosparam: end\n");
4652 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004653}
4654
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004655static int __init advansys_detect(struct scsi_host_template *tpnt);
4656static int advansys_release(struct Scsi_Host *shp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657
4658static struct scsi_host_template driver_template = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004659 .proc_name = "advansys",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004660#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004661 .proc_info = advansys_proc_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004662#endif
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004663 .name = "advansys",
4664 .detect = advansys_detect,
4665 .release = advansys_release,
4666 .info = advansys_info,
4667 .queuecommand = advansys_queuecommand,
4668 .eh_bus_reset_handler = advansys_reset,
4669 .bios_param = advansys_biosparam,
4670 .slave_configure = advansys_slave_configure,
4671 /*
4672 * Because the driver may control an ISA adapter 'unchecked_isa_dma'
4673 * must be set. The flag will be cleared in advansys_detect for non-ISA
4674 * adapters. Refer to the comment in scsi_module.c for more information.
4675 */
4676 .unchecked_isa_dma = 1,
4677 /*
4678 * All adapters controlled by this driver are capable of large
4679 * scatter-gather lists. According to the mid-level SCSI documentation
4680 * this obviates any performance gain provided by setting
4681 * 'use_clustering'. But empirically while CPU utilization is increased
4682 * by enabling clustering, I/O throughput increases as well.
4683 */
4684 .use_clustering = ENABLE_CLUSTERING,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004685};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004686
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004687#include "scsi_module.c"
Linus Torvalds1da177e2005-04-16 15:20:36 -07004688
4689/*
4690 * --- Miscellaneous Driver Functions
4691 */
4692
4693/*
4694 * First-level interrupt handler.
4695 *
4696 * 'dev_id' is a pointer to the interrupting adapter's asc_board_t. Because
4697 * all boards are currently checked for interrupts on each interrupt, 'dev_id'
4698 * is not referenced. 'dev_id' could be used to identify an interrupt passed
4699 * to the AdvanSys driver which is for a device sharing an interrupt with
4700 * an AdvanSys adapter.
4701 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004702static irqreturn_t advansys_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004703{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004704 ulong flags;
4705 int i;
4706 asc_board_t *boardp;
4707 struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
4708 struct scsi_cmnd *new_last_scp;
4709 struct Scsi_Host *shost;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004710
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004711 ASC_DBG(1, "advansys_interrupt: begin\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004712
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004713 /*
4714 * Check for interrupts on all boards.
4715 * AscISR() will call asc_isr_callback().
4716 */
4717 for (i = 0; i < asc_board_count; i++) {
4718 shost = asc_host[i];
4719 boardp = ASC_BOARDP(shost);
4720 ASC_DBG2(2, "advansys_interrupt: i %d, boardp 0x%lx\n",
4721 i, (ulong)boardp);
4722 spin_lock_irqsave(&boardp->lock, flags);
4723 if (ASC_NARROW_BOARD(boardp)) {
4724 /*
4725 * Narrow Board
4726 */
4727 if (AscIsIntPending(shost->io_port)) {
4728 ASC_STATS(shost, interrupt);
4729 ASC_DBG(1,
4730 "advansys_interrupt: before AscISR()\n");
4731 AscISR(&boardp->dvc_var.asc_dvc_var);
4732 }
4733 } else {
4734 /*
4735 * Wide Board
4736 */
4737 ASC_DBG(1, "advansys_interrupt: before AdvISR()\n");
4738 if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
4739 ASC_STATS(shost, interrupt);
4740 }
4741 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004742
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004743 /*
4744 * Start waiting requests and create a list of completed requests.
4745 *
4746 * If a reset request is being performed for the board, the reset
4747 * handler will complete pending requests after it has completed.
4748 */
4749 if ((boardp->flags & ASC_HOST_IN_RESET) == 0) {
4750 ASC_DBG2(1,
4751 "advansys_interrupt: done_scp 0x%lx, last_scp 0x%lx\n",
4752 (ulong)done_scp, (ulong)last_scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004753
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004754 /* Start any waiting commands for the board. */
4755 if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
4756 ASC_DBG(1,
4757 "advansys_interrupt: before asc_execute_queue()\n");
4758 asc_execute_queue(&boardp->waiting);
4759 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004760
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004761 /*
4762 * Add to the list of requests that must be completed.
4763 *
4764 * 'done_scp' will always be NULL on the first iteration
4765 * of this loop. 'last_scp' is set at the same time as
4766 * 'done_scp'.
4767 */
4768 if (done_scp == NULL) {
4769 done_scp =
4770 asc_dequeue_list(&boardp->done, &last_scp,
4771 ASC_TID_ALL);
4772 } else {
4773 ASC_ASSERT(last_scp != NULL);
4774 last_scp->host_scribble =
4775 (unsigned char *)asc_dequeue_list(&boardp->
4776 done,
4777 &new_last_scp,
4778 ASC_TID_ALL);
4779 if (new_last_scp != NULL) {
4780 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
4781 last_scp = new_last_scp;
4782 }
4783 }
4784 }
4785 spin_unlock_irqrestore(&boardp->lock, flags);
4786 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004787
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004788 /*
4789 * If interrupts were enabled on entry, then they
4790 * are now enabled here.
4791 *
4792 * Complete all requests on the done list.
4793 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004794
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004795 asc_scsi_done_list(done_scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004796
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004797 ASC_DBG(1, "advansys_interrupt: end\n");
4798 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004799}
4800
4801/*
4802 * Set the number of commands to queue per device for the
4803 * specified host adapter.
4804 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004805static int advansys_slave_configure(struct scsi_device *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004807 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004808
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004809 boardp = ASC_BOARDP(device->host);
4810 boardp->flags |= ASC_SELECT_QUEUE_DEPTHS;
4811 /*
4812 * Save a pointer to the device and set its initial/maximum
4813 * queue depth. Only save the pointer for a lun0 dev though.
4814 */
4815 if (device->lun == 0)
4816 boardp->device[device->id] = device;
4817 if (device->tagged_supported) {
4818 if (ASC_NARROW_BOARD(boardp)) {
4819 scsi_adjust_queue_depth(device, MSG_ORDERED_TAG,
4820 boardp->dvc_var.asc_dvc_var.
4821 max_dvc_qng[device->id]);
4822 } else {
4823 scsi_adjust_queue_depth(device, MSG_ORDERED_TAG,
4824 boardp->dvc_var.adv_dvc_var.
4825 max_dvc_qng);
4826 }
4827 } else {
4828 scsi_adjust_queue_depth(device, 0, device->host->cmd_per_lun);
4829 }
4830 ASC_DBG4(1,
4831 "advansys_slave_configure: device 0x%lx, boardp 0x%lx, id %d, depth %d\n",
4832 (ulong)device, (ulong)boardp, device->id, device->queue_depth);
4833 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004834}
4835
4836/*
4837 * Complete all requests on the singly linked list pointed
4838 * to by 'scp'.
4839 *
4840 * Interrupts can be enabled on entry.
4841 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004842static void asc_scsi_done_list(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004843{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004844 struct scsi_cmnd *tscp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004845
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004846 ASC_DBG(2, "asc_scsi_done_list: begin\n");
4847 while (scp != NULL) {
4848 asc_board_t *boardp;
4849 struct device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004850
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004851 ASC_DBG1(3, "asc_scsi_done_list: scp 0x%lx\n", (ulong)scp);
4852 tscp = REQPNEXT(scp);
4853 scp->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004854
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004855 boardp = ASC_BOARDP(scp->device->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004856
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004857 if (ASC_NARROW_BOARD(boardp))
4858 dev = boardp->dvc_cfg.asc_dvc_cfg.dev;
4859 else
4860 dev = boardp->dvc_cfg.adv_dvc_cfg.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004861
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004862 if (scp->use_sg)
4863 dma_unmap_sg(dev,
4864 (struct scatterlist *)scp->request_buffer,
4865 scp->use_sg, scp->sc_data_direction);
4866 else if (scp->request_bufflen)
4867 dma_unmap_single(dev, scp->SCp.dma_handle,
4868 scp->request_bufflen,
4869 scp->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004870
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004871 ASC_STATS(scp->device->host, done);
4872 ASC_ASSERT(scp->scsi_done != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004873
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004874 scp->scsi_done(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004875
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004876 scp = tscp;
4877 }
4878 ASC_DBG(2, "asc_scsi_done_list: done\n");
4879 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004880}
4881
4882/*
4883 * Execute a single 'Scsi_Cmnd'.
4884 *
4885 * The function 'done' is called when the request has been completed.
4886 *
4887 * Scsi_Cmnd:
4888 *
4889 * host - board controlling device
4890 * device - device to send command
4891 * target - target of device
4892 * lun - lun of device
4893 * cmd_len - length of SCSI CDB
4894 * cmnd - buffer for SCSI 8, 10, or 12 byte CDB
4895 * use_sg - if non-zero indicates scatter-gather request with use_sg elements
4896 *
4897 * if (use_sg == 0) {
4898 * request_buffer - buffer address for request
4899 * request_bufflen - length of request buffer
4900 * } else {
4901 * request_buffer - pointer to scatterlist structure
4902 * }
4903 *
4904 * sense_buffer - sense command buffer
4905 *
4906 * result (4 bytes of an int):
4907 * Byte Meaning
4908 * 0 SCSI Status Byte Code
4909 * 1 SCSI One Byte Message Code
4910 * 2 Host Error Code
4911 * 3 Mid-Level Error Code
4912 *
4913 * host driver fields:
4914 * SCp - Scsi_Pointer used for command processing status
4915 * scsi_done - used to save caller's done function
4916 * host_scribble - used for pointer to another struct scsi_cmnd
4917 *
4918 * If this function returns ASC_NOERROR the request has been enqueued
4919 * on the board's 'active' queue and will be completed from the
4920 * interrupt handler.
4921 *
4922 * If this function returns ASC_NOERROR the request has been enqueued
4923 * on the board's 'done' queue and must be completed by the caller.
4924 *
4925 * If ASC_BUSY is returned the request will be enqueued by the
4926 * caller on the target's waiting queue and re-tried later.
4927 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004928static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004929{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004930 asc_board_t *boardp;
4931 ASC_DVC_VAR *asc_dvc_varp;
4932 ADV_DVC_VAR *adv_dvc_varp;
4933 ADV_SCSI_REQ_Q *adv_scsiqp;
4934 struct scsi_device *device;
4935 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004936
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004937 ASC_DBG2(1, "asc_execute_scsi_cmnd: scp 0x%lx, done 0x%lx\n",
4938 (ulong)scp, (ulong)scp->scsi_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004939
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004940 boardp = ASC_BOARDP(scp->device->host);
4941 device = boardp->device[scp->device->id];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004942
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004943 if (ASC_NARROW_BOARD(boardp)) {
4944 /*
4945 * Build and execute Narrow Board request.
4946 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004947
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004948 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004949
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004950 /*
4951 * Build Asc Library request structure using the
4952 * global structures 'asc_scsi_req' and 'asc_sg_head'.
4953 *
4954 * If an error is returned, then the request has been
4955 * queued on the board done queue. It will be completed
4956 * by the caller.
4957 *
4958 * asc_build_req() can not return ASC_BUSY.
4959 */
4960 if (asc_build_req(boardp, scp) == ASC_ERROR) {
4961 ASC_STATS(scp->device->host, build_error);
4962 return ASC_ERROR;
4963 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004964
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004965 /*
4966 * Execute the command. If there is no error, add the command
4967 * to the active queue.
4968 */
4969 switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) {
4970 case ASC_NOERROR:
4971 ASC_STATS(scp->device->host, exe_noerror);
4972 /*
4973 * Increment monotonically increasing per device successful
4974 * request counter. Wrapping doesn't matter.
4975 */
4976 boardp->reqcnt[scp->device->id]++;
4977 asc_enqueue(&boardp->active, scp, ASC_BACK);
4978 ASC_DBG(1,
4979 "asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n");
4980 break;
4981 case ASC_BUSY:
4982 /*
4983 * Caller will enqueue request on the target's waiting queue
4984 * and retry later.
4985 */
4986 ASC_STATS(scp->device->host, exe_busy);
4987 break;
4988 case ASC_ERROR:
4989 ASC_PRINT2
4990 ("asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
4991 boardp->id, asc_dvc_varp->err_code);
4992 ASC_STATS(scp->device->host, exe_error);
4993 scp->result = HOST_BYTE(DID_ERROR);
4994 asc_enqueue(&boardp->done, scp, ASC_BACK);
4995 break;
4996 default:
4997 ASC_PRINT2
4998 ("asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() unknown, err_code 0x%x\n",
4999 boardp->id, asc_dvc_varp->err_code);
5000 ASC_STATS(scp->device->host, exe_unknown);
5001 scp->result = HOST_BYTE(DID_ERROR);
5002 asc_enqueue(&boardp->done, scp, ASC_BACK);
5003 break;
5004 }
5005 } else {
5006 /*
5007 * Build and execute Wide Board request.
5008 */
5009 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005010
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005011 /*
5012 * Build and get a pointer to an Adv Library request structure.
5013 *
5014 * If the request is successfully built then send it below,
5015 * otherwise return with an error.
5016 */
5017 switch (adv_build_req(boardp, scp, &adv_scsiqp)) {
5018 case ASC_NOERROR:
5019 ASC_DBG(3,
5020 "asc_execute_scsi_cmnd: adv_build_req ASC_NOERROR\n");
5021 break;
5022 case ASC_BUSY:
5023 ASC_DBG(1,
5024 "asc_execute_scsi_cmnd: adv_build_req ASC_BUSY\n");
5025 /*
5026 * If busy is returned the request has not been enqueued.
5027 * It will be enqueued by the caller on the target's waiting
5028 * queue and retried later.
5029 *
5030 * The asc_stats fields 'adv_build_noreq' and 'adv_build_nosg'
5031 * count wide board busy conditions. They are updated in
5032 * adv_build_req and adv_get_sglist, respectively.
5033 */
5034 return ASC_BUSY;
5035 case ASC_ERROR:
5036 /*
5037 * If an error is returned, then the request has been
5038 * queued on the board done queue. It will be completed
5039 * by the caller.
5040 */
5041 default:
5042 ASC_DBG(1,
5043 "asc_execute_scsi_cmnd: adv_build_req ASC_ERROR\n");
5044 ASC_STATS(scp->device->host, build_error);
5045 return ASC_ERROR;
5046 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005047
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005048 /*
5049 * Execute the command. If there is no error, add the command
5050 * to the active queue.
5051 */
5052 switch (ret = AdvExeScsiQueue(adv_dvc_varp, adv_scsiqp)) {
5053 case ASC_NOERROR:
5054 ASC_STATS(scp->device->host, exe_noerror);
5055 /*
5056 * Increment monotonically increasing per device successful
5057 * request counter. Wrapping doesn't matter.
5058 */
5059 boardp->reqcnt[scp->device->id]++;
5060 asc_enqueue(&boardp->active, scp, ASC_BACK);
5061 ASC_DBG(1,
5062 "asc_execute_scsi_cmnd: AdvExeScsiQueue(), ASC_NOERROR\n");
5063 break;
5064 case ASC_BUSY:
5065 /*
5066 * Caller will enqueue request on the target's waiting queue
5067 * and retry later.
5068 */
5069 ASC_STATS(scp->device->host, exe_busy);
5070 break;
5071 case ASC_ERROR:
5072 ASC_PRINT2
5073 ("asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
5074 boardp->id, adv_dvc_varp->err_code);
5075 ASC_STATS(scp->device->host, exe_error);
5076 scp->result = HOST_BYTE(DID_ERROR);
5077 asc_enqueue(&boardp->done, scp, ASC_BACK);
5078 break;
5079 default:
5080 ASC_PRINT2
5081 ("asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() unknown, err_code 0x%x\n",
5082 boardp->id, adv_dvc_varp->err_code);
5083 ASC_STATS(scp->device->host, exe_unknown);
5084 scp->result = HOST_BYTE(DID_ERROR);
5085 asc_enqueue(&boardp->done, scp, ASC_BACK);
5086 break;
5087 }
5088 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005089
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005090 ASC_DBG(1, "asc_execute_scsi_cmnd: end\n");
5091 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005092}
5093
5094/*
5095 * Build a request structure for the Asc Library (Narrow Board).
5096 *
5097 * The global structures 'asc_scsi_q' and 'asc_sg_head' are
5098 * used to build the request.
5099 *
5100 * If an error occurs, then queue the request on the board done
5101 * queue and return ASC_ERROR.
5102 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005103static int asc_build_req(asc_board_t *boardp, struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005104{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005105 struct device *dev = boardp->dvc_cfg.asc_dvc_cfg.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005106
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005107 /*
5108 * Mutually exclusive access is required to 'asc_scsi_q' and
5109 * 'asc_sg_head' until after the request is started.
5110 */
5111 memset(&asc_scsi_q, 0, sizeof(ASC_SCSI_Q));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005112
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005113 /*
5114 * Point the ASC_SCSI_Q to the 'struct scsi_cmnd'.
5115 */
5116 asc_scsi_q.q2.srb_ptr = ASC_VADDR_TO_U32(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005117
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005118 /*
5119 * Build the ASC_SCSI_Q request.
5120 *
5121 * For narrow boards a CDB length maximum of 12 bytes
5122 * is supported.
5123 */
5124 if (scp->cmd_len > ASC_MAX_CDB_LEN) {
5125 ASC_PRINT3
5126 ("asc_build_req: board %d: cmd_len %d > ASC_MAX_CDB_LEN %d\n",
5127 boardp->id, scp->cmd_len, ASC_MAX_CDB_LEN);
5128 scp->result = HOST_BYTE(DID_ERROR);
5129 asc_enqueue(&boardp->done, scp, ASC_BACK);
5130 return ASC_ERROR;
5131 }
5132 asc_scsi_q.cdbptr = &scp->cmnd[0];
5133 asc_scsi_q.q2.cdb_len = scp->cmd_len;
5134 asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->device->id);
5135 asc_scsi_q.q1.target_lun = scp->device->lun;
5136 asc_scsi_q.q2.target_ix =
5137 ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun);
5138 asc_scsi_q.q1.sense_addr =
5139 cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
5140 asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005141
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005142 /*
5143 * If there are any outstanding requests for the current target,
5144 * then every 255th request send an ORDERED request. This heuristic
5145 * tries to retain the benefit of request sorting while preventing
5146 * request starvation. 255 is the max number of tags or pending commands
5147 * a device may have outstanding.
5148 *
5149 * The request count is incremented below for every successfully
5150 * started request.
5151 *
5152 */
5153 if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->device->id] > 0) &&
5154 (boardp->reqcnt[scp->device->id] % 255) == 0) {
5155 asc_scsi_q.q2.tag_code = MSG_ORDERED_TAG;
5156 } else {
5157 asc_scsi_q.q2.tag_code = MSG_SIMPLE_TAG;
5158 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005159
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005160 /*
5161 * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather
5162 * buffer command.
5163 */
5164 if (scp->use_sg == 0) {
5165 /*
5166 * CDB request of single contiguous buffer.
5167 */
5168 ASC_STATS(scp->device->host, cont_cnt);
5169 scp->SCp.dma_handle = scp->request_bufflen ?
5170 dma_map_single(dev, scp->request_buffer,
5171 scp->request_bufflen,
5172 scp->sc_data_direction) : 0;
5173 asc_scsi_q.q1.data_addr = cpu_to_le32(scp->SCp.dma_handle);
5174 asc_scsi_q.q1.data_cnt = cpu_to_le32(scp->request_bufflen);
5175 ASC_STATS_ADD(scp->device->host, cont_xfer,
5176 ASC_CEILING(scp->request_bufflen, 512));
5177 asc_scsi_q.q1.sg_queue_cnt = 0;
5178 asc_scsi_q.sg_head = NULL;
5179 } else {
5180 /*
5181 * CDB scatter-gather request list.
5182 */
5183 int sgcnt;
5184 int use_sg;
5185 struct scatterlist *slp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005186
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005187 slp = (struct scatterlist *)scp->request_buffer;
5188 use_sg =
5189 dma_map_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005190
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005191 if (use_sg > scp->device->host->sg_tablesize) {
5192 ASC_PRINT3
5193 ("asc_build_req: board %d: use_sg %d > sg_tablesize %d\n",
5194 boardp->id, use_sg,
5195 scp->device->host->sg_tablesize);
5196 dma_unmap_sg(dev, slp, scp->use_sg,
5197 scp->sc_data_direction);
5198 scp->result = HOST_BYTE(DID_ERROR);
5199 asc_enqueue(&boardp->done, scp, ASC_BACK);
5200 return ASC_ERROR;
5201 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005202
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005203 ASC_STATS(scp->device->host, sg_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005204
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005205 /*
5206 * Use global ASC_SG_HEAD structure and set the ASC_SCSI_Q
5207 * structure to point to it.
5208 */
5209 memset(&asc_sg_head, 0, sizeof(ASC_SG_HEAD));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005210
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005211 asc_scsi_q.q1.cntl |= QC_SG_HEAD;
5212 asc_scsi_q.sg_head = &asc_sg_head;
5213 asc_scsi_q.q1.data_cnt = 0;
5214 asc_scsi_q.q1.data_addr = 0;
5215 /* This is a byte value, otherwise it would need to be swapped. */
5216 asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = use_sg;
5217 ASC_STATS_ADD(scp->device->host, sg_elem,
5218 asc_sg_head.entry_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005219
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005220 /*
5221 * Convert scatter-gather list into ASC_SG_HEAD list.
5222 */
5223 for (sgcnt = 0; sgcnt < use_sg; sgcnt++, slp++) {
5224 asc_sg_head.sg_list[sgcnt].addr =
5225 cpu_to_le32(sg_dma_address(slp));
5226 asc_sg_head.sg_list[sgcnt].bytes =
5227 cpu_to_le32(sg_dma_len(slp));
5228 ASC_STATS_ADD(scp->device->host, sg_xfer,
5229 ASC_CEILING(sg_dma_len(slp), 512));
5230 }
5231 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005232
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005233 ASC_DBG_PRT_ASC_SCSI_Q(2, &asc_scsi_q);
5234 ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005235
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005236 return ASC_NOERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005237}
5238
5239/*
5240 * Build a request structure for the Adv Library (Wide Board).
5241 *
5242 * If an adv_req_t can not be allocated to issue the request,
5243 * then return ASC_BUSY. If an error occurs, then return ASC_ERROR.
5244 *
5245 * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the
5246 * microcode for DMA addresses or math operations are byte swapped
5247 * to little-endian order.
5248 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005249static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005250adv_build_req(asc_board_t *boardp, struct scsi_cmnd *scp,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005251 ADV_SCSI_REQ_Q **adv_scsiqpp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005252{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005253 adv_req_t *reqp;
5254 ADV_SCSI_REQ_Q *scsiqp;
5255 int i;
5256 int ret;
5257 struct device *dev = boardp->dvc_cfg.adv_dvc_cfg.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005258
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005259 /*
5260 * Allocate an adv_req_t structure from the board to execute
5261 * the command.
5262 */
5263 if (boardp->adv_reqp == NULL) {
5264 ASC_DBG(1, "adv_build_req: no free adv_req_t\n");
5265 ASC_STATS(scp->device->host, adv_build_noreq);
5266 return ASC_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005267 } else {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005268 reqp = boardp->adv_reqp;
5269 boardp->adv_reqp = reqp->next_reqp;
5270 reqp->next_reqp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005271 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005272
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005273 /*
5274 * Get 32-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers.
5275 */
5276 scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005277
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005278 /*
5279 * Initialize the structure.
5280 */
5281 scsiqp->cntl = scsiqp->scsi_cntl = scsiqp->done_status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005282
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005283 /*
5284 * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure.
5285 */
5286 scsiqp->srb_ptr = ASC_VADDR_TO_U32(reqp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005287
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005288 /*
5289 * Set the adv_req_t 'cmndp' to point to the struct scsi_cmnd structure.
5290 */
5291 reqp->cmndp = scp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005292
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005293 /*
5294 * Build the ADV_SCSI_REQ_Q request.
5295 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005296
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005297 /*
5298 * Set CDB length and copy it to the request structure.
5299 * For wide boards a CDB length maximum of 16 bytes
5300 * is supported.
5301 */
5302 if (scp->cmd_len > ADV_MAX_CDB_LEN) {
5303 ASC_PRINT3
5304 ("adv_build_req: board %d: cmd_len %d > ADV_MAX_CDB_LEN %d\n",
5305 boardp->id, scp->cmd_len, ADV_MAX_CDB_LEN);
5306 scp->result = HOST_BYTE(DID_ERROR);
5307 asc_enqueue(&boardp->done, scp, ASC_BACK);
5308 return ASC_ERROR;
5309 }
5310 scsiqp->cdb_len = scp->cmd_len;
5311 /* Copy first 12 CDB bytes to cdb[]. */
5312 for (i = 0; i < scp->cmd_len && i < 12; i++) {
5313 scsiqp->cdb[i] = scp->cmnd[i];
5314 }
5315 /* Copy last 4 CDB bytes, if present, to cdb16[]. */
5316 for (; i < scp->cmd_len; i++) {
5317 scsiqp->cdb16[i - 12] = scp->cmnd[i];
5318 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005319
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005320 scsiqp->target_id = scp->device->id;
5321 scsiqp->target_lun = scp->device->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005322
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005323 scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
5324 scsiqp->sense_len = sizeof(scp->sense_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005325
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005326 /*
5327 * Build ADV_SCSI_REQ_Q for a contiguous buffer or a scatter-gather
5328 * buffer command.
5329 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005330
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005331 scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
5332 scsiqp->vdata_addr = scp->request_buffer;
5333 scsiqp->data_addr = cpu_to_le32(virt_to_bus(scp->request_buffer));
5334
5335 if (scp->use_sg == 0) {
5336 /*
5337 * CDB request of single contiguous buffer.
5338 */
5339 reqp->sgblkp = NULL;
5340 scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
5341 if (scp->request_bufflen) {
5342 scsiqp->vdata_addr = scp->request_buffer;
5343 scp->SCp.dma_handle =
5344 dma_map_single(dev, scp->request_buffer,
5345 scp->request_bufflen,
5346 scp->sc_data_direction);
5347 } else {
5348 scsiqp->vdata_addr = NULL;
5349 scp->SCp.dma_handle = 0;
5350 }
5351 scsiqp->data_addr = cpu_to_le32(scp->SCp.dma_handle);
5352 scsiqp->sg_list_ptr = NULL;
5353 scsiqp->sg_real_addr = 0;
5354 ASC_STATS(scp->device->host, cont_cnt);
5355 ASC_STATS_ADD(scp->device->host, cont_xfer,
5356 ASC_CEILING(scp->request_bufflen, 512));
5357 } else {
5358 /*
5359 * CDB scatter-gather request list.
5360 */
5361 struct scatterlist *slp;
5362 int use_sg;
5363
5364 slp = (struct scatterlist *)scp->request_buffer;
5365 use_sg =
5366 dma_map_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
5367
5368 if (use_sg > ADV_MAX_SG_LIST) {
5369 ASC_PRINT3
5370 ("adv_build_req: board %d: use_sg %d > ADV_MAX_SG_LIST %d\n",
5371 boardp->id, use_sg,
5372 scp->device->host->sg_tablesize);
5373 dma_unmap_sg(dev, slp, scp->use_sg,
5374 scp->sc_data_direction);
5375 scp->result = HOST_BYTE(DID_ERROR);
5376 asc_enqueue(&boardp->done, scp, ASC_BACK);
5377
5378 /*
5379 * Free the 'adv_req_t' structure by adding it back to the
5380 * board free list.
5381 */
5382 reqp->next_reqp = boardp->adv_reqp;
5383 boardp->adv_reqp = reqp;
5384
5385 return ASC_ERROR;
5386 }
5387
5388 if ((ret =
5389 adv_get_sglist(boardp, reqp, scp,
5390 use_sg)) != ADV_SUCCESS) {
5391 /*
5392 * Free the adv_req_t structure by adding it back to the
5393 * board free list.
5394 */
5395 reqp->next_reqp = boardp->adv_reqp;
5396 boardp->adv_reqp = reqp;
5397
5398 return ret;
5399 }
5400
5401 ASC_STATS(scp->device->host, sg_cnt);
5402 ASC_STATS_ADD(scp->device->host, sg_elem, use_sg);
5403 }
5404
5405 ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
5406 ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
5407
5408 *adv_scsiqpp = scsiqp;
5409
5410 return ASC_NOERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005411}
5412
5413/*
5414 * Build scatter-gather list for Adv Library (Wide Board).
5415 *
5416 * Additional ADV_SG_BLOCK structures will need to be allocated
5417 * if the total number of scatter-gather elements exceeds
5418 * NO_OF_SG_PER_BLOCK (15). The ADV_SG_BLOCK structures are
5419 * assumed to be physically contiguous.
5420 *
5421 * Return:
5422 * ADV_SUCCESS(1) - SG List successfully created
5423 * ADV_ERROR(-1) - SG List creation failed
5424 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005425static int
5426adv_get_sglist(asc_board_t *boardp, adv_req_t *reqp, struct scsi_cmnd *scp,
5427 int use_sg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005428{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005429 adv_sgblk_t *sgblkp;
5430 ADV_SCSI_REQ_Q *scsiqp;
5431 struct scatterlist *slp;
5432 int sg_elem_cnt;
5433 ADV_SG_BLOCK *sg_block, *prev_sg_block;
5434 ADV_PADDR sg_block_paddr;
5435 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005436
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005437 scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
5438 slp = (struct scatterlist *)scp->request_buffer;
5439 sg_elem_cnt = use_sg;
5440 prev_sg_block = NULL;
5441 reqp->sgblkp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005442
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005443 do {
5444 /*
5445 * Allocate a 'adv_sgblk_t' structure from the board free
5446 * list. One 'adv_sgblk_t' structure holds NO_OF_SG_PER_BLOCK
5447 * (15) scatter-gather elements.
5448 */
5449 if ((sgblkp = boardp->adv_sgblkp) == NULL) {
5450 ASC_DBG(1, "adv_get_sglist: no free adv_sgblk_t\n");
5451 ASC_STATS(scp->device->host, adv_build_nosg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005452
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005453 /*
5454 * Allocation failed. Free 'adv_sgblk_t' structures already
5455 * allocated for the request.
5456 */
5457 while ((sgblkp = reqp->sgblkp) != NULL) {
5458 /* Remove 'sgblkp' from the request list. */
5459 reqp->sgblkp = sgblkp->next_sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005460
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005461 /* Add 'sgblkp' to the board free list. */
5462 sgblkp->next_sgblkp = boardp->adv_sgblkp;
5463 boardp->adv_sgblkp = sgblkp;
5464 }
5465 return ASC_BUSY;
5466 } else {
5467 /* Complete 'adv_sgblk_t' board allocation. */
5468 boardp->adv_sgblkp = sgblkp->next_sgblkp;
5469 sgblkp->next_sgblkp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005470
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005471 /*
5472 * Get 8 byte aligned virtual and physical addresses for
5473 * the allocated ADV_SG_BLOCK structure.
5474 */
5475 sg_block =
5476 (ADV_SG_BLOCK *)ADV_8BALIGN(&sgblkp->sg_block);
5477 sg_block_paddr = virt_to_bus(sg_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005478
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005479 /*
5480 * Check if this is the first 'adv_sgblk_t' for the request.
5481 */
5482 if (reqp->sgblkp == NULL) {
5483 /* Request's first scatter-gather block. */
5484 reqp->sgblkp = sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005485
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005486 /*
5487 * Set ADV_SCSI_REQ_T ADV_SG_BLOCK virtual and physical
5488 * address pointers.
5489 */
5490 scsiqp->sg_list_ptr = sg_block;
5491 scsiqp->sg_real_addr =
5492 cpu_to_le32(sg_block_paddr);
5493 } else {
5494 /* Request's second or later scatter-gather block. */
5495 sgblkp->next_sgblkp = reqp->sgblkp;
5496 reqp->sgblkp = sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005497
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005498 /*
5499 * Point the previous ADV_SG_BLOCK structure to
5500 * the newly allocated ADV_SG_BLOCK structure.
5501 */
5502 ASC_ASSERT(prev_sg_block != NULL);
5503 prev_sg_block->sg_ptr =
5504 cpu_to_le32(sg_block_paddr);
5505 }
5506 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005507
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005508 for (i = 0; i < NO_OF_SG_PER_BLOCK; i++) {
5509 sg_block->sg_list[i].sg_addr =
5510 cpu_to_le32(sg_dma_address(slp));
5511 sg_block->sg_list[i].sg_count =
5512 cpu_to_le32(sg_dma_len(slp));
5513 ASC_STATS_ADD(scp->device->host, sg_xfer,
5514 ASC_CEILING(sg_dma_len(slp), 512));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005515
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005516 if (--sg_elem_cnt == 0) { /* Last ADV_SG_BLOCK and scatter-gather entry. */
5517 sg_block->sg_cnt = i + 1;
5518 sg_block->sg_ptr = 0L; /* Last ADV_SG_BLOCK in list. */
5519 return ADV_SUCCESS;
5520 }
5521 slp++;
5522 }
5523 sg_block->sg_cnt = NO_OF_SG_PER_BLOCK;
5524 prev_sg_block = sg_block;
5525 }
5526 while (1);
5527 /* NOTREACHED */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005528}
5529
5530/*
5531 * asc_isr_callback() - Second Level Interrupt Handler called by AscISR().
5532 *
5533 * Interrupt callback function for the Narrow SCSI Asc Library.
5534 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005535static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005536{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005537 asc_board_t *boardp;
5538 struct scsi_cmnd *scp;
5539 struct Scsi_Host *shost;
5540 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005541
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005542 ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp 0x%lx, qdonep 0x%lx\n",
5543 (ulong)asc_dvc_varp, (ulong)qdonep);
5544 ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005545
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005546 /*
5547 * Get the struct scsi_cmnd structure and Scsi_Host structure for the
5548 * command that has been completed.
5549 */
5550 scp = (struct scsi_cmnd *)ASC_U32_TO_VADDR(qdonep->d2.srb_ptr);
5551 ASC_DBG1(1, "asc_isr_callback: scp 0x%lx\n", (ulong)scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005552
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005553 if (scp == NULL) {
5554 ASC_PRINT("asc_isr_callback: scp is NULL\n");
5555 return;
5556 }
5557 ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005558
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005559 /*
5560 * If the request's host pointer is not valid, display a
5561 * message and return.
5562 */
5563 shost = scp->device->host;
5564 for (i = 0; i < asc_board_count; i++) {
5565 if (asc_host[i] == shost) {
5566 break;
5567 }
5568 }
5569 if (i == asc_board_count) {
5570 ASC_PRINT2
5571 ("asc_isr_callback: scp 0x%lx has bad host pointer, host 0x%lx\n",
5572 (ulong)scp, (ulong)shost);
5573 return;
5574 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005575
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005576 ASC_STATS(shost, callback);
5577 ASC_DBG1(1, "asc_isr_callback: shost 0x%lx\n", (ulong)shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005578
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005579 /*
5580 * If the request isn't found on the active queue, it may
5581 * have been removed to handle a reset request.
5582 * Display a message and return.
5583 */
5584 boardp = ASC_BOARDP(shost);
5585 ASC_ASSERT(asc_dvc_varp == &boardp->dvc_var.asc_dvc_var);
5586 if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
5587 ASC_PRINT2
5588 ("asc_isr_callback: board %d: scp 0x%lx not on active queue\n",
5589 boardp->id, (ulong)scp);
5590 return;
5591 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005592
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005593 /*
5594 * 'qdonep' contains the command's ending status.
5595 */
5596 switch (qdonep->d3.done_stat) {
5597 case QD_NO_ERROR:
5598 ASC_DBG(2, "asc_isr_callback: QD_NO_ERROR\n");
5599 scp->result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005600
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005601 /*
5602 * If an INQUIRY command completed successfully, then call
5603 * the AscInquiryHandling() function to set-up the device.
5604 */
5605 if (scp->cmnd[0] == INQUIRY && scp->device->lun == 0 &&
5606 (scp->request_bufflen - qdonep->remain_bytes) >= 8) {
5607 AscInquiryHandling(asc_dvc_varp, scp->device->id & 0x7,
5608 (ASC_SCSI_INQUIRY *)scp->
5609 request_buffer);
5610 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005611
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005612 /*
5613 * Check for an underrun condition.
5614 *
5615 * If there was no error and an underrun condition, then
5616 * then return the number of underrun bytes.
5617 */
5618 if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 &&
5619 qdonep->remain_bytes <= scp->request_bufflen) {
5620 ASC_DBG1(1,
5621 "asc_isr_callback: underrun condition %u bytes\n",
5622 (unsigned)qdonep->remain_bytes);
5623 scp->resid = qdonep->remain_bytes;
5624 }
5625 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005626
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005627 case QD_WITH_ERROR:
5628 ASC_DBG(2, "asc_isr_callback: QD_WITH_ERROR\n");
5629 switch (qdonep->d3.host_stat) {
5630 case QHSTA_NO_ERROR:
5631 if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) {
5632 ASC_DBG(2,
5633 "asc_isr_callback: SAM_STAT_CHECK_CONDITION\n");
5634 ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
5635 sizeof(scp->sense_buffer));
5636 /*
5637 * Note: The 'status_byte()' macro used by target drivers
5638 * defined in scsi.h shifts the status byte returned by
5639 * host drivers right by 1 bit. This is why target drivers
5640 * also use right shifted status byte definitions. For
5641 * instance target drivers use CHECK_CONDITION, defined to
5642 * 0x1, instead of the SCSI defined check condition value
5643 * of 0x2. Host drivers are supposed to return the status
5644 * byte as it is defined by SCSI.
5645 */
5646 scp->result = DRIVER_BYTE(DRIVER_SENSE) |
5647 STATUS_BYTE(qdonep->d3.scsi_stat);
5648 } else {
5649 scp->result = STATUS_BYTE(qdonep->d3.scsi_stat);
5650 }
5651 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005652
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005653 default:
5654 /* QHSTA error occurred */
5655 ASC_DBG1(1, "asc_isr_callback: host_stat 0x%x\n",
5656 qdonep->d3.host_stat);
5657 scp->result = HOST_BYTE(DID_BAD_TARGET);
5658 break;
5659 }
5660 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005661
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005662 case QD_ABORTED_BY_HOST:
5663 ASC_DBG(1, "asc_isr_callback: QD_ABORTED_BY_HOST\n");
5664 scp->result =
5665 HOST_BYTE(DID_ABORT) | MSG_BYTE(qdonep->d3.
5666 scsi_msg) |
5667 STATUS_BYTE(qdonep->d3.scsi_stat);
5668 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005669
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005670 default:
5671 ASC_DBG1(1, "asc_isr_callback: done_stat 0x%x\n",
5672 qdonep->d3.done_stat);
5673 scp->result =
5674 HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.
5675 scsi_msg) |
5676 STATUS_BYTE(qdonep->d3.scsi_stat);
5677 break;
5678 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005679
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005680 /*
5681 * If the 'init_tidmask' bit isn't already set for the target and the
5682 * current request finished normally, then set the bit for the target
5683 * to indicate that a device is present.
5684 */
5685 if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
5686 qdonep->d3.done_stat == QD_NO_ERROR &&
5687 qdonep->d3.host_stat == QHSTA_NO_ERROR) {
5688 boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
5689 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005690
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005691 /*
5692 * Because interrupts may be enabled by the 'struct scsi_cmnd' done
5693 * function, add the command to the end of the board's done queue.
5694 * The done function for the command will be called from
5695 * advansys_interrupt().
5696 */
5697 asc_enqueue(&boardp->done, scp, ASC_BACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005698
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005699 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005700}
5701
5702/*
5703 * adv_isr_callback() - Second Level Interrupt Handler called by AdvISR().
5704 *
5705 * Callback function for the Wide SCSI Adv Library.
5706 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005707static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005708{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005709 asc_board_t *boardp;
5710 adv_req_t *reqp;
5711 adv_sgblk_t *sgblkp;
5712 struct scsi_cmnd *scp;
5713 struct Scsi_Host *shost;
5714 int i;
5715 ADV_DCNT resid_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005716
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005717 ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp 0x%lx, scsiqp 0x%lx\n",
5718 (ulong)adv_dvc_varp, (ulong)scsiqp);
5719 ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005720
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005721 /*
5722 * Get the adv_req_t structure for the command that has been
5723 * completed. The adv_req_t structure actually contains the
5724 * completed ADV_SCSI_REQ_Q structure.
5725 */
5726 reqp = (adv_req_t *)ADV_U32_TO_VADDR(scsiqp->srb_ptr);
5727 ASC_DBG1(1, "adv_isr_callback: reqp 0x%lx\n", (ulong)reqp);
5728 if (reqp == NULL) {
5729 ASC_PRINT("adv_isr_callback: reqp is NULL\n");
5730 return;
5731 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005732
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005733 /*
5734 * Get the struct scsi_cmnd structure and Scsi_Host structure for the
5735 * command that has been completed.
5736 *
5737 * Note: The adv_req_t request structure and adv_sgblk_t structure,
5738 * if any, are dropped, because a board structure pointer can not be
5739 * determined.
5740 */
5741 scp = reqp->cmndp;
5742 ASC_DBG1(1, "adv_isr_callback: scp 0x%lx\n", (ulong)scp);
5743 if (scp == NULL) {
5744 ASC_PRINT
5745 ("adv_isr_callback: scp is NULL; adv_req_t dropped.\n");
5746 return;
5747 }
5748 ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005749
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005750 /*
5751 * If the request's host pointer is not valid, display a message
5752 * and return.
5753 */
5754 shost = scp->device->host;
5755 for (i = 0; i < asc_board_count; i++) {
5756 if (asc_host[i] == shost) {
5757 break;
5758 }
5759 }
5760 /*
5761 * Note: If the host structure is not found, the adv_req_t request
5762 * structure and adv_sgblk_t structure, if any, is dropped.
5763 */
5764 if (i == asc_board_count) {
5765 ASC_PRINT2
5766 ("adv_isr_callback: scp 0x%lx has bad host pointer, host 0x%lx\n",
5767 (ulong)scp, (ulong)shost);
5768 return;
5769 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005770
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005771 ASC_STATS(shost, callback);
5772 ASC_DBG1(1, "adv_isr_callback: shost 0x%lx\n", (ulong)shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005773
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005774 /*
5775 * If the request isn't found on the active queue, it may have been
5776 * removed to handle a reset request. Display a message and return.
5777 *
5778 * Note: Because the structure may still be in use don't attempt
5779 * to free the adv_req_t and adv_sgblk_t, if any, structures.
5780 */
5781 boardp = ASC_BOARDP(shost);
5782 ASC_ASSERT(adv_dvc_varp == &boardp->dvc_var.adv_dvc_var);
5783 if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
5784 ASC_PRINT2
5785 ("adv_isr_callback: board %d: scp 0x%lx not on active queue\n",
5786 boardp->id, (ulong)scp);
5787 return;
5788 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005789
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005790 /*
5791 * 'done_status' contains the command's ending status.
5792 */
5793 switch (scsiqp->done_status) {
5794 case QD_NO_ERROR:
5795 ASC_DBG(2, "adv_isr_callback: QD_NO_ERROR\n");
5796 scp->result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005797
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005798 /*
5799 * Check for an underrun condition.
5800 *
5801 * If there was no error and an underrun condition, then
5802 * then return the number of underrun bytes.
5803 */
5804 resid_cnt = le32_to_cpu(scsiqp->data_cnt);
5805 if (scp->request_bufflen != 0 && resid_cnt != 0 &&
5806 resid_cnt <= scp->request_bufflen) {
5807 ASC_DBG1(1,
5808 "adv_isr_callback: underrun condition %lu bytes\n",
5809 (ulong)resid_cnt);
5810 scp->resid = resid_cnt;
5811 }
5812 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005813
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005814 case QD_WITH_ERROR:
5815 ASC_DBG(2, "adv_isr_callback: QD_WITH_ERROR\n");
5816 switch (scsiqp->host_status) {
5817 case QHSTA_NO_ERROR:
5818 if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) {
5819 ASC_DBG(2,
5820 "adv_isr_callback: SAM_STAT_CHECK_CONDITION\n");
5821 ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
5822 sizeof(scp->sense_buffer));
5823 /*
5824 * Note: The 'status_byte()' macro used by target drivers
5825 * defined in scsi.h shifts the status byte returned by
5826 * host drivers right by 1 bit. This is why target drivers
5827 * also use right shifted status byte definitions. For
5828 * instance target drivers use CHECK_CONDITION, defined to
5829 * 0x1, instead of the SCSI defined check condition value
5830 * of 0x2. Host drivers are supposed to return the status
5831 * byte as it is defined by SCSI.
5832 */
5833 scp->result = DRIVER_BYTE(DRIVER_SENSE) |
5834 STATUS_BYTE(scsiqp->scsi_status);
5835 } else {
5836 scp->result = STATUS_BYTE(scsiqp->scsi_status);
5837 }
5838 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005839
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005840 default:
5841 /* Some other QHSTA error occurred. */
5842 ASC_DBG1(1, "adv_isr_callback: host_status 0x%x\n",
5843 scsiqp->host_status);
5844 scp->result = HOST_BYTE(DID_BAD_TARGET);
5845 break;
5846 }
5847 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005848
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005849 case QD_ABORTED_BY_HOST:
5850 ASC_DBG(1, "adv_isr_callback: QD_ABORTED_BY_HOST\n");
5851 scp->result =
5852 HOST_BYTE(DID_ABORT) | STATUS_BYTE(scsiqp->scsi_status);
5853 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005854
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005855 default:
5856 ASC_DBG1(1, "adv_isr_callback: done_status 0x%x\n",
5857 scsiqp->done_status);
5858 scp->result =
5859 HOST_BYTE(DID_ERROR) | STATUS_BYTE(scsiqp->scsi_status);
5860 break;
5861 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005862
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005863 /*
5864 * If the 'init_tidmask' bit isn't already set for the target and the
5865 * current request finished normally, then set the bit for the target
5866 * to indicate that a device is present.
5867 */
5868 if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
5869 scsiqp->done_status == QD_NO_ERROR &&
5870 scsiqp->host_status == QHSTA_NO_ERROR) {
5871 boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
5872 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005873
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005874 /*
5875 * Because interrupts may be enabled by the 'struct scsi_cmnd' done
5876 * function, add the command to the end of the board's done queue.
5877 * The done function for the command will be called from
5878 * advansys_interrupt().
5879 */
5880 asc_enqueue(&boardp->done, scp, ASC_BACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005881
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005882 /*
5883 * Free all 'adv_sgblk_t' structures allocated for the request.
5884 */
5885 while ((sgblkp = reqp->sgblkp) != NULL) {
5886 /* Remove 'sgblkp' from the request list. */
5887 reqp->sgblkp = sgblkp->next_sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005888
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005889 /* Add 'sgblkp' to the board free list. */
5890 sgblkp->next_sgblkp = boardp->adv_sgblkp;
5891 boardp->adv_sgblkp = sgblkp;
5892 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005893
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005894 /*
5895 * Free the adv_req_t structure used with the command by adding
5896 * it back to the board free list.
5897 */
5898 reqp->next_reqp = boardp->adv_reqp;
5899 boardp->adv_reqp = reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005900
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005901 ASC_DBG(1, "adv_isr_callback: done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005902
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005903 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005904}
5905
5906/*
5907 * adv_async_callback() - Adv Library asynchronous event callback function.
5908 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005909static void adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005910{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005911 switch (code) {
5912 case ADV_ASYNC_SCSI_BUS_RESET_DET:
5913 /*
5914 * The firmware detected a SCSI Bus reset.
5915 */
5916 ASC_DBG(0,
5917 "adv_async_callback: ADV_ASYNC_SCSI_BUS_RESET_DET\n");
5918 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005919
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005920 case ADV_ASYNC_RDMA_FAILURE:
5921 /*
5922 * Handle RDMA failure by resetting the SCSI Bus and
5923 * possibly the chip if it is unresponsive. Log the error
5924 * with a unique code.
5925 */
5926 ASC_DBG(0, "adv_async_callback: ADV_ASYNC_RDMA_FAILURE\n");
5927 AdvResetChipAndSB(adv_dvc_varp);
5928 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005929
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005930 case ADV_HOST_SCSI_BUS_RESET:
5931 /*
5932 * Host generated SCSI bus reset occurred.
5933 */
5934 ASC_DBG(0, "adv_async_callback: ADV_HOST_SCSI_BUS_RESET\n");
5935 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005936
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005937 default:
5938 ASC_DBG1(0, "DvcAsyncCallBack: unknown code 0x%x\n", code);
5939 break;
5940 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005941}
5942
5943/*
5944 * Add a 'REQP' to the end of specified queue. Set 'tidmask'
5945 * to indicate a command is queued for the device.
5946 *
5947 * 'flag' may be either ASC_FRONT or ASC_BACK.
5948 *
5949 * 'REQPNEXT(reqp)' returns reqp's next pointer.
5950 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005951static void asc_enqueue(asc_queue_t *ascq, REQP reqp, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005952{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005953 int tid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005954
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005955 ASC_DBG3(3, "asc_enqueue: ascq 0x%lx, reqp 0x%lx, flag %d\n",
5956 (ulong)ascq, (ulong)reqp, flag);
5957 ASC_ASSERT(reqp != NULL);
5958 ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK);
5959 tid = REQPTID(reqp);
5960 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
5961 if (flag == ASC_FRONT) {
5962 reqp->host_scribble = (unsigned char *)ascq->q_first[tid];
5963 ascq->q_first[tid] = reqp;
5964 /* If the queue was empty, set the last pointer. */
5965 if (ascq->q_last[tid] == NULL) {
5966 ascq->q_last[tid] = reqp;
5967 }
5968 } else { /* ASC_BACK */
5969 if (ascq->q_last[tid] != NULL) {
5970 ascq->q_last[tid]->host_scribble =
5971 (unsigned char *)reqp;
5972 }
5973 ascq->q_last[tid] = reqp;
5974 reqp->host_scribble = NULL;
5975 /* If the queue was empty, set the first pointer. */
5976 if (ascq->q_first[tid] == NULL) {
5977 ascq->q_first[tid] = reqp;
5978 }
5979 }
5980 /* The queue has at least one entry, set its bit. */
5981 ascq->q_tidmask |= ADV_TID_TO_TIDMASK(tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005982#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005983 /* Maintain request queue statistics. */
5984 ascq->q_tot_cnt[tid]++;
5985 ascq->q_cur_cnt[tid]++;
5986 if (ascq->q_cur_cnt[tid] > ascq->q_max_cnt[tid]) {
5987 ascq->q_max_cnt[tid] = ascq->q_cur_cnt[tid];
5988 ASC_DBG2(2, "asc_enqueue: new q_max_cnt[%d] %d\n",
5989 tid, ascq->q_max_cnt[tid]);
5990 }
5991 REQPTIME(reqp) = REQTIMESTAMP();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005992#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005993 ASC_DBG1(3, "asc_enqueue: reqp 0x%lx\n", (ulong)reqp);
5994 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005995}
5996
5997/*
5998 * Return first queued 'REQP' on the specified queue for
5999 * the specified target device. Clear the 'tidmask' bit for
6000 * the device if no more commands are left queued for it.
6001 *
6002 * 'REQPNEXT(reqp)' returns reqp's next pointer.
6003 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006004static REQP asc_dequeue(asc_queue_t *ascq, int tid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006005{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006006 REQP reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006007
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006008 ASC_DBG2(3, "asc_dequeue: ascq 0x%lx, tid %d\n", (ulong)ascq, tid);
6009 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
6010 if ((reqp = ascq->q_first[tid]) != NULL) {
6011 ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid));
6012 ascq->q_first[tid] = REQPNEXT(reqp);
6013 /* If the queue is empty, clear its bit and the last pointer. */
6014 if (ascq->q_first[tid] == NULL) {
6015 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
6016 ASC_ASSERT(ascq->q_last[tid] == reqp);
6017 ascq->q_last[tid] = NULL;
6018 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006019#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006020 /* Maintain request queue statistics. */
6021 ascq->q_cur_cnt[tid]--;
6022 ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
6023 REQTIMESTAT("asc_dequeue", ascq, reqp, tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006024#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006025 }
6026 ASC_DBG1(3, "asc_dequeue: reqp 0x%lx\n", (ulong)reqp);
6027 return reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006028}
6029
6030/*
6031 * Return a pointer to a singly linked list of all the requests queued
6032 * for 'tid' on the 'asc_queue_t' pointed to by 'ascq'.
6033 *
6034 * If 'lastpp' is not NULL, '*lastpp' will be set to point to the
6035 * the last request returned in the singly linked list.
6036 *
6037 * 'tid' should either be a valid target id or if it is ASC_TID_ALL,
6038 * then all queued requests are concatenated into one list and
6039 * returned.
6040 *
6041 * Note: If 'lastpp' is used to append a new list to the end of
6042 * an old list, only change the old list last pointer if '*lastpp'
6043 * (or the function return value) is not NULL, i.e. use a temporary
6044 * variable for 'lastpp' and check its value after the function return
6045 * before assigning it to the list last pointer.
6046 *
6047 * Unfortunately collecting queuing time statistics adds overhead to
6048 * the function that isn't inherent to the function's algorithm.
6049 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006050static REQP asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006051{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006052 REQP firstp, lastp;
6053 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006054
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006055 ASC_DBG2(3, "asc_dequeue_list: ascq 0x%lx, tid %d\n", (ulong)ascq, tid);
6056 ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ADV_MAX_TID));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006057
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006058 /*
6059 * If 'tid' is not ASC_TID_ALL, return requests only for
6060 * the specified 'tid'. If 'tid' is ASC_TID_ALL, return all
6061 * requests for all tids.
6062 */
6063 if (tid != ASC_TID_ALL) {
6064 /* Return all requests for the specified 'tid'. */
6065 if ((ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid)) == 0) {
6066 /* List is empty; Set first and last return pointers to NULL. */
6067 firstp = lastp = NULL;
6068 } else {
6069 firstp = ascq->q_first[tid];
6070 lastp = ascq->q_last[tid];
6071 ascq->q_first[tid] = ascq->q_last[tid] = NULL;
6072 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006073#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006074 {
6075 REQP reqp;
6076 ascq->q_cur_cnt[tid] = 0;
6077 for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
6078 REQTIMESTAT("asc_dequeue_list", ascq,
6079 reqp, tid);
6080 }
6081 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006082#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006083 }
6084 } else {
6085 /* Return all requests for all tids. */
6086 firstp = lastp = NULL;
6087 for (i = 0; i <= ADV_MAX_TID; i++) {
6088 if (ascq->q_tidmask & ADV_TID_TO_TIDMASK(i)) {
6089 if (firstp == NULL) {
6090 firstp = ascq->q_first[i];
6091 lastp = ascq->q_last[i];
6092 } else {
6093 ASC_ASSERT(lastp != NULL);
6094 lastp->host_scribble =
6095 (unsigned char *)ascq->q_first[i];
6096 lastp = ascq->q_last[i];
6097 }
6098 ascq->q_first[i] = ascq->q_last[i] = NULL;
6099 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006100#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006101 ascq->q_cur_cnt[i] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006102#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006103 }
6104 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006105#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006106 {
6107 REQP reqp;
6108 for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
6109 REQTIMESTAT("asc_dequeue_list", ascq, reqp,
6110 reqp->device->id);
6111 }
6112 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006113#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006114 }
6115 if (lastpp) {
6116 *lastpp = lastp;
6117 }
6118 ASC_DBG1(3, "asc_dequeue_list: firstp 0x%lx\n", (ulong)firstp);
6119 return firstp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006120}
6121
6122/*
6123 * Remove the specified 'REQP' from the specified queue for
6124 * the specified target device. Clear the 'tidmask' bit for the
6125 * device if no more commands are left queued for it.
6126 *
6127 * 'REQPNEXT(reqp)' returns reqp's the next pointer.
6128 *
6129 * Return ASC_TRUE if the command was found and removed,
6130 * otherwise return ASC_FALSE.
6131 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006132static int asc_rmqueue(asc_queue_t *ascq, REQP reqp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006133{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006134 REQP currp, prevp;
6135 int tid;
6136 int ret = ASC_FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006137
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006138 ASC_DBG2(3, "asc_rmqueue: ascq 0x%lx, reqp 0x%lx\n",
6139 (ulong)ascq, (ulong)reqp);
6140 ASC_ASSERT(reqp != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006141
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006142 tid = REQPTID(reqp);
6143 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006144
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006145 /*
6146 * Handle the common case of 'reqp' being the first
6147 * entry on the queue.
6148 */
6149 if (reqp == ascq->q_first[tid]) {
6150 ret = ASC_TRUE;
6151 ascq->q_first[tid] = REQPNEXT(reqp);
6152 /* If the queue is now empty, clear its bit and the last pointer. */
6153 if (ascq->q_first[tid] == NULL) {
6154 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
6155 ASC_ASSERT(ascq->q_last[tid] == reqp);
6156 ascq->q_last[tid] = NULL;
6157 }
6158 } else if (ascq->q_first[tid] != NULL) {
6159 ASC_ASSERT(ascq->q_last[tid] != NULL);
6160 /*
6161 * Because the case of 'reqp' being the first entry has been
6162 * handled above and it is known the queue is not empty, if
6163 * 'reqp' is found on the queue it is guaranteed the queue will
6164 * not become empty and that 'q_first[tid]' will not be changed.
6165 *
6166 * Set 'prevp' to the first entry, 'currp' to the second entry,
6167 * and search for 'reqp'.
6168 */
6169 for (prevp = ascq->q_first[tid], currp = REQPNEXT(prevp);
6170 currp; prevp = currp, currp = REQPNEXT(currp)) {
6171 if (currp == reqp) {
6172 ret = ASC_TRUE;
6173 prevp->host_scribble =
6174 (unsigned char *)REQPNEXT(currp);
6175 reqp->host_scribble = NULL;
6176 if (ascq->q_last[tid] == reqp) {
6177 ascq->q_last[tid] = prevp;
6178 }
6179 break;
6180 }
6181 }
6182 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006183#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006184 /* Maintain request queue statistics. */
6185 if (ret == ASC_TRUE) {
6186 ascq->q_cur_cnt[tid]--;
6187 REQTIMESTAT("asc_rmqueue", ascq, reqp, tid);
6188 }
6189 ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006190#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006191 ASC_DBG2(3, "asc_rmqueue: reqp 0x%lx, ret %d\n", (ulong)reqp, ret);
6192 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006193}
6194
6195/*
6196 * Execute as many queued requests as possible for the specified queue.
6197 *
6198 * Calls asc_execute_scsi_cmnd() to execute a REQP/struct scsi_cmnd.
6199 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006200static void asc_execute_queue(asc_queue_t *ascq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006201{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006202 ADV_SCSI_BIT_ID_TYPE scan_tidmask;
6203 REQP reqp;
6204 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006205
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006206 ASC_DBG1(1, "asc_execute_queue: ascq 0x%lx\n", (ulong)ascq);
6207 /*
6208 * Execute queued commands for devices attached to
6209 * the current board in round-robin fashion.
6210 */
6211 scan_tidmask = ascq->q_tidmask;
6212 do {
6213 for (i = 0; i <= ADV_MAX_TID; i++) {
6214 if (scan_tidmask & ADV_TID_TO_TIDMASK(i)) {
6215 if ((reqp = asc_dequeue(ascq, i)) == NULL) {
6216 scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
6217 } else
6218 if (asc_execute_scsi_cmnd
6219 ((struct scsi_cmnd *)reqp)
6220 == ASC_BUSY) {
6221 scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
6222 /*
6223 * The request returned ASC_BUSY. Enqueue at the front of
6224 * target's waiting list to maintain correct ordering.
6225 */
6226 asc_enqueue(ascq, reqp, ASC_FRONT);
6227 }
6228 }
6229 }
6230 } while (scan_tidmask);
6231 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006232}
6233
6234#ifdef CONFIG_PROC_FS
6235/*
6236 * asc_prt_board_devices()
6237 *
6238 * Print driver information for devices attached to the board.
6239 *
6240 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6241 * cf. asc_prt_line().
6242 *
6243 * Return the number of characters copied into 'cp'. No more than
6244 * 'cplen' characters will be copied to 'cp'.
6245 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006246static int asc_prt_board_devices(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006247{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006248 asc_board_t *boardp;
6249 int leftlen;
6250 int totlen;
6251 int len;
6252 int chip_scsi_id;
6253 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006254
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006255 boardp = ASC_BOARDP(shost);
6256 leftlen = cplen;
6257 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006258
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006259 len = asc_prt_line(cp, leftlen,
6260 "\nDevice Information for AdvanSys SCSI Host %d:\n",
6261 shost->host_no);
6262 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006263
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006264 if (ASC_NARROW_BOARD(boardp)) {
6265 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
6266 } else {
6267 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
6268 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006269
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006270 len = asc_prt_line(cp, leftlen, "Target IDs Detected:");
6271 ASC_PRT_NEXT();
6272 for (i = 0; i <= ADV_MAX_TID; i++) {
6273 if (boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) {
6274 len = asc_prt_line(cp, leftlen, " %X,", i);
6275 ASC_PRT_NEXT();
6276 }
6277 }
6278 len = asc_prt_line(cp, leftlen, " (%X=Host Adapter)\n", chip_scsi_id);
6279 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006280
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006281 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006282}
6283
6284/*
6285 * Display Wide Board BIOS Information.
6286 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006287static int asc_prt_adv_bios(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006288{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006289 asc_board_t *boardp;
6290 int leftlen;
6291 int totlen;
6292 int len;
6293 ushort major, minor, letter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006294
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006295 boardp = ASC_BOARDP(shost);
6296 leftlen = cplen;
6297 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006298
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006299 len = asc_prt_line(cp, leftlen, "\nROM BIOS Version: ");
6300 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006301
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006302 /*
6303 * If the BIOS saved a valid signature, then fill in
6304 * the BIOS code segment base address.
6305 */
6306 if (boardp->bios_signature != 0x55AA) {
6307 len = asc_prt_line(cp, leftlen, "Disabled or Pre-3.1\n");
6308 ASC_PRT_NEXT();
6309 len = asc_prt_line(cp, leftlen,
6310 "BIOS either disabled or Pre-3.1. If it is pre-3.1, then a newer version\n");
6311 ASC_PRT_NEXT();
6312 len = asc_prt_line(cp, leftlen,
6313 "can be found at the ConnectCom FTP site: ftp://ftp.connectcom.net/pub\n");
6314 ASC_PRT_NEXT();
6315 } else {
6316 major = (boardp->bios_version >> 12) & 0xF;
6317 minor = (boardp->bios_version >> 8) & 0xF;
6318 letter = (boardp->bios_version & 0xFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006319
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006320 len = asc_prt_line(cp, leftlen, "%d.%d%c\n",
6321 major, minor,
6322 letter >= 26 ? '?' : letter + 'A');
6323 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006324
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006325 /*
6326 * Current available ROM BIOS release is 3.1I for UW
6327 * and 3.2I for U2W. This code doesn't differentiate
6328 * UW and U2W boards.
6329 */
6330 if (major < 3 || (major <= 3 && minor < 1) ||
6331 (major <= 3 && minor <= 1 && letter < ('I' - 'A'))) {
6332 len = asc_prt_line(cp, leftlen,
6333 "Newer version of ROM BIOS is available at the ConnectCom FTP site:\n");
6334 ASC_PRT_NEXT();
6335 len = asc_prt_line(cp, leftlen,
6336 "ftp://ftp.connectcom.net/pub\n");
6337 ASC_PRT_NEXT();
6338 }
6339 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006340
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006341 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006342}
6343
6344/*
6345 * Add serial number to information bar if signature AAh
6346 * is found in at bit 15-9 (7 bits) of word 1.
6347 *
6348 * Serial Number consists fo 12 alpha-numeric digits.
6349 *
6350 * 1 - Product type (A,B,C,D..) Word0: 15-13 (3 bits)
6351 * 2 - MFG Location (A,B,C,D..) Word0: 12-10 (3 bits)
6352 * 3-4 - Product ID (0-99) Word0: 9-0 (10 bits)
6353 * 5 - Product revision (A-J) Word0: " "
6354 *
6355 * Signature Word1: 15-9 (7 bits)
6356 * 6 - Year (0-9) Word1: 8-6 (3 bits) & Word2: 15 (1 bit)
6357 * 7-8 - Week of the year (1-52) Word1: 5-0 (6 bits)
6358 *
6359 * 9-12 - Serial Number (A001-Z999) Word2: 14-0 (15 bits)
6360 *
6361 * Note 1: Only production cards will have a serial number.
6362 *
6363 * Note 2: Signature is most significant 7 bits (0xFE).
6364 *
6365 * Returns ASC_TRUE if serial number found, otherwise returns ASC_FALSE.
6366 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006367static int asc_get_eeprom_string(ushort *serialnum, uchar *cp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006368{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006369 ushort w, num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006370
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006371 if ((serialnum[1] & 0xFE00) != ((ushort)0xAA << 8)) {
6372 return ASC_FALSE;
6373 } else {
6374 /*
6375 * First word - 6 digits.
6376 */
6377 w = serialnum[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006378
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006379 /* Product type - 1st digit. */
6380 if ((*cp = 'A' + ((w & 0xE000) >> 13)) == 'H') {
6381 /* Product type is P=Prototype */
6382 *cp += 0x8;
6383 }
6384 cp++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006385
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006386 /* Manufacturing location - 2nd digit. */
6387 *cp++ = 'A' + ((w & 0x1C00) >> 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006388
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006389 /* Product ID - 3rd, 4th digits. */
6390 num = w & 0x3FF;
6391 *cp++ = '0' + (num / 100);
6392 num %= 100;
6393 *cp++ = '0' + (num / 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006394
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006395 /* Product revision - 5th digit. */
6396 *cp++ = 'A' + (num % 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006397
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006398 /*
6399 * Second word
6400 */
6401 w = serialnum[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006402
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006403 /*
6404 * Year - 6th digit.
6405 *
6406 * If bit 15 of third word is set, then the
6407 * last digit of the year is greater than 7.
6408 */
6409 if (serialnum[2] & 0x8000) {
6410 *cp++ = '8' + ((w & 0x1C0) >> 6);
6411 } else {
6412 *cp++ = '0' + ((w & 0x1C0) >> 6);
6413 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006414
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006415 /* Week of year - 7th, 8th digits. */
6416 num = w & 0x003F;
6417 *cp++ = '0' + num / 10;
6418 num %= 10;
6419 *cp++ = '0' + num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006420
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006421 /*
6422 * Third word
6423 */
6424 w = serialnum[2] & 0x7FFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006425
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006426 /* Serial number - 9th digit. */
6427 *cp++ = 'A' + (w / 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006428
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006429 /* 10th, 11th, 12th digits. */
6430 num = w % 1000;
6431 *cp++ = '0' + num / 100;
6432 num %= 100;
6433 *cp++ = '0' + num / 10;
6434 num %= 10;
6435 *cp++ = '0' + num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006436
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006437 *cp = '\0'; /* Null Terminate the string. */
6438 return ASC_TRUE;
6439 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006440}
6441
6442/*
6443 * asc_prt_asc_board_eeprom()
6444 *
6445 * Print board EEPROM configuration.
6446 *
6447 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6448 * cf. asc_prt_line().
6449 *
6450 * Return the number of characters copied into 'cp'. No more than
6451 * 'cplen' characters will be copied to 'cp'.
6452 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006453static int asc_prt_asc_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006454{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006455 asc_board_t *boardp;
6456 ASC_DVC_VAR *asc_dvc_varp;
6457 int leftlen;
6458 int totlen;
6459 int len;
6460 ASCEEP_CONFIG *ep;
6461 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006462#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006463 int isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07006464#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006465 uchar serialstr[13];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006466
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006467 boardp = ASC_BOARDP(shost);
6468 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
6469 ep = &boardp->eep_config.asc_eep;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006470
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006471 leftlen = cplen;
6472 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006473
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006474 len = asc_prt_line(cp, leftlen,
6475 "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
6476 shost->host_no);
6477 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006478
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006479 if (asc_get_eeprom_string((ushort *)&ep->adapter_info[0], serialstr)
6480 == ASC_TRUE) {
6481 len =
6482 asc_prt_line(cp, leftlen, " Serial Number: %s\n",
6483 serialstr);
6484 ASC_PRT_NEXT();
6485 } else {
6486 if (ep->adapter_info[5] == 0xBB) {
6487 len = asc_prt_line(cp, leftlen,
6488 " Default Settings Used for EEPROM-less Adapter.\n");
6489 ASC_PRT_NEXT();
6490 } else {
6491 len = asc_prt_line(cp, leftlen,
6492 " Serial Number Signature Not Present.\n");
6493 ASC_PRT_NEXT();
6494 }
6495 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006496
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006497 len = asc_prt_line(cp, leftlen,
6498 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6499 ASC_EEP_GET_CHIP_ID(ep), ep->max_total_qng,
6500 ep->max_tag_qng);
6501 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006502
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006503 len = asc_prt_line(cp, leftlen,
6504 " cntl 0x%x, no_scam 0x%x\n", ep->cntl, ep->no_scam);
6505 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006506
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006507 len = asc_prt_line(cp, leftlen, " Target ID: ");
6508 ASC_PRT_NEXT();
6509 for (i = 0; i <= ASC_MAX_TID; i++) {
6510 len = asc_prt_line(cp, leftlen, " %d", i);
6511 ASC_PRT_NEXT();
6512 }
6513 len = asc_prt_line(cp, leftlen, "\n");
6514 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006515
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006516 len = asc_prt_line(cp, leftlen, " Disconnects: ");
6517 ASC_PRT_NEXT();
6518 for (i = 0; i <= ASC_MAX_TID; i++) {
6519 len = asc_prt_line(cp, leftlen, " %c",
6520 (ep->
6521 disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6522 'N');
6523 ASC_PRT_NEXT();
6524 }
6525 len = asc_prt_line(cp, leftlen, "\n");
6526 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006527
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006528 len = asc_prt_line(cp, leftlen, " Command Queuing: ");
6529 ASC_PRT_NEXT();
6530 for (i = 0; i <= ASC_MAX_TID; i++) {
6531 len = asc_prt_line(cp, leftlen, " %c",
6532 (ep->
6533 use_cmd_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6534 'N');
6535 ASC_PRT_NEXT();
6536 }
6537 len = asc_prt_line(cp, leftlen, "\n");
6538 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006539
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006540 len = asc_prt_line(cp, leftlen, " Start Motor: ");
6541 ASC_PRT_NEXT();
6542 for (i = 0; i <= ASC_MAX_TID; i++) {
6543 len = asc_prt_line(cp, leftlen, " %c",
6544 (ep->
6545 start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6546 'N');
6547 ASC_PRT_NEXT();
6548 }
6549 len = asc_prt_line(cp, leftlen, "\n");
6550 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006551
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006552 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
6553 ASC_PRT_NEXT();
6554 for (i = 0; i <= ASC_MAX_TID; i++) {
6555 len = asc_prt_line(cp, leftlen, " %c",
6556 (ep->
6557 init_sdtr & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6558 'N');
6559 ASC_PRT_NEXT();
6560 }
6561 len = asc_prt_line(cp, leftlen, "\n");
6562 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006563
6564#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006565 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
6566 len = asc_prt_line(cp, leftlen,
6567 " Host ISA DMA speed: %d MB/S\n",
6568 isa_dma_speed[ASC_EEP_GET_DMA_SPD(ep)]);
6569 ASC_PRT_NEXT();
6570 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006571#endif /* CONFIG_ISA */
6572
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006573 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006574}
6575
6576/*
6577 * asc_prt_adv_board_eeprom()
6578 *
6579 * Print board EEPROM configuration.
6580 *
6581 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6582 * cf. asc_prt_line().
6583 *
6584 * Return the number of characters copied into 'cp'. No more than
6585 * 'cplen' characters will be copied to 'cp'.
6586 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006587static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006588{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006589 asc_board_t *boardp;
6590 ADV_DVC_VAR *adv_dvc_varp;
6591 int leftlen;
6592 int totlen;
6593 int len;
6594 int i;
6595 char *termstr;
6596 uchar serialstr[13];
6597 ADVEEP_3550_CONFIG *ep_3550 = NULL;
6598 ADVEEP_38C0800_CONFIG *ep_38C0800 = NULL;
6599 ADVEEP_38C1600_CONFIG *ep_38C1600 = NULL;
6600 ushort word;
6601 ushort *wordp;
6602 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006603
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006604 boardp = ASC_BOARDP(shost);
6605 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
6606 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6607 ep_3550 = &boardp->eep_config.adv_3550_eep;
6608 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6609 ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
6610 } else {
6611 ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
6612 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006613
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006614 leftlen = cplen;
6615 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006616
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006617 len = asc_prt_line(cp, leftlen,
6618 "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
6619 shost->host_no);
6620 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006621
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006622 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6623 wordp = &ep_3550->serial_number_word1;
6624 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6625 wordp = &ep_38C0800->serial_number_word1;
6626 } else {
6627 wordp = &ep_38C1600->serial_number_word1;
6628 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006629
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006630 if (asc_get_eeprom_string(wordp, serialstr) == ASC_TRUE) {
6631 len =
6632 asc_prt_line(cp, leftlen, " Serial Number: %s\n",
6633 serialstr);
6634 ASC_PRT_NEXT();
6635 } else {
6636 len = asc_prt_line(cp, leftlen,
6637 " Serial Number Signature Not Present.\n");
6638 ASC_PRT_NEXT();
6639 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006640
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006641 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6642 len = asc_prt_line(cp, leftlen,
6643 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6644 ep_3550->adapter_scsi_id,
6645 ep_3550->max_host_qng, ep_3550->max_dvc_qng);
6646 ASC_PRT_NEXT();
6647 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6648 len = asc_prt_line(cp, leftlen,
6649 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6650 ep_38C0800->adapter_scsi_id,
6651 ep_38C0800->max_host_qng,
6652 ep_38C0800->max_dvc_qng);
6653 ASC_PRT_NEXT();
6654 } else {
6655 len = asc_prt_line(cp, leftlen,
6656 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6657 ep_38C1600->adapter_scsi_id,
6658 ep_38C1600->max_host_qng,
6659 ep_38C1600->max_dvc_qng);
6660 ASC_PRT_NEXT();
6661 }
6662 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6663 word = ep_3550->termination;
6664 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6665 word = ep_38C0800->termination_lvd;
6666 } else {
6667 word = ep_38C1600->termination_lvd;
6668 }
6669 switch (word) {
6670 case 1:
6671 termstr = "Low Off/High Off";
6672 break;
6673 case 2:
6674 termstr = "Low Off/High On";
6675 break;
6676 case 3:
6677 termstr = "Low On/High On";
6678 break;
6679 default:
6680 case 0:
6681 termstr = "Automatic";
6682 break;
6683 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006684
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006685 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6686 len = asc_prt_line(cp, leftlen,
6687 " termination: %u (%s), bios_ctrl: 0x%x\n",
6688 ep_3550->termination, termstr,
6689 ep_3550->bios_ctrl);
6690 ASC_PRT_NEXT();
6691 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6692 len = asc_prt_line(cp, leftlen,
6693 " termination: %u (%s), bios_ctrl: 0x%x\n",
6694 ep_38C0800->termination_lvd, termstr,
6695 ep_38C0800->bios_ctrl);
6696 ASC_PRT_NEXT();
6697 } else {
6698 len = asc_prt_line(cp, leftlen,
6699 " termination: %u (%s), bios_ctrl: 0x%x\n",
6700 ep_38C1600->termination_lvd, termstr,
6701 ep_38C1600->bios_ctrl);
6702 ASC_PRT_NEXT();
6703 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006704
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006705 len = asc_prt_line(cp, leftlen, " Target ID: ");
6706 ASC_PRT_NEXT();
6707 for (i = 0; i <= ADV_MAX_TID; i++) {
6708 len = asc_prt_line(cp, leftlen, " %X", i);
6709 ASC_PRT_NEXT();
6710 }
6711 len = asc_prt_line(cp, leftlen, "\n");
6712 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006713
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006714 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6715 word = ep_3550->disc_enable;
6716 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6717 word = ep_38C0800->disc_enable;
6718 } else {
6719 word = ep_38C1600->disc_enable;
6720 }
6721 len = asc_prt_line(cp, leftlen, " Disconnects: ");
6722 ASC_PRT_NEXT();
6723 for (i = 0; i <= ADV_MAX_TID; i++) {
6724 len = asc_prt_line(cp, leftlen, " %c",
6725 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6726 ASC_PRT_NEXT();
6727 }
6728 len = asc_prt_line(cp, leftlen, "\n");
6729 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006730
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006731 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6732 word = ep_3550->tagqng_able;
6733 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6734 word = ep_38C0800->tagqng_able;
6735 } else {
6736 word = ep_38C1600->tagqng_able;
6737 }
6738 len = asc_prt_line(cp, leftlen, " Command Queuing: ");
6739 ASC_PRT_NEXT();
6740 for (i = 0; i <= ADV_MAX_TID; i++) {
6741 len = asc_prt_line(cp, leftlen, " %c",
6742 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6743 ASC_PRT_NEXT();
6744 }
6745 len = asc_prt_line(cp, leftlen, "\n");
6746 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006747
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006748 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6749 word = ep_3550->start_motor;
6750 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6751 word = ep_38C0800->start_motor;
6752 } else {
6753 word = ep_38C1600->start_motor;
6754 }
6755 len = asc_prt_line(cp, leftlen, " Start Motor: ");
6756 ASC_PRT_NEXT();
6757 for (i = 0; i <= ADV_MAX_TID; i++) {
6758 len = asc_prt_line(cp, leftlen, " %c",
6759 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6760 ASC_PRT_NEXT();
6761 }
6762 len = asc_prt_line(cp, leftlen, "\n");
6763 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006764
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006765 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6766 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
6767 ASC_PRT_NEXT();
6768 for (i = 0; i <= ADV_MAX_TID; i++) {
6769 len = asc_prt_line(cp, leftlen, " %c",
6770 (ep_3550->
6771 sdtr_able & ADV_TID_TO_TIDMASK(i)) ?
6772 'Y' : 'N');
6773 ASC_PRT_NEXT();
6774 }
6775 len = asc_prt_line(cp, leftlen, "\n");
6776 ASC_PRT_NEXT();
6777 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006778
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006779 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6780 len = asc_prt_line(cp, leftlen, " Ultra Transfer: ");
6781 ASC_PRT_NEXT();
6782 for (i = 0; i <= ADV_MAX_TID; i++) {
6783 len = asc_prt_line(cp, leftlen, " %c",
6784 (ep_3550->
6785 ultra_able & ADV_TID_TO_TIDMASK(i))
6786 ? 'Y' : 'N');
6787 ASC_PRT_NEXT();
6788 }
6789 len = asc_prt_line(cp, leftlen, "\n");
6790 ASC_PRT_NEXT();
6791 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006792
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006793 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6794 word = ep_3550->wdtr_able;
6795 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6796 word = ep_38C0800->wdtr_able;
6797 } else {
6798 word = ep_38C1600->wdtr_able;
6799 }
6800 len = asc_prt_line(cp, leftlen, " Wide Transfer: ");
6801 ASC_PRT_NEXT();
6802 for (i = 0; i <= ADV_MAX_TID; i++) {
6803 len = asc_prt_line(cp, leftlen, " %c",
6804 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6805 ASC_PRT_NEXT();
6806 }
6807 len = asc_prt_line(cp, leftlen, "\n");
6808 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006809
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006810 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800 ||
6811 adv_dvc_varp->chip_type == ADV_CHIP_ASC38C1600) {
6812 len = asc_prt_line(cp, leftlen,
6813 " Synchronous Transfer Speed (Mhz):\n ");
6814 ASC_PRT_NEXT();
6815 for (i = 0; i <= ADV_MAX_TID; i++) {
6816 char *speed_str;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006817
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006818 if (i == 0) {
6819 sdtr_speed = adv_dvc_varp->sdtr_speed1;
6820 } else if (i == 4) {
6821 sdtr_speed = adv_dvc_varp->sdtr_speed2;
6822 } else if (i == 8) {
6823 sdtr_speed = adv_dvc_varp->sdtr_speed3;
6824 } else if (i == 12) {
6825 sdtr_speed = adv_dvc_varp->sdtr_speed4;
6826 }
6827 switch (sdtr_speed & ADV_MAX_TID) {
6828 case 0:
6829 speed_str = "Off";
6830 break;
6831 case 1:
6832 speed_str = " 5";
6833 break;
6834 case 2:
6835 speed_str = " 10";
6836 break;
6837 case 3:
6838 speed_str = " 20";
6839 break;
6840 case 4:
6841 speed_str = " 40";
6842 break;
6843 case 5:
6844 speed_str = " 80";
6845 break;
6846 default:
6847 speed_str = "Unk";
6848 break;
6849 }
6850 len = asc_prt_line(cp, leftlen, "%X:%s ", i, speed_str);
6851 ASC_PRT_NEXT();
6852 if (i == 7) {
6853 len = asc_prt_line(cp, leftlen, "\n ");
6854 ASC_PRT_NEXT();
6855 }
6856 sdtr_speed >>= 4;
6857 }
6858 len = asc_prt_line(cp, leftlen, "\n");
6859 ASC_PRT_NEXT();
6860 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006861
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006862 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006863}
6864
6865/*
6866 * asc_prt_driver_conf()
6867 *
6868 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6869 * cf. asc_prt_line().
6870 *
6871 * Return the number of characters copied into 'cp'. No more than
6872 * 'cplen' characters will be copied to 'cp'.
6873 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006874static int asc_prt_driver_conf(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006875{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006876 asc_board_t *boardp;
6877 int leftlen;
6878 int totlen;
6879 int len;
6880 int chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006881
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006882 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006883
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006884 leftlen = cplen;
6885 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006886
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006887 len = asc_prt_line(cp, leftlen,
6888 "\nLinux Driver Configuration and Information for AdvanSys SCSI Host %d:\n",
6889 shost->host_no);
6890 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006891
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006892 len = asc_prt_line(cp, leftlen,
6893 " host_busy %u, last_reset %u, max_id %u, max_lun %u, max_channel %u\n",
6894 shost->host_busy, shost->last_reset, shost->max_id,
6895 shost->max_lun, shost->max_channel);
6896 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006897
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006898 len = asc_prt_line(cp, leftlen,
6899 " unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
6900 shost->unique_id, shost->can_queue, shost->this_id,
6901 shost->sg_tablesize, shost->cmd_per_lun);
6902 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006903
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006904 len = asc_prt_line(cp, leftlen,
6905 " unchecked_isa_dma %d, use_clustering %d\n",
6906 shost->unchecked_isa_dma, shost->use_clustering);
6907 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006908
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006909 len = asc_prt_line(cp, leftlen,
6910 " flags 0x%x, last_reset 0x%x, jiffies 0x%x, asc_n_io_port 0x%x\n",
6911 boardp->flags, boardp->last_reset, jiffies,
6912 boardp->asc_n_io_port);
6913 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006914
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006915 /* 'shost->n_io_port' may be truncated because it is only one byte. */
6916 len = asc_prt_line(cp, leftlen,
6917 " io_port 0x%x, n_io_port 0x%x\n",
6918 shost->io_port, shost->n_io_port);
6919 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006920
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006921 if (ASC_NARROW_BOARD(boardp)) {
6922 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
6923 } else {
6924 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
6925 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006926
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006927 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006928}
6929
6930/*
6931 * asc_prt_asc_board_info()
6932 *
6933 * Print dynamic board configuration information.
6934 *
6935 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6936 * cf. asc_prt_line().
6937 *
6938 * Return the number of characters copied into 'cp'. No more than
6939 * 'cplen' characters will be copied to 'cp'.
6940 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006941static int asc_prt_asc_board_info(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006942{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006943 asc_board_t *boardp;
6944 int chip_scsi_id;
6945 int leftlen;
6946 int totlen;
6947 int len;
6948 ASC_DVC_VAR *v;
6949 ASC_DVC_CFG *c;
6950 int i;
6951 int renegotiate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006952
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006953 boardp = ASC_BOARDP(shost);
6954 v = &boardp->dvc_var.asc_dvc_var;
6955 c = &boardp->dvc_cfg.asc_dvc_cfg;
6956 chip_scsi_id = c->chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006957
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006958 leftlen = cplen;
6959 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006960
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006961 len = asc_prt_line(cp, leftlen,
6962 "\nAsc Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
6963 shost->host_no);
6964 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006965
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006966 len = asc_prt_line(cp, leftlen,
6967 " chip_version %u, lib_version 0x%x, lib_serial_no %u, mcode_date 0x%x\n",
6968 c->chip_version, c->lib_version, c->lib_serial_no,
6969 c->mcode_date);
6970 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006971
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006972 len = asc_prt_line(cp, leftlen,
6973 " mcode_version 0x%x, err_code %u\n",
6974 c->mcode_version, v->err_code);
6975 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006976
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006977 /* Current number of commands waiting for the host. */
6978 len = asc_prt_line(cp, leftlen,
6979 " Total Command Pending: %d\n", v->cur_total_qng);
6980 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006981
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006982 len = asc_prt_line(cp, leftlen, " Command Queuing:");
6983 ASC_PRT_NEXT();
6984 for (i = 0; i <= ASC_MAX_TID; i++) {
6985 if ((chip_scsi_id == i) ||
6986 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6987 continue;
6988 }
6989 len = asc_prt_line(cp, leftlen, " %X:%c",
6990 i,
6991 (v->
6992 use_tagged_qng & ADV_TID_TO_TIDMASK(i)) ?
6993 'Y' : 'N');
6994 ASC_PRT_NEXT();
6995 }
6996 len = asc_prt_line(cp, leftlen, "\n");
6997 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006998
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006999 /* Current number of commands waiting for a device. */
7000 len = asc_prt_line(cp, leftlen, " Command Queue Pending:");
7001 ASC_PRT_NEXT();
7002 for (i = 0; i <= ASC_MAX_TID; i++) {
7003 if ((chip_scsi_id == i) ||
7004 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7005 continue;
7006 }
7007 len = asc_prt_line(cp, leftlen, " %X:%u", i, v->cur_dvc_qng[i]);
7008 ASC_PRT_NEXT();
7009 }
7010 len = asc_prt_line(cp, leftlen, "\n");
7011 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007012
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007013 /* Current limit on number of commands that can be sent to a device. */
7014 len = asc_prt_line(cp, leftlen, " Command Queue Limit:");
7015 ASC_PRT_NEXT();
7016 for (i = 0; i <= ASC_MAX_TID; i++) {
7017 if ((chip_scsi_id == i) ||
7018 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7019 continue;
7020 }
7021 len = asc_prt_line(cp, leftlen, " %X:%u", i, v->max_dvc_qng[i]);
7022 ASC_PRT_NEXT();
7023 }
7024 len = asc_prt_line(cp, leftlen, "\n");
7025 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007026
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007027 /* Indicate whether the device has returned queue full status. */
7028 len = asc_prt_line(cp, leftlen, " Command Queue Full:");
7029 ASC_PRT_NEXT();
7030 for (i = 0; i <= ASC_MAX_TID; i++) {
7031 if ((chip_scsi_id == i) ||
7032 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7033 continue;
7034 }
7035 if (boardp->queue_full & ADV_TID_TO_TIDMASK(i)) {
7036 len = asc_prt_line(cp, leftlen, " %X:Y-%d",
7037 i, boardp->queue_full_cnt[i]);
7038 } else {
7039 len = asc_prt_line(cp, leftlen, " %X:N", i);
7040 }
7041 ASC_PRT_NEXT();
7042 }
7043 len = asc_prt_line(cp, leftlen, "\n");
7044 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007045
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007046 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
7047 ASC_PRT_NEXT();
7048 for (i = 0; i <= ASC_MAX_TID; i++) {
7049 if ((chip_scsi_id == i) ||
7050 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7051 continue;
7052 }
7053 len = asc_prt_line(cp, leftlen, " %X:%c",
7054 i,
7055 (v->
7056 sdtr_done & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
7057 'N');
7058 ASC_PRT_NEXT();
7059 }
7060 len = asc_prt_line(cp, leftlen, "\n");
7061 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007062
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007063 for (i = 0; i <= ASC_MAX_TID; i++) {
7064 uchar syn_period_ix;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007065
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007066 if ((chip_scsi_id == i) ||
7067 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
7068 ((v->init_sdtr & ADV_TID_TO_TIDMASK(i)) == 0)) {
7069 continue;
7070 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007071
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007072 len = asc_prt_line(cp, leftlen, " %X:", i);
7073 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007074
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007075 if ((boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET) == 0) {
7076 len = asc_prt_line(cp, leftlen, " Asynchronous");
7077 ASC_PRT_NEXT();
7078 } else {
7079 syn_period_ix =
7080 (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index -
7081 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007082
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007083 len = asc_prt_line(cp, leftlen,
7084 " Transfer Period Factor: %d (%d.%d Mhz),",
7085 v->sdtr_period_tbl[syn_period_ix],
7086 250 /
7087 v->sdtr_period_tbl[syn_period_ix],
7088 ASC_TENTHS(250,
7089 v->
7090 sdtr_period_tbl
7091 [syn_period_ix]));
7092 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007093
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007094 len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
7095 boardp->
7096 sdtr_data[i] & ASC_SYN_MAX_OFFSET);
7097 ASC_PRT_NEXT();
7098 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007099
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007100 if ((v->sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
7101 len = asc_prt_line(cp, leftlen, "*\n");
7102 renegotiate = 1;
7103 } else {
7104 len = asc_prt_line(cp, leftlen, "\n");
7105 }
7106 ASC_PRT_NEXT();
7107 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007108
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007109 if (renegotiate) {
7110 len = asc_prt_line(cp, leftlen,
7111 " * = Re-negotiation pending before next command.\n");
7112 ASC_PRT_NEXT();
7113 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007114
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007115 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007116}
7117
7118/*
7119 * asc_prt_adv_board_info()
7120 *
7121 * Print dynamic board configuration information.
7122 *
7123 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
7124 * cf. asc_prt_line().
7125 *
7126 * Return the number of characters copied into 'cp'. No more than
7127 * 'cplen' characters will be copied to 'cp'.
7128 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007129static int asc_prt_adv_board_info(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007130{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007131 asc_board_t *boardp;
7132 int leftlen;
7133 int totlen;
7134 int len;
7135 int i;
7136 ADV_DVC_VAR *v;
7137 ADV_DVC_CFG *c;
7138 AdvPortAddr iop_base;
7139 ushort chip_scsi_id;
7140 ushort lramword;
7141 uchar lrambyte;
7142 ushort tagqng_able;
7143 ushort sdtr_able, wdtr_able;
7144 ushort wdtr_done, sdtr_done;
7145 ushort period = 0;
7146 int renegotiate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007147
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007148 boardp = ASC_BOARDP(shost);
7149 v = &boardp->dvc_var.adv_dvc_var;
7150 c = &boardp->dvc_cfg.adv_dvc_cfg;
7151 iop_base = v->iop_base;
7152 chip_scsi_id = v->chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007153
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007154 leftlen = cplen;
7155 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007156
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007157 len = asc_prt_line(cp, leftlen,
7158 "\nAdv Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
7159 shost->host_no);
7160 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007161
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007162 len = asc_prt_line(cp, leftlen,
7163 " iop_base 0x%lx, cable_detect: %X, err_code %u\n",
7164 v->iop_base,
7165 AdvReadWordRegister(iop_base,
7166 IOPW_SCSI_CFG1) & CABLE_DETECT,
7167 v->err_code);
7168 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007169
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007170 len = asc_prt_line(cp, leftlen,
7171 " chip_version %u, lib_version 0x%x, mcode_date 0x%x, mcode_version 0x%x\n",
7172 c->chip_version, c->lib_version, c->mcode_date,
7173 c->mcode_version);
7174 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007175
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007176 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
7177 len = asc_prt_line(cp, leftlen, " Queuing Enabled:");
7178 ASC_PRT_NEXT();
7179 for (i = 0; i <= ADV_MAX_TID; i++) {
7180 if ((chip_scsi_id == i) ||
7181 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7182 continue;
7183 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007184
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007185 len = asc_prt_line(cp, leftlen, " %X:%c",
7186 i,
7187 (tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
7188 'N');
7189 ASC_PRT_NEXT();
7190 }
7191 len = asc_prt_line(cp, leftlen, "\n");
7192 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007193
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007194 len = asc_prt_line(cp, leftlen, " Queue Limit:");
7195 ASC_PRT_NEXT();
7196 for (i = 0; i <= ADV_MAX_TID; i++) {
7197 if ((chip_scsi_id == i) ||
7198 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7199 continue;
7200 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007201
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007202 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + i,
7203 lrambyte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007204
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007205 len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
7206 ASC_PRT_NEXT();
7207 }
7208 len = asc_prt_line(cp, leftlen, "\n");
7209 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007210
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007211 len = asc_prt_line(cp, leftlen, " Command Pending:");
7212 ASC_PRT_NEXT();
7213 for (i = 0; i <= ADV_MAX_TID; i++) {
7214 if ((chip_scsi_id == i) ||
7215 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7216 continue;
7217 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007218
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007219 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_QUEUED_CMD + i,
7220 lrambyte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007221
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007222 len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
7223 ASC_PRT_NEXT();
7224 }
7225 len = asc_prt_line(cp, leftlen, "\n");
7226 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007227
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007228 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
7229 len = asc_prt_line(cp, leftlen, " Wide Enabled:");
7230 ASC_PRT_NEXT();
7231 for (i = 0; i <= ADV_MAX_TID; i++) {
7232 if ((chip_scsi_id == i) ||
7233 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7234 continue;
7235 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007236
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007237 len = asc_prt_line(cp, leftlen, " %X:%c",
7238 i,
7239 (wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
7240 'N');
7241 ASC_PRT_NEXT();
7242 }
7243 len = asc_prt_line(cp, leftlen, "\n");
7244 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007245
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007246 AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, wdtr_done);
7247 len = asc_prt_line(cp, leftlen, " Transfer Bit Width:");
7248 ASC_PRT_NEXT();
7249 for (i = 0; i <= ADV_MAX_TID; i++) {
7250 if ((chip_scsi_id == i) ||
7251 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7252 continue;
7253 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007254
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007255 AdvReadWordLram(iop_base,
7256 ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
7257 lramword);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007258
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007259 len = asc_prt_line(cp, leftlen, " %X:%d",
7260 i, (lramword & 0x8000) ? 16 : 8);
7261 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007262
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007263 if ((wdtr_able & ADV_TID_TO_TIDMASK(i)) &&
7264 (wdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
7265 len = asc_prt_line(cp, leftlen, "*");
7266 ASC_PRT_NEXT();
7267 renegotiate = 1;
7268 }
7269 }
7270 len = asc_prt_line(cp, leftlen, "\n");
7271 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007272
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007273 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
7274 len = asc_prt_line(cp, leftlen, " Synchronous Enabled:");
7275 ASC_PRT_NEXT();
7276 for (i = 0; i <= ADV_MAX_TID; i++) {
7277 if ((chip_scsi_id == i) ||
7278 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7279 continue;
7280 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007281
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007282 len = asc_prt_line(cp, leftlen, " %X:%c",
7283 i,
7284 (sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
7285 'N');
7286 ASC_PRT_NEXT();
7287 }
7288 len = asc_prt_line(cp, leftlen, "\n");
7289 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007290
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007291 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, sdtr_done);
7292 for (i = 0; i <= ADV_MAX_TID; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007293
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007294 AdvReadWordLram(iop_base,
7295 ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
7296 lramword);
7297 lramword &= ~0x8000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007298
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007299 if ((chip_scsi_id == i) ||
7300 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
7301 ((sdtr_able & ADV_TID_TO_TIDMASK(i)) == 0)) {
7302 continue;
7303 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007304
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007305 len = asc_prt_line(cp, leftlen, " %X:", i);
7306 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007307
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007308 if ((lramword & 0x1F) == 0) { /* Check for REQ/ACK Offset 0. */
7309 len = asc_prt_line(cp, leftlen, " Asynchronous");
7310 ASC_PRT_NEXT();
7311 } else {
7312 len =
7313 asc_prt_line(cp, leftlen,
7314 " Transfer Period Factor: ");
7315 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007316
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007317 if ((lramword & 0x1F00) == 0x1100) { /* 80 Mhz */
7318 len =
7319 asc_prt_line(cp, leftlen, "9 (80.0 Mhz),");
7320 ASC_PRT_NEXT();
7321 } else if ((lramword & 0x1F00) == 0x1000) { /* 40 Mhz */
7322 len =
7323 asc_prt_line(cp, leftlen, "10 (40.0 Mhz),");
7324 ASC_PRT_NEXT();
7325 } else { /* 20 Mhz or below. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007326
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007327 period = (((lramword >> 8) * 25) + 50) / 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007328
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007329 if (period == 0) { /* Should never happen. */
7330 len =
7331 asc_prt_line(cp, leftlen,
7332 "%d (? Mhz), ");
7333 ASC_PRT_NEXT();
7334 } else {
7335 len = asc_prt_line(cp, leftlen,
7336 "%d (%d.%d Mhz),",
7337 period, 250 / period,
7338 ASC_TENTHS(250,
7339 period));
7340 ASC_PRT_NEXT();
7341 }
7342 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007343
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007344 len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
7345 lramword & 0x1F);
7346 ASC_PRT_NEXT();
7347 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007348
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007349 if ((sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
7350 len = asc_prt_line(cp, leftlen, "*\n");
7351 renegotiate = 1;
7352 } else {
7353 len = asc_prt_line(cp, leftlen, "\n");
7354 }
7355 ASC_PRT_NEXT();
7356 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007357
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007358 if (renegotiate) {
7359 len = asc_prt_line(cp, leftlen,
7360 " * = Re-negotiation pending before next command.\n");
7361 ASC_PRT_NEXT();
7362 }
7363
7364 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007365}
7366
7367/*
7368 * asc_proc_copy()
7369 *
7370 * Copy proc information to a read buffer taking into account the current
7371 * read offset in the file and the remaining space in the read buffer.
7372 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007373static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07007374asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007375 char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007376{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007377 int cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007378
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007379 ASC_DBG3(2, "asc_proc_copy: offset %d, advoffset %d, cplen %d\n",
7380 (unsigned)offset, (unsigned)advoffset, cplen);
7381 if (offset <= advoffset) {
7382 /* Read offset below current offset, copy everything. */
7383 cnt = min(cplen, leftlen);
7384 ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
7385 (ulong)curbuf, (ulong)cp, cnt);
7386 memcpy(curbuf, cp, cnt);
7387 } else if (offset < advoffset + cplen) {
7388 /* Read offset within current range, partial copy. */
7389 cnt = (advoffset + cplen) - offset;
7390 cp = (cp + cplen) - cnt;
7391 cnt = min(cnt, leftlen);
7392 ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
7393 (ulong)curbuf, (ulong)cp, cnt);
7394 memcpy(curbuf, cp, cnt);
7395 }
7396 return cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007397}
7398
7399/*
7400 * asc_prt_line()
7401 *
7402 * If 'cp' is NULL print to the console, otherwise print to a buffer.
7403 *
7404 * Return 0 if printing to the console, otherwise return the number of
7405 * bytes written to the buffer.
7406 *
7407 * Note: If any single line is greater than ASC_PRTLINE_SIZE bytes the stack
7408 * will be corrupted. 's[]' is defined to be ASC_PRTLINE_SIZE bytes.
7409 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007410static int asc_prt_line(char *buf, int buflen, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007411{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007412 va_list args;
7413 int ret;
7414 char s[ASC_PRTLINE_SIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07007415
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007416 va_start(args, fmt);
7417 ret = vsprintf(s, fmt, args);
7418 ASC_ASSERT(ret < ASC_PRTLINE_SIZE);
7419 if (buf == NULL) {
7420 (void)printk(s);
7421 ret = 0;
7422 } else {
7423 ret = min(buflen, ret);
7424 memcpy(buf, s, ret);
7425 }
7426 va_end(args);
7427 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007428}
7429#endif /* CONFIG_PROC_FS */
7430
Linus Torvalds1da177e2005-04-16 15:20:36 -07007431/*
7432 * --- Functions Required by the Asc Library
7433 */
7434
7435/*
7436 * Delay for 'n' milliseconds. Don't use the 'jiffies'
7437 * global variable which is incremented once every 5 ms
7438 * from a timer interrupt, because this function may be
7439 * called when interrupts are disabled.
7440 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007441static void DvcSleepMilliSecond(ADV_DCNT n)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007442{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007443 ASC_DBG1(4, "DvcSleepMilliSecond: %lu\n", (ulong)n);
7444 mdelay(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007445}
7446
7447/*
7448 * Currently and inline noop but leave as a placeholder.
7449 * Leave DvcEnterCritical() as a noop placeholder.
7450 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007451static inline ulong DvcEnterCritical(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007452{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007453 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007454}
7455
7456/*
7457 * Critical sections are all protected by the board spinlock.
7458 * Leave DvcLeaveCritical() as a noop placeholder.
7459 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007460static inline void DvcLeaveCritical(ulong flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007461{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007462 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007463}
7464
7465/*
7466 * void
7467 * DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
7468 *
7469 * Calling/Exit State:
7470 * none
7471 *
7472 * Description:
7473 * Output an ASC_SCSI_Q structure to the chip
7474 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007475static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07007476DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
7477{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007478 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007479
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007480 ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", outbuf, 2 * words);
7481 AscSetChipLramAddr(iop_base, s_addr);
7482 for (i = 0; i < 2 * words; i += 2) {
7483 if (i == 4 || i == 20) {
7484 continue;
7485 }
7486 outpw(iop_base + IOP_RAM_DATA,
7487 ((ushort)outbuf[i + 1] << 8) | outbuf[i]);
7488 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007489}
7490
7491/*
7492 * void
7493 * DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
7494 *
7495 * Calling/Exit State:
7496 * none
7497 *
7498 * Description:
7499 * Input an ASC_QDONE_INFO structure from the chip
7500 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007501static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07007502DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
7503{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007504 int i;
7505 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007506
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007507 AscSetChipLramAddr(iop_base, s_addr);
7508 for (i = 0; i < 2 * words; i += 2) {
7509 if (i == 10) {
7510 continue;
7511 }
7512 word = inpw(iop_base + IOP_RAM_DATA);
7513 inbuf[i] = word & 0xff;
7514 inbuf[i + 1] = (word >> 8) & 0xff;
7515 }
7516 ASC_DBG_PRT_HEX(2, "DvcGetQinfo", inbuf, 2 * words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007517}
7518
7519/*
7520 * Read a PCI configuration byte.
7521 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007522static uchar __init DvcReadPCIConfigByte(ASC_DVC_VAR *asc_dvc, ushort offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007523{
7524#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007525 uchar byte_data;
7526 pci_read_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, &byte_data);
7527 return byte_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007528#else /* !defined(CONFIG_PCI) */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007529 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007530#endif /* !defined(CONFIG_PCI) */
7531}
7532
7533/*
7534 * Write a PCI configuration byte.
7535 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007536static void __init
7537DvcWritePCIConfigByte(ASC_DVC_VAR *asc_dvc, ushort offset, uchar byte_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007538{
7539#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007540 pci_write_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, byte_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007541#endif /* CONFIG_PCI */
7542}
7543
7544/*
7545 * Return the BIOS address of the adapter at the specified
7546 * I/O port and with the specified bus type.
7547 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007548static ushort __init AscGetChipBiosAddress(PortAddr iop_base, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007549{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007550 ushort cfg_lsw;
7551 ushort bios_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007552
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007553 /*
7554 * The PCI BIOS is re-located by the motherboard BIOS. Because
7555 * of this the driver can not determine where a PCI BIOS is
7556 * loaded and executes.
7557 */
7558 if (bus_type & ASC_IS_PCI) {
7559 return (0);
7560 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007561#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007562 if ((bus_type & ASC_IS_EISA) != 0) {
7563 cfg_lsw = AscGetEisaChipCfg(iop_base);
7564 cfg_lsw &= 0x000F;
7565 bios_addr = (ushort)(ASC_BIOS_MIN_ADDR +
7566 (cfg_lsw * ASC_BIOS_BANK_SIZE));
7567 return (bios_addr);
7568 } /* if */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007569#endif /* CONFIG_ISA */
7570
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007571 cfg_lsw = AscGetChipCfgLsw(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007572
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007573 /*
7574 * ISA PnP uses the top bit as the 32K BIOS flag
7575 */
7576 if (bus_type == ASC_IS_ISAPNP) {
7577 cfg_lsw &= 0x7FFF;
7578 }
7579 /* if */
7580 bios_addr = (ushort)(((cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE) +
7581 ASC_BIOS_MIN_ADDR);
7582 return (bios_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007583}
7584
Linus Torvalds1da177e2005-04-16 15:20:36 -07007585/*
7586 * --- Functions Required by the Adv Library
7587 */
7588
7589/*
7590 * DvcGetPhyAddr()
7591 *
7592 * Return the physical address of 'vaddr' and set '*lenp' to the
7593 * number of physically contiguous bytes that follow 'vaddr'.
7594 * 'flag' indicates the type of structure whose physical address
7595 * is being translated.
7596 *
7597 * Note: Because Linux currently doesn't page the kernel and all
7598 * kernel buffers are physically contiguous, leave '*lenp' unchanged.
7599 */
7600ADV_PADDR
7601DvcGetPhyAddr(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007602 uchar *vaddr, ADV_SDCNT *lenp, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007603{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007604 ADV_PADDR paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007605
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007606 paddr = virt_to_bus(vaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007607
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007608 ASC_DBG4(4,
7609 "DvcGetPhyAddr: vaddr 0x%lx, lenp 0x%lx *lenp %lu, paddr 0x%lx\n",
7610 (ulong)vaddr, (ulong)lenp, (ulong)*((ulong *)lenp),
7611 (ulong)paddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007612
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007613 return paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007614}
7615
7616/*
7617 * Read a PCI configuration byte.
7618 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007619static uchar __init DvcAdvReadPCIConfigByte(ADV_DVC_VAR *asc_dvc, ushort offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007620{
7621#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007622 uchar byte_data;
7623 pci_read_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, &byte_data);
7624 return byte_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007625#else /* CONFIG_PCI */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007626 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007627#endif /* CONFIG_PCI */
7628}
7629
7630/*
7631 * Write a PCI configuration byte.
7632 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007633static void __init
7634DvcAdvWritePCIConfigByte(ADV_DVC_VAR *asc_dvc, ushort offset, uchar byte_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007635{
7636#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007637 pci_write_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, byte_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007638#else /* CONFIG_PCI */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007639 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007640#endif /* CONFIG_PCI */
7641}
7642
7643/*
7644 * --- Tracing and Debugging Functions
7645 */
7646
7647#ifdef ADVANSYS_STATS
7648#ifdef CONFIG_PROC_FS
7649/*
7650 * asc_prt_board_stats()
7651 *
7652 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
7653 * cf. asc_prt_line().
7654 *
7655 * Return the number of characters copied into 'cp'. No more than
7656 * 'cplen' characters will be copied to 'cp'.
7657 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007658static int asc_prt_board_stats(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007659{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007660 int leftlen;
7661 int totlen;
7662 int len;
7663 struct asc_stats *s;
7664 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007665
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007666 leftlen = cplen;
7667 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007668
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007669 boardp = ASC_BOARDP(shost);
7670 s = &boardp->asc_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007671
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007672 len = asc_prt_line(cp, leftlen,
7673 "\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n",
7674 shost->host_no);
7675 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007676
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007677 len = asc_prt_line(cp, leftlen,
7678 " queuecommand %lu, reset %lu, biosparam %lu, interrupt %lu\n",
7679 s->queuecommand, s->reset, s->biosparam,
7680 s->interrupt);
7681 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007682
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007683 len = asc_prt_line(cp, leftlen,
7684 " callback %lu, done %lu, build_error %lu, build_noreq %lu, build_nosg %lu\n",
7685 s->callback, s->done, s->build_error,
7686 s->adv_build_noreq, s->adv_build_nosg);
7687 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007688
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007689 len = asc_prt_line(cp, leftlen,
7690 " exe_noerror %lu, exe_busy %lu, exe_error %lu, exe_unknown %lu\n",
7691 s->exe_noerror, s->exe_busy, s->exe_error,
7692 s->exe_unknown);
7693 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007694
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007695 /*
7696 * Display data transfer statistics.
7697 */
7698 if (s->cont_cnt > 0) {
7699 len = asc_prt_line(cp, leftlen, " cont_cnt %lu, ", s->cont_cnt);
7700 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007701
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007702 len = asc_prt_line(cp, leftlen, "cont_xfer %lu.%01lu kb ",
7703 s->cont_xfer / 2,
7704 ASC_TENTHS(s->cont_xfer, 2));
7705 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007706
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007707 /* Contiguous transfer average size */
7708 len = asc_prt_line(cp, leftlen, "avg_xfer %lu.%01lu kb\n",
7709 (s->cont_xfer / 2) / s->cont_cnt,
7710 ASC_TENTHS((s->cont_xfer / 2), s->cont_cnt));
7711 ASC_PRT_NEXT();
7712 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007713
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007714 if (s->sg_cnt > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007715
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007716 len = asc_prt_line(cp, leftlen, " sg_cnt %lu, sg_elem %lu, ",
7717 s->sg_cnt, s->sg_elem);
7718 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007719
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007720 len = asc_prt_line(cp, leftlen, "sg_xfer %lu.%01lu kb\n",
7721 s->sg_xfer / 2, ASC_TENTHS(s->sg_xfer, 2));
7722 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007723
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007724 /* Scatter gather transfer statistics */
7725 len = asc_prt_line(cp, leftlen, " avg_num_elem %lu.%01lu, ",
7726 s->sg_elem / s->sg_cnt,
7727 ASC_TENTHS(s->sg_elem, s->sg_cnt));
7728 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007729
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007730 len = asc_prt_line(cp, leftlen, "avg_elem_size %lu.%01lu kb, ",
7731 (s->sg_xfer / 2) / s->sg_elem,
7732 ASC_TENTHS((s->sg_xfer / 2), s->sg_elem));
7733 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007734
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007735 len = asc_prt_line(cp, leftlen, "avg_xfer_size %lu.%01lu kb\n",
7736 (s->sg_xfer / 2) / s->sg_cnt,
7737 ASC_TENTHS((s->sg_xfer / 2), s->sg_cnt));
7738 ASC_PRT_NEXT();
7739 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007740
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007741 /*
7742 * Display request queuing statistics.
7743 */
7744 len = asc_prt_line(cp, leftlen,
7745 " Active and Waiting Request Queues (Time Unit: %d HZ):\n",
7746 HZ);
7747 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007748
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007749 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007750}
7751
7752/*
7753 * asc_prt_target_stats()
7754 *
7755 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
7756 * cf. asc_prt_line().
7757 *
7758 * This is separated from asc_prt_board_stats because a full set
7759 * of targets will overflow ASC_PRTBUF_SIZE.
7760 *
7761 * Return the number of characters copied into 'cp'. No more than
7762 * 'cplen' characters will be copied to 'cp'.
7763 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007764static int
7765asc_prt_target_stats(struct Scsi_Host *shost, int tgt_id, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007766{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007767 int leftlen;
7768 int totlen;
7769 int len;
7770 struct asc_stats *s;
7771 ushort chip_scsi_id;
7772 asc_board_t *boardp;
7773 asc_queue_t *active;
7774 asc_queue_t *waiting;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007775
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007776 leftlen = cplen;
7777 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007778
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007779 boardp = ASC_BOARDP(shost);
7780 s = &boardp->asc_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007781
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007782 active = &ASC_BOARDP(shost)->active;
7783 waiting = &ASC_BOARDP(shost)->waiting;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007784
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007785 if (ASC_NARROW_BOARD(boardp)) {
7786 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
7787 } else {
7788 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
7789 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007790
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007791 if ((chip_scsi_id == tgt_id) ||
7792 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(tgt_id)) == 0)) {
7793 return 0;
7794 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007795
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007796 do {
7797 if (active->q_tot_cnt[tgt_id] > 0
7798 || waiting->q_tot_cnt[tgt_id] > 0) {
7799 len = asc_prt_line(cp, leftlen, " target %d\n", tgt_id);
7800 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007801
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007802 len = asc_prt_line(cp, leftlen,
7803 " active: cnt [cur %d, max %d, tot %u], time [min %d, max %d, avg %lu.%01lu]\n",
7804 active->q_cur_cnt[tgt_id],
7805 active->q_max_cnt[tgt_id],
7806 active->q_tot_cnt[tgt_id],
7807 active->q_min_tim[tgt_id],
7808 active->q_max_tim[tgt_id],
7809 (active->q_tot_cnt[tgt_id] ==
7810 0) ? 0 : (active->
7811 q_tot_tim[tgt_id] /
7812 active->
7813 q_tot_cnt[tgt_id]),
7814 (active->q_tot_cnt[tgt_id] ==
7815 0) ? 0 : ASC_TENTHS(active->
7816 q_tot_tim
7817 [tgt_id],
7818 active->
7819 q_tot_cnt
7820 [tgt_id]));
7821 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007822
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007823 len = asc_prt_line(cp, leftlen,
7824 " waiting: cnt [cur %d, max %d, tot %u], time [min %u, max %u, avg %lu.%01lu]\n",
7825 waiting->q_cur_cnt[tgt_id],
7826 waiting->q_max_cnt[tgt_id],
7827 waiting->q_tot_cnt[tgt_id],
7828 waiting->q_min_tim[tgt_id],
7829 waiting->q_max_tim[tgt_id],
7830 (waiting->q_tot_cnt[tgt_id] ==
7831 0) ? 0 : (waiting->
7832 q_tot_tim[tgt_id] /
7833 waiting->
7834 q_tot_cnt[tgt_id]),
7835 (waiting->q_tot_cnt[tgt_id] ==
7836 0) ? 0 : ASC_TENTHS(waiting->
7837 q_tot_tim
7838 [tgt_id],
7839 waiting->
7840 q_tot_cnt
7841 [tgt_id]));
7842 ASC_PRT_NEXT();
7843 }
7844 } while (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007845
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007846 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007847}
7848#endif /* CONFIG_PROC_FS */
7849#endif /* ADVANSYS_STATS */
7850
7851#ifdef ADVANSYS_DEBUG
7852/*
7853 * asc_prt_scsi_host()
7854 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007855static void asc_prt_scsi_host(struct Scsi_Host *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007856{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007857 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007858
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007859 boardp = ASC_BOARDP(s);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007860
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007861 printk("Scsi_Host at addr 0x%lx\n", (ulong)s);
7862 printk(" host_busy %u, host_no %d, last_reset %d,\n",
7863 s->host_busy, s->host_no, (unsigned)s->last_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007864
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007865 printk(" base 0x%lx, io_port 0x%lx, n_io_port %u, irq 0x%x,\n",
7866 (ulong)s->base, (ulong)s->io_port, s->n_io_port, s->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007867
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007868 printk(" dma_channel %d, this_id %d, can_queue %d,\n",
7869 s->dma_channel, s->this_id, s->can_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007870
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007871 printk(" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d\n",
7872 s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007873
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007874 if (ASC_NARROW_BOARD(boardp)) {
7875 asc_prt_asc_dvc_var(&ASC_BOARDP(s)->dvc_var.asc_dvc_var);
7876 asc_prt_asc_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.asc_dvc_cfg);
7877 } else {
7878 asc_prt_adv_dvc_var(&ASC_BOARDP(s)->dvc_var.adv_dvc_var);
7879 asc_prt_adv_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.adv_dvc_cfg);
7880 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007881}
7882
7883/*
7884 * asc_prt_scsi_cmnd()
7885 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007886static void asc_prt_scsi_cmnd(struct scsi_cmnd *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007887{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007888 printk("struct scsi_cmnd at addr 0x%lx\n", (ulong)s);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007889
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007890 printk(" host 0x%lx, device 0x%lx, target %u, lun %u, channel %u,\n",
7891 (ulong)s->device->host, (ulong)s->device, s->device->id,
7892 s->device->lun, s->device->channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007893
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007894 asc_prt_hex(" CDB", s->cmnd, s->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007895
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007896 printk("sc_data_direction %u, resid %d\n",
7897 s->sc_data_direction, s->resid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007898
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007899 printk(" use_sg %u, sglist_len %u\n", s->use_sg, s->sglist_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007900
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007901 printk(" serial_number 0x%x, retries %d, allowed %d\n",
7902 (unsigned)s->serial_number, s->retries, s->allowed);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007903
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007904 printk(" timeout_per_command %d\n", s->timeout_per_command);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007905
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007906 printk
7907 (" scsi_done 0x%lx, done 0x%lx, host_scribble 0x%lx, result 0x%x\n",
7908 (ulong)s->scsi_done, (ulong)s->done, (ulong)s->host_scribble,
7909 s->result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007910
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007911 printk(" tag %u, pid %u\n", (unsigned)s->tag, (unsigned)s->pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007912}
7913
7914/*
7915 * asc_prt_asc_dvc_var()
7916 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007917static void asc_prt_asc_dvc_var(ASC_DVC_VAR *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007918{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007919 printk("ASC_DVC_VAR at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007920
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007921 printk
7922 (" iop_base 0x%x, err_code 0x%x, dvc_cntl 0x%x, bug_fix_cntl %d,\n",
7923 h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007924
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007925 printk
7926 (" bus_type %d, isr_callback 0x%lx, exe_callback 0x%lx, init_sdtr 0x%x,\n",
7927 h->bus_type, (ulong)h->isr_callback, (ulong)h->exe_callback,
7928 (unsigned)h->init_sdtr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007929
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007930 printk
7931 (" sdtr_done 0x%x, use_tagged_qng 0x%x, unit_not_ready 0x%x, chip_no 0x%x,\n",
7932 (unsigned)h->sdtr_done, (unsigned)h->use_tagged_qng,
7933 (unsigned)h->unit_not_ready, (unsigned)h->chip_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007934
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007935 printk
7936 (" queue_full_or_busy 0x%x, start_motor 0x%x, scsi_reset_wait %u,\n",
7937 (unsigned)h->queue_full_or_busy, (unsigned)h->start_motor,
7938 (unsigned)h->scsi_reset_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007939
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007940 printk
7941 (" is_in_int %u, max_total_qng %u, cur_total_qng %u, in_critical_cnt %u,\n",
7942 (unsigned)h->is_in_int, (unsigned)h->max_total_qng,
7943 (unsigned)h->cur_total_qng, (unsigned)h->in_critical_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007944
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007945 printk
7946 (" last_q_shortage %u, init_state 0x%x, no_scam 0x%x, pci_fix_asyn_xfer 0x%x,\n",
7947 (unsigned)h->last_q_shortage, (unsigned)h->init_state,
7948 (unsigned)h->no_scam, (unsigned)h->pci_fix_asyn_xfer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007949
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007950 printk(" cfg 0x%lx, irq_no 0x%x\n", (ulong)h->cfg, (unsigned)h->irq_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007951}
7952
7953/*
7954 * asc_prt_asc_dvc_cfg()
7955 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007956static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007957{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007958 printk("ASC_DVC_CFG at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007959
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007960 printk(" can_tagged_qng 0x%x, cmd_qng_enabled 0x%x,\n",
7961 h->can_tagged_qng, h->cmd_qng_enabled);
7962 printk(" disc_enable 0x%x, sdtr_enable 0x%x,\n",
7963 h->disc_enable, h->sdtr_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007964
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007965 printk
7966 (" chip_scsi_id %d, isa_dma_speed %d, isa_dma_channel %d, chip_version %d,\n",
7967 h->chip_scsi_id, h->isa_dma_speed, h->isa_dma_channel,
7968 h->chip_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007969
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007970 printk
7971 (" pci_device_id %d, lib_serial_no %u, lib_version %u, mcode_date 0x%x,\n",
7972 to_pci_dev(h->dev)->device, h->lib_serial_no, h->lib_version,
7973 h->mcode_date);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007974
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007975 printk(" mcode_version %d, overrun_buf 0x%lx\n",
7976 h->mcode_version, (ulong)h->overrun_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007977}
7978
7979/*
7980 * asc_prt_asc_scsi_q()
7981 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007982static void asc_prt_asc_scsi_q(ASC_SCSI_Q *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007983{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007984 ASC_SG_HEAD *sgp;
7985 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007986
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007987 printk("ASC_SCSI_Q at addr 0x%lx\n", (ulong)q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007988
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007989 printk
7990 (" target_ix 0x%x, target_lun %u, srb_ptr 0x%lx, tag_code 0x%x,\n",
7991 q->q2.target_ix, q->q1.target_lun, (ulong)q->q2.srb_ptr,
7992 q->q2.tag_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007993
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007994 printk
7995 (" data_addr 0x%lx, data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
7996 (ulong)le32_to_cpu(q->q1.data_addr),
7997 (ulong)le32_to_cpu(q->q1.data_cnt),
7998 (ulong)le32_to_cpu(q->q1.sense_addr), q->q1.sense_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007999
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008000 printk(" cdbptr 0x%lx, cdb_len %u, sg_head 0x%lx, sg_queue_cnt %u\n",
8001 (ulong)q->cdbptr, q->q2.cdb_len,
8002 (ulong)q->sg_head, q->q1.sg_queue_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008003
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008004 if (q->sg_head) {
8005 sgp = q->sg_head;
8006 printk("ASC_SG_HEAD at addr 0x%lx\n", (ulong)sgp);
8007 printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt,
8008 sgp->queue_cnt);
8009 for (i = 0; i < sgp->entry_cnt; i++) {
8010 printk(" [%u]: addr 0x%lx, bytes %lu\n",
8011 i, (ulong)le32_to_cpu(sgp->sg_list[i].addr),
8012 (ulong)le32_to_cpu(sgp->sg_list[i].bytes));
8013 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008014
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008015 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008016}
8017
8018/*
8019 * asc_prt_asc_qdone_info()
8020 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008021static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008022{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008023 printk("ASC_QDONE_INFO at addr 0x%lx\n", (ulong)q);
8024 printk(" srb_ptr 0x%lx, target_ix %u, cdb_len %u, tag_code %u,\n",
8025 (ulong)q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len,
8026 q->d2.tag_code);
8027 printk
8028 (" done_stat 0x%x, host_stat 0x%x, scsi_stat 0x%x, scsi_msg 0x%x\n",
8029 q->d3.done_stat, q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008030}
8031
8032/*
8033 * asc_prt_adv_dvc_var()
8034 *
8035 * Display an ADV_DVC_VAR structure.
8036 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008037static void asc_prt_adv_dvc_var(ADV_DVC_VAR *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008038{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008039 printk(" ADV_DVC_VAR at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008040
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008041 printk(" iop_base 0x%lx, err_code 0x%x, ultra_able 0x%x\n",
8042 (ulong)h->iop_base, h->err_code, (unsigned)h->ultra_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008043
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008044 printk(" isr_callback 0x%lx, sdtr_able 0x%x, wdtr_able 0x%x\n",
8045 (ulong)h->isr_callback, (unsigned)h->sdtr_able,
8046 (unsigned)h->wdtr_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008047
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008048 printk(" start_motor 0x%x, scsi_reset_wait 0x%x, irq_no 0x%x,\n",
8049 (unsigned)h->start_motor,
8050 (unsigned)h->scsi_reset_wait, (unsigned)h->irq_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008051
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008052 printk(" max_host_qng %u, max_dvc_qng %u, carr_freelist 0x%lxn\n",
8053 (unsigned)h->max_host_qng, (unsigned)h->max_dvc_qng,
8054 (ulong)h->carr_freelist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008055
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008056 printk(" icq_sp 0x%lx, irq_sp 0x%lx\n",
8057 (ulong)h->icq_sp, (ulong)h->irq_sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008058
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008059 printk(" no_scam 0x%x, tagqng_able 0x%x\n",
8060 (unsigned)h->no_scam, (unsigned)h->tagqng_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008061
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008062 printk(" chip_scsi_id 0x%x, cfg 0x%lx\n",
8063 (unsigned)h->chip_scsi_id, (ulong)h->cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008064}
8065
8066/*
8067 * asc_prt_adv_dvc_cfg()
8068 *
8069 * Display an ADV_DVC_CFG structure.
8070 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008071static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008072{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008073 printk(" ADV_DVC_CFG at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008074
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008075 printk(" disc_enable 0x%x, termination 0x%x\n",
8076 h->disc_enable, h->termination);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008077
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008078 printk(" chip_version 0x%x, mcode_date 0x%x\n",
8079 h->chip_version, h->mcode_date);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008080
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008081 printk(" mcode_version 0x%x, pci_device_id 0x%x, lib_version %u\n",
8082 h->mcode_version, to_pci_dev(h->dev)->device, h->lib_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008083
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008084 printk(" control_flag 0x%x, pci_slot_info 0x%x\n",
8085 h->control_flag, h->pci_slot_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008086}
8087
8088/*
8089 * asc_prt_adv_scsi_req_q()
8090 *
8091 * Display an ADV_SCSI_REQ_Q structure.
8092 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008093static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008094{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008095 int sg_blk_cnt;
8096 struct asc_sg_block *sg_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008097
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008098 printk("ADV_SCSI_REQ_Q at addr 0x%lx\n", (ulong)q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008099
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008100 printk(" target_id %u, target_lun %u, srb_ptr 0x%lx, a_flag 0x%x\n",
8101 q->target_id, q->target_lun, (ulong)q->srb_ptr, q->a_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008102
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008103 printk(" cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n",
8104 q->cntl, (ulong)le32_to_cpu(q->data_addr), (ulong)q->vdata_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008105
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008106 printk(" data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
8107 (ulong)le32_to_cpu(q->data_cnt),
8108 (ulong)le32_to_cpu(q->sense_addr), q->sense_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008109
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008110 printk
8111 (" cdb_len %u, done_status 0x%x, host_status 0x%x, scsi_status 0x%x\n",
8112 q->cdb_len, q->done_status, q->host_status, q->scsi_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008113
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008114 printk(" sg_working_ix 0x%x, target_cmd %u\n",
8115 q->sg_working_ix, q->target_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008116
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008117 printk(" scsiq_rptr 0x%lx, sg_real_addr 0x%lx, sg_list_ptr 0x%lx\n",
8118 (ulong)le32_to_cpu(q->scsiq_rptr),
8119 (ulong)le32_to_cpu(q->sg_real_addr), (ulong)q->sg_list_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008120
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008121 /* Display the request's ADV_SG_BLOCK structures. */
8122 if (q->sg_list_ptr != NULL) {
8123 sg_blk_cnt = 0;
8124 while (1) {
8125 /*
8126 * 'sg_ptr' is a physical address. Convert it to a virtual
8127 * address by indexing 'sg_blk_cnt' into the virtual address
8128 * array 'sg_list_ptr'.
8129 *
8130 * XXX - Assumes all SG physical blocks are virtually contiguous.
8131 */
8132 sg_ptr =
8133 &(((ADV_SG_BLOCK *)(q->sg_list_ptr))[sg_blk_cnt]);
8134 asc_prt_adv_sgblock(sg_blk_cnt, sg_ptr);
8135 if (sg_ptr->sg_ptr == 0) {
8136 break;
8137 }
8138 sg_blk_cnt++;
8139 }
8140 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008141}
8142
8143/*
8144 * asc_prt_adv_sgblock()
8145 *
8146 * Display an ADV_SG_BLOCK structure.
8147 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008148static void asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008149{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008150 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008151
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008152 printk(" ASC_SG_BLOCK at addr 0x%lx (sgblockno %d)\n",
8153 (ulong)b, sgblockno);
8154 printk(" sg_cnt %u, sg_ptr 0x%lx\n",
8155 b->sg_cnt, (ulong)le32_to_cpu(b->sg_ptr));
8156 ASC_ASSERT(b->sg_cnt <= NO_OF_SG_PER_BLOCK);
8157 if (b->sg_ptr != 0) {
8158 ASC_ASSERT(b->sg_cnt == NO_OF_SG_PER_BLOCK);
8159 }
8160 for (i = 0; i < b->sg_cnt; i++) {
8161 printk(" [%u]: sg_addr 0x%lx, sg_count 0x%lx\n",
8162 i, (ulong)b->sg_list[i].sg_addr,
8163 (ulong)b->sg_list[i].sg_count);
8164 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008165}
8166
8167/*
8168 * asc_prt_hex()
8169 *
8170 * Print hexadecimal output in 4 byte groupings 32 bytes
8171 * or 8 double-words per line.
8172 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008173static void asc_prt_hex(char *f, uchar *s, int l)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008174{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008175 int i;
8176 int j;
8177 int k;
8178 int m;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008179
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008180 printk("%s: (%d bytes)\n", f, l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008181
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008182 for (i = 0; i < l; i += 32) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008183
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008184 /* Display a maximum of 8 double-words per line. */
8185 if ((k = (l - i) / 4) >= 8) {
8186 k = 8;
8187 m = 0;
8188 } else {
8189 m = (l - i) % 4;
8190 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008191
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008192 for (j = 0; j < k; j++) {
8193 printk(" %2.2X%2.2X%2.2X%2.2X",
8194 (unsigned)s[i + (j * 4)],
8195 (unsigned)s[i + (j * 4) + 1],
8196 (unsigned)s[i + (j * 4) + 2],
8197 (unsigned)s[i + (j * 4) + 3]);
8198 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008199
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008200 switch (m) {
8201 case 0:
8202 default:
8203 break;
8204 case 1:
8205 printk(" %2.2X", (unsigned)s[i + (j * 4)]);
8206 break;
8207 case 2:
8208 printk(" %2.2X%2.2X",
8209 (unsigned)s[i + (j * 4)],
8210 (unsigned)s[i + (j * 4) + 1]);
8211 break;
8212 case 3:
8213 printk(" %2.2X%2.2X%2.2X",
8214 (unsigned)s[i + (j * 4) + 1],
8215 (unsigned)s[i + (j * 4) + 2],
8216 (unsigned)s[i + (j * 4) + 3]);
8217 break;
8218 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008219
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008220 printk("\n");
8221 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008222}
8223#endif /* ADVANSYS_DEBUG */
8224
8225/*
8226 * --- Asc Library Functions
8227 */
8228
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008229static ushort __init AscGetEisaChipCfg(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008230{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008231 PortAddr eisa_cfg_iop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008232
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008233 eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
8234 (PortAddr) (ASC_EISA_CFG_IOP_MASK);
8235 return (inpw(eisa_cfg_iop));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008236}
8237
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008238static uchar __init AscSetChipScsiID(PortAddr iop_base, uchar new_host_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008239{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008240 ushort cfg_lsw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008241
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008242 if (AscGetChipScsiID(iop_base) == new_host_id) {
8243 return (new_host_id);
8244 }
8245 cfg_lsw = AscGetChipCfgLsw(iop_base);
8246 cfg_lsw &= 0xF8FF;
8247 cfg_lsw |= (ushort)((new_host_id & ASC_MAX_TID) << 8);
8248 AscSetChipCfgLsw(iop_base, cfg_lsw);
8249 return (AscGetChipScsiID(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008250}
8251
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008252static uchar __init AscGetChipScsiCtrl(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008253{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008254 uchar sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008255
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008256 AscSetBank(iop_base, 1);
8257 sc = inp(iop_base + IOP_REG_SC);
8258 AscSetBank(iop_base, 0);
8259 return (sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008260}
8261
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008262static uchar __init AscGetChipVersion(PortAddr iop_base, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008263{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008264 if ((bus_type & ASC_IS_EISA) != 0) {
8265 PortAddr eisa_iop;
8266 uchar revision;
8267 eisa_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
8268 (PortAddr) ASC_EISA_REV_IOP_MASK;
8269 revision = inp(eisa_iop);
8270 return ((uchar)((ASC_CHIP_MIN_VER_EISA - 1) + revision));
8271 }
8272 return (AscGetChipVerNo(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008273}
8274
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008275static ushort __init AscGetChipBusType(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008276{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008277 ushort chip_ver;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008278
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008279 chip_ver = AscGetChipVerNo(iop_base);
8280 if ((chip_ver >= ASC_CHIP_MIN_VER_VL)
8281 && (chip_ver <= ASC_CHIP_MAX_VER_VL)
8282 ) {
8283 if (((iop_base & 0x0C30) == 0x0C30)
8284 || ((iop_base & 0x0C50) == 0x0C50)
8285 ) {
8286 return (ASC_IS_EISA);
8287 }
8288 return (ASC_IS_VL);
8289 }
8290 if ((chip_ver >= ASC_CHIP_MIN_VER_ISA) &&
8291 (chip_ver <= ASC_CHIP_MAX_VER_ISA)) {
8292 if (chip_ver >= ASC_CHIP_MIN_VER_ISA_PNP) {
8293 return (ASC_IS_ISAPNP);
8294 }
8295 return (ASC_IS_ISA);
8296 } else if ((chip_ver >= ASC_CHIP_MIN_VER_PCI) &&
8297 (chip_ver <= ASC_CHIP_MAX_VER_PCI)) {
8298 return (ASC_IS_PCI);
8299 }
8300 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008301}
8302
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008303static ASC_DCNT
8304AscLoadMicroCode(PortAddr iop_base,
8305 ushort s_addr, uchar *mcode_buf, ushort mcode_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008306{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008307 ASC_DCNT chksum;
8308 ushort mcode_word_size;
8309 ushort mcode_chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008310
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008311 /* Write the microcode buffer starting at LRAM address 0. */
8312 mcode_word_size = (ushort)(mcode_size >> 1);
8313 AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size);
8314 AscMemWordCopyPtrToLram(iop_base, s_addr, mcode_buf, mcode_word_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008315
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008316 chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size);
8317 ASC_DBG1(1, "AscLoadMicroCode: chksum 0x%lx\n", (ulong)chksum);
8318 mcode_chksum = (ushort)AscMemSumLramWord(iop_base,
8319 (ushort)ASC_CODE_SEC_BEG,
8320 (ushort)((mcode_size -
8321 s_addr - (ushort)
8322 ASC_CODE_SEC_BEG) /
8323 2));
8324 ASC_DBG1(1, "AscLoadMicroCode: mcode_chksum 0x%lx\n",
8325 (ulong)mcode_chksum);
8326 AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum);
8327 AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size);
8328 return (chksum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008329}
8330
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008331static int AscFindSignature(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008332{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008333 ushort sig_word;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008334
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008335 ASC_DBG2(1, "AscFindSignature: AscGetChipSignatureByte(0x%x) 0x%x\n",
8336 iop_base, AscGetChipSignatureByte(iop_base));
8337 if (AscGetChipSignatureByte(iop_base) == (uchar)ASC_1000_ID1B) {
8338 ASC_DBG2(1,
8339 "AscFindSignature: AscGetChipSignatureWord(0x%x) 0x%x\n",
8340 iop_base, AscGetChipSignatureWord(iop_base));
8341 sig_word = AscGetChipSignatureWord(iop_base);
8342 if ((sig_word == (ushort)ASC_1000_ID0W) ||
8343 (sig_word == (ushort)ASC_1000_ID0W_FIX)) {
8344 return (1);
8345 }
8346 }
8347 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008348}
8349
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008350static PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] __initdata = {
8351 0x100, ASC_IOADR_1, 0x120, ASC_IOADR_2, 0x140, ASC_IOADR_3, ASC_IOADR_4,
8352 ASC_IOADR_5, ASC_IOADR_6, ASC_IOADR_7, ASC_IOADR_8
Linus Torvalds1da177e2005-04-16 15:20:36 -07008353};
8354
8355#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008356static uchar _isa_pnp_inited __initdata = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008357
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008358static PortAddr __init AscSearchIOPortAddr(PortAddr iop_beg, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008359{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008360 if (bus_type & ASC_IS_VL) {
8361 while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) {
8362 if (AscGetChipVersion(iop_beg, bus_type) <=
8363 ASC_CHIP_MAX_VER_VL) {
8364 return (iop_beg);
8365 }
8366 }
8367 return (0);
8368 }
8369 if (bus_type & ASC_IS_ISA) {
8370 if (_isa_pnp_inited == 0) {
8371 AscSetISAPNPWaitForKey();
8372 _isa_pnp_inited++;
8373 }
8374 while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) {
8375 if ((AscGetChipVersion(iop_beg, bus_type) &
8376 ASC_CHIP_VER_ISA_BIT) != 0) {
8377 return (iop_beg);
8378 }
8379 }
8380 return (0);
8381 }
8382 if (bus_type & ASC_IS_EISA) {
8383 if ((iop_beg = AscSearchIOPortAddrEISA(iop_beg)) != 0) {
8384 return (iop_beg);
8385 }
8386 return (0);
8387 }
8388 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008389}
8390
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008391static PortAddr __init AscSearchIOPortAddr11(PortAddr s_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008392{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008393 int i;
8394 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008395
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008396 for (i = 0; i < ASC_IOADR_TABLE_MAX_IX; i++) {
8397 if (_asc_def_iop_base[i] > s_addr) {
8398 break;
8399 }
8400 }
8401 for (; i < ASC_IOADR_TABLE_MAX_IX; i++) {
8402 iop_base = _asc_def_iop_base[i];
8403 if (!request_region(iop_base, ASC_IOADR_GAP, "advansys")) {
8404 ASC_DBG1(1,
8405 "AscSearchIOPortAddr11: check_region() failed I/O port 0x%x\n",
8406 iop_base);
8407 continue;
8408 }
8409 ASC_DBG1(1, "AscSearchIOPortAddr11: probing I/O port 0x%x\n",
8410 iop_base);
8411 release_region(iop_base, ASC_IOADR_GAP);
8412 if (AscFindSignature(iop_base)) {
8413 return (iop_base);
8414 }
8415 }
8416 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008417}
8418
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008419static void __init AscSetISAPNPWaitForKey(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008420{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008421 outp(ASC_ISA_PNP_PORT_ADDR, 0x02);
8422 outp(ASC_ISA_PNP_PORT_WRITE, 0x02);
8423 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008424}
8425#endif /* CONFIG_ISA */
8426
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008427static void __init AscToggleIRQAct(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008428{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008429 AscSetChipStatus(iop_base, CIW_IRQ_ACT);
8430 AscSetChipStatus(iop_base, 0);
8431 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008432}
8433
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008434static uchar __init AscGetChipIRQ(PortAddr iop_base, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008435{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008436 ushort cfg_lsw;
8437 uchar chip_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008438
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008439 if ((bus_type & ASC_IS_EISA) != 0) {
8440 cfg_lsw = AscGetEisaChipCfg(iop_base);
8441 chip_irq = (uchar)(((cfg_lsw >> 8) & 0x07) + 10);
8442 if ((chip_irq == 13) || (chip_irq > 15)) {
8443 return (0);
8444 }
8445 return (chip_irq);
8446 }
8447 if ((bus_type & ASC_IS_VL) != 0) {
8448 cfg_lsw = AscGetChipCfgLsw(iop_base);
8449 chip_irq = (uchar)(((cfg_lsw >> 2) & 0x07));
8450 if ((chip_irq == 0) || (chip_irq == 4) || (chip_irq == 7)) {
8451 return (0);
8452 }
8453 return ((uchar)(chip_irq + (ASC_MIN_IRQ_NO - 1)));
8454 }
8455 cfg_lsw = AscGetChipCfgLsw(iop_base);
8456 chip_irq = (uchar)(((cfg_lsw >> 2) & 0x03));
8457 if (chip_irq == 3)
8458 chip_irq += (uchar)2;
8459 return ((uchar)(chip_irq + ASC_MIN_IRQ_NO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008460}
8461
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008462static uchar __init
8463AscSetChipIRQ(PortAddr iop_base, uchar irq_no, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008464{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008465 ushort cfg_lsw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008466
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008467 if ((bus_type & ASC_IS_VL) != 0) {
8468 if (irq_no != 0) {
8469 if ((irq_no < ASC_MIN_IRQ_NO)
8470 || (irq_no > ASC_MAX_IRQ_NO)) {
8471 irq_no = 0;
8472 } else {
8473 irq_no -= (uchar)((ASC_MIN_IRQ_NO - 1));
8474 }
8475 }
8476 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE3);
8477 cfg_lsw |= (ushort)0x0010;
8478 AscSetChipCfgLsw(iop_base, cfg_lsw);
8479 AscToggleIRQAct(iop_base);
8480 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE0);
8481 cfg_lsw |= (ushort)((irq_no & 0x07) << 2);
8482 AscSetChipCfgLsw(iop_base, cfg_lsw);
8483 AscToggleIRQAct(iop_base);
8484 return (AscGetChipIRQ(iop_base, bus_type));
8485 }
8486 if ((bus_type & (ASC_IS_ISA)) != 0) {
8487 if (irq_no == 15)
8488 irq_no -= (uchar)2;
8489 irq_no -= (uchar)ASC_MIN_IRQ_NO;
8490 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFF3);
8491 cfg_lsw |= (ushort)((irq_no & 0x03) << 2);
8492 AscSetChipCfgLsw(iop_base, cfg_lsw);
8493 return (AscGetChipIRQ(iop_base, bus_type));
8494 }
8495 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008496}
8497
8498#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008499static void __init AscEnableIsaDma(uchar dma_channel)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008500{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008501 if (dma_channel < 4) {
8502 outp(0x000B, (ushort)(0xC0 | dma_channel));
8503 outp(0x000A, dma_channel);
8504 } else if (dma_channel < 8) {
8505 outp(0x00D6, (ushort)(0xC0 | (dma_channel - 4)));
8506 outp(0x00D4, (ushort)(dma_channel - 4));
8507 }
8508 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008509}
8510#endif /* CONFIG_ISA */
8511
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008512static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008513{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008514 EXT_MSG ext_msg;
8515 EXT_MSG out_msg;
8516 ushort halt_q_addr;
8517 int sdtr_accept;
8518 ushort int_halt_code;
8519 ASC_SCSI_BIT_ID_TYPE scsi_busy;
8520 ASC_SCSI_BIT_ID_TYPE target_id;
8521 PortAddr iop_base;
8522 uchar tag_code;
8523 uchar q_status;
8524 uchar halt_qp;
8525 uchar sdtr_data;
8526 uchar target_ix;
8527 uchar q_cntl, tid_no;
8528 uchar cur_dvc_qng;
8529 uchar asyn_sdtr;
8530 uchar scsi_status;
8531 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008532
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008533 ASC_ASSERT(asc_dvc->drv_ptr != NULL);
8534 boardp = asc_dvc->drv_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008535
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008536 iop_base = asc_dvc->iop_base;
8537 int_halt_code = AscReadLramWord(iop_base, ASCV_HALTCODE_W);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008538
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008539 halt_qp = AscReadLramByte(iop_base, ASCV_CURCDB_B);
8540 halt_q_addr = ASC_QNO_TO_QADDR(halt_qp);
8541 target_ix = AscReadLramByte(iop_base,
8542 (ushort)(halt_q_addr +
8543 (ushort)ASC_SCSIQ_B_TARGET_IX));
8544 q_cntl =
8545 AscReadLramByte(iop_base,
8546 (ushort)(halt_q_addr + (ushort)ASC_SCSIQ_B_CNTL));
8547 tid_no = ASC_TIX_TO_TID(target_ix);
8548 target_id = (uchar)ASC_TID_TO_TARGET_ID(tid_no);
8549 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
8550 asyn_sdtr = ASYN_SDTR_DATA_FIX_PCI_REV_AB;
8551 } else {
8552 asyn_sdtr = 0;
8553 }
8554 if (int_halt_code == ASC_HALT_DISABLE_ASYN_USE_SYN_FIX) {
8555 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
8556 AscSetChipSDTR(iop_base, 0, tid_no);
8557 boardp->sdtr_data[tid_no] = 0;
8558 }
8559 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8560 return (0);
8561 } else if (int_halt_code == ASC_HALT_ENABLE_ASYN_USE_SYN_FIX) {
8562 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
8563 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
8564 boardp->sdtr_data[tid_no] = asyn_sdtr;
8565 }
8566 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8567 return (0);
8568 } else if (int_halt_code == ASC_HALT_EXTMSG_IN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008569
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008570 AscMemWordCopyPtrFromLram(iop_base,
8571 ASCV_MSGIN_BEG,
8572 (uchar *)&ext_msg,
8573 sizeof(EXT_MSG) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008574
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008575 if (ext_msg.msg_type == MS_EXTEND &&
8576 ext_msg.msg_req == MS_SDTR_CODE &&
8577 ext_msg.msg_len == MS_SDTR_LEN) {
8578 sdtr_accept = TRUE;
8579 if ((ext_msg.req_ack_offset > ASC_SYN_MAX_OFFSET)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008580
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008581 sdtr_accept = FALSE;
8582 ext_msg.req_ack_offset = ASC_SYN_MAX_OFFSET;
8583 }
8584 if ((ext_msg.xfer_period <
8585 asc_dvc->sdtr_period_tbl[asc_dvc->
8586 host_init_sdtr_index])
8587 || (ext_msg.xfer_period >
8588 asc_dvc->sdtr_period_tbl[asc_dvc->
8589 max_sdtr_index])) {
8590 sdtr_accept = FALSE;
8591 ext_msg.xfer_period =
8592 asc_dvc->sdtr_period_tbl[asc_dvc->
8593 host_init_sdtr_index];
8594 }
8595 if (sdtr_accept) {
8596 sdtr_data =
8597 AscCalSDTRData(asc_dvc, ext_msg.xfer_period,
8598 ext_msg.req_ack_offset);
8599 if ((sdtr_data == 0xFF)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008600
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008601 q_cntl |= QC_MSG_OUT;
8602 asc_dvc->init_sdtr &= ~target_id;
8603 asc_dvc->sdtr_done &= ~target_id;
8604 AscSetChipSDTR(iop_base, asyn_sdtr,
8605 tid_no);
8606 boardp->sdtr_data[tid_no] = asyn_sdtr;
8607 }
8608 }
8609 if (ext_msg.req_ack_offset == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008610
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008611 q_cntl &= ~QC_MSG_OUT;
8612 asc_dvc->init_sdtr &= ~target_id;
8613 asc_dvc->sdtr_done &= ~target_id;
8614 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
8615 } else {
8616 if (sdtr_accept && (q_cntl & QC_MSG_OUT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008617
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008618 q_cntl &= ~QC_MSG_OUT;
8619 asc_dvc->sdtr_done |= target_id;
8620 asc_dvc->init_sdtr |= target_id;
8621 asc_dvc->pci_fix_asyn_xfer &=
8622 ~target_id;
8623 sdtr_data =
8624 AscCalSDTRData(asc_dvc,
8625 ext_msg.xfer_period,
8626 ext_msg.
8627 req_ack_offset);
8628 AscSetChipSDTR(iop_base, sdtr_data,
8629 tid_no);
8630 boardp->sdtr_data[tid_no] = sdtr_data;
8631 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008632
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008633 q_cntl |= QC_MSG_OUT;
8634 AscMsgOutSDTR(asc_dvc,
8635 ext_msg.xfer_period,
8636 ext_msg.req_ack_offset);
8637 asc_dvc->pci_fix_asyn_xfer &=
8638 ~target_id;
8639 sdtr_data =
8640 AscCalSDTRData(asc_dvc,
8641 ext_msg.xfer_period,
8642 ext_msg.
8643 req_ack_offset);
8644 AscSetChipSDTR(iop_base, sdtr_data,
8645 tid_no);
8646 boardp->sdtr_data[tid_no] = sdtr_data;
8647 asc_dvc->sdtr_done |= target_id;
8648 asc_dvc->init_sdtr |= target_id;
8649 }
8650 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008651
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008652 AscWriteLramByte(iop_base,
8653 (ushort)(halt_q_addr +
8654 (ushort)ASC_SCSIQ_B_CNTL),
8655 q_cntl);
8656 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8657 return (0);
8658 } else if (ext_msg.msg_type == MS_EXTEND &&
8659 ext_msg.msg_req == MS_WDTR_CODE &&
8660 ext_msg.msg_len == MS_WDTR_LEN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008661
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008662 ext_msg.wdtr_width = 0;
8663 AscMemWordCopyPtrToLram(iop_base,
8664 ASCV_MSGOUT_BEG,
8665 (uchar *)&ext_msg,
8666 sizeof(EXT_MSG) >> 1);
8667 q_cntl |= QC_MSG_OUT;
8668 AscWriteLramByte(iop_base,
8669 (ushort)(halt_q_addr +
8670 (ushort)ASC_SCSIQ_B_CNTL),
8671 q_cntl);
8672 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8673 return (0);
8674 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008675
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008676 ext_msg.msg_type = MESSAGE_REJECT;
8677 AscMemWordCopyPtrToLram(iop_base,
8678 ASCV_MSGOUT_BEG,
8679 (uchar *)&ext_msg,
8680 sizeof(EXT_MSG) >> 1);
8681 q_cntl |= QC_MSG_OUT;
8682 AscWriteLramByte(iop_base,
8683 (ushort)(halt_q_addr +
8684 (ushort)ASC_SCSIQ_B_CNTL),
8685 q_cntl);
8686 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8687 return (0);
8688 }
8689 } else if (int_halt_code == ASC_HALT_CHK_CONDITION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008690
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008691 q_cntl |= QC_REQ_SENSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008692
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008693 if ((asc_dvc->init_sdtr & target_id) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008694
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008695 asc_dvc->sdtr_done &= ~target_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008696
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008697 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
8698 q_cntl |= QC_MSG_OUT;
8699 AscMsgOutSDTR(asc_dvc,
8700 asc_dvc->
8701 sdtr_period_tbl[(sdtr_data >> 4) &
8702 (uchar)(asc_dvc->
8703 max_sdtr_index -
8704 1)],
8705 (uchar)(sdtr_data & (uchar)
8706 ASC_SYN_MAX_OFFSET));
8707 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008708
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008709 AscWriteLramByte(iop_base,
8710 (ushort)(halt_q_addr +
8711 (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008712
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008713 tag_code = AscReadLramByte(iop_base,
8714 (ushort)(halt_q_addr + (ushort)
8715 ASC_SCSIQ_B_TAG_CODE));
8716 tag_code &= 0xDC;
8717 if ((asc_dvc->pci_fix_asyn_xfer & target_id)
8718 && !(asc_dvc->pci_fix_asyn_xfer_always & target_id)
8719 ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008720
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008721 tag_code |= (ASC_TAG_FLAG_DISABLE_DISCONNECT
8722 | ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008723
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008724 }
8725 AscWriteLramByte(iop_base,
8726 (ushort)(halt_q_addr +
8727 (ushort)ASC_SCSIQ_B_TAG_CODE),
8728 tag_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008729
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008730 q_status = AscReadLramByte(iop_base,
8731 (ushort)(halt_q_addr + (ushort)
8732 ASC_SCSIQ_B_STATUS));
8733 q_status |= (QS_READY | QS_BUSY);
8734 AscWriteLramByte(iop_base,
8735 (ushort)(halt_q_addr +
8736 (ushort)ASC_SCSIQ_B_STATUS),
8737 q_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008738
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008739 scsi_busy = AscReadLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B);
8740 scsi_busy &= ~target_id;
8741 AscWriteLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B, scsi_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008742
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008743 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8744 return (0);
8745 } else if (int_halt_code == ASC_HALT_SDTR_REJECTED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008746
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008747 AscMemWordCopyPtrFromLram(iop_base,
8748 ASCV_MSGOUT_BEG,
8749 (uchar *)&out_msg,
8750 sizeof(EXT_MSG) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008751
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008752 if ((out_msg.msg_type == MS_EXTEND) &&
8753 (out_msg.msg_len == MS_SDTR_LEN) &&
8754 (out_msg.msg_req == MS_SDTR_CODE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008755
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008756 asc_dvc->init_sdtr &= ~target_id;
8757 asc_dvc->sdtr_done &= ~target_id;
8758 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
8759 boardp->sdtr_data[tid_no] = asyn_sdtr;
8760 }
8761 q_cntl &= ~QC_MSG_OUT;
8762 AscWriteLramByte(iop_base,
8763 (ushort)(halt_q_addr +
8764 (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
8765 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8766 return (0);
8767 } else if (int_halt_code == ASC_HALT_SS_QUEUE_FULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008768
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008769 scsi_status = AscReadLramByte(iop_base,
8770 (ushort)((ushort)halt_q_addr +
8771 (ushort)
8772 ASC_SCSIQ_SCSI_STATUS));
8773 cur_dvc_qng =
8774 AscReadLramByte(iop_base,
8775 (ushort)((ushort)ASC_QADR_BEG +
8776 (ushort)target_ix));
8777 if ((cur_dvc_qng > 0) && (asc_dvc->cur_dvc_qng[tid_no] > 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008778
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008779 scsi_busy = AscReadLramByte(iop_base,
8780 (ushort)ASCV_SCSIBUSY_B);
8781 scsi_busy |= target_id;
8782 AscWriteLramByte(iop_base,
8783 (ushort)ASCV_SCSIBUSY_B, scsi_busy);
8784 asc_dvc->queue_full_or_busy |= target_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008785
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008786 if (scsi_status == SAM_STAT_TASK_SET_FULL) {
8787 if (cur_dvc_qng > ASC_MIN_TAGGED_CMD) {
8788 cur_dvc_qng -= 1;
8789 asc_dvc->max_dvc_qng[tid_no] =
8790 cur_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008791
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008792 AscWriteLramByte(iop_base,
8793 (ushort)((ushort)
8794 ASCV_MAX_DVC_QNG_BEG
8795 + (ushort)
8796 tid_no),
8797 cur_dvc_qng);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008798
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008799 /*
8800 * Set the device queue depth to the number of
8801 * active requests when the QUEUE FULL condition
8802 * was encountered.
8803 */
8804 boardp->queue_full |= target_id;
8805 boardp->queue_full_cnt[tid_no] =
8806 cur_dvc_qng;
8807 }
8808 }
8809 }
8810 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8811 return (0);
8812 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008813#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008814 else if (int_halt_code == ASC_HALT_HOST_COPY_SG_LIST_TO_RISC) {
8815 uchar q_no;
8816 ushort q_addr;
8817 uchar sg_wk_q_no;
8818 uchar first_sg_wk_q_no;
8819 ASC_SCSI_Q *scsiq; /* Ptr to driver request. */
8820 ASC_SG_HEAD *sg_head; /* Ptr to driver SG request. */
8821 ASC_SG_LIST_Q scsi_sg_q; /* Structure written to queue. */
8822 ushort sg_list_dwords;
8823 ushort sg_entry_cnt;
8824 uchar next_qp;
8825 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008826
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008827 q_no = AscReadLramByte(iop_base, (ushort)ASCV_REQ_SG_LIST_QP);
8828 if (q_no == ASC_QLINK_END) {
8829 return (0);
8830 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008831
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008832 q_addr = ASC_QNO_TO_QADDR(q_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008833
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008834 /*
8835 * Convert the request's SRB pointer to a host ASC_SCSI_REQ
8836 * structure pointer using a macro provided by the driver.
8837 * The ASC_SCSI_REQ pointer provides a pointer to the
8838 * host ASC_SG_HEAD structure.
8839 */
8840 /* Read request's SRB pointer. */
8841 scsiq = (ASC_SCSI_Q *)
8842 ASC_SRB2SCSIQ(ASC_U32_TO_VADDR(AscReadLramDWord(iop_base,
8843 (ushort)
8844 (q_addr +
8845 ASC_SCSIQ_D_SRBPTR))));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008846
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008847 /*
8848 * Get request's first and working SG queue.
8849 */
8850 sg_wk_q_no = AscReadLramByte(iop_base,
8851 (ushort)(q_addr +
8852 ASC_SCSIQ_B_SG_WK_QP));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008853
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008854 first_sg_wk_q_no = AscReadLramByte(iop_base,
8855 (ushort)(q_addr +
8856 ASC_SCSIQ_B_FIRST_SG_WK_QP));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008857
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008858 /*
8859 * Reset request's working SG queue back to the
8860 * first SG queue.
8861 */
8862 AscWriteLramByte(iop_base,
8863 (ushort)(q_addr +
8864 (ushort)ASC_SCSIQ_B_SG_WK_QP),
8865 first_sg_wk_q_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008866
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008867 sg_head = scsiq->sg_head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008868
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008869 /*
8870 * Set sg_entry_cnt to the number of SG elements
8871 * that will be completed on this interrupt.
8872 *
8873 * Note: The allocated SG queues contain ASC_MAX_SG_LIST - 1
8874 * SG elements. The data_cnt and data_addr fields which
8875 * add 1 to the SG element capacity are not used when
8876 * restarting SG handling after a halt.
8877 */
8878 if (scsiq->remain_sg_entry_cnt > (ASC_MAX_SG_LIST - 1)) {
8879 sg_entry_cnt = ASC_MAX_SG_LIST - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008880
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008881 /*
8882 * Keep track of remaining number of SG elements that will
8883 * need to be handled on the next interrupt.
8884 */
8885 scsiq->remain_sg_entry_cnt -= (ASC_MAX_SG_LIST - 1);
8886 } else {
8887 sg_entry_cnt = scsiq->remain_sg_entry_cnt;
8888 scsiq->remain_sg_entry_cnt = 0;
8889 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008890
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008891 /*
8892 * Copy SG elements into the list of allocated SG queues.
8893 *
8894 * Last index completed is saved in scsiq->next_sg_index.
8895 */
8896 next_qp = first_sg_wk_q_no;
8897 q_addr = ASC_QNO_TO_QADDR(next_qp);
8898 scsi_sg_q.sg_head_qp = q_no;
8899 scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
8900 for (i = 0; i < sg_head->queue_cnt; i++) {
8901 scsi_sg_q.seq_no = i + 1;
8902 if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
8903 sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
8904 sg_entry_cnt -= ASC_SG_LIST_PER_Q;
8905 /*
8906 * After very first SG queue RISC FW uses next
8907 * SG queue first element then checks sg_list_cnt
8908 * against zero and then decrements, so set
8909 * sg_list_cnt 1 less than number of SG elements
8910 * in each SG queue.
8911 */
8912 scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1;
8913 scsi_sg_q.sg_cur_list_cnt =
8914 ASC_SG_LIST_PER_Q - 1;
8915 } else {
8916 /*
8917 * This is the last SG queue in the list of
8918 * allocated SG queues. If there are more
8919 * SG elements than will fit in the allocated
8920 * queues, then set the QCSG_SG_XFER_MORE flag.
8921 */
8922 if (scsiq->remain_sg_entry_cnt != 0) {
8923 scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
8924 } else {
8925 scsi_sg_q.cntl |= QCSG_SG_XFER_END;
8926 }
8927 /* equals sg_entry_cnt * 2 */
8928 sg_list_dwords = sg_entry_cnt << 1;
8929 scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1;
8930 scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1;
8931 sg_entry_cnt = 0;
8932 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008933
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008934 scsi_sg_q.q_no = next_qp;
8935 AscMemWordCopyPtrToLram(iop_base,
8936 q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
8937 (uchar *)&scsi_sg_q,
8938 sizeof(ASC_SG_LIST_Q) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008939
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008940 AscMemDWordCopyPtrToLram(iop_base,
8941 q_addr + ASC_SGQ_LIST_BEG,
8942 (uchar *)&sg_head->
8943 sg_list[scsiq->next_sg_index],
8944 sg_list_dwords);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008945
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008946 scsiq->next_sg_index += ASC_SG_LIST_PER_Q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008947
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008948 /*
8949 * If the just completed SG queue contained the
8950 * last SG element, then no more SG queues need
8951 * to be written.
8952 */
8953 if (scsi_sg_q.cntl & QCSG_SG_XFER_END) {
8954 break;
8955 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008956
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008957 next_qp = AscReadLramByte(iop_base,
8958 (ushort)(q_addr +
8959 ASC_SCSIQ_B_FWD));
8960 q_addr = ASC_QNO_TO_QADDR(next_qp);
8961 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008962
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008963 /*
8964 * Clear the halt condition so the RISC will be restarted
8965 * after the return.
8966 */
8967 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8968 return (0);
8969 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008970#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008971 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008972}
8973
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008974static uchar
8975_AscCopyLramScsiDoneQ(PortAddr iop_base,
8976 ushort q_addr,
8977 ASC_QDONE_INFO *scsiq, ASC_DCNT max_dma_count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008978{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008979 ushort _val;
8980 uchar sg_queue_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008981
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008982 DvcGetQinfo(iop_base,
8983 q_addr + ASC_SCSIQ_DONE_INFO_BEG,
8984 (uchar *)scsiq,
8985 (sizeof(ASC_SCSIQ_2) + sizeof(ASC_SCSIQ_3)) / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008986
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008987 _val = AscReadLramWord(iop_base,
8988 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS));
8989 scsiq->q_status = (uchar)_val;
8990 scsiq->q_no = (uchar)(_val >> 8);
8991 _val = AscReadLramWord(iop_base,
8992 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_CNTL));
8993 scsiq->cntl = (uchar)_val;
8994 sg_queue_cnt = (uchar)(_val >> 8);
8995 _val = AscReadLramWord(iop_base,
8996 (ushort)(q_addr +
8997 (ushort)ASC_SCSIQ_B_SENSE_LEN));
8998 scsiq->sense_len = (uchar)_val;
8999 scsiq->extra_bytes = (uchar)(_val >> 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009000
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009001 /*
9002 * Read high word of remain bytes from alternate location.
9003 */
9004 scsiq->remain_bytes = (((ADV_DCNT)AscReadLramWord(iop_base,
9005 (ushort)(q_addr +
9006 (ushort)
9007 ASC_SCSIQ_W_ALT_DC1)))
9008 << 16);
9009 /*
9010 * Read low word of remain bytes from original location.
9011 */
9012 scsiq->remain_bytes += AscReadLramWord(iop_base,
9013 (ushort)(q_addr + (ushort)
9014 ASC_SCSIQ_DW_REMAIN_XFER_CNT));
Linus Torvalds1da177e2005-04-16 15:20:36 -07009015
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009016 scsiq->remain_bytes &= max_dma_count;
9017 return (sg_queue_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009018}
9019
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009020static int AscIsrQDone(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009021{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009022 uchar next_qp;
9023 uchar n_q_used;
9024 uchar sg_list_qp;
9025 uchar sg_queue_cnt;
9026 uchar q_cnt;
9027 uchar done_q_tail;
9028 uchar tid_no;
9029 ASC_SCSI_BIT_ID_TYPE scsi_busy;
9030 ASC_SCSI_BIT_ID_TYPE target_id;
9031 PortAddr iop_base;
9032 ushort q_addr;
9033 ushort sg_q_addr;
9034 uchar cur_target_qng;
9035 ASC_QDONE_INFO scsiq_buf;
9036 ASC_QDONE_INFO *scsiq;
9037 int false_overrun;
9038 ASC_ISR_CALLBACK asc_isr_callback;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009039
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009040 iop_base = asc_dvc->iop_base;
9041 asc_isr_callback = asc_dvc->isr_callback;
9042 n_q_used = 1;
9043 scsiq = (ASC_QDONE_INFO *)&scsiq_buf;
9044 done_q_tail = (uchar)AscGetVarDoneQTail(iop_base);
9045 q_addr = ASC_QNO_TO_QADDR(done_q_tail);
9046 next_qp = AscReadLramByte(iop_base,
9047 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_FWD));
9048 if (next_qp != ASC_QLINK_END) {
9049 AscPutVarDoneQTail(iop_base, next_qp);
9050 q_addr = ASC_QNO_TO_QADDR(next_qp);
9051 sg_queue_cnt = _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq,
9052 asc_dvc->max_dma_count);
9053 AscWriteLramByte(iop_base,
9054 (ushort)(q_addr +
9055 (ushort)ASC_SCSIQ_B_STATUS),
9056 (uchar)(scsiq->
9057 q_status & (uchar)~(QS_READY |
9058 QS_ABORTED)));
9059 tid_no = ASC_TIX_TO_TID(scsiq->d2.target_ix);
9060 target_id = ASC_TIX_TO_TARGET_ID(scsiq->d2.target_ix);
9061 if ((scsiq->cntl & QC_SG_HEAD) != 0) {
9062 sg_q_addr = q_addr;
9063 sg_list_qp = next_qp;
9064 for (q_cnt = 0; q_cnt < sg_queue_cnt; q_cnt++) {
9065 sg_list_qp = AscReadLramByte(iop_base,
9066 (ushort)(sg_q_addr
9067 + (ushort)
9068 ASC_SCSIQ_B_FWD));
9069 sg_q_addr = ASC_QNO_TO_QADDR(sg_list_qp);
9070 if (sg_list_qp == ASC_QLINK_END) {
9071 AscSetLibErrorCode(asc_dvc,
9072 ASCQ_ERR_SG_Q_LINKS);
9073 scsiq->d3.done_stat = QD_WITH_ERROR;
9074 scsiq->d3.host_stat =
9075 QHSTA_D_QDONE_SG_LIST_CORRUPTED;
9076 goto FATAL_ERR_QDONE;
9077 }
9078 AscWriteLramByte(iop_base,
9079 (ushort)(sg_q_addr + (ushort)
9080 ASC_SCSIQ_B_STATUS),
9081 QS_FREE);
9082 }
9083 n_q_used = sg_queue_cnt + 1;
9084 AscPutVarDoneQTail(iop_base, sg_list_qp);
9085 }
9086 if (asc_dvc->queue_full_or_busy & target_id) {
9087 cur_target_qng = AscReadLramByte(iop_base,
9088 (ushort)((ushort)
9089 ASC_QADR_BEG
9090 + (ushort)
9091 scsiq->d2.
9092 target_ix));
9093 if (cur_target_qng < asc_dvc->max_dvc_qng[tid_no]) {
9094 scsi_busy = AscReadLramByte(iop_base, (ushort)
9095 ASCV_SCSIBUSY_B);
9096 scsi_busy &= ~target_id;
9097 AscWriteLramByte(iop_base,
9098 (ushort)ASCV_SCSIBUSY_B,
9099 scsi_busy);
9100 asc_dvc->queue_full_or_busy &= ~target_id;
9101 }
9102 }
9103 if (asc_dvc->cur_total_qng >= n_q_used) {
9104 asc_dvc->cur_total_qng -= n_q_used;
9105 if (asc_dvc->cur_dvc_qng[tid_no] != 0) {
9106 asc_dvc->cur_dvc_qng[tid_no]--;
9107 }
9108 } else {
9109 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CUR_QNG);
9110 scsiq->d3.done_stat = QD_WITH_ERROR;
9111 goto FATAL_ERR_QDONE;
9112 }
9113 if ((scsiq->d2.srb_ptr == 0UL) ||
9114 ((scsiq->q_status & QS_ABORTED) != 0)) {
9115 return (0x11);
9116 } else if (scsiq->q_status == QS_DONE) {
9117 false_overrun = FALSE;
9118 if (scsiq->extra_bytes != 0) {
9119 scsiq->remain_bytes +=
9120 (ADV_DCNT)scsiq->extra_bytes;
9121 }
9122 if (scsiq->d3.done_stat == QD_WITH_ERROR) {
9123 if (scsiq->d3.host_stat ==
9124 QHSTA_M_DATA_OVER_RUN) {
9125 if ((scsiq->
9126 cntl & (QC_DATA_IN | QC_DATA_OUT))
9127 == 0) {
9128 scsiq->d3.done_stat =
9129 QD_NO_ERROR;
9130 scsiq->d3.host_stat =
9131 QHSTA_NO_ERROR;
9132 } else if (false_overrun) {
9133 scsiq->d3.done_stat =
9134 QD_NO_ERROR;
9135 scsiq->d3.host_stat =
9136 QHSTA_NO_ERROR;
9137 }
9138 } else if (scsiq->d3.host_stat ==
9139 QHSTA_M_HUNG_REQ_SCSI_BUS_RESET) {
9140 AscStopChip(iop_base);
9141 AscSetChipControl(iop_base,
9142 (uchar)(CC_SCSI_RESET
9143 | CC_HALT));
9144 DvcDelayNanoSecond(asc_dvc, 60000);
9145 AscSetChipControl(iop_base, CC_HALT);
9146 AscSetChipStatus(iop_base,
9147 CIW_CLR_SCSI_RESET_INT);
9148 AscSetChipStatus(iop_base, 0);
9149 AscSetChipControl(iop_base, 0);
9150 }
9151 }
9152 if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
9153 (*asc_isr_callback) (asc_dvc, scsiq);
9154 } else {
9155 if ((AscReadLramByte(iop_base,
9156 (ushort)(q_addr + (ushort)
9157 ASC_SCSIQ_CDB_BEG))
9158 == START_STOP)) {
9159 asc_dvc->unit_not_ready &= ~target_id;
9160 if (scsiq->d3.done_stat != QD_NO_ERROR) {
9161 asc_dvc->start_motor &=
9162 ~target_id;
9163 }
9164 }
9165 }
9166 return (1);
9167 } else {
9168 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_Q_STATUS);
9169 FATAL_ERR_QDONE:
9170 if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
9171 (*asc_isr_callback) (asc_dvc, scsiq);
9172 }
9173 return (0x80);
9174 }
9175 }
9176 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009177}
9178
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009179static int AscISR(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009180{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009181 ASC_CS_TYPE chipstat;
9182 PortAddr iop_base;
9183 ushort saved_ram_addr;
9184 uchar ctrl_reg;
9185 uchar saved_ctrl_reg;
9186 int int_pending;
9187 int status;
9188 uchar host_flag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009189
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009190 iop_base = asc_dvc->iop_base;
9191 int_pending = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009192
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009193 if (AscIsIntPending(iop_base) == 0) {
9194 return int_pending;
9195 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009196
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009197 if (((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0)
9198 || (asc_dvc->isr_callback == 0)
9199 ) {
9200 return (ERR);
9201 }
9202 if (asc_dvc->in_critical_cnt != 0) {
9203 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_ON_CRITICAL);
9204 return (ERR);
9205 }
9206 if (asc_dvc->is_in_int) {
9207 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_RE_ENTRY);
9208 return (ERR);
9209 }
9210 asc_dvc->is_in_int = TRUE;
9211 ctrl_reg = AscGetChipControl(iop_base);
9212 saved_ctrl_reg = ctrl_reg & (~(CC_SCSI_RESET | CC_CHIP_RESET |
9213 CC_SINGLE_STEP | CC_DIAG | CC_TEST));
9214 chipstat = AscGetChipStatus(iop_base);
9215 if (chipstat & CSW_SCSI_RESET_LATCH) {
9216 if (!(asc_dvc->bus_type & (ASC_IS_VL | ASC_IS_EISA))) {
9217 int i = 10;
9218 int_pending = TRUE;
9219 asc_dvc->sdtr_done = 0;
9220 saved_ctrl_reg &= (uchar)(~CC_HALT);
9221 while ((AscGetChipStatus(iop_base) &
9222 CSW_SCSI_RESET_ACTIVE) && (i-- > 0)) {
9223 DvcSleepMilliSecond(100);
9224 }
9225 AscSetChipControl(iop_base, (CC_CHIP_RESET | CC_HALT));
9226 AscSetChipControl(iop_base, CC_HALT);
9227 AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
9228 AscSetChipStatus(iop_base, 0);
9229 chipstat = AscGetChipStatus(iop_base);
9230 }
9231 }
9232 saved_ram_addr = AscGetChipLramAddr(iop_base);
9233 host_flag = AscReadLramByte(iop_base,
9234 ASCV_HOST_FLAG_B) &
9235 (uchar)(~ASC_HOST_FLAG_IN_ISR);
9236 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
9237 (uchar)(host_flag | (uchar)ASC_HOST_FLAG_IN_ISR));
9238 if ((chipstat & CSW_INT_PENDING)
9239 || (int_pending)
9240 ) {
9241 AscAckInterrupt(iop_base);
9242 int_pending = TRUE;
9243 if ((chipstat & CSW_HALTED) && (ctrl_reg & CC_SINGLE_STEP)) {
9244 if (AscIsrChipHalted(asc_dvc) == ERR) {
9245 goto ISR_REPORT_QDONE_FATAL_ERROR;
9246 } else {
9247 saved_ctrl_reg &= (uchar)(~CC_HALT);
9248 }
9249 } else {
9250 ISR_REPORT_QDONE_FATAL_ERROR:
9251 if ((asc_dvc->dvc_cntl & ASC_CNTL_INT_MULTI_Q) != 0) {
9252 while (((status =
9253 AscIsrQDone(asc_dvc)) & 0x01) != 0) {
9254 }
9255 } else {
9256 do {
9257 if ((status =
9258 AscIsrQDone(asc_dvc)) == 1) {
9259 break;
9260 }
9261 } while (status == 0x11);
9262 }
9263 if ((status & 0x80) != 0)
9264 int_pending = ERR;
9265 }
9266 }
9267 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
9268 AscSetChipLramAddr(iop_base, saved_ram_addr);
9269 AscSetChipControl(iop_base, saved_ctrl_reg);
9270 asc_dvc->is_in_int = FALSE;
9271 return (int_pending);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009272}
9273
9274/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009275static uchar _asc_mcode_buf[] = {
9276 0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9277 0x00, 0x00, 0x00, 0x00,
9278 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00,
9279 0x00, 0x00, 0x00, 0x00,
9280 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9281 0x00, 0x00, 0x00, 0x00,
9282 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9283 0x00, 0x00, 0x00, 0x00,
9284 0x00, 0x00, 0x00, 0x00, 0xC3, 0x12, 0x0D, 0x05, 0x01, 0x00, 0x00, 0x00,
9285 0x00, 0xFF, 0x00, 0x00,
9286 0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00,
9287 0x00, 0x00, 0x00, 0x00,
9288 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF,
9289 0x00, 0x00, 0x00, 0x00,
9290 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x88,
9291 0x00, 0x00, 0x00, 0x00,
9292 0x80, 0x73, 0x48, 0x04, 0x36, 0x00, 0x00, 0xA2, 0xC2, 0x00, 0x80, 0x73,
9293 0x03, 0x23, 0x36, 0x40,
9294 0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12, 0xDA, 0x00, 0xA2,
9295 0xC2, 0x00, 0x92, 0x80,
9296 0x1E, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xDF, 0x23, 0x36, 0x60,
9297 0xB6, 0x00, 0x92, 0x80,
9298 0x4F, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00,
9299 0x92, 0x80, 0x80, 0x62,
9300 0x92, 0x80, 0x00, 0x46, 0x15, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8,
9301 0xCD, 0x04, 0x4D, 0x00,
9302 0x00, 0xA3, 0xD6, 0x00, 0xA6, 0x97, 0x7F, 0x23, 0x04, 0x61, 0x84, 0x01,
9303 0xE6, 0x84, 0xD2, 0xC1,
9304 0x80, 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xDA, 0x01, 0xA6, 0x97,
9305 0xC6, 0x81, 0xC2, 0x88,
9306 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0xFE, 0x00, 0x4F, 0x00,
9307 0x84, 0x97, 0x07, 0xA6,
9308 0x08, 0x01, 0x00, 0x33, 0x03, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x01, 0xDE,
9309 0xC2, 0x88, 0xCE, 0x00,
9310 0x69, 0x60, 0xCE, 0x00, 0x02, 0x03, 0x4A, 0x60, 0x00, 0xA2, 0x78, 0x01,
9311 0x80, 0x63, 0x07, 0xA6,
9312 0x24, 0x01, 0x78, 0x81, 0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6,
9313 0x34, 0x01, 0x00, 0x33,
9314 0x04, 0x00, 0xC2, 0x88, 0x03, 0x07, 0x02, 0x01, 0x04, 0xCA, 0x0D, 0x23,
9315 0x68, 0x98, 0x4D, 0x04,
9316 0x04, 0x85, 0x05, 0xD8, 0x0D, 0x23, 0x68, 0x98, 0xCD, 0x04, 0x15, 0x23,
9317 0xF8, 0x88, 0xFB, 0x23,
9318 0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, 0x06, 0xA3, 0x62, 0x01,
9319 0x00, 0x33, 0x0A, 0x00,
9320 0xC2, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x6E, 0x01, 0x00, 0x33, 0x0B, 0x00,
9321 0xC2, 0x88, 0xCD, 0x04,
9322 0x36, 0x2D, 0x00, 0x33, 0x1A, 0x00, 0xC2, 0x88, 0x50, 0x04, 0x88, 0x81,
9323 0x06, 0xAB, 0x82, 0x01,
9324 0x88, 0x81, 0x4E, 0x00, 0x07, 0xA3, 0x92, 0x01, 0x50, 0x00, 0x00, 0xA3,
9325 0x3C, 0x01, 0x00, 0x05,
9326 0x7C, 0x81, 0x46, 0x97, 0x02, 0x01, 0x05, 0xC6, 0x04, 0x23, 0xA0, 0x01,
9327 0x15, 0x23, 0xA1, 0x01,
9328 0xBE, 0x81, 0xFD, 0x23, 0x02, 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00,
9329 0x06, 0x61, 0x00, 0xA0,
9330 0xB4, 0x01, 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, 0x00,
9331 0xC2, 0x88, 0x06, 0x23,
9332 0x68, 0x98, 0xCD, 0x04, 0xE6, 0x84, 0x06, 0x01, 0x00, 0xA2, 0xD4, 0x01,
9333 0x57, 0x60, 0x00, 0xA0,
9334 0xDA, 0x01, 0xE6, 0x84, 0x80, 0x23, 0xA0, 0x01, 0xE6, 0x84, 0x80, 0x73,
9335 0x4B, 0x00, 0x06, 0x61,
9336 0x00, 0xA2, 0x00, 0x02, 0x04, 0x01, 0x0C, 0xDE, 0x02, 0x01, 0x03, 0xCC,
9337 0x4F, 0x00, 0x84, 0x97,
9338 0xFC, 0x81, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01, 0x4F, 0x00, 0x62, 0x97,
9339 0x48, 0x04, 0x84, 0x80,
9340 0xF0, 0x97, 0x00, 0x46, 0x56, 0x00, 0x03, 0xC0, 0x01, 0x23, 0xE8, 0x00,
9341 0x81, 0x73, 0x06, 0x29,
9342 0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x6B, 0xEB, 0x11, 0x23, 0xF8, 0x88,
9343 0x04, 0x98, 0xF0, 0x80,
9344 0x80, 0x73, 0x80, 0x77, 0x07, 0xA4, 0x2A, 0x02, 0x7C, 0x95, 0x06, 0xA6,
9345 0x34, 0x02, 0x03, 0xA6,
9346 0x4C, 0x04, 0x46, 0x82, 0x04, 0x01, 0x03, 0xD8, 0xB4, 0x98, 0x6A, 0x96,
9347 0x46, 0x82, 0xFE, 0x95,
9348 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x02, 0xA6, 0x6C, 0x02,
9349 0x07, 0xA6, 0x5A, 0x02,
9350 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x62, 0x02, 0xC2, 0x88, 0x7C, 0x95,
9351 0x48, 0x82, 0x60, 0x96,
9352 0x48, 0x82, 0x04, 0x23, 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x3C, 0x84,
9353 0x04, 0x01, 0x0C, 0xDC,
9354 0xE0, 0x23, 0x25, 0x61, 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01,
9355 0x6F, 0x00, 0xA5, 0x01,
9356 0x03, 0x23, 0xA4, 0x01, 0x06, 0x23, 0x9C, 0x01, 0x24, 0x2B, 0x1C, 0x01,
9357 0x02, 0xA6, 0xAA, 0x02,
9358 0x07, 0xA6, 0x5A, 0x02, 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x20, 0x04,
9359 0x01, 0xA6, 0xB4, 0x02,
9360 0x00, 0xA6, 0xB4, 0x02, 0x00, 0x33, 0x12, 0x00, 0xC2, 0x88, 0x00, 0x0E,
9361 0x80, 0x63, 0x00, 0x43,
9362 0x00, 0xA0, 0x8C, 0x02, 0x4D, 0x04, 0x04, 0x01, 0x0B, 0xDC, 0xE7, 0x23,
9363 0x04, 0x61, 0x84, 0x01,
9364 0x10, 0x31, 0x12, 0x35, 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F,
9365 0x00, 0x00, 0xEA, 0x82,
9366 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE2, 0x02, 0x04, 0x01, 0xA2, 0xC8,
9367 0x00, 0x33, 0x1F, 0x00,
9368 0xC2, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39, 0x0E, 0x3D, 0x7E, 0x98,
9369 0xB6, 0x2D, 0x01, 0xA6,
9370 0x14, 0x03, 0x00, 0xA6, 0x14, 0x03, 0x07, 0xA6, 0x0C, 0x03, 0x06, 0xA6,
9371 0x10, 0x03, 0x03, 0xA6,
9372 0x20, 0x04, 0x02, 0xA6, 0x6C, 0x02, 0x00, 0x33, 0x33, 0x00, 0xC2, 0x88,
9373 0x7C, 0x95, 0xEE, 0x82,
9374 0x60, 0x96, 0xEE, 0x82, 0x82, 0x98, 0x80, 0x42, 0x7E, 0x98, 0x64, 0xE4,
9375 0x04, 0x01, 0x2D, 0xC8,
9376 0x31, 0x05, 0x07, 0x01, 0x00, 0xA2, 0x54, 0x03, 0x00, 0x43, 0x87, 0x01,
9377 0x05, 0x05, 0x86, 0x98,
9378 0x7E, 0x98, 0x00, 0xA6, 0x16, 0x03, 0x07, 0xA6, 0x4C, 0x03, 0x03, 0xA6,
9379 0x3C, 0x04, 0x06, 0xA6,
9380 0x50, 0x03, 0x01, 0xA6, 0x16, 0x03, 0x00, 0x33, 0x25, 0x00, 0xC2, 0x88,
9381 0x7C, 0x95, 0x32, 0x83,
9382 0x60, 0x96, 0x32, 0x83, 0x04, 0x01, 0x10, 0xCE, 0x07, 0xC8, 0x05, 0x05,
9383 0xEB, 0x04, 0x00, 0x33,
9384 0x00, 0x20, 0xC0, 0x20, 0x81, 0x62, 0x72, 0x83, 0x00, 0x01, 0x05, 0x05,
9385 0xFF, 0xA2, 0x7A, 0x03,
9386 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x2E, 0x83, 0x05, 0x05, 0x15, 0x01,
9387 0x00, 0xA2, 0x9A, 0x03,
9388 0xEC, 0x00, 0x6E, 0x00, 0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00,
9389 0x01, 0xA6, 0x96, 0x03,
9390 0x00, 0xA6, 0x96, 0x03, 0x10, 0x84, 0x80, 0x42, 0x7E, 0x98, 0x01, 0xA6,
9391 0xA4, 0x03, 0x00, 0xA6,
9392 0xBC, 0x03, 0x10, 0x84, 0xA8, 0x98, 0x80, 0x42, 0x01, 0xA6, 0xA4, 0x03,
9393 0x07, 0xA6, 0xB2, 0x03,
9394 0xD4, 0x83, 0x7C, 0x95, 0xA8, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xC2, 0x88,
9395 0xA8, 0x98, 0x80, 0x42,
9396 0x00, 0xA6, 0xBC, 0x03, 0x07, 0xA6, 0xCA, 0x03, 0xD4, 0x83, 0x7C, 0x95,
9397 0xC0, 0x83, 0x00, 0x33,
9398 0x26, 0x00, 0xC2, 0x88, 0x38, 0x2B, 0x80, 0x32, 0x80, 0x36, 0x04, 0x23,
9399 0xA0, 0x01, 0x12, 0x23,
9400 0xA1, 0x01, 0x10, 0x84, 0x07, 0xF0, 0x06, 0xA4, 0xF4, 0x03, 0x80, 0x6B,
9401 0x80, 0x67, 0x05, 0x23,
9402 0x83, 0x03, 0x80, 0x63, 0x03, 0xA6, 0x0E, 0x04, 0x07, 0xA6, 0x06, 0x04,
9403 0x06, 0xA6, 0x0A, 0x04,
9404 0x00, 0x33, 0x17, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0xF4, 0x83, 0x60, 0x96,
9405 0xF4, 0x83, 0x20, 0x84,
9406 0x07, 0xF0, 0x06, 0xA4, 0x20, 0x04, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23,
9407 0x83, 0x03, 0x80, 0x63,
9408 0xB6, 0x2D, 0x03, 0xA6, 0x3C, 0x04, 0x07, 0xA6, 0x34, 0x04, 0x06, 0xA6,
9409 0x38, 0x04, 0x00, 0x33,
9410 0x30, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x20, 0x84, 0x60, 0x96, 0x20, 0x84,
9411 0x1D, 0x01, 0x06, 0xCC,
9412 0x00, 0x33, 0x00, 0x84, 0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62,
9413 0xA2, 0x0D, 0x80, 0x63,
9414 0x07, 0xA6, 0x5A, 0x04, 0x00, 0x33, 0x18, 0x00, 0xC2, 0x88, 0x03, 0x03,
9415 0x80, 0x63, 0xA3, 0x01,
9416 0x07, 0xA4, 0x64, 0x04, 0x23, 0x01, 0x00, 0xA2, 0x86, 0x04, 0x0A, 0xA0,
9417 0x76, 0x04, 0xE0, 0x00,
9418 0x00, 0x33, 0x1D, 0x00, 0xC2, 0x88, 0x0B, 0xA0, 0x82, 0x04, 0xE0, 0x00,
9419 0x00, 0x33, 0x1E, 0x00,
9420 0xC2, 0x88, 0x42, 0x23, 0xF8, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xE6, 0x04,
9421 0x08, 0x23, 0x22, 0xA3,
9422 0xA2, 0x04, 0x28, 0x23, 0x22, 0xA3, 0xAE, 0x04, 0x02, 0x23, 0x22, 0xA3,
9423 0xC4, 0x04, 0x42, 0x23,
9424 0xF8, 0x88, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xAE, 0x04, 0x45, 0x23,
9425 0xF8, 0x88, 0x04, 0x98,
9426 0x00, 0xA2, 0xC0, 0x04, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20,
9427 0x81, 0x62, 0xE8, 0x81,
9428 0x47, 0x23, 0xF8, 0x88, 0x04, 0x01, 0x0B, 0xDE, 0x04, 0x98, 0xB4, 0x98,
9429 0x00, 0x33, 0x00, 0x81,
9430 0xC0, 0x20, 0x81, 0x62, 0x14, 0x01, 0x00, 0xA0, 0x00, 0x02, 0x43, 0x23,
9431 0xF8, 0x88, 0x04, 0x23,
9432 0xA0, 0x01, 0x44, 0x23, 0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3,
9433 0xF4, 0x04, 0x00, 0x33,
9434 0x27, 0x00, 0xC2, 0x88, 0x04, 0x01, 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01,
9435 0x04, 0x23, 0xA0, 0x01,
9436 0x04, 0x98, 0x26, 0x95, 0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00,
9437 0x00, 0xA3, 0x22, 0x05,
9438 0x00, 0x05, 0x76, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x1C, 0x05, 0x0A, 0x85,
9439 0x46, 0x97, 0xCD, 0x04,
9440 0x24, 0x85, 0x48, 0x04, 0x84, 0x80, 0x02, 0x01, 0x03, 0xDA, 0x80, 0x23,
9441 0x82, 0x01, 0x34, 0x85,
9442 0x02, 0x23, 0xA0, 0x01, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x40, 0x05,
9443 0x1D, 0x01, 0x04, 0xD6,
9444 0xFF, 0x23, 0x86, 0x41, 0x4B, 0x60, 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01,
9445 0x49, 0x00, 0x81, 0x01,
9446 0x04, 0x01, 0x02, 0xC8, 0x30, 0x01, 0x80, 0x01, 0xF7, 0x04, 0x03, 0x01,
9447 0x49, 0x04, 0x80, 0x01,
9448 0xC9, 0x00, 0x00, 0x05, 0x00, 0x01, 0xFF, 0xA0, 0x60, 0x05, 0x77, 0x04,
9449 0x01, 0x23, 0xEA, 0x00,
9450 0x5D, 0x00, 0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63,
9451 0x07, 0xA4, 0xF8, 0x05,
9452 0x03, 0x03, 0x02, 0xA0, 0x8E, 0x05, 0xF4, 0x85, 0x00, 0x33, 0x2D, 0x00,
9453 0xC2, 0x88, 0x04, 0xA0,
9454 0xB8, 0x05, 0x80, 0x63, 0x00, 0x23, 0xDF, 0x00, 0x4A, 0x00, 0x06, 0x61,
9455 0x00, 0xA2, 0xA4, 0x05,
9456 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, 0x02, 0x41, 0x82, 0x01, 0x50, 0x00,
9457 0x62, 0x97, 0x04, 0x85,
9458 0x04, 0x23, 0x02, 0x41, 0x82, 0x01, 0x04, 0x85, 0x08, 0xA0, 0xBE, 0x05,
9459 0xF4, 0x85, 0x03, 0xA0,
9460 0xC4, 0x05, 0xF4, 0x85, 0x01, 0xA0, 0xCE, 0x05, 0x88, 0x00, 0x80, 0x63,
9461 0xCC, 0x86, 0x07, 0xA0,
9462 0xEE, 0x05, 0x5F, 0x00, 0x00, 0x2B, 0xDF, 0x08, 0x00, 0xA2, 0xE6, 0x05,
9463 0x80, 0x67, 0x80, 0x63,
9464 0x01, 0xA2, 0x7A, 0x06, 0x7C, 0x85, 0x06, 0x23, 0x68, 0x98, 0x48, 0x23,
9465 0xF8, 0x88, 0x07, 0x23,
9466 0x80, 0x00, 0x06, 0x87, 0x80, 0x63, 0x7C, 0x85, 0x00, 0x23, 0xDF, 0x00,
9467 0x00, 0x63, 0x4A, 0x00,
9468 0x06, 0x61, 0x00, 0xA2, 0x36, 0x06, 0x1D, 0x01, 0x16, 0xD4, 0xC0, 0x23,
9469 0x07, 0x41, 0x83, 0x03,
9470 0x80, 0x63, 0x06, 0xA6, 0x1C, 0x06, 0x00, 0x33, 0x37, 0x00, 0xC2, 0x88,
9471 0x1D, 0x01, 0x01, 0xD6,
9472 0x20, 0x23, 0x63, 0x60, 0x83, 0x03, 0x80, 0x63, 0x02, 0x23, 0xDF, 0x00,
9473 0x07, 0xA6, 0x7C, 0x05,
9474 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00,
9475 0x52, 0x00, 0x06, 0x61,
9476 0x00, 0xA2, 0x4E, 0x06, 0x1D, 0x01, 0x03, 0xCA, 0xC0, 0x23, 0x07, 0x41,
9477 0x00, 0x63, 0x1D, 0x01,
9478 0x04, 0xCC, 0x00, 0x33, 0x00, 0x83, 0xC0, 0x20, 0x81, 0x62, 0x80, 0x23,
9479 0x07, 0x41, 0x00, 0x63,
9480 0x80, 0x67, 0x08, 0x23, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x01, 0x23,
9481 0xDF, 0x00, 0x06, 0xA6,
9482 0x84, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67, 0x80, 0x63, 0x00, 0x33,
9483 0x00, 0x40, 0xC0, 0x20,
9484 0x81, 0x62, 0x00, 0x63, 0x00, 0x00, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63,
9485 0x06, 0xA6, 0x94, 0x06,
9486 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x00, 0x01, 0xA0, 0x14, 0x07, 0x00, 0x2B,
9487 0x40, 0x0E, 0x80, 0x63,
9488 0x01, 0x00, 0x06, 0xA6, 0xAA, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x40, 0x0E,
9489 0x80, 0x63, 0x00, 0x43,
9490 0x00, 0xA0, 0xA2, 0x06, 0x06, 0xA6, 0xBC, 0x06, 0x07, 0xA6, 0x7C, 0x05,
9491 0x80, 0x67, 0x40, 0x0E,
9492 0x80, 0x63, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63,
9493 0x07, 0xA6, 0xD6, 0x06,
9494 0x00, 0x33, 0x2A, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x80, 0x63, 0x89, 0x00,
9495 0x0A, 0x2B, 0x07, 0xA6,
9496 0xE8, 0x06, 0x00, 0x33, 0x29, 0x00, 0xC2, 0x88, 0x00, 0x43, 0x00, 0xA2,
9497 0xF4, 0x06, 0xC0, 0x0E,
9498 0x80, 0x63, 0xDE, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, 0xC0, 0x20,
9499 0x81, 0x62, 0x04, 0x01,
9500 0x02, 0xDA, 0x80, 0x63, 0x7C, 0x85, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6,
9501 0x8C, 0x06, 0x00, 0x33,
9502 0x2C, 0x00, 0xC2, 0x88, 0x0C, 0xA2, 0x2E, 0x07, 0xFE, 0x95, 0x83, 0x03,
9503 0x80, 0x63, 0x06, 0xA6,
9504 0x2C, 0x07, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x33, 0x3D, 0x00, 0xC2, 0x88,
9505 0x00, 0x00, 0x80, 0x67,
9506 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x44, 0x07, 0x07, 0xA6, 0x7C, 0x05,
9507 0xBF, 0x23, 0x04, 0x61,
9508 0x84, 0x01, 0xE6, 0x84, 0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00,
9509 0x00, 0x01, 0xF2, 0x00,
9510 0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81, 0x01, 0x70, 0x04,
9511 0x80, 0x05, 0x81, 0x05,
9512 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x01, 0x01, 0xF1, 0x00,
9513 0x70, 0x00, 0x81, 0x01,
9514 0x70, 0x04, 0x71, 0x00, 0x81, 0x01, 0x72, 0x00, 0x80, 0x01, 0x71, 0x04,
9515 0x70, 0x00, 0x80, 0x01,
9516 0x70, 0x04, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01,
9517 0xF1, 0x00, 0x70, 0x00,
9518 0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01, 0x72, 0x00, 0x81, 0x01,
9519 0x71, 0x04, 0x70, 0x00,
9520 0x81, 0x01, 0x70, 0x04, 0x00, 0x63, 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05,
9521 0xA3, 0x01, 0xA2, 0x01,
9522 0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1,
9523 0xC4, 0x07, 0x00, 0x33,
9524 0x07, 0x00, 0xC2, 0x88, 0x80, 0x05, 0x81, 0x05, 0x04, 0x01, 0x11, 0xC8,
9525 0x48, 0x00, 0xB0, 0x01,
9526 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x05, 0x01, 0x48, 0x04, 0x00, 0x43,
9527 0x00, 0xA2, 0xE4, 0x07,
9528 0x00, 0x05, 0xDA, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01,
9529 0x05, 0x05, 0x00, 0x63,
9530 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x80, 0x43,
9531 0x76, 0x08, 0x80, 0x02,
9532 0x77, 0x04, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04,
9533 0x00, 0x02, 0x00, 0xA0,
9534 0x14, 0x08, 0x16, 0x88, 0x00, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04,
9535 0x00, 0x63, 0xF3, 0x04,
9536 0x00, 0x23, 0xF4, 0x00, 0x74, 0x00, 0x80, 0x43, 0xF4, 0x00, 0xCF, 0x40,
9537 0x00, 0xA2, 0x44, 0x08,
9538 0x74, 0x04, 0x02, 0x01, 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1,
9539 0x24, 0x08, 0x04, 0x98,
9540 0x26, 0x95, 0x24, 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04,
9541 0x5A, 0x88, 0x02, 0x01,
9542 0x04, 0xD8, 0x46, 0x97, 0x04, 0x98, 0x26, 0x95, 0x4A, 0x88, 0x75, 0x00,
9543 0x00, 0xA3, 0x64, 0x08,
9544 0x00, 0x05, 0x4E, 0x88, 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63,
9545 0x06, 0xA6, 0x76, 0x08,
9546 0x00, 0x33, 0x3E, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63,
9547 0x00, 0x63, 0x38, 0x2B,
9548 0x9C, 0x88, 0x38, 0x2B, 0x92, 0x88, 0x32, 0x09, 0x31, 0x05, 0x92, 0x98,
9549 0x05, 0x05, 0xB2, 0x09,
9550 0x00, 0x63, 0x00, 0x32, 0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63,
9551 0x80, 0x32, 0x80, 0x36,
9552 0x80, 0x3A, 0x80, 0x3E, 0xB4, 0x3D, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32,
9553 0x40, 0x36, 0x40, 0x3A,
9554 0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40, 0x00, 0xA0, 0xB4, 0x08,
9555 0x5D, 0x00, 0xFE, 0xC3,
9556 0x00, 0x63, 0x80, 0x73, 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73,
9557 0xFF, 0xFD, 0x80, 0x73,
9558 0x13, 0x23, 0xF8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01,
9559 0xA1, 0x23, 0xA1, 0x01,
9560 0x81, 0x62, 0xE2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x68, 0x00, 0x00, 0xA2,
9561 0x80, 0x00, 0x03, 0xC2,
9562 0xF1, 0xC7, 0x41, 0x23, 0xF8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23,
9563 0xA0, 0x01, 0xE6, 0x84,
Linus Torvalds1da177e2005-04-16 15:20:36 -07009564};
9565
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009566static ushort _asc_mcode_size = sizeof(_asc_mcode_buf);
9567static ADV_DCNT _asc_mcode_chksum = 0x012C453FUL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009568
9569#define ASC_SYN_OFFSET_ONE_DISABLE_LIST 16
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009570static uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] = {
9571 INQUIRY,
9572 REQUEST_SENSE,
9573 READ_CAPACITY,
9574 READ_TOC,
9575 MODE_SELECT,
9576 MODE_SENSE,
9577 MODE_SELECT_10,
9578 MODE_SENSE_10,
9579 0xFF,
9580 0xFF,
9581 0xFF,
9582 0xFF,
9583 0xFF,
9584 0xFF,
9585 0xFF,
9586 0xFF
Linus Torvalds1da177e2005-04-16 15:20:36 -07009587};
9588
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009589static int AscExeScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009590{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009591 PortAddr iop_base;
9592 ulong last_int_level;
9593 int sta;
9594 int n_q_required;
9595 int disable_syn_offset_one_fix;
9596 int i;
9597 ASC_PADDR addr;
9598 ASC_EXE_CALLBACK asc_exe_callback;
9599 ushort sg_entry_cnt = 0;
9600 ushort sg_entry_cnt_minus_one = 0;
9601 uchar target_ix;
9602 uchar tid_no;
9603 uchar sdtr_data;
9604 uchar extra_bytes;
9605 uchar scsi_cmd;
9606 uchar disable_cmd;
9607 ASC_SG_HEAD *sg_head;
9608 ASC_DCNT data_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009609
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009610 iop_base = asc_dvc->iop_base;
9611 sg_head = scsiq->sg_head;
9612 asc_exe_callback = asc_dvc->exe_callback;
9613 if (asc_dvc->err_code != 0)
9614 return (ERR);
9615 if (scsiq == (ASC_SCSI_Q *)0L) {
9616 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SCSIQ_NULL_PTR);
9617 return (ERR);
9618 }
9619 scsiq->q1.q_no = 0;
9620 if ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0) {
9621 scsiq->q1.extra_bytes = 0;
9622 }
9623 sta = 0;
9624 target_ix = scsiq->q2.target_ix;
9625 tid_no = ASC_TIX_TO_TID(target_ix);
9626 n_q_required = 1;
9627 if (scsiq->cdbptr[0] == REQUEST_SENSE) {
9628 if ((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) {
9629 asc_dvc->sdtr_done &= ~scsiq->q1.target_id;
9630 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
9631 AscMsgOutSDTR(asc_dvc,
9632 asc_dvc->
9633 sdtr_period_tbl[(sdtr_data >> 4) &
9634 (uchar)(asc_dvc->
9635 max_sdtr_index -
9636 1)],
9637 (uchar)(sdtr_data & (uchar)
9638 ASC_SYN_MAX_OFFSET));
9639 scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT);
9640 }
9641 }
9642 last_int_level = DvcEnterCritical();
9643 if (asc_dvc->in_critical_cnt != 0) {
9644 DvcLeaveCritical(last_int_level);
9645 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CRITICAL_RE_ENTRY);
9646 return (ERR);
9647 }
9648 asc_dvc->in_critical_cnt++;
9649 if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
9650 if ((sg_entry_cnt = sg_head->entry_cnt) == 0) {
9651 asc_dvc->in_critical_cnt--;
9652 DvcLeaveCritical(last_int_level);
9653 return (ERR);
9654 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009655#if !CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009656 if (sg_entry_cnt > ASC_MAX_SG_LIST) {
9657 asc_dvc->in_critical_cnt--;
9658 DvcLeaveCritical(last_int_level);
9659 return (ERR);
9660 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009661#endif /* !CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009662 if (sg_entry_cnt == 1) {
9663 scsiq->q1.data_addr =
9664 (ADV_PADDR)sg_head->sg_list[0].addr;
9665 scsiq->q1.data_cnt =
9666 (ADV_DCNT)sg_head->sg_list[0].bytes;
9667 scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE);
9668 }
9669 sg_entry_cnt_minus_one = sg_entry_cnt - 1;
9670 }
9671 scsi_cmd = scsiq->cdbptr[0];
9672 disable_syn_offset_one_fix = FALSE;
9673 if ((asc_dvc->pci_fix_asyn_xfer & scsiq->q1.target_id) &&
9674 !(asc_dvc->pci_fix_asyn_xfer_always & scsiq->q1.target_id)) {
9675 if (scsiq->q1.cntl & QC_SG_HEAD) {
9676 data_cnt = 0;
9677 for (i = 0; i < sg_entry_cnt; i++) {
9678 data_cnt +=
9679 (ADV_DCNT)le32_to_cpu(sg_head->sg_list[i].
9680 bytes);
9681 }
9682 } else {
9683 data_cnt = le32_to_cpu(scsiq->q1.data_cnt);
9684 }
9685 if (data_cnt != 0UL) {
9686 if (data_cnt < 512UL) {
9687 disable_syn_offset_one_fix = TRUE;
9688 } else {
9689 for (i = 0; i < ASC_SYN_OFFSET_ONE_DISABLE_LIST;
9690 i++) {
9691 disable_cmd =
9692 _syn_offset_one_disable_cmd[i];
9693 if (disable_cmd == 0xFF) {
9694 break;
9695 }
9696 if (scsi_cmd == disable_cmd) {
9697 disable_syn_offset_one_fix =
9698 TRUE;
9699 break;
9700 }
9701 }
9702 }
9703 }
9704 }
9705 if (disable_syn_offset_one_fix) {
9706 scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
9707 scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX |
9708 ASC_TAG_FLAG_DISABLE_DISCONNECT);
9709 } else {
9710 scsiq->q2.tag_code &= 0x27;
9711 }
9712 if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
9713 if (asc_dvc->bug_fix_cntl) {
9714 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
9715 if ((scsi_cmd == READ_6) ||
9716 (scsi_cmd == READ_10)) {
9717 addr =
9718 (ADV_PADDR)le32_to_cpu(sg_head->
9719 sg_list
9720 [sg_entry_cnt_minus_one].
9721 addr) +
9722 (ADV_DCNT)le32_to_cpu(sg_head->
9723 sg_list
9724 [sg_entry_cnt_minus_one].
9725 bytes);
9726 extra_bytes =
9727 (uchar)((ushort)addr & 0x0003);
9728 if ((extra_bytes != 0)
9729 &&
9730 ((scsiq->q2.
9731 tag_code &
9732 ASC_TAG_FLAG_EXTRA_BYTES)
9733 == 0)) {
9734 scsiq->q2.tag_code |=
9735 ASC_TAG_FLAG_EXTRA_BYTES;
9736 scsiq->q1.extra_bytes =
9737 extra_bytes;
9738 data_cnt =
9739 le32_to_cpu(sg_head->
9740 sg_list
9741 [sg_entry_cnt_minus_one].
9742 bytes);
9743 data_cnt -=
9744 (ASC_DCNT) extra_bytes;
9745 sg_head->
9746 sg_list
9747 [sg_entry_cnt_minus_one].
9748 bytes =
9749 cpu_to_le32(data_cnt);
9750 }
9751 }
9752 }
9753 }
9754 sg_head->entry_to_copy = sg_head->entry_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009755#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009756 /*
9757 * Set the sg_entry_cnt to the maximum possible. The rest of
9758 * the SG elements will be copied when the RISC completes the
9759 * SG elements that fit and halts.
9760 */
9761 if (sg_entry_cnt > ASC_MAX_SG_LIST) {
9762 sg_entry_cnt = ASC_MAX_SG_LIST;
9763 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009764#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009765 n_q_required = AscSgListToQueue(sg_entry_cnt);
9766 if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >=
9767 (uint) n_q_required)
9768 || ((scsiq->q1.cntl & QC_URGENT) != 0)) {
9769 if ((sta =
9770 AscSendScsiQueue(asc_dvc, scsiq,
9771 n_q_required)) == 1) {
9772 asc_dvc->in_critical_cnt--;
9773 if (asc_exe_callback != 0) {
9774 (*asc_exe_callback) (asc_dvc, scsiq);
9775 }
9776 DvcLeaveCritical(last_int_level);
9777 return (sta);
9778 }
9779 }
9780 } else {
9781 if (asc_dvc->bug_fix_cntl) {
9782 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
9783 if ((scsi_cmd == READ_6) ||
9784 (scsi_cmd == READ_10)) {
9785 addr =
9786 le32_to_cpu(scsiq->q1.data_addr) +
9787 le32_to_cpu(scsiq->q1.data_cnt);
9788 extra_bytes =
9789 (uchar)((ushort)addr & 0x0003);
9790 if ((extra_bytes != 0)
9791 &&
9792 ((scsiq->q2.
9793 tag_code &
9794 ASC_TAG_FLAG_EXTRA_BYTES)
9795 == 0)) {
9796 data_cnt =
9797 le32_to_cpu(scsiq->q1.
9798 data_cnt);
9799 if (((ushort)data_cnt & 0x01FF)
9800 == 0) {
9801 scsiq->q2.tag_code |=
9802 ASC_TAG_FLAG_EXTRA_BYTES;
9803 data_cnt -= (ASC_DCNT)
9804 extra_bytes;
9805 scsiq->q1.data_cnt =
9806 cpu_to_le32
9807 (data_cnt);
9808 scsiq->q1.extra_bytes =
9809 extra_bytes;
9810 }
9811 }
9812 }
9813 }
9814 }
9815 n_q_required = 1;
9816 if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, 1) >= 1) ||
9817 ((scsiq->q1.cntl & QC_URGENT) != 0)) {
9818 if ((sta = AscSendScsiQueue(asc_dvc, scsiq,
9819 n_q_required)) == 1) {
9820 asc_dvc->in_critical_cnt--;
9821 if (asc_exe_callback != 0) {
9822 (*asc_exe_callback) (asc_dvc, scsiq);
9823 }
9824 DvcLeaveCritical(last_int_level);
9825 return (sta);
9826 }
9827 }
9828 }
9829 asc_dvc->in_critical_cnt--;
9830 DvcLeaveCritical(last_int_level);
9831 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009832}
9833
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009834static int
9835AscSendScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar n_q_required)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009836{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009837 PortAddr iop_base;
9838 uchar free_q_head;
9839 uchar next_qp;
9840 uchar tid_no;
9841 uchar target_ix;
9842 int sta;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009843
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009844 iop_base = asc_dvc->iop_base;
9845 target_ix = scsiq->q2.target_ix;
9846 tid_no = ASC_TIX_TO_TID(target_ix);
9847 sta = 0;
9848 free_q_head = (uchar)AscGetVarFreeQHead(iop_base);
9849 if (n_q_required > 1) {
9850 if ((next_qp = AscAllocMultipleFreeQueue(iop_base,
9851 free_q_head, (uchar)
9852 (n_q_required)))
9853 != (uchar)ASC_QLINK_END) {
9854 asc_dvc->last_q_shortage = 0;
9855 scsiq->sg_head->queue_cnt = n_q_required - 1;
9856 scsiq->q1.q_no = free_q_head;
9857 if ((sta = AscPutReadySgListQueue(asc_dvc, scsiq,
9858 free_q_head)) == 1) {
9859 AscPutVarFreeQHead(iop_base, next_qp);
9860 asc_dvc->cur_total_qng += (uchar)(n_q_required);
9861 asc_dvc->cur_dvc_qng[tid_no]++;
9862 }
9863 return (sta);
9864 }
9865 } else if (n_q_required == 1) {
9866 if ((next_qp = AscAllocFreeQueue(iop_base,
9867 free_q_head)) !=
9868 ASC_QLINK_END) {
9869 scsiq->q1.q_no = free_q_head;
9870 if ((sta = AscPutReadyQueue(asc_dvc, scsiq,
9871 free_q_head)) == 1) {
9872 AscPutVarFreeQHead(iop_base, next_qp);
9873 asc_dvc->cur_total_qng++;
9874 asc_dvc->cur_dvc_qng[tid_no]++;
9875 }
9876 return (sta);
9877 }
9878 }
9879 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009880}
9881
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009882static int AscSgListToQueue(int sg_list)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009883{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009884 int n_sg_list_qs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009885
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009886 n_sg_list_qs = ((sg_list - 1) / ASC_SG_LIST_PER_Q);
9887 if (((sg_list - 1) % ASC_SG_LIST_PER_Q) != 0)
9888 n_sg_list_qs++;
9889 return (n_sg_list_qs + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009890}
9891
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009892static uint
9893AscGetNumOfFreeQueue(ASC_DVC_VAR *asc_dvc, uchar target_ix, uchar n_qs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009894{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009895 uint cur_used_qs;
9896 uint cur_free_qs;
9897 ASC_SCSI_BIT_ID_TYPE target_id;
9898 uchar tid_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009899
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009900 target_id = ASC_TIX_TO_TARGET_ID(target_ix);
9901 tid_no = ASC_TIX_TO_TID(target_ix);
9902 if ((asc_dvc->unit_not_ready & target_id) ||
9903 (asc_dvc->queue_full_or_busy & target_id)) {
9904 return (0);
9905 }
9906 if (n_qs == 1) {
9907 cur_used_qs = (uint) asc_dvc->cur_total_qng +
9908 (uint) asc_dvc->last_q_shortage + (uint) ASC_MIN_FREE_Q;
9909 } else {
9910 cur_used_qs = (uint) asc_dvc->cur_total_qng +
9911 (uint) ASC_MIN_FREE_Q;
9912 }
9913 if ((uint) (cur_used_qs + n_qs) <= (uint) asc_dvc->max_total_qng) {
9914 cur_free_qs = (uint) asc_dvc->max_total_qng - cur_used_qs;
9915 if (asc_dvc->cur_dvc_qng[tid_no] >=
9916 asc_dvc->max_dvc_qng[tid_no]) {
9917 return (0);
9918 }
9919 return (cur_free_qs);
9920 }
9921 if (n_qs > 1) {
9922 if ((n_qs > asc_dvc->last_q_shortage)
9923 && (n_qs <= (asc_dvc->max_total_qng - ASC_MIN_FREE_Q))) {
9924 asc_dvc->last_q_shortage = n_qs;
9925 }
9926 }
9927 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009928}
9929
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009930static int AscPutReadyQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009931{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009932 ushort q_addr;
9933 uchar tid_no;
9934 uchar sdtr_data;
9935 uchar syn_period_ix;
9936 uchar syn_offset;
9937 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009938
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009939 iop_base = asc_dvc->iop_base;
9940 if (((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) &&
9941 ((asc_dvc->sdtr_done & scsiq->q1.target_id) == 0)) {
9942 tid_no = ASC_TIX_TO_TID(scsiq->q2.target_ix);
9943 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
9944 syn_period_ix =
9945 (sdtr_data >> 4) & (asc_dvc->max_sdtr_index - 1);
9946 syn_offset = sdtr_data & ASC_SYN_MAX_OFFSET;
9947 AscMsgOutSDTR(asc_dvc,
9948 asc_dvc->sdtr_period_tbl[syn_period_ix],
9949 syn_offset);
9950 scsiq->q1.cntl |= QC_MSG_OUT;
9951 }
9952 q_addr = ASC_QNO_TO_QADDR(q_no);
9953 if ((scsiq->q1.target_id & asc_dvc->use_tagged_qng) == 0) {
9954 scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
9955 }
9956 scsiq->q1.status = QS_FREE;
9957 AscMemWordCopyPtrToLram(iop_base,
9958 q_addr + ASC_SCSIQ_CDB_BEG,
9959 (uchar *)scsiq->cdbptr, scsiq->q2.cdb_len >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009960
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009961 DvcPutScsiQ(iop_base,
9962 q_addr + ASC_SCSIQ_CPY_BEG,
9963 (uchar *)&scsiq->q1.cntl,
9964 ((sizeof(ASC_SCSIQ_1) + sizeof(ASC_SCSIQ_2)) / 2) - 1);
9965 AscWriteLramWord(iop_base,
9966 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS),
9967 (ushort)(((ushort)scsiq->q1.
9968 q_no << 8) | (ushort)QS_READY));
9969 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009970}
9971
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009972static int
9973AscPutReadySgListQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009974{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009975 int sta;
9976 int i;
9977 ASC_SG_HEAD *sg_head;
9978 ASC_SG_LIST_Q scsi_sg_q;
9979 ASC_DCNT saved_data_addr;
9980 ASC_DCNT saved_data_cnt;
9981 PortAddr iop_base;
9982 ushort sg_list_dwords;
9983 ushort sg_index;
9984 ushort sg_entry_cnt;
9985 ushort q_addr;
9986 uchar next_qp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009987
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009988 iop_base = asc_dvc->iop_base;
9989 sg_head = scsiq->sg_head;
9990 saved_data_addr = scsiq->q1.data_addr;
9991 saved_data_cnt = scsiq->q1.data_cnt;
9992 scsiq->q1.data_addr = (ASC_PADDR) sg_head->sg_list[0].addr;
9993 scsiq->q1.data_cnt = (ASC_DCNT) sg_head->sg_list[0].bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009994#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009995 /*
9996 * If sg_head->entry_cnt is greater than ASC_MAX_SG_LIST
9997 * then not all SG elements will fit in the allocated queues.
9998 * The rest of the SG elements will be copied when the RISC
9999 * completes the SG elements that fit and halts.
10000 */
10001 if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
10002 /*
10003 * Set sg_entry_cnt to be the number of SG elements that
10004 * will fit in the allocated SG queues. It is minus 1, because
10005 * the first SG element is handled above. ASC_MAX_SG_LIST is
10006 * already inflated by 1 to account for this. For example it
10007 * may be 50 which is 1 + 7 queues * 7 SG elements.
10008 */
10009 sg_entry_cnt = ASC_MAX_SG_LIST - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010010
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010011 /*
10012 * Keep track of remaining number of SG elements that will
10013 * need to be handled from a_isr.c.
10014 */
10015 scsiq->remain_sg_entry_cnt =
10016 sg_head->entry_cnt - ASC_MAX_SG_LIST;
10017 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -070010018#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010019 /*
10020 * Set sg_entry_cnt to be the number of SG elements that
10021 * will fit in the allocated SG queues. It is minus 1, because
10022 * the first SG element is handled above.
10023 */
10024 sg_entry_cnt = sg_head->entry_cnt - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010025#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010026 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010027#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010028 if (sg_entry_cnt != 0) {
10029 scsiq->q1.cntl |= QC_SG_HEAD;
10030 q_addr = ASC_QNO_TO_QADDR(q_no);
10031 sg_index = 1;
10032 scsiq->q1.sg_queue_cnt = sg_head->queue_cnt;
10033 scsi_sg_q.sg_head_qp = q_no;
10034 scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
10035 for (i = 0; i < sg_head->queue_cnt; i++) {
10036 scsi_sg_q.seq_no = i + 1;
10037 if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
10038 sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
10039 sg_entry_cnt -= ASC_SG_LIST_PER_Q;
10040 if (i == 0) {
10041 scsi_sg_q.sg_list_cnt =
10042 ASC_SG_LIST_PER_Q;
10043 scsi_sg_q.sg_cur_list_cnt =
10044 ASC_SG_LIST_PER_Q;
10045 } else {
10046 scsi_sg_q.sg_list_cnt =
10047 ASC_SG_LIST_PER_Q - 1;
10048 scsi_sg_q.sg_cur_list_cnt =
10049 ASC_SG_LIST_PER_Q - 1;
10050 }
10051 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -070010052#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010053 /*
10054 * This is the last SG queue in the list of
10055 * allocated SG queues. If there are more
10056 * SG elements than will fit in the allocated
10057 * queues, then set the QCSG_SG_XFER_MORE flag.
10058 */
10059 if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
10060 scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
10061 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -070010062#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010063 scsi_sg_q.cntl |= QCSG_SG_XFER_END;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010064#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010065 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010066#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010067 sg_list_dwords = sg_entry_cnt << 1;
10068 if (i == 0) {
10069 scsi_sg_q.sg_list_cnt = sg_entry_cnt;
10070 scsi_sg_q.sg_cur_list_cnt =
10071 sg_entry_cnt;
10072 } else {
10073 scsi_sg_q.sg_list_cnt =
10074 sg_entry_cnt - 1;
10075 scsi_sg_q.sg_cur_list_cnt =
10076 sg_entry_cnt - 1;
10077 }
10078 sg_entry_cnt = 0;
10079 }
10080 next_qp = AscReadLramByte(iop_base,
10081 (ushort)(q_addr +
10082 ASC_SCSIQ_B_FWD));
10083 scsi_sg_q.q_no = next_qp;
10084 q_addr = ASC_QNO_TO_QADDR(next_qp);
10085 AscMemWordCopyPtrToLram(iop_base,
10086 q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
10087 (uchar *)&scsi_sg_q,
10088 sizeof(ASC_SG_LIST_Q) >> 1);
10089 AscMemDWordCopyPtrToLram(iop_base,
10090 q_addr + ASC_SGQ_LIST_BEG,
10091 (uchar *)&sg_head->
10092 sg_list[sg_index],
10093 sg_list_dwords);
10094 sg_index += ASC_SG_LIST_PER_Q;
10095 scsiq->next_sg_index = sg_index;
10096 }
10097 } else {
10098 scsiq->q1.cntl &= ~QC_SG_HEAD;
10099 }
10100 sta = AscPutReadyQueue(asc_dvc, scsiq, q_no);
10101 scsiq->q1.data_addr = saved_data_addr;
10102 scsiq->q1.data_cnt = saved_data_cnt;
10103 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010104}
10105
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010106static int
10107AscSetRunChipSynRegAtID(PortAddr iop_base, uchar tid_no, uchar sdtr_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010108{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010109 int sta = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010110
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010111 if (AscHostReqRiscHalt(iop_base)) {
10112 sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
10113 AscStartChip(iop_base);
10114 return (sta);
10115 }
10116 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010117}
10118
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010119static int AscSetChipSynRegAtID(PortAddr iop_base, uchar id, uchar sdtr_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010120{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010121 ASC_SCSI_BIT_ID_TYPE org_id;
10122 int i;
10123 int sta = TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010124
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010125 AscSetBank(iop_base, 1);
10126 org_id = AscReadChipDvcID(iop_base);
10127 for (i = 0; i <= ASC_MAX_TID; i++) {
10128 if (org_id == (0x01 << i))
10129 break;
10130 }
10131 org_id = (ASC_SCSI_BIT_ID_TYPE) i;
10132 AscWriteChipDvcID(iop_base, id);
10133 if (AscReadChipDvcID(iop_base) == (0x01 << id)) {
10134 AscSetBank(iop_base, 0);
10135 AscSetChipSyn(iop_base, sdtr_data);
10136 if (AscGetChipSyn(iop_base) != sdtr_data) {
10137 sta = FALSE;
10138 }
10139 } else {
10140 sta = FALSE;
10141 }
10142 AscSetBank(iop_base, 1);
10143 AscWriteChipDvcID(iop_base, org_id);
10144 AscSetBank(iop_base, 0);
10145 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010146}
10147
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010148static ushort AscInitLram(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010149{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010150 uchar i;
10151 ushort s_addr;
10152 PortAddr iop_base;
10153 ushort warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010154
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010155 iop_base = asc_dvc->iop_base;
10156 warn_code = 0;
10157 AscMemWordSetLram(iop_base, ASC_QADR_BEG, 0,
10158 (ushort)(((int)(asc_dvc->max_total_qng + 2 + 1) *
10159 64) >> 1)
10160 );
10161 i = ASC_MIN_ACTIVE_QNO;
10162 s_addr = ASC_QADR_BEG + ASC_QBLK_SIZE;
10163 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
10164 (uchar)(i + 1));
10165 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
10166 (uchar)(asc_dvc->max_total_qng));
10167 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
10168 (uchar)i);
10169 i++;
10170 s_addr += ASC_QBLK_SIZE;
10171 for (; i < asc_dvc->max_total_qng; i++, s_addr += ASC_QBLK_SIZE) {
10172 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
10173 (uchar)(i + 1));
10174 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
10175 (uchar)(i - 1));
10176 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
10177 (uchar)i);
10178 }
10179 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
10180 (uchar)ASC_QLINK_END);
10181 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
10182 (uchar)(asc_dvc->max_total_qng - 1));
10183 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
10184 (uchar)asc_dvc->max_total_qng);
10185 i++;
10186 s_addr += ASC_QBLK_SIZE;
10187 for (; i <= (uchar)(asc_dvc->max_total_qng + 3);
10188 i++, s_addr += ASC_QBLK_SIZE) {
10189 AscWriteLramByte(iop_base,
10190 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_FWD), i);
10191 AscWriteLramByte(iop_base,
10192 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_BWD), i);
10193 AscWriteLramByte(iop_base,
10194 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_QNO), i);
10195 }
10196 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010197}
10198
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010199static ushort AscInitQLinkVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010200{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010201 PortAddr iop_base;
10202 int i;
10203 ushort lram_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010204
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010205 iop_base = asc_dvc->iop_base;
10206 AscPutRiscVarFreeQHead(iop_base, 1);
10207 AscPutRiscVarDoneQTail(iop_base, asc_dvc->max_total_qng);
10208 AscPutVarFreeQHead(iop_base, 1);
10209 AscPutVarDoneQTail(iop_base, asc_dvc->max_total_qng);
10210 AscWriteLramByte(iop_base, ASCV_BUSY_QHEAD_B,
10211 (uchar)((int)asc_dvc->max_total_qng + 1));
10212 AscWriteLramByte(iop_base, ASCV_DISC1_QHEAD_B,
10213 (uchar)((int)asc_dvc->max_total_qng + 2));
10214 AscWriteLramByte(iop_base, (ushort)ASCV_TOTAL_READY_Q_B,
10215 asc_dvc->max_total_qng);
10216 AscWriteLramWord(iop_base, ASCV_ASCDVC_ERR_CODE_W, 0);
10217 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
10218 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0);
10219 AscWriteLramByte(iop_base, ASCV_SCSIBUSY_B, 0);
10220 AscWriteLramByte(iop_base, ASCV_WTM_FLAG_B, 0);
10221 AscPutQDoneInProgress(iop_base, 0);
10222 lram_addr = ASC_QADR_BEG;
10223 for (i = 0; i < 32; i++, lram_addr += 2) {
10224 AscWriteLramWord(iop_base, lram_addr, 0);
10225 }
10226 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010227}
10228
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010229static int AscSetLibErrorCode(ASC_DVC_VAR *asc_dvc, ushort err_code)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010230{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010231 if (asc_dvc->err_code == 0) {
10232 asc_dvc->err_code = err_code;
10233 AscWriteLramWord(asc_dvc->iop_base, ASCV_ASCDVC_ERR_CODE_W,
10234 err_code);
10235 }
10236 return (err_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010237}
10238
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010239static uchar
10240AscMsgOutSDTR(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar sdtr_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010241{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010242 EXT_MSG sdtr_buf;
10243 uchar sdtr_period_index;
10244 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010245
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010246 iop_base = asc_dvc->iop_base;
10247 sdtr_buf.msg_type = MS_EXTEND;
10248 sdtr_buf.msg_len = MS_SDTR_LEN;
10249 sdtr_buf.msg_req = MS_SDTR_CODE;
10250 sdtr_buf.xfer_period = sdtr_period;
10251 sdtr_offset &= ASC_SYN_MAX_OFFSET;
10252 sdtr_buf.req_ack_offset = sdtr_offset;
10253 if ((sdtr_period_index =
10254 AscGetSynPeriodIndex(asc_dvc, sdtr_period)) <=
10255 asc_dvc->max_sdtr_index) {
10256 AscMemWordCopyPtrToLram(iop_base,
10257 ASCV_MSGOUT_BEG,
10258 (uchar *)&sdtr_buf,
10259 sizeof(EXT_MSG) >> 1);
10260 return ((sdtr_period_index << 4) | sdtr_offset);
10261 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -070010262
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010263 sdtr_buf.req_ack_offset = 0;
10264 AscMemWordCopyPtrToLram(iop_base,
10265 ASCV_MSGOUT_BEG,
10266 (uchar *)&sdtr_buf,
10267 sizeof(EXT_MSG) >> 1);
10268 return (0);
10269 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010270}
10271
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010272static uchar
10273AscCalSDTRData(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar syn_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010274{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010275 uchar byte;
10276 uchar sdtr_period_ix;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010277
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010278 sdtr_period_ix = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
10279 if ((sdtr_period_ix > asc_dvc->max_sdtr_index)
10280 ) {
10281 return (0xFF);
10282 }
10283 byte = (sdtr_period_ix << 4) | (syn_offset & ASC_SYN_MAX_OFFSET);
10284 return (byte);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010285}
10286
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010287static void AscSetChipSDTR(PortAddr iop_base, uchar sdtr_data, uchar tid_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010288{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010289 AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
10290 AscPutMCodeSDTRDoneAtID(iop_base, tid_no, sdtr_data);
10291 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010292}
10293
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010294static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *asc_dvc, uchar syn_time)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010295{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010296 uchar *period_table;
10297 int max_index;
10298 int min_index;
10299 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010300
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010301 period_table = asc_dvc->sdtr_period_tbl;
10302 max_index = (int)asc_dvc->max_sdtr_index;
10303 min_index = (int)asc_dvc->host_init_sdtr_index;
10304 if ((syn_time <= period_table[max_index])) {
10305 for (i = min_index; i < (max_index - 1); i++) {
10306 if (syn_time <= period_table[i]) {
10307 return ((uchar)i);
10308 }
10309 }
10310 return ((uchar)max_index);
10311 } else {
10312 return ((uchar)(max_index + 1));
10313 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010314}
10315
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010316static uchar AscAllocFreeQueue(PortAddr iop_base, uchar free_q_head)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010317{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010318 ushort q_addr;
10319 uchar next_qp;
10320 uchar q_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010321
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010322 q_addr = ASC_QNO_TO_QADDR(free_q_head);
10323 q_status = (uchar)AscReadLramByte(iop_base,
10324 (ushort)(q_addr +
10325 ASC_SCSIQ_B_STATUS));
10326 next_qp = AscReadLramByte(iop_base, (ushort)(q_addr + ASC_SCSIQ_B_FWD));
10327 if (((q_status & QS_READY) == 0) && (next_qp != ASC_QLINK_END)) {
10328 return (next_qp);
10329 }
10330 return (ASC_QLINK_END);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010331}
10332
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010333static uchar
10334AscAllocMultipleFreeQueue(PortAddr iop_base, uchar free_q_head, uchar n_free_q)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010335{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010336 uchar i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010337
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010338 for (i = 0; i < n_free_q; i++) {
10339 if ((free_q_head = AscAllocFreeQueue(iop_base, free_q_head))
10340 == ASC_QLINK_END) {
10341 return (ASC_QLINK_END);
10342 }
10343 }
10344 return (free_q_head);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010345}
10346
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010347static int AscHostReqRiscHalt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010348{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010349 int count = 0;
10350 int sta = 0;
10351 uchar saved_stop_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010352
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010353 if (AscIsChipHalted(iop_base))
10354 return (1);
10355 saved_stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
10356 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
10357 ASC_STOP_HOST_REQ_RISC_HALT | ASC_STOP_REQ_RISC_STOP);
10358 do {
10359 if (AscIsChipHalted(iop_base)) {
10360 sta = 1;
10361 break;
10362 }
10363 DvcSleepMilliSecond(100);
10364 } while (count++ < 20);
10365 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, saved_stop_code);
10366 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010367}
10368
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010369static int AscStopQueueExe(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010370{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010371 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010372
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010373 if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) {
10374 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
10375 ASC_STOP_REQ_RISC_STOP);
10376 do {
10377 if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) &
10378 ASC_STOP_ACK_RISC_STOP) {
10379 return (1);
10380 }
10381 DvcSleepMilliSecond(100);
10382 } while (count++ < 20);
10383 }
10384 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010385}
10386
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010387static void DvcDelayMicroSecond(ADV_DVC_VAR *asc_dvc, ushort micro_sec)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010388{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010389 udelay(micro_sec);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010390}
10391
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010392static void DvcDelayNanoSecond(ASC_DVC_VAR *asc_dvc, ASC_DCNT nano_sec)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010393{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010394 udelay((nano_sec + 999) / 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010395}
10396
10397#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010398static ASC_DCNT __init AscGetEisaProductID(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010399{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010400 PortAddr eisa_iop;
10401 ushort product_id_high, product_id_low;
10402 ASC_DCNT product_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010403
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010404 eisa_iop = ASC_GET_EISA_SLOT(iop_base) | ASC_EISA_PID_IOP_MASK;
10405 product_id_low = inpw(eisa_iop);
10406 product_id_high = inpw(eisa_iop + 2);
10407 product_id = ((ASC_DCNT) product_id_high << 16) |
10408 (ASC_DCNT) product_id_low;
10409 return (product_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010410}
10411
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010412static PortAddr __init AscSearchIOPortAddrEISA(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010413{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010414 ASC_DCNT eisa_product_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010415
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010416 if (iop_base == 0) {
10417 iop_base = ASC_EISA_MIN_IOP_ADDR;
10418 } else {
10419 if (iop_base == ASC_EISA_MAX_IOP_ADDR)
10420 return (0);
10421 if ((iop_base & 0x0050) == 0x0050) {
10422 iop_base += ASC_EISA_BIG_IOP_GAP;
10423 } else {
10424 iop_base += ASC_EISA_SMALL_IOP_GAP;
10425 }
10426 }
10427 while (iop_base <= ASC_EISA_MAX_IOP_ADDR) {
10428 eisa_product_id = AscGetEisaProductID(iop_base);
10429 if ((eisa_product_id == ASC_EISA_ID_740) ||
10430 (eisa_product_id == ASC_EISA_ID_750)) {
10431 if (AscFindSignature(iop_base)) {
10432 inpw(iop_base + 4);
10433 return (iop_base);
10434 }
10435 }
10436 if (iop_base == ASC_EISA_MAX_IOP_ADDR)
10437 return (0);
10438 if ((iop_base & 0x0050) == 0x0050) {
10439 iop_base += ASC_EISA_BIG_IOP_GAP;
10440 } else {
10441 iop_base += ASC_EISA_SMALL_IOP_GAP;
10442 }
10443 }
10444 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010445}
10446#endif /* CONFIG_ISA */
10447
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010448static int AscStartChip(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010449{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010450 AscSetChipControl(iop_base, 0);
10451 if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
10452 return (0);
10453 }
10454 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010455}
10456
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010457static int AscStopChip(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010458{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010459 uchar cc_val;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010460
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010461 cc_val =
10462 AscGetChipControl(iop_base) &
10463 (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG));
10464 AscSetChipControl(iop_base, (uchar)(cc_val | CC_HALT));
10465 AscSetChipIH(iop_base, INS_HALT);
10466 AscSetChipIH(iop_base, INS_RFLAG_WTM);
10467 if ((AscGetChipStatus(iop_base) & CSW_HALTED) == 0) {
10468 return (0);
10469 }
10470 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010471}
10472
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010473static int AscIsChipHalted(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010474{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010475 if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
10476 if ((AscGetChipControl(iop_base) & CC_HALT) != 0) {
10477 return (1);
10478 }
10479 }
10480 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010481}
10482
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010483static void AscSetChipIH(PortAddr iop_base, ushort ins_code)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010484{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010485 AscSetBank(iop_base, 1);
10486 AscWriteChipIH(iop_base, ins_code);
10487 AscSetBank(iop_base, 0);
10488 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010489}
10490
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010491static void AscAckInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010492{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010493 uchar host_flag;
10494 uchar risc_flag;
10495 ushort loop;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010496
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010497 loop = 0;
10498 do {
10499 risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B);
10500 if (loop++ > 0x7FFF) {
10501 break;
10502 }
10503 } while ((risc_flag & ASC_RISC_FLAG_GEN_INT) != 0);
10504 host_flag =
10505 AscReadLramByte(iop_base,
10506 ASCV_HOST_FLAG_B) & (~ASC_HOST_FLAG_ACK_INT);
10507 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
10508 (uchar)(host_flag | ASC_HOST_FLAG_ACK_INT));
10509 AscSetChipStatus(iop_base, CIW_INT_ACK);
10510 loop = 0;
10511 while (AscGetChipStatus(iop_base) & CSW_INT_PENDING) {
10512 AscSetChipStatus(iop_base, CIW_INT_ACK);
10513 if (loop++ > 3) {
10514 break;
10515 }
10516 }
10517 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
10518 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010519}
10520
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010521static void AscDisableInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010522{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010523 ushort cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010524
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010525 cfg = AscGetChipCfgLsw(iop_base);
10526 AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON));
10527 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010528}
10529
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010530static void AscEnableInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010531{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010532 ushort cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010533
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010534 cfg = AscGetChipCfgLsw(iop_base);
10535 AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON);
10536 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010537}
10538
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010539static void AscSetBank(PortAddr iop_base, uchar bank)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010540{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010541 uchar val;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010542
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010543 val = AscGetChipControl(iop_base) &
10544 (~
10545 (CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET |
10546 CC_CHIP_RESET));
10547 if (bank == 1) {
10548 val |= CC_BANK_ONE;
10549 } else if (bank == 2) {
10550 val |= CC_DIAG | CC_BANK_ONE;
10551 } else {
10552 val &= ~CC_BANK_ONE;
10553 }
10554 AscSetChipControl(iop_base, val);
10555 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010556}
10557
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010558static int AscResetChipAndScsiBus(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010559{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010560 PortAddr iop_base;
10561 int i = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010562
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010563 iop_base = asc_dvc->iop_base;
10564 while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE)
10565 && (i-- > 0)) {
10566 DvcSleepMilliSecond(100);
10567 }
10568 AscStopChip(iop_base);
10569 AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT);
10570 DvcDelayNanoSecond(asc_dvc, 60000);
10571 AscSetChipIH(iop_base, INS_RFLAG_WTM);
10572 AscSetChipIH(iop_base, INS_HALT);
10573 AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT);
10574 AscSetChipControl(iop_base, CC_HALT);
10575 DvcSleepMilliSecond(200);
10576 AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
10577 AscSetChipStatus(iop_base, 0);
10578 return (AscIsChipHalted(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010579}
10580
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010581static ASC_DCNT __init AscGetMaxDmaCount(ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010582{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010583 if (bus_type & ASC_IS_ISA)
10584 return (ASC_MAX_ISA_DMA_COUNT);
10585 else if (bus_type & (ASC_IS_EISA | ASC_IS_VL))
10586 return (ASC_MAX_VL_DMA_COUNT);
10587 return (ASC_MAX_PCI_DMA_COUNT);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010588}
10589
10590#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010591static ushort __init AscGetIsaDmaChannel(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010592{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010593 ushort channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010594
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010595 channel = AscGetChipCfgLsw(iop_base) & 0x0003;
10596 if (channel == 0x03)
10597 return (0);
10598 else if (channel == 0x00)
10599 return (7);
10600 return (channel + 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010601}
10602
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010603static ushort __init AscSetIsaDmaChannel(PortAddr iop_base, ushort dma_channel)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010604{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010605 ushort cfg_lsw;
10606 uchar value;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010607
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010608 if ((dma_channel >= 5) && (dma_channel <= 7)) {
10609 if (dma_channel == 7)
10610 value = 0x00;
10611 else
10612 value = dma_channel - 4;
10613 cfg_lsw = AscGetChipCfgLsw(iop_base) & 0xFFFC;
10614 cfg_lsw |= value;
10615 AscSetChipCfgLsw(iop_base, cfg_lsw);
10616 return (AscGetIsaDmaChannel(iop_base));
10617 }
10618 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010619}
10620
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010621static uchar __init AscSetIsaDmaSpeed(PortAddr iop_base, uchar speed_value)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010622{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010623 speed_value &= 0x07;
10624 AscSetBank(iop_base, 1);
10625 AscWriteChipDmaSpeed(iop_base, speed_value);
10626 AscSetBank(iop_base, 0);
10627 return (AscGetIsaDmaSpeed(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010628}
10629
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010630static uchar __init AscGetIsaDmaSpeed(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010631{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010632 uchar speed_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010633
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010634 AscSetBank(iop_base, 1);
10635 speed_value = AscReadChipDmaSpeed(iop_base);
10636 speed_value &= 0x07;
10637 AscSetBank(iop_base, 0);
10638 return (speed_value);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010639}
10640#endif /* CONFIG_ISA */
10641
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010642static ushort __init
10643AscReadPCIConfigWord(ASC_DVC_VAR *asc_dvc, ushort pci_config_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010644{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010645 uchar lsb, msb;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010646
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010647 lsb = DvcReadPCIConfigByte(asc_dvc, pci_config_offset);
10648 msb = DvcReadPCIConfigByte(asc_dvc, pci_config_offset + 1);
10649 return ((ushort)((msb << 8) | lsb));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010650}
10651
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010652static ushort __init AscInitGetConfig(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010653{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010654 ushort warn_code;
10655 PortAddr iop_base;
10656 ushort PCIDeviceID;
10657 ushort PCIVendorID;
10658 uchar PCIRevisionID;
10659 uchar prevCmdRegBits;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010660
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010661 warn_code = 0;
10662 iop_base = asc_dvc->iop_base;
10663 asc_dvc->init_state = ASC_INIT_STATE_BEG_GET_CFG;
10664 if (asc_dvc->err_code != 0) {
10665 return (UW_ERR);
10666 }
10667 if (asc_dvc->bus_type == ASC_IS_PCI) {
10668 PCIVendorID = AscReadPCIConfigWord(asc_dvc,
10669 AscPCIConfigVendorIDRegister);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010670
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010671 PCIDeviceID = AscReadPCIConfigWord(asc_dvc,
10672 AscPCIConfigDeviceIDRegister);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010673
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010674 PCIRevisionID = DvcReadPCIConfigByte(asc_dvc,
10675 AscPCIConfigRevisionIDRegister);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010676
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010677 if (PCIVendorID != PCI_VENDOR_ID_ASP) {
10678 warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
10679 }
10680 prevCmdRegBits = DvcReadPCIConfigByte(asc_dvc,
10681 AscPCIConfigCommandRegister);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010682
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010683 if ((prevCmdRegBits & AscPCICmdRegBits_IOMemBusMaster) !=
10684 AscPCICmdRegBits_IOMemBusMaster) {
10685 DvcWritePCIConfigByte(asc_dvc,
10686 AscPCIConfigCommandRegister,
10687 (prevCmdRegBits |
10688 AscPCICmdRegBits_IOMemBusMaster));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010689
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010690 if ((DvcReadPCIConfigByte(asc_dvc,
10691 AscPCIConfigCommandRegister)
10692 & AscPCICmdRegBits_IOMemBusMaster)
10693 != AscPCICmdRegBits_IOMemBusMaster) {
10694 warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
10695 }
10696 }
10697 if ((PCIDeviceID == PCI_DEVICE_ID_ASP_1200A) ||
10698 (PCIDeviceID == PCI_DEVICE_ID_ASP_ABP940)) {
10699 DvcWritePCIConfigByte(asc_dvc,
10700 AscPCIConfigLatencyTimer, 0x00);
10701 if (DvcReadPCIConfigByte
10702 (asc_dvc, AscPCIConfigLatencyTimer)
10703 != 0x00) {
10704 warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
10705 }
10706 } else if (PCIDeviceID == PCI_DEVICE_ID_ASP_ABP940U) {
10707 if (DvcReadPCIConfigByte(asc_dvc,
10708 AscPCIConfigLatencyTimer) <
10709 0x20) {
10710 DvcWritePCIConfigByte(asc_dvc,
10711 AscPCIConfigLatencyTimer,
10712 0x20);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010713
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010714 if (DvcReadPCIConfigByte(asc_dvc,
10715 AscPCIConfigLatencyTimer)
10716 < 0x20) {
10717 warn_code |=
10718 ASC_WARN_SET_PCI_CONFIG_SPACE;
10719 }
10720 }
10721 }
10722 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010723
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010724 if (AscFindSignature(iop_base)) {
10725 warn_code |= AscInitAscDvcVar(asc_dvc);
10726 warn_code |= AscInitFromEEP(asc_dvc);
10727 asc_dvc->init_state |= ASC_INIT_STATE_END_GET_CFG;
10728 if (asc_dvc->scsi_reset_wait > ASC_MAX_SCSI_RESET_WAIT) {
10729 asc_dvc->scsi_reset_wait = ASC_MAX_SCSI_RESET_WAIT;
10730 }
10731 } else {
10732 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
10733 }
10734 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010735}
10736
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010737static ushort __init AscInitSetConfig(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010738{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010739 ushort warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010740
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010741 asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG;
10742 if (asc_dvc->err_code != 0)
10743 return (UW_ERR);
10744 if (AscFindSignature(asc_dvc->iop_base)) {
10745 warn_code |= AscInitFromAscDvcVar(asc_dvc);
10746 asc_dvc->init_state |= ASC_INIT_STATE_END_SET_CFG;
10747 } else {
10748 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
10749 }
10750 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010751}
10752
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010753static ushort __init AscInitFromAscDvcVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010754{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010755 PortAddr iop_base;
10756 ushort cfg_msw;
10757 ushort warn_code;
10758 ushort pci_device_id = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010759
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010760 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010761#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010762 if (asc_dvc->cfg->dev)
10763 pci_device_id = to_pci_dev(asc_dvc->cfg->dev)->device;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010764#endif
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010765 warn_code = 0;
10766 cfg_msw = AscGetChipCfgMsw(iop_base);
10767 if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
10768 cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
10769 warn_code |= ASC_WARN_CFG_MSW_RECOVER;
10770 AscSetChipCfgMsw(iop_base, cfg_msw);
10771 }
10772 if ((asc_dvc->cfg->cmd_qng_enabled & asc_dvc->cfg->disc_enable) !=
10773 asc_dvc->cfg->cmd_qng_enabled) {
10774 asc_dvc->cfg->disc_enable = asc_dvc->cfg->cmd_qng_enabled;
10775 warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
10776 }
10777 if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
10778 warn_code |= ASC_WARN_AUTO_CONFIG;
10779 }
10780 if ((asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL)) != 0) {
10781 if (AscSetChipIRQ(iop_base, asc_dvc->irq_no, asc_dvc->bus_type)
10782 != asc_dvc->irq_no) {
10783 asc_dvc->err_code |= ASC_IERR_SET_IRQ_NO;
10784 }
10785 }
10786 if (asc_dvc->bus_type & ASC_IS_PCI) {
10787 cfg_msw &= 0xFFC0;
10788 AscSetChipCfgMsw(iop_base, cfg_msw);
10789 if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) {
10790 } else {
10791 if ((pci_device_id == PCI_DEVICE_ID_ASP_1200A) ||
10792 (pci_device_id == PCI_DEVICE_ID_ASP_ABP940)) {
10793 asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB;
10794 asc_dvc->bug_fix_cntl |=
10795 ASC_BUG_FIX_ASYN_USE_SYN;
10796 }
10797 }
10798 } else if (asc_dvc->bus_type == ASC_IS_ISAPNP) {
10799 if (AscGetChipVersion(iop_base, asc_dvc->bus_type)
10800 == ASC_CHIP_VER_ASYN_BUG) {
10801 asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN;
10802 }
10803 }
10804 if (AscSetChipScsiID(iop_base, asc_dvc->cfg->chip_scsi_id) !=
10805 asc_dvc->cfg->chip_scsi_id) {
10806 asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID;
10807 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010808#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010809 if (asc_dvc->bus_type & ASC_IS_ISA) {
10810 AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel);
10811 AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed);
10812 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010813#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010814 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010815}
10816
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010817static ushort AscInitAsc1000Driver(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010818{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010819 ushort warn_code;
10820 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010821
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010822 iop_base = asc_dvc->iop_base;
10823 warn_code = 0;
10824 if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) &&
10825 !(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) {
10826 AscResetChipAndScsiBus(asc_dvc);
10827 DvcSleepMilliSecond((ASC_DCNT)
10828 ((ushort)asc_dvc->scsi_reset_wait * 1000));
10829 }
10830 asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC;
10831 if (asc_dvc->err_code != 0)
10832 return (UW_ERR);
10833 if (!AscFindSignature(asc_dvc->iop_base)) {
10834 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
10835 return (warn_code);
10836 }
10837 AscDisableInterrupt(iop_base);
10838 warn_code |= AscInitLram(asc_dvc);
10839 if (asc_dvc->err_code != 0)
10840 return (UW_ERR);
10841 ASC_DBG1(1, "AscInitAsc1000Driver: _asc_mcode_chksum 0x%lx\n",
10842 (ulong)_asc_mcode_chksum);
10843 if (AscLoadMicroCode(iop_base, 0, _asc_mcode_buf,
10844 _asc_mcode_size) != _asc_mcode_chksum) {
10845 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
10846 return (warn_code);
10847 }
10848 warn_code |= AscInitMicroCodeVar(asc_dvc);
10849 asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC;
10850 AscEnableInterrupt(iop_base);
10851 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010852}
10853
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010854static ushort __init AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010855{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010856 int i;
10857 PortAddr iop_base;
10858 ushort warn_code;
10859 uchar chip_version;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010860
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010861 iop_base = asc_dvc->iop_base;
10862 warn_code = 0;
10863 asc_dvc->err_code = 0;
10864 if ((asc_dvc->bus_type &
10865 (ASC_IS_ISA | ASC_IS_PCI | ASC_IS_EISA | ASC_IS_VL)) == 0) {
10866 asc_dvc->err_code |= ASC_IERR_NO_BUS_TYPE;
10867 }
10868 AscSetChipControl(iop_base, CC_HALT);
10869 AscSetChipStatus(iop_base, 0);
10870 asc_dvc->bug_fix_cntl = 0;
10871 asc_dvc->pci_fix_asyn_xfer = 0;
10872 asc_dvc->pci_fix_asyn_xfer_always = 0;
10873 /* asc_dvc->init_state initalized in AscInitGetConfig(). */
10874 asc_dvc->sdtr_done = 0;
10875 asc_dvc->cur_total_qng = 0;
10876 asc_dvc->is_in_int = 0;
10877 asc_dvc->in_critical_cnt = 0;
10878 asc_dvc->last_q_shortage = 0;
10879 asc_dvc->use_tagged_qng = 0;
10880 asc_dvc->no_scam = 0;
10881 asc_dvc->unit_not_ready = 0;
10882 asc_dvc->queue_full_or_busy = 0;
10883 asc_dvc->redo_scam = 0;
10884 asc_dvc->res2 = 0;
10885 asc_dvc->host_init_sdtr_index = 0;
10886 asc_dvc->cfg->can_tagged_qng = 0;
10887 asc_dvc->cfg->cmd_qng_enabled = 0;
10888 asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL;
10889 asc_dvc->init_sdtr = 0;
10890 asc_dvc->max_total_qng = ASC_DEF_MAX_TOTAL_QNG;
10891 asc_dvc->scsi_reset_wait = 3;
10892 asc_dvc->start_motor = ASC_SCSI_WIDTH_BIT_SET;
10893 asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type);
10894 asc_dvc->cfg->sdtr_enable = ASC_SCSI_WIDTH_BIT_SET;
10895 asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET;
10896 asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID;
10897 asc_dvc->cfg->lib_serial_no = ASC_LIB_SERIAL_NUMBER;
10898 asc_dvc->cfg->lib_version = (ASC_LIB_VERSION_MAJOR << 8) |
10899 ASC_LIB_VERSION_MINOR;
10900 chip_version = AscGetChipVersion(iop_base, asc_dvc->bus_type);
10901 asc_dvc->cfg->chip_version = chip_version;
10902 asc_dvc->sdtr_period_tbl[0] = SYN_XFER_NS_0;
10903 asc_dvc->sdtr_period_tbl[1] = SYN_XFER_NS_1;
10904 asc_dvc->sdtr_period_tbl[2] = SYN_XFER_NS_2;
10905 asc_dvc->sdtr_period_tbl[3] = SYN_XFER_NS_3;
10906 asc_dvc->sdtr_period_tbl[4] = SYN_XFER_NS_4;
10907 asc_dvc->sdtr_period_tbl[5] = SYN_XFER_NS_5;
10908 asc_dvc->sdtr_period_tbl[6] = SYN_XFER_NS_6;
10909 asc_dvc->sdtr_period_tbl[7] = SYN_XFER_NS_7;
10910 asc_dvc->max_sdtr_index = 7;
10911 if ((asc_dvc->bus_type & ASC_IS_PCI) &&
10912 (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3150)) {
10913 asc_dvc->bus_type = ASC_IS_PCI_ULTRA;
10914 asc_dvc->sdtr_period_tbl[0] = SYN_ULTRA_XFER_NS_0;
10915 asc_dvc->sdtr_period_tbl[1] = SYN_ULTRA_XFER_NS_1;
10916 asc_dvc->sdtr_period_tbl[2] = SYN_ULTRA_XFER_NS_2;
10917 asc_dvc->sdtr_period_tbl[3] = SYN_ULTRA_XFER_NS_3;
10918 asc_dvc->sdtr_period_tbl[4] = SYN_ULTRA_XFER_NS_4;
10919 asc_dvc->sdtr_period_tbl[5] = SYN_ULTRA_XFER_NS_5;
10920 asc_dvc->sdtr_period_tbl[6] = SYN_ULTRA_XFER_NS_6;
10921 asc_dvc->sdtr_period_tbl[7] = SYN_ULTRA_XFER_NS_7;
10922 asc_dvc->sdtr_period_tbl[8] = SYN_ULTRA_XFER_NS_8;
10923 asc_dvc->sdtr_period_tbl[9] = SYN_ULTRA_XFER_NS_9;
10924 asc_dvc->sdtr_period_tbl[10] = SYN_ULTRA_XFER_NS_10;
10925 asc_dvc->sdtr_period_tbl[11] = SYN_ULTRA_XFER_NS_11;
10926 asc_dvc->sdtr_period_tbl[12] = SYN_ULTRA_XFER_NS_12;
10927 asc_dvc->sdtr_period_tbl[13] = SYN_ULTRA_XFER_NS_13;
10928 asc_dvc->sdtr_period_tbl[14] = SYN_ULTRA_XFER_NS_14;
10929 asc_dvc->sdtr_period_tbl[15] = SYN_ULTRA_XFER_NS_15;
10930 asc_dvc->max_sdtr_index = 15;
10931 if (chip_version == ASC_CHIP_VER_PCI_ULTRA_3150) {
10932 AscSetExtraControl(iop_base,
10933 (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
10934 } else if (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3050) {
10935 AscSetExtraControl(iop_base,
10936 (SEC_ACTIVE_NEGATE |
10937 SEC_ENABLE_FILTER));
10938 }
10939 }
10940 if (asc_dvc->bus_type == ASC_IS_PCI) {
10941 AscSetExtraControl(iop_base,
10942 (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
10943 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010944
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010945 asc_dvc->cfg->isa_dma_speed = ASC_DEF_ISA_DMA_SPEED;
10946 if (AscGetChipBusType(iop_base) == ASC_IS_ISAPNP) {
10947 AscSetChipIFC(iop_base, IFC_INIT_DEFAULT);
10948 asc_dvc->bus_type = ASC_IS_ISAPNP;
10949 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010950#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010951 if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) {
10952 asc_dvc->cfg->isa_dma_channel =
10953 (uchar)AscGetIsaDmaChannel(iop_base);
10954 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010955#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010956 for (i = 0; i <= ASC_MAX_TID; i++) {
10957 asc_dvc->cur_dvc_qng[i] = 0;
10958 asc_dvc->max_dvc_qng[i] = ASC_MAX_SCSI1_QNG;
10959 asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q *)0L;
10960 asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q *)0L;
10961 asc_dvc->cfg->max_tag_qng[i] = ASC_MAX_INRAM_TAG_QNG;
10962 }
10963 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010964}
10965
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010966static ushort __init AscInitFromEEP(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010967{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010968 ASCEEP_CONFIG eep_config_buf;
10969 ASCEEP_CONFIG *eep_config;
10970 PortAddr iop_base;
10971 ushort chksum;
10972 ushort warn_code;
10973 ushort cfg_msw, cfg_lsw;
10974 int i;
10975 int write_eep = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010976
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010977 iop_base = asc_dvc->iop_base;
10978 warn_code = 0;
10979 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE);
10980 AscStopQueueExe(iop_base);
10981 if ((AscStopChip(iop_base) == FALSE) ||
10982 (AscGetChipScsiCtrl(iop_base) != 0)) {
10983 asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE;
10984 AscResetChipAndScsiBus(asc_dvc);
10985 DvcSleepMilliSecond((ASC_DCNT)
10986 ((ushort)asc_dvc->scsi_reset_wait * 1000));
10987 }
10988 if (AscIsChipHalted(iop_base) == FALSE) {
10989 asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
10990 return (warn_code);
10991 }
10992 AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
10993 if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
10994 asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
10995 return (warn_code);
10996 }
10997 eep_config = (ASCEEP_CONFIG *)&eep_config_buf;
10998 cfg_msw = AscGetChipCfgMsw(iop_base);
10999 cfg_lsw = AscGetChipCfgLsw(iop_base);
11000 if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
11001 cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
11002 warn_code |= ASC_WARN_CFG_MSW_RECOVER;
11003 AscSetChipCfgMsw(iop_base, cfg_msw);
11004 }
11005 chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type);
11006 ASC_DBG1(1, "AscInitFromEEP: chksum 0x%x\n", chksum);
11007 if (chksum == 0) {
11008 chksum = 0xaa55;
11009 }
11010 if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
11011 warn_code |= ASC_WARN_AUTO_CONFIG;
11012 if (asc_dvc->cfg->chip_version == 3) {
11013 if (eep_config->cfg_lsw != cfg_lsw) {
11014 warn_code |= ASC_WARN_EEPROM_RECOVER;
11015 eep_config->cfg_lsw =
11016 AscGetChipCfgLsw(iop_base);
11017 }
11018 if (eep_config->cfg_msw != cfg_msw) {
11019 warn_code |= ASC_WARN_EEPROM_RECOVER;
11020 eep_config->cfg_msw =
11021 AscGetChipCfgMsw(iop_base);
11022 }
11023 }
11024 }
11025 eep_config->cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
11026 eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON;
11027 ASC_DBG1(1, "AscInitFromEEP: eep_config->chksum 0x%x\n",
11028 eep_config->chksum);
11029 if (chksum != eep_config->chksum) {
11030 if (AscGetChipVersion(iop_base, asc_dvc->bus_type) ==
11031 ASC_CHIP_VER_PCI_ULTRA_3050) {
11032 ASC_DBG(1,
11033 "AscInitFromEEP: chksum error ignored; EEPROM-less board\n");
11034 eep_config->init_sdtr = 0xFF;
11035 eep_config->disc_enable = 0xFF;
11036 eep_config->start_motor = 0xFF;
11037 eep_config->use_cmd_qng = 0;
11038 eep_config->max_total_qng = 0xF0;
11039 eep_config->max_tag_qng = 0x20;
11040 eep_config->cntl = 0xBFFF;
11041 ASC_EEP_SET_CHIP_ID(eep_config, 7);
11042 eep_config->no_scam = 0;
11043 eep_config->adapter_info[0] = 0;
11044 eep_config->adapter_info[1] = 0;
11045 eep_config->adapter_info[2] = 0;
11046 eep_config->adapter_info[3] = 0;
11047 eep_config->adapter_info[4] = 0;
11048 /* Indicate EEPROM-less board. */
11049 eep_config->adapter_info[5] = 0xBB;
11050 } else {
11051 ASC_PRINT
11052 ("AscInitFromEEP: EEPROM checksum error; Will try to re-write EEPROM.\n");
11053 write_eep = 1;
11054 warn_code |= ASC_WARN_EEPROM_CHKSUM;
11055 }
11056 }
11057 asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr;
11058 asc_dvc->cfg->disc_enable = eep_config->disc_enable;
11059 asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng;
11060 asc_dvc->cfg->isa_dma_speed = ASC_EEP_GET_DMA_SPD(eep_config);
11061 asc_dvc->start_motor = eep_config->start_motor;
11062 asc_dvc->dvc_cntl = eep_config->cntl;
11063 asc_dvc->no_scam = eep_config->no_scam;
11064 asc_dvc->cfg->adapter_info[0] = eep_config->adapter_info[0];
11065 asc_dvc->cfg->adapter_info[1] = eep_config->adapter_info[1];
11066 asc_dvc->cfg->adapter_info[2] = eep_config->adapter_info[2];
11067 asc_dvc->cfg->adapter_info[3] = eep_config->adapter_info[3];
11068 asc_dvc->cfg->adapter_info[4] = eep_config->adapter_info[4];
11069 asc_dvc->cfg->adapter_info[5] = eep_config->adapter_info[5];
11070 if (!AscTestExternalLram(asc_dvc)) {
11071 if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) ==
11072 ASC_IS_PCI_ULTRA)) {
11073 eep_config->max_total_qng =
11074 ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG;
11075 eep_config->max_tag_qng =
11076 ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG;
11077 } else {
11078 eep_config->cfg_msw |= 0x0800;
11079 cfg_msw |= 0x0800;
11080 AscSetChipCfgMsw(iop_base, cfg_msw);
11081 eep_config->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG;
11082 eep_config->max_tag_qng = ASC_MAX_INRAM_TAG_QNG;
11083 }
11084 } else {
11085 }
11086 if (eep_config->max_total_qng < ASC_MIN_TOTAL_QNG) {
11087 eep_config->max_total_qng = ASC_MIN_TOTAL_QNG;
11088 }
11089 if (eep_config->max_total_qng > ASC_MAX_TOTAL_QNG) {
11090 eep_config->max_total_qng = ASC_MAX_TOTAL_QNG;
11091 }
11092 if (eep_config->max_tag_qng > eep_config->max_total_qng) {
11093 eep_config->max_tag_qng = eep_config->max_total_qng;
11094 }
11095 if (eep_config->max_tag_qng < ASC_MIN_TAG_Q_PER_DVC) {
11096 eep_config->max_tag_qng = ASC_MIN_TAG_Q_PER_DVC;
11097 }
11098 asc_dvc->max_total_qng = eep_config->max_total_qng;
11099 if ((eep_config->use_cmd_qng & eep_config->disc_enable) !=
11100 eep_config->use_cmd_qng) {
11101 eep_config->disc_enable = eep_config->use_cmd_qng;
11102 warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
11103 }
11104 if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) {
11105 asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type);
11106 }
11107 ASC_EEP_SET_CHIP_ID(eep_config,
11108 ASC_EEP_GET_CHIP_ID(eep_config) & ASC_MAX_TID);
11109 asc_dvc->cfg->chip_scsi_id = ASC_EEP_GET_CHIP_ID(eep_config);
11110 if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) &&
11111 !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) {
11112 asc_dvc->host_init_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX;
11113 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011114
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011115 for (i = 0; i <= ASC_MAX_TID; i++) {
11116 asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i];
11117 asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng;
11118 asc_dvc->cfg->sdtr_period_offset[i] =
11119 (uchar)(ASC_DEF_SDTR_OFFSET |
11120 (asc_dvc->host_init_sdtr_index << 4));
11121 }
11122 eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
11123 if (write_eep) {
11124 if ((i =
11125 AscSetEEPConfig(iop_base, eep_config,
11126 asc_dvc->bus_type)) != 0) {
11127 ASC_PRINT1
11128 ("AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n",
11129 i);
11130 } else {
11131 ASC_PRINT
11132 ("AscInitFromEEP: Successfully re-wrote EEPROM.\n");
11133 }
11134 }
11135 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011136}
11137
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011138static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011139{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011140 int i;
11141 ushort warn_code;
11142 PortAddr iop_base;
11143 ASC_PADDR phy_addr;
11144 ASC_DCNT phy_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011145
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011146 iop_base = asc_dvc->iop_base;
11147 warn_code = 0;
11148 for (i = 0; i <= ASC_MAX_TID; i++) {
11149 AscPutMCodeInitSDTRAtID(iop_base, i,
11150 asc_dvc->cfg->sdtr_period_offset[i]
11151 );
11152 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011153
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011154 AscInitQLinkVar(asc_dvc);
11155 AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B,
11156 asc_dvc->cfg->disc_enable);
11157 AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B,
11158 ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070011159
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011160 /* Align overrun buffer on an 8 byte boundary. */
11161 phy_addr = virt_to_bus(asc_dvc->cfg->overrun_buf);
11162 phy_addr = cpu_to_le32((phy_addr + 7) & ~0x7);
11163 AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D,
11164 (uchar *)&phy_addr, 1);
11165 phy_size = cpu_to_le32(ASC_OVERRUN_BSIZE - 8);
11166 AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_BSIZE_D,
11167 (uchar *)&phy_size, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011168
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011169 asc_dvc->cfg->mcode_date =
11170 AscReadLramWord(iop_base, (ushort)ASCV_MC_DATE_W);
11171 asc_dvc->cfg->mcode_version =
11172 AscReadLramWord(iop_base, (ushort)ASCV_MC_VER_W);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011173
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011174 AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
11175 if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
11176 asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
11177 return (warn_code);
11178 }
11179 if (AscStartChip(iop_base) != 1) {
11180 asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
11181 return (warn_code);
11182 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011183
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011184 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011185}
11186
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011187static int __init AscTestExternalLram(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011188{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011189 PortAddr iop_base;
11190 ushort q_addr;
11191 ushort saved_word;
11192 int sta;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011193
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011194 iop_base = asc_dvc->iop_base;
11195 sta = 0;
11196 q_addr = ASC_QNO_TO_QADDR(241);
11197 saved_word = AscReadLramWord(iop_base, q_addr);
11198 AscSetChipLramAddr(iop_base, q_addr);
11199 AscSetChipLramData(iop_base, 0x55AA);
11200 DvcSleepMilliSecond(10);
11201 AscSetChipLramAddr(iop_base, q_addr);
11202 if (AscGetChipLramData(iop_base) == 0x55AA) {
11203 sta = 1;
11204 AscWriteLramWord(iop_base, q_addr, saved_word);
11205 }
11206 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011207}
11208
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011209static int __init AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011210{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011211 uchar read_back;
11212 int retry;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011213
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011214 retry = 0;
11215 while (TRUE) {
11216 AscSetChipEEPCmd(iop_base, cmd_reg);
11217 DvcSleepMilliSecond(1);
11218 read_back = AscGetChipEEPCmd(iop_base);
11219 if (read_back == cmd_reg) {
11220 return (1);
11221 }
11222 if (retry++ > ASC_EEP_MAX_RETRY) {
11223 return (0);
11224 }
11225 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011226}
11227
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011228static int __init AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011229{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011230 ushort read_back;
11231 int retry;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011232
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011233 retry = 0;
11234 while (TRUE) {
11235 AscSetChipEEPData(iop_base, data_reg);
11236 DvcSleepMilliSecond(1);
11237 read_back = AscGetChipEEPData(iop_base);
11238 if (read_back == data_reg) {
11239 return (1);
11240 }
11241 if (retry++ > ASC_EEP_MAX_RETRY) {
11242 return (0);
11243 }
11244 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011245}
11246
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011247static void __init AscWaitEEPRead(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011248{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011249 DvcSleepMilliSecond(1);
11250 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011251}
11252
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011253static void __init AscWaitEEPWrite(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011254{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011255 DvcSleepMilliSecond(20);
11256 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011257}
11258
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011259static ushort __init AscReadEEPWord(PortAddr iop_base, uchar addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011260{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011261 ushort read_wval;
11262 uchar cmd_reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011263
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011264 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
11265 AscWaitEEPRead();
11266 cmd_reg = addr | ASC_EEP_CMD_READ;
11267 AscWriteEEPCmdReg(iop_base, cmd_reg);
11268 AscWaitEEPRead();
11269 read_wval = AscGetChipEEPData(iop_base);
11270 AscWaitEEPRead();
11271 return (read_wval);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011272}
11273
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011274static ushort __init
11275AscWriteEEPWord(PortAddr iop_base, uchar addr, ushort word_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011276{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011277 ushort read_wval;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011278
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011279 read_wval = AscReadEEPWord(iop_base, addr);
11280 if (read_wval != word_val) {
11281 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_ABLE);
11282 AscWaitEEPRead();
11283 AscWriteEEPDataReg(iop_base, word_val);
11284 AscWaitEEPRead();
11285 AscWriteEEPCmdReg(iop_base,
11286 (uchar)((uchar)ASC_EEP_CMD_WRITE | addr));
11287 AscWaitEEPWrite();
11288 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
11289 AscWaitEEPRead();
11290 return (AscReadEEPWord(iop_base, addr));
11291 }
11292 return (read_wval);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011293}
11294
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011295static ushort __init
11296AscGetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011297{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011298 ushort wval;
11299 ushort sum;
11300 ushort *wbuf;
11301 int cfg_beg;
11302 int cfg_end;
11303 int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
11304 int s_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011305
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011306 wbuf = (ushort *)cfg_buf;
11307 sum = 0;
11308 /* Read two config words; Byte-swapping done by AscReadEEPWord(). */
11309 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
11310 *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
11311 sum += *wbuf;
11312 }
11313 if (bus_type & ASC_IS_VL) {
11314 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
11315 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
11316 } else {
11317 cfg_beg = ASC_EEP_DVC_CFG_BEG;
11318 cfg_end = ASC_EEP_MAX_DVC_ADDR;
11319 }
11320 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
11321 wval = AscReadEEPWord(iop_base, (uchar)s_addr);
11322 if (s_addr <= uchar_end_in_config) {
11323 /*
11324 * Swap all char fields - must unswap bytes already swapped
11325 * by AscReadEEPWord().
11326 */
11327 *wbuf = le16_to_cpu(wval);
11328 } else {
11329 /* Don't swap word field at the end - cntl field. */
11330 *wbuf = wval;
11331 }
11332 sum += wval; /* Checksum treats all EEPROM data as words. */
11333 }
11334 /*
11335 * Read the checksum word which will be compared against 'sum'
11336 * by the caller. Word field already swapped.
11337 */
11338 *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
11339 return (sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011340}
11341
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011342static int __init
11343AscSetEEPConfigOnce(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011344{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011345 int n_error;
11346 ushort *wbuf;
11347 ushort word;
11348 ushort sum;
11349 int s_addr;
11350 int cfg_beg;
11351 int cfg_end;
11352 int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011353
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011354 wbuf = (ushort *)cfg_buf;
11355 n_error = 0;
11356 sum = 0;
11357 /* Write two config words; AscWriteEEPWord() will swap bytes. */
11358 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
11359 sum += *wbuf;
11360 if (*wbuf != AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
11361 n_error++;
11362 }
11363 }
11364 if (bus_type & ASC_IS_VL) {
11365 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
11366 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
11367 } else {
11368 cfg_beg = ASC_EEP_DVC_CFG_BEG;
11369 cfg_end = ASC_EEP_MAX_DVC_ADDR;
11370 }
11371 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
11372 if (s_addr <= uchar_end_in_config) {
11373 /*
11374 * This is a char field. Swap char fields before they are
11375 * swapped again by AscWriteEEPWord().
11376 */
11377 word = cpu_to_le16(*wbuf);
11378 if (word !=
11379 AscWriteEEPWord(iop_base, (uchar)s_addr, word)) {
11380 n_error++;
11381 }
11382 } else {
11383 /* Don't swap word field at the end - cntl field. */
11384 if (*wbuf !=
11385 AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
11386 n_error++;
11387 }
11388 }
11389 sum += *wbuf; /* Checksum calculated from word values. */
11390 }
11391 /* Write checksum word. It will be swapped by AscWriteEEPWord(). */
11392 *wbuf = sum;
11393 if (sum != AscWriteEEPWord(iop_base, (uchar)s_addr, sum)) {
11394 n_error++;
11395 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011396
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011397 /* Read EEPROM back again. */
11398 wbuf = (ushort *)cfg_buf;
11399 /*
11400 * Read two config words; Byte-swapping done by AscReadEEPWord().
11401 */
11402 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
11403 if (*wbuf != AscReadEEPWord(iop_base, (uchar)s_addr)) {
11404 n_error++;
11405 }
11406 }
11407 if (bus_type & ASC_IS_VL) {
11408 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
11409 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
11410 } else {
11411 cfg_beg = ASC_EEP_DVC_CFG_BEG;
11412 cfg_end = ASC_EEP_MAX_DVC_ADDR;
11413 }
11414 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
11415 if (s_addr <= uchar_end_in_config) {
11416 /*
11417 * Swap all char fields. Must unswap bytes already swapped
11418 * by AscReadEEPWord().
11419 */
11420 word =
11421 le16_to_cpu(AscReadEEPWord
11422 (iop_base, (uchar)s_addr));
11423 } else {
11424 /* Don't swap word field at the end - cntl field. */
11425 word = AscReadEEPWord(iop_base, (uchar)s_addr);
11426 }
11427 if (*wbuf != word) {
11428 n_error++;
11429 }
11430 }
11431 /* Read checksum; Byte swapping not needed. */
11432 if (AscReadEEPWord(iop_base, (uchar)s_addr) != sum) {
11433 n_error++;
11434 }
11435 return (n_error);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011436}
11437
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011438static int __init
11439AscSetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011440{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011441 int retry;
11442 int n_error;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011443
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011444 retry = 0;
11445 while (TRUE) {
11446 if ((n_error = AscSetEEPConfigOnce(iop_base, cfg_buf,
11447 bus_type)) == 0) {
11448 break;
11449 }
11450 if (++retry > ASC_EEP_MAX_RETRY) {
11451 break;
11452 }
11453 }
11454 return (n_error);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011455}
11456
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011457static void
11458AscAsyncFix(ASC_DVC_VAR *asc_dvc, uchar tid_no, ASC_SCSI_INQUIRY *inq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011459{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011460 uchar dvc_type;
11461 ASC_SCSI_BIT_ID_TYPE tid_bits;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011462
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011463 dvc_type = ASC_INQ_DVC_TYPE(inq);
11464 tid_bits = ASC_TIX_TO_TARGET_ID(tid_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011465
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011466 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN) {
11467 if (!(asc_dvc->init_sdtr & tid_bits)) {
11468 if ((dvc_type == TYPE_ROM) &&
11469 (AscCompareString((uchar *)inq->vendor_id,
11470 (uchar *)"HP ", 3) == 0)) {
11471 asc_dvc->pci_fix_asyn_xfer_always |= tid_bits;
11472 }
11473 asc_dvc->pci_fix_asyn_xfer |= tid_bits;
11474 if ((dvc_type == TYPE_PROCESSOR) ||
11475 (dvc_type == TYPE_SCANNER) ||
11476 (dvc_type == TYPE_ROM) || (dvc_type == TYPE_TAPE)) {
11477 asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
11478 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011479
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011480 if (asc_dvc->pci_fix_asyn_xfer & tid_bits) {
11481 AscSetRunChipSynRegAtID(asc_dvc->iop_base,
11482 tid_no,
11483 ASYN_SDTR_DATA_FIX_PCI_REV_AB);
11484 }
11485 }
11486 }
11487 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011488}
11489
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011490static int AscTagQueuingSafe(ASC_SCSI_INQUIRY *inq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011491{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011492 if ((inq->add_len >= 32) &&
11493 (AscCompareString((uchar *)inq->vendor_id,
11494 (uchar *)"QUANTUM XP34301", 15) == 0) &&
11495 (AscCompareString((uchar *)inq->product_rev_level,
11496 (uchar *)"1071", 4) == 0)) {
11497 return 0;
11498 }
11499 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011500}
11501
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011502static void
11503AscInquiryHandling(ASC_DVC_VAR *asc_dvc, uchar tid_no, ASC_SCSI_INQUIRY *inq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011504{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011505 ASC_SCSI_BIT_ID_TYPE tid_bit = ASC_TIX_TO_TARGET_ID(tid_no);
11506 ASC_SCSI_BIT_ID_TYPE orig_init_sdtr, orig_use_tagged_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011507
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011508 orig_init_sdtr = asc_dvc->init_sdtr;
11509 orig_use_tagged_qng = asc_dvc->use_tagged_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011510
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011511 asc_dvc->init_sdtr &= ~tid_bit;
11512 asc_dvc->cfg->can_tagged_qng &= ~tid_bit;
11513 asc_dvc->use_tagged_qng &= ~tid_bit;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011514
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011515 if (ASC_INQ_RESPONSE_FMT(inq) >= 2 || ASC_INQ_ANSI_VER(inq) >= 2) {
11516 if ((asc_dvc->cfg->sdtr_enable & tid_bit) && ASC_INQ_SYNC(inq)) {
11517 asc_dvc->init_sdtr |= tid_bit;
11518 }
11519 if ((asc_dvc->cfg->cmd_qng_enabled & tid_bit) &&
11520 ASC_INQ_CMD_QUEUE(inq)) {
11521 if (AscTagQueuingSafe(inq)) {
11522 asc_dvc->use_tagged_qng |= tid_bit;
11523 asc_dvc->cfg->can_tagged_qng |= tid_bit;
11524 }
11525 }
11526 }
11527 if (orig_use_tagged_qng != asc_dvc->use_tagged_qng) {
11528 AscWriteLramByte(asc_dvc->iop_base, ASCV_DISC_ENABLE_B,
11529 asc_dvc->cfg->disc_enable);
11530 AscWriteLramByte(asc_dvc->iop_base, ASCV_USE_TAGGED_QNG_B,
11531 asc_dvc->use_tagged_qng);
11532 AscWriteLramByte(asc_dvc->iop_base, ASCV_CAN_TAGGED_QNG_B,
11533 asc_dvc->cfg->can_tagged_qng);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011534
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011535 asc_dvc->max_dvc_qng[tid_no] =
11536 asc_dvc->cfg->max_tag_qng[tid_no];
11537 AscWriteLramByte(asc_dvc->iop_base,
11538 (ushort)(ASCV_MAX_DVC_QNG_BEG + tid_no),
11539 asc_dvc->max_dvc_qng[tid_no]);
11540 }
11541 if (orig_init_sdtr != asc_dvc->init_sdtr) {
11542 AscAsyncFix(asc_dvc, tid_no, inq);
11543 }
11544 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011545}
11546
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011547static int AscCompareString(uchar *str1, uchar *str2, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011548{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011549 int i;
11550 int diff;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011551
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011552 for (i = 0; i < len; i++) {
11553 diff = (int)(str1[i] - str2[i]);
11554 if (diff != 0)
11555 return (diff);
11556 }
11557 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011558}
11559
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011560static uchar AscReadLramByte(PortAddr iop_base, ushort addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011561{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011562 uchar byte_data;
11563 ushort word_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011564
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011565 if (isodd_word(addr)) {
11566 AscSetChipLramAddr(iop_base, addr - 1);
11567 word_data = AscGetChipLramData(iop_base);
11568 byte_data = (uchar)((word_data >> 8) & 0xFF);
11569 } else {
11570 AscSetChipLramAddr(iop_base, addr);
11571 word_data = AscGetChipLramData(iop_base);
11572 byte_data = (uchar)(word_data & 0xFF);
11573 }
11574 return (byte_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011575}
Linus Torvalds1da177e2005-04-16 15:20:36 -070011576
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011577static ushort AscReadLramWord(PortAddr iop_base, ushort addr)
11578{
11579 ushort word_data;
11580
11581 AscSetChipLramAddr(iop_base, addr);
11582 word_data = AscGetChipLramData(iop_base);
11583 return (word_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011584}
11585
11586#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011587static ASC_DCNT AscReadLramDWord(PortAddr iop_base, ushort addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011588{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011589 ushort val_low, val_high;
11590 ASC_DCNT dword_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011591
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011592 AscSetChipLramAddr(iop_base, addr);
11593 val_low = AscGetChipLramData(iop_base);
11594 val_high = AscGetChipLramData(iop_base);
11595 dword_data = ((ASC_DCNT) val_high << 16) | (ASC_DCNT) val_low;
11596 return (dword_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011597}
11598#endif /* CC_VERY_LONG_SG_LIST */
11599
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011600static void AscWriteLramWord(PortAddr iop_base, ushort addr, ushort word_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011601{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011602 AscSetChipLramAddr(iop_base, addr);
11603 AscSetChipLramData(iop_base, word_val);
11604 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011605}
11606
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011607static void AscWriteLramByte(PortAddr iop_base, ushort addr, uchar byte_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011608{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011609 ushort word_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011610
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011611 if (isodd_word(addr)) {
11612 addr--;
11613 word_data = AscReadLramWord(iop_base, addr);
11614 word_data &= 0x00FF;
11615 word_data |= (((ushort)byte_val << 8) & 0xFF00);
11616 } else {
11617 word_data = AscReadLramWord(iop_base, addr);
11618 word_data &= 0xFF00;
11619 word_data |= ((ushort)byte_val & 0x00FF);
11620 }
11621 AscWriteLramWord(iop_base, addr, word_data);
11622 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011623}
11624
11625/*
11626 * Copy 2 bytes to LRAM.
11627 *
11628 * The source data is assumed to be in little-endian order in memory
11629 * and is maintained in little-endian order when written to LRAM.
11630 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011631static void
11632AscMemWordCopyPtrToLram(PortAddr iop_base,
11633 ushort s_addr, uchar *s_buffer, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011634{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011635 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011636
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011637 AscSetChipLramAddr(iop_base, s_addr);
11638 for (i = 0; i < 2 * words; i += 2) {
11639 /*
11640 * On a little-endian system the second argument below
11641 * produces a little-endian ushort which is written to
11642 * LRAM in little-endian order. On a big-endian system
11643 * the second argument produces a big-endian ushort which
11644 * is "transparently" byte-swapped by outpw() and written
11645 * in little-endian order to LRAM.
11646 */
11647 outpw(iop_base + IOP_RAM_DATA,
11648 ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]);
11649 }
11650 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011651}
11652
11653/*
11654 * Copy 4 bytes to LRAM.
11655 *
11656 * The source data is assumed to be in little-endian order in memory
11657 * and is maintained in little-endian order when writen to LRAM.
11658 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011659static void
11660AscMemDWordCopyPtrToLram(PortAddr iop_base,
11661 ushort s_addr, uchar *s_buffer, int dwords)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011662{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011663 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011664
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011665 AscSetChipLramAddr(iop_base, s_addr);
11666 for (i = 0; i < 4 * dwords; i += 4) {
11667 outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]); /* LSW */
11668 outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 3] << 8) | s_buffer[i + 2]); /* MSW */
11669 }
11670 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011671}
11672
11673/*
11674 * Copy 2 bytes from LRAM.
11675 *
11676 * The source data is assumed to be in little-endian order in LRAM
11677 * and is maintained in little-endian order when written to memory.
11678 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011679static void
11680AscMemWordCopyPtrFromLram(PortAddr iop_base,
11681 ushort s_addr, uchar *d_buffer, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011682{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011683 int i;
11684 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011685
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011686 AscSetChipLramAddr(iop_base, s_addr);
11687 for (i = 0; i < 2 * words; i += 2) {
11688 word = inpw(iop_base + IOP_RAM_DATA);
11689 d_buffer[i] = word & 0xff;
11690 d_buffer[i + 1] = (word >> 8) & 0xff;
11691 }
11692 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011693}
11694
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011695static ASC_DCNT AscMemSumLramWord(PortAddr iop_base, ushort s_addr, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011696{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011697 ASC_DCNT sum;
11698 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011699
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011700 sum = 0L;
11701 for (i = 0; i < words; i++, s_addr += 2) {
11702 sum += AscReadLramWord(iop_base, s_addr);
11703 }
11704 return (sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011705}
11706
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011707static void
11708AscMemWordSetLram(PortAddr iop_base, ushort s_addr, ushort set_wval, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011709{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011710 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011711
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011712 AscSetChipLramAddr(iop_base, s_addr);
11713 for (i = 0; i < words; i++) {
11714 AscSetChipLramData(iop_base, set_wval);
11715 }
11716 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011717}
11718
Linus Torvalds1da177e2005-04-16 15:20:36 -070011719/*
11720 * --- Adv Library Functions
11721 */
11722
11723/* a_mcode.h */
11724
11725/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011726static unsigned char _adv_asc3550_buf[] = {
11727 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x18, 0xe4, 0x00, 0xfc,
11728 0x01, 0x00, 0x48, 0xe4,
11729 0xbe, 0x18, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0x00, 0xfa, 0xff, 0xff,
11730 0x28, 0x0e, 0x9e, 0xe7,
11731 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x00, 0xf6, 0x01, 0xe6, 0x09, 0xe7,
11732 0x55, 0xf0, 0x01, 0xf6,
11733 0x01, 0xfa, 0x08, 0x00, 0x03, 0x00, 0x04, 0x00, 0x18, 0xf4, 0x10, 0x00,
11734 0x00, 0xec, 0x85, 0xf0,
11735 0xbc, 0x00, 0xd5, 0xf0, 0x8e, 0x0c, 0x38, 0x54, 0x00, 0xe6, 0x1e, 0xf0,
11736 0x86, 0xf0, 0xb4, 0x00,
11737 0x98, 0x57, 0xd0, 0x01, 0x0c, 0x1c, 0x3e, 0x1c, 0x0c, 0x00, 0xbb, 0x00,
11738 0xaa, 0x18, 0x02, 0x80,
11739 0x32, 0xf0, 0x01, 0xfc, 0x88, 0x0c, 0xc6, 0x12, 0x02, 0x13, 0x18, 0x40,
11740 0x00, 0x57, 0x01, 0xea,
11741 0x3c, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12, 0x3e, 0x57, 0x00, 0x80,
11742 0x03, 0xe6, 0xb6, 0x00,
11743 0xc0, 0x00, 0x01, 0x01, 0x3e, 0x01, 0xda, 0x0f, 0x22, 0x10, 0x08, 0x12,
11744 0x02, 0x4a, 0xb9, 0x54,
11745 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4, 0x20, 0x00, 0x32, 0x00,
11746 0x3e, 0x00, 0x80, 0x00,
11747 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01,
11748 0x74, 0x01, 0x76, 0x01,
11749 0x78, 0x01, 0x62, 0x0a, 0x92, 0x0c, 0x2c, 0x10, 0x2e, 0x10, 0x06, 0x13,
11750 0x4c, 0x1c, 0xbb, 0x55,
11751 0x3c, 0x56, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0xb1, 0xf0,
11752 0x03, 0xf7, 0x06, 0xf7,
11753 0x03, 0xfc, 0x0f, 0x00, 0x40, 0x00, 0xbe, 0x00, 0x00, 0x01, 0xb0, 0x08,
11754 0x30, 0x13, 0x64, 0x15,
11755 0x32, 0x1c, 0x38, 0x1c, 0x4e, 0x1c, 0x10, 0x44, 0x02, 0x48, 0x00, 0x4c,
11756 0x04, 0xea, 0x5d, 0xf0,
11757 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00,
11758 0xcc, 0x00, 0x20, 0x01,
11759 0x4e, 0x01, 0x4e, 0x0b, 0x1e, 0x0e, 0x0c, 0x10, 0x0a, 0x12, 0x04, 0x13,
11760 0x40, 0x13, 0x30, 0x1c,
11761 0x00, 0x4e, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
11762 0x59, 0xf0, 0xa7, 0xf0,
11763 0xb8, 0xf0, 0x0e, 0xf7, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00,
11764 0xa4, 0x00, 0xb5, 0x00,
11765 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00, 0xde, 0x03, 0x56, 0x0a,
11766 0x14, 0x0e, 0x02, 0x10,
11767 0x04, 0x10, 0x0a, 0x10, 0x36, 0x10, 0x0a, 0x13, 0x12, 0x13, 0x52, 0x13,
11768 0x10, 0x15, 0x14, 0x15,
11769 0xac, 0x16, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44,
11770 0x91, 0x44, 0x0a, 0x45,
11771 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x83, 0x55, 0xb0, 0x57, 0x01, 0x58,
11772 0x83, 0x59, 0x05, 0xe6,
11773 0x0b, 0xf0, 0x0c, 0xf0, 0x5c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8, 0x05, 0xf8,
11774 0x02, 0xfa, 0x03, 0xfa,
11775 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x1c, 0x00,
11776 0x9e, 0x00, 0xa8, 0x00,
11777 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01,
11778 0x7a, 0x01, 0xc0, 0x01,
11779 0xc2, 0x01, 0x7c, 0x02, 0x5a, 0x03, 0xea, 0x04, 0xe8, 0x07, 0x68, 0x08,
11780 0x69, 0x08, 0xba, 0x08,
11781 0xe9, 0x09, 0x06, 0x0b, 0x3a, 0x0e, 0x00, 0x10, 0x1a, 0x10, 0xed, 0x10,
11782 0xf1, 0x10, 0x06, 0x12,
11783 0x0c, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x82, 0x13, 0x42, 0x14, 0xd6, 0x14,
11784 0x8a, 0x15, 0xc6, 0x17,
11785 0xd2, 0x17, 0x6b, 0x18, 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40,
11786 0x0e, 0x47, 0x48, 0x47,
11787 0x41, 0x48, 0x89, 0x48, 0x80, 0x4c, 0x00, 0x54, 0x44, 0x55, 0xe5, 0x55,
11788 0x14, 0x56, 0x77, 0x57,
11789 0xbf, 0x57, 0x40, 0x5c, 0x06, 0x80, 0x08, 0x90, 0x03, 0xa1, 0xfe, 0x9c,
11790 0xf0, 0x29, 0x02, 0xfe,
11791 0xb8, 0x0c, 0xff, 0x10, 0x00, 0x00, 0xd0, 0xfe, 0xcc, 0x18, 0x00, 0xcf,
11792 0xfe, 0x80, 0x01, 0xff,
11793 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
11794 0x00, 0xfe, 0x57, 0x24,
11795 0x00, 0xfe, 0x48, 0x00, 0x4f, 0xff, 0x04, 0x00, 0x00, 0x10, 0xff, 0x09,
11796 0x00, 0x00, 0xff, 0x08,
11797 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
11798 0xff, 0xff, 0xff, 0x0f,
11799 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
11800 0xfe, 0x04, 0xf7, 0xcf,
11801 0x2a, 0x67, 0x0b, 0x01, 0xfe, 0xce, 0x0e, 0xfe, 0x04, 0xf7, 0xcf, 0x67,
11802 0x0b, 0x3c, 0x2a, 0xfe,
11803 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x91, 0xf0,
11804 0xfe, 0xf0, 0x01, 0xfe,
11805 0x90, 0xf0, 0xfe, 0xf0, 0x01, 0xfe, 0x8f, 0xf0, 0x9c, 0x05, 0x51, 0x3b,
11806 0x02, 0xfe, 0xd4, 0x0c,
11807 0x01, 0xfe, 0x44, 0x0d, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28,
11808 0x1c, 0x05, 0xfe, 0xa6,
11809 0x00, 0xfe, 0xd3, 0x12, 0x47, 0x18, 0xfe, 0xa6, 0x00, 0xb5, 0xfe, 0x48,
11810 0xf0, 0xfe, 0x86, 0x02,
11811 0xfe, 0x49, 0xf0, 0xfe, 0xa0, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xbe, 0x02,
11812 0xfe, 0x46, 0xf0, 0xfe,
11813 0x50, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x56, 0x02, 0xfe, 0x43, 0xf0, 0xfe,
11814 0x44, 0x02, 0xfe, 0x44,
11815 0xf0, 0xfe, 0x48, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x4c, 0x02, 0x17, 0x0b,
11816 0xa0, 0x17, 0x06, 0x18,
11817 0x96, 0x02, 0x29, 0xfe, 0x00, 0x1c, 0xde, 0xfe, 0x02, 0x1c, 0xdd, 0xfe,
11818 0x1e, 0x1c, 0xfe, 0xe9,
11819 0x10, 0x01, 0xfe, 0x20, 0x17, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xc7,
11820 0x0a, 0x6b, 0x01, 0x9e,
11821 0x02, 0x29, 0x14, 0x4d, 0x37, 0x97, 0x01, 0xfe, 0x64, 0x0f, 0x0a, 0x6b,
11822 0x01, 0x82, 0xfe, 0xbd,
11823 0x10, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
11824 0x58, 0x1c, 0x17, 0x06,
11825 0x18, 0x96, 0x2a, 0x25, 0x29, 0xfe, 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0x21,
11826 0xfe, 0x94, 0x02, 0xfe,
11827 0x5a, 0x1c, 0xea, 0xfe, 0x14, 0x1c, 0x14, 0xfe, 0x30, 0x00, 0x37, 0x97,
11828 0x01, 0xfe, 0x54, 0x0f,
11829 0x17, 0x06, 0x18, 0x96, 0x02, 0xd0, 0x1e, 0x20, 0x07, 0x10, 0x34, 0xfe,
11830 0x69, 0x10, 0x17, 0x06,
11831 0x18, 0x96, 0xfe, 0x04, 0xec, 0x20, 0x46, 0x3d, 0x12, 0x20, 0xfe, 0x05,
11832 0xf6, 0xc7, 0x01, 0xfe,
11833 0x52, 0x16, 0x09, 0x4a, 0x4c, 0x35, 0x11, 0x2d, 0x3c, 0x8a, 0x01, 0xe6,
11834 0x02, 0x29, 0x0a, 0x40,
11835 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x01, 0x6f, 0xfe, 0x18, 0x10, 0xfe, 0x41,
11836 0x58, 0x0a, 0x99, 0x01,
11837 0x0e, 0xfe, 0xc8, 0x54, 0x64, 0xfe, 0x0c, 0x03, 0x01, 0xe6, 0x02, 0x29,
11838 0x2a, 0x46, 0xfe, 0x02,
11839 0xe8, 0x27, 0xf8, 0xfe, 0x9e, 0x43, 0xf7, 0xfe, 0x27, 0xf0, 0xfe, 0xdc,
11840 0x01, 0xfe, 0x07, 0x4b,
11841 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x40, 0x1c, 0x25, 0xd2, 0xfe, 0x26, 0xf0,
11842 0xfe, 0x56, 0x03, 0xfe,
11843 0xa0, 0xf0, 0xfe, 0x44, 0x03, 0xfe, 0x11, 0xf0, 0x9c, 0xfe, 0xef, 0x10,
11844 0xfe, 0x9f, 0xf0, 0xfe,
11845 0x64, 0x03, 0xeb, 0x0f, 0xfe, 0x11, 0x00, 0x02, 0x5a, 0x2a, 0xfe, 0x48,
11846 0x1c, 0xeb, 0x09, 0x04,
11847 0x1d, 0xfe, 0x18, 0x13, 0x23, 0x1e, 0x98, 0xac, 0x12, 0x98, 0x0a, 0x40,
11848 0x01, 0x0e, 0xac, 0x75,
11849 0x01, 0xfe, 0xbc, 0x15, 0x11, 0xca, 0x25, 0xd2, 0xfe, 0x01, 0xf0, 0xd2,
11850 0xfe, 0x82, 0xf0, 0xfe,
11851 0x92, 0x03, 0xec, 0x11, 0xfe, 0xe4, 0x00, 0x65, 0xfe, 0xa4, 0x03, 0x25,
11852 0x32, 0x1f, 0xfe, 0xb4,
11853 0x03, 0x01, 0x43, 0xfe, 0x06, 0xf0, 0xfe, 0xc4, 0x03, 0x8d, 0x81, 0xfe,
11854 0x0a, 0xf0, 0xfe, 0x7a,
11855 0x06, 0x02, 0x22, 0x05, 0x6b, 0x28, 0x16, 0xfe, 0xf6, 0x04, 0x14, 0x2c,
11856 0x01, 0x33, 0x8f, 0xfe,
11857 0x66, 0x02, 0x02, 0xd1, 0xeb, 0x2a, 0x67, 0x1a, 0xfe, 0x67, 0x1b, 0xf8,
11858 0xf7, 0xfe, 0x48, 0x1c,
11859 0x70, 0x01, 0x6e, 0x87, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x16, 0xd3,
11860 0x0a, 0xca, 0x01, 0x0e,
11861 0x74, 0x60, 0x59, 0x76, 0x27, 0x05, 0x6b, 0x28, 0xfe, 0x10, 0x12, 0x14,
11862 0x2c, 0x01, 0x33, 0x8f,
11863 0xfe, 0x66, 0x02, 0x02, 0xd1, 0xbc, 0x7d, 0xbd, 0x7f, 0x25, 0x22, 0x65,
11864 0xfe, 0x3c, 0x04, 0x1f,
11865 0xfe, 0x38, 0x04, 0x68, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e,
11866 0x12, 0x2b, 0xff, 0x02,
11867 0x00, 0x10, 0x01, 0x08, 0x1f, 0xfe, 0xe0, 0x04, 0x2b, 0x01, 0x08, 0x1f,
11868 0x22, 0x30, 0x2e, 0xd5,
11869 0xfe, 0x4c, 0x44, 0xfe, 0x4c, 0x12, 0x60, 0xfe, 0x44, 0x48, 0x13, 0x2c,
11870 0xfe, 0x4c, 0x54, 0x64,
11871 0xd3, 0x46, 0x76, 0x27, 0xfa, 0xef, 0xfe, 0x62, 0x13, 0x09, 0x04, 0x1d,
11872 0xfe, 0x2a, 0x13, 0x2f,
11873 0x07, 0x7e, 0xa5, 0xfe, 0x20, 0x10, 0x13, 0x2c, 0xfe, 0x4c, 0x54, 0x64,
11874 0xd3, 0xfa, 0xef, 0x86,
11875 0x09, 0x04, 0x1d, 0xfe, 0x08, 0x13, 0x2f, 0x07, 0x7e, 0x6e, 0x09, 0x04,
11876 0x1d, 0xfe, 0x1c, 0x12,
11877 0x14, 0x92, 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe,
11878 0x70, 0x0c, 0x02, 0x22,
11879 0x2b, 0x11, 0xfe, 0xe6, 0x00, 0xfe, 0x1c, 0x90, 0xf9, 0x03, 0x14, 0x92,
11880 0x01, 0x33, 0x02, 0x29,
11881 0xfe, 0x42, 0x5b, 0x67, 0x1a, 0xfe, 0x46, 0x59, 0xf8, 0xf7, 0xfe, 0x87,
11882 0x80, 0xfe, 0x31, 0xe4,
11883 0x4f, 0x09, 0x04, 0x0b, 0xfe, 0x78, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x1a,
11884 0xfe, 0x70, 0x12, 0x49,
11885 0x04, 0x06, 0xfe, 0x60, 0x13, 0x05, 0xfe, 0xa2, 0x00, 0x28, 0x16, 0xfe,
11886 0x80, 0x05, 0xfe, 0x31,
11887 0xe4, 0x6a, 0x49, 0x04, 0x0b, 0xfe, 0x4a, 0x13, 0x05, 0xfe, 0xa0, 0x00,
11888 0x28, 0xfe, 0x42, 0x12,
11889 0x5e, 0x01, 0x08, 0x25, 0x32, 0xf1, 0x01, 0x08, 0x26, 0xfe, 0x98, 0x05,
11890 0x11, 0xfe, 0xe3, 0x00,
11891 0x23, 0x49, 0xfe, 0x4a, 0xf0, 0xfe, 0x6a, 0x05, 0xfe, 0x49, 0xf0, 0xfe,
11892 0x64, 0x05, 0x83, 0x24,
11893 0xfe, 0x21, 0x00, 0xa1, 0x24, 0xfe, 0x22, 0x00, 0xa0, 0x24, 0x4c, 0xfe,
11894 0x09, 0x48, 0x01, 0x08,
11895 0x26, 0xfe, 0x98, 0x05, 0xfe, 0xe2, 0x08, 0x49, 0x04, 0xc5, 0x3b, 0x01,
11896 0x86, 0x24, 0x06, 0x12,
11897 0xcc, 0x37, 0xfe, 0x27, 0x01, 0x09, 0x04, 0x1d, 0xfe, 0x22, 0x12, 0x47,
11898 0x01, 0xa7, 0x14, 0x92,
11899 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe, 0x70, 0x0c,
11900 0x02, 0x22, 0x05, 0xfe,
11901 0x9c, 0x00, 0x28, 0xfe, 0x3e, 0x12, 0x05, 0x50, 0x28, 0xfe, 0x36, 0x13,
11902 0x47, 0x01, 0xa7, 0x26,
11903 0xfe, 0x08, 0x06, 0x0a, 0x06, 0x49, 0x04, 0x19, 0xfe, 0x02, 0x12, 0x5f,
11904 0x01, 0xfe, 0xaa, 0x14,
11905 0x1f, 0xfe, 0xfe, 0x05, 0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00,
11906 0x05, 0x50, 0xb4, 0x0c,
11907 0x50, 0x05, 0xc6, 0x28, 0xfe, 0x62, 0x12, 0x05, 0x3f, 0x28, 0xfe, 0x5a,
11908 0x13, 0x01, 0xfe, 0x14,
11909 0x18, 0x01, 0xfe, 0x66, 0x18, 0xfe, 0x43, 0x48, 0xb7, 0x19, 0x13, 0x6c,
11910 0xff, 0x02, 0x00, 0x57,
11911 0x48, 0x8b, 0x1c, 0x3d, 0x85, 0xb7, 0x69, 0x47, 0x01, 0xa7, 0x26, 0xfe,
11912 0x72, 0x06, 0x49, 0x04,
11913 0x1b, 0xdf, 0x89, 0x0a, 0x4d, 0x01, 0xfe, 0xd8, 0x14, 0x1f, 0xfe, 0x68,
11914 0x06, 0x11, 0x9a, 0x01,
11915 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x3f, 0xb4, 0x0c, 0x3f, 0x17, 0x06,
11916 0x01, 0xa7, 0xec, 0x72,
11917 0x70, 0x01, 0x6e, 0x87, 0x11, 0xfe, 0xe2, 0x00, 0x01, 0x08, 0x25, 0x32,
11918 0xfe, 0x0a, 0xf0, 0xfe,
11919 0xa6, 0x06, 0x8c, 0xfe, 0x5c, 0x07, 0xfe, 0x06, 0xf0, 0xfe, 0x64, 0x07,
11920 0x8d, 0x81, 0x02, 0x22,
11921 0x09, 0x04, 0x0b, 0xfe, 0x2e, 0x12, 0x15, 0x1a, 0x01, 0x08, 0x15, 0x00,
11922 0x01, 0x08, 0x15, 0x00,
11923 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08, 0x15,
11924 0x00, 0x02, 0xfe, 0x32,
11925 0x08, 0x61, 0x04, 0x1b, 0xfe, 0x38, 0x12, 0x09, 0x04, 0x1b, 0x6e, 0x15,
11926 0xfe, 0x1b, 0x00, 0x01,
11927 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01,
11928 0x08, 0x15, 0x06, 0x01,
11929 0x08, 0x15, 0x00, 0x02, 0xd9, 0x66, 0x4c, 0xfe, 0x3a, 0x55, 0x5f, 0xfe,
11930 0x9a, 0x81, 0x4b, 0x1d,
11931 0xba, 0xfe, 0x32, 0x07, 0x0a, 0x1d, 0xfe, 0x09, 0x6f, 0xaf, 0xfe, 0xca,
11932 0x45, 0xfe, 0x32, 0x12,
11933 0x62, 0x2c, 0x85, 0x66, 0x7b, 0x01, 0x08, 0x25, 0x32, 0xfe, 0x0a, 0xf0,
11934 0xfe, 0x32, 0x07, 0x8d,
11935 0x81, 0x8c, 0xfe, 0x5c, 0x07, 0x02, 0x22, 0x01, 0x43, 0x02, 0xfe, 0x8a,
11936 0x06, 0x15, 0x19, 0x02,
11937 0xfe, 0x8a, 0x06, 0xfe, 0x9c, 0xf7, 0xd4, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
11938 0x90, 0x77, 0xfe, 0xca,
11939 0x07, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x4a, 0x6a, 0x35, 0x1e, 0x20, 0x07,
11940 0x10, 0xfe, 0x0e, 0x12,
11941 0x74, 0xfe, 0x80, 0x80, 0x37, 0x20, 0x63, 0x27, 0xfe, 0x06, 0x10, 0xfe,
11942 0x83, 0xe7, 0xc4, 0xa1,
11943 0xfe, 0x03, 0x40, 0x09, 0x4a, 0x4f, 0x35, 0x01, 0xa8, 0xad, 0xfe, 0x1f,
11944 0x40, 0x12, 0x58, 0x01,
11945 0xa5, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6,
11946 0x51, 0x83, 0xfb, 0xfe,
11947 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x0c, 0x90, 0xfe, 0x8e, 0x90,
11948 0xfe, 0x40, 0x50, 0xfe,
11949 0xc2, 0x50, 0x0c, 0x39, 0x18, 0x3a, 0xfe, 0x4a, 0x10, 0x09, 0x04, 0x6a,
11950 0xfe, 0x2a, 0x12, 0xfe,
11951 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x04, 0x4f,
11952 0x85, 0x01, 0xa8, 0xfe,
11953 0x1f, 0x80, 0x12, 0x58, 0xfe, 0x44, 0x90, 0xfe, 0xc6, 0x90, 0x0c, 0x56,
11954 0x18, 0x57, 0xfb, 0xfe,
11955 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90,
11956 0x0c, 0x39, 0x18, 0x3a,
11957 0x0c, 0x38, 0x18, 0x4e, 0x09, 0x4a, 0x19, 0x35, 0x2a, 0x13, 0xfe, 0x4e,
11958 0x11, 0x65, 0xfe, 0x48,
11959 0x08, 0xfe, 0x9e, 0xf0, 0xfe, 0x5c, 0x08, 0xb1, 0x16, 0x32, 0x2a, 0x73,
11960 0xdd, 0xb8, 0xfe, 0x80,
11961 0x08, 0xb9, 0xfe, 0x9e, 0x08, 0x8c, 0xfe, 0x74, 0x08, 0xfe, 0x06, 0xf0,
11962 0xfe, 0x7a, 0x08, 0x8d,
11963 0x81, 0x02, 0x22, 0x01, 0x43, 0xfe, 0xc9, 0x10, 0x15, 0x19, 0xfe, 0xc9,
11964 0x10, 0x61, 0x04, 0x06,
11965 0xfe, 0x10, 0x12, 0x61, 0x04, 0x0b, 0x45, 0x09, 0x04, 0x0b, 0xfe, 0x68,
11966 0x12, 0xfe, 0x2e, 0x1c,
11967 0x02, 0xfe, 0x24, 0x0a, 0x61, 0x04, 0x06, 0x45, 0x61, 0x04, 0x0b, 0xfe,
11968 0x52, 0x12, 0xfe, 0x2c,
11969 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0x1e, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0xbe,
11970 0x08, 0xfe, 0x8a, 0x10,
11971 0xaa, 0xfe, 0xf3, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0xca, 0x08, 0x02, 0xfe,
11972 0x24, 0x0a, 0xab, 0xfe,
11973 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0x9d, 0xe9, 0x1c, 0xfe, 0x00, 0xfe, 0xfe,
11974 0x1c, 0x12, 0xb5, 0xfe,
11975 0xd2, 0xf0, 0x9d, 0xfe, 0x76, 0x18, 0x1c, 0x1a, 0x16, 0x9d, 0x05, 0xcb,
11976 0x1c, 0x06, 0x16, 0x9d,
11977 0xb8, 0x6d, 0xb9, 0x6d, 0xaa, 0xab, 0xfe, 0xb1, 0x10, 0x70, 0x5e, 0x2b,
11978 0x14, 0x92, 0x01, 0x33,
11979 0x0f, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x5a, 0x0f, 0x7c, 0x02, 0x5a,
11980 0xfe, 0x74, 0x18, 0x1c,
11981 0xfe, 0x00, 0xf8, 0x16, 0x6d, 0x67, 0x1b, 0x01, 0xfe, 0x44, 0x0d, 0x3b,
11982 0x01, 0xe6, 0x1e, 0x27,
11983 0x74, 0x67, 0x1a, 0x02, 0x6d, 0x09, 0x04, 0x0b, 0x21, 0xfe, 0x06, 0x0a,
11984 0x09, 0x04, 0x6a, 0xfe,
11985 0x82, 0x12, 0x09, 0x04, 0x19, 0xfe, 0x66, 0x13, 0x1e, 0x58, 0xac, 0xfc,
11986 0xfe, 0x83, 0x80, 0xfe,
11987 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91, 0x63,
11988 0x27, 0xfe, 0x40, 0x59,
11989 0xfe, 0xc1, 0x59, 0x77, 0xd7, 0x05, 0x54, 0x31, 0x55, 0x0c, 0x7b, 0x18,
11990 0x7c, 0xbe, 0x54, 0xbf,
11991 0x55, 0x01, 0xa8, 0xad, 0x63, 0x27, 0x12, 0x58, 0xc0, 0x38, 0xc1, 0x4e,
11992 0x79, 0x56, 0x68, 0x57,
11993 0xf4, 0xf5, 0xfe, 0x04, 0xfa, 0x38, 0xfe, 0x05, 0xfa, 0x4e, 0x01, 0xa5,
11994 0xa2, 0x23, 0x0c, 0x7b,
11995 0x0c, 0x7c, 0x79, 0x56, 0x68, 0x57, 0xfe, 0x12, 0x10, 0x09, 0x04, 0x19,
11996 0x16, 0xd7, 0x79, 0x39,
11997 0x68, 0x3a, 0x09, 0x04, 0xfe, 0xf7, 0x00, 0x35, 0x05, 0x52, 0x31, 0x53,
11998 0xfe, 0x10, 0x58, 0xfe,
11999 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x02, 0x6d, 0x09, 0x04,
12000 0x19, 0x16, 0xd7, 0x09,
12001 0x04, 0xfe, 0xf7, 0x00, 0x35, 0xfe, 0x3a, 0x55, 0xfe, 0x19, 0x81, 0x5f,
12002 0xfe, 0x10, 0x90, 0xfe,
12003 0x92, 0x90, 0xfe, 0xd7, 0x10, 0x2f, 0x07, 0x9b, 0x16, 0xfe, 0xc6, 0x08,
12004 0x11, 0x9b, 0x09, 0x04,
12005 0x0b, 0xfe, 0x14, 0x13, 0x05, 0x39, 0x31, 0x3a, 0x77, 0xfe, 0xc6, 0x08,
12006 0xfe, 0x0c, 0x58, 0xfe,
12007 0x8d, 0x58, 0x02, 0x6d, 0x23, 0x47, 0xfe, 0x19, 0x80, 0xde, 0x09, 0x04,
12008 0x0b, 0xfe, 0x1a, 0x12,
12009 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xe9, 0xb5, 0xfe, 0xd1, 0xf0, 0xd9,
12010 0x14, 0x7a, 0x01, 0x33,
12011 0x0f, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19, 0xbe, 0x39,
12012 0xfe, 0xed, 0x19, 0xbf,
12013 0x3a, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xe9, 0x1c, 0xfe, 0x00, 0xff,
12014 0x34, 0xfe, 0x74, 0x10,
12015 0xb5, 0xfe, 0xd2, 0xf0, 0xfe, 0xb2, 0x0a, 0xfe, 0x76, 0x18, 0x1c, 0x1a,
12016 0x84, 0x05, 0xcb, 0x1c,
12017 0x06, 0xfe, 0x08, 0x13, 0x0f, 0xfe, 0x16, 0x00, 0x02, 0x5a, 0xfe, 0xd1,
12018 0xf0, 0xfe, 0xc4, 0x0a,
12019 0x14, 0x7a, 0x01, 0x33, 0x0f, 0xfe, 0x17, 0x00, 0xfe, 0x42, 0x10, 0xfe,
12020 0xce, 0xf0, 0xfe, 0xca,
12021 0x0a, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xd6, 0x0a, 0x0f, 0xfe,
12022 0x22, 0x00, 0x02, 0x5a,
12023 0xfe, 0xcb, 0xf0, 0xfe, 0xe2, 0x0a, 0x0f, 0xfe, 0x24, 0x00, 0x02, 0x5a,
12024 0xfe, 0xd0, 0xf0, 0xfe,
12025 0xec, 0x0a, 0x0f, 0x93, 0xdc, 0xfe, 0xcf, 0xf0, 0xfe, 0xf6, 0x0a, 0x0f,
12026 0x4c, 0xfe, 0x10, 0x10,
12027 0xfe, 0xcc, 0xf0, 0xd9, 0x61, 0x04, 0x19, 0x3b, 0x0f, 0xfe, 0x12, 0x00,
12028 0x2a, 0x13, 0xfe, 0x4e,
12029 0x11, 0x65, 0xfe, 0x0c, 0x0b, 0xfe, 0x9e, 0xf0, 0xfe, 0x20, 0x0b, 0xb1,
12030 0x16, 0x32, 0x2a, 0x73,
12031 0xdd, 0xb8, 0x22, 0xb9, 0x22, 0x2a, 0xec, 0x65, 0xfe, 0x2c, 0x0b, 0x25,
12032 0x32, 0x8c, 0xfe, 0x48,
12033 0x0b, 0x8d, 0x81, 0xb8, 0xd4, 0xb9, 0xd4, 0x02, 0x22, 0x01, 0x43, 0xfe,
12034 0xdb, 0x10, 0x11, 0xfe,
12035 0xe8, 0x00, 0xaa, 0xab, 0x70, 0xbc, 0x7d, 0xbd, 0x7f, 0xfe, 0x89, 0xf0,
12036 0x22, 0x30, 0x2e, 0xd8,
12037 0xbc, 0x7d, 0xbd, 0x7f, 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd6, 0xb1,
12038 0x45, 0x0f, 0xfe, 0x42,
12039 0x00, 0x02, 0x5a, 0x78, 0x06, 0xfe, 0x81, 0x49, 0x16, 0xfe, 0x38, 0x0c,
12040 0x09, 0x04, 0x0b, 0xfe,
12041 0x44, 0x13, 0x0f, 0x00, 0x4b, 0x0b, 0xfe, 0x54, 0x12, 0x4b, 0xfe, 0x28,
12042 0x00, 0x21, 0xfe, 0xa6,
12043 0x0c, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x3e, 0xfe, 0x28, 0x00,
12044 0xfe, 0xe2, 0x10, 0x01,
12045 0xe7, 0x01, 0xe8, 0x0a, 0x99, 0x01, 0xfe, 0x32, 0x0e, 0x59, 0x11, 0x2d,
12046 0x01, 0x6f, 0x02, 0x29,
12047 0x0f, 0xfe, 0x44, 0x00, 0x4b, 0x0b, 0xdf, 0x3e, 0x0b, 0xfe, 0xb4, 0x10,
12048 0x01, 0x86, 0x3e, 0x0b,
12049 0xfe, 0xaa, 0x10, 0x01, 0x86, 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xa3,
12050 0x3e, 0x0b, 0x0f, 0xfe,
12051 0x43, 0x00, 0xfe, 0x96, 0x10, 0x09, 0x4a, 0x0b, 0x35, 0x01, 0xe7, 0x01,
12052 0xe8, 0x59, 0x11, 0x2d,
12053 0x01, 0x6f, 0x67, 0x0b, 0x59, 0x3c, 0x8a, 0x02, 0xfe, 0x2a, 0x03, 0x09,
12054 0x04, 0x0b, 0x84, 0x3e,
12055 0x0b, 0x0f, 0x00, 0xfe, 0x5c, 0x10, 0x61, 0x04, 0x1b, 0xfe, 0x58, 0x12,
12056 0x09, 0x04, 0x1b, 0xfe,
12057 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x5c, 0x0c, 0xfe,
12058 0x1c, 0x1c, 0xfe, 0x9d,
12059 0xf0, 0xfe, 0x62, 0x0c, 0x09, 0x4a, 0x1b, 0x35, 0xfe, 0xa9, 0x10, 0x0f,
12060 0xfe, 0x15, 0x00, 0xfe,
12061 0x04, 0xe6, 0x0b, 0x5f, 0x5c, 0x0f, 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10,
12062 0x0f, 0xfe, 0x47, 0x00,
12063 0xa1, 0x0f, 0xfe, 0x41, 0x00, 0xa0, 0x0f, 0xfe, 0x24, 0x00, 0x87, 0xaa,
12064 0xab, 0x70, 0x05, 0x6b,
12065 0x28, 0x21, 0xd1, 0x5f, 0xfe, 0x04, 0xe6, 0x1b, 0xfe, 0x9d, 0x41, 0xfe,
12066 0x1c, 0x42, 0x59, 0x01,
12067 0xda, 0x02, 0x29, 0xea, 0x14, 0x0b, 0x37, 0x95, 0xa9, 0x14, 0xfe, 0x31,
12068 0x00, 0x37, 0x97, 0x01,
12069 0xfe, 0x54, 0x0f, 0x02, 0xd0, 0x3c, 0xfe, 0x06, 0xec, 0xc9, 0xee, 0x3e,
12070 0x1d, 0xfe, 0xce, 0x45,
12071 0x34, 0x3c, 0xfe, 0x06, 0xea, 0xc9, 0xfe, 0x47, 0x4b, 0x89, 0xfe, 0x75,
12072 0x57, 0x05, 0x51, 0xfe,
12073 0x98, 0x56, 0xfe, 0x38, 0x12, 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x44, 0x48,
12074 0x46, 0x09, 0x04, 0x1d,
12075 0xfe, 0x1a, 0x13, 0x0a, 0x40, 0x01, 0x0e, 0x47, 0xfe, 0x41, 0x58, 0x0a,
12076 0x99, 0x01, 0x0e, 0xfe,
12077 0x49, 0x54, 0x8e, 0xfe, 0x2a, 0x0d, 0x02, 0xfe, 0x2a, 0x03, 0x0a, 0x51,
12078 0xfe, 0xee, 0x14, 0xee,
12079 0x3e, 0x1d, 0xfe, 0xce, 0x45, 0x34, 0x3c, 0xfe, 0xce, 0x47, 0xfe, 0xad,
12080 0x13, 0x02, 0x29, 0x1e,
12081 0x20, 0x07, 0x10, 0xfe, 0x9e, 0x12, 0x23, 0x12, 0x4d, 0x12, 0x94, 0x12,
12082 0xce, 0x1e, 0x2d, 0x47,
12083 0x37, 0x2d, 0xb1, 0xe0, 0xfe, 0xbc, 0xf0, 0xfe, 0xec, 0x0d, 0x13, 0x06,
12084 0x12, 0x4d, 0x01, 0xfe,
12085 0xe2, 0x15, 0x05, 0xfe, 0x38, 0x01, 0x31, 0xfe, 0x3a, 0x01, 0x77, 0xfe,
12086 0xf0, 0x0d, 0xfe, 0x02,
12087 0xec, 0xce, 0x62, 0x00, 0x5d, 0xfe, 0x04, 0xec, 0x20, 0x46, 0xfe, 0x05,
12088 0xf6, 0xfe, 0x34, 0x01,
12089 0x01, 0xfe, 0x52, 0x16, 0xfb, 0xfe, 0x48, 0xf4, 0x0d, 0xfe, 0x18, 0x13,
12090 0xaf, 0xfe, 0x02, 0xea,
12091 0xce, 0x62, 0x7a, 0xfe, 0xc5, 0x13, 0x14, 0x1b, 0x37, 0x95, 0xa9, 0x5c,
12092 0x05, 0xfe, 0x38, 0x01,
12093 0x1c, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x05, 0xfe, 0x3a, 0x01,
12094 0x0c, 0xfe, 0x62, 0x01,
12095 0x3d, 0x12, 0x20, 0x24, 0x06, 0x12, 0x2d, 0x11, 0x2d, 0x8a, 0x13, 0x06,
12096 0x03, 0x23, 0x03, 0x1e,
12097 0x4d, 0xfe, 0xf7, 0x12, 0x1e, 0x94, 0xac, 0x12, 0x94, 0x07, 0x7a, 0xfe,
12098 0x71, 0x13, 0xfe, 0x24,
12099 0x1c, 0x14, 0x1a, 0x37, 0x95, 0xa9, 0xfe, 0xd9, 0x10, 0xb6, 0xfe, 0x03,
12100 0xdc, 0xfe, 0x73, 0x57,
12101 0xfe, 0x80, 0x5d, 0x03, 0xb6, 0xfe, 0x03, 0xdc, 0xfe, 0x5b, 0x57, 0xfe,
12102 0x80, 0x5d, 0x03, 0xfe,
12103 0x03, 0x57, 0xb6, 0x23, 0xfe, 0x00, 0xcc, 0x03, 0xfe, 0x03, 0x57, 0xb6,
12104 0x75, 0x03, 0x09, 0x04,
12105 0x4c, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13,
12106 0xfe, 0x1e, 0x80, 0xe1,
12107 0xfe, 0x1d, 0x80, 0xa4, 0xfe, 0x0c, 0x90, 0xfe, 0x0e, 0x13, 0xfe, 0x0e,
12108 0x90, 0xa3, 0xfe, 0x3c,
12109 0x90, 0xfe, 0x30, 0xf4, 0x0b, 0xfe, 0x3c, 0x50, 0xa0, 0x01, 0xfe, 0x82,
12110 0x16, 0x2f, 0x07, 0x2d,
12111 0xe0, 0x01, 0xfe, 0xbc, 0x15, 0x09, 0x04, 0x1d, 0x45, 0x01, 0xe7, 0x01,
12112 0xe8, 0x11, 0xfe, 0xe9,
12113 0x00, 0x09, 0x04, 0x4c, 0xfe, 0x2c, 0x13, 0x01, 0xfe, 0x14, 0x16, 0xfe,
12114 0x1e, 0x1c, 0xfe, 0x14,
12115 0x90, 0xfe, 0x96, 0x90, 0x0c, 0xfe, 0x64, 0x01, 0x18, 0xfe, 0x66, 0x01,
12116 0x09, 0x04, 0x4f, 0xfe,
12117 0x12, 0x12, 0xfe, 0x03, 0x80, 0x74, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80,
12118 0x40, 0x12, 0x20, 0x63,
12119 0x27, 0x11, 0xc8, 0x59, 0x1e, 0x20, 0xed, 0x76, 0x20, 0x03, 0xfe, 0x08,
12120 0x1c, 0x05, 0xfe, 0xac,
12121 0x00, 0xfe, 0x06, 0x58, 0x05, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x05,
12122 0xfe, 0xb0, 0x00, 0xfe,
12123 0x08, 0x58, 0x05, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c,
12124 0x24, 0x69, 0x12, 0xc9,
12125 0x23, 0x0c, 0x50, 0x0c, 0x3f, 0x13, 0x40, 0x48, 0x5f, 0x17, 0x1d, 0xfe,
12126 0x90, 0x4d, 0xfe, 0x91,
12127 0x54, 0x21, 0xfe, 0x08, 0x0f, 0x3e, 0x10, 0x13, 0x42, 0x48, 0x17, 0x4c,
12128 0xfe, 0x90, 0x4d, 0xfe,
12129 0x91, 0x54, 0x21, 0xfe, 0x1e, 0x0f, 0x24, 0x10, 0x12, 0x20, 0x78, 0x2c,
12130 0x46, 0x1e, 0x20, 0xed,
12131 0x76, 0x20, 0x11, 0xc8, 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x32, 0x0f, 0xea,
12132 0x70, 0xfe, 0x14, 0x1c,
12133 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x03, 0x3c, 0xfe, 0x0c, 0x14, 0xee,
12134 0xfe, 0x07, 0xe6, 0x1d,
12135 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x03, 0x01, 0x86, 0x78, 0x2c, 0x46,
12136 0xfa, 0xef, 0xfe, 0x42,
12137 0x13, 0x2f, 0x07, 0x2d, 0xfe, 0x34, 0x13, 0x0a, 0x42, 0x01, 0x0e, 0xb0,
12138 0xfe, 0x36, 0x12, 0xf0,
12139 0xfe, 0x45, 0x48, 0x01, 0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13,
12140 0x3d, 0x75, 0x07, 0x10,
12141 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x6f, 0xfe, 0x0e,
12142 0x10, 0x07, 0x7e, 0x45,
12143 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x6c, 0x0f, 0x03, 0xfe, 0x44, 0x58, 0x74,
12144 0xfe, 0x01, 0xec, 0x97,
12145 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1b, 0x76,
12146 0x27, 0x01, 0xda, 0xfe,
12147 0xdd, 0x10, 0x2a, 0xbc, 0x7d, 0xbd, 0x7f, 0x30, 0x2e, 0xd5, 0x07, 0x1b,
12148 0xfe, 0x48, 0x12, 0x07,
12149 0x0b, 0xfe, 0x56, 0x12, 0x07, 0x1a, 0xfe, 0x30, 0x12, 0x07, 0xc2, 0x16,
12150 0xfe, 0x3e, 0x11, 0x07,
12151 0xfe, 0x23, 0x00, 0x16, 0xfe, 0x4a, 0x11, 0x07, 0x06, 0x16, 0xfe, 0xa8,
12152 0x11, 0x07, 0x19, 0xfe,
12153 0x12, 0x12, 0x07, 0x00, 0x16, 0x22, 0x14, 0xc2, 0x01, 0x33, 0x9f, 0x2b,
12154 0x01, 0x08, 0x8c, 0x43,
12155 0x03, 0x2b, 0xfe, 0x62, 0x08, 0x0a, 0xca, 0x01, 0xfe, 0x32, 0x0e, 0x11,
12156 0x7e, 0x02, 0x29, 0x2b,
12157 0x2f, 0x07, 0x9b, 0xfe, 0xd9, 0x13, 0x79, 0x39, 0x68, 0x3a, 0x77, 0xfe,
12158 0xfc, 0x10, 0x09, 0x04,
12159 0x6a, 0xfe, 0x72, 0x12, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x8e, 0xfe,
12160 0xc6, 0x10, 0x1e, 0x58,
12161 0xfe, 0x26, 0x13, 0x05, 0x7b, 0x31, 0x7c, 0x77, 0xfe, 0x82, 0x0c, 0x0c,
12162 0x54, 0x18, 0x55, 0x23,
12163 0x0c, 0x7b, 0x0c, 0x7c, 0x01, 0xa8, 0x24, 0x69, 0x73, 0x12, 0x58, 0x01,
12164 0xa5, 0xc0, 0x38, 0xc1,
12165 0x4e, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x38, 0xfe,
12166 0x05, 0xfa, 0x4e, 0xfe,
12167 0x91, 0x10, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56,
12168 0x0c, 0x56, 0x18, 0x57,
12169 0x83, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x05, 0x52, 0x31, 0x53, 0xfe,
12170 0x00, 0x56, 0xfe, 0xa1,
12171 0x56, 0x0c, 0x52, 0x18, 0x53, 0x09, 0x04, 0x6a, 0xfe, 0x1e, 0x12, 0x1e,
12172 0x58, 0xfe, 0x1f, 0x40,
12173 0x05, 0x54, 0x31, 0x55, 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x05, 0x56,
12174 0x31, 0x57, 0xfe, 0x44,
12175 0x50, 0xfe, 0xc6, 0x50, 0x05, 0x52, 0x31, 0x53, 0xfe, 0x08, 0x50, 0xfe,
12176 0x8a, 0x50, 0x05, 0x39,
12177 0x31, 0x3a, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x5c, 0x24, 0x06,
12178 0x12, 0xcd, 0x02, 0x5b,
12179 0x2b, 0x01, 0x08, 0x1f, 0x44, 0x30, 0x2e, 0xd5, 0x07, 0x06, 0x21, 0x44,
12180 0x2f, 0x07, 0x9b, 0x21,
12181 0x5b, 0x01, 0x6e, 0x1c, 0x3d, 0x16, 0x44, 0x09, 0x04, 0x0b, 0xe2, 0x79,
12182 0x39, 0x68, 0x3a, 0xfe,
12183 0x0a, 0x55, 0x34, 0xfe, 0x8b, 0x55, 0xbe, 0x39, 0xbf, 0x3a, 0xfe, 0x0c,
12184 0x51, 0xfe, 0x8e, 0x51,
12185 0x02, 0x5b, 0xfe, 0x19, 0x81, 0xaf, 0xfe, 0x19, 0x41, 0x02, 0x5b, 0x2b,
12186 0x01, 0x08, 0x25, 0x32,
12187 0x1f, 0xa2, 0x30, 0x2e, 0xd8, 0x4b, 0x1a, 0xfe, 0xa6, 0x12, 0x4b, 0x0b,
12188 0x3b, 0x02, 0x44, 0x01,
12189 0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e, 0xd6, 0x07, 0x1a, 0x21, 0x44,
12190 0x01, 0x08, 0x1f, 0xa2,
12191 0x30, 0x2e, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x60, 0x05, 0xfe, 0x9c,
12192 0x00, 0x28, 0x84, 0x49,
12193 0x04, 0x19, 0x34, 0x9f, 0xfe, 0xbb, 0x45, 0x4b, 0x00, 0x45, 0x3e, 0x06,
12194 0x78, 0x3d, 0xfe, 0xda,
12195 0x14, 0x01, 0x6e, 0x87, 0xfe, 0x4b, 0x45, 0xe2, 0x2f, 0x07, 0x9a, 0xe1,
12196 0x05, 0xc6, 0x28, 0x84,
12197 0x05, 0x3f, 0x28, 0x34, 0x5e, 0x02, 0x5b, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8,
12198 0x14, 0xfe, 0x03, 0x17,
12199 0x05, 0x50, 0xb4, 0x0c, 0x50, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01,
12200 0xfe, 0xaa, 0x14, 0x02,
12201 0x5c, 0x01, 0x08, 0x25, 0x32, 0x1f, 0x44, 0x30, 0x2e, 0xd6, 0x07, 0x06,
12202 0x21, 0x44, 0x01, 0xfe,
12203 0x8e, 0x13, 0xfe, 0x42, 0x58, 0xfe, 0x82, 0x14, 0xfe, 0xa4, 0x14, 0x87,
12204 0xfe, 0x4a, 0xf4, 0x0b,
12205 0x16, 0x44, 0xfe, 0x4a, 0xf4, 0x06, 0xfe, 0x0c, 0x12, 0x2f, 0x07, 0x9a,
12206 0x85, 0x02, 0x5b, 0x05,
12207 0x3f, 0xb4, 0x0c, 0x3f, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe,
12208 0xd8, 0x14, 0x02, 0x5c,
12209 0x13, 0x06, 0x65, 0xfe, 0xca, 0x12, 0x26, 0xfe, 0xe0, 0x12, 0x72, 0xf1,
12210 0x01, 0x08, 0x23, 0x72,
12211 0x03, 0x8f, 0xfe, 0xdc, 0x12, 0x25, 0xfe, 0xdc, 0x12, 0x1f, 0xfe, 0xca,
12212 0x12, 0x5e, 0x2b, 0x01,
12213 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b,
12214 0x1c, 0xfe, 0xff, 0x7f,
12215 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00,
12216 0x57, 0x48, 0x8b, 0x1c,
12217 0x3d, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02,
12218 0x00, 0x57, 0x48, 0x8b,
12219 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0xfe, 0x0b, 0x58,
12220 0x03, 0x0a, 0x50, 0x01,
12221 0x82, 0x0a, 0x3f, 0x01, 0x82, 0x03, 0xfc, 0x1c, 0x10, 0xff, 0x03, 0x00,
12222 0x54, 0xfe, 0x00, 0xf4,
12223 0x19, 0x48, 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe,
12224 0x03, 0x7c, 0x63, 0x27,
12225 0x0c, 0x52, 0x18, 0x53, 0xbe, 0x56, 0xbf, 0x57, 0x03, 0xfe, 0x62, 0x08,
12226 0xfe, 0x82, 0x4a, 0xfe,
12227 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x74, 0x03, 0x01, 0xfe, 0x14, 0x18, 0xfe,
12228 0x42, 0x48, 0x5f, 0x60,
12229 0x89, 0x01, 0x08, 0x1f, 0xfe, 0xa2, 0x14, 0x30, 0x2e, 0xd8, 0x01, 0x08,
12230 0x1f, 0xfe, 0xa2, 0x14,
12231 0x30, 0x2e, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x05, 0xc6, 0x28, 0xfe,
12232 0xcc, 0x12, 0x49, 0x04,
12233 0x1b, 0xfe, 0xc4, 0x13, 0x23, 0x62, 0x1b, 0xe2, 0x4b, 0xc3, 0x64, 0xfe,
12234 0xe8, 0x13, 0x3b, 0x13,
12235 0x06, 0x17, 0xc3, 0x78, 0xdb, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55,
12236 0xa1, 0xff, 0x02, 0x83,
12237 0x55, 0x62, 0x1a, 0xa4, 0xbb, 0xfe, 0x30, 0x00, 0x8e, 0xe4, 0x17, 0x2c,
12238 0x13, 0x06, 0xfe, 0x56,
12239 0x10, 0x62, 0x0b, 0xe1, 0xbb, 0xfe, 0x64, 0x00, 0x8e, 0xe4, 0x0a, 0xfe,
12240 0x64, 0x00, 0x17, 0x93,
12241 0x13, 0x06, 0xfe, 0x28, 0x10, 0x62, 0x06, 0xfe, 0x60, 0x13, 0xbb, 0xfe,
12242 0xc8, 0x00, 0x8e, 0xe4,
12243 0x0a, 0xfe, 0xc8, 0x00, 0x17, 0x4d, 0x13, 0x06, 0x83, 0xbb, 0xfe, 0x90,
12244 0x01, 0xba, 0xfe, 0x4e,
12245 0x14, 0x89, 0xfe, 0x12, 0x10, 0xfe, 0x43, 0xf4, 0x94, 0xfe, 0x56, 0xf0,
12246 0xfe, 0x60, 0x14, 0xfe,
12247 0x04, 0xf4, 0x6c, 0xfe, 0x43, 0xf4, 0x93, 0xfe, 0xf3, 0x10, 0xf9, 0x01,
12248 0xfe, 0x22, 0x13, 0x1c,
12249 0x3d, 0xfe, 0x10, 0x13, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x69, 0xba,
12250 0xfe, 0x9c, 0x14, 0xb7,
12251 0x69, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x19, 0xba,
12252 0xfe, 0x9c, 0x14, 0xb7,
12253 0x19, 0x83, 0x60, 0x23, 0xfe, 0x4d, 0xf4, 0x00, 0xdf, 0x89, 0x13, 0x06,
12254 0xfe, 0xb4, 0x56, 0xfe,
12255 0xc3, 0x58, 0x03, 0x60, 0x13, 0x0b, 0x03, 0x15, 0x06, 0x01, 0x08, 0x26,
12256 0xe5, 0x15, 0x0b, 0x01,
12257 0x08, 0x26, 0xe5, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xe5, 0x72, 0xfe, 0x89,
12258 0x49, 0x01, 0x08, 0x03,
12259 0x15, 0x06, 0x01, 0x08, 0x26, 0xa6, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xa6,
12260 0x15, 0x06, 0x01, 0x08,
12261 0x26, 0xa6, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x26, 0xa6, 0x72, 0xfe, 0x89,
12262 0x4a, 0x01, 0x08, 0x03,
12263 0x60, 0x03, 0x1e, 0xcc, 0x07, 0x06, 0xfe, 0x44, 0x13, 0xad, 0x12, 0xcc,
12264 0xfe, 0x49, 0xf4, 0x00,
12265 0x3b, 0x72, 0x9f, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xf1, 0x01,
12266 0x08, 0x2f, 0x07, 0xfe,
12267 0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1f, 0xfe, 0x5a, 0x15, 0x23, 0x12, 0xcd,
12268 0x01, 0x43, 0x1e, 0xcd,
12269 0x07, 0x06, 0x45, 0x09, 0x4a, 0x06, 0x35, 0x03, 0x0a, 0x42, 0x01, 0x0e,
12270 0xed, 0x88, 0x07, 0x10,
12271 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a,
12272 0x80, 0x01, 0x0e, 0x88,
12273 0xfe, 0x80, 0xe7, 0x10, 0x07, 0x10, 0x84, 0xfe, 0x45, 0x58, 0x01, 0xe3,
12274 0x88, 0x03, 0x0a, 0x42,
12275 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a, 0x42, 0x01, 0x0e,
12276 0xfe, 0x80, 0x80, 0xf2,
12277 0xfe, 0x49, 0xe4, 0x10, 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x0a, 0x51,
12278 0x01, 0x82, 0x03, 0x17,
12279 0x10, 0x71, 0x66, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde,
12280 0xfe, 0x24, 0x1c, 0xfe,
12281 0x1d, 0xf7, 0x1d, 0x90, 0xfe, 0xf6, 0x15, 0x01, 0xfe, 0xfc, 0x16, 0xe0,
12282 0x91, 0x1d, 0x66, 0xfe,
12283 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x03, 0xae, 0x21, 0xfe, 0xe6, 0x15, 0xfe,
12284 0xda, 0x10, 0x17, 0x10,
12285 0x71, 0x05, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x19, 0xfe, 0x18, 0x58,
12286 0x05, 0xfe, 0x66, 0x01,
12287 0xfe, 0x19, 0x58, 0x91, 0x19, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4, 0x06,
12288 0xfe, 0x3c, 0x50, 0x66,
12289 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x19, 0x90, 0xfe,
12290 0x40, 0x16, 0xfe, 0xb6,
12291 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x18, 0x16, 0xfe, 0x9c, 0x10, 0x17,
12292 0x10, 0x71, 0xfe, 0x83,
12293 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, 0x38, 0x90,
12294 0xfe, 0x62, 0x16, 0xfe,
12295 0x94, 0x14, 0xfe, 0x10, 0x13, 0x91, 0x38, 0x66, 0x1b, 0xfe, 0xaf, 0x19,
12296 0xfe, 0x98, 0xe7, 0x00,
12297 0x03, 0xae, 0x21, 0xfe, 0x56, 0x16, 0xfe, 0x6c, 0x10, 0x17, 0x10, 0x71,
12298 0xfe, 0x30, 0xbc, 0xfe,
12299 0xb2, 0xbc, 0x91, 0xc5, 0x66, 0x1b, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
12300 0xc5, 0x90, 0xfe, 0x9a,
12301 0x16, 0xfe, 0x5c, 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x86, 0x16, 0xfe,
12302 0x42, 0x10, 0xfe, 0x02,
12303 0xf6, 0x10, 0x71, 0xfe, 0x18, 0xfe, 0x54, 0xfe, 0x19, 0xfe, 0x55, 0xfc,
12304 0xfe, 0x1d, 0xf7, 0x4f,
12305 0x90, 0xfe, 0xc0, 0x16, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, 0x91, 0x4f,
12306 0x47, 0xfe, 0x83, 0x58,
12307 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x10, 0xfe, 0x81, 0xe7, 0x10, 0x11,
12308 0xfe, 0xdd, 0x00, 0x63,
12309 0x27, 0x03, 0x63, 0x27, 0xfe, 0x12, 0x45, 0x21, 0xfe, 0xb0, 0x16, 0x14,
12310 0x06, 0x37, 0x95, 0xa9,
12311 0x02, 0x29, 0xfe, 0x39, 0xf0, 0xfe, 0x04, 0x17, 0x23, 0x03, 0xfe, 0x7e,
12312 0x18, 0x1c, 0x1a, 0x5d,
12313 0x13, 0x0d, 0x03, 0x71, 0x05, 0xcb, 0x1c, 0x06, 0xfe, 0xef, 0x12, 0xfe,
12314 0xe1, 0x10, 0x78, 0x2c,
12315 0x46, 0x2f, 0x07, 0x2d, 0xfe, 0x3c, 0x13, 0xfe, 0x82, 0x14, 0xfe, 0x42,
12316 0x13, 0x3c, 0x8a, 0x0a,
12317 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x3e, 0x12, 0xf0, 0xfe, 0x45, 0x48, 0x01,
12318 0xe3, 0xfe, 0x00, 0xcc,
12319 0xb0, 0xfe, 0xf3, 0x13, 0x3d, 0x75, 0x07, 0x10, 0xa3, 0x0a, 0x80, 0x01,
12320 0x0e, 0xf2, 0x01, 0x6f,
12321 0xfe, 0x16, 0x10, 0x07, 0x7e, 0x85, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12,
12322 0xf6, 0xfe, 0xd6, 0xf0,
12323 0xfe, 0x24, 0x17, 0x17, 0x0b, 0x03, 0xfe, 0x9c, 0xe7, 0x0b, 0x0f, 0xfe,
12324 0x15, 0x00, 0x59, 0x76,
12325 0x27, 0x01, 0xda, 0x17, 0x06, 0x03, 0x3c, 0x8a, 0x09, 0x4a, 0x1d, 0x35,
12326 0x11, 0x2d, 0x01, 0x6f,
12327 0x17, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x79, 0xc7, 0x68,
12328 0xc8, 0xfe, 0x48, 0x55,
12329 0x34, 0xfe, 0xc9, 0x55, 0x03, 0x1e, 0x98, 0x73, 0x12, 0x98, 0x03, 0x0a,
12330 0x99, 0x01, 0x0e, 0xf0,
12331 0x0a, 0x40, 0x01, 0x0e, 0xfe, 0x49, 0x44, 0x16, 0xfe, 0xf0, 0x17, 0x73,
12332 0x75, 0x03, 0x0a, 0x42,
12333 0x01, 0x0e, 0x07, 0x10, 0x45, 0x0a, 0x51, 0x01, 0x9e, 0x0a, 0x40, 0x01,
12334 0x0e, 0x73, 0x75, 0x03,
12335 0xfe, 0x4e, 0xe4, 0x1a, 0x64, 0xfe, 0x24, 0x18, 0x05, 0xfe, 0x90, 0x00,
12336 0xfe, 0x3a, 0x45, 0x5b,
12337 0xfe, 0x4e, 0xe4, 0xc2, 0x64, 0xfe, 0x36, 0x18, 0x05, 0xfe, 0x92, 0x00,
12338 0xfe, 0x02, 0xe6, 0x1b,
12339 0xdc, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x64, 0xfe, 0x48, 0x18, 0x05,
12340 0xfe, 0x94, 0x00, 0xfe,
12341 0x02, 0xe6, 0x19, 0xfe, 0x08, 0x10, 0x05, 0xfe, 0x96, 0x00, 0xfe, 0x02,
12342 0xe6, 0x2c, 0xfe, 0x4e,
12343 0x45, 0xfe, 0x0c, 0x12, 0xaf, 0xff, 0x04, 0x68, 0x54, 0xde, 0x1c, 0x69,
12344 0x03, 0x07, 0x7a, 0xfe,
12345 0x5a, 0xf0, 0xfe, 0x74, 0x18, 0x24, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
12346 0x07, 0x1b, 0xfe, 0x5a,
12347 0xf0, 0xfe, 0x82, 0x18, 0x24, 0xc3, 0xfe, 0x26, 0x10, 0x07, 0x1a, 0x5d,
12348 0x24, 0x2c, 0xdc, 0x07,
12349 0x0b, 0x5d, 0x24, 0x93, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x5d, 0x24, 0x4d,
12350 0x9f, 0xad, 0x03, 0x14,
12351 0xfe, 0x09, 0x00, 0x01, 0x33, 0xfe, 0x04, 0xfe, 0x7d, 0x05, 0x7f, 0xf9,
12352 0x03, 0x25, 0xfe, 0xca,
12353 0x18, 0xfe, 0x14, 0xf0, 0x08, 0x65, 0xfe, 0xc6, 0x18, 0x03, 0xff, 0x1a,
12354 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070012355};
12356
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012357static unsigned short _adv_asc3550_size = sizeof(_adv_asc3550_buf); /* 0x13AD */
12358static ADV_DCNT _adv_asc3550_chksum = 0x04D52DDDUL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070012359
12360/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012361static unsigned char _adv_asc38C0800_buf[] = {
12362 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0x16, 0x18, 0xe4,
12363 0x01, 0x00, 0x48, 0xe4,
12364 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0xce, 0x19, 0x00, 0xfa, 0xff, 0xff,
12365 0x1c, 0x0f, 0x00, 0xf6,
12366 0x9e, 0xe7, 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x01, 0xfa, 0x01, 0xe6,
12367 0x09, 0xe7, 0x55, 0xf0,
12368 0x01, 0xf6, 0x03, 0x00, 0x04, 0x00, 0x10, 0x00, 0x1e, 0xf0, 0x85, 0xf0,
12369 0x18, 0xf4, 0x08, 0x00,
12370 0xbc, 0x00, 0x38, 0x54, 0x00, 0xec, 0xd5, 0xf0, 0x82, 0x0d, 0x00, 0xe6,
12371 0x86, 0xf0, 0xb1, 0xf0,
12372 0x98, 0x57, 0x01, 0xfc, 0xb4, 0x00, 0xd4, 0x01, 0x0c, 0x1c, 0x3e, 0x1c,
12373 0x3c, 0x00, 0xbb, 0x00,
12374 0x00, 0x10, 0xba, 0x19, 0x02, 0x80, 0x32, 0xf0, 0x7c, 0x0d, 0x02, 0x13,
12375 0xba, 0x13, 0x18, 0x40,
12376 0x00, 0x57, 0x01, 0xea, 0x02, 0xfc, 0x03, 0xfc, 0x3e, 0x00, 0x6c, 0x01,
12377 0x6e, 0x01, 0x74, 0x01,
12378 0x76, 0x01, 0xb9, 0x54, 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00,
12379 0xc0, 0x00, 0x01, 0x01,
12380 0x3e, 0x01, 0x7a, 0x01, 0xca, 0x08, 0xce, 0x10, 0x16, 0x11, 0x04, 0x12,
12381 0x08, 0x12, 0x02, 0x4a,
12382 0xbb, 0x55, 0x3c, 0x56, 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4,
12383 0x5d, 0xf0, 0x02, 0xfa,
12384 0x20, 0x00, 0x32, 0x00, 0x40, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01,
12385 0x68, 0x01, 0x6a, 0x01,
12386 0x70, 0x01, 0x72, 0x01, 0x78, 0x01, 0x7c, 0x01, 0x62, 0x0a, 0x86, 0x0d,
12387 0x06, 0x13, 0x4c, 0x1c,
12388 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x0c, 0x00,
12389 0x0f, 0x00, 0x47, 0x00,
12390 0xbe, 0x00, 0x00, 0x01, 0x20, 0x11, 0x5c, 0x16, 0x32, 0x1c, 0x38, 0x1c,
12391 0x4e, 0x1c, 0x10, 0x44,
12392 0x00, 0x4c, 0x04, 0xea, 0x5c, 0xf0, 0xa7, 0xf0, 0x04, 0xf6, 0x03, 0xfa,
12393 0x05, 0x00, 0x34, 0x00,
12394 0x36, 0x00, 0x98, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01, 0x4a, 0x0b,
12395 0x42, 0x0c, 0x12, 0x0f,
12396 0x0c, 0x10, 0x22, 0x11, 0x0a, 0x12, 0x04, 0x13, 0x30, 0x1c, 0x02, 0x48,
12397 0x00, 0x4e, 0x42, 0x54,
12398 0x44, 0x55, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
12399 0x59, 0xf0, 0xb8, 0xf0,
12400 0x4b, 0xf4, 0x06, 0xf7, 0x0e, 0xf7, 0x04, 0xfc, 0x05, 0xfc, 0x06, 0x00,
12401 0x19, 0x00, 0x33, 0x00,
12402 0x9b, 0x00, 0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00,
12403 0xe7, 0x00, 0xe2, 0x03,
12404 0x08, 0x0f, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10, 0x0a, 0x13, 0x0c, 0x13,
12405 0x12, 0x13, 0x24, 0x14,
12406 0x34, 0x14, 0x04, 0x16, 0x08, 0x16, 0xa4, 0x17, 0x20, 0x1c, 0x34, 0x1c,
12407 0x36, 0x1c, 0x08, 0x44,
12408 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54,
12409 0x3a, 0x55, 0x83, 0x55,
12410 0xe5, 0x55, 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0,
12411 0x0c, 0xf0, 0x04, 0xf8,
12412 0x05, 0xf8, 0x07, 0x00, 0x0a, 0x00, 0x1c, 0x00, 0x1e, 0x00, 0x9e, 0x00,
12413 0xa8, 0x00, 0xaa, 0x00,
12414 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01, 0x7e, 0x01,
12415 0xc4, 0x01, 0xc6, 0x01,
12416 0x80, 0x02, 0x5e, 0x03, 0xee, 0x04, 0x9a, 0x06, 0xf8, 0x07, 0x62, 0x08,
12417 0x68, 0x08, 0x69, 0x08,
12418 0xd6, 0x08, 0xe9, 0x09, 0xfa, 0x0b, 0x2e, 0x0f, 0x12, 0x10, 0x1a, 0x10,
12419 0xed, 0x10, 0xf1, 0x10,
12420 0x2a, 0x11, 0x06, 0x12, 0x0c, 0x12, 0x3e, 0x12, 0x10, 0x13, 0x16, 0x13,
12421 0x1e, 0x13, 0x46, 0x14,
12422 0x76, 0x14, 0x82, 0x14, 0x36, 0x15, 0xca, 0x15, 0x6b, 0x18, 0xbe, 0x18,
12423 0xca, 0x18, 0xe6, 0x19,
12424 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40, 0x0e, 0x47, 0xfe, 0x9c,
12425 0xf0, 0x2b, 0x02, 0xfe,
12426 0xac, 0x0d, 0xff, 0x10, 0x00, 0x00, 0xd7, 0xfe, 0xe8, 0x19, 0x00, 0xd6,
12427 0xfe, 0x84, 0x01, 0xff,
12428 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
12429 0x00, 0xfe, 0x57, 0x24,
12430 0x00, 0xfe, 0x4c, 0x00, 0x5b, 0xff, 0x04, 0x00, 0x00, 0x11, 0xff, 0x09,
12431 0x00, 0x00, 0xff, 0x08,
12432 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
12433 0xff, 0xff, 0xff, 0x11,
12434 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
12435 0xfe, 0x04, 0xf7, 0xd6,
12436 0x2c, 0x99, 0x0a, 0x01, 0xfe, 0xc2, 0x0f, 0xfe, 0x04, 0xf7, 0xd6, 0x99,
12437 0x0a, 0x42, 0x2c, 0xfe,
12438 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0xfe, 0x20, 0xf0, 0xa7, 0xfe, 0x91, 0xf0,
12439 0xfe, 0xf4, 0x01, 0xfe,
12440 0x90, 0xf0, 0xfe, 0xf4, 0x01, 0xfe, 0x8f, 0xf0, 0xa7, 0x03, 0x5d, 0x4d,
12441 0x02, 0xfe, 0xc8, 0x0d,
12442 0x01, 0xfe, 0x38, 0x0e, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28,
12443 0x1c, 0x03, 0xfe, 0xa6,
12444 0x00, 0xfe, 0xd3, 0x12, 0x41, 0x14, 0xfe, 0xa6, 0x00, 0xc2, 0xfe, 0x48,
12445 0xf0, 0xfe, 0x8a, 0x02,
12446 0xfe, 0x49, 0xf0, 0xfe, 0xa4, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc2, 0x02,
12447 0xfe, 0x46, 0xf0, 0xfe,
12448 0x54, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x5a, 0x02, 0xfe, 0x43, 0xf0, 0xfe,
12449 0x48, 0x02, 0xfe, 0x44,
12450 0xf0, 0xfe, 0x4c, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x50, 0x02, 0x18, 0x0a,
12451 0xaa, 0x18, 0x06, 0x14,
12452 0xa1, 0x02, 0x2b, 0xfe, 0x00, 0x1c, 0xe7, 0xfe, 0x02, 0x1c, 0xe6, 0xfe,
12453 0x1e, 0x1c, 0xfe, 0xe9,
12454 0x10, 0x01, 0xfe, 0x18, 0x18, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xce,
12455 0x09, 0x70, 0x01, 0xa8,
12456 0x02, 0x2b, 0x15, 0x59, 0x39, 0xa2, 0x01, 0xfe, 0x58, 0x10, 0x09, 0x70,
12457 0x01, 0x87, 0xfe, 0xbd,
12458 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
12459 0x58, 0x1c, 0x18, 0x06,
12460 0x14, 0xa1, 0x2c, 0x1c, 0x2b, 0xfe, 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0x23,
12461 0xfe, 0x98, 0x02, 0xfe,
12462 0x5a, 0x1c, 0xf8, 0xfe, 0x14, 0x1c, 0x15, 0xfe, 0x30, 0x00, 0x39, 0xa2,
12463 0x01, 0xfe, 0x48, 0x10,
12464 0x18, 0x06, 0x14, 0xa1, 0x02, 0xd7, 0x22, 0x20, 0x07, 0x11, 0x35, 0xfe,
12465 0x69, 0x10, 0x18, 0x06,
12466 0x14, 0xa1, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0x43, 0x13, 0x20, 0xfe, 0x05,
12467 0xf6, 0xce, 0x01, 0xfe,
12468 0x4a, 0x17, 0x08, 0x54, 0x58, 0x37, 0x12, 0x2f, 0x42, 0x92, 0x01, 0xfe,
12469 0x82, 0x16, 0x02, 0x2b,
12470 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66, 0x01, 0x73, 0xfe, 0x18, 0x10,
12471 0xfe, 0x41, 0x58, 0x09,
12472 0xa4, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x6b, 0xfe, 0x10, 0x03, 0x01, 0xfe,
12473 0x82, 0x16, 0x02, 0x2b,
12474 0x2c, 0x4f, 0xfe, 0x02, 0xe8, 0x2a, 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43,
12475 0xfe, 0x77, 0x57, 0xfe,
12476 0x27, 0xf0, 0xfe, 0xe0, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xa7,
12477 0xfe, 0x40, 0x1c, 0x1c,
12478 0xd9, 0xfe, 0x26, 0xf0, 0xfe, 0x5a, 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x48,
12479 0x03, 0xfe, 0x11, 0xf0,
12480 0xa7, 0xfe, 0xef, 0x10, 0xfe, 0x9f, 0xf0, 0xfe, 0x68, 0x03, 0xf9, 0x10,
12481 0xfe, 0x11, 0x00, 0x02,
12482 0x65, 0x2c, 0xfe, 0x48, 0x1c, 0xf9, 0x08, 0x05, 0x1b, 0xfe, 0x18, 0x13,
12483 0x21, 0x22, 0xa3, 0xb7,
12484 0x13, 0xa3, 0x09, 0x46, 0x01, 0x0e, 0xb7, 0x78, 0x01, 0xfe, 0xb4, 0x16,
12485 0x12, 0xd1, 0x1c, 0xd9,
12486 0xfe, 0x01, 0xf0, 0xd9, 0xfe, 0x82, 0xf0, 0xfe, 0x96, 0x03, 0xfa, 0x12,
12487 0xfe, 0xe4, 0x00, 0x27,
12488 0xfe, 0xa8, 0x03, 0x1c, 0x34, 0x1d, 0xfe, 0xb8, 0x03, 0x01, 0x4b, 0xfe,
12489 0x06, 0xf0, 0xfe, 0xc8,
12490 0x03, 0x95, 0x86, 0xfe, 0x0a, 0xf0, 0xfe, 0x8a, 0x06, 0x02, 0x24, 0x03,
12491 0x70, 0x28, 0x17, 0xfe,
12492 0xfa, 0x04, 0x15, 0x6d, 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02, 0xd8,
12493 0xf9, 0x2c, 0x99, 0x19,
12494 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c,
12495 0x74, 0x01, 0xaf, 0x8c,
12496 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x17, 0xda, 0x09, 0xd1, 0x01, 0x0e,
12497 0x8d, 0x51, 0x64, 0x79,
12498 0x2a, 0x03, 0x70, 0x28, 0xfe, 0x10, 0x12, 0x15, 0x6d, 0x01, 0x36, 0x7b,
12499 0xfe, 0x6a, 0x02, 0x02,
12500 0xd8, 0xc7, 0x81, 0xc8, 0x83, 0x1c, 0x24, 0x27, 0xfe, 0x40, 0x04, 0x1d,
12501 0xfe, 0x3c, 0x04, 0x3b,
12502 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e, 0x12, 0x2d, 0xff, 0x02,
12503 0x00, 0x10, 0x01, 0x0b,
12504 0x1d, 0xfe, 0xe4, 0x04, 0x2d, 0x01, 0x0b, 0x1d, 0x24, 0x33, 0x31, 0xde,
12505 0xfe, 0x4c, 0x44, 0xfe,
12506 0x4c, 0x12, 0x51, 0xfe, 0x44, 0x48, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b,
12507 0xda, 0x4f, 0x79, 0x2a,
12508 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x62, 0x13, 0x08, 0x05, 0x1b,
12509 0xfe, 0x2a, 0x13, 0x32,
12510 0x07, 0x82, 0xfe, 0x52, 0x13, 0xfe, 0x20, 0x10, 0x0f, 0x6f, 0xfe, 0x4c,
12511 0x54, 0x6b, 0xda, 0xfe,
12512 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x40, 0x13, 0x08, 0x05, 0x1b, 0xfe,
12513 0x08, 0x13, 0x32, 0x07,
12514 0x82, 0xfe, 0x30, 0x13, 0x08, 0x05, 0x1b, 0xfe, 0x1c, 0x12, 0x15, 0x9d,
12515 0x08, 0x05, 0x06, 0x4d,
12516 0x15, 0xfe, 0x0d, 0x00, 0x01, 0x36, 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24,
12517 0x2d, 0x12, 0xfe, 0xe6,
12518 0x00, 0xfe, 0x1c, 0x90, 0xfe, 0x40, 0x5c, 0x04, 0x15, 0x9d, 0x01, 0x36,
12519 0x02, 0x2b, 0xfe, 0x42,
12520 0x5b, 0x99, 0x19, 0xfe, 0x46, 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57,
12521 0xfe, 0x87, 0x80, 0xfe,
12522 0x31, 0xe4, 0x5b, 0x08, 0x05, 0x0a, 0xfe, 0x84, 0x13, 0xfe, 0x20, 0x80,
12523 0x07, 0x19, 0xfe, 0x7c,
12524 0x12, 0x53, 0x05, 0x06, 0xfe, 0x6c, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x28,
12525 0x17, 0xfe, 0x90, 0x05,
12526 0xfe, 0x31, 0xe4, 0x5a, 0x53, 0x05, 0x0a, 0xfe, 0x56, 0x13, 0x03, 0xfe,
12527 0xa0, 0x00, 0x28, 0xfe,
12528 0x4e, 0x12, 0x67, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x48, 0x05, 0x1c,
12529 0x34, 0xfe, 0x89, 0x48,
12530 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x56, 0x05, 0x26, 0xfe, 0xa8, 0x05,
12531 0x12, 0xfe, 0xe3, 0x00,
12532 0x21, 0x53, 0xfe, 0x4a, 0xf0, 0xfe, 0x76, 0x05, 0xfe, 0x49, 0xf0, 0xfe,
12533 0x70, 0x05, 0x88, 0x25,
12534 0xfe, 0x21, 0x00, 0xab, 0x25, 0xfe, 0x22, 0x00, 0xaa, 0x25, 0x58, 0xfe,
12535 0x09, 0x48, 0xff, 0x02,
12536 0x00, 0x10, 0x27, 0xfe, 0x86, 0x05, 0x26, 0xfe, 0xa8, 0x05, 0xfe, 0xe2,
12537 0x08, 0x53, 0x05, 0xcb,
12538 0x4d, 0x01, 0xb0, 0x25, 0x06, 0x13, 0xd3, 0x39, 0xfe, 0x27, 0x01, 0x08,
12539 0x05, 0x1b, 0xfe, 0x22,
12540 0x12, 0x41, 0x01, 0xb2, 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe,
12541 0x0d, 0x00, 0x01, 0x36,
12542 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0xeb,
12543 0x03, 0x5c, 0x28, 0xfe,
12544 0x36, 0x13, 0x41, 0x01, 0xb2, 0x26, 0xfe, 0x18, 0x06, 0x09, 0x06, 0x53,
12545 0x05, 0x1f, 0xfe, 0x02,
12546 0x12, 0x50, 0x01, 0xfe, 0x9e, 0x15, 0x1d, 0xfe, 0x0e, 0x06, 0x12, 0xa5,
12547 0x01, 0x4b, 0x12, 0xfe,
12548 0xe5, 0x00, 0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x03, 0xcd, 0x28, 0xfe, 0x62,
12549 0x12, 0x03, 0x45, 0x28,
12550 0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x0c, 0x19, 0x01, 0xfe, 0x76, 0x19, 0xfe,
12551 0x43, 0x48, 0xc4, 0xcc,
12552 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0x8b, 0xc4,
12553 0x6e, 0x41, 0x01, 0xb2,
12554 0x26, 0xfe, 0x82, 0x06, 0x53, 0x05, 0x1a, 0xe9, 0x91, 0x09, 0x59, 0x01,
12555 0xfe, 0xcc, 0x15, 0x1d,
12556 0xfe, 0x78, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12, 0xfe, 0xe5, 0x00, 0x03,
12557 0x45, 0xc1, 0x0c, 0x45,
12558 0x18, 0x06, 0x01, 0xb2, 0xfa, 0x76, 0x74, 0x01, 0xaf, 0x8c, 0x12, 0xfe,
12559 0xe2, 0x00, 0x27, 0xdb,
12560 0x1c, 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0xb6, 0x06, 0x94, 0xfe, 0x6c, 0x07,
12561 0xfe, 0x06, 0xf0, 0xfe,
12562 0x74, 0x07, 0x95, 0x86, 0x02, 0x24, 0x08, 0x05, 0x0a, 0xfe, 0x2e, 0x12,
12563 0x16, 0x19, 0x01, 0x0b,
12564 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b,
12565 0xfe, 0x99, 0xa4, 0x01,
12566 0x0b, 0x16, 0x00, 0x02, 0xfe, 0x42, 0x08, 0x68, 0x05, 0x1a, 0xfe, 0x38,
12567 0x12, 0x08, 0x05, 0x1a,
12568 0xfe, 0x30, 0x13, 0x16, 0xfe, 0x1b, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01,
12569 0x0b, 0x16, 0x00, 0x01,
12570 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x06, 0x01, 0x0b, 0x16, 0x00, 0x02,
12571 0xe2, 0x6c, 0x58, 0xbe,
12572 0x50, 0xfe, 0x9a, 0x81, 0x55, 0x1b, 0x7a, 0xfe, 0x42, 0x07, 0x09, 0x1b,
12573 0xfe, 0x09, 0x6f, 0xba,
12574 0xfe, 0xca, 0x45, 0xfe, 0x32, 0x12, 0x69, 0x6d, 0x8b, 0x6c, 0x7f, 0x27,
12575 0xfe, 0x54, 0x07, 0x1c,
12576 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0x42, 0x07, 0x95, 0x86, 0x94, 0xfe, 0x6c,
12577 0x07, 0x02, 0x24, 0x01,
12578 0x4b, 0x02, 0xdb, 0x16, 0x1f, 0x02, 0xdb, 0xfe, 0x9c, 0xf7, 0xdc, 0xfe,
12579 0x2c, 0x90, 0xfe, 0xae,
12580 0x90, 0x56, 0xfe, 0xda, 0x07, 0x0c, 0x60, 0x14, 0x61, 0x08, 0x54, 0x5a,
12581 0x37, 0x22, 0x20, 0x07,
12582 0x11, 0xfe, 0x0e, 0x12, 0x8d, 0xfe, 0x80, 0x80, 0x39, 0x20, 0x6a, 0x2a,
12583 0xfe, 0x06, 0x10, 0xfe,
12584 0x83, 0xe7, 0xfe, 0x48, 0x00, 0xab, 0xfe, 0x03, 0x40, 0x08, 0x54, 0x5b,
12585 0x37, 0x01, 0xb3, 0xb8,
12586 0xfe, 0x1f, 0x40, 0x13, 0x62, 0x01, 0xef, 0xfe, 0x08, 0x50, 0xfe, 0x8a,
12587 0x50, 0xfe, 0x44, 0x51,
12588 0xfe, 0xc6, 0x51, 0x88, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0c, 0x5e,
12589 0x14, 0x5f, 0xfe, 0x0c,
12590 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x0c, 0x3d,
12591 0x14, 0x3e, 0xfe, 0x4a,
12592 0x10, 0x08, 0x05, 0x5a, 0xfe, 0x2a, 0x12, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
12593 0x90, 0x0c, 0x60, 0x14,
12594 0x61, 0x08, 0x05, 0x5b, 0x8b, 0x01, 0xb3, 0xfe, 0x1f, 0x80, 0x13, 0x62,
12595 0xfe, 0x44, 0x90, 0xfe,
12596 0xc6, 0x90, 0x0c, 0x3f, 0x14, 0x40, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90,
12597 0x0c, 0x5e, 0x14, 0x5f,
12598 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90, 0x0c, 0x3d, 0x14, 0x3e, 0x0c, 0x2e,
12599 0x14, 0x3c, 0x21, 0x0c,
12600 0x49, 0x0c, 0x63, 0x08, 0x54, 0x1f, 0x37, 0x2c, 0x0f, 0xfe, 0x4e, 0x11,
12601 0x27, 0xdd, 0xfe, 0x9e,
12602 0xf0, 0xfe, 0x76, 0x08, 0xbc, 0x17, 0x34, 0x2c, 0x77, 0xe6, 0xc5, 0xfe,
12603 0x9a, 0x08, 0xc6, 0xfe,
12604 0xb8, 0x08, 0x94, 0xfe, 0x8e, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x94, 0x08,
12605 0x95, 0x86, 0x02, 0x24,
12606 0x01, 0x4b, 0xfe, 0xc9, 0x10, 0x16, 0x1f, 0xfe, 0xc9, 0x10, 0x68, 0x05,
12607 0x06, 0xfe, 0x10, 0x12,
12608 0x68, 0x05, 0x0a, 0x4e, 0x08, 0x05, 0x0a, 0xfe, 0x90, 0x12, 0xfe, 0x2e,
12609 0x1c, 0x02, 0xfe, 0x18,
12610 0x0b, 0x68, 0x05, 0x06, 0x4e, 0x68, 0x05, 0x0a, 0xfe, 0x7a, 0x12, 0xfe,
12611 0x2c, 0x1c, 0xfe, 0xaa,
12612 0xf0, 0xfe, 0xd2, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0x00, 0x09, 0x02, 0xfe,
12613 0xde, 0x09, 0xfe, 0xb7,
12614 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0x02, 0xf6, 0x1a, 0x50, 0xfe, 0x70, 0x18,
12615 0xfe, 0xf1, 0x18, 0xfe,
12616 0x40, 0x55, 0xfe, 0xe1, 0x55, 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0xfe,
12617 0x14, 0x59, 0xfe, 0x95,
12618 0x59, 0x1c, 0x85, 0xfe, 0x8c, 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0xac, 0xf0,
12619 0xfe, 0xf0, 0x08, 0xb5,
12620 0xfe, 0xcb, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0x0c, 0x09, 0x02, 0xfe, 0x18,
12621 0x0b, 0xb6, 0xfe, 0xbf,
12622 0x10, 0xfe, 0x2b, 0xf0, 0x85, 0xf4, 0x1e, 0xfe, 0x00, 0xfe, 0xfe, 0x1c,
12623 0x12, 0xc2, 0xfe, 0xd2,
12624 0xf0, 0x85, 0xfe, 0x76, 0x18, 0x1e, 0x19, 0x17, 0x85, 0x03, 0xd2, 0x1e,
12625 0x06, 0x17, 0x85, 0xc5,
12626 0x4a, 0xc6, 0x4a, 0xb5, 0xb6, 0xfe, 0x89, 0x10, 0x74, 0x67, 0x2d, 0x15,
12627 0x9d, 0x01, 0x36, 0x10,
12628 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x65, 0x10, 0x80, 0x02, 0x65, 0xfe,
12629 0x98, 0x80, 0xfe, 0x19,
12630 0xe4, 0x0a, 0xfe, 0x1a, 0x12, 0x51, 0xfe, 0x19, 0x82, 0xfe, 0x6c, 0x18,
12631 0xfe, 0x44, 0x54, 0xbe,
12632 0xfe, 0x19, 0x81, 0xfe, 0x74, 0x18, 0x8f, 0x90, 0x17, 0xfe, 0xce, 0x08,
12633 0x02, 0x4a, 0x08, 0x05,
12634 0x5a, 0xec, 0x03, 0x2e, 0x29, 0x3c, 0x0c, 0x3f, 0x14, 0x40, 0x9b, 0x2e,
12635 0x9c, 0x3c, 0xfe, 0x6c,
12636 0x18, 0xfe, 0xed, 0x18, 0xfe, 0x44, 0x54, 0xfe, 0xe5, 0x54, 0x3a, 0x3f,
12637 0x3b, 0x40, 0x03, 0x49,
12638 0x29, 0x63, 0x8f, 0xfe, 0xe3, 0x54, 0xfe, 0x74, 0x18, 0xfe, 0xf5, 0x18,
12639 0x8f, 0xfe, 0xe3, 0x54,
12640 0x90, 0xc0, 0x56, 0xfe, 0xce, 0x08, 0x02, 0x4a, 0xfe, 0x37, 0xf0, 0xfe,
12641 0xda, 0x09, 0xfe, 0x8b,
12642 0xf0, 0xfe, 0x60, 0x09, 0x02, 0x4a, 0x08, 0x05, 0x0a, 0x23, 0xfe, 0xfa,
12643 0x0a, 0x3a, 0x49, 0x3b,
12644 0x63, 0x56, 0xfe, 0x3e, 0x0a, 0x0f, 0xfe, 0xc0, 0x07, 0x41, 0x98, 0x00,
12645 0xad, 0xfe, 0x01, 0x59,
12646 0xfe, 0x52, 0xf0, 0xfe, 0x0c, 0x0a, 0x8f, 0x7a, 0xfe, 0x24, 0x0a, 0x3a,
12647 0x49, 0x8f, 0xfe, 0xe3,
12648 0x54, 0x57, 0x49, 0x7d, 0x63, 0xfe, 0x14, 0x58, 0xfe, 0x95, 0x58, 0x02,
12649 0x4a, 0x3a, 0x49, 0x3b,
12650 0x63, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0xbe, 0x57, 0x49, 0x57, 0x63,
12651 0x02, 0x4a, 0x08, 0x05,
12652 0x5a, 0xfe, 0x82, 0x12, 0x08, 0x05, 0x1f, 0xfe, 0x66, 0x13, 0x22, 0x62,
12653 0xb7, 0xfe, 0x03, 0xa1,
12654 0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91,
12655 0xfe, 0x86, 0x91, 0x6a,
12656 0x2a, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x56, 0xe0, 0x03, 0x60, 0x29,
12657 0x61, 0x0c, 0x7f, 0x14,
12658 0x80, 0x57, 0x60, 0x7d, 0x61, 0x01, 0xb3, 0xb8, 0x6a, 0x2a, 0x13, 0x62,
12659 0x9b, 0x2e, 0x9c, 0x3c,
12660 0x3a, 0x3f, 0x3b, 0x40, 0x90, 0xc0, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05,
12661 0xfa, 0x3c, 0x01, 0xef,
12662 0xfe, 0x36, 0x10, 0x21, 0x0c, 0x7f, 0x0c, 0x80, 0x3a, 0x3f, 0x3b, 0x40,
12663 0xe4, 0x08, 0x05, 0x1f,
12664 0x17, 0xe0, 0x3a, 0x3d, 0x3b, 0x3e, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37,
12665 0x03, 0x5e, 0x29, 0x5f,
12666 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0x57, 0x49, 0x7d, 0x63, 0x02, 0xfe,
12667 0xf4, 0x09, 0x08, 0x05,
12668 0x1f, 0x17, 0xe0, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37, 0xbe, 0xfe, 0x19,
12669 0x81, 0x50, 0xfe, 0x10,
12670 0x90, 0xfe, 0x92, 0x90, 0xfe, 0xd3, 0x10, 0x32, 0x07, 0xa6, 0x17, 0xfe,
12671 0x08, 0x09, 0x12, 0xa6,
12672 0x08, 0x05, 0x0a, 0xfe, 0x14, 0x13, 0x03, 0x3d, 0x29, 0x3e, 0x56, 0xfe,
12673 0x08, 0x09, 0xfe, 0x0c,
12674 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x4a, 0x21, 0x41, 0xfe, 0x19, 0x80, 0xe7,
12675 0x08, 0x05, 0x0a, 0xfe,
12676 0x1a, 0x12, 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xf4, 0xc2, 0xfe, 0xd1,
12677 0xf0, 0xe2, 0x15, 0x7e,
12678 0x01, 0x36, 0x10, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19,
12679 0x57, 0x3d, 0xfe, 0xed,
12680 0x19, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xf4, 0x1e, 0xfe,
12681 0x00, 0xff, 0x35, 0xfe,
12682 0x74, 0x10, 0xc2, 0xfe, 0xd2, 0xf0, 0xfe, 0xa6, 0x0b, 0xfe, 0x76, 0x18,
12683 0x1e, 0x19, 0x8a, 0x03,
12684 0xd2, 0x1e, 0x06, 0xfe, 0x08, 0x13, 0x10, 0xfe, 0x16, 0x00, 0x02, 0x65,
12685 0xfe, 0xd1, 0xf0, 0xfe,
12686 0xb8, 0x0b, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe, 0x17, 0x00, 0xfe, 0x42,
12687 0x10, 0xfe, 0xce, 0xf0,
12688 0xfe, 0xbe, 0x0b, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xca, 0x0b,
12689 0x10, 0xfe, 0x22, 0x00,
12690 0x02, 0x65, 0xfe, 0xcb, 0xf0, 0xfe, 0xd6, 0x0b, 0x10, 0xfe, 0x24, 0x00,
12691 0x02, 0x65, 0xfe, 0xd0,
12692 0xf0, 0xfe, 0xe0, 0x0b, 0x10, 0x9e, 0xe5, 0xfe, 0xcf, 0xf0, 0xfe, 0xea,
12693 0x0b, 0x10, 0x58, 0xfe,
12694 0x10, 0x10, 0xfe, 0xcc, 0xf0, 0xe2, 0x68, 0x05, 0x1f, 0x4d, 0x10, 0xfe,
12695 0x12, 0x00, 0x2c, 0x0f,
12696 0xfe, 0x4e, 0x11, 0x27, 0xfe, 0x00, 0x0c, 0xfe, 0x9e, 0xf0, 0xfe, 0x14,
12697 0x0c, 0xbc, 0x17, 0x34,
12698 0x2c, 0x77, 0xe6, 0xc5, 0x24, 0xc6, 0x24, 0x2c, 0xfa, 0x27, 0xfe, 0x20,
12699 0x0c, 0x1c, 0x34, 0x94,
12700 0xfe, 0x3c, 0x0c, 0x95, 0x86, 0xc5, 0xdc, 0xc6, 0xdc, 0x02, 0x24, 0x01,
12701 0x4b, 0xfe, 0xdb, 0x10,
12702 0x12, 0xfe, 0xe8, 0x00, 0xb5, 0xb6, 0x74, 0xc7, 0x81, 0xc8, 0x83, 0xfe,
12703 0x89, 0xf0, 0x24, 0x33,
12704 0x31, 0xe1, 0xc7, 0x81, 0xc8, 0x83, 0x27, 0xfe, 0x66, 0x0c, 0x1d, 0x24,
12705 0x33, 0x31, 0xdf, 0xbc,
12706 0x4e, 0x10, 0xfe, 0x42, 0x00, 0x02, 0x65, 0x7c, 0x06, 0xfe, 0x81, 0x49,
12707 0x17, 0xfe, 0x2c, 0x0d,
12708 0x08, 0x05, 0x0a, 0xfe, 0x44, 0x13, 0x10, 0x00, 0x55, 0x0a, 0xfe, 0x54,
12709 0x12, 0x55, 0xfe, 0x28,
12710 0x00, 0x23, 0xfe, 0x9a, 0x0d, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66,
12711 0x44, 0xfe, 0x28, 0x00,
12712 0xfe, 0xe2, 0x10, 0x01, 0xf5, 0x01, 0xf6, 0x09, 0xa4, 0x01, 0xfe, 0x26,
12713 0x0f, 0x64, 0x12, 0x2f,
12714 0x01, 0x73, 0x02, 0x2b, 0x10, 0xfe, 0x44, 0x00, 0x55, 0x0a, 0xe9, 0x44,
12715 0x0a, 0xfe, 0xb4, 0x10,
12716 0x01, 0xb0, 0x44, 0x0a, 0xfe, 0xaa, 0x10, 0x01, 0xb0, 0xfe, 0x19, 0x82,
12717 0xfe, 0x34, 0x46, 0xac,
12718 0x44, 0x0a, 0x10, 0xfe, 0x43, 0x00, 0xfe, 0x96, 0x10, 0x08, 0x54, 0x0a,
12719 0x37, 0x01, 0xf5, 0x01,
12720 0xf6, 0x64, 0x12, 0x2f, 0x01, 0x73, 0x99, 0x0a, 0x64, 0x42, 0x92, 0x02,
12721 0xfe, 0x2e, 0x03, 0x08,
12722 0x05, 0x0a, 0x8a, 0x44, 0x0a, 0x10, 0x00, 0xfe, 0x5c, 0x10, 0x68, 0x05,
12723 0x1a, 0xfe, 0x58, 0x12,
12724 0x08, 0x05, 0x1a, 0xfe, 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0,
12725 0xfe, 0x50, 0x0d, 0xfe,
12726 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x56, 0x0d, 0x08, 0x54, 0x1a, 0x37,
12727 0xfe, 0xa9, 0x10, 0x10,
12728 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0a, 0x50, 0xfe, 0x2e, 0x10, 0x10,
12729 0xfe, 0x13, 0x00, 0xfe,
12730 0x10, 0x10, 0x10, 0x6f, 0xab, 0x10, 0xfe, 0x41, 0x00, 0xaa, 0x10, 0xfe,
12731 0x24, 0x00, 0x8c, 0xb5,
12732 0xb6, 0x74, 0x03, 0x70, 0x28, 0x23, 0xd8, 0x50, 0xfe, 0x04, 0xe6, 0x1a,
12733 0xfe, 0x9d, 0x41, 0xfe,
12734 0x1c, 0x42, 0x64, 0x01, 0xe3, 0x02, 0x2b, 0xf8, 0x15, 0x0a, 0x39, 0xa0,
12735 0xb4, 0x15, 0xfe, 0x31,
12736 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10, 0x02, 0xd7, 0x42, 0xfe, 0x06,
12737 0xec, 0xd0, 0xfc, 0x44,
12738 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe, 0x06, 0xea, 0xd0, 0xfe, 0x47,
12739 0x4b, 0x91, 0xfe, 0x75,
12740 0x57, 0x03, 0x5d, 0xfe, 0x98, 0x56, 0xfe, 0x38, 0x12, 0x09, 0x48, 0x01,
12741 0x0e, 0xfe, 0x44, 0x48,
12742 0x4f, 0x08, 0x05, 0x1b, 0xfe, 0x1a, 0x13, 0x09, 0x46, 0x01, 0x0e, 0x41,
12743 0xfe, 0x41, 0x58, 0x09,
12744 0xa4, 0x01, 0x0e, 0xfe, 0x49, 0x54, 0x96, 0xfe, 0x1e, 0x0e, 0x02, 0xfe,
12745 0x2e, 0x03, 0x09, 0x5d,
12746 0xfe, 0xee, 0x14, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe,
12747 0xce, 0x47, 0xfe, 0xad,
12748 0x13, 0x02, 0x2b, 0x22, 0x20, 0x07, 0x11, 0xfe, 0x9e, 0x12, 0x21, 0x13,
12749 0x59, 0x13, 0x9f, 0x13,
12750 0xd5, 0x22, 0x2f, 0x41, 0x39, 0x2f, 0xbc, 0xad, 0xfe, 0xbc, 0xf0, 0xfe,
12751 0xe0, 0x0e, 0x0f, 0x06,
12752 0x13, 0x59, 0x01, 0xfe, 0xda, 0x16, 0x03, 0xfe, 0x38, 0x01, 0x29, 0xfe,
12753 0x3a, 0x01, 0x56, 0xfe,
12754 0xe4, 0x0e, 0xfe, 0x02, 0xec, 0xd5, 0x69, 0x00, 0x66, 0xfe, 0x04, 0xec,
12755 0x20, 0x4f, 0xfe, 0x05,
12756 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x4a, 0x17, 0xfe, 0x08, 0x90, 0xfe,
12757 0x48, 0xf4, 0x0d, 0xfe,
12758 0x18, 0x13, 0xba, 0xfe, 0x02, 0xea, 0xd5, 0x69, 0x7e, 0xfe, 0xc5, 0x13,
12759 0x15, 0x1a, 0x39, 0xa0,
12760 0xb4, 0xfe, 0x2e, 0x10, 0x03, 0xfe, 0x38, 0x01, 0x1e, 0xfe, 0xf0, 0xff,
12761 0x0c, 0xfe, 0x60, 0x01,
12762 0x03, 0xfe, 0x3a, 0x01, 0x0c, 0xfe, 0x62, 0x01, 0x43, 0x13, 0x20, 0x25,
12763 0x06, 0x13, 0x2f, 0x12,
12764 0x2f, 0x92, 0x0f, 0x06, 0x04, 0x21, 0x04, 0x22, 0x59, 0xfe, 0xf7, 0x12,
12765 0x22, 0x9f, 0xb7, 0x13,
12766 0x9f, 0x07, 0x7e, 0xfe, 0x71, 0x13, 0xfe, 0x24, 0x1c, 0x15, 0x19, 0x39,
12767 0xa0, 0xb4, 0xfe, 0xd9,
12768 0x10, 0xc3, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x04,
12769 0xc3, 0xfe, 0x03, 0xdc,
12770 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x21,
12771 0xfe, 0x00, 0xcc, 0x04,
12772 0xfe, 0x03, 0x57, 0xc3, 0x78, 0x04, 0x08, 0x05, 0x58, 0xfe, 0x22, 0x13,
12773 0xfe, 0x1c, 0x80, 0x07,
12774 0x06, 0xfe, 0x1a, 0x13, 0xfe, 0x1e, 0x80, 0xed, 0xfe, 0x1d, 0x80, 0xae,
12775 0xfe, 0x0c, 0x90, 0xfe,
12776 0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xac, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4,
12777 0x0a, 0xfe, 0x3c, 0x50,
12778 0xaa, 0x01, 0xfe, 0x7a, 0x17, 0x32, 0x07, 0x2f, 0xad, 0x01, 0xfe, 0xb4,
12779 0x16, 0x08, 0x05, 0x1b,
12780 0x4e, 0x01, 0xf5, 0x01, 0xf6, 0x12, 0xfe, 0xe9, 0x00, 0x08, 0x05, 0x58,
12781 0xfe, 0x2c, 0x13, 0x01,
12782 0xfe, 0x0c, 0x17, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90,
12783 0x0c, 0xfe, 0x64, 0x01,
12784 0x14, 0xfe, 0x66, 0x01, 0x08, 0x05, 0x5b, 0xfe, 0x12, 0x12, 0xfe, 0x03,
12785 0x80, 0x8d, 0xfe, 0x01,
12786 0xec, 0x20, 0xfe, 0x80, 0x40, 0x13, 0x20, 0x6a, 0x2a, 0x12, 0xcf, 0x64,
12787 0x22, 0x20, 0xfb, 0x79,
12788 0x20, 0x04, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58,
12789 0x03, 0xfe, 0xae, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070012790
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012791 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x03, 0xfe,
12792 0xb2, 0x00, 0xfe, 0x09,
12793 0x58, 0xfe, 0x0a, 0x1c, 0x25, 0x6e, 0x13, 0xd0, 0x21, 0x0c, 0x5c, 0x0c,
12794 0x45, 0x0f, 0x46, 0x52,
12795 0x50, 0x18, 0x1b, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xfe, 0xfc,
12796 0x0f, 0x44, 0x11, 0x0f,
12797 0x48, 0x52, 0x18, 0x58, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xe4,
12798 0x25, 0x11, 0x13, 0x20,
12799 0x7c, 0x6f, 0x4f, 0x22, 0x20, 0xfb, 0x79, 0x20, 0x12, 0xcf, 0xfe, 0x14,
12800 0x56, 0xfe, 0xd6, 0xf0,
12801 0xfe, 0x26, 0x10, 0xf8, 0x74, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe,
12802 0x18, 0x1c, 0x04, 0x42,
12803 0xfe, 0x0c, 0x14, 0xfc, 0xfe, 0x07, 0xe6, 0x1b, 0xfe, 0xce, 0x47, 0xfe,
12804 0xf5, 0x13, 0x04, 0x01,
12805 0xb0, 0x7c, 0x6f, 0x4f, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42,
12806 0x13, 0x32, 0x07, 0x2f,
12807 0xfe, 0x34, 0x13, 0x09, 0x48, 0x01, 0x0e, 0xbb, 0xfe, 0x36, 0x12, 0xfe,
12808 0x41, 0x48, 0xfe, 0x45,
12809 0x48, 0x01, 0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78,
12810 0x07, 0x11, 0xac, 0x09,
12811 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x73, 0xfe, 0x0e, 0x10, 0x07,
12812 0x82, 0x4e, 0xfe, 0x14,
12813 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x60, 0x10, 0x04, 0xfe, 0x44, 0x58, 0x8d,
12814 0xfe, 0x01, 0xec, 0xa2,
12815 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1a, 0x79,
12816 0x2a, 0x01, 0xe3, 0xfe,
12817 0xdd, 0x10, 0x2c, 0xc7, 0x81, 0xc8, 0x83, 0x33, 0x31, 0xde, 0x07, 0x1a,
12818 0xfe, 0x48, 0x12, 0x07,
12819 0x0a, 0xfe, 0x56, 0x12, 0x07, 0x19, 0xfe, 0x30, 0x12, 0x07, 0xc9, 0x17,
12820 0xfe, 0x32, 0x12, 0x07,
12821 0xfe, 0x23, 0x00, 0x17, 0xeb, 0x07, 0x06, 0x17, 0xfe, 0x9c, 0x12, 0x07,
12822 0x1f, 0xfe, 0x12, 0x12,
12823 0x07, 0x00, 0x17, 0x24, 0x15, 0xc9, 0x01, 0x36, 0xa9, 0x2d, 0x01, 0x0b,
12824 0x94, 0x4b, 0x04, 0x2d,
12825 0xdd, 0x09, 0xd1, 0x01, 0xfe, 0x26, 0x0f, 0x12, 0x82, 0x02, 0x2b, 0x2d,
12826 0x32, 0x07, 0xa6, 0xfe,
12827 0xd9, 0x13, 0x3a, 0x3d, 0x3b, 0x3e, 0x56, 0xfe, 0xf0, 0x11, 0x08, 0x05,
12828 0x5a, 0xfe, 0x72, 0x12,
12829 0x9b, 0x2e, 0x9c, 0x3c, 0x90, 0xc0, 0x96, 0xfe, 0xba, 0x11, 0x22, 0x62,
12830 0xfe, 0x26, 0x13, 0x03,
12831 0x7f, 0x29, 0x80, 0x56, 0xfe, 0x76, 0x0d, 0x0c, 0x60, 0x14, 0x61, 0x21,
12832 0x0c, 0x7f, 0x0c, 0x80,
12833 0x01, 0xb3, 0x25, 0x6e, 0x77, 0x13, 0x62, 0x01, 0xef, 0x9b, 0x2e, 0x9c,
12834 0x3c, 0xfe, 0x04, 0x55,
12835 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0xfe,
12836 0x91, 0x10, 0x03, 0x3f,
12837 0x29, 0x40, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x3f, 0x14, 0x40,
12838 0x88, 0x9b, 0x2e, 0x9c,
12839 0x3c, 0x90, 0xc0, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x00, 0x56, 0xfe, 0xa1,
12840 0x56, 0x0c, 0x5e, 0x14,
12841 0x5f, 0x08, 0x05, 0x5a, 0xfe, 0x1e, 0x12, 0x22, 0x62, 0xfe, 0x1f, 0x40,
12842 0x03, 0x60, 0x29, 0x61,
12843 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x03, 0x3f, 0x29, 0x40, 0xfe, 0x44,
12844 0x50, 0xfe, 0xc6, 0x50,
12845 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x3d,
12846 0x29, 0x3e, 0xfe, 0x40,
12847 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x89, 0x25, 0x06, 0x13, 0xd4, 0x02, 0x72,
12848 0x2d, 0x01, 0x0b, 0x1d,
12849 0x4c, 0x33, 0x31, 0xde, 0x07, 0x06, 0x23, 0x4c, 0x32, 0x07, 0xa6, 0x23,
12850 0x72, 0x01, 0xaf, 0x1e,
12851 0x43, 0x17, 0x4c, 0x08, 0x05, 0x0a, 0xee, 0x3a, 0x3d, 0x3b, 0x3e, 0xfe,
12852 0x0a, 0x55, 0x35, 0xfe,
12853 0x8b, 0x55, 0x57, 0x3d, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51,
12854 0x02, 0x72, 0xfe, 0x19,
12855 0x81, 0xba, 0xfe, 0x19, 0x41, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1c, 0x34,
12856 0x1d, 0xe8, 0x33, 0x31,
12857 0xe1, 0x55, 0x19, 0xfe, 0xa6, 0x12, 0x55, 0x0a, 0x4d, 0x02, 0x4c, 0x01,
12858 0x0b, 0x1c, 0x34, 0x1d,
12859 0xe8, 0x33, 0x31, 0xdf, 0x07, 0x19, 0x23, 0x4c, 0x01, 0x0b, 0x1d, 0xe8,
12860 0x33, 0x31, 0xfe, 0xe8,
12861 0x09, 0xfe, 0xc2, 0x49, 0x51, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0x8a, 0x53,
12862 0x05, 0x1f, 0x35, 0xa9,
12863 0xfe, 0xbb, 0x45, 0x55, 0x00, 0x4e, 0x44, 0x06, 0x7c, 0x43, 0xfe, 0xda,
12864 0x14, 0x01, 0xaf, 0x8c,
12865 0xfe, 0x4b, 0x45, 0xee, 0x32, 0x07, 0xa5, 0xed, 0x03, 0xcd, 0x28, 0x8a,
12866 0x03, 0x45, 0x28, 0x35,
12867 0x67, 0x02, 0x72, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17,
12868 0x03, 0x5c, 0xc1, 0x0c,
12869 0x5c, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01, 0xfe, 0x9e, 0x15, 0x02,
12870 0x89, 0x01, 0x0b, 0x1c,
12871 0x34, 0x1d, 0x4c, 0x33, 0x31, 0xdf, 0x07, 0x06, 0x23, 0x4c, 0x01, 0xf1,
12872 0xfe, 0x42, 0x58, 0xf1,
12873 0xfe, 0xa4, 0x14, 0x8c, 0xfe, 0x4a, 0xf4, 0x0a, 0x17, 0x4c, 0xfe, 0x4a,
12874 0xf4, 0x06, 0xea, 0x32,
12875 0x07, 0xa5, 0x8b, 0x02, 0x72, 0x03, 0x45, 0xc1, 0x0c, 0x45, 0x67, 0x2d,
12876 0x01, 0x0b, 0x26, 0x89,
12877 0x01, 0xfe, 0xcc, 0x15, 0x02, 0x89, 0x0f, 0x06, 0x27, 0xfe, 0xbe, 0x13,
12878 0x26, 0xfe, 0xd4, 0x13,
12879 0x76, 0xfe, 0x89, 0x48, 0x01, 0x0b, 0x21, 0x76, 0x04, 0x7b, 0xfe, 0xd0,
12880 0x13, 0x1c, 0xfe, 0xd0,
12881 0x13, 0x1d, 0xfe, 0xbe, 0x13, 0x67, 0x2d, 0x01, 0x0b, 0xfe, 0xd5, 0x10,
12882 0x0f, 0x71, 0xff, 0x02,
12883 0x00, 0x57, 0x52, 0x93, 0x1e, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe,
12884 0x00, 0x5c, 0x04, 0x0f,
12885 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0xfe, 0x30, 0x56,
12886 0xfe, 0x00, 0x5c, 0x04,
12887 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x04, 0x0f, 0x71, 0xff,
12888 0x02, 0x00, 0x57, 0x52,
12889 0x93, 0xfe, 0x0b, 0x58, 0x04, 0x09, 0x5c, 0x01, 0x87, 0x09, 0x45, 0x01,
12890 0x87, 0x04, 0xfe, 0x03,
12891 0xa1, 0x1e, 0x11, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x1f, 0x52,
12892 0xfe, 0x00, 0x7d, 0xfe,
12893 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, 0x6a, 0x2a, 0x0c, 0x5e,
12894 0x14, 0x5f, 0x57, 0x3f,
12895 0x7d, 0x40, 0x04, 0xdd, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83,
12896 0x5a, 0x8d, 0x04, 0x01,
12897 0xfe, 0x0c, 0x19, 0xfe, 0x42, 0x48, 0x50, 0x51, 0x91, 0x01, 0x0b, 0x1d,
12898 0xfe, 0x96, 0x15, 0x33,
12899 0x31, 0xe1, 0x01, 0x0b, 0x1d, 0xfe, 0x96, 0x15, 0x33, 0x31, 0xfe, 0xe8,
12900 0x0a, 0xfe, 0xc1, 0x59,
12901 0x03, 0xcd, 0x28, 0xfe, 0xcc, 0x12, 0x53, 0x05, 0x1a, 0xfe, 0xc4, 0x13,
12902 0x21, 0x69, 0x1a, 0xee,
12903 0x55, 0xca, 0x6b, 0xfe, 0xdc, 0x14, 0x4d, 0x0f, 0x06, 0x18, 0xca, 0x7c,
12904 0x30, 0xfe, 0x78, 0x10,
12905 0xff, 0x02, 0x83, 0x55, 0xab, 0xff, 0x02, 0x83, 0x55, 0x69, 0x19, 0xae,
12906 0x98, 0xfe, 0x30, 0x00,
12907 0x96, 0xf2, 0x18, 0x6d, 0x0f, 0x06, 0xfe, 0x56, 0x10, 0x69, 0x0a, 0xed,
12908 0x98, 0xfe, 0x64, 0x00,
12909 0x96, 0xf2, 0x09, 0xfe, 0x64, 0x00, 0x18, 0x9e, 0x0f, 0x06, 0xfe, 0x28,
12910 0x10, 0x69, 0x06, 0xfe,
12911 0x60, 0x13, 0x98, 0xfe, 0xc8, 0x00, 0x96, 0xf2, 0x09, 0xfe, 0xc8, 0x00,
12912 0x18, 0x59, 0x0f, 0x06,
12913 0x88, 0x98, 0xfe, 0x90, 0x01, 0x7a, 0xfe, 0x42, 0x15, 0x91, 0xe4, 0xfe,
12914 0x43, 0xf4, 0x9f, 0xfe,
12915 0x56, 0xf0, 0xfe, 0x54, 0x15, 0xfe, 0x04, 0xf4, 0x71, 0xfe, 0x43, 0xf4,
12916 0x9e, 0xfe, 0xf3, 0x10,
12917 0xfe, 0x40, 0x5c, 0x01, 0xfe, 0x16, 0x14, 0x1e, 0x43, 0xec, 0xfe, 0x00,
12918 0x17, 0xfe, 0x4d, 0xe4,
12919 0x6e, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0x6e, 0xfe, 0x1c, 0x10, 0xfe, 0x00,
12920 0x17, 0xfe, 0x4d, 0xe4,
12921 0xcc, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0xcc, 0x88, 0x51, 0x21, 0xfe, 0x4d,
12922 0xf4, 0x00, 0xe9, 0x91,
12923 0x0f, 0x06, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x04, 0x51, 0x0f, 0x0a,
12924 0x04, 0x16, 0x06, 0x01,
12925 0x0b, 0x26, 0xf3, 0x16, 0x0a, 0x01, 0x0b, 0x26, 0xf3, 0x16, 0x19, 0x01,
12926 0x0b, 0x26, 0xf3, 0x76,
12927 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1,
12928 0x16, 0x19, 0x01, 0x0b,
12929 0x26, 0xb1, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1, 0xfe, 0x89, 0x49, 0x01,
12930 0x0b, 0x26, 0xb1, 0x76,
12931 0xfe, 0x89, 0x4a, 0x01, 0x0b, 0x04, 0x51, 0x04, 0x22, 0xd3, 0x07, 0x06,
12932 0xfe, 0x48, 0x13, 0xb8,
12933 0x13, 0xd3, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x76, 0xa9, 0x67, 0xfe, 0x01,
12934 0xec, 0xfe, 0x27, 0x01,
12935 0xfe, 0x89, 0x48, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x2e, 0x16, 0x32,
12936 0x07, 0xfe, 0xe3, 0x00,
12937 0xfe, 0x20, 0x13, 0x1d, 0xfe, 0x52, 0x16, 0x21, 0x13, 0xd4, 0x01, 0x4b,
12938 0x22, 0xd4, 0x07, 0x06,
12939 0x4e, 0x08, 0x54, 0x06, 0x37, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfb, 0x8e,
12940 0x07, 0x11, 0xae, 0x09,
12941 0x84, 0x01, 0x0e, 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x84, 0x01,
12942 0x0e, 0x8e, 0xfe, 0x80,
12943 0xe7, 0x11, 0x07, 0x11, 0x8a, 0xfe, 0x45, 0x58, 0x01, 0xf0, 0x8e, 0x04,
12944 0x09, 0x48, 0x01, 0x0e,
12945 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfe, 0x80,
12946 0x80, 0xfe, 0x80, 0x4c,
12947 0xfe, 0x49, 0xe4, 0x11, 0xae, 0x09, 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x4c,
12948 0x09, 0x5d, 0x01, 0x87,
12949 0x04, 0x18, 0x11, 0x75, 0x6c, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe,
12950 0x19, 0xde, 0xfe, 0x24,
12951 0x1c, 0xfe, 0x1d, 0xf7, 0x1b, 0x97, 0xfe, 0xee, 0x16, 0x01, 0xfe, 0xf4,
12952 0x17, 0xad, 0x9a, 0x1b,
12953 0x6c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x04, 0xb9, 0x23, 0xfe, 0xde,
12954 0x16, 0xfe, 0xda, 0x10,
12955 0x18, 0x11, 0x75, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x1f, 0xfe,
12956 0x18, 0x58, 0x03, 0xfe,
12957 0x66, 0x01, 0xfe, 0x19, 0x58, 0x9a, 0x1f, 0xfe, 0x3c, 0x90, 0xfe, 0x30,
12958 0xf4, 0x06, 0xfe, 0x3c,
12959 0x50, 0x6c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x1f,
12960 0x97, 0xfe, 0x38, 0x17,
12961 0xfe, 0xb6, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x10, 0x17, 0xfe, 0x9c,
12962 0x10, 0x18, 0x11, 0x75,
12963 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7,
12964 0x2e, 0x97, 0xfe, 0x5a,
12965 0x17, 0xfe, 0x94, 0x14, 0xec, 0x9a, 0x2e, 0x6c, 0x1a, 0xfe, 0xaf, 0x19,
12966 0xfe, 0x98, 0xe7, 0x00,
12967 0x04, 0xb9, 0x23, 0xfe, 0x4e, 0x17, 0xfe, 0x6c, 0x10, 0x18, 0x11, 0x75,
12968 0xfe, 0x30, 0xbc, 0xfe,
12969 0xb2, 0xbc, 0x9a, 0xcb, 0x6c, 0x1a, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
12970 0xcb, 0x97, 0xfe, 0x92,
12971 0x17, 0xfe, 0x5c, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x7e, 0x17, 0xfe,
12972 0x42, 0x10, 0xfe, 0x02,
12973 0xf6, 0x11, 0x75, 0xfe, 0x18, 0xfe, 0x60, 0xfe, 0x19, 0xfe, 0x61, 0xfe,
12974 0x03, 0xa1, 0xfe, 0x1d,
12975 0xf7, 0x5b, 0x97, 0xfe, 0xb8, 0x17, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13,
12976 0x9a, 0x5b, 0x41, 0xfe,
12977 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x11, 0xfe, 0x81, 0xe7,
12978 0x11, 0x12, 0xfe, 0xdd,
12979 0x00, 0x6a, 0x2a, 0x04, 0x6a, 0x2a, 0xfe, 0x12, 0x45, 0x23, 0xfe, 0xa8,
12980 0x17, 0x15, 0x06, 0x39,
12981 0xa0, 0xb4, 0x02, 0x2b, 0xfe, 0x39, 0xf0, 0xfe, 0xfc, 0x17, 0x21, 0x04,
12982 0xfe, 0x7e, 0x18, 0x1e,
12983 0x19, 0x66, 0x0f, 0x0d, 0x04, 0x75, 0x03, 0xd2, 0x1e, 0x06, 0xfe, 0xef,
12984 0x12, 0xfe, 0xe1, 0x10,
12985 0x7c, 0x6f, 0x4f, 0x32, 0x07, 0x2f, 0xfe, 0x3c, 0x13, 0xf1, 0xfe, 0x42,
12986 0x13, 0x42, 0x92, 0x09,
12987 0x48, 0x01, 0x0e, 0xbb, 0xeb, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01,
12988 0xf0, 0xfe, 0x00, 0xcc,
12989 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11, 0xac, 0x09, 0x84, 0x01,
12990 0x0e, 0xfe, 0x80, 0x4c,
12991 0x01, 0x73, 0xfe, 0x16, 0x10, 0x07, 0x82, 0x8b, 0xfe, 0x40, 0x14, 0xfe,
12992 0x24, 0x12, 0xfe, 0x14,
12993 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x1c, 0x18, 0x18, 0x0a, 0x04, 0xfe, 0x9c,
12994 0xe7, 0x0a, 0x10, 0xfe,
12995 0x15, 0x00, 0x64, 0x79, 0x2a, 0x01, 0xe3, 0x18, 0x06, 0x04, 0x42, 0x92,
12996 0x08, 0x54, 0x1b, 0x37,
12997 0x12, 0x2f, 0x01, 0x73, 0x18, 0x06, 0x04, 0xfe, 0x38, 0x90, 0xfe, 0xba,
12998 0x90, 0x3a, 0xce, 0x3b,
12999 0xcf, 0xfe, 0x48, 0x55, 0x35, 0xfe, 0xc9, 0x55, 0x04, 0x22, 0xa3, 0x77,
13000 0x13, 0xa3, 0x04, 0x09,
13001 0xa4, 0x01, 0x0e, 0xfe, 0x41, 0x48, 0x09, 0x46, 0x01, 0x0e, 0xfe, 0x49,
13002 0x44, 0x17, 0xfe, 0xe8,
13003 0x18, 0x77, 0x78, 0x04, 0x09, 0x48, 0x01, 0x0e, 0x07, 0x11, 0x4e, 0x09,
13004 0x5d, 0x01, 0xa8, 0x09,
13005 0x46, 0x01, 0x0e, 0x77, 0x78, 0x04, 0xfe, 0x4e, 0xe4, 0x19, 0x6b, 0xfe,
13006 0x1c, 0x19, 0x03, 0xfe,
13007 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe, 0x4e, 0xe4, 0xc9,
13008 0x6b, 0xfe, 0x2e, 0x19,
13009 0x03, 0xfe, 0x92, 0x00, 0xfe, 0x02, 0xe6, 0x1a, 0xe5, 0xfe, 0x4e, 0xe4,
13010 0xfe, 0x0b, 0x00, 0x6b,
13011 0xfe, 0x40, 0x19, 0x03, 0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x1f, 0xfe,
13012 0x08, 0x10, 0x03, 0xfe,
13013 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x6d, 0xfe, 0x4e, 0x45, 0xea, 0xba, 0xff,
13014 0x04, 0x68, 0x54, 0xe7,
13015 0x1e, 0x6e, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c, 0xfe,
13016 0x1a, 0xf4, 0xfe, 0x00,
13017 0x04, 0xea, 0xfe, 0x48, 0xf4, 0x19, 0x7a, 0xfe, 0x74, 0x19, 0x0f, 0x19,
13018 0x04, 0x07, 0x7e, 0xfe,
13019 0x5a, 0xf0, 0xfe, 0x84, 0x19, 0x25, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
13020 0x07, 0x1a, 0xfe, 0x5a,
13021 0xf0, 0xfe, 0x92, 0x19, 0x25, 0xca, 0xfe, 0x26, 0x10, 0x07, 0x19, 0x66,
13022 0x25, 0x6d, 0xe5, 0x07,
13023 0x0a, 0x66, 0x25, 0x9e, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x66, 0x25, 0x59,
13024 0xa9, 0xb8, 0x04, 0x15,
13025 0xfe, 0x09, 0x00, 0x01, 0x36, 0xfe, 0x04, 0xfe, 0x81, 0x03, 0x83, 0xfe,
13026 0x40, 0x5c, 0x04, 0x1c,
13027 0xf7, 0xfe, 0x14, 0xf0, 0x0b, 0x27, 0xfe, 0xd6, 0x19, 0x1c, 0xf7, 0x7b,
13028 0xf7, 0xfe, 0x82, 0xf0,
13029 0xfe, 0xda, 0x19, 0x04, 0xff, 0xcc, 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070013030};
13031
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013032static unsigned short _adv_asc38C0800_size = sizeof(_adv_asc38C0800_buf); /* 0x14E1 */
13033static ADV_DCNT _adv_asc38C0800_chksum = 0x050D3FD8UL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013034
13035/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013036static unsigned char _adv_asc38C1600_buf[] = {
13037 0x00, 0x00, 0x00, 0xf2, 0x00, 0x16, 0x00, 0xfc, 0x00, 0x10, 0x00, 0xf0,
13038 0x18, 0xe4, 0x01, 0x00,
13039 0x04, 0x1e, 0x48, 0xe4, 0x03, 0xf6, 0xf7, 0x13, 0x2e, 0x1e, 0x02, 0x00,
13040 0x07, 0x17, 0xc0, 0x5f,
13041 0x00, 0xfa, 0xff, 0xff, 0x04, 0x00, 0x00, 0xf6, 0x09, 0xe7, 0x82, 0xe7,
13042 0x85, 0xf0, 0x86, 0xf0,
13043 0x4e, 0x10, 0x9e, 0xe7, 0xff, 0x00, 0x55, 0xf0, 0x01, 0xf6, 0x03, 0x00,
13044 0x98, 0x57, 0x01, 0xe6,
13045 0x00, 0xea, 0x00, 0xec, 0x01, 0xfa, 0x18, 0xf4, 0x08, 0x00, 0xf0, 0x1d,
13046 0x38, 0x54, 0x32, 0xf0,
13047 0x10, 0x00, 0xc2, 0x0e, 0x1e, 0xf0, 0xd5, 0xf0, 0xbc, 0x00, 0x4b, 0xe4,
13048 0x00, 0xe6, 0xb1, 0xf0,
13049 0xb4, 0x00, 0x02, 0x13, 0x3e, 0x1c, 0xc8, 0x47, 0x3e, 0x00, 0xd8, 0x01,
13050 0x06, 0x13, 0x0c, 0x1c,
13051 0x5e, 0x1e, 0x00, 0x57, 0xc8, 0x57, 0x01, 0xfc, 0xbc, 0x0e, 0xa2, 0x12,
13052 0xb9, 0x54, 0x00, 0x80,
13053 0x62, 0x0a, 0x5a, 0x12, 0xc8, 0x15, 0x3e, 0x1e, 0x18, 0x40, 0xbd, 0x56,
13054 0x03, 0xe6, 0x01, 0xea,
13055 0x5c, 0xf0, 0x0f, 0x00, 0x20, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12,
13056 0x04, 0x13, 0xbb, 0x55,
13057 0x3c, 0x56, 0x3e, 0x57, 0x03, 0x58, 0x4a, 0xe4, 0x40, 0x00, 0xb6, 0x00,
13058 0xbb, 0x00, 0xc0, 0x00,
13059 0x00, 0x01, 0x01, 0x01, 0x3e, 0x01, 0x58, 0x0a, 0x44, 0x10, 0x0a, 0x12,
13060 0x4c, 0x1c, 0x4e, 0x1c,
13061 0x02, 0x4a, 0x30, 0xe4, 0x05, 0xe6, 0x0c, 0x00, 0x3c, 0x00, 0x80, 0x00,
13062 0x24, 0x01, 0x3c, 0x01,
13063 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01, 0x74, 0x01, 0x76, 0x01,
13064 0x78, 0x01, 0x7c, 0x01,
13065 0xc6, 0x0e, 0x0c, 0x10, 0xac, 0x12, 0xae, 0x12, 0x16, 0x1a, 0x32, 0x1c,
13066 0x6e, 0x1e, 0x02, 0x48,
13067 0x3a, 0x55, 0xc9, 0x57, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x06, 0xf7,
13068 0x03, 0xfc, 0x06, 0x00,
13069 0x1e, 0x00, 0xbe, 0x00, 0xe1, 0x00, 0x0c, 0x12, 0x18, 0x1a, 0x70, 0x1a,
13070 0x30, 0x1c, 0x38, 0x1c,
13071 0x10, 0x44, 0x00, 0x4c, 0xb0, 0x57, 0x40, 0x5c, 0x4d, 0xe4, 0x04, 0xea,
13072 0x5d, 0xf0, 0xa7, 0xf0,
13073 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x09, 0x00, 0x19, 0x00, 0x32, 0x00,
13074 0x33, 0x00, 0x34, 0x00,
13075 0x36, 0x00, 0x98, 0x00, 0x9e, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01,
13076 0x79, 0x01, 0x3c, 0x09,
13077 0x68, 0x0d, 0x02, 0x10, 0x04, 0x10, 0x3a, 0x10, 0x08, 0x12, 0x0a, 0x13,
13078 0x40, 0x16, 0x50, 0x16,
13079 0x00, 0x17, 0x4a, 0x19, 0x00, 0x4e, 0x00, 0x54, 0x01, 0x58, 0x00, 0xdc,
13080 0x05, 0xf0, 0x09, 0xf0,
13081 0x59, 0xf0, 0xb8, 0xf0, 0x48, 0xf4, 0x0e, 0xf7, 0x0a, 0x00, 0x9b, 0x00,
13082 0x9c, 0x00, 0xa4, 0x00,
13083 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe7, 0x00, 0xf0, 0x03, 0x69, 0x08,
13084 0xe9, 0x09, 0x5c, 0x0c,
13085 0xb6, 0x12, 0xbc, 0x19, 0xd8, 0x1b, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c,
13086 0x42, 0x1d, 0x08, 0x44,
13087 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x89, 0x48, 0x68, 0x54,
13088 0x83, 0x55, 0x83, 0x59,
13089 0x31, 0xe4, 0x02, 0xe6, 0x07, 0xf0, 0x08, 0xf0, 0x0b, 0xf0, 0x0c, 0xf0,
13090 0x4b, 0xf4, 0x04, 0xf8,
13091 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa, 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00,
13092 0xa8, 0x00, 0xaa, 0x00,
13093 0xb9, 0x00, 0xe0, 0x00, 0xe5, 0x00, 0x22, 0x01, 0x26, 0x01, 0x60, 0x01,
13094 0x7a, 0x01, 0x82, 0x01,
13095 0xc8, 0x01, 0xca, 0x01, 0x86, 0x02, 0x6a, 0x03, 0x18, 0x05, 0xb2, 0x07,
13096 0x68, 0x08, 0x10, 0x0d,
13097 0x06, 0x10, 0x0a, 0x10, 0x0e, 0x10, 0x12, 0x10, 0x60, 0x10, 0xed, 0x10,
13098 0xf3, 0x10, 0x06, 0x12,
13099 0x10, 0x12, 0x1e, 0x12, 0x0c, 0x13, 0x0e, 0x13, 0x10, 0x13, 0xfe, 0x9c,
13100 0xf0, 0x35, 0x05, 0xfe,
13101 0xec, 0x0e, 0xff, 0x10, 0x00, 0x00, 0xe9, 0xfe, 0x34, 0x1f, 0x00, 0xe8,
13102 0xfe, 0x88, 0x01, 0xff,
13103 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
13104 0x00, 0xfe, 0x57, 0x24,
13105 0x00, 0xfe, 0x4c, 0x00, 0x65, 0xff, 0x04, 0x00, 0x00, 0x1a, 0xff, 0x09,
13106 0x00, 0x00, 0xff, 0x08,
13107 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
13108 0xff, 0xff, 0xff, 0x13,
13109 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
13110 0xfe, 0x04, 0xf7, 0xe8,
13111 0x37, 0x7d, 0x0d, 0x01, 0xfe, 0x4a, 0x11, 0xfe, 0x04, 0xf7, 0xe8, 0x7d,
13112 0x0d, 0x51, 0x37, 0xfe,
13113 0x3d, 0xf0, 0xfe, 0x0c, 0x02, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x91, 0xf0,
13114 0xfe, 0xf8, 0x01, 0xfe,
13115 0x90, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, 0x8f, 0xf0, 0xbc, 0x03, 0x67, 0x4d,
13116 0x05, 0xfe, 0x08, 0x0f,
13117 0x01, 0xfe, 0x78, 0x0f, 0xfe, 0xdd, 0x12, 0x05, 0xfe, 0x0e, 0x03, 0xfe,
13118 0x28, 0x1c, 0x03, 0xfe,
13119 0xa6, 0x00, 0xfe, 0xd1, 0x12, 0x3e, 0x22, 0xfe, 0xa6, 0x00, 0xac, 0xfe,
13120 0x48, 0xf0, 0xfe, 0x90,
13121 0x02, 0xfe, 0x49, 0xf0, 0xfe, 0xaa, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc8,
13122 0x02, 0xfe, 0x46, 0xf0,
13123 0xfe, 0x5a, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x60, 0x02, 0xfe, 0x43, 0xf0,
13124 0xfe, 0x4e, 0x02, 0xfe,
13125 0x44, 0xf0, 0xfe, 0x52, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x56, 0x02, 0x1c,
13126 0x0d, 0xa2, 0x1c, 0x07,
13127 0x22, 0xb7, 0x05, 0x35, 0xfe, 0x00, 0x1c, 0xfe, 0xf1, 0x10, 0xfe, 0x02,
13128 0x1c, 0xf5, 0xfe, 0x1e,
13129 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0x5f, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc,
13130 0xde, 0x0a, 0x81, 0x01,
13131 0xa3, 0x05, 0x35, 0x1f, 0x95, 0x47, 0xb8, 0x01, 0xfe, 0xe4, 0x11, 0x0a,
13132 0x81, 0x01, 0x5c, 0xfe,
13133 0xbd, 0x10, 0x0a, 0x81, 0x01, 0x5c, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c,
13134 0xfe, 0x58, 0x1c, 0x1c,
13135 0x07, 0x22, 0xb7, 0x37, 0x2a, 0x35, 0xfe, 0x3d, 0xf0, 0xfe, 0x0c, 0x02,
13136 0x2b, 0xfe, 0x9e, 0x02,
13137 0xfe, 0x5a, 0x1c, 0xfe, 0x12, 0x1c, 0xfe, 0x14, 0x1c, 0x1f, 0xfe, 0x30,
13138 0x00, 0x47, 0xb8, 0x01,
13139 0xfe, 0xd4, 0x11, 0x1c, 0x07, 0x22, 0xb7, 0x05, 0xe9, 0x21, 0x2c, 0x09,
13140 0x1a, 0x31, 0xfe, 0x69,
13141 0x10, 0x1c, 0x07, 0x22, 0xb7, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0x01, 0xfe,
13142 0x1e, 0x1e, 0x20, 0x2c,
13143 0xfe, 0x05, 0xf6, 0xde, 0x01, 0xfe, 0x62, 0x1b, 0x01, 0x0c, 0x61, 0x4a,
13144 0x44, 0x15, 0x56, 0x51,
13145 0x01, 0xfe, 0x9e, 0x1e, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x0a, 0x57,
13146 0x01, 0x18, 0x09, 0x00,
13147 0x36, 0x01, 0x85, 0xfe, 0x18, 0x10, 0xfe, 0x41, 0x58, 0x0a, 0xba, 0x01,
13148 0x18, 0xfe, 0xc8, 0x54,
13149 0x7b, 0xfe, 0x1c, 0x03, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x37, 0x60,
13150 0xfe, 0x02, 0xe8, 0x30,
13151 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe, 0x27, 0xf0,
13152 0xfe, 0xe4, 0x01, 0xfe,
13153 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x40, 0x1c, 0x2a, 0xeb, 0xfe,
13154 0x26, 0xf0, 0xfe, 0x66,
13155 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x54, 0x03, 0xfe, 0x11, 0xf0, 0xbc, 0xfe,
13156 0xef, 0x10, 0xfe, 0x9f,
13157 0xf0, 0xfe, 0x74, 0x03, 0xfe, 0x46, 0x1c, 0x19, 0xfe, 0x11, 0x00, 0x05,
13158 0x70, 0x37, 0xfe, 0x48,
13159 0x1c, 0xfe, 0x46, 0x1c, 0x01, 0x0c, 0x06, 0x28, 0xfe, 0x18, 0x13, 0x26,
13160 0x21, 0xb9, 0xc7, 0x20,
13161 0xb9, 0x0a, 0x57, 0x01, 0x18, 0xc7, 0x89, 0x01, 0xfe, 0xc8, 0x1a, 0x15,
13162 0xe1, 0x2a, 0xeb, 0xfe,
13163 0x01, 0xf0, 0xeb, 0xfe, 0x82, 0xf0, 0xfe, 0xa4, 0x03, 0xfe, 0x9c, 0x32,
13164 0x15, 0xfe, 0xe4, 0x00,
13165 0x2f, 0xfe, 0xb6, 0x03, 0x2a, 0x3c, 0x16, 0xfe, 0xc6, 0x03, 0x01, 0x41,
13166 0xfe, 0x06, 0xf0, 0xfe,
13167 0xd6, 0x03, 0xaf, 0xa0, 0xfe, 0x0a, 0xf0, 0xfe, 0xa2, 0x07, 0x05, 0x29,
13168 0x03, 0x81, 0x1e, 0x1b,
13169 0xfe, 0x24, 0x05, 0x1f, 0x63, 0x01, 0x42, 0x8f, 0xfe, 0x70, 0x02, 0x05,
13170 0xea, 0xfe, 0x46, 0x1c,
13171 0x37, 0x7d, 0x1d, 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57,
13172 0xfe, 0x48, 0x1c, 0x75,
13173 0x01, 0xa6, 0x86, 0x0a, 0x57, 0x01, 0x18, 0x09, 0x00, 0x1b, 0xec, 0x0a,
13174 0xe1, 0x01, 0x18, 0x77,
13175 0x50, 0x40, 0x8d, 0x30, 0x03, 0x81, 0x1e, 0xf8, 0x1f, 0x63, 0x01, 0x42,
13176 0x8f, 0xfe, 0x70, 0x02,
13177 0x05, 0xea, 0xd7, 0x99, 0xd8, 0x9c, 0x2a, 0x29, 0x2f, 0xfe, 0x4e, 0x04,
13178 0x16, 0xfe, 0x4a, 0x04,
13179 0x7e, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x54, 0x12, 0x32, 0xff,
13180 0x02, 0x00, 0x10, 0x01,
13181 0x08, 0x16, 0xfe, 0x02, 0x05, 0x32, 0x01, 0x08, 0x16, 0x29, 0x27, 0x25,
13182 0xee, 0xfe, 0x4c, 0x44,
13183 0xfe, 0x58, 0x12, 0x50, 0xfe, 0x44, 0x48, 0x13, 0x34, 0xfe, 0x4c, 0x54,
13184 0x7b, 0xec, 0x60, 0x8d,
13185 0x30, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x7c, 0x13, 0x01,
13186 0x0c, 0x06, 0x28, 0xfe,
13187 0x32, 0x13, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x68, 0x13, 0xfe, 0x26, 0x10,
13188 0x13, 0x34, 0xfe, 0x4c,
13189 0x54, 0x7b, 0xec, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x54,
13190 0x13, 0x01, 0x0c, 0x06,
13191 0x28, 0xa5, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x40, 0x13, 0x01, 0x0c, 0x06,
13192 0x28, 0xf9, 0x1f, 0x7f,
13193 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42, 0x8f,
13194 0xfe, 0xa4, 0x0e, 0x05,
13195 0x29, 0x32, 0x15, 0xfe, 0xe6, 0x00, 0x0f, 0xfe, 0x1c, 0x90, 0x04, 0xfe,
13196 0x9c, 0x93, 0x3a, 0x0b,
13197 0x0e, 0x8b, 0x02, 0x1f, 0x7f, 0x01, 0x42, 0x05, 0x35, 0xfe, 0x42, 0x5b,
13198 0x7d, 0x1d, 0xfe, 0x46,
13199 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0x0f, 0xfe, 0x87, 0x80, 0x04,
13200 0xfe, 0x87, 0x83, 0xfe,
13201 0xc9, 0x47, 0x0b, 0x0e, 0xd0, 0x65, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x98,
13202 0x13, 0x0f, 0xfe, 0x20,
13203 0x80, 0x04, 0xfe, 0xa0, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x1d, 0xfe, 0x84,
13204 0x12, 0x01, 0x38, 0x06,
13205 0x07, 0xfe, 0x70, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x1e, 0x1b, 0xfe, 0xda,
13206 0x05, 0xd0, 0x54, 0x01,
13207 0x38, 0x06, 0x0d, 0xfe, 0x58, 0x13, 0x03, 0xfe, 0xa0, 0x00, 0x1e, 0xfe,
13208 0x50, 0x12, 0x5e, 0xff,
13209 0x02, 0x00, 0x10, 0x2f, 0xfe, 0x90, 0x05, 0x2a, 0x3c, 0xcc, 0xff, 0x02,
13210 0x00, 0x10, 0x2f, 0xfe,
13211 0x9e, 0x05, 0x17, 0xfe, 0xf4, 0x05, 0x15, 0xfe, 0xe3, 0x00, 0x26, 0x01,
13212 0x38, 0xfe, 0x4a, 0xf0,
13213 0xfe, 0xc0, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0xba, 0x05, 0x71, 0x2e, 0xfe,
13214 0x21, 0x00, 0xf1, 0x2e,
13215 0xfe, 0x22, 0x00, 0xa2, 0x2e, 0x4a, 0xfe, 0x09, 0x48, 0xff, 0x02, 0x00,
13216 0x10, 0x2f, 0xfe, 0xd0,
13217 0x05, 0x17, 0xfe, 0xf4, 0x05, 0xfe, 0xe2, 0x08, 0x01, 0x38, 0x06, 0xfe,
13218 0x1c, 0x00, 0x4d, 0x01,
13219 0xa7, 0x2e, 0x07, 0x20, 0xe4, 0x47, 0xfe, 0x27, 0x01, 0x01, 0x0c, 0x06,
13220 0x28, 0xfe, 0x24, 0x12,
13221 0x3e, 0x01, 0x84, 0x1f, 0x7f, 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe,
13222 0x0d, 0x00, 0x01, 0x42,
13223 0x8f, 0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x03, 0xe6, 0x1e, 0xfe, 0xca, 0x13,
13224 0x03, 0xb6, 0x1e, 0xfe,
13225 0x40, 0x12, 0x03, 0x66, 0x1e, 0xfe, 0x38, 0x13, 0x3e, 0x01, 0x84, 0x17,
13226 0xfe, 0x72, 0x06, 0x0a,
13227 0x07, 0x01, 0x38, 0x06, 0x24, 0xfe, 0x02, 0x12, 0x4f, 0x01, 0xfe, 0x56,
13228 0x19, 0x16, 0xfe, 0x68,
13229 0x06, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x66, 0x8a, 0x10, 0x66,
13230 0x03, 0x9a, 0x1e, 0xfe,
13231 0x70, 0x12, 0x03, 0x55, 0x1e, 0xfe, 0x68, 0x13, 0x01, 0xc6, 0x09, 0x12,
13232 0x48, 0xfe, 0x92, 0x06,
13233 0x2e, 0x12, 0x01, 0xfe, 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0x13,
13234 0x58, 0xff, 0x02, 0x00,
13235 0x57, 0x52, 0xad, 0x23, 0x3f, 0x4e, 0x62, 0x49, 0x3e, 0x01, 0x84, 0x17,
13236 0xfe, 0xea, 0x06, 0x01,
13237 0x38, 0x06, 0x12, 0xf7, 0x45, 0x0a, 0x95, 0x01, 0xfe, 0x84, 0x19, 0x16,
13238 0xfe, 0xe0, 0x06, 0x15,
13239 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x1c, 0x07,
13240 0x01, 0x84, 0xfe, 0xae,
13241 0x10, 0x03, 0x6f, 0x1e, 0xfe, 0x9e, 0x13, 0x3e, 0x01, 0x84, 0x03, 0x9a,
13242 0x1e, 0xfe, 0x1a, 0x12,
13243 0x01, 0x38, 0x06, 0x12, 0xfc, 0x01, 0xc6, 0x01, 0xfe, 0xac, 0x1d, 0xfe,
13244 0x43, 0x48, 0x62, 0x80,
13245 0xf0, 0x45, 0x0a, 0x95, 0x03, 0xb6, 0x1e, 0xf8, 0x01, 0x38, 0x06, 0x24,
13246 0x36, 0xfe, 0x02, 0xf6,
13247 0x07, 0x71, 0x78, 0x8c, 0x00, 0x4d, 0x62, 0x49, 0x3e, 0x2d, 0x93, 0x4e,
13248 0xd0, 0x0d, 0x17, 0xfe,
13249 0x9a, 0x07, 0x01, 0xfe, 0xc0, 0x19, 0x16, 0xfe, 0x90, 0x07, 0x26, 0x20,
13250 0x9e, 0x15, 0x82, 0x01,
13251 0x41, 0x15, 0xe2, 0x21, 0x9e, 0x09, 0x07, 0xfb, 0x03, 0xe6, 0xfe, 0x58,
13252 0x57, 0x10, 0xe6, 0x05,
13253 0xfe, 0x2a, 0x06, 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x1c, 0x07, 0x01, 0x84,
13254 0xfe, 0x9c, 0x32, 0x5f,
13255 0x75, 0x01, 0xa6, 0x86, 0x15, 0xfe, 0xe2, 0x00, 0x2f, 0xed, 0x2a, 0x3c,
13256 0xfe, 0x0a, 0xf0, 0xfe,
13257 0xce, 0x07, 0xae, 0xfe, 0x96, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x9e, 0x08,
13258 0xaf, 0xa0, 0x05, 0x29,
13259 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x2e, 0x12, 0x14, 0x1d, 0x01, 0x08, 0x14,
13260 0x00, 0x01, 0x08, 0x14,
13261 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08,
13262 0x14, 0x00, 0x05, 0xfe,
13263 0xc6, 0x09, 0x01, 0x76, 0x06, 0x12, 0xfe, 0x3a, 0x12, 0x01, 0x0c, 0x06,
13264 0x12, 0xfe, 0x30, 0x13,
13265 0x14, 0xfe, 0x1b, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00,
13266 0x01, 0x08, 0x14, 0x00,
13267 0x01, 0x08, 0x14, 0x07, 0x01, 0x08, 0x14, 0x00, 0x05, 0xef, 0x7c, 0x4a,
13268 0x78, 0x4f, 0x0f, 0xfe,
13269 0x9a, 0x81, 0x04, 0xfe, 0x9a, 0x83, 0xfe, 0xcb, 0x47, 0x0b, 0x0e, 0x2d,
13270 0x28, 0x48, 0xfe, 0x6c,
13271 0x08, 0x0a, 0x28, 0xfe, 0x09, 0x6f, 0xca, 0xfe, 0xca, 0x45, 0xfe, 0x32,
13272 0x12, 0x53, 0x63, 0x4e,
13273 0x7c, 0x97, 0x2f, 0xfe, 0x7e, 0x08, 0x2a, 0x3c, 0xfe, 0x0a, 0xf0, 0xfe,
13274 0x6c, 0x08, 0xaf, 0xa0,
13275 0xae, 0xfe, 0x96, 0x08, 0x05, 0x29, 0x01, 0x41, 0x05, 0xed, 0x14, 0x24,
13276 0x05, 0xed, 0xfe, 0x9c,
13277 0xf7, 0x9f, 0x01, 0xfe, 0xae, 0x1e, 0xfe, 0x18, 0x58, 0x01, 0xfe, 0xbe,
13278 0x1e, 0xfe, 0x99, 0x58,
13279 0xfe, 0x78, 0x18, 0xfe, 0xf9, 0x18, 0x8e, 0xfe, 0x16, 0x09, 0x10, 0x6a,
13280 0x22, 0x6b, 0x01, 0x0c,
13281 0x61, 0x54, 0x44, 0x21, 0x2c, 0x09, 0x1a, 0xf8, 0x77, 0x01, 0xfe, 0x7e,
13282 0x1e, 0x47, 0x2c, 0x7a,
13283 0x30, 0xf0, 0xfe, 0x83, 0xe7, 0xfe, 0x3f, 0x00, 0x71, 0xfe, 0x03, 0x40,
13284 0x01, 0x0c, 0x61, 0x65,
13285 0x44, 0x01, 0xc2, 0xc8, 0xfe, 0x1f, 0x40, 0x20, 0x6e, 0x01, 0xfe, 0x6a,
13286 0x16, 0xfe, 0x08, 0x50,
13287 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6, 0x51, 0xfe, 0x10, 0x10,
13288 0x01, 0xfe, 0xce, 0x1e,
13289 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x01, 0xfe, 0xee, 0x1e,
13290 0x01, 0xfe, 0xfe, 0x1e,
13291 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x10, 0x4b, 0x22, 0x4c, 0xfe, 0x8a,
13292 0x10, 0x01, 0x0c, 0x06,
13293 0x54, 0xfe, 0x50, 0x12, 0x01, 0xfe, 0xae, 0x1e, 0x01, 0xfe, 0xbe, 0x1e,
13294 0x10, 0x6a, 0x22, 0x6b,
13295 0x01, 0x0c, 0x06, 0x65, 0x4e, 0x01, 0xc2, 0x0f, 0xfe, 0x1f, 0x80, 0x04,
13296 0xfe, 0x9f, 0x83, 0x33,
13297 0x0b, 0x0e, 0x20, 0x6e, 0x0f, 0xfe, 0x44, 0x90, 0x04, 0xfe, 0xc4, 0x93,
13298 0x3a, 0x0b, 0xfe, 0xc6,
13299 0x90, 0x04, 0xfe, 0xc6, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x6c, 0x22, 0x6d,
13300 0x01, 0xfe, 0xce, 0x1e,
13301 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x0f, 0xfe, 0x40, 0x90,
13302 0x04, 0xfe, 0xc0, 0x93,
13303 0x3a, 0x0b, 0xfe, 0xc2, 0x90, 0x04, 0xfe, 0xc2, 0x93, 0x79, 0x0b, 0x0e,
13304 0x10, 0x4b, 0x22, 0x4c,
13305 0x10, 0x64, 0x22, 0x34, 0x01, 0x0c, 0x61, 0x24, 0x44, 0x37, 0x13, 0xfe,
13306 0x4e, 0x11, 0x2f, 0xfe,
13307 0xde, 0x09, 0xfe, 0x9e, 0xf0, 0xfe, 0xf2, 0x09, 0xfe, 0x01, 0x48, 0x1b,
13308 0x3c, 0x37, 0x88, 0xf5,
13309 0xd4, 0xfe, 0x1e, 0x0a, 0xd5, 0xfe, 0x42, 0x0a, 0xd2, 0xfe, 0x1e, 0x0a,
13310 0xd3, 0xfe, 0x42, 0x0a,
13311 0xae, 0xfe, 0x12, 0x0a, 0xfe, 0x06, 0xf0, 0xfe, 0x18, 0x0a, 0xaf, 0xa0,
13312 0x05, 0x29, 0x01, 0x41,
13313 0xfe, 0xc1, 0x10, 0x14, 0x24, 0xfe, 0xc1, 0x10, 0x01, 0x76, 0x06, 0x07,
13314 0xfe, 0x14, 0x12, 0x01,
13315 0x76, 0x06, 0x0d, 0x5d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x74, 0x12, 0xfe,
13316 0x2e, 0x1c, 0x05, 0xfe,
13317 0x1a, 0x0c, 0x01, 0x76, 0x06, 0x07, 0x5d, 0x01, 0x76, 0x06, 0x0d, 0x41,
13318 0xfe, 0x2c, 0x1c, 0xfe,
13319 0xaa, 0xf0, 0xfe, 0xce, 0x0a, 0xfe, 0xac, 0xf0, 0xfe, 0x66, 0x0a, 0xfe,
13320 0x92, 0x10, 0xc4, 0xf6,
13321 0xfe, 0xad, 0xf0, 0xfe, 0x72, 0x0a, 0x05, 0xfe, 0x1a, 0x0c, 0xc5, 0xfe,
13322 0xe7, 0x10, 0xfe, 0x2b,
13323 0xf0, 0xbf, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xfe, 0xfe, 0x1c, 0x12,
13324 0xac, 0xfe, 0xd2, 0xf0,
13325 0xbf, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x1b, 0xbf, 0x03, 0xe3, 0x23, 0x07,
13326 0x1b, 0xbf, 0xd4, 0x5b,
13327 0xd5, 0x5b, 0xd2, 0x5b, 0xd3, 0x5b, 0xc4, 0xc5, 0xfe, 0xa9, 0x10, 0x75,
13328 0x5e, 0x32, 0x1f, 0x7f,
13329 0x01, 0x42, 0x19, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x70, 0x19, 0x98,
13330 0x05, 0x70, 0xfe, 0x74,
13331 0x18, 0x23, 0xfe, 0x00, 0xf8, 0x1b, 0x5b, 0x7d, 0x12, 0x01, 0xfe, 0x78,
13332 0x0f, 0x4d, 0x01, 0xfe,
13333 0x96, 0x1a, 0x21, 0x30, 0x77, 0x7d, 0x1d, 0x05, 0x5b, 0x01, 0x0c, 0x06,
13334 0x0d, 0x2b, 0xfe, 0xe2,
13335 0x0b, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0xa6, 0x12, 0x01, 0x0c, 0x06, 0x24,
13336 0xfe, 0x88, 0x13, 0x21,
13337 0x6e, 0xc7, 0x01, 0xfe, 0x1e, 0x1f, 0x0f, 0xfe, 0x83, 0x80, 0x04, 0xfe,
13338 0x83, 0x83, 0xfe, 0xc9,
13339 0x47, 0x0b, 0x0e, 0xfe, 0xc8, 0x44, 0xfe, 0x42, 0x13, 0x0f, 0xfe, 0x04,
13340 0x91, 0x04, 0xfe, 0x84,
13341 0x93, 0xfe, 0xca, 0x57, 0x0b, 0xfe, 0x86, 0x91, 0x04, 0xfe, 0x86, 0x93,
13342 0xfe, 0xcb, 0x57, 0x0b,
13343 0x0e, 0x7a, 0x30, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x8e, 0x40, 0x03,
13344 0x6a, 0x3b, 0x6b, 0x10,
13345 0x97, 0x22, 0x98, 0xd9, 0x6a, 0xda, 0x6b, 0x01, 0xc2, 0xc8, 0x7a, 0x30,
13346 0x20, 0x6e, 0xdb, 0x64,
13347 0xdc, 0x34, 0x91, 0x6c, 0x7e, 0x6d, 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55,
13348 0xfe, 0x04, 0xfa, 0x64,
13349 0xfe, 0x05, 0xfa, 0x34, 0x01, 0xfe, 0x6a, 0x16, 0xa3, 0x26, 0x10, 0x97,
13350 0x10, 0x98, 0x91, 0x6c,
13351 0x7e, 0x6d, 0xfe, 0x14, 0x10, 0x01, 0x0c, 0x06, 0x24, 0x1b, 0x40, 0x91,
13352 0x4b, 0x7e, 0x4c, 0x01,
13353 0x0c, 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x10,
13354 0x58, 0xfe, 0x91, 0x58,
13355 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x05, 0x5b, 0x01, 0x0c, 0x06, 0x24,
13356 0x1b, 0x40, 0x01, 0x0c,
13357 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x78, 0x01, 0xfe, 0x8e, 0x1e, 0x4f, 0x0f,
13358 0xfe, 0x10, 0x90, 0x04,
13359 0xfe, 0x90, 0x93, 0x3a, 0x0b, 0xfe, 0x92, 0x90, 0x04, 0xfe, 0x92, 0x93,
13360 0x79, 0x0b, 0x0e, 0xfe,
13361 0xbd, 0x10, 0x01, 0x43, 0x09, 0xbb, 0x1b, 0xfe, 0x6e, 0x0a, 0x15, 0xbb,
13362 0x01, 0x0c, 0x06, 0x0d,
13363 0xfe, 0x14, 0x13, 0x03, 0x4b, 0x3b, 0x4c, 0x8e, 0xfe, 0x6e, 0x0a, 0xfe,
13364 0x0c, 0x58, 0xfe, 0x8d,
13365 0x58, 0x05, 0x5b, 0x26, 0x3e, 0x0f, 0xfe, 0x19, 0x80, 0x04, 0xfe, 0x99,
13366 0x83, 0x33, 0x0b, 0x0e,
13367 0xfe, 0xe5, 0x10, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1a, 0x12, 0xfe, 0x6c,
13368 0x19, 0xfe, 0x19, 0x41,
13369 0xfe, 0x6b, 0x18, 0xac, 0xfe, 0xd1, 0xf0, 0xef, 0x1f, 0x92, 0x01, 0x42,
13370 0x19, 0xfe, 0x44, 0x00,
13371 0xfe, 0x90, 0x10, 0xfe, 0x6c, 0x19, 0xd9, 0x4b, 0xfe, 0xed, 0x19, 0xda,
13372 0x4c, 0xfe, 0x0c, 0x51,
13373 0xfe, 0x8e, 0x51, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xff, 0x31, 0xfe,
13374 0x76, 0x10, 0xac, 0xfe,
13375 0xd2, 0xf0, 0xfe, 0xba, 0x0c, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x5d, 0x03,
13376 0xe3, 0x23, 0x07, 0xfe,
13377 0x08, 0x13, 0x19, 0xfe, 0x16, 0x00, 0x05, 0x70, 0xfe, 0xd1, 0xf0, 0xfe,
13378 0xcc, 0x0c, 0x1f, 0x92,
13379 0x01, 0x42, 0x19, 0xfe, 0x17, 0x00, 0x5c, 0xfe, 0xce, 0xf0, 0xfe, 0xd2,
13380 0x0c, 0xfe, 0x3e, 0x10,
13381 0xfe, 0xcd, 0xf0, 0xfe, 0xde, 0x0c, 0x19, 0xfe, 0x22, 0x00, 0x05, 0x70,
13382 0xfe, 0xcb, 0xf0, 0xfe,
13383 0xea, 0x0c, 0x19, 0xfe, 0x24, 0x00, 0x05, 0x70, 0xfe, 0xd0, 0xf0, 0xfe,
13384 0xf4, 0x0c, 0x19, 0x94,
13385 0xfe, 0x1c, 0x10, 0xfe, 0xcf, 0xf0, 0xfe, 0xfe, 0x0c, 0x19, 0x4a, 0xf3,
13386 0xfe, 0xcc, 0xf0, 0xef,
13387 0x01, 0x76, 0x06, 0x24, 0x4d, 0x19, 0xfe, 0x12, 0x00, 0x37, 0x13, 0xfe,
13388 0x4e, 0x11, 0x2f, 0xfe,
13389 0x16, 0x0d, 0xfe, 0x9e, 0xf0, 0xfe, 0x2a, 0x0d, 0xfe, 0x01, 0x48, 0x1b,
13390 0x3c, 0x37, 0x88, 0xf5,
13391 0xd4, 0x29, 0xd5, 0x29, 0xd2, 0x29, 0xd3, 0x29, 0x37, 0xfe, 0x9c, 0x32,
13392 0x2f, 0xfe, 0x3e, 0x0d,
13393 0x2a, 0x3c, 0xae, 0xfe, 0x62, 0x0d, 0xaf, 0xa0, 0xd4, 0x9f, 0xd5, 0x9f,
13394 0xd2, 0x9f, 0xd3, 0x9f,
13395 0x05, 0x29, 0x01, 0x41, 0xfe, 0xd3, 0x10, 0x15, 0xfe, 0xe8, 0x00, 0xc4,
13396 0xc5, 0x75, 0xd7, 0x99,
13397 0xd8, 0x9c, 0xfe, 0x89, 0xf0, 0x29, 0x27, 0x25, 0xbe, 0xd7, 0x99, 0xd8,
13398 0x9c, 0x2f, 0xfe, 0x8c,
13399 0x0d, 0x16, 0x29, 0x27, 0x25, 0xbd, 0xfe, 0x01, 0x48, 0xa4, 0x19, 0xfe,
13400 0x42, 0x00, 0x05, 0x70,
13401 0x90, 0x07, 0xfe, 0x81, 0x49, 0x1b, 0xfe, 0x64, 0x0e, 0x01, 0x0c, 0x06,
13402 0x0d, 0xfe, 0x44, 0x13,
13403 0x19, 0x00, 0x2d, 0x0d, 0xfe, 0x54, 0x12, 0x2d, 0xfe, 0x28, 0x00, 0x2b,
13404 0xfe, 0xda, 0x0e, 0x0a,
13405 0x57, 0x01, 0x18, 0x09, 0x00, 0x36, 0x46, 0xfe, 0x28, 0x00, 0xfe, 0xfa,
13406 0x10, 0x01, 0xfe, 0xf4,
13407 0x1c, 0x01, 0xfe, 0x00, 0x1d, 0x0a, 0xba, 0x01, 0xfe, 0x58, 0x10, 0x40,
13408 0x15, 0x56, 0x01, 0x85,
13409 0x05, 0x35, 0x19, 0xfe, 0x44, 0x00, 0x2d, 0x0d, 0xf7, 0x46, 0x0d, 0xfe,
13410 0xcc, 0x10, 0x01, 0xa7,
13411 0x46, 0x0d, 0xfe, 0xc2, 0x10, 0x01, 0xa7, 0x0f, 0xfe, 0x19, 0x82, 0x04,
13412 0xfe, 0x99, 0x83, 0xfe,
13413 0xcc, 0x47, 0x0b, 0x0e, 0xfe, 0x34, 0x46, 0xa5, 0x46, 0x0d, 0x19, 0xfe,
13414 0x43, 0x00, 0xfe, 0xa2,
13415 0x10, 0x01, 0x0c, 0x61, 0x0d, 0x44, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe,
13416 0x00, 0x1d, 0x40, 0x15,
13417 0x56, 0x01, 0x85, 0x7d, 0x0d, 0x40, 0x51, 0x01, 0xfe, 0x9e, 0x1e, 0x05,
13418 0xfe, 0x3a, 0x03, 0x01,
13419 0x0c, 0x06, 0x0d, 0x5d, 0x46, 0x0d, 0x19, 0x00, 0xfe, 0x62, 0x10, 0x01,
13420 0x76, 0x06, 0x12, 0xfe,
13421 0x5c, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x52, 0x13, 0xfe, 0x1c, 0x1c,
13422 0xfe, 0x9d, 0xf0, 0xfe,
13423 0x8e, 0x0e, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x94, 0x0e, 0x01,
13424 0x0c, 0x61, 0x12, 0x44,
13425 0xfe, 0x9f, 0x10, 0x19, 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0d, 0x4f,
13426 0xfe, 0x2e, 0x10, 0x19,
13427 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x19, 0xfe, 0x47, 0x00, 0xf1, 0x19,
13428 0xfe, 0x41, 0x00, 0xa2,
13429 0x19, 0xfe, 0x24, 0x00, 0x86, 0xc4, 0xc5, 0x75, 0x03, 0x81, 0x1e, 0x2b,
13430 0xea, 0x4f, 0xfe, 0x04,
13431 0xe6, 0x12, 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, 0x40, 0x01, 0xf4, 0x05,
13432 0x35, 0xfe, 0x12, 0x1c,
13433 0x1f, 0x0d, 0x47, 0xb5, 0xc3, 0x1f, 0xfe, 0x31, 0x00, 0x47, 0xb8, 0x01,
13434 0xfe, 0xd4, 0x11, 0x05,
13435 0xe9, 0x51, 0xfe, 0x06, 0xec, 0xe0, 0xfe, 0x0e, 0x47, 0x46, 0x28, 0xfe,
13436 0xce, 0x45, 0x31, 0x51,
13437 0xfe, 0x06, 0xea, 0xe0, 0xfe, 0x47, 0x4b, 0x45, 0xfe, 0x75, 0x57, 0x03,
13438 0x67, 0xfe, 0x98, 0x56,
13439 0xfe, 0x38, 0x12, 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x44, 0x48, 0x60, 0x01,
13440 0x0c, 0x06, 0x28, 0xfe,
13441 0x18, 0x13, 0x0a, 0x57, 0x01, 0x18, 0x3e, 0xfe, 0x41, 0x58, 0x0a, 0xba,
13442 0xfe, 0xfa, 0x14, 0xfe,
13443 0x49, 0x54, 0xb0, 0xfe, 0x5e, 0x0f, 0x05, 0xfe, 0x3a, 0x03, 0x0a, 0x67,
13444 0xfe, 0xe0, 0x14, 0xfe,
13445 0x0e, 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0xce, 0x47,
13446 0xfe, 0xad, 0x13, 0x05,
13447 0x35, 0x21, 0x2c, 0x09, 0x1a, 0xfe, 0x98, 0x12, 0x26, 0x20, 0x96, 0x20,
13448 0xe7, 0xfe, 0x08, 0x1c,
13449 0xfe, 0x7c, 0x19, 0xfe, 0xfd, 0x19, 0xfe, 0x0a, 0x1c, 0x03, 0xe5, 0xfe,
13450 0x48, 0x55, 0xa5, 0x3b,
13451 0xfe, 0x62, 0x01, 0xfe, 0xc9, 0x55, 0x31, 0xfe, 0x74, 0x10, 0x01, 0xfe,
13452 0xf0, 0x1a, 0x03, 0xfe,
13453 0x38, 0x01, 0x3b, 0xfe, 0x3a, 0x01, 0x8e, 0xfe, 0x1e, 0x10, 0xfe, 0x02,
13454 0xec, 0xe7, 0x53, 0x00,
13455 0x36, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01,
13456 0x01, 0xfe, 0x62, 0x1b,
13457 0x01, 0xfe, 0xce, 0x1e, 0xb2, 0x11, 0xfe, 0x18, 0x13, 0xca, 0xfe, 0x02,
13458 0xea, 0xe7, 0x53, 0x92,
13459 0xfe, 0xc3, 0x13, 0x1f, 0x12, 0x47, 0xb5, 0xc3, 0xfe, 0x2a, 0x10, 0x03,
13460 0xfe, 0x38, 0x01, 0x23,
13461 0xfe, 0xf0, 0xff, 0x10, 0xe5, 0x03, 0xfe, 0x3a, 0x01, 0x10, 0xfe, 0x62,
13462 0x01, 0x01, 0xfe, 0x1e,
13463 0x1e, 0x20, 0x2c, 0x15, 0x56, 0x01, 0xfe, 0x9e, 0x1e, 0x13, 0x07, 0x02,
13464 0x26, 0x02, 0x21, 0x96,
13465 0xc7, 0x20, 0x96, 0x09, 0x92, 0xfe, 0x79, 0x13, 0x1f, 0x1d, 0x47, 0xb5,
13466 0xc3, 0xfe, 0xe1, 0x10,
13467 0xcf, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xcf,
13468 0xfe, 0x03, 0xdc, 0xfe,
13469 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x26, 0xfe,
13470 0x00, 0xcc, 0x02, 0xfe,
13471 0x03, 0x57, 0xcf, 0x89, 0x02, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13,
13472 0x0f, 0xfe, 0x1c, 0x80,
13473 0x04, 0xfe, 0x9c, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x07, 0xfe, 0x3a, 0x13,
13474 0x0f, 0xfe, 0x1e, 0x80,
13475 0x04, 0xfe, 0x9e, 0x83, 0x33, 0x0b, 0x0e, 0xfe, 0x2a, 0x13, 0x0f, 0xfe,
13476 0x1d, 0x80, 0x04, 0xfe,
13477 0x9d, 0x83, 0xfe, 0xf9, 0x13, 0x0e, 0xfe, 0x1c, 0x13, 0x01, 0xfe, 0xee,
13478 0x1e, 0xac, 0xfe, 0x14,
13479 0x13, 0x01, 0xfe, 0xfe, 0x1e, 0xfe, 0x81, 0x58, 0xfa, 0x01, 0xfe, 0x0e,
13480 0x1f, 0xfe, 0x30, 0xf4,
13481 0x0d, 0xfe, 0x3c, 0x50, 0xa2, 0x01, 0xfe, 0x92, 0x1b, 0x01, 0x43, 0x09,
13482 0x56, 0xfb, 0x01, 0xfe,
13483 0xc8, 0x1a, 0x01, 0x0c, 0x06, 0x28, 0xa4, 0x01, 0xfe, 0xf4, 0x1c, 0x01,
13484 0xfe, 0x00, 0x1d, 0x15,
13485 0xfe, 0xe9, 0x00, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13, 0x01, 0xfe,
13486 0x22, 0x1b, 0xfe, 0x1e,
13487 0x1c, 0x0f, 0xfe, 0x14, 0x90, 0x04, 0xfe, 0x94, 0x93, 0x3a, 0x0b, 0xfe,
13488 0x96, 0x90, 0x04, 0xfe,
13489 0x96, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0xfe, 0x64, 0x01, 0x22, 0xfe, 0x66,
13490 0x01, 0x01, 0x0c, 0x06,
13491 0x65, 0xf9, 0x0f, 0xfe, 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b,
13492 0x0e, 0x77, 0xfe, 0x01,
13493 0xec, 0x2c, 0xfe, 0x80, 0x40, 0x20, 0x2c, 0x7a, 0x30, 0x15, 0xdf, 0x40,
13494 0x21, 0x2c, 0xfe, 0x00,
13495 0x40, 0x8d, 0x2c, 0x02, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe,
13496 0x06, 0x58, 0x03, 0xfe,
13497 0xae, 0x00, 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58,
13498 0x03, 0xfe, 0xb2, 0x00,
13499 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x2e, 0x49, 0x20, 0xe0, 0x26, 0x10,
13500 0x66, 0x10, 0x55, 0x10,
13501 0x6f, 0x13, 0x57, 0x52, 0x4f, 0x1c, 0x28, 0xfe, 0x90, 0x4d, 0xfe, 0x91,
13502 0x54, 0x2b, 0xfe, 0x88,
13503 0x11, 0x46, 0x1a, 0x13, 0x5a, 0x52, 0x1c, 0x4a, 0xfe, 0x90, 0x4d, 0xfe,
13504 0x91, 0x54, 0x2b, 0xfe,
13505 0x9e, 0x11, 0x2e, 0x1a, 0x20, 0x2c, 0x90, 0x34, 0x60, 0x21, 0x2c, 0xfe,
13506 0x00, 0x40, 0x8d, 0x2c,
13507 0x15, 0xdf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0xb2, 0x11, 0xfe,
13508 0x12, 0x1c, 0x75, 0xfe,
13509 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x02, 0x51, 0xfe, 0x0c,
13510 0x14, 0xfe, 0x0e, 0x47,
13511 0xfe, 0x07, 0xe6, 0x28, 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x02, 0x01,
13512 0xa7, 0x90, 0x34, 0x60,
13513 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42, 0x13, 0xfe, 0x02, 0x80,
13514 0x09, 0x56, 0xfe, 0x34,
13515 0x13, 0x0a, 0x5a, 0x01, 0x18, 0xcb, 0xfe, 0x36, 0x12, 0xfe, 0x41, 0x48,
13516 0xfe, 0x45, 0x48, 0x01,
13517 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f, 0x89,
13518 0x09, 0x1a, 0xa5, 0x0a,
13519 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x5c, 0x01, 0x85, 0xf2, 0x09, 0x9b, 0xa4,
13520 0xfe, 0x14, 0x56, 0xfe,
13521 0xd6, 0xf0, 0xfe, 0xec, 0x11, 0x02, 0xfe, 0x44, 0x58, 0x77, 0xfe, 0x01,
13522 0xec, 0xb8, 0xfe, 0x9e,
13523 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x12, 0x8d, 0x30, 0x01,
13524 0xf4, 0xfe, 0xdd, 0x10,
13525 0x37, 0xd7, 0x99, 0xd8, 0x9c, 0x27, 0x25, 0xee, 0x09, 0x12, 0xfe, 0x48,
13526 0x12, 0x09, 0x0d, 0xfe,
13527 0x56, 0x12, 0x09, 0x1d, 0xfe, 0x30, 0x12, 0x09, 0xdd, 0x1b, 0xfe, 0xc4,
13528 0x13, 0x09, 0xfe, 0x23,
13529 0x00, 0x1b, 0xfe, 0xd0, 0x13, 0x09, 0x07, 0x1b, 0xfe, 0x34, 0x14, 0x09,
13530 0x24, 0xfe, 0x12, 0x12,
13531 0x09, 0x00, 0x1b, 0x29, 0x1f, 0xdd, 0x01, 0x42, 0xa1, 0x32, 0x01, 0x08,
13532 0xae, 0x41, 0x02, 0x32,
13533 0xfe, 0x62, 0x08, 0x0a, 0xe1, 0x01, 0xfe, 0x58, 0x10, 0x15, 0x9b, 0x05,
13534 0x35, 0x32, 0x01, 0x43,
13535 0x09, 0xbb, 0xfe, 0xd7, 0x13, 0x91, 0x4b, 0x7e, 0x4c, 0x8e, 0xfe, 0x80,
13536 0x13, 0x01, 0x0c, 0x06,
13537 0x54, 0xfe, 0x72, 0x12, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x44, 0x55, 0xfe,
13538 0xe5, 0x55, 0xb0, 0xfe,
13539 0x4a, 0x13, 0x21, 0x6e, 0xfe, 0x26, 0x13, 0x03, 0x97, 0x3b, 0x98, 0x8e,
13540 0xfe, 0xb6, 0x0e, 0x10,
13541 0x6a, 0x22, 0x6b, 0x26, 0x10, 0x97, 0x10, 0x98, 0x01, 0xc2, 0x2e, 0x49,
13542 0x88, 0x20, 0x6e, 0x01,
13543 0xfe, 0x6a, 0x16, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x04, 0x55, 0xfe, 0xa5,
13544 0x55, 0xfe, 0x04, 0xfa,
13545 0x64, 0xfe, 0x05, 0xfa, 0x34, 0xfe, 0x8f, 0x10, 0x03, 0x6c, 0x3b, 0x6d,
13546 0xfe, 0x40, 0x56, 0xfe,
13547 0xe1, 0x56, 0x10, 0x6c, 0x22, 0x6d, 0x71, 0xdb, 0x64, 0xdc, 0x34, 0xfe,
13548 0x44, 0x55, 0xfe, 0xe5,
13549 0x55, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x00, 0x56, 0xfe, 0xa1, 0x56, 0x10,
13550 0x68, 0x22, 0x69, 0x01,
13551 0x0c, 0x06, 0x54, 0xf9, 0x21, 0x6e, 0xfe, 0x1f, 0x40, 0x03, 0x6a, 0x3b,
13552 0x6b, 0xfe, 0x2c, 0x50,
13553 0xfe, 0xae, 0x50, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x44, 0x50, 0xfe, 0xc6,
13554 0x50, 0x03, 0x68, 0x3b,
13555 0x69, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x4b, 0x3b, 0x4c, 0xfe,
13556 0x40, 0x50, 0xfe, 0xc2,
13557 0x50, 0x05, 0x73, 0x2e, 0x07, 0x20, 0x9e, 0x05, 0x72, 0x32, 0x01, 0x08,
13558 0x16, 0x3d, 0x27, 0x25,
13559 0xee, 0x09, 0x07, 0x2b, 0x3d, 0x01, 0x43, 0x09, 0xbb, 0x2b, 0x72, 0x01,
13560 0xa6, 0x23, 0x3f, 0x1b,
13561 0x3d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1e, 0x13, 0x91, 0x4b, 0x7e, 0x4c,
13562 0xfe, 0x0a, 0x55, 0x31,
13563 0xfe, 0x8b, 0x55, 0xd9, 0x4b, 0xda, 0x4c, 0xfe, 0x0c, 0x51, 0xfe, 0x8e,
13564 0x51, 0x05, 0x72, 0x01,
13565 0xfe, 0x8e, 0x1e, 0xca, 0xfe, 0x19, 0x41, 0x05, 0x72, 0x32, 0x01, 0x08,
13566 0x2a, 0x3c, 0x16, 0xc0,
13567 0x27, 0x25, 0xbe, 0x2d, 0x1d, 0xc0, 0x2d, 0x0d, 0x83, 0x2d, 0x7f, 0x1b,
13568 0xfe, 0x66, 0x15, 0x05,
13569 0x3d, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbd, 0x09, 0x1d,
13570 0x2b, 0x3d, 0x01, 0x08,
13571 0x16, 0xc0, 0x27, 0x25, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x50, 0x03,
13572 0xb6, 0x1e, 0x83, 0x01,
13573 0x38, 0x06, 0x24, 0x31, 0xa1, 0xfe, 0xbb, 0x45, 0x2d, 0x00, 0xa4, 0x46,
13574 0x07, 0x90, 0x3f, 0x01,
13575 0xfe, 0xf8, 0x15, 0x01, 0xa6, 0x86, 0xfe, 0x4b, 0x45, 0xfe, 0x20, 0x13,
13576 0x01, 0x43, 0x09, 0x82,
13577 0xfe, 0x16, 0x13, 0x03, 0x9a, 0x1e, 0x5d, 0x03, 0x55, 0x1e, 0x31, 0x5e,
13578 0x05, 0x72, 0xfe, 0xc0,
13579 0x5d, 0x01, 0xa7, 0xfe, 0x03, 0x17, 0x03, 0x66, 0x8a, 0x10, 0x66, 0x5e,
13580 0x32, 0x01, 0x08, 0x17,
13581 0x73, 0x01, 0xfe, 0x56, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16,
13582 0x3d, 0x27, 0x25, 0xbd,
13583 0x09, 0x07, 0x2b, 0x3d, 0x01, 0xfe, 0xbe, 0x16, 0xfe, 0x42, 0x58, 0xfe,
13584 0xe8, 0x14, 0x01, 0xa6,
13585 0x86, 0xfe, 0x4a, 0xf4, 0x0d, 0x1b, 0x3d, 0xfe, 0x4a, 0xf4, 0x07, 0xfe,
13586 0x0e, 0x12, 0x01, 0x43,
13587 0x09, 0x82, 0x4e, 0x05, 0x72, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x5e, 0x32,
13588 0x01, 0x08, 0x17, 0x73,
13589 0x01, 0xfe, 0x84, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d,
13590 0x27, 0x25, 0xbd, 0x09,
13591 0x12, 0x2b, 0x3d, 0x01, 0xfe, 0xe8, 0x17, 0x8b, 0xfe, 0xaa, 0x14, 0xfe,
13592 0xb6, 0x14, 0x86, 0xa8,
13593 0xb2, 0x0d, 0x1b, 0x3d, 0xb2, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09,
13594 0x82, 0x4e, 0x05, 0x72,
13595 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01,
13596 0xfe, 0xc0, 0x19, 0x05,
13597 0x73, 0x13, 0x07, 0x2f, 0xfe, 0xcc, 0x15, 0x17, 0xfe, 0xe2, 0x15, 0x5f,
13598 0xcc, 0x01, 0x08, 0x26,
13599 0x5f, 0x02, 0x8f, 0xfe, 0xde, 0x15, 0x2a, 0xfe, 0xde, 0x15, 0x16, 0xfe,
13600 0xcc, 0x15, 0x5e, 0x32,
13601 0x01, 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52,
13602 0xad, 0x23, 0xfe, 0xff,
13603 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff, 0x02,
13604 0x00, 0x57, 0x52, 0xad,
13605 0x23, 0x3f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff,
13606 0x02, 0x00, 0x57, 0x52,
13607 0xad, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xfe, 0x00, 0x5e,
13608 0x02, 0x13, 0x58, 0xff,
13609 0x02, 0x00, 0x57, 0x52, 0xad, 0xfe, 0x0b, 0x58, 0x02, 0x0a, 0x66, 0x01,
13610 0x5c, 0x0a, 0x55, 0x01,
13611 0x5c, 0x0a, 0x6f, 0x01, 0x5c, 0x02, 0x01, 0xfe, 0x1e, 0x1f, 0x23, 0x1a,
13612 0xff, 0x03, 0x00, 0x54,
13613 0xfe, 0x00, 0xf4, 0x24, 0x52, 0x0f, 0xfe, 0x00, 0x7c, 0x04, 0xfe, 0x07,
13614 0x7c, 0x3a, 0x0b, 0x0e,
13615 0xfe, 0x00, 0x71, 0xfe, 0xf9, 0x18, 0xfe, 0x7a, 0x19, 0xfe, 0xfb, 0x19,
13616 0xfe, 0x1a, 0xf7, 0x00,
13617 0xfe, 0x1b, 0xf7, 0x00, 0x7a, 0x30, 0x10, 0x68, 0x22, 0x69, 0xd9, 0x6c,
13618 0xda, 0x6d, 0x02, 0xfe,
13619 0x62, 0x08, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x77,
13620 0x02, 0x01, 0xc6, 0xfe,
13621 0x42, 0x48, 0x4f, 0x50, 0x45, 0x01, 0x08, 0x16, 0xfe, 0xe0, 0x17, 0x27,
13622 0x25, 0xbe, 0x01, 0x08,
13623 0x16, 0xfe, 0xe0, 0x17, 0x27, 0x25, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59,
13624 0x03, 0x9a, 0x1e, 0xfe,
13625 0xda, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfe, 0xd0, 0x13, 0x26, 0x53, 0x12,
13626 0x48, 0xfe, 0x08, 0x17,
13627 0xd1, 0x12, 0x53, 0x12, 0xfe, 0x1e, 0x13, 0x2d, 0xb4, 0x7b, 0xfe, 0x26,
13628 0x17, 0x4d, 0x13, 0x07,
13629 0x1c, 0xb4, 0x90, 0x04, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xf1,
13630 0xff, 0x02, 0x83, 0x55,
13631 0x53, 0x1d, 0xfe, 0x12, 0x13, 0xd6, 0xfe, 0x30, 0x00, 0xb0, 0xfe, 0x80,
13632 0x17, 0x1c, 0x63, 0x13,
13633 0x07, 0xfe, 0x56, 0x10, 0x53, 0x0d, 0xfe, 0x16, 0x13, 0xd6, 0xfe, 0x64,
13634 0x00, 0xb0, 0xfe, 0x80,
13635 0x17, 0x0a, 0xfe, 0x64, 0x00, 0x1c, 0x94, 0x13, 0x07, 0xfe, 0x28, 0x10,
13636 0x53, 0x07, 0xfe, 0x60,
13637 0x13, 0xd6, 0xfe, 0xc8, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0xc8,
13638 0x00, 0x1c, 0x95, 0x13,
13639 0x07, 0x71, 0xd6, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0x8c, 0x17, 0x45, 0xf3,
13640 0xfe, 0x43, 0xf4, 0x96,
13641 0xfe, 0x56, 0xf0, 0xfe, 0x9e, 0x17, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x43,
13642 0xf4, 0x94, 0xf6, 0x8b,
13643 0x01, 0xfe, 0x24, 0x16, 0x23, 0x3f, 0xfc, 0xa8, 0x8c, 0x49, 0x48, 0xfe,
13644 0xda, 0x17, 0x62, 0x49,
13645 0xfe, 0x1c, 0x10, 0xa8, 0x8c, 0x80, 0x48, 0xfe, 0xda, 0x17, 0x62, 0x80,
13646 0x71, 0x50, 0x26, 0xfe,
13647 0x4d, 0xf4, 0x00, 0xf7, 0x45, 0x13, 0x07, 0xfe, 0xb4, 0x56, 0xfe, 0xc3,
13648 0x58, 0x02, 0x50, 0x13,
13649 0x0d, 0x02, 0x50, 0x3e, 0x78, 0x4f, 0x45, 0x01, 0x08, 0x16, 0xa9, 0x27,
13650 0x25, 0xbe, 0xfe, 0x03,
13651 0xea, 0xfe, 0x7e, 0x01, 0x01, 0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe, 0xe9,
13652 0x0a, 0x01, 0x08, 0x16,
13653 0xa9, 0x27, 0x25, 0xfe, 0xe9, 0x0a, 0xfe, 0x05, 0xea, 0xfe, 0x7f, 0x01,
13654 0x01, 0x08, 0x16, 0xa9,
13655 0x27, 0x25, 0xfe, 0x69, 0x09, 0xfe, 0x02, 0xea, 0xfe, 0x80, 0x01, 0x01,
13656 0x08, 0x16, 0xa9, 0x27,
13657 0x25, 0xfe, 0xe8, 0x08, 0x47, 0xfe, 0x81, 0x01, 0x03, 0xb6, 0x1e, 0x83,
13658 0x01, 0x38, 0x06, 0x24,
13659 0x31, 0xa2, 0x78, 0xf2, 0x53, 0x07, 0x36, 0xfe, 0x34, 0xf4, 0x3f, 0xa1,
13660 0x78, 0x03, 0x9a, 0x1e,
13661 0x83, 0x01, 0x38, 0x06, 0x12, 0x31, 0xf0, 0x4f, 0x45, 0xfe, 0x90, 0x10,
13662 0xfe, 0x40, 0x5a, 0x23,
13663 0x3f, 0xfb, 0x8c, 0x49, 0x48, 0xfe, 0xaa, 0x18, 0x62, 0x49, 0x71, 0x8c,
13664 0x80, 0x48, 0xfe, 0xaa,
13665 0x18, 0x62, 0x80, 0xfe, 0xb4, 0x56, 0xfe, 0x40, 0x5d, 0x01, 0xc6, 0x01,
13666 0xfe, 0xac, 0x1d, 0xfe,
13667 0x02, 0x17, 0xfe, 0xc8, 0x45, 0xfe, 0x5a, 0xf0, 0xfe, 0xc0, 0x18, 0xfe,
13668 0x43, 0x48, 0x2d, 0x93,
13669 0x36, 0xfe, 0x34, 0xf4, 0xfe, 0x00, 0x11, 0xfe, 0x40, 0x10, 0x2d, 0xb4,
13670 0x36, 0xfe, 0x34, 0xf4,
13671 0x04, 0xfe, 0x34, 0x10, 0x2d, 0xfe, 0x0b, 0x00, 0x36, 0x46, 0x63, 0xfe,
13672 0x28, 0x10, 0xfe, 0xc0,
13673 0x49, 0xff, 0x02, 0x00, 0x54, 0xb2, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0xfa,
13674 0x18, 0x45, 0xfe, 0x1c,
13675 0xf4, 0x3f, 0xf3, 0xfe, 0x40, 0xf4, 0x96, 0xfe, 0x56, 0xf0, 0xfe, 0x0c,
13676 0x19, 0xfe, 0x04, 0xf4,
13677 0x58, 0xfe, 0x40, 0xf4, 0x94, 0xf6, 0x3e, 0x2d, 0x93, 0x4e, 0xd0, 0x0d,
13678 0x21, 0xfe, 0x7f, 0x01,
13679 0xfe, 0xc8, 0x46, 0xfe, 0x24, 0x13, 0x8c, 0x00, 0x5d, 0x26, 0x21, 0xfe,
13680 0x7e, 0x01, 0xfe, 0xc8,
13681 0x45, 0xfe, 0x14, 0x13, 0x21, 0xfe, 0x80, 0x01, 0xfe, 0x48, 0x45, 0xfa,
13682 0x21, 0xfe, 0x81, 0x01,
13683 0xfe, 0xc8, 0x44, 0x4e, 0x26, 0x02, 0x13, 0x07, 0x02, 0x78, 0x45, 0x50,
13684 0x13, 0x0d, 0x02, 0x14,
13685 0x07, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x14, 0x0d, 0x01, 0x08, 0x17,
13686 0xfe, 0x82, 0x19, 0x14,
13687 0x1d, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x5f, 0xfe, 0x89, 0x49, 0x01,
13688 0x08, 0x02, 0x14, 0x07,
13689 0x01, 0x08, 0x17, 0xc1, 0x14, 0x1d, 0x01, 0x08, 0x17, 0xc1, 0x14, 0x07,
13690 0x01, 0x08, 0x17, 0xc1,
13691 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0xc1, 0x5f, 0xfe, 0x89, 0x4a, 0x01,
13692 0x08, 0x02, 0x50, 0x02,
13693 0x14, 0x07, 0x01, 0x08, 0x17, 0x74, 0x14, 0x7f, 0x01, 0x08, 0x17, 0x74,
13694 0x14, 0x12, 0x01, 0x08,
13695 0x17, 0x74, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0x74, 0x14, 0x00, 0x01,
13696 0x08, 0x17, 0x74, 0xfe,
13697 0x89, 0x4a, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x09, 0x49, 0x01, 0x08, 0x17,
13698 0x74, 0x5f, 0xcc, 0x01,
13699 0x08, 0x02, 0x21, 0xe4, 0x09, 0x07, 0xfe, 0x4c, 0x13, 0xc8, 0x20, 0xe4,
13700 0xfe, 0x49, 0xf4, 0x00,
13701 0x4d, 0x5f, 0xa1, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xcc, 0xff,
13702 0x02, 0x00, 0x10, 0x2f,
13703 0xfe, 0x3e, 0x1a, 0x01, 0x43, 0x09, 0xfe, 0xe3, 0x00, 0xfe, 0x22, 0x13,
13704 0x16, 0xfe, 0x64, 0x1a,
13705 0x26, 0x20, 0x9e, 0x01, 0x41, 0x21, 0x9e, 0x09, 0x07, 0x5d, 0x01, 0x0c,
13706 0x61, 0x07, 0x44, 0x02,
13707 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x00, 0x40, 0xaa, 0x09, 0x1a, 0xfe, 0x12,
13708 0x13, 0x0a, 0x9d, 0x01,
13709 0x18, 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x9d, 0x01, 0x18, 0xaa,
13710 0xfe, 0x80, 0xe7, 0x1a,
13711 0x09, 0x1a, 0x5d, 0xfe, 0x45, 0x58, 0x01, 0xfe, 0xb2, 0x16, 0xaa, 0x02,
13712 0x0a, 0x5a, 0x01, 0x18,
13713 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x01, 0xfe,
13714 0x7e, 0x1e, 0xfe, 0x80,
13715 0x4c, 0xfe, 0x49, 0xe4, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01, 0x18,
13716 0xfe, 0x80, 0x4c, 0x0a,
13717 0x67, 0x01, 0x5c, 0x02, 0x1c, 0x1a, 0x87, 0x7c, 0xe5, 0xfe, 0x18, 0xdf,
13718 0xfe, 0x19, 0xde, 0xfe,
13719 0x24, 0x1c, 0xfe, 0x1d, 0xf7, 0x28, 0xb1, 0xfe, 0x04, 0x1b, 0x01, 0xfe,
13720 0x2a, 0x1c, 0xfa, 0xb3,
13721 0x28, 0x7c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x02, 0xc9, 0x2b, 0xfe,
13722 0xf4, 0x1a, 0xfe, 0xfa,
13723 0x10, 0x1c, 0x1a, 0x87, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x24,
13724 0xfe, 0x18, 0x58, 0x03,
13725 0xfe, 0x66, 0x01, 0xfe, 0x19, 0x58, 0xb3, 0x24, 0x01, 0xfe, 0x0e, 0x1f,
13726 0xfe, 0x30, 0xf4, 0x07,
13727 0xfe, 0x3c, 0x50, 0x7c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c,
13728 0xf7, 0x24, 0xb1, 0xfe,
13729 0x50, 0x1b, 0xfe, 0xd4, 0x14, 0x31, 0x02, 0xc9, 0x2b, 0xfe, 0x26, 0x1b,
13730 0xfe, 0xba, 0x10, 0x1c,
13731 0x1a, 0x87, 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe,
13732 0x1d, 0xf7, 0x54, 0xb1,
13733 0xfe, 0x72, 0x1b, 0xfe, 0xb2, 0x14, 0xfc, 0xb3, 0x54, 0x7c, 0x12, 0xfe,
13734 0xaf, 0x19, 0xfe, 0x98,
13735 0xe7, 0x00, 0x02, 0xc9, 0x2b, 0xfe, 0x66, 0x1b, 0xfe, 0x8a, 0x10, 0x1c,
13736 0x1a, 0x87, 0x8b, 0x0f,
13737 0xfe, 0x30, 0x90, 0x04, 0xfe, 0xb0, 0x93, 0x3a, 0x0b, 0xfe, 0x18, 0x58,
13738 0xfe, 0x32, 0x90, 0x04,
13739 0xfe, 0xb2, 0x93, 0x3a, 0x0b, 0xfe, 0x19, 0x58, 0x0e, 0xa8, 0xb3, 0x4a,
13740 0x7c, 0x12, 0xfe, 0x0f,
13741 0x79, 0xfe, 0x1c, 0xf7, 0x4a, 0xb1, 0xfe, 0xc6, 0x1b, 0xfe, 0x5e, 0x14,
13742 0x31, 0x02, 0xc9, 0x2b,
13743 0xfe, 0x96, 0x1b, 0x5c, 0xfe, 0x02, 0xf6, 0x1a, 0x87, 0xfe, 0x18, 0xfe,
13744 0x6a, 0xfe, 0x19, 0xfe,
13745 0x6b, 0x01, 0xfe, 0x1e, 0x1f, 0xfe, 0x1d, 0xf7, 0x65, 0xb1, 0xfe, 0xee,
13746 0x1b, 0xfe, 0x36, 0x14,
13747 0xfe, 0x1c, 0x13, 0xb3, 0x65, 0x3e, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19,
13748 0xfe, 0x80, 0xe7, 0x1a,
13749 0xfe, 0x81, 0xe7, 0x1a, 0x15, 0xfe, 0xdd, 0x00, 0x7a, 0x30, 0x02, 0x7a,
13750 0x30, 0xfe, 0x12, 0x45,
13751 0x2b, 0xfe, 0xdc, 0x1b, 0x1f, 0x07, 0x47, 0xb5, 0xc3, 0x05, 0x35, 0xfe,
13752 0x39, 0xf0, 0x75, 0x26,
13753 0x02, 0xfe, 0x7e, 0x18, 0x23, 0x1d, 0x36, 0x13, 0x11, 0x02, 0x87, 0x03,
13754 0xe3, 0x23, 0x07, 0xfe,
13755 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x90, 0x34, 0x60, 0xfe, 0x02, 0x80, 0x09,
13756 0x56, 0xfe, 0x3c, 0x13,
13757 0xfe, 0x82, 0x14, 0xfe, 0x42, 0x13, 0x51, 0xfe, 0x06, 0x83, 0x0a, 0x5a,
13758 0x01, 0x18, 0xcb, 0xfe,
13759 0x3e, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, 0xfe, 0xb2, 0x16,
13760 0xfe, 0x00, 0xcc, 0xcb,
13761 0xfe, 0xf3, 0x13, 0x3f, 0x89, 0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18,
13762 0xfe, 0x80, 0x4c, 0x01,
13763 0x85, 0xfe, 0x16, 0x10, 0x09, 0x9b, 0x4e, 0xfe, 0x40, 0x14, 0xfe, 0x24,
13764 0x12, 0xfe, 0x14, 0x56,
13765 0xfe, 0xd6, 0xf0, 0xfe, 0x52, 0x1c, 0x1c, 0x0d, 0x02, 0xfe, 0x9c, 0xe7,
13766 0x0d, 0x19, 0xfe, 0x15,
13767 0x00, 0x40, 0x8d, 0x30, 0x01, 0xf4, 0x1c, 0x07, 0x02, 0x51, 0xfe, 0x06,
13768 0x83, 0xfe, 0x18, 0x80,
13769 0x61, 0x28, 0x44, 0x15, 0x56, 0x01, 0x85, 0x1c, 0x07, 0x02, 0xfe, 0x38,
13770 0x90, 0xfe, 0xba, 0x90,
13771 0x91, 0xde, 0x7e, 0xdf, 0xfe, 0x48, 0x55, 0x31, 0xfe, 0xc9, 0x55, 0x02,
13772 0x21, 0xb9, 0x88, 0x20,
13773 0xb9, 0x02, 0x0a, 0xba, 0x01, 0x18, 0xfe, 0x41, 0x48, 0x0a, 0x57, 0x01,
13774 0x18, 0xfe, 0x49, 0x44,
13775 0x1b, 0xfe, 0x1e, 0x1d, 0x88, 0x89, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x09,
13776 0x1a, 0xa4, 0x0a, 0x67,
13777 0x01, 0xa3, 0x0a, 0x57, 0x01, 0x18, 0x88, 0x89, 0x02, 0xfe, 0x4e, 0xe4,
13778 0x1d, 0x7b, 0xfe, 0x52,
13779 0x1d, 0x03, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe,
13780 0x4e, 0xe4, 0xdd, 0x7b,
13781 0xfe, 0x64, 0x1d, 0x03, 0xfe, 0x92, 0x00, 0xd1, 0x12, 0xfe, 0x1a, 0x10,
13782 0xfe, 0x4e, 0xe4, 0xfe,
13783 0x0b, 0x00, 0x7b, 0xfe, 0x76, 0x1d, 0x03, 0xfe, 0x94, 0x00, 0xd1, 0x24,
13784 0xfe, 0x08, 0x10, 0x03,
13785 0xfe, 0x96, 0x00, 0xd1, 0x63, 0xfe, 0x4e, 0x45, 0x83, 0xca, 0xff, 0x04,
13786 0x68, 0x54, 0xfe, 0xf1,
13787 0x10, 0x23, 0x49, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c,
13788 0xfe, 0x1a, 0xf4, 0xfe,
13789 0x00, 0x04, 0x83, 0xb2, 0x1d, 0x48, 0xfe, 0xaa, 0x1d, 0x13, 0x1d, 0x02,
13790 0x09, 0x92, 0xfe, 0x5a,
13791 0xf0, 0xfe, 0xba, 0x1d, 0x2e, 0x93, 0xfe, 0x34, 0x10, 0x09, 0x12, 0xfe,
13792 0x5a, 0xf0, 0xfe, 0xc8,
13793 0x1d, 0x2e, 0xb4, 0xfe, 0x26, 0x10, 0x09, 0x1d, 0x36, 0x2e, 0x63, 0xfe,
13794 0x1a, 0x10, 0x09, 0x0d,
13795 0x36, 0x2e, 0x94, 0xf2, 0x09, 0x07, 0x36, 0x2e, 0x95, 0xa1, 0xc8, 0x02,
13796 0x1f, 0x93, 0x01, 0x42,
13797 0xfe, 0x04, 0xfe, 0x99, 0x03, 0x9c, 0x8b, 0x02, 0x2a, 0xfe, 0x1c, 0x1e,
13798 0xfe, 0x14, 0xf0, 0x08,
13799 0x2f, 0xfe, 0x0c, 0x1e, 0x2a, 0xfe, 0x1c, 0x1e, 0x8f, 0xfe, 0x1c, 0x1e,
13800 0xfe, 0x82, 0xf0, 0xfe,
13801 0x10, 0x1e, 0x02, 0x0f, 0x3f, 0x04, 0xfe, 0x80, 0x83, 0x33, 0x0b, 0x0e,
13802 0x02, 0x0f, 0xfe, 0x18,
13803 0x80, 0x04, 0xfe, 0x98, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x02,
13804 0x80, 0x04, 0xfe, 0x82,
13805 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x80, 0x04, 0xfe, 0x86,
13806 0x83, 0x33, 0x0b, 0x0e,
13807 0x02, 0x0f, 0xfe, 0x1b, 0x80, 0x04, 0xfe, 0x9b, 0x83, 0x33, 0x0b, 0x0e,
13808 0x02, 0x0f, 0xfe, 0x04,
13809 0x80, 0x04, 0xfe, 0x84, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x80,
13810 0x80, 0x04, 0xfe, 0x80,
13811 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x19, 0x81, 0x04,
13812 0xfe, 0x99, 0x83, 0xfe,
13813 0xca, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x83, 0x04, 0xfe, 0x86,
13814 0x83, 0xfe, 0xce, 0x47,
13815 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x2c, 0x90, 0x04, 0xfe, 0xac, 0x93, 0x3a,
13816 0x0b, 0x0e, 0x02, 0x0f,
13817 0xfe, 0xae, 0x90, 0x04, 0xfe, 0xae, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
13818 0xfe, 0x08, 0x90, 0x04,
13819 0xfe, 0x88, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x8a, 0x90, 0x04,
13820 0xfe, 0x8a, 0x93, 0x79,
13821 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x0c, 0x90, 0x04, 0xfe, 0x8c, 0x93, 0x3a,
13822 0x0b, 0x0e, 0x02, 0x0f,
13823 0xfe, 0x8e, 0x90, 0x04, 0xfe, 0x8e, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
13824 0xfe, 0x3c, 0x90, 0x04,
13825 0xfe, 0xbc, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x8b, 0x0f, 0xfe, 0x03, 0x80,
13826 0x04, 0xfe, 0x83, 0x83,
13827 0x33, 0x0b, 0x77, 0x0e, 0xa8, 0x02, 0xff, 0x66, 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070013828};
13829
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013830static unsigned short _adv_asc38C1600_size = sizeof(_adv_asc38C1600_buf); /* 0x1673 */
13831static ADV_DCNT _adv_asc38C1600_chksum = 0x0604EF77UL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013832
13833/* a_init.c */
13834/*
13835 * EEPROM Configuration.
13836 *
13837 * All drivers should use this structure to set the default EEPROM
13838 * configuration. The BIOS now uses this structure when it is built.
13839 * Additional structure information can be found in a_condor.h where
13840 * the structure is defined.
13841 *
13842 * The *_Field_IsChar structs are needed to correct for endianness.
13843 * These values are read from the board 16 bits at a time directly
13844 * into the structs. Because some fields are char, the values will be
13845 * in the wrong order. The *_Field_IsChar tells when to flip the
13846 * bytes. Data read and written to PCI memory is automatically swapped
13847 * on big-endian platforms so char fields read as words are actually being
13848 * unswapped on big-endian platforms.
13849 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013850static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config __initdata = {
13851 ADV_EEPROM_BIOS_ENABLE, /* cfg_lsw */
13852 0x0000, /* cfg_msw */
13853 0xFFFF, /* disc_enable */
13854 0xFFFF, /* wdtr_able */
13855 0xFFFF, /* sdtr_able */
13856 0xFFFF, /* start_motor */
13857 0xFFFF, /* tagqng_able */
13858 0xFFFF, /* bios_scan */
13859 0, /* scam_tolerant */
13860 7, /* adapter_scsi_id */
13861 0, /* bios_boot_delay */
13862 3, /* scsi_reset_delay */
13863 0, /* bios_id_lun */
13864 0, /* termination */
13865 0, /* reserved1 */
13866 0xFFE7, /* bios_ctrl */
13867 0xFFFF, /* ultra_able */
13868 0, /* reserved2 */
13869 ASC_DEF_MAX_HOST_QNG, /* max_host_qng */
13870 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
13871 0, /* dvc_cntl */
13872 0, /* bug_fix */
13873 0, /* serial_number_word1 */
13874 0, /* serial_number_word2 */
13875 0, /* serial_number_word3 */
13876 0, /* check_sum */
13877 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
13878 , /* oem_name[16] */
13879 0, /* dvc_err_code */
13880 0, /* adv_err_code */
13881 0, /* adv_err_addr */
13882 0, /* saved_dvc_err_code */
13883 0, /* saved_adv_err_code */
13884 0, /* saved_adv_err_addr */
13885 0 /* num_of_err */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013886};
13887
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013888static ADVEEP_3550_CONFIG ADVEEP_3550_Config_Field_IsChar __initdata = {
13889 0, /* cfg_lsw */
13890 0, /* cfg_msw */
13891 0, /* -disc_enable */
13892 0, /* wdtr_able */
13893 0, /* sdtr_able */
13894 0, /* start_motor */
13895 0, /* tagqng_able */
13896 0, /* bios_scan */
13897 0, /* scam_tolerant */
13898 1, /* adapter_scsi_id */
13899 1, /* bios_boot_delay */
13900 1, /* scsi_reset_delay */
13901 1, /* bios_id_lun */
13902 1, /* termination */
13903 1, /* reserved1 */
13904 0, /* bios_ctrl */
13905 0, /* ultra_able */
13906 0, /* reserved2 */
13907 1, /* max_host_qng */
13908 1, /* max_dvc_qng */
13909 0, /* dvc_cntl */
13910 0, /* bug_fix */
13911 0, /* serial_number_word1 */
13912 0, /* serial_number_word2 */
13913 0, /* serial_number_word3 */
13914 0, /* check_sum */
13915 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
13916 , /* oem_name[16] */
13917 0, /* dvc_err_code */
13918 0, /* adv_err_code */
13919 0, /* adv_err_addr */
13920 0, /* saved_dvc_err_code */
13921 0, /* saved_adv_err_code */
13922 0, /* saved_adv_err_addr */
13923 0 /* num_of_err */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013924};
13925
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013926static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config __initdata = {
13927 ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
13928 0x0000, /* 01 cfg_msw */
13929 0xFFFF, /* 02 disc_enable */
13930 0xFFFF, /* 03 wdtr_able */
13931 0x4444, /* 04 sdtr_speed1 */
13932 0xFFFF, /* 05 start_motor */
13933 0xFFFF, /* 06 tagqng_able */
13934 0xFFFF, /* 07 bios_scan */
13935 0, /* 08 scam_tolerant */
13936 7, /* 09 adapter_scsi_id */
13937 0, /* bios_boot_delay */
13938 3, /* 10 scsi_reset_delay */
13939 0, /* bios_id_lun */
13940 0, /* 11 termination_se */
13941 0, /* termination_lvd */
13942 0xFFE7, /* 12 bios_ctrl */
13943 0x4444, /* 13 sdtr_speed2 */
13944 0x4444, /* 14 sdtr_speed3 */
13945 ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
13946 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
13947 0, /* 16 dvc_cntl */
13948 0x4444, /* 17 sdtr_speed4 */
13949 0, /* 18 serial_number_word1 */
13950 0, /* 19 serial_number_word2 */
13951 0, /* 20 serial_number_word3 */
13952 0, /* 21 check_sum */
13953 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
13954 , /* 22-29 oem_name[16] */
13955 0, /* 30 dvc_err_code */
13956 0, /* 31 adv_err_code */
13957 0, /* 32 adv_err_addr */
13958 0, /* 33 saved_dvc_err_code */
13959 0, /* 34 saved_adv_err_code */
13960 0, /* 35 saved_adv_err_addr */
13961 0, /* 36 reserved */
13962 0, /* 37 reserved */
13963 0, /* 38 reserved */
13964 0, /* 39 reserved */
13965 0, /* 40 reserved */
13966 0, /* 41 reserved */
13967 0, /* 42 reserved */
13968 0, /* 43 reserved */
13969 0, /* 44 reserved */
13970 0, /* 45 reserved */
13971 0, /* 46 reserved */
13972 0, /* 47 reserved */
13973 0, /* 48 reserved */
13974 0, /* 49 reserved */
13975 0, /* 50 reserved */
13976 0, /* 51 reserved */
13977 0, /* 52 reserved */
13978 0, /* 53 reserved */
13979 0, /* 54 reserved */
13980 0, /* 55 reserved */
13981 0, /* 56 cisptr_lsw */
13982 0, /* 57 cisprt_msw */
13983 PCI_VENDOR_ID_ASP, /* 58 subsysvid */
13984 PCI_DEVICE_ID_38C0800_REV1, /* 59 subsysid */
13985 0, /* 60 reserved */
13986 0, /* 61 reserved */
13987 0, /* 62 reserved */
13988 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013989};
13990
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013991static ADVEEP_38C0800_CONFIG ADVEEP_38C0800_Config_Field_IsChar __initdata = {
13992 0, /* 00 cfg_lsw */
13993 0, /* 01 cfg_msw */
13994 0, /* 02 disc_enable */
13995 0, /* 03 wdtr_able */
13996 0, /* 04 sdtr_speed1 */
13997 0, /* 05 start_motor */
13998 0, /* 06 tagqng_able */
13999 0, /* 07 bios_scan */
14000 0, /* 08 scam_tolerant */
14001 1, /* 09 adapter_scsi_id */
14002 1, /* bios_boot_delay */
14003 1, /* 10 scsi_reset_delay */
14004 1, /* bios_id_lun */
14005 1, /* 11 termination_se */
14006 1, /* termination_lvd */
14007 0, /* 12 bios_ctrl */
14008 0, /* 13 sdtr_speed2 */
14009 0, /* 14 sdtr_speed3 */
14010 1, /* 15 max_host_qng */
14011 1, /* max_dvc_qng */
14012 0, /* 16 dvc_cntl */
14013 0, /* 17 sdtr_speed4 */
14014 0, /* 18 serial_number_word1 */
14015 0, /* 19 serial_number_word2 */
14016 0, /* 20 serial_number_word3 */
14017 0, /* 21 check_sum */
14018 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
14019 , /* 22-29 oem_name[16] */
14020 0, /* 30 dvc_err_code */
14021 0, /* 31 adv_err_code */
14022 0, /* 32 adv_err_addr */
14023 0, /* 33 saved_dvc_err_code */
14024 0, /* 34 saved_adv_err_code */
14025 0, /* 35 saved_adv_err_addr */
14026 0, /* 36 reserved */
14027 0, /* 37 reserved */
14028 0, /* 38 reserved */
14029 0, /* 39 reserved */
14030 0, /* 40 reserved */
14031 0, /* 41 reserved */
14032 0, /* 42 reserved */
14033 0, /* 43 reserved */
14034 0, /* 44 reserved */
14035 0, /* 45 reserved */
14036 0, /* 46 reserved */
14037 0, /* 47 reserved */
14038 0, /* 48 reserved */
14039 0, /* 49 reserved */
14040 0, /* 50 reserved */
14041 0, /* 51 reserved */
14042 0, /* 52 reserved */
14043 0, /* 53 reserved */
14044 0, /* 54 reserved */
14045 0, /* 55 reserved */
14046 0, /* 56 cisptr_lsw */
14047 0, /* 57 cisprt_msw */
14048 0, /* 58 subsysvid */
14049 0, /* 59 subsysid */
14050 0, /* 60 reserved */
14051 0, /* 61 reserved */
14052 0, /* 62 reserved */
14053 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014054};
14055
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014056static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config __initdata = {
14057 ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
14058 0x0000, /* 01 cfg_msw */
14059 0xFFFF, /* 02 disc_enable */
14060 0xFFFF, /* 03 wdtr_able */
14061 0x5555, /* 04 sdtr_speed1 */
14062 0xFFFF, /* 05 start_motor */
14063 0xFFFF, /* 06 tagqng_able */
14064 0xFFFF, /* 07 bios_scan */
14065 0, /* 08 scam_tolerant */
14066 7, /* 09 adapter_scsi_id */
14067 0, /* bios_boot_delay */
14068 3, /* 10 scsi_reset_delay */
14069 0, /* bios_id_lun */
14070 0, /* 11 termination_se */
14071 0, /* termination_lvd */
14072 0xFFE7, /* 12 bios_ctrl */
14073 0x5555, /* 13 sdtr_speed2 */
14074 0x5555, /* 14 sdtr_speed3 */
14075 ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
14076 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
14077 0, /* 16 dvc_cntl */
14078 0x5555, /* 17 sdtr_speed4 */
14079 0, /* 18 serial_number_word1 */
14080 0, /* 19 serial_number_word2 */
14081 0, /* 20 serial_number_word3 */
14082 0, /* 21 check_sum */
14083 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
14084 , /* 22-29 oem_name[16] */
14085 0, /* 30 dvc_err_code */
14086 0, /* 31 adv_err_code */
14087 0, /* 32 adv_err_addr */
14088 0, /* 33 saved_dvc_err_code */
14089 0, /* 34 saved_adv_err_code */
14090 0, /* 35 saved_adv_err_addr */
14091 0, /* 36 reserved */
14092 0, /* 37 reserved */
14093 0, /* 38 reserved */
14094 0, /* 39 reserved */
14095 0, /* 40 reserved */
14096 0, /* 41 reserved */
14097 0, /* 42 reserved */
14098 0, /* 43 reserved */
14099 0, /* 44 reserved */
14100 0, /* 45 reserved */
14101 0, /* 46 reserved */
14102 0, /* 47 reserved */
14103 0, /* 48 reserved */
14104 0, /* 49 reserved */
14105 0, /* 50 reserved */
14106 0, /* 51 reserved */
14107 0, /* 52 reserved */
14108 0, /* 53 reserved */
14109 0, /* 54 reserved */
14110 0, /* 55 reserved */
14111 0, /* 56 cisptr_lsw */
14112 0, /* 57 cisprt_msw */
14113 PCI_VENDOR_ID_ASP, /* 58 subsysvid */
14114 PCI_DEVICE_ID_38C1600_REV1, /* 59 subsysid */
14115 0, /* 60 reserved */
14116 0, /* 61 reserved */
14117 0, /* 62 reserved */
14118 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014119};
14120
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014121static ADVEEP_38C1600_CONFIG ADVEEP_38C1600_Config_Field_IsChar __initdata = {
14122 0, /* 00 cfg_lsw */
14123 0, /* 01 cfg_msw */
14124 0, /* 02 disc_enable */
14125 0, /* 03 wdtr_able */
14126 0, /* 04 sdtr_speed1 */
14127 0, /* 05 start_motor */
14128 0, /* 06 tagqng_able */
14129 0, /* 07 bios_scan */
14130 0, /* 08 scam_tolerant */
14131 1, /* 09 adapter_scsi_id */
14132 1, /* bios_boot_delay */
14133 1, /* 10 scsi_reset_delay */
14134 1, /* bios_id_lun */
14135 1, /* 11 termination_se */
14136 1, /* termination_lvd */
14137 0, /* 12 bios_ctrl */
14138 0, /* 13 sdtr_speed2 */
14139 0, /* 14 sdtr_speed3 */
14140 1, /* 15 max_host_qng */
14141 1, /* max_dvc_qng */
14142 0, /* 16 dvc_cntl */
14143 0, /* 17 sdtr_speed4 */
14144 0, /* 18 serial_number_word1 */
14145 0, /* 19 serial_number_word2 */
14146 0, /* 20 serial_number_word3 */
14147 0, /* 21 check_sum */
14148 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
14149 , /* 22-29 oem_name[16] */
14150 0, /* 30 dvc_err_code */
14151 0, /* 31 adv_err_code */
14152 0, /* 32 adv_err_addr */
14153 0, /* 33 saved_dvc_err_code */
14154 0, /* 34 saved_adv_err_code */
14155 0, /* 35 saved_adv_err_addr */
14156 0, /* 36 reserved */
14157 0, /* 37 reserved */
14158 0, /* 38 reserved */
14159 0, /* 39 reserved */
14160 0, /* 40 reserved */
14161 0, /* 41 reserved */
14162 0, /* 42 reserved */
14163 0, /* 43 reserved */
14164 0, /* 44 reserved */
14165 0, /* 45 reserved */
14166 0, /* 46 reserved */
14167 0, /* 47 reserved */
14168 0, /* 48 reserved */
14169 0, /* 49 reserved */
14170 0, /* 50 reserved */
14171 0, /* 51 reserved */
14172 0, /* 52 reserved */
14173 0, /* 53 reserved */
14174 0, /* 54 reserved */
14175 0, /* 55 reserved */
14176 0, /* 56 cisptr_lsw */
14177 0, /* 57 cisprt_msw */
14178 0, /* 58 subsysvid */
14179 0, /* 59 subsysid */
14180 0, /* 60 reserved */
14181 0, /* 61 reserved */
14182 0, /* 62 reserved */
14183 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014184};
14185
14186/*
14187 * Initialize the ADV_DVC_VAR structure.
14188 *
14189 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
14190 *
14191 * For a non-fatal error return a warning code. If there are no warnings
14192 * then 0 is returned.
14193 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014194static int __init AdvInitGetConfig(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014195{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014196 ushort warn_code;
14197 AdvPortAddr iop_base;
14198 uchar pci_cmd_reg;
14199 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014200
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014201 warn_code = 0;
14202 asc_dvc->err_code = 0;
14203 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014204
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014205 /*
14206 * PCI Command Register
14207 *
14208 * Note: AscPCICmdRegBits_BusMastering definition (0x0007) includes
14209 * I/O Space Control, Memory Space Control and Bus Master Control bits.
14210 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014211
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014212 if (((pci_cmd_reg = DvcAdvReadPCIConfigByte(asc_dvc,
14213 AscPCIConfigCommandRegister))
14214 & AscPCICmdRegBits_BusMastering)
14215 != AscPCICmdRegBits_BusMastering) {
14216 pci_cmd_reg |= AscPCICmdRegBits_BusMastering;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014217
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014218 DvcAdvWritePCIConfigByte(asc_dvc,
14219 AscPCIConfigCommandRegister,
14220 pci_cmd_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014221
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014222 if (((DvcAdvReadPCIConfigByte
14223 (asc_dvc, AscPCIConfigCommandRegister))
14224 & AscPCICmdRegBits_BusMastering)
14225 != AscPCICmdRegBits_BusMastering) {
14226 warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
14227 }
14228 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014229
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014230 /*
14231 * PCI Latency Timer
14232 *
14233 * If the "latency timer" register is 0x20 or above, then we don't need
14234 * to change it. Otherwise, set it to 0x20 (i.e. set it to 0x20 if it
14235 * comes up less than 0x20).
14236 */
14237 if (DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer) < 0x20) {
14238 DvcAdvWritePCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer,
14239 0x20);
14240 if (DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer) <
14241 0x20) {
14242 warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
14243 }
14244 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014245
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014246 /*
14247 * Save the state of the PCI Configuration Command Register
14248 * "Parity Error Response Control" Bit. If the bit is clear (0),
14249 * in AdvInitAsc3550/38C0800Driver() tell the microcode to ignore
14250 * DMA parity errors.
14251 */
14252 asc_dvc->cfg->control_flag = 0;
14253 if (((DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigCommandRegister)
14254 & AscPCICmdRegBits_ParErrRespCtrl)) == 0) {
14255 asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR;
14256 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014257
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014258 asc_dvc->cfg->lib_version = (ADV_LIB_VERSION_MAJOR << 8) |
14259 ADV_LIB_VERSION_MINOR;
14260 asc_dvc->cfg->chip_version =
14261 AdvGetChipVersion(iop_base, asc_dvc->bus_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014262
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014263 ASC_DBG2(1, "AdvInitGetConfig: iopb_chip_id_1: 0x%x 0x%x\n",
14264 (ushort)AdvReadByteRegister(iop_base, IOPB_CHIP_ID_1),
14265 (ushort)ADV_CHIP_ID_BYTE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014266
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014267 ASC_DBG2(1, "AdvInitGetConfig: iopw_chip_id_0: 0x%x 0x%x\n",
14268 (ushort)AdvReadWordRegister(iop_base, IOPW_CHIP_ID_0),
14269 (ushort)ADV_CHIP_ID_WORD);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014270
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014271 /*
14272 * Reset the chip to start and allow register writes.
14273 */
14274 if (AdvFindSignature(iop_base) == 0) {
14275 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
14276 return ADV_ERROR;
14277 } else {
14278 /*
14279 * The caller must set 'chip_type' to a valid setting.
14280 */
14281 if (asc_dvc->chip_type != ADV_CHIP_ASC3550 &&
14282 asc_dvc->chip_type != ADV_CHIP_ASC38C0800 &&
14283 asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
14284 asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
14285 return ADV_ERROR;
14286 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014287
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014288 /*
14289 * Reset Chip.
14290 */
14291 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
14292 ADV_CTRL_REG_CMD_RESET);
14293 DvcSleepMilliSecond(100);
14294 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
14295 ADV_CTRL_REG_CMD_WR_IO_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014296
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014297 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
14298 if ((status =
14299 AdvInitFrom38C1600EEP(asc_dvc)) == ADV_ERROR) {
14300 return ADV_ERROR;
14301 }
14302 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
14303 if ((status =
14304 AdvInitFrom38C0800EEP(asc_dvc)) == ADV_ERROR) {
14305 return ADV_ERROR;
14306 }
14307 } else {
14308 if ((status = AdvInitFrom3550EEP(asc_dvc)) == ADV_ERROR) {
14309 return ADV_ERROR;
14310 }
14311 }
14312 warn_code |= status;
14313 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014314
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014315 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014316}
14317
14318/*
14319 * Initialize the ASC-3550.
14320 *
14321 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
14322 *
14323 * For a non-fatal error return a warning code. If there are no warnings
14324 * then 0 is returned.
14325 *
14326 * Needed after initialization for error recovery.
14327 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014328static int AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014329{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014330 AdvPortAddr iop_base;
14331 ushort warn_code;
14332 ADV_DCNT sum;
14333 int begin_addr;
14334 int end_addr;
14335 ushort code_sum;
14336 int word;
14337 int j;
14338 int adv_asc3550_expanded_size;
14339 ADV_CARR_T *carrp;
14340 ADV_DCNT contig_len;
14341 ADV_SDCNT buf_size;
14342 ADV_PADDR carr_paddr;
14343 int i;
14344 ushort scsi_cfg1;
14345 uchar tid;
14346 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
14347 ushort wdtr_able = 0, sdtr_able, tagqng_able;
14348 uchar max_cmd[ADV_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070014349
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014350 /* If there is already an error, don't continue. */
14351 if (asc_dvc->err_code != 0) {
14352 return ADV_ERROR;
14353 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014354
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014355 /*
14356 * The caller must set 'chip_type' to ADV_CHIP_ASC3550.
14357 */
14358 if (asc_dvc->chip_type != ADV_CHIP_ASC3550) {
14359 asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
14360 return ADV_ERROR;
14361 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014362
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014363 warn_code = 0;
14364 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014365
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014366 /*
14367 * Save the RISC memory BIOS region before writing the microcode.
14368 * The BIOS may already be loaded and using its RISC LRAM region
14369 * so its region must be saved and restored.
14370 *
14371 * Note: This code makes the assumption, which is currently true,
14372 * that a chip reset does not clear RISC LRAM.
14373 */
14374 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
14375 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
14376 bios_mem[i]);
14377 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014378
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014379 /*
14380 * Save current per TID negotiated values.
14381 */
14382 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] == 0x55AA) {
14383 ushort bios_version, major, minor;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014384
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014385 bios_version =
14386 bios_mem[(ASC_MC_BIOS_VERSION - ASC_MC_BIOSMEM) / 2];
14387 major = (bios_version >> 12) & 0xF;
14388 minor = (bios_version >> 8) & 0xF;
14389 if (major < 3 || (major == 3 && minor == 1)) {
14390 /* BIOS 3.1 and earlier location of 'wdtr_able' variable. */
14391 AdvReadWordLram(iop_base, 0x120, wdtr_able);
14392 } else {
14393 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14394 }
14395 }
14396 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14397 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
14398 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14399 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
14400 max_cmd[tid]);
14401 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014402
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014403 /*
14404 * Load the Microcode
14405 *
14406 * Write the microcode image to RISC memory starting at address 0.
14407 */
14408 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
14409 /* Assume the following compressed format of the microcode buffer:
14410 *
14411 * 254 word (508 byte) table indexed by byte code followed
14412 * by the following byte codes:
14413 *
14414 * 1-Byte Code:
14415 * 00: Emit word 0 in table.
14416 * 01: Emit word 1 in table.
14417 * .
14418 * FD: Emit word 253 in table.
14419 *
14420 * Multi-Byte Code:
14421 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
14422 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
14423 */
14424 word = 0;
14425 for (i = 253 * 2; i < _adv_asc3550_size; i++) {
14426 if (_adv_asc3550_buf[i] == 0xff) {
14427 for (j = 0; j < _adv_asc3550_buf[i + 1]; j++) {
14428 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14429 _adv_asc3550_buf
14430 [i +
14431 3] << 8) |
14432 _adv_asc3550_buf
14433 [i + 2]));
14434 word++;
14435 }
14436 i += 3;
14437 } else if (_adv_asc3550_buf[i] == 0xfe) {
14438 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14439 _adv_asc3550_buf[i +
14440 2]
14441 << 8) |
14442 _adv_asc3550_buf[i +
14443 1]));
14444 i += 2;
14445 word++;
14446 } else {
14447 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14448 _adv_asc3550_buf[(_adv_asc3550_buf[i] * 2) + 1] << 8) | _adv_asc3550_buf[_adv_asc3550_buf[i] * 2]));
14449 word++;
14450 }
14451 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014452
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014453 /*
14454 * Set 'word' for later use to clear the rest of memory and save
14455 * the expanded mcode size.
14456 */
14457 word *= 2;
14458 adv_asc3550_expanded_size = word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014459
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014460 /*
14461 * Clear the rest of ASC-3550 Internal RAM (8KB).
14462 */
14463 for (; word < ADV_3550_MEMSIZE; word += 2) {
14464 AdvWriteWordAutoIncLram(iop_base, 0);
14465 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014466
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014467 /*
14468 * Verify the microcode checksum.
14469 */
14470 sum = 0;
14471 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014472
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014473 for (word = 0; word < adv_asc3550_expanded_size; word += 2) {
14474 sum += AdvReadWordAutoIncLram(iop_base);
14475 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014476
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014477 if (sum != _adv_asc3550_chksum) {
14478 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
14479 return ADV_ERROR;
14480 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014481
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014482 /*
14483 * Restore the RISC memory BIOS region.
14484 */
14485 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
14486 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
14487 bios_mem[i]);
14488 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014489
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014490 /*
14491 * Calculate and write the microcode code checksum to the microcode
14492 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
14493 */
14494 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
14495 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
14496 code_sum = 0;
14497 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
14498 for (word = begin_addr; word < end_addr; word += 2) {
14499 code_sum += AdvReadWordAutoIncLram(iop_base);
14500 }
14501 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014502
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014503 /*
14504 * Read and save microcode version and date.
14505 */
14506 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
14507 asc_dvc->cfg->mcode_date);
14508 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
14509 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014510
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014511 /*
14512 * Set the chip type to indicate the ASC3550.
14513 */
14514 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014515
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014516 /*
14517 * If the PCI Configuration Command Register "Parity Error Response
14518 * Control" Bit was clear (0), then set the microcode variable
14519 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
14520 * to ignore DMA parity errors.
14521 */
14522 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
14523 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
14524 word |= CONTROL_FLAG_IGNORE_PERR;
14525 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
14526 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014527
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014528 /*
14529 * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO
14530 * threshold of 128 bytes. This register is only accessible to the host.
14531 */
14532 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
14533 START_CTL_EMFU | READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014534
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014535 /*
14536 * Microcode operating variables for WDTR, SDTR, and command tag
14537 * queuing will be set in AdvInquiryHandling() based on what a
14538 * device reports it is capable of in Inquiry byte 7.
14539 *
14540 * If SCSI Bus Resets have been disabled, then directly set
14541 * SDTR and WDTR from the EEPROM configuration. This will allow
14542 * the BIOS and warm boot to work without a SCSI bus hang on
14543 * the Inquiry caused by host and target mismatched DTR values.
14544 * Without the SCSI Bus Reset, before an Inquiry a device can't
14545 * be assumed to be in Asynchronous, Narrow mode.
14546 */
14547 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
14548 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
14549 asc_dvc->wdtr_able);
14550 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
14551 asc_dvc->sdtr_able);
14552 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014553
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014554 /*
14555 * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2,
14556 * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID
14557 * bitmask. These values determine the maximum SDTR speed negotiated
14558 * with a device.
14559 *
14560 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
14561 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
14562 * without determining here whether the device supports SDTR.
14563 *
14564 * 4-bit speed SDTR speed name
14565 * =========== ===============
14566 * 0000b (0x0) SDTR disabled
14567 * 0001b (0x1) 5 Mhz
14568 * 0010b (0x2) 10 Mhz
14569 * 0011b (0x3) 20 Mhz (Ultra)
14570 * 0100b (0x4) 40 Mhz (LVD/Ultra2)
14571 * 0101b (0x5) 80 Mhz (LVD2/Ultra3)
14572 * 0110b (0x6) Undefined
14573 * .
14574 * 1111b (0xF) Undefined
14575 */
14576 word = 0;
14577 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14578 if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able) {
14579 /* Set Ultra speed for TID 'tid'. */
14580 word |= (0x3 << (4 * (tid % 4)));
14581 } else {
14582 /* Set Fast speed for TID 'tid'. */
14583 word |= (0x2 << (4 * (tid % 4)));
14584 }
14585 if (tid == 3) { /* Check if done with sdtr_speed1. */
14586 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word);
14587 word = 0;
14588 } else if (tid == 7) { /* Check if done with sdtr_speed2. */
14589 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word);
14590 word = 0;
14591 } else if (tid == 11) { /* Check if done with sdtr_speed3. */
14592 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word);
14593 word = 0;
14594 } else if (tid == 15) { /* Check if done with sdtr_speed4. */
14595 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word);
14596 /* End of loop. */
14597 }
14598 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014599
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014600 /*
14601 * Set microcode operating variable for the disconnect per TID bitmask.
14602 */
14603 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
14604 asc_dvc->cfg->disc_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014605
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014606 /*
14607 * Set SCSI_CFG0 Microcode Default Value.
14608 *
14609 * The microcode will set the SCSI_CFG0 register using this value
14610 * after it is started below.
14611 */
14612 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
14613 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
14614 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014615
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014616 /*
14617 * Determine SCSI_CFG1 Microcode Default Value.
14618 *
14619 * The microcode will set the SCSI_CFG1 register using this value
14620 * after it is started below.
14621 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014622
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014623 /* Read current SCSI_CFG1 Register value. */
14624 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014625
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014626 /*
14627 * If all three connectors are in use, return an error.
14628 */
14629 if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 ||
14630 (scsi_cfg1 & CABLE_ILLEGAL_B) == 0) {
14631 asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION;
14632 return ADV_ERROR;
14633 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014634
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014635 /*
14636 * If the internal narrow cable is reversed all of the SCSI_CTRL
14637 * register signals will be set. Check for and return an error if
14638 * this condition is found.
14639 */
14640 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
14641 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
14642 return ADV_ERROR;
14643 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014644
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014645 /*
14646 * If this is a differential board and a single-ended device
14647 * is attached to one of the connectors, return an error.
14648 */
14649 if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0) {
14650 asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE;
14651 return ADV_ERROR;
14652 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014653
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014654 /*
14655 * If automatic termination control is enabled, then set the
14656 * termination value based on a table listed in a_condor.h.
14657 *
14658 * If manual termination was specified with an EEPROM setting
14659 * then 'termination' was set-up in AdvInitFrom3550EEPROM() and
14660 * is ready to be 'ored' into SCSI_CFG1.
14661 */
14662 if (asc_dvc->cfg->termination == 0) {
14663 /*
14664 * The software always controls termination by setting TERM_CTL_SEL.
14665 * If TERM_CTL_SEL were set to 0, the hardware would set termination.
14666 */
14667 asc_dvc->cfg->termination |= TERM_CTL_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014668
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014669 switch (scsi_cfg1 & CABLE_DETECT) {
14670 /* TERM_CTL_H: on, TERM_CTL_L: on */
14671 case 0x3:
14672 case 0x7:
14673 case 0xB:
14674 case 0xD:
14675 case 0xE:
14676 case 0xF:
14677 asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L);
14678 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014679
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014680 /* TERM_CTL_H: on, TERM_CTL_L: off */
14681 case 0x1:
14682 case 0x5:
14683 case 0x9:
14684 case 0xA:
14685 case 0xC:
14686 asc_dvc->cfg->termination |= TERM_CTL_H;
14687 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014688
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014689 /* TERM_CTL_H: off, TERM_CTL_L: off */
14690 case 0x2:
14691 case 0x6:
14692 break;
14693 }
14694 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014695
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014696 /*
14697 * Clear any set TERM_CTL_H and TERM_CTL_L bits.
14698 */
14699 scsi_cfg1 &= ~TERM_CTL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014700
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014701 /*
14702 * Invert the TERM_CTL_H and TERM_CTL_L bits and then
14703 * set 'scsi_cfg1'. The TERM_POL bit does not need to be
14704 * referenced, because the hardware internally inverts
14705 * the Termination High and Low bits if TERM_POL is set.
14706 */
14707 scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014708
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014709 /*
14710 * Set SCSI_CFG1 Microcode Default Value
14711 *
14712 * Set filter value and possibly modified termination control
14713 * bits in the Microcode SCSI_CFG1 Register Value.
14714 *
14715 * The microcode will set the SCSI_CFG1 register using this value
14716 * after it is started below.
14717 */
14718 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1,
14719 FLTR_DISABLE | scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014720
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014721 /*
14722 * Set MEM_CFG Microcode Default Value
14723 *
14724 * The microcode will set the MEM_CFG register using this value
14725 * after it is started below.
14726 *
14727 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
14728 * are defined.
14729 *
14730 * ASC-3550 has 8KB internal memory.
14731 */
14732 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
14733 BIOS_EN | RAM_SZ_8KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014734
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014735 /*
14736 * Set SEL_MASK Microcode Default Value
14737 *
14738 * The microcode will set the SEL_MASK register using this value
14739 * after it is started below.
14740 */
14741 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
14742 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014743
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014744 /*
14745 * Build carrier freelist.
14746 *
14747 * Driver must have already allocated memory and set 'carrier_buf'.
14748 */
14749 ASC_ASSERT(asc_dvc->carrier_buf != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014750
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014751 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
14752 asc_dvc->carr_freelist = NULL;
14753 if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
14754 buf_size = ADV_CARRIER_BUFSIZE;
14755 } else {
14756 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
14757 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014758
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014759 do {
14760 /*
14761 * Get physical address of the carrier 'carrp'.
14762 */
14763 contig_len = sizeof(ADV_CARR_T);
14764 carr_paddr =
14765 cpu_to_le32(DvcGetPhyAddr
14766 (asc_dvc, NULL, (uchar *)carrp,
14767 (ADV_SDCNT *)&contig_len,
14768 ADV_IS_CARRIER_FLAG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014769
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014770 buf_size -= sizeof(ADV_CARR_T);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014771
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014772 /*
14773 * If the current carrier is not physically contiguous, then
14774 * maybe there was a page crossing. Try the next carrier aligned
14775 * start address.
14776 */
14777 if (contig_len < sizeof(ADV_CARR_T)) {
14778 carrp++;
14779 continue;
14780 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014781
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014782 carrp->carr_pa = carr_paddr;
14783 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014784
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014785 /*
14786 * Insert the carrier at the beginning of the freelist.
14787 */
14788 carrp->next_vpa =
14789 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
14790 asc_dvc->carr_freelist = carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014791
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014792 carrp++;
14793 }
14794 while (buf_size > 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014795
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014796 /*
14797 * Set-up the Host->RISC Initiator Command Queue (ICQ).
14798 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014799
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014800 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
14801 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14802 return ADV_ERROR;
14803 }
14804 asc_dvc->carr_freelist = (ADV_CARR_T *)
14805 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014806
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014807 /*
14808 * The first command issued will be placed in the stopper carrier.
14809 */
14810 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014811
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014812 /*
14813 * Set RISC ICQ physical address start value.
14814 */
14815 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014816
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014817 /*
14818 * Set-up the RISC->Host Initiator Response Queue (IRQ).
14819 */
14820 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
14821 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14822 return ADV_ERROR;
14823 }
14824 asc_dvc->carr_freelist = (ADV_CARR_T *)
14825 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014826
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014827 /*
14828 * The first command completed by the RISC will be placed in
14829 * the stopper.
14830 *
14831 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
14832 * completed the RISC will set the ASC_RQ_STOPPER bit.
14833 */
14834 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014835
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014836 /*
14837 * Set RISC IRQ physical address start value.
14838 */
14839 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
14840 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014841
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014842 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
14843 (ADV_INTR_ENABLE_HOST_INTR |
14844 ADV_INTR_ENABLE_GLOBAL_INTR));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014845
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014846 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
14847 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014848
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014849 /* finally, finally, gentlemen, start your engine */
14850 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014851
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014852 /*
14853 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
14854 * Resets should be performed. The RISC has to be running
14855 * to issue a SCSI Bus Reset.
14856 */
14857 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
14858 /*
14859 * If the BIOS Signature is present in memory, restore the
14860 * BIOS Handshake Configuration Table and do not perform
14861 * a SCSI Bus Reset.
14862 */
14863 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
14864 0x55AA) {
14865 /*
14866 * Restore per TID negotiated values.
14867 */
14868 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14869 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14870 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
14871 tagqng_able);
14872 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14873 AdvWriteByteLram(iop_base,
14874 ASC_MC_NUMBER_OF_MAX_CMD + tid,
14875 max_cmd[tid]);
14876 }
14877 } else {
14878 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
14879 warn_code = ASC_WARN_BUSRESET_ERROR;
14880 }
14881 }
14882 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014883
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014884 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014885}
14886
14887/*
14888 * Initialize the ASC-38C0800.
14889 *
14890 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
14891 *
14892 * For a non-fatal error return a warning code. If there are no warnings
14893 * then 0 is returned.
14894 *
14895 * Needed after initialization for error recovery.
14896 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014897static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014898{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014899 AdvPortAddr iop_base;
14900 ushort warn_code;
14901 ADV_DCNT sum;
14902 int begin_addr;
14903 int end_addr;
14904 ushort code_sum;
14905 int word;
14906 int j;
14907 int adv_asc38C0800_expanded_size;
14908 ADV_CARR_T *carrp;
14909 ADV_DCNT contig_len;
14910 ADV_SDCNT buf_size;
14911 ADV_PADDR carr_paddr;
14912 int i;
14913 ushort scsi_cfg1;
14914 uchar byte;
14915 uchar tid;
14916 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
14917 ushort wdtr_able, sdtr_able, tagqng_able;
14918 uchar max_cmd[ADV_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070014919
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014920 /* If there is already an error, don't continue. */
14921 if (asc_dvc->err_code != 0) {
14922 return ADV_ERROR;
14923 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014924
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014925 /*
14926 * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800.
14927 */
14928 if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800) {
14929 asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
14930 return ADV_ERROR;
14931 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014932
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014933 warn_code = 0;
14934 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014935
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014936 /*
14937 * Save the RISC memory BIOS region before writing the microcode.
14938 * The BIOS may already be loaded and using its RISC LRAM region
14939 * so its region must be saved and restored.
14940 *
14941 * Note: This code makes the assumption, which is currently true,
14942 * that a chip reset does not clear RISC LRAM.
14943 */
14944 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
14945 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
14946 bios_mem[i]);
14947 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014948
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014949 /*
14950 * Save current per TID negotiated values.
14951 */
14952 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14953 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14954 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
14955 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14956 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
14957 max_cmd[tid]);
14958 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014959
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014960 /*
14961 * RAM BIST (RAM Built-In Self Test)
14962 *
14963 * Address : I/O base + offset 0x38h register (byte).
14964 * Function: Bit 7-6(RW) : RAM mode
14965 * Normal Mode : 0x00
14966 * Pre-test Mode : 0x40
14967 * RAM Test Mode : 0x80
14968 * Bit 5 : unused
14969 * Bit 4(RO) : Done bit
14970 * Bit 3-0(RO) : Status
14971 * Host Error : 0x08
14972 * Int_RAM Error : 0x04
14973 * RISC Error : 0x02
14974 * SCSI Error : 0x01
14975 * No Error : 0x00
14976 *
14977 * Note: RAM BIST code should be put right here, before loading the
14978 * microcode and after saving the RISC memory BIOS region.
14979 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014980
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014981 /*
14982 * LRAM Pre-test
14983 *
14984 * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
14985 * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
14986 * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
14987 * to NORMAL_MODE, return an error too.
14988 */
14989 for (i = 0; i < 2; i++) {
14990 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
14991 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
14992 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
14993 if ((byte & RAM_TEST_DONE) == 0
14994 || (byte & 0x0F) != PRE_TEST_VALUE) {
14995 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
14996 return ADV_ERROR;
14997 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014998
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014999 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
15000 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
15001 if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
15002 != NORMAL_VALUE) {
15003 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
15004 return ADV_ERROR;
15005 }
15006 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015007
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015008 /*
15009 * LRAM Test - It takes about 1.5 ms to run through the test.
15010 *
15011 * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
15012 * If Done bit not set or Status not 0, save register byte, set the
15013 * err_code, and return an error.
15014 */
15015 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
15016 DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070015017
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015018 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
15019 if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
15020 /* Get here if Done bit not set or Status not 0. */
15021 asc_dvc->bist_err_code = byte; /* for BIOS display message */
15022 asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
15023 return ADV_ERROR;
15024 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015025
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015026 /* We need to reset back to normal mode after LRAM test passes. */
15027 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015028
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015029 /*
15030 * Load the Microcode
15031 *
15032 * Write the microcode image to RISC memory starting at address 0.
15033 *
15034 */
15035 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015036
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015037 /* Assume the following compressed format of the microcode buffer:
15038 *
15039 * 254 word (508 byte) table indexed by byte code followed
15040 * by the following byte codes:
15041 *
15042 * 1-Byte Code:
15043 * 00: Emit word 0 in table.
15044 * 01: Emit word 1 in table.
15045 * .
15046 * FD: Emit word 253 in table.
15047 *
15048 * Multi-Byte Code:
15049 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
15050 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
15051 */
15052 word = 0;
15053 for (i = 253 * 2; i < _adv_asc38C0800_size; i++) {
15054 if (_adv_asc38C0800_buf[i] == 0xff) {
15055 for (j = 0; j < _adv_asc38C0800_buf[i + 1]; j++) {
15056 AdvWriteWordAutoIncLram(iop_base, (((ushort)
15057 _adv_asc38C0800_buf
15058 [i +
15059 3] << 8) |
15060 _adv_asc38C0800_buf
15061 [i + 2]));
15062 word++;
15063 }
15064 i += 3;
15065 } else if (_adv_asc38C0800_buf[i] == 0xfe) {
15066 AdvWriteWordAutoIncLram(iop_base, (((ushort)
15067 _adv_asc38C0800_buf
15068 [i +
15069 2] << 8) |
15070 _adv_asc38C0800_buf[i
15071 +
15072 1]));
15073 i += 2;
15074 word++;
15075 } else {
15076 AdvWriteWordAutoIncLram(iop_base, (((ushort)
15077 _adv_asc38C0800_buf[(_adv_asc38C0800_buf[i] * 2) + 1] << 8) | _adv_asc38C0800_buf[_adv_asc38C0800_buf[i] * 2]));
15078 word++;
15079 }
15080 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015081
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015082 /*
15083 * Set 'word' for later use to clear the rest of memory and save
15084 * the expanded mcode size.
15085 */
15086 word *= 2;
15087 adv_asc38C0800_expanded_size = word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015088
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015089 /*
15090 * Clear the rest of ASC-38C0800 Internal RAM (16KB).
15091 */
15092 for (; word < ADV_38C0800_MEMSIZE; word += 2) {
15093 AdvWriteWordAutoIncLram(iop_base, 0);
15094 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015095
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015096 /*
15097 * Verify the microcode checksum.
15098 */
15099 sum = 0;
15100 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015101
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015102 for (word = 0; word < adv_asc38C0800_expanded_size; word += 2) {
15103 sum += AdvReadWordAutoIncLram(iop_base);
15104 }
15105 ASC_DBG2(1, "AdvInitAsc38C0800Driver: word %d, i %d\n", word, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015106
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015107 ASC_DBG2(1,
15108 "AdvInitAsc38C0800Driver: sum 0x%lx, _adv_asc38C0800_chksum 0x%lx\n",
15109 (ulong)sum, (ulong)_adv_asc38C0800_chksum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015110
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015111 if (sum != _adv_asc38C0800_chksum) {
15112 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
15113 return ADV_ERROR;
15114 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015115
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015116 /*
15117 * Restore the RISC memory BIOS region.
15118 */
15119 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
15120 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
15121 bios_mem[i]);
15122 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015123
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015124 /*
15125 * Calculate and write the microcode code checksum to the microcode
15126 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
15127 */
15128 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
15129 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
15130 code_sum = 0;
15131 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
15132 for (word = begin_addr; word < end_addr; word += 2) {
15133 code_sum += AdvReadWordAutoIncLram(iop_base);
15134 }
15135 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015136
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015137 /*
15138 * Read microcode version and date.
15139 */
15140 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
15141 asc_dvc->cfg->mcode_date);
15142 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
15143 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015144
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015145 /*
15146 * Set the chip type to indicate the ASC38C0800.
15147 */
15148 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015149
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015150 /*
15151 * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
15152 * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
15153 * cable detection and then we are able to read C_DET[3:0].
15154 *
15155 * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
15156 * Microcode Default Value' section below.
15157 */
15158 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
15159 AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
15160 scsi_cfg1 | DIS_TERM_DRV);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015161
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015162 /*
15163 * If the PCI Configuration Command Register "Parity Error Response
15164 * Control" Bit was clear (0), then set the microcode variable
15165 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
15166 * to ignore DMA parity errors.
15167 */
15168 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
15169 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15170 word |= CONTROL_FLAG_IGNORE_PERR;
15171 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15172 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015173
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015174 /*
15175 * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2]
15176 * bits for the default FIFO threshold.
15177 *
15178 * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes.
15179 *
15180 * For DMA Errata #4 set the BC_THRESH_ENB bit.
15181 */
15182 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
15183 BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH |
15184 READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015185
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015186 /*
15187 * Microcode operating variables for WDTR, SDTR, and command tag
15188 * queuing will be set in AdvInquiryHandling() based on what a
15189 * device reports it is capable of in Inquiry byte 7.
15190 *
15191 * If SCSI Bus Resets have been disabled, then directly set
15192 * SDTR and WDTR from the EEPROM configuration. This will allow
15193 * the BIOS and warm boot to work without a SCSI bus hang on
15194 * the Inquiry caused by host and target mismatched DTR values.
15195 * Without the SCSI Bus Reset, before an Inquiry a device can't
15196 * be assumed to be in Asynchronous, Narrow mode.
15197 */
15198 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
15199 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
15200 asc_dvc->wdtr_able);
15201 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
15202 asc_dvc->sdtr_able);
15203 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015204
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015205 /*
15206 * Set microcode operating variables for DISC and SDTR_SPEED1,
15207 * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
15208 * configuration values.
15209 *
15210 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
15211 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
15212 * without determining here whether the device supports SDTR.
15213 */
15214 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
15215 asc_dvc->cfg->disc_enable);
15216 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
15217 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
15218 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
15219 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015220
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015221 /*
15222 * Set SCSI_CFG0 Microcode Default Value.
15223 *
15224 * The microcode will set the SCSI_CFG0 register using this value
15225 * after it is started below.
15226 */
15227 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
15228 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
15229 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015230
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015231 /*
15232 * Determine SCSI_CFG1 Microcode Default Value.
15233 *
15234 * The microcode will set the SCSI_CFG1 register using this value
15235 * after it is started below.
15236 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070015237
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015238 /* Read current SCSI_CFG1 Register value. */
15239 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015240
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015241 /*
15242 * If the internal narrow cable is reversed all of the SCSI_CTRL
15243 * register signals will be set. Check for and return an error if
15244 * this condition is found.
15245 */
15246 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
15247 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
15248 return ADV_ERROR;
15249 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015250
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015251 /*
15252 * All kind of combinations of devices attached to one of four connectors
15253 * are acceptable except HVD device attached. For example, LVD device can
15254 * be attached to SE connector while SE device attached to LVD connector.
15255 * If LVD device attached to SE connector, it only runs up to Ultra speed.
15256 *
15257 * If an HVD device is attached to one of LVD connectors, return an error.
15258 * However, there is no way to detect HVD device attached to SE connectors.
15259 */
15260 if (scsi_cfg1 & HVD) {
15261 asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
15262 return ADV_ERROR;
15263 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015264
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015265 /*
15266 * If either SE or LVD automatic termination control is enabled, then
15267 * set the termination value based on a table listed in a_condor.h.
15268 *
15269 * If manual termination was specified with an EEPROM setting then
15270 * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready to
15271 * be 'ored' into SCSI_CFG1.
15272 */
15273 if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
15274 /* SE automatic termination control is enabled. */
15275 switch (scsi_cfg1 & C_DET_SE) {
15276 /* TERM_SE_HI: on, TERM_SE_LO: on */
15277 case 0x1:
15278 case 0x2:
15279 case 0x3:
15280 asc_dvc->cfg->termination |= TERM_SE;
15281 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015282
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015283 /* TERM_SE_HI: on, TERM_SE_LO: off */
15284 case 0x0:
15285 asc_dvc->cfg->termination |= TERM_SE_HI;
15286 break;
15287 }
15288 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015289
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015290 if ((asc_dvc->cfg->termination & TERM_LVD) == 0) {
15291 /* LVD automatic termination control is enabled. */
15292 switch (scsi_cfg1 & C_DET_LVD) {
15293 /* TERM_LVD_HI: on, TERM_LVD_LO: on */
15294 case 0x4:
15295 case 0x8:
15296 case 0xC:
15297 asc_dvc->cfg->termination |= TERM_LVD;
15298 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015299
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015300 /* TERM_LVD_HI: off, TERM_LVD_LO: off */
15301 case 0x0:
15302 break;
15303 }
15304 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015305
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015306 /*
15307 * Clear any set TERM_SE and TERM_LVD bits.
15308 */
15309 scsi_cfg1 &= (~TERM_SE & ~TERM_LVD);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015310
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015311 /*
15312 * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'.
15313 */
15314 scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015315
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015316 /*
15317 * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE bits
15318 * and set possibly modified termination control bits in the Microcode
15319 * SCSI_CFG1 Register Value.
15320 */
15321 scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015322
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015323 /*
15324 * Set SCSI_CFG1 Microcode Default Value
15325 *
15326 * Set possibly modified termination control and reset DIS_TERM_DRV
15327 * bits in the Microcode SCSI_CFG1 Register Value.
15328 *
15329 * The microcode will set the SCSI_CFG1 register using this value
15330 * after it is started below.
15331 */
15332 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015333
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015334 /*
15335 * Set MEM_CFG Microcode Default Value
15336 *
15337 * The microcode will set the MEM_CFG register using this value
15338 * after it is started below.
15339 *
15340 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
15341 * are defined.
15342 *
15343 * ASC-38C0800 has 16KB internal memory.
15344 */
15345 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
15346 BIOS_EN | RAM_SZ_16KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015347
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015348 /*
15349 * Set SEL_MASK Microcode Default Value
15350 *
15351 * The microcode will set the SEL_MASK register using this value
15352 * after it is started below.
15353 */
15354 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
15355 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015356
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015357 /*
15358 * Build the carrier freelist.
15359 *
15360 * Driver must have already allocated memory and set 'carrier_buf'.
15361 */
15362 ASC_ASSERT(asc_dvc->carrier_buf != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015363
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015364 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
15365 asc_dvc->carr_freelist = NULL;
15366 if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
15367 buf_size = ADV_CARRIER_BUFSIZE;
15368 } else {
15369 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
15370 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015371
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015372 do {
15373 /*
15374 * Get physical address for the carrier 'carrp'.
15375 */
15376 contig_len = sizeof(ADV_CARR_T);
15377 carr_paddr =
15378 cpu_to_le32(DvcGetPhyAddr
15379 (asc_dvc, NULL, (uchar *)carrp,
15380 (ADV_SDCNT *)&contig_len,
15381 ADV_IS_CARRIER_FLAG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015382
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015383 buf_size -= sizeof(ADV_CARR_T);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015384
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015385 /*
15386 * If the current carrier is not physically contiguous, then
15387 * maybe there was a page crossing. Try the next carrier aligned
15388 * start address.
15389 */
15390 if (contig_len < sizeof(ADV_CARR_T)) {
15391 carrp++;
15392 continue;
15393 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015394
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015395 carrp->carr_pa = carr_paddr;
15396 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015397
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015398 /*
15399 * Insert the carrier at the beginning of the freelist.
15400 */
15401 carrp->next_vpa =
15402 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
15403 asc_dvc->carr_freelist = carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015404
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015405 carrp++;
15406 }
15407 while (buf_size > 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015408
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015409 /*
15410 * Set-up the Host->RISC Initiator Command Queue (ICQ).
15411 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070015412
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015413 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
15414 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
15415 return ADV_ERROR;
15416 }
15417 asc_dvc->carr_freelist = (ADV_CARR_T *)
15418 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015419
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015420 /*
15421 * The first command issued will be placed in the stopper carrier.
15422 */
15423 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015424
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015425 /*
15426 * Set RISC ICQ physical address start value.
15427 * carr_pa is LE, must be native before write
15428 */
15429 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015430
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015431 /*
15432 * Set-up the RISC->Host Initiator Response Queue (IRQ).
15433 */
15434 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
15435 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
15436 return ADV_ERROR;
15437 }
15438 asc_dvc->carr_freelist = (ADV_CARR_T *)
15439 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015440
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015441 /*
15442 * The first command completed by the RISC will be placed in
15443 * the stopper.
15444 *
15445 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
15446 * completed the RISC will set the ASC_RQ_STOPPER bit.
15447 */
15448 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015449
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015450 /*
15451 * Set RISC IRQ physical address start value.
15452 *
15453 * carr_pa is LE, must be native before write *
15454 */
15455 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
15456 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015457
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015458 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
15459 (ADV_INTR_ENABLE_HOST_INTR |
15460 ADV_INTR_ENABLE_GLOBAL_INTR));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015461
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015462 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
15463 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015464
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015465 /* finally, finally, gentlemen, start your engine */
15466 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015467
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015468 /*
15469 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
15470 * Resets should be performed. The RISC has to be running
15471 * to issue a SCSI Bus Reset.
15472 */
15473 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
15474 /*
15475 * If the BIOS Signature is present in memory, restore the
15476 * BIOS Handshake Configuration Table and do not perform
15477 * a SCSI Bus Reset.
15478 */
15479 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
15480 0x55AA) {
15481 /*
15482 * Restore per TID negotiated values.
15483 */
15484 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
15485 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
15486 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
15487 tagqng_able);
15488 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
15489 AdvWriteByteLram(iop_base,
15490 ASC_MC_NUMBER_OF_MAX_CMD + tid,
15491 max_cmd[tid]);
15492 }
15493 } else {
15494 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
15495 warn_code = ASC_WARN_BUSRESET_ERROR;
15496 }
15497 }
15498 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015499
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015500 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015501}
15502
15503/*
15504 * Initialize the ASC-38C1600.
15505 *
15506 * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
15507 *
15508 * For a non-fatal error return a warning code. If there are no warnings
15509 * then 0 is returned.
15510 *
15511 * Needed after initialization for error recovery.
15512 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015513static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070015514{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015515 AdvPortAddr iop_base;
15516 ushort warn_code;
15517 ADV_DCNT sum;
15518 int begin_addr;
15519 int end_addr;
15520 ushort code_sum;
15521 long word;
15522 int j;
15523 int adv_asc38C1600_expanded_size;
15524 ADV_CARR_T *carrp;
15525 ADV_DCNT contig_len;
15526 ADV_SDCNT buf_size;
15527 ADV_PADDR carr_paddr;
15528 int i;
15529 ushort scsi_cfg1;
15530 uchar byte;
15531 uchar tid;
15532 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
15533 ushort wdtr_able, sdtr_able, ppr_able, tagqng_able;
15534 uchar max_cmd[ASC_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070015535
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015536 /* If there is already an error, don't continue. */
15537 if (asc_dvc->err_code != 0) {
15538 return ADV_ERROR;
15539 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015540
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015541 /*
15542 * The caller must set 'chip_type' to ADV_CHIP_ASC38C1600.
15543 */
15544 if (asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
15545 asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
15546 return ADV_ERROR;
15547 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015548
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015549 warn_code = 0;
15550 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015551
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015552 /*
15553 * Save the RISC memory BIOS region before writing the microcode.
15554 * The BIOS may already be loaded and using its RISC LRAM region
15555 * so its region must be saved and restored.
15556 *
15557 * Note: This code makes the assumption, which is currently true,
15558 * that a chip reset does not clear RISC LRAM.
15559 */
15560 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
15561 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
15562 bios_mem[i]);
15563 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015564
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015565 /*
15566 * Save current per TID negotiated values.
15567 */
15568 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
15569 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
15570 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
15571 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
15572 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
15573 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
15574 max_cmd[tid]);
15575 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015576
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015577 /*
15578 * RAM BIST (Built-In Self Test)
15579 *
15580 * Address : I/O base + offset 0x38h register (byte).
15581 * Function: Bit 7-6(RW) : RAM mode
15582 * Normal Mode : 0x00
15583 * Pre-test Mode : 0x40
15584 * RAM Test Mode : 0x80
15585 * Bit 5 : unused
15586 * Bit 4(RO) : Done bit
15587 * Bit 3-0(RO) : Status
15588 * Host Error : 0x08
15589 * Int_RAM Error : 0x04
15590 * RISC Error : 0x02
15591 * SCSI Error : 0x01
15592 * No Error : 0x00
15593 *
15594 * Note: RAM BIST code should be put right here, before loading the
15595 * microcode and after saving the RISC memory BIOS region.
15596 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070015597
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015598 /*
15599 * LRAM Pre-test
15600 *
15601 * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
15602 * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
15603 * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
15604 * to NORMAL_MODE, return an error too.
15605 */
15606 for (i = 0; i < 2; i++) {
15607 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
15608 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
15609 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
15610 if ((byte & RAM_TEST_DONE) == 0
15611 || (byte & 0x0F) != PRE_TEST_VALUE) {
15612 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
15613 return ADV_ERROR;
15614 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015615
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015616 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
15617 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
15618 if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
15619 != NORMAL_VALUE) {
15620 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
15621 return ADV_ERROR;
15622 }
15623 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015624
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015625 /*
15626 * LRAM Test - It takes about 1.5 ms to run through the test.
15627 *
15628 * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
15629 * If Done bit not set or Status not 0, save register byte, set the
15630 * err_code, and return an error.
15631 */
15632 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
15633 DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070015634
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015635 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
15636 if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
15637 /* Get here if Done bit not set or Status not 0. */
15638 asc_dvc->bist_err_code = byte; /* for BIOS display message */
15639 asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
15640 return ADV_ERROR;
15641 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015642
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015643 /* We need to reset back to normal mode after LRAM test passes. */
15644 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015645
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015646 /*
15647 * Load the Microcode
15648 *
15649 * Write the microcode image to RISC memory starting at address 0.
15650 *
15651 */
15652 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015653
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015654 /*
15655 * Assume the following compressed format of the microcode buffer:
15656 *
15657 * 254 word (508 byte) table indexed by byte code followed
15658 * by the following byte codes:
15659 *
15660 * 1-Byte Code:
15661 * 00: Emit word 0 in table.
15662 * 01: Emit word 1 in table.
15663 * .
15664 * FD: Emit word 253 in table.
15665 *
15666 * Multi-Byte Code:
15667 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
15668 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
15669 */
15670 word = 0;
15671 for (i = 253 * 2; i < _adv_asc38C1600_size; i++) {
15672 if (_adv_asc38C1600_buf[i] == 0xff) {
15673 for (j = 0; j < _adv_asc38C1600_buf[i + 1]; j++) {
15674 AdvWriteWordAutoIncLram(iop_base, (((ushort)
15675 _adv_asc38C1600_buf
15676 [i +
15677 3] << 8) |
15678 _adv_asc38C1600_buf
15679 [i + 2]));
15680 word++;
15681 }
15682 i += 3;
15683 } else if (_adv_asc38C1600_buf[i] == 0xfe) {
15684 AdvWriteWordAutoIncLram(iop_base, (((ushort)
15685 _adv_asc38C1600_buf
15686 [i +
15687 2] << 8) |
15688 _adv_asc38C1600_buf[i
15689 +
15690 1]));
15691 i += 2;
15692 word++;
15693 } else {
15694 AdvWriteWordAutoIncLram(iop_base, (((ushort)
15695 _adv_asc38C1600_buf[(_adv_asc38C1600_buf[i] * 2) + 1] << 8) | _adv_asc38C1600_buf[_adv_asc38C1600_buf[i] * 2]));
15696 word++;
15697 }
15698 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015699
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015700 /*
15701 * Set 'word' for later use to clear the rest of memory and save
15702 * the expanded mcode size.
15703 */
15704 word *= 2;
15705 adv_asc38C1600_expanded_size = word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015706
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015707 /*
15708 * Clear the rest of ASC-38C1600 Internal RAM (32KB).
15709 */
15710 for (; word < ADV_38C1600_MEMSIZE; word += 2) {
15711 AdvWriteWordAutoIncLram(iop_base, 0);
15712 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015713
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015714 /*
15715 * Verify the microcode checksum.
15716 */
15717 sum = 0;
15718 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015719
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015720 for (word = 0; word < adv_asc38C1600_expanded_size; word += 2) {
15721 sum += AdvReadWordAutoIncLram(iop_base);
15722 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015723
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015724 if (sum != _adv_asc38C1600_chksum) {
15725 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
15726 return ADV_ERROR;
15727 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015728
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015729 /*
15730 * Restore the RISC memory BIOS region.
15731 */
15732 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
15733 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
15734 bios_mem[i]);
15735 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015736
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015737 /*
15738 * Calculate and write the microcode code checksum to the microcode
15739 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
15740 */
15741 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
15742 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
15743 code_sum = 0;
15744 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
15745 for (word = begin_addr; word < end_addr; word += 2) {
15746 code_sum += AdvReadWordAutoIncLram(iop_base);
15747 }
15748 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015749
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015750 /*
15751 * Read microcode version and date.
15752 */
15753 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
15754 asc_dvc->cfg->mcode_date);
15755 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
15756 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015757
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015758 /*
15759 * Set the chip type to indicate the ASC38C1600.
15760 */
15761 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C1600);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015762
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015763 /*
15764 * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
15765 * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
15766 * cable detection and then we are able to read C_DET[3:0].
15767 *
15768 * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
15769 * Microcode Default Value' section below.
15770 */
15771 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
15772 AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
15773 scsi_cfg1 | DIS_TERM_DRV);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015774
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015775 /*
15776 * If the PCI Configuration Command Register "Parity Error Response
15777 * Control" Bit was clear (0), then set the microcode variable
15778 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
15779 * to ignore DMA parity errors.
15780 */
15781 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
15782 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15783 word |= CONTROL_FLAG_IGNORE_PERR;
15784 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15785 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015786
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015787 /*
15788 * If the BIOS control flag AIPP (Asynchronous Information
15789 * Phase Protection) disable bit is not set, then set the firmware
15790 * 'control_flag' CONTROL_FLAG_ENABLE_AIPP bit to enable
15791 * AIPP checking and encoding.
15792 */
15793 if ((asc_dvc->bios_ctrl & BIOS_CTRL_AIPP_DIS) == 0) {
15794 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15795 word |= CONTROL_FLAG_ENABLE_AIPP;
15796 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15797 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015798
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015799 /*
15800 * For ASC-38C1600 use DMA_CFG0 default values: FIFO_THRESH_80B [6:4],
15801 * and START_CTL_TH [3:2].
15802 */
15803 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
15804 FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015805
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015806 /*
15807 * Microcode operating variables for WDTR, SDTR, and command tag
15808 * queuing will be set in AdvInquiryHandling() based on what a
15809 * device reports it is capable of in Inquiry byte 7.
15810 *
15811 * If SCSI Bus Resets have been disabled, then directly set
15812 * SDTR and WDTR from the EEPROM configuration. This will allow
15813 * the BIOS and warm boot to work without a SCSI bus hang on
15814 * the Inquiry caused by host and target mismatched DTR values.
15815 * Without the SCSI Bus Reset, before an Inquiry a device can't
15816 * be assumed to be in Asynchronous, Narrow mode.
15817 */
15818 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
15819 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
15820 asc_dvc->wdtr_able);
15821 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
15822 asc_dvc->sdtr_able);
15823 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015824
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015825 /*
15826 * Set microcode operating variables for DISC and SDTR_SPEED1,
15827 * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
15828 * configuration values.
15829 *
15830 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
15831 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
15832 * without determining here whether the device supports SDTR.
15833 */
15834 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
15835 asc_dvc->cfg->disc_enable);
15836 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
15837 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
15838 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
15839 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015840
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015841 /*
15842 * Set SCSI_CFG0 Microcode Default Value.
15843 *
15844 * The microcode will set the SCSI_CFG0 register using this value
15845 * after it is started below.
15846 */
15847 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
15848 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
15849 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015850
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015851 /*
15852 * Calculate SCSI_CFG1 Microcode Default Value.
15853 *
15854 * The microcode will set the SCSI_CFG1 register using this value
15855 * after it is started below.
15856 *
15857 * Each ASC-38C1600 function has only two cable detect bits.
15858 * The bus mode override bits are in IOPB_SOFT_OVER_WR.
15859 */
15860 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015861
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015862 /*
15863 * If the cable is reversed all of the SCSI_CTRL register signals
15864 * will be set. Check for and return an error if this condition is
15865 * found.
15866 */
15867 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
15868 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
15869 return ADV_ERROR;
15870 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015871
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015872 /*
15873 * Each ASC-38C1600 function has two connectors. Only an HVD device
15874 * can not be connected to either connector. An LVD device or SE device
15875 * may be connected to either connecor. If an SE device is connected,
15876 * then at most Ultra speed (20 Mhz) can be used on both connectors.
15877 *
15878 * If an HVD device is attached, return an error.
15879 */
15880 if (scsi_cfg1 & HVD) {
15881 asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
15882 return ADV_ERROR;
15883 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015884
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015885 /*
15886 * Each function in the ASC-38C1600 uses only the SE cable detect and
15887 * termination because there are two connectors for each function. Each
15888 * function may use either LVD or SE mode. Corresponding the SE automatic
15889 * termination control EEPROM bits are used for each function. Each
15890 * function has its own EEPROM. If SE automatic control is enabled for
15891 * the function, then set the termination value based on a table listed
15892 * in a_condor.h.
15893 *
15894 * If manual termination is specified in the EEPROM for the function,
15895 * then 'termination' was set-up in AscInitFrom38C1600EEPROM() and is
15896 * ready to be 'ored' into SCSI_CFG1.
15897 */
15898 if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
15899 /* SE automatic termination control is enabled. */
15900 switch (scsi_cfg1 & C_DET_SE) {
15901 /* TERM_SE_HI: on, TERM_SE_LO: on */
15902 case 0x1:
15903 case 0x2:
15904 case 0x3:
15905 asc_dvc->cfg->termination |= TERM_SE;
15906 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015907
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015908 case 0x0:
15909 if (ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) == 0) {
15910 /* Function 0 - TERM_SE_HI: off, TERM_SE_LO: off */
15911 } else {
15912 /* Function 1 - TERM_SE_HI: on, TERM_SE_LO: off */
15913 asc_dvc->cfg->termination |= TERM_SE_HI;
15914 }
15915 break;
15916 }
15917 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015918
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015919 /*
15920 * Clear any set TERM_SE bits.
15921 */
15922 scsi_cfg1 &= ~TERM_SE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015923
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015924 /*
15925 * Invert the TERM_SE bits and then set 'scsi_cfg1'.
15926 */
15927 scsi_cfg1 |= (~asc_dvc->cfg->termination & TERM_SE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015928
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015929 /*
15930 * Clear Big Endian and Terminator Polarity bits and set possibly
15931 * modified termination control bits in the Microcode SCSI_CFG1
15932 * Register Value.
15933 *
15934 * Big Endian bit is not used even on big endian machines.
15935 */
15936 scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015937
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015938 /*
15939 * Set SCSI_CFG1 Microcode Default Value
15940 *
15941 * Set possibly modified termination control bits in the Microcode
15942 * SCSI_CFG1 Register Value.
15943 *
15944 * The microcode will set the SCSI_CFG1 register using this value
15945 * after it is started below.
15946 */
15947 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015948
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015949 /*
15950 * Set MEM_CFG Microcode Default Value
15951 *
15952 * The microcode will set the MEM_CFG register using this value
15953 * after it is started below.
15954 *
15955 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
15956 * are defined.
15957 *
15958 * ASC-38C1600 has 32KB internal memory.
15959 *
15960 * XXX - Since ASC38C1600 Rev.3 has a Local RAM failure issue, we come
15961 * out a special 16K Adv Library and Microcode version. After the issue
15962 * resolved, we should turn back to the 32K support. Both a_condor.h and
15963 * mcode.sas files also need to be updated.
15964 *
15965 * AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
15966 * BIOS_EN | RAM_SZ_32KB);
15967 */
15968 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
15969 BIOS_EN | RAM_SZ_16KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015970
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015971 /*
15972 * Set SEL_MASK Microcode Default Value
15973 *
15974 * The microcode will set the SEL_MASK register using this value
15975 * after it is started below.
15976 */
15977 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
15978 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015979
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015980 /*
15981 * Build the carrier freelist.
15982 *
15983 * Driver must have already allocated memory and set 'carrier_buf'.
15984 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070015985
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015986 ASC_ASSERT(asc_dvc->carrier_buf != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015987
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015988 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
15989 asc_dvc->carr_freelist = NULL;
15990 if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
15991 buf_size = ADV_CARRIER_BUFSIZE;
15992 } else {
15993 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
15994 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015995
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015996 do {
15997 /*
15998 * Get physical address for the carrier 'carrp'.
15999 */
16000 contig_len = sizeof(ADV_CARR_T);
16001 carr_paddr =
16002 cpu_to_le32(DvcGetPhyAddr
16003 (asc_dvc, NULL, (uchar *)carrp,
16004 (ADV_SDCNT *)&contig_len,
16005 ADV_IS_CARRIER_FLAG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016006
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016007 buf_size -= sizeof(ADV_CARR_T);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016008
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016009 /*
16010 * If the current carrier is not physically contiguous, then
16011 * maybe there was a page crossing. Try the next carrier aligned
16012 * start address.
16013 */
16014 if (contig_len < sizeof(ADV_CARR_T)) {
16015 carrp++;
16016 continue;
16017 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016018
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016019 carrp->carr_pa = carr_paddr;
16020 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016021
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016022 /*
16023 * Insert the carrier at the beginning of the freelist.
16024 */
16025 carrp->next_vpa =
16026 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
16027 asc_dvc->carr_freelist = carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016028
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016029 carrp++;
16030 }
16031 while (buf_size > 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016032
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016033 /*
16034 * Set-up the Host->RISC Initiator Command Queue (ICQ).
16035 */
16036 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
16037 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
16038 return ADV_ERROR;
16039 }
16040 asc_dvc->carr_freelist = (ADV_CARR_T *)
16041 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016042
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016043 /*
16044 * The first command issued will be placed in the stopper carrier.
16045 */
16046 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016047
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016048 /*
16049 * Set RISC ICQ physical address start value. Initialize the
16050 * COMMA register to the same value otherwise the RISC will
16051 * prematurely detect a command is available.
16052 */
16053 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
16054 AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
16055 le32_to_cpu(asc_dvc->icq_sp->carr_pa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016056
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016057 /*
16058 * Set-up the RISC->Host Initiator Response Queue (IRQ).
16059 */
16060 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
16061 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
16062 return ADV_ERROR;
16063 }
16064 asc_dvc->carr_freelist = (ADV_CARR_T *)
16065 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016066
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016067 /*
16068 * The first command completed by the RISC will be placed in
16069 * the stopper.
16070 *
16071 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
16072 * completed the RISC will set the ASC_RQ_STOPPER bit.
16073 */
16074 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016075
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016076 /*
16077 * Set RISC IRQ physical address start value.
16078 */
16079 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
16080 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016081
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016082 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
16083 (ADV_INTR_ENABLE_HOST_INTR |
16084 ADV_INTR_ENABLE_GLOBAL_INTR));
16085 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
16086 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016087
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016088 /* finally, finally, gentlemen, start your engine */
16089 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016090
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016091 /*
16092 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
16093 * Resets should be performed. The RISC has to be running
16094 * to issue a SCSI Bus Reset.
16095 */
16096 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
16097 /*
16098 * If the BIOS Signature is present in memory, restore the
16099 * per TID microcode operating variables.
16100 */
16101 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
16102 0x55AA) {
16103 /*
16104 * Restore per TID negotiated values.
16105 */
16106 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
16107 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
16108 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
16109 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
16110 tagqng_able);
16111 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
16112 AdvWriteByteLram(iop_base,
16113 ASC_MC_NUMBER_OF_MAX_CMD + tid,
16114 max_cmd[tid]);
16115 }
16116 } else {
16117 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
16118 warn_code = ASC_WARN_BUSRESET_ERROR;
16119 }
16120 }
16121 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016122
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016123 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016124}
16125
16126/*
16127 * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
16128 * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
16129 * all of this is done.
16130 *
16131 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
16132 *
16133 * For a non-fatal error return a warning code. If there are no warnings
16134 * then 0 is returned.
16135 *
16136 * Note: Chip is stopped on entry.
16137 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016138static int __init AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016139{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016140 AdvPortAddr iop_base;
16141 ushort warn_code;
16142 ADVEEP_3550_CONFIG eep_config;
16143 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016144
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016145 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016146
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016147 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016148
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016149 /*
16150 * Read the board's EEPROM configuration.
16151 *
16152 * Set default values if a bad checksum is found.
16153 */
16154 if (AdvGet3550EEPConfig(iop_base, &eep_config) != eep_config.check_sum) {
16155 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016156
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016157 /*
16158 * Set EEPROM default values.
16159 */
16160 for (i = 0; i < sizeof(ADVEEP_3550_CONFIG); i++) {
16161 *((uchar *)&eep_config + i) =
16162 *((uchar *)&Default_3550_EEPROM_Config + i);
16163 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016164
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016165 /*
16166 * Assume the 6 byte board serial number that was read
16167 * from EEPROM is correct even if the EEPROM checksum
16168 * failed.
16169 */
16170 eep_config.serial_number_word3 =
16171 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016172
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016173 eep_config.serial_number_word2 =
16174 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016175
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016176 eep_config.serial_number_word1 =
16177 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016178
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016179 AdvSet3550EEPConfig(iop_base, &eep_config);
16180 }
16181 /*
16182 * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
16183 * EEPROM configuration that was read.
16184 *
16185 * This is the mapping of EEPROM fields to Adv Library fields.
16186 */
16187 asc_dvc->wdtr_able = eep_config.wdtr_able;
16188 asc_dvc->sdtr_able = eep_config.sdtr_able;
16189 asc_dvc->ultra_able = eep_config.ultra_able;
16190 asc_dvc->tagqng_able = eep_config.tagqng_able;
16191 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
16192 asc_dvc->max_host_qng = eep_config.max_host_qng;
16193 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
16194 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
16195 asc_dvc->start_motor = eep_config.start_motor;
16196 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
16197 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
16198 asc_dvc->no_scam = eep_config.scam_tolerant;
16199 asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
16200 asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
16201 asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016202
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016203 /*
16204 * Set the host maximum queuing (max. 253, min. 16) and the per device
16205 * maximum queuing (max. 63, min. 4).
16206 */
16207 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
16208 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
16209 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
16210 /* If the value is zero, assume it is uninitialized. */
16211 if (eep_config.max_host_qng == 0) {
16212 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
16213 } else {
16214 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
16215 }
16216 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016217
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016218 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
16219 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
16220 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
16221 /* If the value is zero, assume it is uninitialized. */
16222 if (eep_config.max_dvc_qng == 0) {
16223 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
16224 } else {
16225 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
16226 }
16227 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016228
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016229 /*
16230 * If 'max_dvc_qng' is greater than 'max_host_qng', then
16231 * set 'max_dvc_qng' to 'max_host_qng'.
16232 */
16233 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
16234 eep_config.max_dvc_qng = eep_config.max_host_qng;
16235 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016236
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016237 /*
16238 * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
16239 * values based on possibly adjusted EEPROM values.
16240 */
16241 asc_dvc->max_host_qng = eep_config.max_host_qng;
16242 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016243
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016244 /*
16245 * If the EEPROM 'termination' field is set to automatic (0), then set
16246 * the ADV_DVC_CFG 'termination' field to automatic also.
16247 *
16248 * If the termination is specified with a non-zero 'termination'
16249 * value check that a legal value is set and set the ADV_DVC_CFG
16250 * 'termination' field appropriately.
16251 */
16252 if (eep_config.termination == 0) {
16253 asc_dvc->cfg->termination = 0; /* auto termination */
16254 } else {
16255 /* Enable manual control with low off / high off. */
16256 if (eep_config.termination == 1) {
16257 asc_dvc->cfg->termination = TERM_CTL_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016258
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016259 /* Enable manual control with low off / high on. */
16260 } else if (eep_config.termination == 2) {
16261 asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016262
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016263 /* Enable manual control with low on / high on. */
16264 } else if (eep_config.termination == 3) {
16265 asc_dvc->cfg->termination =
16266 TERM_CTL_SEL | TERM_CTL_H | TERM_CTL_L;
16267 } else {
16268 /*
16269 * The EEPROM 'termination' field contains a bad value. Use
16270 * automatic termination instead.
16271 */
16272 asc_dvc->cfg->termination = 0;
16273 warn_code |= ASC_WARN_EEPROM_TERMINATION;
16274 }
16275 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016276
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016277 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016278}
16279
16280/*
16281 * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
16282 * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
16283 * all of this is done.
16284 *
16285 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
16286 *
16287 * For a non-fatal error return a warning code. If there are no warnings
16288 * then 0 is returned.
16289 *
16290 * Note: Chip is stopped on entry.
16291 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016292static int __init AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016293{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016294 AdvPortAddr iop_base;
16295 ushort warn_code;
16296 ADVEEP_38C0800_CONFIG eep_config;
16297 int i;
16298 uchar tid, termination;
16299 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016300
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016301 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016302
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016303 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016304
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016305 /*
16306 * Read the board's EEPROM configuration.
16307 *
16308 * Set default values if a bad checksum is found.
16309 */
16310 if (AdvGet38C0800EEPConfig(iop_base, &eep_config) !=
16311 eep_config.check_sum) {
16312 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016313
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016314 /*
16315 * Set EEPROM default values.
16316 */
16317 for (i = 0; i < sizeof(ADVEEP_38C0800_CONFIG); i++) {
16318 *((uchar *)&eep_config + i) =
16319 *((uchar *)&Default_38C0800_EEPROM_Config + i);
16320 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016321
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016322 /*
16323 * Assume the 6 byte board serial number that was read
16324 * from EEPROM is correct even if the EEPROM checksum
16325 * failed.
16326 */
16327 eep_config.serial_number_word3 =
16328 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016329
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016330 eep_config.serial_number_word2 =
16331 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016332
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016333 eep_config.serial_number_word1 =
16334 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016335
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016336 AdvSet38C0800EEPConfig(iop_base, &eep_config);
16337 }
16338 /*
16339 * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the
16340 * EEPROM configuration that was read.
16341 *
16342 * This is the mapping of EEPROM fields to Adv Library fields.
16343 */
16344 asc_dvc->wdtr_able = eep_config.wdtr_able;
16345 asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
16346 asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
16347 asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
16348 asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
16349 asc_dvc->tagqng_able = eep_config.tagqng_able;
16350 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
16351 asc_dvc->max_host_qng = eep_config.max_host_qng;
16352 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
16353 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
16354 asc_dvc->start_motor = eep_config.start_motor;
16355 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
16356 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
16357 asc_dvc->no_scam = eep_config.scam_tolerant;
16358 asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
16359 asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
16360 asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016361
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016362 /*
16363 * For every Target ID if any of its 'sdtr_speed[1234]' bits
16364 * are set, then set an 'sdtr_able' bit for it.
16365 */
16366 asc_dvc->sdtr_able = 0;
16367 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
16368 if (tid == 0) {
16369 sdtr_speed = asc_dvc->sdtr_speed1;
16370 } else if (tid == 4) {
16371 sdtr_speed = asc_dvc->sdtr_speed2;
16372 } else if (tid == 8) {
16373 sdtr_speed = asc_dvc->sdtr_speed3;
16374 } else if (tid == 12) {
16375 sdtr_speed = asc_dvc->sdtr_speed4;
16376 }
16377 if (sdtr_speed & ADV_MAX_TID) {
16378 asc_dvc->sdtr_able |= (1 << tid);
16379 }
16380 sdtr_speed >>= 4;
16381 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016382
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016383 /*
16384 * Set the host maximum queuing (max. 253, min. 16) and the per device
16385 * maximum queuing (max. 63, min. 4).
16386 */
16387 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
16388 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
16389 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
16390 /* If the value is zero, assume it is uninitialized. */
16391 if (eep_config.max_host_qng == 0) {
16392 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
16393 } else {
16394 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
16395 }
16396 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016397
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016398 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
16399 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
16400 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
16401 /* If the value is zero, assume it is uninitialized. */
16402 if (eep_config.max_dvc_qng == 0) {
16403 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
16404 } else {
16405 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
16406 }
16407 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016408
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016409 /*
16410 * If 'max_dvc_qng' is greater than 'max_host_qng', then
16411 * set 'max_dvc_qng' to 'max_host_qng'.
16412 */
16413 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
16414 eep_config.max_dvc_qng = eep_config.max_host_qng;
16415 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016416
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016417 /*
16418 * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
16419 * values based on possibly adjusted EEPROM values.
16420 */
16421 asc_dvc->max_host_qng = eep_config.max_host_qng;
16422 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016423
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016424 /*
16425 * If the EEPROM 'termination' field is set to automatic (0), then set
16426 * the ADV_DVC_CFG 'termination' field to automatic also.
16427 *
16428 * If the termination is specified with a non-zero 'termination'
16429 * value check that a legal value is set and set the ADV_DVC_CFG
16430 * 'termination' field appropriately.
16431 */
16432 if (eep_config.termination_se == 0) {
16433 termination = 0; /* auto termination for SE */
16434 } else {
16435 /* Enable manual control with low off / high off. */
16436 if (eep_config.termination_se == 1) {
16437 termination = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016438
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016439 /* Enable manual control with low off / high on. */
16440 } else if (eep_config.termination_se == 2) {
16441 termination = TERM_SE_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016442
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016443 /* Enable manual control with low on / high on. */
16444 } else if (eep_config.termination_se == 3) {
16445 termination = TERM_SE;
16446 } else {
16447 /*
16448 * The EEPROM 'termination_se' field contains a bad value.
16449 * Use automatic termination instead.
16450 */
16451 termination = 0;
16452 warn_code |= ASC_WARN_EEPROM_TERMINATION;
16453 }
16454 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016455
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016456 if (eep_config.termination_lvd == 0) {
16457 asc_dvc->cfg->termination = termination; /* auto termination for LVD */
16458 } else {
16459 /* Enable manual control with low off / high off. */
16460 if (eep_config.termination_lvd == 1) {
16461 asc_dvc->cfg->termination = termination;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016462
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016463 /* Enable manual control with low off / high on. */
16464 } else if (eep_config.termination_lvd == 2) {
16465 asc_dvc->cfg->termination = termination | TERM_LVD_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016466
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016467 /* Enable manual control with low on / high on. */
16468 } else if (eep_config.termination_lvd == 3) {
16469 asc_dvc->cfg->termination = termination | TERM_LVD;
16470 } else {
16471 /*
16472 * The EEPROM 'termination_lvd' field contains a bad value.
16473 * Use automatic termination instead.
16474 */
16475 asc_dvc->cfg->termination = termination;
16476 warn_code |= ASC_WARN_EEPROM_TERMINATION;
16477 }
16478 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016479
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016480 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016481}
16482
16483/*
16484 * Read the board's EEPROM configuration. Set fields in ASC_DVC_VAR and
16485 * ASC_DVC_CFG based on the EEPROM settings. The chip is stopped while
16486 * all of this is done.
16487 *
16488 * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
16489 *
16490 * For a non-fatal error return a warning code. If there are no warnings
16491 * then 0 is returned.
16492 *
16493 * Note: Chip is stopped on entry.
16494 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016495static int __init AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016496{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016497 AdvPortAddr iop_base;
16498 ushort warn_code;
16499 ADVEEP_38C1600_CONFIG eep_config;
16500 int i;
16501 uchar tid, termination;
16502 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016503
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016504 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016505
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016506 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016507
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016508 /*
16509 * Read the board's EEPROM configuration.
16510 *
16511 * Set default values if a bad checksum is found.
16512 */
16513 if (AdvGet38C1600EEPConfig(iop_base, &eep_config) !=
16514 eep_config.check_sum) {
16515 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016516
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016517 /*
16518 * Set EEPROM default values.
16519 */
16520 for (i = 0; i < sizeof(ADVEEP_38C1600_CONFIG); i++) {
16521 if (i == 1
16522 && ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) !=
16523 0) {
16524 /*
16525 * Set Function 1 EEPROM Word 0 MSB
16526 *
16527 * Clear the BIOS_ENABLE (bit 14) and INTAB (bit 11)
16528 * EEPROM bits.
16529 *
16530 * Disable Bit 14 (BIOS_ENABLE) to fix SPARC Ultra 60 and
16531 * old Mac system booting problem. The Expansion ROM must
16532 * be disabled in Function 1 for these systems.
16533 *
16534 */
16535 *((uchar *)&eep_config + i) =
16536 ((*
16537 ((uchar *)&Default_38C1600_EEPROM_Config
16538 +
16539 i)) &
16540 (~
16541 (((ADV_EEPROM_BIOS_ENABLE |
16542 ADV_EEPROM_INTAB) >> 8) & 0xFF)));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016543
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016544 /*
16545 * Set the INTAB (bit 11) if the GPIO 0 input indicates
16546 * the Function 1 interrupt line is wired to INTA.
16547 *
16548 * Set/Clear Bit 11 (INTAB) from the GPIO bit 0 input:
16549 * 1 - Function 1 interrupt line wired to INT A.
16550 * 0 - Function 1 interrupt line wired to INT B.
16551 *
16552 * Note: Adapter boards always have Function 0 wired to INTA.
16553 * Put all 5 GPIO bits in input mode and then read
16554 * their input values.
16555 */
16556 AdvWriteByteRegister(iop_base, IOPB_GPIO_CNTL,
16557 0);
16558 if (AdvReadByteRegister
16559 (iop_base, IOPB_GPIO_DATA) & 0x01) {
16560 /* Function 1 interrupt wired to INTA; Set EEPROM bit. */
16561 *((uchar *)&eep_config + i) |=
16562 ((ADV_EEPROM_INTAB >> 8) & 0xFF);
16563 }
16564 } else {
16565 *((uchar *)&eep_config + i) =
16566 *((uchar *)&Default_38C1600_EEPROM_Config
16567 + i);
16568 }
16569 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016570
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016571 /*
16572 * Assume the 6 byte board serial number that was read
16573 * from EEPROM is correct even if the EEPROM checksum
16574 * failed.
16575 */
16576 eep_config.serial_number_word3 =
16577 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016578
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016579 eep_config.serial_number_word2 =
16580 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016581
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016582 eep_config.serial_number_word1 =
16583 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016584
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016585 AdvSet38C1600EEPConfig(iop_base, &eep_config);
16586 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016587
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016588 /*
16589 * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
16590 * EEPROM configuration that was read.
16591 *
16592 * This is the mapping of EEPROM fields to Adv Library fields.
16593 */
16594 asc_dvc->wdtr_able = eep_config.wdtr_able;
16595 asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
16596 asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
16597 asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
16598 asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
16599 asc_dvc->ppr_able = 0;
16600 asc_dvc->tagqng_able = eep_config.tagqng_able;
16601 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
16602 asc_dvc->max_host_qng = eep_config.max_host_qng;
16603 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
16604 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ASC_MAX_TID);
16605 asc_dvc->start_motor = eep_config.start_motor;
16606 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
16607 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
16608 asc_dvc->no_scam = eep_config.scam_tolerant;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016609
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016610 /*
16611 * For every Target ID if any of its 'sdtr_speed[1234]' bits
16612 * are set, then set an 'sdtr_able' bit for it.
16613 */
16614 asc_dvc->sdtr_able = 0;
16615 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
16616 if (tid == 0) {
16617 sdtr_speed = asc_dvc->sdtr_speed1;
16618 } else if (tid == 4) {
16619 sdtr_speed = asc_dvc->sdtr_speed2;
16620 } else if (tid == 8) {
16621 sdtr_speed = asc_dvc->sdtr_speed3;
16622 } else if (tid == 12) {
16623 sdtr_speed = asc_dvc->sdtr_speed4;
16624 }
16625 if (sdtr_speed & ASC_MAX_TID) {
16626 asc_dvc->sdtr_able |= (1 << tid);
16627 }
16628 sdtr_speed >>= 4;
16629 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016630
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016631 /*
16632 * Set the host maximum queuing (max. 253, min. 16) and the per device
16633 * maximum queuing (max. 63, min. 4).
16634 */
16635 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
16636 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
16637 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
16638 /* If the value is zero, assume it is uninitialized. */
16639 if (eep_config.max_host_qng == 0) {
16640 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
16641 } else {
16642 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
16643 }
16644 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016645
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016646 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
16647 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
16648 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
16649 /* If the value is zero, assume it is uninitialized. */
16650 if (eep_config.max_dvc_qng == 0) {
16651 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
16652 } else {
16653 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
16654 }
16655 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016656
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016657 /*
16658 * If 'max_dvc_qng' is greater than 'max_host_qng', then
16659 * set 'max_dvc_qng' to 'max_host_qng'.
16660 */
16661 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
16662 eep_config.max_dvc_qng = eep_config.max_host_qng;
16663 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016664
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016665 /*
16666 * Set ASC_DVC_VAR 'max_host_qng' and ASC_DVC_VAR 'max_dvc_qng'
16667 * values based on possibly adjusted EEPROM values.
16668 */
16669 asc_dvc->max_host_qng = eep_config.max_host_qng;
16670 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016671
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016672 /*
16673 * If the EEPROM 'termination' field is set to automatic (0), then set
16674 * the ASC_DVC_CFG 'termination' field to automatic also.
16675 *
16676 * If the termination is specified with a non-zero 'termination'
16677 * value check that a legal value is set and set the ASC_DVC_CFG
16678 * 'termination' field appropriately.
16679 */
16680 if (eep_config.termination_se == 0) {
16681 termination = 0; /* auto termination for SE */
16682 } else {
16683 /* Enable manual control with low off / high off. */
16684 if (eep_config.termination_se == 1) {
16685 termination = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016686
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016687 /* Enable manual control with low off / high on. */
16688 } else if (eep_config.termination_se == 2) {
16689 termination = TERM_SE_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016690
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016691 /* Enable manual control with low on / high on. */
16692 } else if (eep_config.termination_se == 3) {
16693 termination = TERM_SE;
16694 } else {
16695 /*
16696 * The EEPROM 'termination_se' field contains a bad value.
16697 * Use automatic termination instead.
16698 */
16699 termination = 0;
16700 warn_code |= ASC_WARN_EEPROM_TERMINATION;
16701 }
16702 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016703
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016704 if (eep_config.termination_lvd == 0) {
16705 asc_dvc->cfg->termination = termination; /* auto termination for LVD */
16706 } else {
16707 /* Enable manual control with low off / high off. */
16708 if (eep_config.termination_lvd == 1) {
16709 asc_dvc->cfg->termination = termination;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016710
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016711 /* Enable manual control with low off / high on. */
16712 } else if (eep_config.termination_lvd == 2) {
16713 asc_dvc->cfg->termination = termination | TERM_LVD_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016714
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016715 /* Enable manual control with low on / high on. */
16716 } else if (eep_config.termination_lvd == 3) {
16717 asc_dvc->cfg->termination = termination | TERM_LVD;
16718 } else {
16719 /*
16720 * The EEPROM 'termination_lvd' field contains a bad value.
16721 * Use automatic termination instead.
16722 */
16723 asc_dvc->cfg->termination = termination;
16724 warn_code |= ASC_WARN_EEPROM_TERMINATION;
16725 }
16726 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016727
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016728 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016729}
16730
16731/*
16732 * Read EEPROM configuration into the specified buffer.
16733 *
16734 * Return a checksum based on the EEPROM configuration read.
16735 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016736static ushort __init
Linus Torvalds1da177e2005-04-16 15:20:36 -070016737AdvGet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
16738{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016739 ushort wval, chksum;
16740 ushort *wbuf;
16741 int eep_addr;
16742 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016743
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016744 charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
16745 wbuf = (ushort *)cfg_buf;
16746 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016747
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016748 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
16749 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
16750 wval = AdvReadEEPWord(iop_base, eep_addr);
16751 chksum += wval; /* Checksum is calculated from word values. */
16752 if (*charfields++) {
16753 *wbuf = le16_to_cpu(wval);
16754 } else {
16755 *wbuf = wval;
16756 }
16757 }
16758 /* Read checksum word. */
16759 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16760 wbuf++;
16761 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016762
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016763 /* Read rest of EEPROM not covered by the checksum. */
16764 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
16765 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
16766 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16767 if (*charfields++) {
16768 *wbuf = le16_to_cpu(*wbuf);
16769 }
16770 }
16771 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016772}
16773
16774/*
16775 * Read EEPROM configuration into the specified buffer.
16776 *
16777 * Return a checksum based on the EEPROM configuration read.
16778 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016779static ushort __init
16780AdvGet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016781{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016782 ushort wval, chksum;
16783 ushort *wbuf;
16784 int eep_addr;
16785 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016786
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016787 charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
16788 wbuf = (ushort *)cfg_buf;
16789 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016790
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016791 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
16792 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
16793 wval = AdvReadEEPWord(iop_base, eep_addr);
16794 chksum += wval; /* Checksum is calculated from word values. */
16795 if (*charfields++) {
16796 *wbuf = le16_to_cpu(wval);
16797 } else {
16798 *wbuf = wval;
16799 }
16800 }
16801 /* Read checksum word. */
16802 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16803 wbuf++;
16804 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016805
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016806 /* Read rest of EEPROM not covered by the checksum. */
16807 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
16808 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
16809 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16810 if (*charfields++) {
16811 *wbuf = le16_to_cpu(*wbuf);
16812 }
16813 }
16814 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016815}
16816
16817/*
16818 * Read EEPROM configuration into the specified buffer.
16819 *
16820 * Return a checksum based on the EEPROM configuration read.
16821 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016822static ushort __init
16823AdvGet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016824{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016825 ushort wval, chksum;
16826 ushort *wbuf;
16827 int eep_addr;
16828 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016829
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016830 charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
16831 wbuf = (ushort *)cfg_buf;
16832 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016833
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016834 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
16835 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
16836 wval = AdvReadEEPWord(iop_base, eep_addr);
16837 chksum += wval; /* Checksum is calculated from word values. */
16838 if (*charfields++) {
16839 *wbuf = le16_to_cpu(wval);
16840 } else {
16841 *wbuf = wval;
16842 }
16843 }
16844 /* Read checksum word. */
16845 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16846 wbuf++;
16847 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016848
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016849 /* Read rest of EEPROM not covered by the checksum. */
16850 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
16851 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
16852 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16853 if (*charfields++) {
16854 *wbuf = le16_to_cpu(*wbuf);
16855 }
16856 }
16857 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016858}
16859
16860/*
16861 * Read the EEPROM from specified location
16862 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016863static ushort __init AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016864{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016865 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16866 ASC_EEP_CMD_READ | eep_word_addr);
16867 AdvWaitEEPCmd(iop_base);
16868 return AdvReadWordRegister(iop_base, IOPW_EE_DATA);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016869}
16870
16871/*
16872 * Wait for EEPROM command to complete
16873 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016874static void __init AdvWaitEEPCmd(AdvPortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016875{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016876 int eep_delay_ms;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016877
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016878 for (eep_delay_ms = 0; eep_delay_ms < ADV_EEP_DELAY_MS; eep_delay_ms++) {
16879 if (AdvReadWordRegister(iop_base, IOPW_EE_CMD) &
16880 ASC_EEP_CMD_DONE) {
16881 break;
16882 }
16883 DvcSleepMilliSecond(1);
16884 }
16885 if ((AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) ==
16886 0) {
16887 ASC_ASSERT(0);
16888 }
16889 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016890}
16891
16892/*
16893 * Write the EEPROM from 'cfg_buf'.
16894 */
Randy Dunlapc8360432006-06-25 05:48:40 -070016895void __init
Linus Torvalds1da177e2005-04-16 15:20:36 -070016896AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
16897{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016898 ushort *wbuf;
16899 ushort addr, chksum;
16900 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016901
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016902 wbuf = (ushort *)cfg_buf;
16903 charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
16904 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016905
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016906 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
16907 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016908
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016909 /*
16910 * Write EEPROM from word 0 to word 20.
16911 */
16912 for (addr = ADV_EEP_DVC_CFG_BEGIN;
16913 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
16914 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016915
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016916 if (*charfields++) {
16917 word = cpu_to_le16(*wbuf);
16918 } else {
16919 word = *wbuf;
16920 }
16921 chksum += *wbuf; /* Checksum is calculated from word values. */
16922 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16923 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16924 ASC_EEP_CMD_WRITE | addr);
16925 AdvWaitEEPCmd(iop_base);
16926 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
16927 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016928
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016929 /*
16930 * Write EEPROM checksum at word 21.
16931 */
16932 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
16933 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
16934 AdvWaitEEPCmd(iop_base);
16935 wbuf++;
16936 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016937
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016938 /*
16939 * Write EEPROM OEM name at words 22 to 29.
16940 */
16941 for (addr = ADV_EEP_DVC_CTL_BEGIN;
16942 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
16943 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016944
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016945 if (*charfields++) {
16946 word = cpu_to_le16(*wbuf);
16947 } else {
16948 word = *wbuf;
16949 }
16950 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16951 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16952 ASC_EEP_CMD_WRITE | addr);
16953 AdvWaitEEPCmd(iop_base);
16954 }
16955 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
16956 AdvWaitEEPCmd(iop_base);
16957 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016958}
16959
16960/*
16961 * Write the EEPROM from 'cfg_buf'.
16962 */
Randy Dunlapc8360432006-06-25 05:48:40 -070016963void __init
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016964AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016965{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016966 ushort *wbuf;
16967 ushort *charfields;
16968 ushort addr, chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016969
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016970 wbuf = (ushort *)cfg_buf;
16971 charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
16972 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016973
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016974 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
16975 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016976
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016977 /*
16978 * Write EEPROM from word 0 to word 20.
16979 */
16980 for (addr = ADV_EEP_DVC_CFG_BEGIN;
16981 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
16982 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016983
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016984 if (*charfields++) {
16985 word = cpu_to_le16(*wbuf);
16986 } else {
16987 word = *wbuf;
16988 }
16989 chksum += *wbuf; /* Checksum is calculated from word values. */
16990 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16991 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16992 ASC_EEP_CMD_WRITE | addr);
16993 AdvWaitEEPCmd(iop_base);
16994 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
16995 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016996
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016997 /*
16998 * Write EEPROM checksum at word 21.
16999 */
17000 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
17001 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
17002 AdvWaitEEPCmd(iop_base);
17003 wbuf++;
17004 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017005
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017006 /*
17007 * Write EEPROM OEM name at words 22 to 29.
17008 */
17009 for (addr = ADV_EEP_DVC_CTL_BEGIN;
17010 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
17011 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017012
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017013 if (*charfields++) {
17014 word = cpu_to_le16(*wbuf);
17015 } else {
17016 word = *wbuf;
17017 }
17018 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
17019 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
17020 ASC_EEP_CMD_WRITE | addr);
17021 AdvWaitEEPCmd(iop_base);
17022 }
17023 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
17024 AdvWaitEEPCmd(iop_base);
17025 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017026}
17027
17028/*
17029 * Write the EEPROM from 'cfg_buf'.
17030 */
Randy Dunlapc8360432006-06-25 05:48:40 -070017031void __init
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017032AdvSet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070017033{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017034 ushort *wbuf;
17035 ushort *charfields;
17036 ushort addr, chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017037
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017038 wbuf = (ushort *)cfg_buf;
17039 charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
17040 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017041
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017042 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
17043 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017044
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017045 /*
17046 * Write EEPROM from word 0 to word 20.
17047 */
17048 for (addr = ADV_EEP_DVC_CFG_BEGIN;
17049 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
17050 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017051
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017052 if (*charfields++) {
17053 word = cpu_to_le16(*wbuf);
17054 } else {
17055 word = *wbuf;
17056 }
17057 chksum += *wbuf; /* Checksum is calculated from word values. */
17058 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
17059 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
17060 ASC_EEP_CMD_WRITE | addr);
17061 AdvWaitEEPCmd(iop_base);
17062 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
17063 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017064
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017065 /*
17066 * Write EEPROM checksum at word 21.
17067 */
17068 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
17069 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
17070 AdvWaitEEPCmd(iop_base);
17071 wbuf++;
17072 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017073
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017074 /*
17075 * Write EEPROM OEM name at words 22 to 29.
17076 */
17077 for (addr = ADV_EEP_DVC_CTL_BEGIN;
17078 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
17079 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017080
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017081 if (*charfields++) {
17082 word = cpu_to_le16(*wbuf);
17083 } else {
17084 word = *wbuf;
17085 }
17086 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
17087 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
17088 ASC_EEP_CMD_WRITE | addr);
17089 AdvWaitEEPCmd(iop_base);
17090 }
17091 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
17092 AdvWaitEEPCmd(iop_base);
17093 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017094}
17095
17096/* a_advlib.c */
17097/*
17098 * AdvExeScsiQueue() - Send a request to the RISC microcode program.
17099 *
17100 * Allocate a carrier structure, point the carrier to the ADV_SCSI_REQ_Q,
17101 * add the carrier to the ICQ (Initiator Command Queue), and tickle the
17102 * RISC to notify it a new command is ready to be executed.
17103 *
17104 * If 'done_status' is not set to QD_DO_RETRY, then 'error_retry' will be
17105 * set to SCSI_MAX_RETRY.
17106 *
17107 * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the microcode
17108 * for DMA addresses or math operations are byte swapped to little-endian
17109 * order.
17110 *
17111 * Return:
17112 * ADV_SUCCESS(1) - The request was successfully queued.
17113 * ADV_BUSY(0) - Resource unavailable; Retry again after pending
17114 * request completes.
17115 * ADV_ERROR(-1) - Invalid ADV_SCSI_REQ_Q request structure
17116 * host IC error.
17117 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017118static int AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070017119{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017120 ulong last_int_level;
17121 AdvPortAddr iop_base;
17122 ADV_DCNT req_size;
17123 ADV_PADDR req_paddr;
17124 ADV_CARR_T *new_carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017125
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017126 ASC_ASSERT(scsiq != NULL); /* 'scsiq' should never be NULL. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070017127
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017128 /*
17129 * The ADV_SCSI_REQ_Q 'target_id' field should never exceed ADV_MAX_TID.
17130 */
17131 if (scsiq->target_id > ADV_MAX_TID) {
17132 scsiq->host_status = QHSTA_M_INVALID_DEVICE;
17133 scsiq->done_status = QD_WITH_ERROR;
17134 return ADV_ERROR;
17135 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017136
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017137 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017138
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017139 last_int_level = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070017140
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017141 /*
17142 * Allocate a carrier ensuring at least one carrier always
17143 * remains on the freelist and initialize fields.
17144 */
17145 if ((new_carrp = asc_dvc->carr_freelist) == NULL) {
17146 DvcLeaveCritical(last_int_level);
17147 return ADV_BUSY;
17148 }
17149 asc_dvc->carr_freelist = (ADV_CARR_T *)
17150 ADV_U32_TO_VADDR(le32_to_cpu(new_carrp->next_vpa));
17151 asc_dvc->carr_pending_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017152
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017153 /*
17154 * Set the carrier to be a stopper by setting 'next_vpa'
17155 * to the stopper value. The current stopper will be changed
17156 * below to point to the new stopper.
17157 */
17158 new_carrp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017159
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017160 /*
17161 * Clear the ADV_SCSI_REQ_Q done flag.
17162 */
17163 scsiq->a_flag &= ~ADV_SCSIQ_DONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017164
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017165 req_size = sizeof(ADV_SCSI_REQ_Q);
17166 req_paddr = DvcGetPhyAddr(asc_dvc, scsiq, (uchar *)scsiq,
17167 (ADV_SDCNT *)&req_size, ADV_IS_SCSIQ_FLAG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017168
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017169 ASC_ASSERT(ADV_32BALIGN(req_paddr) == req_paddr);
17170 ASC_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q));
Linus Torvalds1da177e2005-04-16 15:20:36 -070017171
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017172 /* Wait for assertion before making little-endian */
17173 req_paddr = cpu_to_le32(req_paddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017174
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017175 /* Save virtual and physical address of ADV_SCSI_REQ_Q and carrier. */
17176 scsiq->scsiq_ptr = cpu_to_le32(ADV_VADDR_TO_U32(scsiq));
17177 scsiq->scsiq_rptr = req_paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017178
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017179 scsiq->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->icq_sp));
17180 /*
17181 * Every ADV_CARR_T.carr_pa is byte swapped to little-endian
17182 * order during initialization.
17183 */
17184 scsiq->carr_pa = asc_dvc->icq_sp->carr_pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017185
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017186 /*
17187 * Use the current stopper to send the ADV_SCSI_REQ_Q command to
17188 * the microcode. The newly allocated stopper will become the new
17189 * stopper.
17190 */
17191 asc_dvc->icq_sp->areq_vpa = req_paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017192
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017193 /*
17194 * Set the 'next_vpa' pointer for the old stopper to be the
17195 * physical address of the new stopper. The RISC can only
17196 * follow physical addresses.
17197 */
17198 asc_dvc->icq_sp->next_vpa = new_carrp->carr_pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017199
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017200 /*
17201 * Set the host adapter stopper pointer to point to the new carrier.
17202 */
17203 asc_dvc->icq_sp = new_carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017204
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017205 if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
17206 asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
17207 /*
17208 * Tickle the RISC to tell it to read its Command Queue Head pointer.
17209 */
17210 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
17211 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
17212 /*
17213 * Clear the tickle value. In the ASC-3550 the RISC flag
17214 * command 'clr_tickle_a' does not work unless the host
17215 * value is cleared.
17216 */
17217 AdvWriteByteRegister(iop_base, IOPB_TICKLE,
17218 ADV_TICKLE_NOP);
17219 }
17220 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
17221 /*
17222 * Notify the RISC a carrier is ready by writing the physical
17223 * address of the new carrier stopper to the COMMA register.
17224 */
17225 AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
17226 le32_to_cpu(new_carrp->carr_pa));
17227 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017228
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017229 DvcLeaveCritical(last_int_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017230
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017231 return ADV_SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017232}
17233
17234/*
17235 * Reset SCSI Bus and purge all outstanding requests.
17236 *
17237 * Return Value:
17238 * ADV_TRUE(1) - All requests are purged and SCSI Bus is reset.
17239 * ADV_FALSE(0) - Microcode command failed.
17240 * ADV_ERROR(-1) - Microcode command timed-out. Microcode or IC
17241 * may be hung which requires driver recovery.
17242 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017243static int AdvResetSB(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070017244{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017245 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017246
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017247 /*
17248 * Send the SCSI Bus Reset idle start idle command which asserts
17249 * the SCSI Bus Reset signal.
17250 */
17251 status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_START, 0L);
17252 if (status != ADV_TRUE) {
17253 return status;
17254 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017255
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017256 /*
17257 * Delay for the specified SCSI Bus Reset hold time.
17258 *
17259 * The hold time delay is done on the host because the RISC has no
17260 * microsecond accurate timer.
17261 */
17262 DvcDelayMicroSecond(asc_dvc, (ushort)ASC_SCSI_RESET_HOLD_TIME_US);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017263
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017264 /*
17265 * Send the SCSI Bus Reset end idle command which de-asserts
17266 * the SCSI Bus Reset signal and purges any pending requests.
17267 */
17268 status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_END, 0L);
17269 if (status != ADV_TRUE) {
17270 return status;
17271 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017272
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017273 DvcSleepMilliSecond((ADV_DCNT)asc_dvc->scsi_reset_wait * 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017274
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017275 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017276}
17277
17278/*
17279 * Reset chip and SCSI Bus.
17280 *
17281 * Return Value:
17282 * ADV_TRUE(1) - Chip re-initialization and SCSI Bus Reset successful.
17283 * ADV_FALSE(0) - Chip re-initialization and SCSI Bus Reset failure.
17284 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017285static int AdvResetChipAndSB(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070017286{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017287 int status;
17288 ushort wdtr_able, sdtr_able, tagqng_able;
17289 ushort ppr_able = 0;
17290 uchar tid, max_cmd[ADV_MAX_TID + 1];
17291 AdvPortAddr iop_base;
17292 ushort bios_sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017293
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017294 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017295
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017296 /*
17297 * Save current per TID negotiated values.
17298 */
17299 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
17300 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
17301 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
17302 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
17303 }
17304 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
17305 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
17306 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
17307 max_cmd[tid]);
17308 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017309
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017310 /*
17311 * Force the AdvInitAsc3550/38C0800Driver() function to
17312 * perform a SCSI Bus Reset by clearing the BIOS signature word.
17313 * The initialization functions assumes a SCSI Bus Reset is not
17314 * needed if the BIOS signature word is present.
17315 */
17316 AdvReadWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
17317 AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017318
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017319 /*
17320 * Stop chip and reset it.
17321 */
17322 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_STOP);
17323 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET);
17324 DvcSleepMilliSecond(100);
17325 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
17326 ADV_CTRL_REG_CMD_WR_IO_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017327
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017328 /*
17329 * Reset Adv Library error code, if any, and try
17330 * re-initializing the chip.
17331 */
17332 asc_dvc->err_code = 0;
17333 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
17334 status = AdvInitAsc38C1600Driver(asc_dvc);
17335 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
17336 status = AdvInitAsc38C0800Driver(asc_dvc);
17337 } else {
17338 status = AdvInitAsc3550Driver(asc_dvc);
17339 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017340
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017341 /* Translate initialization return value to status value. */
17342 if (status == 0) {
17343 status = ADV_TRUE;
17344 } else {
17345 status = ADV_FALSE;
17346 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017347
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017348 /*
17349 * Restore the BIOS signature word.
17350 */
17351 AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017352
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017353 /*
17354 * Restore per TID negotiated values.
17355 */
17356 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
17357 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
17358 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
17359 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
17360 }
17361 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
17362 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
17363 AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
17364 max_cmd[tid]);
17365 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017366
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017367 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017368}
17369
17370/*
17371 * Adv Library Interrupt Service Routine
17372 *
17373 * This function is called by a driver's interrupt service routine.
17374 * The function disables and re-enables interrupts.
17375 *
17376 * When a microcode idle command is completed, the ADV_DVC_VAR
17377 * 'idle_cmd_done' field is set to ADV_TRUE.
17378 *
17379 * Note: AdvISR() can be called when interrupts are disabled or even
17380 * when there is no hardware interrupt condition present. It will
17381 * always check for completed idle commands and microcode requests.
17382 * This is an important feature that shouldn't be changed because it
17383 * allows commands to be completed from polling mode loops.
17384 *
17385 * Return:
17386 * ADV_TRUE(1) - interrupt was pending
17387 * ADV_FALSE(0) - no interrupt was pending
17388 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017389static int AdvISR(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070017390{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017391 AdvPortAddr iop_base;
17392 uchar int_stat;
17393 ushort target_bit;
17394 ADV_CARR_T *free_carrp;
17395 ADV_VADDR irq_next_vpa;
17396 int flags;
17397 ADV_SCSI_REQ_Q *scsiq;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017398
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017399 flags = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070017400
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017401 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017402
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017403 /* Reading the register clears the interrupt. */
17404 int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017405
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017406 if ((int_stat & (ADV_INTR_STATUS_INTRA | ADV_INTR_STATUS_INTRB |
17407 ADV_INTR_STATUS_INTRC)) == 0) {
17408 DvcLeaveCritical(flags);
17409 return ADV_FALSE;
17410 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017411
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017412 /*
17413 * Notify the driver of an asynchronous microcode condition by
17414 * calling the ADV_DVC_VAR.async_callback function. The function
17415 * is passed the microcode ASC_MC_INTRB_CODE byte value.
17416 */
17417 if (int_stat & ADV_INTR_STATUS_INTRB) {
17418 uchar intrb_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017419
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017420 AdvReadByteLram(iop_base, ASC_MC_INTRB_CODE, intrb_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017421
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017422 if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
17423 asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
17424 if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE &&
17425 asc_dvc->carr_pending_cnt != 0) {
17426 AdvWriteByteRegister(iop_base, IOPB_TICKLE,
17427 ADV_TICKLE_A);
17428 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
17429 AdvWriteByteRegister(iop_base,
17430 IOPB_TICKLE,
17431 ADV_TICKLE_NOP);
17432 }
17433 }
17434 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017435
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017436 if (asc_dvc->async_callback != 0) {
17437 (*asc_dvc->async_callback) (asc_dvc, intrb_code);
17438 }
17439 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017440
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017441 /*
17442 * Check if the IRQ stopper carrier contains a completed request.
17443 */
17444 while (((irq_next_vpa =
17445 le32_to_cpu(asc_dvc->irq_sp->next_vpa)) & ASC_RQ_DONE) != 0) {
17446 /*
17447 * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure.
17448 * The RISC will have set 'areq_vpa' to a virtual address.
17449 *
17450 * The firmware will have copied the ASC_SCSI_REQ_Q.scsiq_ptr
17451 * field to the carrier ADV_CARR_T.areq_vpa field. The conversion
17452 * below complements the conversion of ASC_SCSI_REQ_Q.scsiq_ptr'
17453 * in AdvExeScsiQueue().
17454 */
17455 scsiq = (ADV_SCSI_REQ_Q *)
17456 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->areq_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070017457
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017458 /*
17459 * Request finished with good status and the queue was not
17460 * DMAed to host memory by the firmware. Set all status fields
17461 * to indicate good status.
17462 */
17463 if ((irq_next_vpa & ASC_RQ_GOOD) != 0) {
17464 scsiq->done_status = QD_NO_ERROR;
17465 scsiq->host_status = scsiq->scsi_status = 0;
17466 scsiq->data_cnt = 0L;
17467 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017468
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017469 /*
17470 * Advance the stopper pointer to the next carrier
17471 * ignoring the lower four bits. Free the previous
17472 * stopper carrier.
17473 */
17474 free_carrp = asc_dvc->irq_sp;
17475 asc_dvc->irq_sp = (ADV_CARR_T *)
17476 ADV_U32_TO_VADDR(ASC_GET_CARRP(irq_next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070017477
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017478 free_carrp->next_vpa =
17479 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
17480 asc_dvc->carr_freelist = free_carrp;
17481 asc_dvc->carr_pending_cnt--;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017482
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017483 ASC_ASSERT(scsiq != NULL);
17484 target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017485
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017486 /*
17487 * Clear request microcode control flag.
17488 */
17489 scsiq->cntl = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017490
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017491 /*
17492 * If the command that completed was a SCSI INQUIRY and
17493 * LUN 0 was sent the command, then process the INQUIRY
17494 * command information for the device.
17495 *
17496 * Note: If data returned were either VPD or CmdDt data,
17497 * don't process the INQUIRY command information for
17498 * the device, otherwise may erroneously set *_able bits.
17499 */
17500 if (scsiq->done_status == QD_NO_ERROR &&
17501 scsiq->cdb[0] == INQUIRY &&
17502 scsiq->target_lun == 0 &&
17503 (scsiq->cdb[1] & ADV_INQ_RTN_VPD_AND_CMDDT)
17504 == ADV_INQ_RTN_STD_INQUIRY_DATA) {
17505 AdvInquiryHandling(asc_dvc, scsiq);
17506 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017507
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017508 /*
17509 * Notify the driver of the completed request by passing
17510 * the ADV_SCSI_REQ_Q pointer to its callback function.
17511 */
17512 scsiq->a_flag |= ADV_SCSIQ_DONE;
17513 (*asc_dvc->isr_callback) (asc_dvc, scsiq);
17514 /*
17515 * Note: After the driver callback function is called, 'scsiq'
17516 * can no longer be referenced.
17517 *
17518 * Fall through and continue processing other completed
17519 * requests...
17520 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070017521
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017522 /*
17523 * Disable interrupts again in case the driver inadvertently
17524 * enabled interrupts in its callback function.
17525 *
17526 * The DvcEnterCritical() return value is ignored, because
17527 * the 'flags' saved when AdvISR() was first entered will be
17528 * used to restore the interrupt flag on exit.
17529 */
17530 (void)DvcEnterCritical();
17531 }
17532 DvcLeaveCritical(flags);
17533 return ADV_TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017534}
17535
17536/*
17537 * Send an idle command to the chip and wait for completion.
17538 *
17539 * Command completion is polled for once per microsecond.
17540 *
17541 * The function can be called from anywhere including an interrupt handler.
17542 * But the function is not re-entrant, so it uses the DvcEnter/LeaveCritical()
17543 * functions to prevent reentrancy.
17544 *
17545 * Return Values:
17546 * ADV_TRUE - command completed successfully
17547 * ADV_FALSE - command failed
17548 * ADV_ERROR - command timed out
17549 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017550static int
Linus Torvalds1da177e2005-04-16 15:20:36 -070017551AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017552 ushort idle_cmd, ADV_DCNT idle_cmd_parameter)
Linus Torvalds1da177e2005-04-16 15:20:36 -070017553{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017554 ulong last_int_level;
17555 int result;
17556 ADV_DCNT i, j;
17557 AdvPortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017558
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017559 last_int_level = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070017560
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017561 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017562
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017563 /*
17564 * Clear the idle command status which is set by the microcode
17565 * to a non-zero value to indicate when the command is completed.
17566 * The non-zero result is one of the IDLE_CMD_STATUS_* values
17567 * defined in a_advlib.h.
17568 */
17569 AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, (ushort)0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017570
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017571 /*
17572 * Write the idle command value after the idle command parameter
17573 * has been written to avoid a race condition. If the order is not
17574 * followed, the microcode may process the idle command before the
17575 * parameters have been written to LRAM.
17576 */
17577 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IDLE_CMD_PARAMETER,
17578 cpu_to_le32(idle_cmd_parameter));
17579 AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017580
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017581 /*
17582 * Tickle the RISC to tell it to process the idle command.
17583 */
17584 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_B);
17585 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
17586 /*
17587 * Clear the tickle value. In the ASC-3550 the RISC flag
17588 * command 'clr_tickle_b' does not work unless the host
17589 * value is cleared.
17590 */
17591 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
17592 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017593
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017594 /* Wait for up to 100 millisecond for the idle command to timeout. */
17595 for (i = 0; i < SCSI_WAIT_100_MSEC; i++) {
17596 /* Poll once each microsecond for command completion. */
17597 for (j = 0; j < SCSI_US_PER_MSEC; j++) {
17598 AdvReadWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS,
17599 result);
17600 if (result != 0) {
17601 DvcLeaveCritical(last_int_level);
17602 return result;
17603 }
17604 DvcDelayMicroSecond(asc_dvc, (ushort)1);
17605 }
17606 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017607
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017608 ASC_ASSERT(0); /* The idle command should never timeout. */
17609 DvcLeaveCritical(last_int_level);
17610 return ADV_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017611}
17612
17613/*
17614 * Inquiry Information Byte 7 Handling
17615 *
17616 * Handle SCSI Inquiry Command information for a device by setting
17617 * microcode operating variables that affect WDTR, SDTR, and Tag
17618 * Queuing.
17619 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017620static void AdvInquiryHandling(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070017621{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017622 AdvPortAddr iop_base;
17623 uchar tid;
17624 ADV_SCSI_INQUIRY *inq;
17625 ushort tidmask;
17626 ushort cfg_word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017627
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017628 /*
17629 * AdvInquiryHandling() requires up to INQUIRY information Byte 7
17630 * to be available.
17631 *
17632 * If less than 8 bytes of INQUIRY information were requested or less
17633 * than 8 bytes were transferred, then return. cdb[4] is the request
17634 * length and the ADV_SCSI_REQ_Q 'data_cnt' field is set by the
17635 * microcode to the transfer residual count.
17636 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070017637
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017638 if (scsiq->cdb[4] < 8 ||
17639 (scsiq->cdb[4] - le32_to_cpu(scsiq->data_cnt)) < 8) {
17640 return;
17641 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017642
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017643 iop_base = asc_dvc->iop_base;
17644 tid = scsiq->target_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017645
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017646 inq = (ADV_SCSI_INQUIRY *) scsiq->vdata_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017647
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017648 /*
17649 * WDTR, SDTR, and Tag Queuing cannot be enabled for old devices.
17650 */
17651 if (ADV_INQ_RESPONSE_FMT(inq) < 2 && ADV_INQ_ANSI_VER(inq) < 2) {
17652 return;
17653 } else {
17654 /*
17655 * INQUIRY Byte 7 Handling
17656 *
17657 * Use a device's INQUIRY byte 7 to determine whether it
17658 * supports WDTR, SDTR, and Tag Queuing. If the feature
17659 * is enabled in the EEPROM and the device supports the
17660 * feature, then enable it in the microcode.
17661 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070017662
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017663 tidmask = ADV_TID_TO_TIDMASK(tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017664
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017665 /*
17666 * Wide Transfers
17667 *
17668 * If the EEPROM enabled WDTR for the device and the device
17669 * supports wide bus (16 bit) transfers, then turn on the
17670 * device's 'wdtr_able' bit and write the new value to the
17671 * microcode.
17672 */
17673 if ((asc_dvc->wdtr_able & tidmask) && ADV_INQ_WIDE16(inq)) {
17674 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
17675 if ((cfg_word & tidmask) == 0) {
17676 cfg_word |= tidmask;
17677 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
17678 cfg_word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017679
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017680 /*
17681 * Clear the microcode "SDTR negotiation" and "WDTR
17682 * negotiation" done indicators for the target to cause
17683 * it to negotiate with the new setting set above.
17684 * WDTR when accepted causes the target to enter
17685 * asynchronous mode, so SDTR must be negotiated.
17686 */
17687 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE,
17688 cfg_word);
17689 cfg_word &= ~tidmask;
17690 AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE,
17691 cfg_word);
17692 AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE,
17693 cfg_word);
17694 cfg_word &= ~tidmask;
17695 AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE,
17696 cfg_word);
17697 }
17698 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017699
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017700 /*
17701 * Synchronous Transfers
17702 *
17703 * If the EEPROM enabled SDTR for the device and the device
17704 * supports synchronous transfers, then turn on the device's
17705 * 'sdtr_able' bit. Write the new value to the microcode.
17706 */
17707 if ((asc_dvc->sdtr_able & tidmask) && ADV_INQ_SYNC(inq)) {
17708 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
17709 if ((cfg_word & tidmask) == 0) {
17710 cfg_word |= tidmask;
17711 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
17712 cfg_word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017713
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017714 /*
17715 * Clear the microcode "SDTR negotiation" done indicator
17716 * for the target to cause it to negotiate with the new
17717 * setting set above.
17718 */
17719 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE,
17720 cfg_word);
17721 cfg_word &= ~tidmask;
17722 AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE,
17723 cfg_word);
17724 }
17725 }
17726 /*
17727 * If the Inquiry data included enough space for the SPI-3
17728 * Clocking field, then check if DT mode is supported.
17729 */
17730 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600 &&
17731 (scsiq->cdb[4] >= 57 ||
17732 (scsiq->cdb[4] - le32_to_cpu(scsiq->data_cnt)) >= 57)) {
17733 /*
17734 * PPR (Parallel Protocol Request) Capable
17735 *
17736 * If the device supports DT mode, then it must be PPR capable.
17737 * The PPR message will be used in place of the SDTR and WDTR
17738 * messages to negotiate synchronous speed and offset, transfer
17739 * width, and protocol options.
17740 */
17741 if (ADV_INQ_CLOCKING(inq) & ADV_INQ_CLOCKING_DT_ONLY) {
17742 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE,
17743 asc_dvc->ppr_able);
17744 asc_dvc->ppr_able |= tidmask;
17745 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE,
17746 asc_dvc->ppr_able);
17747 }
17748 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017749
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017750 /*
17751 * If the EEPROM enabled Tag Queuing for the device and the
17752 * device supports Tag Queueing, then turn on the device's
17753 * 'tagqng_enable' bit in the microcode and set the microcode
17754 * maximum command count to the ADV_DVC_VAR 'max_dvc_qng'
17755 * value.
17756 *
17757 * Tag Queuing is disabled for the BIOS which runs in polled
17758 * mode and would see no benefit from Tag Queuing. Also by
17759 * disabling Tag Queuing in the BIOS devices with Tag Queuing
17760 * bugs will at least work with the BIOS.
17761 */
17762 if ((asc_dvc->tagqng_able & tidmask) && ADV_INQ_CMD_QUEUE(inq)) {
17763 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
17764 cfg_word |= tidmask;
17765 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
17766 cfg_word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017767
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017768 AdvWriteByteLram(iop_base,
17769 ASC_MC_NUMBER_OF_MAX_CMD + tid,
17770 asc_dvc->max_dvc_qng);
17771 }
17772 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017773}
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017774
Linus Torvalds1da177e2005-04-16 15:20:36 -070017775MODULE_LICENSE("Dual BSD/GPL");
Dave Jones2672ea82006-08-02 17:11:49 -040017776
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017777static struct Scsi_Host *__devinit
17778advansys_board_found(int iop, struct device *dev, int bus_type)
17779{
17780 struct Scsi_Host *shost;
17781 struct pci_dev *pdev = bus_type == ASC_IS_PCI ? to_pci_dev(dev) : NULL;
17782 asc_board_t *boardp;
17783 ASC_DVC_VAR *asc_dvc_varp = NULL;
17784 ADV_DVC_VAR *adv_dvc_varp = NULL;
17785 adv_sgblk_t *sgp = NULL;
17786 int share_irq = FALSE;
17787 int iolen = 0;
17788 ADV_PADDR pci_memory_address;
17789 int warn_code, err_code;
17790 int ret;
17791
17792 /*
17793 * Adapter found.
17794 *
17795 * Register the adapter, get its configuration, and
17796 * initialize it.
17797 */
17798 ASC_DBG(2, "advansys_board_found: scsi_register()\n");
17799 shost = scsi_register(&driver_template, sizeof(asc_board_t));
17800
17801 if (!shost)
17802 return NULL;
17803
17804 /* Save a pointer to the Scsi_Host of each board found. */
17805 asc_host[asc_board_count++] = shost;
17806
17807 /* Initialize private per board data */
17808 boardp = ASC_BOARDP(shost);
17809 memset(boardp, 0, sizeof(asc_board_t));
17810 boardp->id = asc_board_count - 1;
17811
17812 /* Initialize spinlock. */
17813 spin_lock_init(&boardp->lock);
17814
17815 /*
17816 * Handle both narrow and wide boards.
17817 *
17818 * If a Wide board was detected, set the board structure
17819 * wide board flag. Set-up the board structure based on
17820 * the board type.
17821 */
17822#ifdef CONFIG_PCI
17823 if (bus_type == ASC_IS_PCI &&
17824 (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW ||
17825 pdev->device == PCI_DEVICE_ID_38C0800_REV1 ||
17826 pdev->device == PCI_DEVICE_ID_38C1600_REV1)) {
17827 boardp->flags |= ASC_IS_WIDE_BOARD;
17828 }
17829#endif /* CONFIG_PCI */
17830
17831 if (ASC_NARROW_BOARD(boardp)) {
17832 ASC_DBG(1, "advansys_board_found: narrow board\n");
17833 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
17834 asc_dvc_varp->bus_type = bus_type;
17835 asc_dvc_varp->drv_ptr = boardp;
17836 asc_dvc_varp->cfg = &boardp->dvc_cfg.asc_dvc_cfg;
17837 asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0];
17838 asc_dvc_varp->iop_base = iop;
17839 asc_dvc_varp->isr_callback = asc_isr_callback;
17840 } else {
17841 ASC_DBG(1, "advansys_board_found: wide board\n");
17842 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
17843 adv_dvc_varp->drv_ptr = boardp;
17844 adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg;
17845 adv_dvc_varp->isr_callback = adv_isr_callback;
17846 adv_dvc_varp->async_callback = adv_async_callback;
17847#ifdef CONFIG_PCI
17848 if (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW) {
17849 ASC_DBG(1, "advansys_board_found: ASC-3550\n");
17850 adv_dvc_varp->chip_type = ADV_CHIP_ASC3550;
17851 } else if (pdev->device == PCI_DEVICE_ID_38C0800_REV1) {
17852 ASC_DBG(1, "advansys_board_found: ASC-38C0800\n");
17853 adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800;
17854 } else {
17855 ASC_DBG(1, "advansys_board_found: ASC-38C1600\n");
17856 adv_dvc_varp->chip_type = ADV_CHIP_ASC38C1600;
17857 }
17858#endif /* CONFIG_PCI */
17859
17860 /*
17861 * Map the board's registers into virtual memory for
17862 * PCI slave access. Only memory accesses are used to
17863 * access the board's registers.
17864 *
17865 * Note: The PCI register base address is not always
17866 * page aligned, but the address passed to ioremap()
17867 * must be page aligned. It is guaranteed that the
17868 * PCI register base address will not cross a page
17869 * boundary.
17870 */
17871 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
17872 iolen = ADV_3550_IOLEN;
17873 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
17874 iolen = ADV_38C0800_IOLEN;
17875 } else {
17876 iolen = ADV_38C1600_IOLEN;
17877 }
17878#ifdef CONFIG_PCI
17879 pci_memory_address = pci_resource_start(pdev, 1);
17880 ASC_DBG1(1,
17881 "advansys_board_found: pci_memory_address: 0x%lx\n",
17882 (ulong)pci_memory_address);
17883 if ((boardp->ioremap_addr =
17884 ioremap(pci_memory_address & PAGE_MASK, PAGE_SIZE)) == 0) {
17885 ASC_PRINT3
17886 ("advansys_board_found: board %d: ioremap(%x, %d) returned NULL\n",
17887 boardp->id, pci_memory_address, iolen);
17888 scsi_unregister(shost);
17889 asc_board_count--;
17890 return NULL;
17891 }
17892 ASC_DBG1(1,
17893 "advansys_board_found: ioremap_addr: 0x%lx\n",
17894 (ulong)boardp->ioremap_addr);
17895 adv_dvc_varp->iop_base = (AdvPortAddr)
17896 (boardp->ioremap_addr +
17897 (pci_memory_address - (pci_memory_address & PAGE_MASK)));
17898 ASC_DBG1(1,
17899 "advansys_board_found: iop_base: 0x%lx\n",
17900 adv_dvc_varp->iop_base);
17901#endif /* CONFIG_PCI */
17902
17903 /*
17904 * Even though it isn't used to access wide boards, other
17905 * than for the debug line below, save I/O Port address so
17906 * that it can be reported.
17907 */
17908 boardp->ioport = iop;
17909
17910 ASC_DBG2(1,
17911 "advansys_board_found: iopb_chip_id_1 0x%x, iopw_chip_id_0 0x%x\n",
17912 (ushort)inp(iop + 1), (ushort)inpw(iop));
17913 }
17914
17915#ifdef CONFIG_PROC_FS
17916 /*
17917 * Allocate buffer for printing information from
17918 * /proc/scsi/advansys/[0...].
17919 */
17920 if ((boardp->prtbuf = kmalloc(ASC_PRTBUF_SIZE, GFP_ATOMIC)) == NULL) {
17921 ASC_PRINT3
17922 ("advansys_board_found: board %d: kmalloc(%d, %d) returned NULL\n",
17923 boardp->id, ASC_PRTBUF_SIZE, GFP_ATOMIC);
17924 scsi_unregister(shost);
17925 asc_board_count--;
17926 return NULL;
17927 }
17928#endif /* CONFIG_PROC_FS */
17929
17930 if (ASC_NARROW_BOARD(boardp)) {
17931 asc_dvc_varp->cfg->dev = dev;
17932 /*
17933 * Set the board bus type and PCI IRQ before
17934 * calling AscInitGetConfig().
17935 */
17936 switch (asc_dvc_varp->bus_type) {
17937#ifdef CONFIG_ISA
17938 case ASC_IS_ISA:
17939 shost->unchecked_isa_dma = TRUE;
17940 share_irq = FALSE;
17941 break;
17942 case ASC_IS_VL:
17943 shost->unchecked_isa_dma = FALSE;
17944 share_irq = FALSE;
17945 break;
17946 case ASC_IS_EISA:
17947 shost->unchecked_isa_dma = FALSE;
17948 share_irq = TRUE;
17949 break;
17950#endif /* CONFIG_ISA */
17951#ifdef CONFIG_PCI
17952 case ASC_IS_PCI:
17953 shost->irq = asc_dvc_varp->irq_no = pdev->irq;
17954 asc_dvc_varp->cfg->pci_slot_info =
17955 ASC_PCI_MKID(pdev->bus->number,
17956 PCI_SLOT(pdev->devfn),
17957 PCI_FUNC(pdev->devfn));
17958 shost->unchecked_isa_dma = FALSE;
17959 share_irq = TRUE;
17960 break;
17961#endif /* CONFIG_PCI */
17962 default:
17963 ASC_PRINT2
17964 ("advansys_board_found: board %d: unknown adapter type: %d\n",
17965 boardp->id, asc_dvc_varp->bus_type);
17966 shost->unchecked_isa_dma = TRUE;
17967 share_irq = FALSE;
17968 break;
17969 }
17970 } else {
17971 adv_dvc_varp->cfg->dev = dev;
17972 /*
17973 * For Wide boards set PCI information before calling
17974 * AdvInitGetConfig().
17975 */
17976#ifdef CONFIG_PCI
17977 shost->irq = adv_dvc_varp->irq_no = pdev->irq;
17978 adv_dvc_varp->cfg->pci_slot_info =
17979 ASC_PCI_MKID(pdev->bus->number,
17980 PCI_SLOT(pdev->devfn),
17981 PCI_FUNC(pdev->devfn));
17982 shost->unchecked_isa_dma = FALSE;
17983 share_irq = TRUE;
17984#endif /* CONFIG_PCI */
17985 }
17986
17987 /*
17988 * Read the board configuration.
17989 */
17990 if (ASC_NARROW_BOARD(boardp)) {
17991 /*
17992 * NOTE: AscInitGetConfig() may change the board's
17993 * bus_type value. The bus_type value should no
17994 * longer be used. If the bus_type field must be
17995 * referenced only use the bit-wise AND operator "&".
17996 */
17997 ASC_DBG(2, "advansys_board_found: AscInitGetConfig()\n");
17998 switch (ret = AscInitGetConfig(asc_dvc_varp)) {
17999 case 0: /* No error */
18000 break;
18001 case ASC_WARN_IO_PORT_ROTATE:
18002 ASC_PRINT1
18003 ("AscInitGetConfig: board %d: I/O port address modified\n",
18004 boardp->id);
18005 break;
18006 case ASC_WARN_AUTO_CONFIG:
18007 ASC_PRINT1
18008 ("AscInitGetConfig: board %d: I/O port increment switch enabled\n",
18009 boardp->id);
18010 break;
18011 case ASC_WARN_EEPROM_CHKSUM:
18012 ASC_PRINT1
18013 ("AscInitGetConfig: board %d: EEPROM checksum error\n",
18014 boardp->id);
18015 break;
18016 case ASC_WARN_IRQ_MODIFIED:
18017 ASC_PRINT1
18018 ("AscInitGetConfig: board %d: IRQ modified\n",
18019 boardp->id);
18020 break;
18021 case ASC_WARN_CMD_QNG_CONFLICT:
18022 ASC_PRINT1
18023 ("AscInitGetConfig: board %d: tag queuing enabled w/o disconnects\n",
18024 boardp->id);
18025 break;
18026 default:
18027 ASC_PRINT2
18028 ("AscInitGetConfig: board %d: unknown warning: 0x%x\n",
18029 boardp->id, ret);
18030 break;
18031 }
18032 if ((err_code = asc_dvc_varp->err_code) != 0) {
18033 ASC_PRINT3
18034 ("AscInitGetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
18035 boardp->id,
18036 asc_dvc_varp->init_state, asc_dvc_varp->err_code);
18037 }
18038 } else {
18039 ASC_DBG(2, "advansys_board_found: AdvInitGetConfig()\n");
18040 if ((ret = AdvInitGetConfig(adv_dvc_varp)) != 0) {
18041 ASC_PRINT2
18042 ("AdvInitGetConfig: board %d: warning: 0x%x\n",
18043 boardp->id, ret);
18044 }
18045 if ((err_code = adv_dvc_varp->err_code) != 0) {
18046 ASC_PRINT2
18047 ("AdvInitGetConfig: board %d error: err_code 0x%x\n",
18048 boardp->id, adv_dvc_varp->err_code);
18049 }
18050 }
18051
18052 if (err_code != 0) {
18053#ifdef CONFIG_PROC_FS
18054 kfree(boardp->prtbuf);
18055#endif /* CONFIG_PROC_FS */
18056 scsi_unregister(shost);
18057 asc_board_count--;
18058 return NULL;
18059 }
18060
18061 /*
18062 * Save the EEPROM configuration so that it can be displayed
18063 * from /proc/scsi/advansys/[0...].
18064 */
18065 if (ASC_NARROW_BOARD(boardp)) {
18066
18067 ASCEEP_CONFIG *ep;
18068
18069 /*
18070 * Set the adapter's target id bit in the 'init_tidmask' field.
18071 */
18072 boardp->init_tidmask |=
18073 ADV_TID_TO_TIDMASK(asc_dvc_varp->cfg->chip_scsi_id);
18074
18075 /*
18076 * Save EEPROM settings for the board.
18077 */
18078 ep = &boardp->eep_config.asc_eep;
18079
18080 ep->init_sdtr = asc_dvc_varp->cfg->sdtr_enable;
18081 ep->disc_enable = asc_dvc_varp->cfg->disc_enable;
18082 ep->use_cmd_qng = asc_dvc_varp->cfg->cmd_qng_enabled;
18083 ASC_EEP_SET_DMA_SPD(ep, asc_dvc_varp->cfg->isa_dma_speed);
18084 ep->start_motor = asc_dvc_varp->start_motor;
18085 ep->cntl = asc_dvc_varp->dvc_cntl;
18086 ep->no_scam = asc_dvc_varp->no_scam;
18087 ep->max_total_qng = asc_dvc_varp->max_total_qng;
18088 ASC_EEP_SET_CHIP_ID(ep, asc_dvc_varp->cfg->chip_scsi_id);
18089 /* 'max_tag_qng' is set to the same value for every device. */
18090 ep->max_tag_qng = asc_dvc_varp->cfg->max_tag_qng[0];
18091 ep->adapter_info[0] = asc_dvc_varp->cfg->adapter_info[0];
18092 ep->adapter_info[1] = asc_dvc_varp->cfg->adapter_info[1];
18093 ep->adapter_info[2] = asc_dvc_varp->cfg->adapter_info[2];
18094 ep->adapter_info[3] = asc_dvc_varp->cfg->adapter_info[3];
18095 ep->adapter_info[4] = asc_dvc_varp->cfg->adapter_info[4];
18096 ep->adapter_info[5] = asc_dvc_varp->cfg->adapter_info[5];
18097
18098 /*
18099 * Modify board configuration.
18100 */
18101 ASC_DBG(2, "advansys_board_found: AscInitSetConfig()\n");
18102 switch (ret = AscInitSetConfig(asc_dvc_varp)) {
18103 case 0: /* No error. */
18104 break;
18105 case ASC_WARN_IO_PORT_ROTATE:
18106 ASC_PRINT1
18107 ("AscInitSetConfig: board %d: I/O port address modified\n",
18108 boardp->id);
18109 break;
18110 case ASC_WARN_AUTO_CONFIG:
18111 ASC_PRINT1
18112 ("AscInitSetConfig: board %d: I/O port increment switch enabled\n",
18113 boardp->id);
18114 break;
18115 case ASC_WARN_EEPROM_CHKSUM:
18116 ASC_PRINT1
18117 ("AscInitSetConfig: board %d: EEPROM checksum error\n",
18118 boardp->id);
18119 break;
18120 case ASC_WARN_IRQ_MODIFIED:
18121 ASC_PRINT1
18122 ("AscInitSetConfig: board %d: IRQ modified\n",
18123 boardp->id);
18124 break;
18125 case ASC_WARN_CMD_QNG_CONFLICT:
18126 ASC_PRINT1
18127 ("AscInitSetConfig: board %d: tag queuing w/o disconnects\n",
18128 boardp->id);
18129 break;
18130 default:
18131 ASC_PRINT2
18132 ("AscInitSetConfig: board %d: unknown warning: 0x%x\n",
18133 boardp->id, ret);
18134 break;
18135 }
18136 if (asc_dvc_varp->err_code != 0) {
18137 ASC_PRINT3
18138 ("AscInitSetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
18139 boardp->id,
18140 asc_dvc_varp->init_state, asc_dvc_varp->err_code);
18141#ifdef CONFIG_PROC_FS
18142 kfree(boardp->prtbuf);
18143#endif /* CONFIG_PROC_FS */
18144 scsi_unregister(shost);
18145 asc_board_count--;
18146 return NULL;
18147 }
18148
18149 /*
18150 * Finish initializing the 'Scsi_Host' structure.
18151 */
18152 /* AscInitSetConfig() will set the IRQ for non-PCI boards. */
18153 if ((asc_dvc_varp->bus_type & ASC_IS_PCI) == 0) {
18154 shost->irq = asc_dvc_varp->irq_no;
18155 }
18156 } else {
18157 ADVEEP_3550_CONFIG *ep_3550;
18158 ADVEEP_38C0800_CONFIG *ep_38C0800;
18159 ADVEEP_38C1600_CONFIG *ep_38C1600;
18160
18161 /*
18162 * Save Wide EEP Configuration Information.
18163 */
18164 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
18165 ep_3550 = &boardp->eep_config.adv_3550_eep;
18166
18167 ep_3550->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
18168 ep_3550->max_host_qng = adv_dvc_varp->max_host_qng;
18169 ep_3550->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
18170 ep_3550->termination = adv_dvc_varp->cfg->termination;
18171 ep_3550->disc_enable = adv_dvc_varp->cfg->disc_enable;
18172 ep_3550->bios_ctrl = adv_dvc_varp->bios_ctrl;
18173 ep_3550->wdtr_able = adv_dvc_varp->wdtr_able;
18174 ep_3550->sdtr_able = adv_dvc_varp->sdtr_able;
18175 ep_3550->ultra_able = adv_dvc_varp->ultra_able;
18176 ep_3550->tagqng_able = adv_dvc_varp->tagqng_able;
18177 ep_3550->start_motor = adv_dvc_varp->start_motor;
18178 ep_3550->scsi_reset_delay =
18179 adv_dvc_varp->scsi_reset_wait;
18180 ep_3550->serial_number_word1 =
18181 adv_dvc_varp->cfg->serial1;
18182 ep_3550->serial_number_word2 =
18183 adv_dvc_varp->cfg->serial2;
18184 ep_3550->serial_number_word3 =
18185 adv_dvc_varp->cfg->serial3;
18186 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
18187 ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
18188
18189 ep_38C0800->adapter_scsi_id =
18190 adv_dvc_varp->chip_scsi_id;
18191 ep_38C0800->max_host_qng = adv_dvc_varp->max_host_qng;
18192 ep_38C0800->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
18193 ep_38C0800->termination_lvd =
18194 adv_dvc_varp->cfg->termination;
18195 ep_38C0800->disc_enable =
18196 adv_dvc_varp->cfg->disc_enable;
18197 ep_38C0800->bios_ctrl = adv_dvc_varp->bios_ctrl;
18198 ep_38C0800->wdtr_able = adv_dvc_varp->wdtr_able;
18199 ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
18200 ep_38C0800->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
18201 ep_38C0800->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
18202 ep_38C0800->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
18203 ep_38C0800->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
18204 ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
18205 ep_38C0800->start_motor = adv_dvc_varp->start_motor;
18206 ep_38C0800->scsi_reset_delay =
18207 adv_dvc_varp->scsi_reset_wait;
18208 ep_38C0800->serial_number_word1 =
18209 adv_dvc_varp->cfg->serial1;
18210 ep_38C0800->serial_number_word2 =
18211 adv_dvc_varp->cfg->serial2;
18212 ep_38C0800->serial_number_word3 =
18213 adv_dvc_varp->cfg->serial3;
18214 } else {
18215 ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
18216
18217 ep_38C1600->adapter_scsi_id =
18218 adv_dvc_varp->chip_scsi_id;
18219 ep_38C1600->max_host_qng = adv_dvc_varp->max_host_qng;
18220 ep_38C1600->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
18221 ep_38C1600->termination_lvd =
18222 adv_dvc_varp->cfg->termination;
18223 ep_38C1600->disc_enable =
18224 adv_dvc_varp->cfg->disc_enable;
18225 ep_38C1600->bios_ctrl = adv_dvc_varp->bios_ctrl;
18226 ep_38C1600->wdtr_able = adv_dvc_varp->wdtr_able;
18227 ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
18228 ep_38C1600->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
18229 ep_38C1600->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
18230 ep_38C1600->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
18231 ep_38C1600->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
18232 ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
18233 ep_38C1600->start_motor = adv_dvc_varp->start_motor;
18234 ep_38C1600->scsi_reset_delay =
18235 adv_dvc_varp->scsi_reset_wait;
18236 ep_38C1600->serial_number_word1 =
18237 adv_dvc_varp->cfg->serial1;
18238 ep_38C1600->serial_number_word2 =
18239 adv_dvc_varp->cfg->serial2;
18240 ep_38C1600->serial_number_word3 =
18241 adv_dvc_varp->cfg->serial3;
18242 }
18243
18244 /*
18245 * Set the adapter's target id bit in the 'init_tidmask' field.
18246 */
18247 boardp->init_tidmask |=
18248 ADV_TID_TO_TIDMASK(adv_dvc_varp->chip_scsi_id);
18249
18250 /*
18251 * Finish initializing the 'Scsi_Host' structure.
18252 */
18253 shost->irq = adv_dvc_varp->irq_no;
18254 }
18255
18256 /*
18257 * Channels are numbered beginning with 0. For AdvanSys one host
18258 * structure supports one channel. Multi-channel boards have a
18259 * separate host structure for each channel.
18260 */
18261 shost->max_channel = 0;
18262 if (ASC_NARROW_BOARD(boardp)) {
18263 shost->max_id = ASC_MAX_TID + 1;
18264 shost->max_lun = ASC_MAX_LUN + 1;
18265
18266 shost->io_port = asc_dvc_varp->iop_base;
18267 boardp->asc_n_io_port = ASC_IOADR_GAP;
18268 shost->this_id = asc_dvc_varp->cfg->chip_scsi_id;
18269
18270 /* Set maximum number of queues the adapter can handle. */
18271 shost->can_queue = asc_dvc_varp->max_total_qng;
18272 } else {
18273 shost->max_id = ADV_MAX_TID + 1;
18274 shost->max_lun = ADV_MAX_LUN + 1;
18275
18276 /*
18277 * Save the I/O Port address and length even though
18278 * I/O ports are not used to access Wide boards.
18279 * Instead the Wide boards are accessed with
18280 * PCI Memory Mapped I/O.
18281 */
18282 shost->io_port = iop;
18283 boardp->asc_n_io_port = iolen;
18284
18285 shost->this_id = adv_dvc_varp->chip_scsi_id;
18286
18287 /* Set maximum number of queues the adapter can handle. */
18288 shost->can_queue = adv_dvc_varp->max_host_qng;
18289 }
18290
18291 /*
18292 * 'n_io_port' currently is one byte.
18293 *
18294 * Set a value to 'n_io_port', but never referenced it because
18295 * it may be truncated.
18296 */
18297 shost->n_io_port = boardp->asc_n_io_port <= 255 ?
18298 boardp->asc_n_io_port : 255;
18299
18300 /*
18301 * Following v1.3.89, 'cmd_per_lun' is no longer needed
18302 * and should be set to zero.
18303 *
18304 * But because of a bug introduced in v1.3.89 if the driver is
18305 * compiled as a module and 'cmd_per_lun' is zero, the Mid-Level
18306 * SCSI function 'allocate_device' will panic. To allow the driver
18307 * to work as a module in these kernels set 'cmd_per_lun' to 1.
18308 *
18309 * Note: This is wrong. cmd_per_lun should be set to the depth
18310 * you want on untagged devices always.
18311 #ifdef MODULE
18312 */
18313 shost->cmd_per_lun = 1;
18314/* #else
18315 shost->cmd_per_lun = 0;
18316#endif */
18317
18318 /*
18319 * Set the maximum number of scatter-gather elements the
18320 * adapter can handle.
18321 */
18322 if (ASC_NARROW_BOARD(boardp)) {
18323 /*
18324 * Allow two commands with 'sg_tablesize' scatter-gather
18325 * elements to be executed simultaneously. This value is
18326 * the theoretical hardware limit. It may be decreased
18327 * below.
18328 */
18329 shost->sg_tablesize =
18330 (((asc_dvc_varp->max_total_qng - 2) / 2) *
18331 ASC_SG_LIST_PER_Q) + 1;
18332 } else {
18333 shost->sg_tablesize = ADV_MAX_SG_LIST;
18334 }
18335
18336 /*
18337 * The value of 'sg_tablesize' can not exceed the SCSI
18338 * mid-level driver definition of SG_ALL. SG_ALL also
18339 * must not be exceeded, because it is used to define the
18340 * size of the scatter-gather table in 'struct asc_sg_head'.
18341 */
18342 if (shost->sg_tablesize > SG_ALL) {
18343 shost->sg_tablesize = SG_ALL;
18344 }
18345
18346 ASC_DBG1(1, "advansys_board_found: sg_tablesize: %d\n", shost->sg_tablesize);
18347
18348 /* BIOS start address. */
18349 if (ASC_NARROW_BOARD(boardp)) {
18350 shost->base = ((ulong)
18351 AscGetChipBiosAddress(asc_dvc_varp->
18352 iop_base,
18353 asc_dvc_varp->bus_type));
18354 } else {
18355 /*
18356 * Fill-in BIOS board variables. The Wide BIOS saves
18357 * information in LRAM that is used by the driver.
18358 */
18359 AdvReadWordLram(adv_dvc_varp->iop_base,
18360 BIOS_SIGNATURE, boardp->bios_signature);
18361 AdvReadWordLram(adv_dvc_varp->iop_base,
18362 BIOS_VERSION, boardp->bios_version);
18363 AdvReadWordLram(adv_dvc_varp->iop_base,
18364 BIOS_CODESEG, boardp->bios_codeseg);
18365 AdvReadWordLram(adv_dvc_varp->iop_base,
18366 BIOS_CODELEN, boardp->bios_codelen);
18367
18368 ASC_DBG2(1,
18369 "advansys_board_found: bios_signature 0x%x, bios_version 0x%x\n",
18370 boardp->bios_signature, boardp->bios_version);
18371
18372 ASC_DBG2(1,
18373 "advansys_board_found: bios_codeseg 0x%x, bios_codelen 0x%x\n",
18374 boardp->bios_codeseg, boardp->bios_codelen);
18375
18376 /*
18377 * If the BIOS saved a valid signature, then fill in
18378 * the BIOS code segment base address.
18379 */
18380 if (boardp->bios_signature == 0x55AA) {
18381 /*
18382 * Convert x86 realmode code segment to a linear
18383 * address by shifting left 4.
18384 */
18385 shost->base = ((ulong)boardp->bios_codeseg << 4);
18386 } else {
18387 shost->base = 0;
18388 }
18389 }
18390
18391 /*
18392 * Register Board Resources - I/O Port, DMA, IRQ
18393 */
18394
18395 /*
18396 * Register I/O port range.
18397 *
18398 * For Wide boards the I/O ports are not used to access
18399 * the board, but request the region anyway.
18400 *
18401 * 'shost->n_io_port' is not referenced, because it may be truncated.
18402 */
18403 ASC_DBG2(2,
18404 "advansys_board_found: request_region port 0x%lx, len 0x%x\n",
18405 (ulong)shost->io_port, boardp->asc_n_io_port);
18406 if (request_region(shost->io_port, boardp->asc_n_io_port,
18407 "advansys") == NULL) {
18408 ASC_PRINT3
18409 ("advansys_board_found: board %d: request_region() failed, port 0x%lx, len 0x%x\n",
18410 boardp->id, (ulong)shost->io_port, boardp->asc_n_io_port);
18411#ifdef CONFIG_PROC_FS
18412 kfree(boardp->prtbuf);
18413#endif /* CONFIG_PROC_FS */
18414 scsi_unregister(shost);
18415 asc_board_count--;
18416 return NULL;
18417 }
18418
18419 /* Register DMA Channel for Narrow boards. */
18420 shost->dma_channel = NO_ISA_DMA; /* Default to no ISA DMA. */
18421#ifdef CONFIG_ISA
18422 if (ASC_NARROW_BOARD(boardp)) {
18423 /* Register DMA channel for ISA bus. */
18424 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
18425 shost->dma_channel = asc_dvc_varp->cfg->isa_dma_channel;
18426 if ((ret =
18427 request_dma(shost->dma_channel, "advansys")) != 0) {
18428 ASC_PRINT3
18429 ("advansys_board_found: board %d: request_dma() %d failed %d\n",
18430 boardp->id, shost->dma_channel, ret);
18431 release_region(shost->io_port,
18432 boardp->asc_n_io_port);
18433#ifdef CONFIG_PROC_FS
18434 kfree(boardp->prtbuf);
18435#endif /* CONFIG_PROC_FS */
18436 scsi_unregister(shost);
18437 asc_board_count--;
18438 return NULL;
18439 }
18440 AscEnableIsaDma(shost->dma_channel);
18441 }
18442 }
18443#endif /* CONFIG_ISA */
18444
18445 /* Register IRQ Number. */
18446 ASC_DBG1(2, "advansys_board_found: request_irq() %d\n", shost->irq);
18447 /*
18448 * If request_irq() fails with the IRQF_DISABLED flag set,
18449 * then try again without the IRQF_DISABLED flag set. This
18450 * allows IRQ sharing to work even with other drivers that
18451 * do not set the IRQF_DISABLED flag.
18452 *
18453 * If IRQF_DISABLED is not set, then interrupts are enabled
18454 * before the driver interrupt function is called.
18455 */
18456 if (((ret = request_irq(shost->irq, advansys_interrupt,
18457 IRQF_DISABLED | (share_irq ==
18458 TRUE ?
18459 IRQF_SHARED :
18460 0), "advansys", boardp)) != 0)
18461 &&
18462 ((ret =
18463 request_irq(shost->irq, advansys_interrupt,
18464 (share_irq == TRUE ? IRQF_SHARED : 0),
18465 "advansys", boardp)) != 0)) {
18466 if (ret == -EBUSY) {
18467 ASC_PRINT2
18468 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x already in use.\n",
18469 boardp->id, shost->irq);
18470 } else if (ret == -EINVAL) {
18471 ASC_PRINT2
18472 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x not valid.\n",
18473 boardp->id, shost->irq);
18474 } else {
18475 ASC_PRINT3
18476 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x failed with %d\n",
18477 boardp->id, shost->irq, ret);
18478 }
18479 release_region(shost->io_port, boardp->asc_n_io_port);
18480 iounmap(boardp->ioremap_addr);
18481 if (shost->dma_channel != NO_ISA_DMA) {
18482 free_dma(shost->dma_channel);
18483 }
18484#ifdef CONFIG_PROC_FS
18485 kfree(boardp->prtbuf);
18486#endif /* CONFIG_PROC_FS */
18487 scsi_unregister(shost);
18488 asc_board_count--;
18489 return NULL;
18490 }
18491
18492 /*
18493 * Initialize board RISC chip and enable interrupts.
18494 */
18495 if (ASC_NARROW_BOARD(boardp)) {
18496 ASC_DBG(2, "advansys_board_found: AscInitAsc1000Driver()\n");
18497 warn_code = AscInitAsc1000Driver(asc_dvc_varp);
18498 err_code = asc_dvc_varp->err_code;
18499
18500 if (warn_code || err_code) {
18501 ASC_PRINT4
18502 ("advansys_board_found: board %d error: init_state 0x%x, warn 0x%x, error 0x%x\n",
18503 boardp->id,
18504 asc_dvc_varp->init_state, warn_code, err_code);
18505 }
18506 } else {
18507 ADV_CARR_T *carrp;
18508 int req_cnt = 0;
18509 adv_req_t *reqp = NULL;
18510 int sg_cnt = 0;
18511
18512 /*
18513 * Allocate buffer carrier structures. The total size
18514 * is about 4 KB, so allocate all at once.
18515 */
18516 carrp = (ADV_CARR_T *) kmalloc(ADV_CARRIER_BUFSIZE, GFP_ATOMIC);
18517 ASC_DBG1(1, "advansys_board_found: carrp 0x%lx\n", (ulong)carrp);
18518
18519 if (carrp == NULL) {
18520 goto kmalloc_error;
18521 }
18522
18523 /*
18524 * Allocate up to 'max_host_qng' request structures for
18525 * the Wide board. The total size is about 16 KB, so
18526 * allocate all at once. If the allocation fails decrement
18527 * and try again.
18528 */
18529 for (req_cnt = adv_dvc_varp->max_host_qng;
18530 req_cnt > 0; req_cnt--) {
18531
18532 reqp = (adv_req_t *)
18533 kmalloc(sizeof(adv_req_t) * req_cnt, GFP_ATOMIC);
18534
18535 ASC_DBG3(1,
18536 "advansys_board_found: reqp 0x%lx, req_cnt %d, bytes %lu\n",
18537 (ulong)reqp, req_cnt,
18538 (ulong)sizeof(adv_req_t) * req_cnt);
18539
18540 if (reqp != NULL) {
18541 break;
18542 }
18543 }
18544 if (reqp == NULL) {
18545 goto kmalloc_error;
18546 }
18547
18548 /*
18549 * Allocate up to ADV_TOT_SG_BLOCK request structures for
18550 * the Wide board. Each structure is about 136 bytes.
18551 */
18552 boardp->adv_sgblkp = NULL;
18553 for (sg_cnt = 0; sg_cnt < ADV_TOT_SG_BLOCK; sg_cnt++) {
18554
18555 sgp = (adv_sgblk_t *)
18556 kmalloc(sizeof(adv_sgblk_t), GFP_ATOMIC);
18557
18558 if (sgp == NULL) {
18559 break;
18560 }
18561
18562 sgp->next_sgblkp = boardp->adv_sgblkp;
18563 boardp->adv_sgblkp = sgp;
18564
18565 }
18566 ASC_DBG3(1,
18567 "advansys_board_found: sg_cnt %d * %u = %u bytes\n",
18568 sg_cnt, sizeof(adv_sgblk_t),
18569 (unsigned)(sizeof(adv_sgblk_t) * sg_cnt));
18570
18571 /*
18572 * If no request structures or scatter-gather structures could
18573 * be allocated, then return an error. Otherwise continue with
18574 * initialization.
18575 */
18576 kmalloc_error:
18577 if (carrp == NULL) {
18578 ASC_PRINT1
18579 ("advansys_board_found: board %d error: failed to kmalloc() carrier buffer.\n",
18580 boardp->id);
18581 err_code = ADV_ERROR;
18582 } else if (reqp == NULL) {
18583 kfree(carrp);
18584 ASC_PRINT1
18585 ("advansys_board_found: board %d error: failed to kmalloc() adv_req_t buffer.\n",
18586 boardp->id);
18587 err_code = ADV_ERROR;
18588 } else if (boardp->adv_sgblkp == NULL) {
18589 kfree(carrp);
18590 kfree(reqp);
18591 ASC_PRINT1
18592 ("advansys_board_found: board %d error: failed to kmalloc() adv_sgblk_t buffers.\n",
18593 boardp->id);
18594 err_code = ADV_ERROR;
18595 } else {
18596
18597 /* Save carrier buffer pointer. */
18598 boardp->orig_carrp = carrp;
18599
18600 /*
18601 * Save original pointer for kfree() in case the
18602 * driver is built as a module and can be unloaded.
18603 */
18604 boardp->orig_reqp = reqp;
18605
18606 adv_dvc_varp->carrier_buf = carrp;
18607
18608 /*
18609 * Point 'adv_reqp' to the request structures and
18610 * link them together.
18611 */
18612 req_cnt--;
18613 reqp[req_cnt].next_reqp = NULL;
18614 for (; req_cnt > 0; req_cnt--) {
18615 reqp[req_cnt - 1].next_reqp = &reqp[req_cnt];
18616 }
18617 boardp->adv_reqp = &reqp[0];
18618
18619 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
18620 ASC_DBG(2,
18621 "advansys_board_found: AdvInitAsc3550Driver()\n");
18622 warn_code = AdvInitAsc3550Driver(adv_dvc_varp);
18623 } else if (adv_dvc_varp->chip_type ==
18624 ADV_CHIP_ASC38C0800) {
18625 ASC_DBG(2,
18626 "advansys_board_found: AdvInitAsc38C0800Driver()\n");
18627 warn_code =
18628 AdvInitAsc38C0800Driver(adv_dvc_varp);
18629 } else {
18630 ASC_DBG(2,
18631 "advansys_board_found: AdvInitAsc38C1600Driver()\n");
18632 warn_code =
18633 AdvInitAsc38C1600Driver(adv_dvc_varp);
18634 }
18635 err_code = adv_dvc_varp->err_code;
18636
18637 if (warn_code || err_code) {
18638 ASC_PRINT3
18639 ("advansys_board_found: board %d error: warn 0x%x, error 0x%x\n",
18640 boardp->id, warn_code, err_code);
18641 }
18642 }
18643 }
18644
18645 if (err_code != 0) {
18646 release_region(shost->io_port, boardp->asc_n_io_port);
18647 if (ASC_WIDE_BOARD(boardp)) {
18648 iounmap(boardp->ioremap_addr);
18649 kfree(boardp->orig_carrp);
18650 boardp->orig_carrp = NULL;
18651 if (boardp->orig_reqp) {
18652 kfree(boardp->orig_reqp);
18653 boardp->orig_reqp = boardp->adv_reqp = NULL;
18654 }
18655 while ((sgp = boardp->adv_sgblkp) != NULL) {
18656 boardp->adv_sgblkp = sgp->next_sgblkp;
18657 kfree(sgp);
18658 }
18659 }
18660 if (shost->dma_channel != NO_ISA_DMA) {
18661 free_dma(shost->dma_channel);
18662 }
18663#ifdef CONFIG_PROC_FS
18664 kfree(boardp->prtbuf);
18665#endif /* CONFIG_PROC_FS */
18666 free_irq(shost->irq, boardp);
18667 scsi_unregister(shost);
18668 asc_board_count--;
18669 return NULL;
18670 }
18671 ASC_DBG_PRT_SCSI_HOST(2, shost);
18672
18673 return shost;
18674}
18675
18676/*
18677 * advansys_detect()
18678 *
18679 * Detect function for AdvanSys adapters.
18680 *
18681 * Argument is a pointer to the host driver's scsi_hosts entry.
18682 *
18683 * Return number of adapters found.
18684 *
18685 * Note: Because this function is called during system initialization
18686 * it must not call SCSI mid-level functions including scsi_malloc()
18687 * and scsi_free().
18688 */
18689static int __init advansys_detect(struct scsi_host_template *tpnt)
18690{
18691 static int detect_called = ASC_FALSE;
18692 int iop;
18693 int bus;
18694 int ioport = 0;
18695 struct device *dev = NULL;
18696#ifdef CONFIG_PCI
18697 int pci_init_search = 0;
18698 struct pci_dev *pci_devicep[ASC_NUM_BOARD_SUPPORTED];
18699 int pci_card_cnt_max = 0;
18700 int pci_card_cnt = 0;
18701 struct pci_dev *pdev = NULL;
18702 int pci_device_id_cnt = 0;
18703 unsigned int pci_device_id[ASC_PCI_DEVICE_ID_CNT] = {
18704 PCI_DEVICE_ID_ASP_1200A,
18705 PCI_DEVICE_ID_ASP_ABP940,
18706 PCI_DEVICE_ID_ASP_ABP940U,
18707 PCI_DEVICE_ID_ASP_ABP940UW,
18708 PCI_DEVICE_ID_38C0800_REV1,
18709 PCI_DEVICE_ID_38C1600_REV1
18710 };
18711#endif /* CONFIG_PCI */
18712
18713 if (detect_called == ASC_FALSE) {
18714 detect_called = ASC_TRUE;
18715 } else {
18716 printk
18717 ("AdvanSys SCSI: advansys_detect() multiple calls ignored\n");
18718 return 0;
18719 }
18720
18721 ASC_DBG(1, "advansys_detect: begin\n");
18722
18723 asc_board_count = 0;
18724
18725 /*
18726 * If I/O port probing has been modified, then verify and
18727 * clean-up the 'asc_ioport' list.
18728 */
18729 if (asc_iopflag == ASC_TRUE) {
18730 for (ioport = 0; ioport < ASC_NUM_IOPORT_PROBE; ioport++) {
18731 ASC_DBG2(1, "advansys_detect: asc_ioport[%d] 0x%x\n",
18732 ioport, asc_ioport[ioport]);
18733 if (asc_ioport[ioport] != 0) {
18734 for (iop = 0; iop < ASC_IOADR_TABLE_MAX_IX;
18735 iop++) {
18736 if (_asc_def_iop_base[iop] ==
18737 asc_ioport[ioport]) {
18738 break;
18739 }
18740 }
18741 if (iop == ASC_IOADR_TABLE_MAX_IX) {
18742 printk
18743 ("AdvanSys SCSI: specified I/O Port 0x%X is invalid\n",
18744 asc_ioport[ioport]);
18745 asc_ioport[ioport] = 0;
18746 }
18747 }
18748 }
18749 ioport = 0;
18750 }
18751
18752 for (bus = 0; bus < ASC_NUM_BUS; bus++) {
18753
18754 ASC_DBG2(1, "advansys_detect: bus search type %d (%s)\n",
18755 bus, asc_bus_name[bus]);
18756 iop = 0;
18757
18758 while (asc_board_count < ASC_NUM_BOARD_SUPPORTED) {
18759
18760 ASC_DBG1(2, "advansys_detect: asc_board_count %d\n",
18761 asc_board_count);
18762
18763 switch (asc_bus[bus]) {
18764 case ASC_IS_ISA:
18765 case ASC_IS_VL:
18766#ifdef CONFIG_ISA
18767 if (asc_iopflag == ASC_FALSE) {
18768 iop =
18769 AscSearchIOPortAddr(iop,
18770 asc_bus[bus]);
18771 } else {
18772 /*
18773 * ISA and VL I/O port scanning has either been
18774 * eliminated or limited to selected ports on
18775 * the LILO command line, /etc/lilo.conf, or
18776 * by setting variables when the module was loaded.
18777 */
18778 ASC_DBG(1,
18779 "advansys_detect: I/O port scanning modified\n");
18780 ioport_try_again:
18781 iop = 0;
18782 for (; ioport < ASC_NUM_IOPORT_PROBE;
18783 ioport++) {
18784 if ((iop =
18785 asc_ioport[ioport]) != 0) {
18786 break;
18787 }
18788 }
18789 if (iop) {
18790 ASC_DBG1(1,
18791 "advansys_detect: probing I/O port 0x%x...\n",
18792 iop);
18793 if (!request_region
18794 (iop, ASC_IOADR_GAP,
18795 "advansys")) {
18796 printk
18797 ("AdvanSys SCSI: specified I/O Port 0x%X is busy\n",
18798 iop);
18799 /* Don't try this I/O port twice. */
18800 asc_ioport[ioport] = 0;
18801 goto ioport_try_again;
18802 } else if (AscFindSignature(iop)
18803 == ASC_FALSE) {
18804 printk
18805 ("AdvanSys SCSI: specified I/O Port 0x%X has no adapter\n",
18806 iop);
18807 /* Don't try this I/O port twice. */
18808 release_region(iop,
18809 ASC_IOADR_GAP);
18810 asc_ioport[ioport] = 0;
18811 goto ioport_try_again;
18812 } else {
18813 /*
18814 * If this isn't an ISA board, then it must be
18815 * a VL board. If currently looking an ISA
18816 * board is being looked for then try for
18817 * another ISA board in 'asc_ioport'.
18818 */
18819 if (asc_bus[bus] ==
18820 ASC_IS_ISA
18821 &&
18822 (AscGetChipVersion
18823 (iop,
18824 ASC_IS_ISA) &
18825 ASC_CHIP_VER_ISA_BIT)
18826 == 0) {
18827 /*
18828 * Don't clear 'asc_ioport[ioport]'. Try
18829 * this board again for VL. Increment
18830 * 'ioport' past this board.
18831 */
18832 ioport++;
18833 release_region
18834 (iop,
18835 ASC_IOADR_GAP);
18836 goto ioport_try_again;
18837 }
18838 }
18839 /*
18840 * This board appears good, don't try the I/O port
18841 * again by clearing its value. Increment 'ioport'
18842 * for the next iteration.
18843 */
18844 asc_ioport[ioport++] = 0;
18845 }
18846 }
18847#endif /* CONFIG_ISA */
18848 break;
18849
18850 case ASC_IS_EISA:
18851#ifdef CONFIG_ISA
18852 iop = AscSearchIOPortAddr(iop, asc_bus[bus]);
18853#endif /* CONFIG_ISA */
18854 break;
18855
18856 case ASC_IS_PCI:
18857#ifdef CONFIG_PCI
18858 if (pci_init_search == 0) {
18859 int i, j;
18860
18861 pci_init_search = 1;
18862
18863 /* Find all PCI cards. */
18864 while (pci_device_id_cnt <
18865 ASC_PCI_DEVICE_ID_CNT) {
18866 if ((pdev =
18867 pci_find_device
18868 (PCI_VENDOR_ID_ASP,
18869 pci_device_id
18870 [pci_device_id_cnt],
18871 pdev)) == NULL) {
18872 pci_device_id_cnt++;
18873 } else {
18874 if (pci_enable_device
18875 (pdev) == 0) {
18876 pci_devicep
18877 [pci_card_cnt_max++]
18878 = pdev;
18879 }
18880 }
18881 }
18882
18883 /*
18884 * Sort PCI cards in ascending order by PCI Bus, Slot,
18885 * and Device Number.
18886 */
18887 for (i = 0; i < pci_card_cnt_max - 1;
18888 i++) {
18889 for (j = i + 1;
18890 j < pci_card_cnt_max;
18891 j++) {
18892 if ((pci_devicep[j]->
18893 bus->number <
18894 pci_devicep[i]->
18895 bus->number)
18896 ||
18897 ((pci_devicep[j]->
18898 bus->number ==
18899 pci_devicep[i]->
18900 bus->number)
18901 &&
18902 (pci_devicep[j]->
18903 devfn <
18904 pci_devicep[i]->
18905 devfn))) {
18906 pdev =
18907 pci_devicep
18908 [i];
18909 pci_devicep[i] =
18910 pci_devicep
18911 [j];
18912 pci_devicep[j] =
18913 pdev;
18914 }
18915 }
18916 }
18917
18918 pci_card_cnt = 0;
18919 } else {
18920 pci_card_cnt++;
18921 }
18922
18923 if (pci_card_cnt == pci_card_cnt_max) {
18924 iop = 0;
18925 } else {
18926 pdev = pci_devicep[pci_card_cnt];
18927
18928 ASC_DBG2(2,
18929 "advansys_detect: devfn %d, bus number %d\n",
18930 pdev->devfn,
18931 pdev->bus->number);
18932 iop = pci_resource_start(pdev, 0);
18933 ASC_DBG2(1,
18934 "advansys_detect: vendorID %X, deviceID %X\n",
18935 pdev->vendor,
18936 pdev->device);
18937 ASC_DBG2(2,
18938 "advansys_detect: iop %X, irqLine %d\n",
18939 iop, pdev->irq);
18940 }
18941 if (pdev)
18942 dev = &pdev->dev;
18943
18944#endif /* CONFIG_PCI */
18945 break;
18946
18947 default:
18948 ASC_PRINT1
18949 ("advansys_detect: unknown bus type: %d\n",
18950 asc_bus[bus]);
18951 break;
18952 }
18953 ASC_DBG1(1, "advansys_detect: iop 0x%x\n", iop);
18954
18955 /*
18956 * Adapter not found, try next bus type.
18957 */
18958 if (iop == 0) {
18959 break;
18960 }
18961
18962 advansys_board_found(iop, dev, asc_bus[bus]);
18963 }
18964 }
18965
18966 ASC_DBG1(1, "advansys_detect: done: asc_board_count %d\n",
18967 asc_board_count);
18968 return asc_board_count;
18969}
18970
18971/*
18972 * advansys_release()
18973 *
18974 * Release resources allocated for a single AdvanSys adapter.
18975 */
18976static int advansys_release(struct Scsi_Host *shost)
18977{
18978 asc_board_t *boardp;
18979
18980 ASC_DBG(1, "advansys_release: begin\n");
18981 boardp = ASC_BOARDP(shost);
18982 free_irq(shost->irq, boardp);
18983 if (shost->dma_channel != NO_ISA_DMA) {
18984 ASC_DBG(1, "advansys_release: free_dma()\n");
18985 free_dma(shost->dma_channel);
18986 }
18987 release_region(shost->io_port, boardp->asc_n_io_port);
18988 if (ASC_WIDE_BOARD(boardp)) {
18989 adv_sgblk_t *sgp = NULL;
18990
18991 iounmap(boardp->ioremap_addr);
18992 kfree(boardp->orig_carrp);
18993 boardp->orig_carrp = NULL;
18994 if (boardp->orig_reqp) {
18995 kfree(boardp->orig_reqp);
18996 boardp->orig_reqp = boardp->adv_reqp = NULL;
18997 }
18998 while ((sgp = boardp->adv_sgblkp) != NULL) {
18999 boardp->adv_sgblkp = sgp->next_sgblkp;
19000 kfree(sgp);
19001 }
19002 }
19003#ifdef CONFIG_PROC_FS
19004 ASC_ASSERT(boardp->prtbuf != NULL);
19005 kfree(boardp->prtbuf);
19006#endif /* CONFIG_PROC_FS */
19007 scsi_unregister(shost);
19008 ASC_DBG(1, "advansys_release: end\n");
19009 return 0;
19010}
19011
Randy Dunlapd8dafd82006-11-21 13:50:47 -080019012#ifdef CONFIG_PCI
Dave Jones2672ea82006-08-02 17:11:49 -040019013/* PCI Devices supported by this driver */
19014static struct pci_device_id advansys_pci_tbl[] __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040019015 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_1200A,
19016 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
19017 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940,
19018 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
19019 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940U,
19020 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
19021 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940UW,
19022 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
19023 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C0800_REV1,
19024 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
19025 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C1600_REV1,
19026 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
19027 {}
Dave Jones2672ea82006-08-02 17:11:49 -040019028};
Matthew Wilcox27c868c2007-07-26 10:56:23 -040019029
Dave Jones2672ea82006-08-02 17:11:49 -040019030MODULE_DEVICE_TABLE(pci, advansys_pci_tbl);
Randy Dunlapd8dafd82006-11-21 13:50:47 -080019031#endif /* CONFIG_PCI */